图采样

图采样是管理大规模图数据的有效技术,在GraphSAGE框架为代表的编程范式中得到广泛应用。采样能减小数据规模,并通过数据对齐使基于张量的计算框架能够高效处理。

在采样之前,我们需要提供种子,这些种子可以是节点或边。相应地,GLE提供了图遍历操作符来为批量采样准备种子:

  • 节点采样器

  • 边采样器

那么,用户对采样的需求可以被抽象并归类为GLE中的以下几类操作:

  • 邻域采样。

  • 子图采样。

  • 负采样。

邻域采样(Neighborhood Sampling)涉及根据输入顶点选择一跳或多跳相邻顶点,以构建GCN理论中的感知域。邻域采样的输入可以来自图遍历输出或其他外部数据源。

子图采样涉及一跳或多跳的顶点,以及所有源顶点和目标顶点已被采样的边,从而形成一个子图。随着GNN表达能力研究的进展,这种采样方法变得越来越重要。

负采样会选择与输入顶点不直接相连的顶点,这种方法通常用于无监督学习。

图遍历

在图神经网络(GNN)中,图遍历与传统图计算具有不同的语义。主流深度学习算法的训练模型通过批次进行迭代。为满足这一需求,数据必须能够按批次访问,我们将这种数据访问模式称为遍历。在GNN算法中,数据源是图结构,训练样本通常由图的顶点和边组成。图遍历指的是为算法提供按批次访问顶点、边或子图的能力。

目前GLE支持对顶点和边进行批量遍历。这种随机遍历可以是不回放或回放模式。在不回放遍历中,每当一个周期结束时都会触发gl.OutOfRangeError。被遍历的数据源是分区的,即当前工作节点(在分布式TF情况下)仅遍历与其对应的Server上的数据。

关于图遍历的使用方法和接口,请查看GLE的遍历部分获取更多详情。

邻域采样

每种采样操作都支持不同的实现策略,例如随机采样和基于边权重的采样。通过实际生产应用,我们已积累了10多种采样算子,并开放了算子编程接口,允许用户自定义以满足不断演进的图神经网络需求。

对于采样策略,GLE目前支持以下采样策略,对应生成NeighborSampler对象时的strategy参数。

策略

描述

edge_weight

按边权重概率采样

随机

带替换的随机

topk

Return the neighbors with edge weight topK, if there are not enough neighbors, refer to the padding rule.

in_degree

按顶点度进行概率采样。

full

返回所有邻居节点,expand_factor参数不起作用,结果对象为SparseNodes或SparseEdges。

接下来是一个邻居采样的示例:

示例:

如下图所示,从类型为user的顶点出发,采样其2跳邻居,并将结果以层级形式返回,包含layer1和layer2。层级索引从1开始,即1跳邻居为layer1,2跳邻居为layer2。

2 hop sampling

s = g.neighbor_sampler(["buy", "i2i"], expand_factor=[2, 2])
l = s.get(ids) # input ids: shape=(batch_size)

# Nodes object
# shape=(batch_size, expand_factor[0])
l.layer_nodes(1).ids
l.layer_nodes(1).int_attrs

 # Edges object
 # shape=(batch_size * expand_factor[0], expand_factor[1])
l.layer_edges(2).weights
l.layer_edges(2).float_attrs

关于邻域采样的使用方法和接口,请查阅GLE的采样部分获取更多详情。

子图采样

与EgoGraph不同,SubGraph包含了图拓扑的edge_index,因此消息传递路径(前向计算路径)可以直接由edge_index确定,卷积层的实现可以直接通过edge_index和节点/边数据来完成。此外,SubGraph与PyG中的Data完全兼容,因此可以复用PyG的模型部分。

子图采样涉及一跳或多跳的顶点,以及所有源顶点和目标顶点已被采样的边,这些元素共同构成一个子图。

随着GNN表达能力研究的深入,这种采样方法变得越来越重要。

负采样

负采样指的是对与给定顶点无直接边关系的顶点进行采样。与邻居采样类似,负采样有不同的实现策略,例如随机采样、基于节点入度等。作为GNN的常见算子,负采样支持扩展和面向场景的定制。此外,GLE还提供了按指定属性条件进行负采样的能力。

GLE目前支持以下负采样策略,对应生成NegativeSampler对象时的strategy参数。

策略

描述

random

随机负采样,不保证是真实负样本

in_degree

基于顶点入度分布的负采样概率,确保真实负样本

node_weight

基于顶点权重概率的负采样,真负样本

以下是一个负采样示例:

示例:

es = g.edge_sampler("buy", batch_size=3, strategy="random")
ns = g.negative_sampler("buy", 5, strategy="random")

for i in range(5):
    edges = es.get()
    neg_nodes = ns.get(edges.src_ids)
    
    print(neg_nodes.ids) # shape is (3, 5)
    print(neg_nodes.int_attrs) # shape is (3, 5, count(int_attrs))
    print(neg_nodes.float_attrs) # shape as (3, 5, count(float_attrs))

关于负采样的使用方法和接口,请查阅GLE的负采样部分获取更多详情。

GSL

GLE将采样操作抽象为一组接口,称为GSL(图采样语言)。通常,图采样包含以下几种类别。

  • 遍历类型(Traverse),用于从图中批量获取点或边的数据。

  • 关系型(邻域、子图),用于获取点的N跳邻域或生成由点组成的子图以构建训练样本。

  • 负采样(Negative),与关系型相对,通常用于无监督训练场景中生成负例样本。

例如,在“用户点击产品”的异构图场景中,“随机采样64个用户,并根据边权重为每个用户采样10个相关产品”。这可以通过GSL表示为

g.V("user").batch(64).outV("click").sample(10).by("edge_weight")

考虑到实际图数据的特性,GSL支持超大图、异构图和属性图,其语法设计接近Gremlin形式以便于理解。

更多详情,请查看GLE的GSL部分