跳转到主要内容

HugeGraph-ML

HugeGraph-ML 从 HugeGraph 读取图数据并转换为 DGL 图,供节点嵌入、节点分类、图分类、链接预测和欺诈检测等任务使用。模型实现位于 hugegraph-ml/src/hugegraph_ml/models/

环境要求

  • Python 3.10 或更高版本
  • HugeGraph Server 1.0 或更高版本,推荐 1.5 及以上版本
  • uv 0.7 或更高版本

所有服务端访问都通过同一仓库中的 hugegraph-python-client(即 pyhugegraph 包)完成。HugeGraph2DGL 使用 Gremlin 接口的 g.V().hasLabel(...)g.E().hasLabel(...) 拉取点边,数据集导入函数则通过 schema 接口和顶点、边的批量接口写入,每批 500 条。

ML 依赖在仓库根目录的 [tool.uv] constraint-dependencies 中固定版本:

依赖版本约束
torch==2.2.0
dgl~=2.1.0
ogb~=1.3.6
torchdata~=0.7.0
catboost~=1.2.3
category-encoders~=2.6.3
numpy~=1.24.4
pandas~=2.2.3

上述约束安装的是 CPU 版本。每个任务都有 gpu 参数,默认值 -1 表示使用 CPU;只有自行安装 CUDA 版的 torchdgl 之后,才可以传入设备编号。

安装

git clone https://github.com/apache/hugegraph-ai.git
cd hugegraph-ai
uv sync --extra ml
source .venv/bin/activate
cd hugegraph-ml/src

HugeGraph-ML 是根项目的路径依赖,但不属于 uv workspace members。应在仓库根目录选择 ml extra,不要在子目录建立另一套锁文件。

已实现模型

下列模块均位于 hugegraph-ml/src/hugegraph_ml/models/models/__init__.py 不做任何再导出,需要直接从模块文件导入。

模型模块入口类用途论文
AGNNagnn.pyAGNN节点分类1803.03735
APPNPappnp.pyAPPNP节点分类1810.05997
ARMAarma.pyARMA4NC节点分类1901.01343
BGNNbgnn.pyBGNNPredictor梯度提升与 GNN 结合处理节点特征,自带示例执行回归任务2101.08543
BGRLbgrl.pyBGRL自监督节点嵌入2102.06514
CARE-GNNcare_gnn.pyCAREGNN欺诈检测2008.08692
Cluster-GCNcluster_gcn.pySAGE基于子图采样的节点分类1905.07953
C&Scorrect_and_smooth.pyMLPCorrectAndSmoothLabelPropagation对基础预测结果做校正与平滑2010.13993
DAGNNdagnn.pyDAGNN节点分类2007.09296
DeeperGCNdeepergcn.pyDeeperGCN带边特征的节点分类2006.07739
DGIdgi.pyDGI自监督节点嵌入1809.10341
DiffPooldiffpool.pyDiffPool图分类1806.08804
GATNEgatne.pyDGLGATNE异构网络嵌入1905.01669
GINgin_global_pool.pyGIN图分类
GRACEgrace.pyGRACE自监督节点嵌入2006.04131
GRANDgrand.pyGRAND节点分类2005.11079
JKNetjknet.pyJKNet节点分类1806.03536
MLPmlp.pyMLPClassifier基于已学习嵌入的下游分类器
P-GNNpgnn.pyPGNN链接预测you19b
SEALseal.pyDGCNNSEALData链接预测1802.09691

GINpooling 参数可取 sum(默认)、meanmaxglobal_attentionset2set

读取图数据

hugegraph-ml/src/hugegraph_ml/data/hugegraph2dgl.py 中的 HugeGraph2DGL 会创建 PyHugeClient,并把查询结果转换为 DGL 对象:

from hugegraph_ml.data.hugegraph2dgl import HugeGraph2DGL

hg2d = HugeGraph2DGL(
    url="http://127.0.0.1:8080",
    graph="hugegraph",
    user="",
    pwd="",
    graphspace=None,
)
方法返回值说明
convert_graph(vertex_label, edge_label, feat_key="feat", label_key="label", mask_keys=None)dgl.DGLGraphmask_keys 为空时取 ["train_mask", "val_mask", "test_mask"]
convert_hetero_graph(vertex_labels, edge_labels, feat_key="feat", label_key="label", mask_keys=None)DGL 异构图参数为标签列表
convert_graph_dataset(graph_vertex_label, vertex_label, edge_label, feat_key="feat", label_key="label")HugeGraphDatasetinfo 中写入 n_graphsmax_n_nodesn_feat_dimn_classes
convert_graph_nx(vertex_label, edge_label)networkx.GraphP-GNN 使用
convert_graph_with_edge_feat(vertex_label, edge_label, node_feat_key="feat", edge_feat_key="edge_feat", label_key="label", mask_keys=None)dgl.DGLGraph同时填充 edata["feat"]
convert_graph_ogb(vertex_label, edge_label, split_label)(dgl.DGLGraph, split_edge)SEAL 使用
convert_hetero_graph_bgnn(vertex_labels, edge_labels, feat_key="feat", label_key="class", cat_key="cat_features", mask_keys=None)DGL 异构图BGNN 使用

节点特征写入 ndata["feat"],标签写入 ndata["label"],各掩码写入 ndata[<mask key>]NodeEmbed 只要求 featNodeClassifyNodeClassifyWithEdgeNodeClassifyWithSample 要求 featlabeltrain_maskval_masktest_mask,缺少任意一项都会抛出 ValueError

导入示例数据集

hugegraph_ml.utils.dgl2hugegraph_utils 负责把 DGL、OGB 和 NetworkX 数据集写入 HugeGraph,供转换层读取。这些函数都接受与 HugeGraph2DGL 相同的 urlgraphuserpwdgraphspace 参数,并且多数会先把数据集名转为大写再匹配。

函数支持的数据集创建的标签
import_graph_from_dglCORACITESEERPUBMED<NAME>_vertex<NAME>_edge
import_graphs_from_dglMUTAGCOLLABNCI1PROTEINSPTCENZYMESDD<NAME>_graph_vertex<NAME>_vertex<NAME>_edge
import_hetero_graph_from_dglACM<NAME>_<ntype>_v<NAME>_<etype>_e
import_hetero_graph_from_dgl_no_featAMAZONGATNE<NAME>_<ntype>_v<NAME>_<etype>_e
import_hetero_graph_from_dgl_bgnnAVAZU<NAME>_<ntype>_v<NAME>_<etype>_e
import_graph_from_nxCAVEMAN<NAME>_vertex<NAME>_edge
import_graph_from_dgl_with_edge_featCORACITESEERPUBMED<NAME>_edge_feat_vertex<NAME>_edge_feat_edge
import_graph_from_ogbogbl-collab,不做大写转换<NAME>_vertex<NAME>_edge
import_split_edge_from_ogbogbl-collab,不做大写转换<NAME>_split_edge

传入其他名称会抛出 ValueError("dataset not supported")import_split_edge_from_ogb 还需要顶点导入返回的 idx_to_vertex_id 映射和 max_nodes 上限。

clear_all_data() 会清空目标图中的全部点和边。测试 fixture 先调用它,再导入 CORAMUTAGACM,结束时再次调用。

AMAZONGATNEAVAZU 不会自动下载,压缩包地址写在 import_hetero_graph_from_dgl_no_featimport_hetero_graph_from_dgl_bgnn 上方的注释里。

任务

任务类位于 hugegraph-ml/src/hugegraph_ml/tasks/,均接收转换后的图和模型实例。

模块入口方法
NodeEmbednode_embed.pytrain_and_embed(add_self_loop=True, lr=1e-3, weight_decay=0, n_epochs=200, patience=inf, gpu=-1),返回 ndata["feat"] 被替换为嵌入结果的图
NodeClassifynode_classify.pytrain(lr, weight_decay, n_epochs, patience, early_stopping_monitor, gpu),再 evaluate() 返回 {"accuracy": ..., "loss": ...}
NodeClassifyWithEdgenode_classify_with_edge.py结构相同,适用于同时读取 edata["feat"] 的模型
NodeClassifyWithSamplenode_classify_with_sample.py基于 ClusterGCNSampler 分区的训练,仅使用 CPU,没有 gpu 参数
GraphClassifygraph_classify.pytrain(batch_size=20, lr, weight_decay, n_epochs, patience, early_stopping_monitor, clip=2.0, gpu),在 HugeGraphDataset 上按 70/20/10 划分
DetectorCaregnnfraud_detector_caregnn.pyCARE-GNN 训练,evaluate() 输出 recall 和 ROC AUC,并读取 ndata["feature"] 而非 ndata["feat"]
HeteroSampleEmbedGATNEhetero_sample_embed_gatne.pytrain_and_embed(lr=1e-3, n_epochs=200, gpu=-1)
LinkPredictionPGNNlink_prediction_pgnn.pytrain(lr, weight_decay, n_epochs, gpu)
LinkPredictionSeallink_prediction_seal.py构造函数内部已调用 data_prepare(),随后执行 train(lr=1e-3, n_epochs=200, gpu=-1)

patience 默认值为 float("inf")utils/early_stopping.py 中的 EarlyStopping 可以监控 lossaccuracy,保存最优权重并在训练结束时恢复。

可运行示例

脚本位于 hugegraph-ml/src/hugegraph_ml/examples/。在 hugegraph-ml/src 目录下执行:

python ./hugegraph_ml/examples/dgi_example.py

每个脚本同时提供同名函数,可以导入后用较小的 epoch 数调用。

脚本模型任务读取的标签
agnn_example.pyAGNNNodeClassifyCORA_vertexCORA_edge
appnp_example.pyAPPNPNodeClassifyCORA_vertexCORA_edge
arma_example.pyARMA4NCNodeClassifyCORA_vertexCORA_edge
bgnn_example.pyBGNNPredictor模型自带的 fit()AVAZU__N_vAVAZU__E_e
bgrl_example.pyBGRLNodeEmbedNodeClassifyCORA_vertexCORA_edge
care_gnn_example.pyCAREGNNDetectorCaregnnAMAZON_user_v 以及 AMAZON_net_upu_eAMAZON_net_usu_eAMAZON_net_uvu_e
cluster_gcn_example.pySAGENodeClassifyWithSampleCORA_vertexCORA_edge
correct_and_smooth_example.pycorrect_and_smooth 中的 MLPNodeClassifyCORA_vertexCORA_edge
dagnn_example.pyDAGNNNodeClassifyCORA_vertexCORA_edge
deepergcn_example.pyDeeperGCNNodeClassifyWithEdge通过 convert_graph_with_edge_feat 读取 CORA_vertexCORA_edge
dgi_example.pyDGINodeEmbedNodeClassifyCORA_vertexCORA_edge
diffpool_example.pyDiffPoolGraphClassifyMUTAG_graph_vertexMUTAG_vertexMUTAG_edge
gatne_example.pyDGLGATNEHeteroSampleEmbedGATNEAMAZONGATNE__N_vAMAZONGATNE_1_eAMAZONGATNE_2_e
gin_example.pyGINGraphClassifyMUTAG_graph_vertexMUTAG_vertexMUTAG_edge
grace_example.pyGRACENodeEmbedNodeClassifyCORA_vertexCORA_edge
grand_example.pyGRANDNodeClassifyCORA_vertexCORA_edge
jknet_example.pyJKNetNodeClassifyCORA_vertexCORA_edge
pgnn_example.pyPGNNLinkPredictionPGNNCAVEMAN_vertexCAVEMAN_edge
seal_example.pyDGCNNLinkPredictionSealogbl-collab_vertexogbl-collab_edgeogbl-collab_split_edge

DGI 节点嵌入示例

先把 DGL 的 Cora 数据集导入 HugeGraph。数据集名会先转为大写,因此 coraCORA 都会生成 CORA_vertexCORA_edge 标签:

from hugegraph_ml.utils.dgl2hugegraph_utils import import_graph_from_dgl

import_graph_from_dgl("cora")

读取图并训练 DGI:

from hugegraph_ml.data.hugegraph2dgl import HugeGraph2DGL
from hugegraph_ml.models.dgi import DGI
from hugegraph_ml.models.mlp import MLPClassifier
from hugegraph_ml.tasks.node_classify import NodeClassify
from hugegraph_ml.tasks.node_embed import NodeEmbed

hg2d = HugeGraph2DGL()
graph = hg2d.convert_graph(
    vertex_label="CORA_vertex",
    edge_label="CORA_edge",
)

embed_model = DGI(n_in_feats=graph.ndata["feat"].shape[1])
embed_task = NodeEmbed(graph=graph, model=embed_model)
embedded_graph = embed_task.train_and_embed(
    add_self_loop=True,
    n_epochs=300,
    patience=30,
)

classifier = MLPClassifier(
    n_in_feat=embedded_graph.ndata["feat"].shape[1],
    n_out_feat=embedded_graph.ndata["label"].unique().shape[0],
)
classify_task = NodeClassify(graph=embedded_graph, model=classifier)
classify_task.train(lr=1e-3, n_epochs=400, patience=40)
print(classify_task.evaluate())

evaluate() 返回类似 {'accuracy': 0.82, 'loss': 0.5714246034622192} 的字典。完整脚本是 hugegraph-ml/src/hugegraph_ml/examples/dgi_example.py

GRAND 节点分类示例

from hugegraph_ml.data.hugegraph2dgl import HugeGraph2DGL
from hugegraph_ml.models.grand import GRAND
from hugegraph_ml.tasks.node_classify import NodeClassify

hg2d = HugeGraph2DGL()
graph = hg2d.convert_graph(
    vertex_label="CORA_vertex",
    edge_label="CORA_edge",
)
model = GRAND(
    n_in_feats=graph.ndata["feat"].shape[1],
    n_out_feats=graph.ndata["label"].unique().shape[0],
)
task = NodeClassify(graph, model)
task.train(lr=1e-2, weight_decay=5e-4, n_epochs=2000, patience=100)
print(task.evaluate())

GRAND 每次增强采样都会返回一组 logits,NodeClassify 会对列表中的每个元素分别应用掩码后再计算损失。完整脚本是 hugegraph-ml/src/hugegraph_ml/examples/grand_example.py

排查问题

  • 连接失败:检查 HugeGraph Server 地址、端口和认证信息。
  • Schema 不匹配:示例默认使用 CORA_vertexCORA_edge,自有数据需要传入实际标签。
  • ValueError: Graph is missing required node attribute ...:节点分类任务需要 ndata 中包含 featlabeltrain_maskval_masktest_mask。请导入带掩码的数据集,或给 convert_graph 传入自定义的 mask_keys
  • ValueError: dataset not supported:导入函数只接受上表列出的名称,且 import_graph_from_ogb 匹配 ogbl-collab 时不做大写转换。
  • DGL 或 PyTorch 导入失败:回到仓库根目录重新执行 uv sync --extra ml,并确认当前 Python 来自根目录 .venv
  • bgrl_example.py 目前在导入阶段就会失败:它从 hugegraph_ml.models.bgrl 导入 MLP_Predictor,而该模块中的类名是 MLPPredictor
  • care_gnn_example.py 读取 AMAZON_user_v 和三个 AMAZON_net_*_e 边标签,仓库内没有对应的导入函数,需要自行准备该数据集后再运行。