GraphConv

class dgl.nn.pytorch.conv.GraphConv(in_feats, out_feats, norm='both', weight=True, bias=True, activation=None, allow_zero_in_degree=False)[source]

基类:Module

图卷积层,来自 Semi-Supervised Classification with Graph Convolutional Networks

其数学定义如下:

\[h_i^{(l+1)} = \sigma(b^{(l)} + \sum_{j\in\mathcal{N}(i)}\frac{1}{c_{ji}}h_j^{(l)}W^{(l)})\]

其中 \(\mathcal{N}(i)\) 是节点 \(i\) 的邻居集合,\(c_{ji}\) 是节点度的平方根的乘积(即 \(c_{ji} = \sqrt{|\mathcal{N}(j)|}\sqrt{|\mathcal{N}(i)|}\)),\(\sigma\) 是一个激活函数。

如果提供了每条边的权重张量,加权图卷积定义为:

\[h_i^{(l+1)} = \sigma(b^{(l)} + \sum_{j\in\mathcal{N}(i)}\frac{e_{ji}}{c_{ji}}h_j^{(l)}W^{(l)})\]

其中 \(e_{ji}\) 是从节点 \(j\) 到节点 \(i\) 的边的标量权重。这与论文中的加权图卷积网络公式不等价。

要自定义归一化项 \(c_{ji}\),可以首先将模型的 norm 设置为 'none',然后将预归一化的 \(e_{ji}\) 传递给前向计算。我们提供了 EdgeWeightNorm,用于按照 GCN 论文对标量边权重进行归一化。

参数:
  • in_feats (int) – 输入特征大小;即 \(h_j^{(l)}\) 的维数。

  • out_feats (int) – 输出特征大小;即 \(h_i^{(l+1)}\) 的维数。

  • norm (str, 可选) –

    如何应用归一化器。可以是以下值之一:

    • right,将聚合后的消息除以每个节点的入度,这等价于对接收到的消息求平均。

    • none,不应用任何归一化。

    • both (默认),消息按上面的 \(1/c_{ji}\) 进行缩放,等价于对称归一化。

    • left,将从每个节点发出的消息除以其出度,等价于随机游走归一化。

  • weight (bool, 可选) – 如果为 True,应用一个线性层。否则,在没有权重矩阵的情况下聚合消息。

  • bias (bool, 可选) – 如果为 True,在输出中添加一个可学习的偏置。默认值:True

  • activation (可调用的激活函数/层None, 可选) – 如果不为 None,则对更新后的节点特征应用激活函数。默认值:None

  • allow_zero_in_degree (bool, 可选) – 如果图中存在入度为 0 的节点,则这些节点的输出将无效,因为没有消息会传递到这些节点。这对于某些应用是有害的,会导致隐性性能下降。如果此模块在输入图中检测到入度为 0 的节点,将引发 DGLError。通过将其设置为 True,将抑制此检查,并让用户自行处理。默认值:False

weight

可学习的权重张量。

类型:

torch.Tensor

bias

可学习的偏置张量。

类型:

torch.Tensor

注意

入度为零的节点将导致输出值无效。这是因为没有消息会传递到这些节点,聚合函数将应用于空输入。避免这种情况的一种常见做法是,如果图是同构的,则为图中的每个节点添加自环,这可以通过以下方式实现:

>>> g = ... # a DGLGraph
>>> g = dgl.add_self_loop(g)

调用 add_self_loop 对于某些图可能无效,例如异构图,因为无法为自环边确定边类型。对于这些情况,将 allow_zero_in_degree 设置为 True 以解除代码阻塞并手动处理入度为零的节点。一种常见的处理方法是在卷积后过滤掉入度为零的节点。

示例

>>> import dgl
>>> import numpy as np
>>> import torch as th
>>> from dgl.nn import GraphConv
>>> # Case 1: Homogeneous graph
>>> g = dgl.graph(([0,1,2,3,2,5], [1,2,3,4,0,3]))
>>> g = dgl.add_self_loop(g)
>>> feat = th.ones(6, 10)
>>> conv = GraphConv(10, 2, norm='both', weight=True, bias=True)
>>> res = conv(g, feat)
>>> print(res)
tensor([[ 1.3326, -0.2797],
        [ 1.4673, -0.3080],
        [ 1.3326, -0.2797],
        [ 1.6871, -0.3541],
        [ 1.7711, -0.3717],
        [ 1.0375, -0.2178]], grad_fn=<AddBackward0>)
>>> # allow_zero_in_degree example
>>> g = dgl.graph(([0,1,2,3,2,5], [1,2,3,4,0,3]))
>>> conv = GraphConv(10, 2, norm='both', weight=True, bias=True, allow_zero_in_degree=True)
>>> res = conv(g, feat)
>>> print(res)
tensor([[-0.2473, -0.4631],
        [-0.3497, -0.6549],
        [-0.3497, -0.6549],
        [-0.4221, -0.7905],
        [-0.3497, -0.6549],
        [ 0.0000,  0.0000]], grad_fn=<AddBackward0>)
>>> # Case 2: Unidirectional bipartite graph
>>> u = [0, 1, 0, 0, 1]
>>> v = [0, 1, 2, 3, 2]
>>> g = dgl.heterograph({('_U', '_E', '_V') : (u, v)})
>>> u_fea = th.rand(2, 5)
>>> v_fea = th.rand(4, 5)
>>> conv = GraphConv(5, 2, norm='both', weight=True, bias=True)
>>> res = conv(g, (u_fea, v_fea))
>>> res
tensor([[-0.2994,  0.6106],
        [-0.4482,  0.5540],
        [-0.5287,  0.8235],
        [-0.2994,  0.6106]], grad_fn=<AddBackward0>)
forward(graph, feat, weight=None, edge_weight=None)[source]

描述

计算图卷积。

参数 graph:

图。

类型 graph:

DGLGraph

参数 feat:

如果给定一个 torch.Tensor,它表示形状为 \((N, D_{in})\) 的输入特征,其中 \(D_{in}\) 是输入特征的大小,\(N\) 是节点数量。如果给定一对 torch.Tensor(适用于二分图),这对张量必须包含形状为 \((N_{in}, D_{in_{src}})\)\((N_{out}, D_{in_{dst}})\) 的两个张量。

类型 feat:

torch.Tensor 或一对 torch.Tensor

参数 weight:

可选的外部权重张量。

类型 weight:

torch.Tensor, 可选

参数 edge_weight:

可选的边上的张量。如果给定,卷积将根据消息进行加权。

类型 edge_weight:

torch.Tensor, 可选

返回值:

输出特征

返回类型:

torch.Tensor

引发 DGLError:

情况 1:如果输入图中存在入度为 0 的节点,将引发 DGLError,因为没有消息会传递到这些节点。这将导致输出无效。通过将 allow_zero_in_degree 参数设置为 True,可以忽略此错误。情况 2:提供了外部权重,同时模块自身也定义了权重参数。

注意

  • 输入形状:\((N, *, \text{in_feats})\),其中 * 表示任意数量的附加维度,\(N\) 是节点数量。

  • 输出形状:\((N, *, \text{out_feats})\),其中除最后一个维度外,所有其他维度与输入形状相同。

  • 权重形状:\((\text{in_feats}, \text{out_feats})\)

reset_parameters()[source]

描述

重新初始化可学习参数。

注意

模型参数的初始化遵循原始实现,其中权重 \(W^{(l)}\) 使用 Glorot 均匀初始化,偏置初始化为零。