去今年刚出就买了. 一查豆瓣评分比我想的还低(我这种小白都能看出一些错误), 有1说1对于入门还是可以的, 至少能知道GNN大概的发展路线, 如图卷积 → \rightarrow →GCN → \rightarrow →GNN等. 如果小白直接上手GNN啥的, 连图滤波, 空域频域等概念都不知道, 也只能瞎搞.
其实看书很容易也很快, 难得是把参考文献里的论文看完, 精华都在论文里.
笔记GNN
- Laplasian矩阵
- 先导知识
- [[梯度、散度、旋度、Jacobian、Hessian、Laplacian]]
- 用散度的概念解读
-
∇
f
=
0
\nabla f=0
∇f=0
- 中心点 的势和其周围点的势是相等的, 局部范围内不存在势差。所以该点无源
-
∇
f
>
0
\nabla f>0
∇f>0
- 可以近似认为中心点 的势低于周围点,可以想象成中心点如恒星一样发出能量,补给周围的点,所以该点是正源
-
∇
f
<
0
\nabla f<0
∇f<0
- 可以近似认为中心点 的势高于周围点,可以想象成中心点如吸引子一样在吸收能量,所以该点是负源
-
∇
f
=
0
\nabla f=0
∇f=0
- 推导
- 元素形式
- Δ f i = ∑ j ∈ N i W i j ( f i − f j ) \Delta f_{i}=\sum_{j \in N_{i}} W_{i j}\left(f_{i}-f_{j}\right) Δfi=∑j∈NiWij(fi−fj)
-
Δ
f
i
=
∑
j
∈
N
w
i
j
(
f
i
−
f
j
)
\Delta f_{i}=\sum_{j \in N} w_{i j}\left(f_{i}-f_{j}\right)
Δfi=∑j∈Nwij(fi−fj)
- = ∑ j ∈ N w i j f i − ∑ j ∈ N w i j f j =\sum_{j \in N} w_{i j} f_{i}-\sum_{j \in N} w_{i j} f_{j} =∑j∈Nwijfi−∑j∈Nwijfj
- = d i f i − w i : f =d_{i} f_{i}-w_{i:} f =difi−wi:f
- 矩阵形式
- Δ f = ( Δ f 1 ⋮ Δ f N ) = ( d 1 f 1 − w 1 : f ⋮ d N f N − w N : f ) \Delta f=\left(\begin{array}{c}\Delta f_{1} \\ \vdots \\ \Delta f_{N}\end{array}\right)=\left(\begin{array}{c}d_{1} f_{1}-w_{1:} f \\ \vdots \\ d_{N} f_{N}-w_{N:} f\end{array}\right) Δf=⎝⎜⎛Δf1⋮ΔfN⎠⎟⎞=⎝⎜⎛d1f1−w1:f⋮dNfN−wN:f⎠⎟⎞
- = ( d 1 ⋯ 0 ⋮ ⋱ ⋮ 0 ⋯ d N ) f − ( w 1 : ⋮ w N : ) f =\left(\begin{array}{ccc}d_{1} & \cdots & 0 \\ \vdots & \ddots & \vdots \\ 0 & \cdots & d_{N}\end{array}\right) f-\left(\begin{array}{c}w_{1:} \\ \vdots \\ w_{N:}\end{array}\right) f =⎝⎜⎛d1⋮0⋯⋱⋯0⋮dN⎠⎟⎞f−⎝⎜⎛w1:⋮wN:⎠⎟⎞f
- = diag ( d i ) f − W f =\operatorname{diag}\left(d_{i}\right) f-W f =diag(di)f−Wf
- = ( D − W ) f =(D-W) f =(D−W)f
- = L f =L f =Lf
- 拉普拉斯矩阵中的第 i i i行实际上反应了第 i i i个节点在对其他所有节点产生扰动时所产生的增益累积。
- 图拉普拉斯反映了当我们在节点 i i i上施加一个势,这个势以哪个方向能够多顺畅的流向其他节点。
- 元素形式
- TV(x) , Total Variation
- T V ( x ) = x T L x = Σ e i j ∈ E ( x i − x j ) ² TV(x)=x^TLx=\Sigma_{e_{ij}\in E}(x_i-x_j)² TV(x)=xTLx=Σeij∈E(xi−xj)²
- 刻画了图信号的整体平滑度
- laplacian矩阵二次型
- 对总变差进行改写
- T V ( x ) = x T L x = x T V Λ V T x TV(x)=x^TLx=x^TV\Lambda V^Tx TV(x)=xTLx=xTVΛVTx
- x = V x ^ x=V\hat{x} x=Vx^
- x ^ = V T x \hat{x}=V^Tx x^=VTx
- T V ( x ) = x ^ T Λ x ^ = Σ k N λ k x ^ k ² TV(x)=\hat{x}^T\Lambda \hat{x}=\Sigma_k^N \lambda_k \hat{x}_k² TV(x)=x^TΛx^=ΣkNλkx^k²
-
总变差
是图所有特征值的一个线性组合- 权重是图信号对应fourier系数的平方
- 先导知识
- 图滤波器
- 公式与推导
- y = H x = Σ k = 1 N ( h ( λ k ) x ^ k ) v k y=Hx=\Sigma^N_{k=1}(h(\lambda_k)\hat{x}_k)v_k y=Hx=Σk=1N(h(λk)x^k)vk
-
H
=
V
Λ
h
V
T
H=V\Lambda_hV^T
H=VΛhVT
- 相比与laplacian矩阵, H只改动了对焦线上的值, 故其所有定义与laplacian矩阵相同
- Λ h \Lambda_h Λh图滤波器H的频率响应矩阵
- 性质
- 线性
- H ( x + y ) = H x + H y H(x+y)=Hx+Hy H(x+y)=Hx+Hy
- 顺序无关
- H ₁ ( H ₂ ( x ) ) H₁(H₂(x)) H₁(H₂(x))
- 可逆
- 如果 h ( λ ) ≠ 0 h(\lambda)\neq 0 h(λ)=0
- 线性
- 泰勒展开
- H = Σ k = 0 K h k L k H=\Sigma_{k=0}^Kh_kL^k H=Σk=0KhkLk
- 空域角度
- y = H x = Σ k = 0 K h k L k x y=Hx=\Sigma_{k=0}^Kh_kL^k x y=Hx=Σk=0KhkLkx
- 性质
- 局部性
- 每个节点的输出信号值只需要考虑K阶子图
- 可通过K步迭代的矩阵乘法完成滤波
- 局部性
- 频域角度
- y = H x = V ( Σ k = 0 K h k Λ k ) V T x y=Hx=V(\Sigma_{k=0}^Kh_k\Lambda^k)V^Tx y=Hx=V(Σk=0KhkΛk)VTx
- 性质
- 需要做特征分解, 与空域的矩阵乘法相比有工程上的局限性
- 公式与推导
- GCN
- 图卷积等价于图滤波
- 空域视角: 引入一个自适应图位移算子, 完成对输入图信号的变换操作
- 频域视角: 自适应的图滤波器, 频率响应函数
- 问题
- 学习参数=节点数, 容易过拟合
- 信息蕴含在低频段
- 卷积层定义
- K=1
- X ′ = σ ( L s y m X W ) X^{\prime}=\sigma(L_{sym}XW) X′=σ(LsymXW)
- L s y m ∈ ( − 1 , 1 ] L_{sym}\in (-1,1] Lsym∈(−1,1] 防止梯度消失爆炸
- 等价于对邻居节点的特征响亮进行聚合操作
- 时间复杂度:
- O ( ∣ E ∣ d ) O(|E|d) O(∣E∣d)
- 性质
- 与CNN的区别与联系
- 1.图像是一种特殊的图数据
- 2.局部连接
- 但GCN权重参数只有1组, CNN的权重参数为卷积核size
- (在我看来GCN根本没有权重参数, 边权是预设的)
- 3.二者卷积核权重是处处共享的
- 4.感受野随着卷积层增加而变大
- 图数据的信息刻画
- 属性信息
- 结构信息
- 非端到端的传统图数据学习方法
- 手工特征
- 节点的度
- 中心度
- PageRank值
- 随机游走
- 手工特征
- GCN能解决图同构问题(graph isomorphism problem)
- Weisfeiler-Lehman
- GIN(Graph Isomorphism Network)
- https://arxiv.org/abs/1810.00826
How Powerful are Graph Neural Networks?
- GCN是个低通滤波器
- 半监督学习中, 需要在损失函数中加个正则项
-
L
r
e
g
=
Σ
e
i
j
∈
E
A
i
j
∣
∣
f
(
x
i
)
−
f
(
x
j
)
∣
∣
²
=
f
(
X
)
T
L
f
(
X
)
\mathcal{L}_{reg}=\Sigma_{e_{ij}\in E}A_{ij}||f(x_i)-f(x_j)||²=f(X)^TLf(X)
Lreg=Σeij∈EAij∣∣f(xi)−f(xj)∣∣²=f(X)TLf(X)
- laplacian的二次型
- 希望相邻结点分类标签尽量一致
-
L
r
e
g
=
Σ
e
i
j
∈
E
A
i
j
∣
∣
f
(
x
i
)
−
f
(
x
j
)
∣
∣
²
=
f
(
X
)
T
L
f
(
X
)
\mathcal{L}_{reg}=\Sigma_{e_{ij}\in E}A_{ij}||f(x_i)-f(x_j)||²=f(X)^TLf(X)
Lreg=Σeij∈EAij∣∣f(xi)−f(xj)∣∣²=f(X)TLf(X)
- GCN不需要正则项
- 重归一化的laplasian矩阵的频率响应函数 p ( λ ) = 1 − λ ^ ∈ ( − 1 , 1 ] p(\lambda)=1-\hat{\lambda}\in (-1,1] p(λ)=1−λ^∈(−1,1]
- p ( λ ) p(\lambda) p(λ)是一个线性收缩函数
- 直接将多层GCN退化为 σ ( L k X W ) \sigma(L^kXW) σ(LkXW)
- 半监督学习中, 需要在损失函数中加个正则项
- 低频信号包含对学习更有效的信息
Revisiting Graph Neural Networks: All We Have is Low-Pass Filters
- https://arxiv.org/abs/1905.09550
- https://www.cnblogs.com/liuxiangyan/p/12669728.html
- 容易造成的问题: 过平滑(over smooth)
- 所有节点信号趋同
- 解决方法
- 空域视角
- 保留每层输出,最后进行聚合
- 拼接
- 平均池化
- 最大池化
- LSTM
Representation Learning on Graphs with Jumping Knowledge Networks
- https://arxiv.org/abs/1806.03536
- 保留每层输出,最后进行聚合
- 频域视角
- 重新分配权重
- A i j ′ = { p / ∑ j = 1 C A i j , if i ≠ j 1 − p , if i = j \boldsymbol{A}_{i j}^{\prime}=\left\{\begin{array}{ll}p / \sum_{j=1}^{C} \boldsymbol{A}_{i j}, & \text { if } i \neq j \\ 1-p, & \text { if } i=j\end{array}\right. Aij′={p/∑j=1CAij,1−p, if i=j if i=j
-
p
→
1
p\rightarrow1
p→1
- 模型趋向于不使用自身信息
- 加速低通滤波效应
-
p
→
0
p\rightarrow0
p→0
- 模型趋向于不聚合邻居信息
- 缓解低通滤波效应
Multi-Label Image Recognition with Graph Convolutional Networks
- https://arxiv.org/abs/1904.03582
- https://github.com/Megvii-Nanjing/ML-GCN
- 重新分配权重
- 空域视角
- 与CNN的区别与联系
- 图卷积等价于图滤波
- GNN
- GraphSAGE
Inductive Representation Learning on Large Graphs
- https://arxiv.org/abs/1706.02216
- implement
- https://github.com/twjiang/graphSAGE-pytorch
- https://github.com/dsgiitr/graph_nets
- 两种学习方法
- 归纳学习 (Inductive Learning)
- 没有Laplasian矩阵的参与, 每个节点的特征学习仅与k阶邻居有关
- 对训练阶段见不到的数据进行直接预测而不用重新训练
- 转导学习 (transductive learning)
- deepwalk
- 图半监督算法
- lda2vec
- 归纳学习 (Inductive Learning)
- GAT
Graph Attention Networks
- https://arxiv.org/abs/1710.10903
- 保留了非常完整的局部性, 一样能进行归纳学习
- R-GCN
Modeling Relational Data with Graph Convolutional Networks
- https://arxiv.org/abs/1703.06103
- DeepWalk
DeepWalk: Online Learning of Social Representations
- https://arxiv.org/abs/1403.6652
- GraphSAGE
https://github.com/FighterLYL/GraphNeuralNetwork
chapter 5 | GCN
分析
train_index.shape
Out[30]: (140,)
val_index.shape
Out[31]: (500,)
test_index.shape
Out[32]: (1000,)
x = dataset.x / dataset.x.sum(1, keepdims=True) # 归一化数据,使得每一行和为1
x是每个节点(论文文本)的特征, 词带特征
Laplasian矩阵的规范化
L = D − 1 2 ( A + I ) D − 1 2 L=D^{-\frac{1}{2}}(A+I)D^{-\frac{1}{2}} L=D−21(A+I)D−21
def normalization(adjacency):
"""计算 L=D^-0.5 * (A+I) * D^-0.5"""
adjacency += sp.eye(adjacency.shape[0]) # 增加自连接
degree = np.array(adjacency.sum(1))
d_hat = sp.diags(np.power(degree, -0.5).flatten())
return d_hat.dot(adjacency).dot(d_hat).tocoo()
最后的操作tocoo()
是把csr
变成coo
TODO
kaiming_uniform_
是否合理
数据集切分, 训练集测试集都在一个图上(信息可传递, 共享) 是否会造成数据泄漏
之考虑词袋特征, 表现如何? 只考虑图结构特征, 表现如何?
改代码得到的结论
论文引用关系实质上是有向图, 数据处理时改为了无向图. 我将其改为有向图后, 无明显变化, 除了学习曲线有些波动
这图貌似就是无向图, 改代码没用
graph[999]
Out[2]: [1358, 346]
graph[346]
Out[3]: [1358, 999]
chapter 6 | GraphSage
分析
sampling.multihop_sampling
len(sampling_result[0])
Out[3]: 16
len(sampling_result[1])
Out[4]: 160
batch_sampling_x[2].shape
Out[9]: torch.Size([1600, 1433])
16
表示batch
, 10
表示采样数
self.gcn
Out[11]:
ModuleList(
(0): SageGCN(
in_features=1433, out_features=128, aggr_hidden_method=sum
(aggregator): NeighborAggregator(in_features=1433, out_features=128, aggr_method=mean)
)
(1): SageGCN(
in_features=128, out_features=7, aggr_hidden_method=sum
(aggregator): NeighborAggregator(in_features=128, out_features=7, aggr_method=mean)
)
)
NeighborAggregator
可以理解为对所有邻居进行了聚合然后做仿射变换
src_node_features.shape
Out[17]: torch.Size([16, 1433])
neighbor_node_features.shape
Out[18]: torch.Size([16, 10, 1433])
SageGCN
层与子结构NeighborAggregator
的weight不共享
hidden[0].shape
Out[26]: torch.Size([16, 1433])
hidden[1].shape
Out[27]: torch.Size([160, 1433])
hidden[2].shape
Out[28]: torch.Size([1600, 1433])
next_hidden[0].shape
Out[30]: torch.Size([16, 128])
next_hidden[1].shape
Out[31]: torch.Size([160, 128])
next_hidden[0].shape
Out[36]: torch.Size([16, 7])
如码所示, 最后得到了这批batch 16个样本(图结点)的logits
需要注意的点:
- 聚合操作, 对以目标点为弧尾的点进行聚合
- 重要的超参有
聚合邻居方法
和聚合隐层方法
.
- 聚合邻居方法
- mean
- sum
- max
- 聚合隐层方法
- sum
- concat
Test Accuracy: 0.7470000386238098
TODO
改写代码, 比较使用其他聚合方法的区别