图卷积神经网络GCN原理总结

目录

  • 1. 图信号处理知识
    • 1.1 图的拉普拉斯矩阵
      • 1.1.1 拉普拉斯矩阵的定义及示例
      • 1.1.2 正则化拉普拉斯矩阵
      • 1.1.3 拉普拉斯矩阵的性质
    • 1.2 图上的傅里叶变换
    • 1.3 图信号滤波器
  • 2. 图卷积神经网络
    • 2.1 数学定义
    • 2.2 GCN的理解及时间复杂度
    • 2.3 GCN的优缺点
  • 3. Pytorch代码解析


1. 图信号处理知识

图卷积神经网络涉及到图信号处理的相关知识,也是由图信号处理领域的知识推导发展而来,了解图信号处理的知识是理解图卷积神经网络的基础。

1.1 图的拉普拉斯矩阵

拉普拉斯矩阵是体现图结构关联的一种重要矩阵,是图卷积神经网络的一个重要部分。

1.1.1 拉普拉斯矩阵的定义及示例

拉普拉斯矩阵的定义为:L=D-A,其中D为图的度矩阵,A为图的邻接矩阵。
数学表达式为:
L i j = { d e g ( v i ) if i=j − 1 if eij∈E 0 otherwise L_{ij}= \begin{cases} deg(v_i)& \text{if i=j}\\ -1& \text{if e{ij}∈E}\\ 0& \text{otherwise} \end{cases} Lij=deg(vi)10if i=jif eij∈Eotherwise
实例:
图卷积神经网络GCN原理总结_第1张图片
按照上述计算式子,可以得到拉普拉斯矩阵为:
图卷积神经网络GCN原理总结_第2张图片

1.1.2 正则化拉普拉斯矩阵

在GCN中用到的是拉普拉斯矩阵的正则化形式,其定义为: L s y m = D − 1 / 2 L D 1 / 2 L_{sym}=D^{-1 /2}LD^{1/2} Lsym=D1/2LD1/2,数学表达式为:
L s y m [ i , j ] = { 1 if i=j − 1 d e g ( v i ) d e g ( v j ) if eij∈E 0 otherwise L_{sym}[i,j]= \begin{cases} 1& \text{if i=j}\\ \frac{-1}{\sqrt{deg(v_i)deg(v_j)}}& \text{if e{ij}∈E}\\ 0& \text{otherwise} \end{cases} Lsym[i,j]=1deg(vi)deg(vj) 10if i=jif eij∈Eotherwise

1.1.3 拉普拉斯矩阵的性质

拉普拉斯矩阵之所以在图卷积神经网络得到运用,一个重要原因是其本身具有很好的矩阵性质:
(1)拉普拉斯矩阵是一个反映图信号局部平滑度的算子;
对于任意给定的向量x, L x = ( D − A ) x = [ . . . , ∑ v j ∈ N ( v i ) ( x i − x j ) , . . . ] Lx=(D-A)x=[..., \sum_{v_j∈N(v_i)}(x_i-x_j), ...] Lx=(DA)x=[...,vjN(vi)(xixj),...],从式子可以看出,拉普拉斯矩阵很好的反映了图信号局部平滑度。
(2)拉普拉斯矩阵是一个半正定矩阵,故其所有特征值均大于等于0;
证明:
对于任意给定的向量x,拉普拉斯矩阵的二次型为:
x T L x = ∑ v i ∑ v j ∈ N ( v i ) x i ( x i − x j ) = ∑ e i j ∈ E ( x i − x j ) 2 ≥ 0 x^TLx=\sum_{v_i}\sum_{v_j∈N(v_i)}x_i(x_i-x_j)=\sum_{e_{ij}∈E}(x_i-x_j)^2≥0 xTLx=vivjN(vi)xi(xixj)=eijE(xixj)20
故拉普拉斯矩阵为半正定矩阵。
(3)拉普拉斯矩阵很好的刻画了图信号整体的平滑度;
由(2),令 T V ( x ) = x T L x = ∑ e i j ∈ E ( x i − x j ) 2 TV(x)=x^TLx=\sum_{e_{ij}∈E}(x_i-x_j)^2 TV(x)=xTLx=eijE(xixj)2,称其为图信号的总变差,由式子可以看出,其表示了各边关联的图信号的差值的平方,刻画了图信号整体的平滑度。
(4)由于 L I = 0 LI=0 LI=0,故拉普拉斯矩阵具有最小特征值0,另外,对于正则化拉普拉斯矩阵,可以证明,其特征值存在上限,小于等于2。

1.2 图上的傅里叶变换

傅里叶变换是一种分析信号的方法,它可分析信号的成分,也可用这些成分合成信号。它将信号从时域转换到频域,从频域视角给出了信号处理的另一种解法。
(1)对于图结构,可以定义图上的傅里叶变换(GFT),对于任意一个在图G上的信号x,其傅里叶变换表示为:
x k ~ = ∑ i = 1 N V k i T x i = < v k , x > \tilde{x_{k}}=\sum_{i=1}^{N}V_{ki}^{T}x_i= xk~=i=1NVkiTxi=<vk,x>
其中,称特征向量v为傅里叶基, x k ~ \tilde{x_{k}} xk~是x在第k个傅里叶基上的傅里叶系数。
可以看出,傅里叶系数即为图信号x在傅里叶基上的投影,衡量两者间的相似度。
(2)逆图傅里叶变换:如傅里叶变换与逆傅里叶变换,图上的傅里叶变换也能推导其逆。
推导:
式子1: x ~ = V T x , x ~ ∈ R N \tilde{x}=V^{T}x, \tilde{x}∈R^N x~=VTx,x~RN
由于V是L的N个特征向量,是一个正交矩阵,故对式1做左乘V,则: V x ~ = V V T x = I x = x V\tilde{x}=VV^Tx=Ix=x Vx~=VVTx=Ix=x,故有:
式子2: x = V x ~ , x ∈ R N x=V\tilde{x}, x∈R^N x=Vx~,xRN
故定义逆图傅里叶变换(IGFT): x k = ∑ i = 1 N V k i x i ~ x_k=\sum_{i=1}^NV_{ki}\tilde{x_i} xk=i=1NVkixi~
将式2展开,可得到逆图傅里叶变换的向量形式:
x = V x ~ = x 1 ~ v 1 + . . . + x N ~ v N = ∑ k = 1 N x k ~ v k x=V\tilde{x}=\tilde{x_1}v_1+...+\tilde{x_N}v_N=\sum_{k=1}^{N}\tilde{x_k}v_k x=Vx~=x1~v1+...+xN~vN=k=1Nxk~vk
从线代角度,可以清晰的看出:v1,…, vn构成了N维特征空间中的一组完备基向量,G中任意一个图信号都可表示为这些基向量的线性加权求和,系数为图信号对应傅里叶基上的傅里叶系数。


回到之前提到的拉普拉斯矩阵刻画平滑度的总变差:
T V ( x ) = x T L x = X T V λ V T x = ( V x ~ ) T V λ V T ( V x ~ ) = x T ~ V T V λ V T V x ~ = x T ~ λ x ~ = ∑ k N λ k x k 2 ~ TV(x)=x^TLx=X^TV\lambda V^Tx \\ =(V\tilde{x})^TV\lambda V^T(V\tilde{x}) \\ =\tilde{x^T}V^TV\lambda V^TV\tilde{x} \\ =\tilde{x^T}\lambda\tilde{x}=\sum_{k}^{N}\lambda_k\tilde{x_k^2} TV(x)=xTLx=XTVλVTx=(Vx~)TVλVT(Vx~)=xT~VTVλVTVx~=xT~λx~=kNλkxk2~
可以看成:刻画图平滑度的总变差是图中所有节点特征值的线性组合,权值为傅里叶系数的平方。
总变差取最小值的条件是图信号与最小的特征值所对应的特征向量完全重合,结合其描述图信号整体平滑度的意义,可将特征值等价成频率:特征值越低,频率越低,对应的傅里叶基变化缓慢,即相近节点的信号值趋于一致。
把图信号所有的傅里叶系数结合称为频谱(spectrum),频域的视角从全局视角既考虑信号本身,也考虑到图的结构性质。

1.3 图信号滤波器

图滤波器(Graph Filter)为对图中的频率分量进行增强或衰减,图滤波算子核心为其频率响应矩阵,为滤波器带来不同的滤波效果。
故图滤波器根据滤波效果可分为低通,高通和带通。
低通滤波器:保留低频部分,关注信号的平滑部分;
高通滤波器:保留高频部分,关注信号的剧烈变化部分;
带通滤波器:保留特定频段部分;
而拉普拉斯矩阵多项式扩展可形成图滤波器H:
H = h 0 L 0 + . . . + h k L k = ∑ k = 0 K h k L k H=h_0L^0+...+h_kL^k=\sum_{k=0}^{K}h_kL^k H=h0L0+...+hkLk=k=0KhkLk

2. 图卷积神经网络

2.1 数学定义

图卷积运算的数学定义为:
x 1 ∗ x 2 = I G F T ( G F T ( x 1 ) @ G F T ( x 2 ) ) x_1*x_2=IGFT(GFT(x_1)@GFT(x_2)) x1x2=IGFT(GFT(x1)@GFT(x2)),其中@表示矩阵的哈达玛积运算(即对应位置的元素相乘)
对运算式子推导:
x 1 ∗ x 2 = V ( ( V T x 1 ) @ ( V T x 2 ) ) = V ( x 1 ~ @ ( V T x 2 ) ) = V ( d i a g ( x 1 ~ ) ( V T x 2 ) ) = ( V d i a g ( x 1 ~ ) V T ) x 2 x_1*x_2=V((V^Tx_1)@(V^Tx_2))=V(\tilde{x_1}@(V^Tx_2))\\=V(diag(\tilde{x1})(V^Tx_2))=(Vdiag(\tilde{x_1})V^T)x_2 x1x2=V((VTx1)@(VTx2))=V(x1~@(VTx2))=V(diag(x1~)(VTx2))=(Vdiag(x1~)VT)x2
H x 1 ~ = V d i a g ( x 1 ~ ) V T H_{\tilde{x_1}}=Vdiag(\tilde{x_1})V^T Hx1~=Vdiag(x1~)VT,则 x 1 ∗ x 2 = H x 1 ~ x 2 x_1*x_2=H_{\tilde{x_1}}x_2 x1x2=Hx1~x2
H作为图位移算子。
故图卷积可以等价于相应的图滤波,可将卷积运算定义为上述滤波运算。


由于图卷积等价于图滤波,而图滤波算子核心为其频率响应矩阵,故设频率响应矩阵为可训练参数,则可得到如下的网络层:
X ′ = σ ( V [ θ 1 θ 2 ⋱ θ N ] V T X ) = σ ( V d i a g ( θ ) V T X ) = σ ( Θ X ) X'=\sigma(V\begin{bmatrix}\theta_1 & & & & \\ & \theta_2 & & & \\ & & \ddots & & \\ & & & & \theta_N\end{bmatrix}V^TX)\\=\sigma(Vdiag(\theta)V^TX)=\sigma(\Theta X) X=σ(Vθ1θ2θNVTX)=σ(Vdiag(θ)VTX)=σ(ΘX)
其中 σ \sigma σ为激活函数, θ \theta θ为可训练参数,整个 Θ \Theta Θ为需要训练的图滤波器(其实图卷积层就是在训练该层对应的图滤波器),X为输入特征,X’为输出特征。
上述公式存在一个较大问题:学习参数为N,这涉及到整个图的所有节点,对于大规模数据极易发生过拟合。


进一步的化简推导:将之前说到的拉普拉斯矩阵的多项式展开代替上述可训练参数矩阵。
X ′ = σ ( V ( ∑ k = 0 K θ k Λ k ) V T X ) = σ ( V d i a g ( Ψ θ ) V T X ) X'=\sigma(V(\sum_{k=0}^{K}\theta_k\Lambda^k)V^TX)\\=\sigma(Vdiag(\Psi\theta)V^TX) X=σ(V(k=0KθkΛk)VTX)=σ(Vdiag(Ψθ)VTX)
其中 θ \theta θ为可训练参数,与之前不同的是,此方法可控制K的大小进而限制参数数量,一般设K<

进一步的化简推导:限制K=1,再令所得 θ 0 = θ 1 = θ \theta_0=\theta_1=\theta θ0=θ1=θ
X ′ = σ ( θ 0 L 0 X + θ 1 L 1 X ) = σ ( θ 0 X + θ 1 L X ) = σ ( ( θ ( I + L ) X ) = σ ( θ L ~ X ) X'=\sigma(\theta_0L^0X+\theta_1L^1X)\\=\sigma(\theta_0X+\theta_1LX)\\=\sigma((\theta(I+L)X)\\=\sigma(\theta\tilde{L}X) X=σ(θ0L0X+θ1L1X)=σ(θ0X+θ1LX)=σ((θ(I+L)X)=σ(θL~X)
此处的 θ \theta θ是一个尺度变换,是不必要的,因此再令 θ = 1 \theta=1 θ=1,得到固定的图滤波器 L ~ \tilde{L} L~


最后一步推导:对得到的固定滤波器进行归一化处理,得到重归一化的拉普拉斯矩阵 L s y m ~ \tilde{L_{sym}} Lsym~(比拉普拉斯矩阵多一个自环)。
进一步地,为了加强拟合能力,作者引入了一个可训练参数的权重矩阵对输入特征进行线性变换,终于!得到了:
X ′ = σ ( L s y m ~ X W ) X'=\sigma(\tilde{L_{sym}}XW) X=σ(Lsym~XW)
此结构内容即定义为图卷积层(GCN layer),有图卷积层堆叠得到的网络模型即为图卷积网络GCN。

2.2 GCN的理解及时间复杂度

图卷积层是对频率响应矩阵的极大化简,将本要训练的图滤波器直接退化为重归一化拉普拉斯矩阵,图卷积操作变为 L s y m ~ x \tilde{L_{sym}}x Lsym~x,计算等价于对邻居节点的特征向量进行聚合,其节点层面的计算式子可表示为:
x i = σ ( ∑ v j ∈ N ~ ( v i ) L s y m [ i , j ] ( W x j ~ ) x_i=\sigma(\sum_{v_j∈\tilde{N}(v_i)}\tilde{L_{sym}[i,j](Wx_j}) xi=σ(vjN~(vi)Lsym[i,j](Wxj~)
可以很清晰的看出其特征聚合功能。
对比频域图卷积的矩阵分解 O ( N 3 ) O(N^3) O(N3)的高时间复杂度,此图卷积层的空域操作时间复杂度大大降低了,为 O ( ∣ E ∣ d ) O(|E|d) O(Ed)

2.3 GCN的优缺点

优点:GCN作为近年图神经网络的基础之作,对处理图数据非常有效,其对图结构的结构信息和节点的属性信息同时学习,共同得到最终的节点特征表示,考虑到了节点之间的结构关联性,这在图操作中是非常重要的。


缺点:过平滑问题(多层叠加之后,节点的表示向量趋向一致,节点难以区分),由于GCN具有一个低通滤波器的作用(j聚合特征时使得节点特征不断融合),多次迭代后特征会趋于相同。

3. Pytorch代码解析

GCN层的pytorch实现:

class GraphConvolutionLayer(nn.Module):
    '''
        图卷积层:Lsym*X*W
            其中 Lsym表示正则化图拉普拉斯矩阵, X为输入特征, W为权重矩阵, X'表示输出特征;
            *表示矩阵乘法
    '''
    def __init__(self, input_dim, output_dim, use_bias=True):
        #初始化, parameters: input_dim-->输入维度, output_dim-->输出维度, use_bias-->是否使用偏置项, boolean
        super(GraphConvolutionLayer,self).__init__()
        self.input_dim=input_dim
        self.output_dim=output_dim
        self.use_bias=use_bias #是否加入偏置, 默认为True
        self.weight=nn.Parameter(torch.Tensor(input_dim, output_dim))#权重矩阵为可训练参数
        if self.use_bias==True: #加入偏置
            self.bias=nn.Parameter(torch.Tensor(output_dim)) 
        else: #设置偏置为空
            self.register_parameter('bias', None)
        self.reset_parameters()
    
    def reset_parameters(self):
        #初始化参数
        stdv = 1. / math.sqrt(self.weight.size(1))
        self.weight.data.uniform_(-stdv, stdv)#使用均匀分布U(-stdv,stdv)初始化权重Tensor
        if self.bias is not None:
            self.bias.data.uniform_(-stdv, stdv)
    
    def forward(self, adj, input_feature):
        #前向传播, parameters: adj-->邻接矩阵(输入为正则化拉普拉斯矩阵), input_future-->输入特征矩阵
        temp=torch.mm(input_feature, self.weight)#矩阵乘法, 得到X*W
        output_feature=torch.sparse.mm(adj, temp)#由于邻接矩阵adj为稀疏矩阵, 采用稀疏矩阵乘法提高计算效率, 得到Lsym*temp=Lsym*X*W
        if self.use_bias==True: #若设置了偏置, 加入偏置项
            output_feature+=self.bias
        return output_feature

定义两层的GCN网络模型:

class GCN(nn.Module):
    '''
        定义两层GCN网络模型
    '''
    def __init__(self, input_dim, hidden_dim, output_dim):
        #初始化, parameters: input_dim-->输入维度, hidden_dim-->隐藏层维度, output_dim-->输出维度
        super.__init__(GCN, self).__init__()
        #定义两层图卷积层
        self.gcn1=GraphConvolutionLayer(input_dim, hidden_dim)
        self.gcn2=GraphConvolutionLayer(hidden_dim, output_dim)
    
    def forward(self, adj, feature):
        #前向传播, parameters: adj-->邻接矩阵, feature-->输入特征
        x=F.relu(self.gcn1(adj, feature))
        x=self.gcn2(adj, x)
        return F.log_softmax(x, dim=1)

你可能感兴趣的:(机器学习)