GCN:基于切比雪夫多项式(chebyshev ploynomials)为核的图卷积推导与pytorch实现

GCN图卷积神经网络

顾名思义,图卷积神经网络,是对图信息进行卷积,从而获取相邻节点的信息和特征,本文将介绍和推导目前较为流行的以chebyshev ploynomials 契比雪夫多项式为核的图卷积公式,同时通过pytorch代码实现。
在这里插入图片描述

图卷积的定义

通过表示图信息的矩阵及上一层特征输入,输出该层对图信息的特征,表示如下:
H l = f ( H l − 1 , A ) H_l = f(H_{l-1},A) Hl=f(Hl1,A)
A代表邻接矩阵,或关于图表示的矩阵。
常用数学传播表示方式如下:
H l = σ ( D ~ − 1 2 A ~ D ~ − 1 2 H l − 1 W l − 1 ) H_l=\sigma(\widetilde{D}^{-\frac{1}{2}}\widetilde{A}\widetilde{D}^{-\frac{1}{2}}H_{l-1}W_{l-1}) Hl=σ(D 21A D 21Hl1Wl1)

其中 D ~ \widetilde{D} D 代表 A ~ \widetilde{A} A 的度矩阵

A ~ \widetilde{A} A 代表邻接矩阵 A A A与单位矩阵 I I I的和: A ~ = A + I \widetilde{A}=A+I A =A+I

H H H代表卷积后的特征,初始输入 H = X H=X H=X

σ \sigma σ为激活函数

推导

  1. 图的表示方式:

    1)邻接矩阵 A A A,表示节点与节点之间是否存在连接,若存在则为1,不存在为0,对角线均为0

    2)度矩阵 D D D ,只有对角线有值,表示该节点所连接边的个数

    ​3) Laplacian 拉普拉斯矩阵: L = D − A L=D-A L=DA 1)对称 2)非负特征值 3)正交

    ​ 归一化Laplacian: L s y m = D − 1 2 L D − 1 2 = I − D − 1 2 A D − 1 2 L^{sym}=D^{-\frac{1}{2}}LD^{-\frac{1}{2}}=I-D^{-\frac{1}{2}}AD^{-\frac{1}{2}} Lsym=D21LD21=ID21AD21

  2. 卷积公式:其中 F ( X ) F(X) F(X)表示傅里叶变换

    f ∗ g = F − 1 ( F ( f ) ∗ F ( g ) ) f*g=F^{-1}(F(f)*F(g)) fg=F1(F(f)F(g))

  3. 根据拉普拉斯矩阵正交特性,存在 U , U T U,U^T U,UT使得 L = U Λ U T L=U\Lambda U^T L=UΛUT 其中 Λ \Lambda Λ表示特征向量

    则Graph Fourier可对应表示如下:

    G F ( x ) = U T x GF(x)=U^Tx GF(x)=UTx

    根据卷积公式,对应图卷积公式如下:

    g ∗ x = U ( U T g U T x ) g*x=U(U^TgU^Tx) gx=U(UTgUTx)

    每一次卷积操作作用域都希望在中心节点附近的区域,则我们可以将 g g g看作关于拉普拉斯矩阵 L L L的函数 g ( L ) g(L) g(L),那么,每卷积一次则相当于传递一次相邻节点信息

    而由 L L L特征值特性: U T L = Λ U T U^TL=\Lambda U^T UTL=ΛUT 可知, U T g ( L ) U^Tg(L) UTg(L) 可看作是关于拉普拉斯矩阵 L L L的特征函数 g θ ( Λ ) g_\theta(\Lambda) gθ(Λ)

    则图卷积表达式可写作:

    g ∗ x = U ( U T g U T x ) = U g θ U T x g*x=U(U^TgU^Tx)=Ug_\theta U^Tx gx=U(UTgUTx)=UgθUTx

  4. 运算简化

    由于计算 g θ g_\theta gθ需要计算拉普拉斯矩阵特征值,计算复杂,因而提出利用切比雪夫Chebyshev polynomials多项式来进行近似计算,这里并不影响特征值的计算属性,只是通过切比雪夫多项式作为核能够将特征值矩阵计算化简为L,从而跳过特征值计算的步骤,表示如下。

    g θ = ∑ k = 0 K θ k T k ( Λ ~ ) g_\theta=\sum_{k=0}^{K}\theta_k T_k(\widetilde{\Lambda}) gθ=k=0KθkTk(Λ )

    其中 Λ ~ = 2 ∗ Λ Λ m a x − 1 \widetilde{\Lambda}=2*\frac{\Lambda}{\Lambda_{max}}-1 Λ =2ΛmaxΛ1,只是因为Chebyshev polynomials要求 x x x处于 [ − 1 , 1 ] [-1,1] [1,1]

    T k ( x ) = 2 x T k − 1 ( x ) − T k − 2 ( x ) T_k(x)=2xT_{k-1}(x)-T_{k-2}(x) Tk(x)=2xTk1(x)Tk2(x), T 0 = 0 T_0=0 T0=0, T 1 = 1 T_1=1 T1=1

    那么将上式代入卷积表达式可以得到:

    g ∗ x = U ∑ k = 0 K θ k T k ( Λ ~ ) U T x = ∑ k = 0 K θ K T k ( L ~ ) x g*x=U\sum_{k=0}^{K}\theta_k T_k(\widetilde{\Lambda})U^Tx\\=\sum_{k=0}^K\theta_K T_k(\widetilde{L})x gx=Uk=0KθkTk(Λ )UTx=k=0KθKTk(L )x

pytorch代码实现

包需求:

import numpy as np
import torch
import torch.nn as nn

1.Laplacian 以及scaled_Laplacian:

'''D matrix 根据邻接矩阵获取度矩阵'''
def get_d_matrix(adj_matrix):
    d_matrix = np.zeros((adj_matrix.shape[0], adj_matrix.shape[1]))
    for i in range(adj_matrix.shape[0]):
        d_matrix[i, i] = np.sum(adj_matrix[i, :])
    return d_matrix

'''Laplace matrix'''
def get_laplace_matrix(adj, d):
    d_turn = np.zeros((adj.shape[0], adj.shape[0]))
    for i in range(adj.shape[0]):
        d_turn[i, i] = np.power(d[i, i], -0.5)
    res = np.eye(adj.shape[0]) - d_turn @ adj @ d_turn
    return res


'''
get the  rou of matrix 获取矩阵谱半径,即最大绝对值特征值
'''
def getRou(x):
    lambdas, features = np.linalg.eig(x)
    return np.max(np.abs(lambdas))

'''
get scaled laplacian for chebyshev ploynomials
'''
def scaled_laplacian(L):
    res = (2*L)/getRou(L)-np.identity(L.shape[0])
    return res
  1. 契比雪夫多项式的实现
'''
get chebyshev ploynomials 
'''
def chebyshev_ploynomials(scaled_laplacian, K):
    '''
    :param scaled_laplacian: [-1,1]的拉普拉斯矩阵
    :param K: 多项式项数
    :return: list
    '''
    res = [np.identity(scaled_laplacian.shape[0]), scaled_laplacian]
    if K>=2:
        for i in range(2, K+1):
            res.append(2*scaled_laplacian*res[i-1]-res[i-2])
    return res
  1. pytorch 实现图卷积
'''
take chebyshev ploynomials as kernal for graph conv
'''
class Cheb_conv(nn.Module):
    def __init__(self, chebyshev_ploynomials, K, in_channel, out_channel):
        super(Cheb_conv, self).__init__()
        self.K = K
        self.chebyshev_ploynomials = chebyshev_ploynomials
        self.device = chebyshev_ploynomials[0].device
        self.thetaList = nn.ParameterList([nn.Parameter(torch.FloatTensor(in_channel, out_channel).to(self.device)) for _ in range(K)])
        self.relu = nn.ReLU()

    def forward(self, x):
        '''

        :param x: (batch, nodes_num, features(in_channel), seq_len)
        :return:
        '''
        batch_size, nodes_num, in_channel, seq_len = x.shape
        #(batch, seq_len, nodes_num, in_channel)
        x = x.permute(0,3,1,2)
        output = torch.zeros(batch_size, nodes_num, self.out_channels, seq_len).to(self.DEVICE)
        for i in range(self.K):
            cheb = self.chebyshev_ploynomials[i]
            #(batch, seq_len, nodes_num, in_channel)
            cash = cheb.matmul(x)
            # (batch, seq_len, nodes_num, out_channel)
            cash = self.cash.matmul(self.thetaList[i])
            #(batch, nodes_num, out_channel, seq_len)
            cash = cash.permute(0,2,3,1)
            output += cash

        return self.relu(output)
### 切比雪夫多项式卷积的应用 在深度学习和其他数值计算场景中,切比谢夫多项式被广泛应用于图神经网络中的谱域卷积操作。具体来说,K阶切比谢夫多项式的定义如下: \[ T_k(x) = \begin{cases} 1 & k=0 \\ x & k=1 \\ 2xT_{k-1}(x)-T_{k-2}(x), & k\geq 2 \end{cases} \] 这种形式允许快速逼近拉普拉斯算子的特征分解[^1]。 对于大规模图结构数据处理而言,采用切比谢夫多项式可以有效减少参数数量并加速训练过程。通过引入切比雪夫近似方法来代替传统的傅里叶变换方式,可以在保持较高精度的同时显著降低计算复杂度。 #### 实现示例 下面是一个简单的Python实现例子,展示了如何利用TensorFlow库构建基于切比谢夫展开的图卷积: ```python import tensorflow as tf class ChebConv(tf.keras.layers.Layer): def __init__(self, units, K_order, **kwargs): super(ChebConv, self).__init__(**kwargs) self.units = units self.K_order = K_order def build(self, input_shape): # 初始化权重矩阵W和偏置向量b initializer = tf.random_normal_initializer() self.W = self.add_weight(shape=(input_shape[-1], self.units), initializer=initializer, trainable=True) self.b = self.add_weight(shape=(self.units,), initializer='zeros', trainable=True) def call(self, inputs, L): """ :param inputs: 输入节点特征 (batch_size, num_nodes, feature_dim) :param L: 图拉普拉斯矩阵 (num_nodes, num_nodes) """ outputs = [] for i in range(inputs.shape[0]): x = inputs[i] Tx_0 = tf.matmul(L, x) out = tf.zeros_like(Tx_0 @ self.W) if self.K_order >= 1: Tx_1 = tf.matmul(L, Tx_0) out += Tx_1 @ self.W for _ in range(2, min(self.K_order + 1, len(x))): Tx_2 = 2 * tf.matmul(L, Tx_1) - Tx_0 out += Tx_2 @ self.W Tx_0, Tx_1 = Tx_1, Tx_2 outputs.append(out + self.b) return tf.stack(outputs) ``` 此代码片段实现了具有指定阶数`K_order`的一维离散时间信号上的切比雪夫滤波器响应,并将其应用到输入张量上。注意这里假设已经获得了标准化后的邻接矩阵L作为额外输入传递给call函数。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xx_Mike

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值