图卷积神经网络

##图卷积网络的简单是实现
1.图卷积神经网络
GCN 是一类非常强大的用于图数据的神经网络架构。事实上,它非常强大,即使是随机初始化的两层 GCN 也可以生成图网络中节点的有用特征表征。下图展示了这种两层 GCN 生成的每个节点的二维表征。请注意,即使没有经过任何训练,这些二维表征也能够保存图中节点的相对邻近性。
在这里插入图片描述
在这里插入图片描述
更形式化地说,图卷积网络(GCN)是一个对图数据进行操作的神经网络。给定图 G = (V, E),GCN 的输入为:

1,一个输入维度为 N × F⁰ 的特征矩阵 X,其中 N 是图网络中的节点数而 F⁰ 是每个节点的输入特征数。

2,一个图结构的维度为 N × N 的矩阵表征,例如图 G 的邻接矩阵 A。[1]

因此,GCN 中的隐藏层可以写作 Hⁱ = f(Hⁱ⁻¹, A))。其中,H⁰ = X,f 是一种传播规则 [1]。每一个隐藏层 Hⁱ 都对应一个维度为 N × Fⁱ 的特征矩阵,该矩阵中的每一行都是某个节点的特征表征。在每一层中,GCN 会使用传播规则 f 将这些信息聚合起来,从而形成下一层的特征。这样一来,在每个连续的层中特征就会变得越来越抽象。在该框架下,GCN 的各种变体只不过是在传播规则 f 的选择上有所不同 [1]。
2.propation
f(Hⁱ, A) = σ(AHⁱWⁱ)
其中,Wⁱ 是第 i 层的权重矩阵,σ 是非线性激活函数(如 ReLU 函数)。权重矩阵的维度为 Fⁱ × Fⁱ⁺¹,即权重矩阵第二个维度的大小决定了下一层的特征数。如果你对卷积神经网络很熟悉,那么你会发现由于这些权重在图中的节点间共享,该操作与卷积核滤波操作类似。

简化
接下来我们在最简单的层次上研究传播规则。令:

1,i = 1,(约束条件 f 是作用于输入特征矩阵的函数)

2,σ 为恒等函数

3,选择权重(约束条件: AH⁰W⁰ =AXW⁰ = AX)

换言之,f(X, A) = AX。该传播规则可能过于简单,本文后面会补充缺失的部分。此外,AX 等价于多层感知机的输入层。在这里插入图片描述
numpy 编写

A = np.matrix([
    [0, 1, 0, 0],
    [0, 0, 1, 1],
    [0, 1, 0, 0],
    [1, 0, 1, 0]],
    dtype=float
)

In [3]: X = np.matrix([
            [i, -i]
            for i in range(A.shape[0])
        ], dtype=float)
        X
Out[3]: matrix([
           [ 0.,  0.],
           [ 1., -1.],
           [ 2., -2.],
           [ 3., -3.]
        ])

现在已经建立了一个图,其邻接矩阵为 A,输入特征的集合为 X。下面让我们来看看,当我们对其应用传播规则后会发生什么:

我们现在已经建立了一个图,其邻接矩阵为 A,输入特征的集合为 X。下面让我们来看看,当我们对其应用传播规则后会发生什么


In [6]: A * X
Out[6]: matrix([
            [ 1., -1.],
            [ 5., -5.],
            [ 1., -1.],
            [ 2., -2.]]

每个节点的表征(每一行)现在是其相邻节点特征的和!换句话说,图卷积层将每个节点表示为其相邻节点的聚合。大家可以自己动手验证这个计算过程。请注意,在这种情况下,如果存在从 v 到 n 的边,则节点 n 是节点 v 的邻居
3.问题
1,节点的聚合表征不包含它自己的特征!该表征是相邻节点的特征聚合,因此只有具有自环(self-loop)的节点才会在该聚合中包含自己的特征 [1]。

2,度大的节点在其特征表征中将具有较大的值,度小的节点将具有较小的值。这可能会导致梯度消失或梯度爆炸 [1, 2],也会影响随机梯度下降算法(随机梯度下降算法通常被用于训练这类网络,且对每个输入特征的规模(或值的范围)都很敏感)。
4.解决方法
(1)增加自环

In [4]: I = np.matrix(np.eye(A.shape[0]))
        I
Out[4]: matrix([
            [1., 0., 0., 0.],
            [0., 1., 0., 0.],
            [0., 0., 1., 0.],
            [0., 0., 0., 1.]
        ])
In [8]: A_hat = A + I
        A_hat * X
Out[8]: matrix([
            [ 1., -1.],
            [ 6., -6.],
            [ 3., -3.],
            [ 5., -5.]])

(2)对特征表征进行归一化处理
通过将邻接矩阵 A 与度矩阵 D 的逆相乘,对其进行变换,从而通过节点的度对特征表征进行归一化。因此,我们简化后的传播规则如下:

f(X, A) = D⁻¹AX

让我们看看发生了什么。我们首先计算出节点的度矩阵。注意:此处计算节点的度是用节点的入度,也可以根据自身的任务特点用出度,在本文中,这个选择是任意的。一般来说,您应该考虑节点之间的关系是如何与您的具体任务相关。例如,您可以使用in-degree来进行度矩阵计算,前提是只有关于节点的in-neighbors的信息与预测其具体任务中的标签相关。相反,如果只有关于外部邻居的信息是相关的,则可以使用out-degree。最后,如果节点的out-和in-邻居都与您的预测相关,那么您可以基于in-和out-度的组合来计算度矩阵。

In [9]: D = np.array(np.sum(A, axis=0))[0]
        D = np.matrix(np.diag(D))
        D
Out[9]: matrix([
            [1., 0., 0., 0.],
            [0., 2., 0., 0.],
            [0., 0., 2., 0.],
            [0., 0., 0., 1.]
        ])

可以观察到,邻接矩阵中每一行的权重(值)都除以该行对应节点的度。我们接下来对变换后的邻接矩阵应用传播规则:

得到与相邻节点的特征均值对应的节点表征。这是因为(变换后)邻接矩阵的权重对应于相邻节点特征加权和的权重。大家可以自己动手验证这个结果。
5.添加权重
首先要做的是应用权重。请注意,这里的 D_hat 是 A_hat = A + I 对应的度矩阵,即具有强制自环的矩阵 A 的度矩阵

In [45]: W = np.matrix([
             [1, -1],
             [-1, 1]
         ])
         D_hat**-1 * A_hat * X * W
Out[45]: matrix([
            [ 1., -1.],
            [ 4., -4.],
            [ 2., -2.],
            [ 5., -5.]
        ])

如果我们想要减小输出特征表征的维度,我们可以减小权重矩阵 W 的规模:


In [46]: W = np.matrix([
             [1],
             [-1]
         ])
         D_hat**-1 * A_hat * X * W
Out[46]: matrix([[1.],
        [4.],
        [2.],
        [5.]]
)

6.添加激活函数:
Relu函数的公式是f(x)=max(0,x),代码为:

def relu(x):
    return (abs(x) + x) / 2

一个带有邻接矩阵、输入特征、权重和激活函数的完整隐藏层如下:

In [51]: W = np.matrix([
             [1, -1],
             [-1, 1]
         ])
         relu(D_hat**-1 * A_hat * X * W)
Out[51]: matrix([[1., 0.],
        [4., 0.],
        [2., 0.],
        [5., 0.]])
 

典例:空手道俱乐部数据集

import networx as nx 
from networkx import to_numpy_matrix
zkc = nx.karate_club_graph()
order = sorted(list(zkc.nodes()))
A = to_numpy_matrix(zkc, nodelist=order)
I = np.eye(zkc.number_of_nodes())
A_hat = A + I
D_hat = np.array(np.sum(A_hat, axis=0))[0]
D_hat = np.matrix(np.diag(D_hat))
W_1 = np.random.normal(
    loc=0, scale=1, size=(zkc.number_of_nodes(), 4))
W_1
array([[-1.60850738, -1.81286031, -1.21488112, -0.67512344],
       [ 0.4728306 ,  0.48590465,  0.46768218, -1.28452497],
       [ 0.48404091,  0.36123352, -0.28535282,  1.3567935 ],
       [ 0.5454595 ,  1.47414699, -0.2436099 ,  1.8448905 ],
       [ 0.35601084,  0.17007017, -1.08012856,  0.12243646],
       [ 1.08218031, -0.86061025,  0.2198768 , -0.88965361],
       [ 0.77173117,  1.0753156 ,  0.80771322, -0.44305522],
       [ 2.32292136, -1.11497939, -0.08832334, -0.48259347],
       [-1.14989919, -1.07299688,  0.35833233, -1.02271864],
       [-1.26604098,  1.11403405, -1.27368651,  0.68473466],
       [ 0.03711537, -0.75404804,  2.41704567, -0.26348625],
       [-0.82774307, -1.27096915,  0.01414155, -0.26087749],
       [-0.47360135,  2.2111597 , -0.2785656 , -1.19886492],
       [-0.39920476,  0.37976039,  0.37631679, -0.85434706],
       [-1.06777751,  1.37249251, -1.5528223 , -0.7082742 ],
       [ 1.21119404, -1.00086211,  0.79906034,  1.51296967],
       [-1.93495147, -1.41661229, -1.46847639, -0.88607286],
       [-0.57851013,  0.91926198, -0.4840015 ,  0.3120885 ],
       [-0.1431892 ,  0.66630315,  0.37068425,  0.65605851],
       [ 1.73521822, -1.78790492, -0.08257555,  1.30993567],
       [-1.45908455,  0.12757605,  0.57191581,  0.02318818],
       [ 0.7415613 ,  1.26621066, -0.51246359,  0.8104835 ],
       [ 0.91050774,  0.05019478, -0.95328867, -0.17870357],
       [ 1.208966  ,  0.04708878,  0.2219424 , -1.04159587],
       [ 0.1054095 , -0.41581914, -1.09173746, -0.55462029],
       [-1.21917691,  0.9778717 , -0.54145143, -2.0725276 ],
       [-0.61375621,  0.98126815,  0.07500444, -0.76939277],
       [-0.94490006,  1.98768759,  0.1917666 , -0.64337003],
       [-1.47937171,  0.09036739,  0.57247029,  1.32377866],
       [ 0.24979308,  0.65461977,  0.84397059, -2.47825603],
       [-1.65513804,  0.49083851, -1.52508566, -1.12353088],
       [-0.42206369, -0.54915933, -0.03701411, -1.96757786],
       [ 0.75976155,  1.28285357,  0.44180894,  1.92307764],
       [-1.0557052 , -0.7521497 , -1.97767775,  0.01836153]])        

W_2 = np.random.normal(
    loc=0, size=(W_1.shape[1], 2))
W_2

array([[-0.96457918,  0.45900237],
       [-0.55060714, -1.08875363],
       [-1.07701631, -0.71475231],
       [ 0.45233694, -0.26491149]])
def gcn_layer(A_hat, D_hat, X, W):
    return relu(D_hat**-1 * A_hat * X * W)
H_1 = gcn_layer(A_hat, D_hat, I, W_1)
H_2 = gcn_layer(A_hat, D_hat, H_1, W_2)
output = H_2
output
matrix([[0.17394349, 0.12613323],
        [0.21514969, 0.1248979 ],
        [0.2200705 , 0.07164891],
        [0.20434201, 0.16982548],
        [0.17972395, 0.26591497],
        [0.13314916, 0.17843399],
        [0.08887072, 0.11894365],
        [0.24585268, 0.25294519],
        [0.17443997, 0.14387933],
        [0.27246705, 0.07764017],
        [0.18066635, 0.25648615],
        [0.2912415 , 0.46735709],
        [0.23301799, 0.20337298],
        [0.20719444, 0.21210805],
        [0.10766761, 0.02108594],
        [0.1048165 , 0.02436026],
        [0.01142164, 0.0006152 ],
        [0.23678846, 0.06878243],
        [0.14423298, 0.        ],
        [0.16002963, 0.10097575],
        [0.13788295, 0.11606215],
        [0.34037411, 0.27910508],
        [0.14169454, 0.09565058],
        [0.16444515, 0.        ],
        [0.13790554, 0.        ],
        [0.13951285, 0.        ],
        [0.08406175, 0.04714129],
        [0.18639611, 0.04326001],
        [0.20328647, 0.26678944],
        [0.11548443, 0.04857866],
        [0.11449148, 0.        ],
        [0.17931359, 0.1911088 ],
        [0.14008594, 0.        ],
        [0.14183489, 0.        ]])

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值