本篇文章主要基于 DGL 框架用三种不同的方式来实现图卷积神经网络。
1. DGL
DGL(Deep Graph Library)框架是由纽约大学和 AWS 工程师共同开发的开源框架,旨在为大家提供一个在图上进行深度学习的工具,帮助大家更高效的实现算法。
用现有的一些框架比如 TensorFlow、Pytorch、MXNet 等实现图神经网络模型都不太方便,同样现有框架实现图神经网络模型的速度不够快。
DGL 框架设计理念主要在于将图神经网络看作是消息传递的过程,每一个节点会发出它自己的消息,也会接收来自其它节点的消息。然后在得到所有信息之后做聚合,计算出节点新的表示。原有的深度学习框架都是进行张量运算,但是图很多时候并不能直接表示成一个完整的张量,需要手动补零,这其实很麻烦,不高效。
DGL 是基于现有框架,帮助用户更容易实现图神经网络模型。DGL 现在主要是以消息传递的接口作为核心,同时提供图采样以及批量处理图的接口。
关于 DGL 就不再进行过多介绍,感兴趣的同学可以去官网(http://dgl.ai/)了解。
2. Prepare
import torch
import time
import math
import dgl
import numpy as np
import torch.nn as nn
from dgl.data import citation_graph as citegrh
from dgl import DGLGraph
import dgl.function as fn
import networkx as nx
import torch.nn.functional as F
# 疑问 1: 为什么可以直接从 pytorch 中导入 GraphConv,这个不应该是 conv 文件中的吗
from dgl.nn import GraphConv
# from dgl.nn.pytorch import GraphConv
# from dgl.nn.pytorch.conv import GraphConv
这里有三种导入方法,建议用第一种,因为 DGL 的开发同学设计了一个机制,会自动 detect 用了什么 beckend,从而适配对应的 backend 的 api。
print(torch.__version__)
print(dgl.__version__)
print(nx.__version__)
1.4.0
0.4.3
2.3
3. GCN
3.1 First version
DGL 的第一种写法是利用 DGL 预定义的图卷积模块 GraphConv 来实现的。
GCN 的数学公式如下:
h i ( l + 1 ) = σ ( b ( l ) + ∑ j ∈ N ( i ) 1 c i j h j ( l ) W ( l ) ) h_i^{(l+1)} = \sigma(b^{(l)} + \sum_{j\in\mathcal{N}(i)}\frac{1}{c_{ij}}h_j^{(l)}W^{(l)}) hi(l+1)=σ(b(l)+j∈N(i)∑cij1hj(l)W(l))
其中, N ( i ) \mathcal{N}(i) N(i) 为节点的邻居集合, c i j = ∣ N ( i ) ∣ ∣ N ( j ) ∣ c_{ij}=\sqrt{|\mathcal{N}(i)|}\sqrt{|\mathcal{N}(j)|} cij=∣N(i)∣∣N(j)∣ 表示节点度的平方根的乘积,用于归一化数据, s i g m a sigma sigma 为激活函数
GraphConv 模型参数初始化参考 tkipf 大佬的原始实现,其中 W ( l ) W^{(l)} W(l) 使用 Glorot uniform 统一初始化,并将偏差初始化为零。
简单介绍下 Glorot 均匀分布(uniform)
Glorot 均匀分布,也叫 Xavier 均匀分布,该方法源于 2010 年的一篇论文《Understanding the difficulty of training deep feedforward neural networks》。其核心思想在于:为了使得网络中信息更好的流动,每一层输出的方差应该尽量相等。基于这个目标,权重 W 的方差需要满足 ∀ i V a r [ W i ] = 2 n i + n i + 1 \forall i \; Var[W^i] = \frac{2}{n_{i}+n_{i+1}} ∀iVar[Wi]=n