SEAL链路预测代码函数功能

SEAL是一个链路预测框架,它将问题转化为子图分类。通过提取封闭子图并利用双半径节点标记法为节点分配结构标签,结合节点嵌入和图神经网络(如DGCNN)进行预测。该框架适用于多种数据集,包括OGB和自定义网络,并且可以与传统的启发式方法如共同邻居和Adamic-Adar协同工作,提高性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、DGL库实现版本

utilis.py

  • parse_arguments()
  • load_ogb_dataset(dataset)
    ogb:神经网络基准数据集库
    返回:一张图,划分好的边(测试,训练,验证)
  • drnl_node_labeling(subgraph, src, dst)
    双半径节点标记法,获得节点在子图里的位置标记
    返回:节点位置标记
  • evaluate_hits(name, pos_pred, neg_pred, K)
    正负样本命中数值

sampler.py

import 节点标记函数 drnl_node_labeling(subgraph, src, dst)

  • class GraphDataSet(Dataset)
    节点list,节点tensor,节点和tensor的索引

  • class PosNegEdgesGenerator(object)
    生成正负样本
    参数:

    1. 图,
    2. 划分好的边,
    3. 每一个正样本对应的负样本个数,
    4. 子样本的比例
    • subsample(self, edges, subsample_ratio)
      返回:子样本所有边的tensor
  • class EdgeDataSet(Dataset):
    用于加速SEALSampler的辅助数据集

  • class SEALSampler(object):
    两节点周围的K跳邻居采样(构成封闭子图)

    • sample_subgraph(self, target_nodes):
      两个节点的tensor,返回两节点所在的封闭子图
    • _collate(self, batch):
      将 n 张小图打包在一起,生成一张含 n 个不相连小图的大图
      将几个label的tensor生成一个新tensor
      返回:一张大图,一个新tensor
  • class SEALData(object):
    生成正负样本
    打印:
    Load existing processed {} files :加载已处理的{}文件
    Generate {} edges totally :完全生成{}边
    Save preprocessed subgraph to :将预处理的子图保存到{}

model.py

  • class GCN(nn.Module):
    利用邻居更新节点emb
  • class DGCNN(nn.Module):

整个GN块的处理包含了三次update操作和三次聚合操作:

1.通过原始Edge,起始Node信息,全局信息共同update Edge;

2.通过当前Node 的信息,更新后Edge的信息,全局信息共同update Node;

3.通过更新后Edge、Node信息,和当前的全局信息共同update global;

4.每次更新后,聚合更新前的特征信息和更新后的特征信息作为当前的特征信息。

main

from model import DGCNN, GCN
from sampler import SEALData (生成正负样本)
from utils import evaluate_hits, load_ogb_dataset, parse_arguments
(计算正负样本命中率,/ 一张图,划分好的边(测试,训练,验证)/ 参数解析器)

  • def train():
  • def evaluate(model, dataloader, device):
  • def main(args, print_fn=print):

if name == “main”:
args = parse_arguments()
logger = LightLogging(log_name=“SEAL”, log_path=“./logs”)
main(args, logger.info)


核心:学习一个映射,将子图模式 -> 边的存在性
输入:(A,X)
A是封闭子图的邻接矩阵
X是节点信息矩阵,其中每一行是一个节点的特征向量

如何构造X是重点:
首先,X由:结构节点标签、节点嵌入,节点属性三部分组成

第一个组件是每个节点的结构标签

在这里插入图片描述

  • 构造一个映射函数:给封闭子图里的每一个节点赋予一个整数标签
  • 利用代码:utilis.py 里的 drnl_node_labeling(subgraph, src, dst)
  • 双半径节点标记法,获得节点在子图里的位置标记
    返回:节点位置标记 7/2/3

1)中心节点x和y是链路所处的目标节点( src, dst )
2)与中心相对位置不同的节点对链路具有不同的结构重要性。

  • 在得到标签后,我们使用它们的one-hot编码向量来构造X

  • 节点标签函数用在了 def sample_subgraph(self, target_nodes):
    target_nodes(Tensor):两个目标节点的张量
    返回:子图(DGLGraph):子图,返回一个节点数据视图,用于设置/获取节点特性

z = drnl_node_labeling(subgraph, u_id, v_id)
subgraph.ndata["z"] = z

在这里插入图片描述
以两个目标节点为基准,利用双半径节点标记法,为子图里的所有节点标记,最终获得子图的节点特征(结构标签)。

第二个组件:节点嵌入

  • Given:网络G = (V, E),一组正样本训练边集合Ep⊆E,一组负样本边集合En( En∩E =∅ ,负样本边不属于边集)
  • 如果直接在G上生成节点嵌入,则节点嵌入将包含:训练边集的边存在信息,因为正样本边属于边集。
  • 我们观察到GNN进行节点嵌入时,可以快速发现这类链路存在信息, 导致正负样本获得的信息有差异。
  • 我们的方法是:暂时把负样本En加到E中,并生成节点在新图上的嵌入:G0 = (V, E∪En),使得正负训练集都能在嵌入中加入相同的链路存在信息。

两种方法获得节点嵌入:使用GNN或节点嵌入。

  • DGCNN作为默认GNN
  • node2vec作为默认嵌入

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

总的来说,Node2vec的流程如下:

  1. 使用改进的随机游走的方法(BFS和DFS的混合)产生采样节点序列。
  2. 将生成的序列通过word2vec模型进行embedding

Official实现版本

总结:
【Main.py使用】
找data name = none 的代码(75-82, 98-112, 120-128) train-name test-name is not none 的,没有use embedding 和use attributes
利用util里的sample_neg生成不重叠的neg_train和neg_test

链路预测代码的困难:服务器崩溃(经常需要重新训练),
社团发现算法的实现困难:先调试类似的小数据集跑社团发现代码,再修改我们的数据集作为输入调试,数据集和测试数据相差十倍,导致可视化运行的时候速度很慢(还在找解决方法),提供了六种社团发现算法,还要逐步应用于数据集比较可视化的性能
八个数据集:SAir NS PB Yeast Celegans Power Router Ecoli

python Main.py --data-name XXX --hop 'auto' --batch-size 1

1.输入“python Main.py——data-name USAir”在USAir网络上尝试SEAL。
在命令后面附加“——seed Y”来使用其他种子。在数据集XXX上再现本文表1中的实验结果。
默认种子为1。
在这里插入图片描述

  1. python Main.py --data-name NS –test-ratio 0.5 --hop ‘auto’ –use-embedding

2.在NS网络上运行SEAL

  • 随机移除50% 观察到的链路作为测试链路
  • 跳数自动从{1,2}设置
  • 并包括node2vec嵌入
  1. python Main.py --data-name PPI_subgraph –test-ratio 0.5 --use-embedding --use-attribute
  1. 在包含节点属性的PPI_subgraph上运行SEAL。
  • 并包括node2vec嵌入
  • 随机移除50% 观察到的链路作为测试链路
  • 假定节点属性保存在.mat文件的组中。
  1. python Main.py –train-name PB_train.txt --test-name PB_test.txt --hop 1
  1. 在自定义分割上的训练和测试边集上运行SEAL
  • “PB_train.txt”的每一行是一个观察到的训练边
  • “PB_test.txt”的每一行是一个未观察到的测试边
    • 注意,“PB_train.txt”中的边将用于构建观测到的网络,但不需要用“PB_train.txt”中的所有边训练SEAL,特别是当观测到的链接数量很大时。
    • 例如,要设置要训练的最大边数,可以附加“—max-train-num 10000”

    • 当1跳邻居过多时,例如twitter网络中的一个中心节点拥有数百万个追随者。添加**“——max-nodes-per-hop 100”**使用随机抽样将1hop邻居数量限制在100以下。

  1. python Main.py –data-name PB –train-name PB_train.txt --test-name PB_test.txt --hop 1
  • 仍然使用正训练边集“PB_train.txt”和测试边集“PB_test.txt”
  • 但使用“PB. mat”中包含的网络。
    (如果“PB.mat”中有一个组,则可以使用 ——use-attribute)

如果希望使用SEAL输出未知链路的链路存在概率,请使用4.

  1. python Main.py --train-name PB_train.txt –test-name PB_val.txt --hop 1 –save-model
  • PB_val.txt是验证模型的边集
  • —save-model”将最终模型保存到data/PB_model.pth
  1. python Main.py --train-name PB_train.txt –test-name PB_test.txt --hop 1 –only-predict
  1. PB_test.txt 是想要输出边存在概率的节点对(它可能同时包含正负连边)
  • 加载已保存的模型,并将“PB_test.txt”的预测结果输出到“data/PB_test_pred.txt”

SEAL代码(从子图、嵌入和属性中学习链接预测)。
SEAL是一种新的链路预测框架,它将链路预测系统地转化为子图分类问题。

对于每个目标链路,SEAL提取其h-hop封闭子图A,并构建其节点信息矩阵X(包含结构节点标签、潜在嵌入和节点的显式属性)。
然后,SEAL将(A, X)输入到图神经网络(GNN)中对链路存在性进行分类,使其可以同时从图结构特征(从A)和潜在/显式特征(从X)中学习,进行链路预测。

  • 对于SEAL来说,嵌入和属性都不是必需的。
  • 在大多数网络中,SEAL可以学习一个非常好的模型,而不需要使用任何嵌入或属性(因此利用纯图结构)。
  • 正如实验所示,在X中包含嵌入甚至可能会损害性能。
  • 如果X中不包含节点嵌入,SEAL将成为归纳式链路预测模型。

util_function.py

def sample_neg(net, test_ratio=0.1, train_pos=None, test_pos=None, max_train_num=None, all_unknown_as_negative=False):
返回:正负样本的测试集和训练集
train_pos, train_neg, test_pos, test_neg

def links2subgraphs(A, train_pos, train_neg, test_pos, test_neg, h=1, max_nodes_per_hop=None, node_information=None, no_parallel=False):
返回:训练封闭子图集,测试封闭子图集,?
return train_graphs, test_graphs, max_n_label[‘value’]

def parallel_worker(x):
返回:提取的子图标签
subgraph_extraction_labeling

subgraph_extraction_labeling(ind, A, h=1, max_nodes_per_hop=None, node_information=None):
返回:子图,字体节点标签,节点特征
return g, labels.tolist(), features

def neighbors(fringe, A):
返回:边缘节点集的一跳邻居集

def node_label(subgraph):
提出的双半径节点标记(DRNL)的实现
返回:子图节点位置标签集

def generate_node2vec_embeddings(A, emd_size=128, negative_injection=False, train_neg=None):
返回:node2vec嵌入

def AA(A, test_pos, test_neg):
返回:Adamic-Adar score
return CalcAUC(sim, test_pos, test_neg)

def CN(A, test_pos, test_neg):
返回:共同邻居得分

def CalcAUC(sim, test_pos, test_neg):
返回:AUC
return auc


Pytorch实现版本

  • 这个存储库用PyTorch-Geometric库重新实现了SEAL,并在开放图形基准测试(OGB)数据集上测试SEAL。
    在提交时,SEAL在OGB排行榜的4个链接预测数据集中的3个中排名第一。
    它还支持类似plantoid的数据集,如Cora, CiteSeer和PubMed,其中使用随机0.85/0.05/0.1分割和AUC度量。
    使用自定义数据集也很容易,可以用自己的数据集替换Planetoid数据集。

  • 前文提到X中可以不需要节点嵌入和节点属性,aka:
    SEAL是一种基于gnn的链路预测方法:

    1. 为每个目标链路提取一个k跳包围子图
    2. 应用一种称为双半径节点标记(DRNL)的标记技巧给每个节点一个整数标签作为其附加特征。
    3. 这些标记的封闭子图被馈送到图神经网络DGCNN来预测链接的存在。
  • 第三步GNN可以用启发式方法替代:Common Neighbor (CN)和adam Adar (AA)
    它们在ogbl-ppa和ogbl-collab上的性能比许多GNN方法好得多。
    Common Neighbor应用命令:

    python seal_link_pred.py --use_heuristic CN --dataset ogbl-ppa
    

utils.py

def neighbors(fringe, A, outgoing=True):

  • 找到图A的一跳邻居集
    A是scipy的CSR类型压缩矩阵
    outgoing表示是否是有向图

def k_hop_subgraph(src, dst, num_hops, A, sample_ratio=1.0,
max_nodes_per_hop=None, node_features=None,
y=1, directed=False, A_csc=None):

  • 从图A中找到(u,v )边的k-hop封闭子图
    返回:节点集,子图,节点特征

def drnl_node_labeling(adj, src, dst):

  • 返回:子图节点的双半径节点标记(DRNL)

def de_node_labeling(adj, src, dst, max_dist=3):

  • 返回:节点距离编码
    def de_plus_node_labeling(adj, src, dst, max_dist=100):
    距离编码plus,本质与DRNL相同

def construct_pyg_graph(node_ids, adj, dists, node_features, y, node_label=‘drnl’):

  • 返回:从scipy csr邻接矩阵构造pytorch_geometric图

def extract_enclosing_subgraphs(link_index, A, x, y, num_hops, node_label=‘drnl’,
ratio_per_hop=1.0, max_nodes_per_hop=None,
directed=False, A_csc=None):

  • 从图A中为link_index中的所有边提取封闭子图

def do_edge_split(dataset, fast_split=False, val_ratio=0.05, test_ratio=0.1):

  • 数据集边分割,验证训练测试

def get_pos_neg_edges(split, split_edge, edge_index, num_nodes, percent=100):

  • 获得正负样本边集

计算共同邻居启发式得分,亚当-阿达尔启发式评分,个性化PageRank启发式评分。

models.py

构造了GCN,SAGE,DGCNN,GIN四个网络

seal_link_pred.py

构造了SEALDataset类:
  • 初始化
  • 处理文件名
  • 处理数据集
    • 用权重将多条边压缩成单边
    • 提取正负样本边集的封闭子图
构造SEALDynamicDataset类:
  • 初始化
    • 用权重将多条边压缩成单边
def train() def test()
def test_multiple_models
def evaluate_hits评估命中率
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

炖鹅小铁锅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值