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]

Bases: Module

图卷积层来自使用图卷积网络进行半监督分类

数学上定义如下:

\[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 论文中的方法归一化标量边权重。

Parameters:
  • in_feats (int) – Input feature size; i.e, the number of dimensions of \(h_j^{(l)}\).

  • out_feats (int) – Output feature size; i.e., the number of dimensions of \(h_i^{(l+1)}\).

  • norm (str, optional) –

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

    • right,将聚合的消息除以每个节点的入度,相当于平均接收到的消息。

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

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

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

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

  • bias (bool, optional) – If True, adds a learnable bias to the output. Default: True.

  • activation (callable activation function/layer or None, optional) – If not None, applies an activation function to the updated node features. Default: None.

  • allow_zero_in_degree (bool, optional) – If there are 0-in-degree nodes in the graph, output for those nodes will be invalid since no message will be passed to those nodes. This is harmful for some applications causing silent performance regression. This module will raise a DGLError if it detects 0-in-degree nodes in input graph. By setting True, it will suppress the check and let the users handle it by themselves. Default: False.

weight

可学习的权重张量。

Type:

torch.Tensor

bias

可学习的偏置张量。

Type:

torch.Tensor

注意

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

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

Calling add_self_loop will not work for some graphs, for example, heterogeneous graph since the edge type can not be decided for self_loop edges. Set allow_zero_in_degree to True for those cases to unblock the code and handle zero-in-degree nodes manually. A common practise to handle this is to filter out the nodes with zero-in-degree when use after conv.

示例

>>> 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]

Description

计算图卷积。

param graph:

图表。

type graph:

DGLGraph

param feat:

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

type feat:

torch.Tensor 或一对 torch.Tensor

param weight:

可选的外部权重张量。

type weight:

torch.Tensor, 可选的

param edge_weight:

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

type edge_weight:

torch.Tensor, 可选的

returns:

输出特征

rtype:

torch.Tensor

raises DGLError:

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

注意

  • Input shape: \((N, *, \text{in_feats})\) where * means any number of additional dimensions, \(N\) is the number of nodes.

  • Output shape: \((N, *, \text{out_feats})\) where all but the last dimension are the same shape as the input.

  • Weight shape: \((\text{in_feats}, \text{out_feats})\).

reset_parameters()[source]

Description

重新初始化可学习的参数。

注意

模型参数的初始化方式与 原始实现 相同,其中权重 \(W^{(l)}\) 使用 Glorot 均匀初始化进行初始化, 偏置初始化为零。