论文题目:Graph Attention Network (GAT)
时间:2018
来源:ICLR
论文链接:https://arxiv.org/abs/1710.10903
Github链接:https://github.com/Diego999/pyGAT
graph上的deep learning方法无外乎就是希望学习节点特征以及节点在图中的结构特征。
对待图结构的数据有两种方法,谱方法和非谱方法
例如:GCN
Semi-Supervised Classification with Graph Convolutional Networks,ICLR 2017这篇文章中的方法
解析 :Semi-Supervised Classification with Graph Convolutional Networks用图卷积进行半监督分类
例如:GraphSAGE
William L Hamilton, Rex Ying, and Jure Leskovec. Inductive representation learning on largegraphs. Neural Information Processing Systems (NIPS), 2017.
解析:GraphSAGE:Inductive Representation Learning on Large Graphs
这种方法是将相邻节点设置为固定的长度,然后进行specific aggregator,这种方法在几个大的benchmarks上取得了非常好的效果。
优点:可以处理任意大小输入的问题,并且关注最具有影响能力的输入。
注意力机制再RNN与CNN之中,都取得了不错的效果,并且可以达到state-of-the-art的性能。
attention来源于自然语言处理领域的这篇很著名的文章:
Attention is all you need
和所有的attention mechanism一样,GAT的计算也分为两步:计算注意力系数(attention coefficient)和加权求和(aggregate)
input
单个 graph attentional layer的输入是一个节点特征向量集合
h = { h 1 ⃗ , h 2 ⃗ , … , h N ⃗ } , h i ⃗ ∈ R F h=\lbrace \vec{h_1},\vec{h_2},\dots,\vec{h_N} \rbrace,\; \vec{h_i}\in R^F h={h1,h2,…,hN},hi∈RF
其中
output
并生成一个新的节点特征集合
h ′ = { h 1 ′ ⃗ , h 2 ′ ⃗ , … , h N ′ ⃗ } , h i ′ ⃗ ∈ R F ′ h^{'}=\lbrace \vec{h_1^{'}},\vec{h_2^{'}},\dots,\vec{h_N^{'}} \rbrace,\; \vec{h_i^{'}}\in R^{F^{'}} h′={h1′,h2′,…,hN′},hi′∈RF′
其中 F F F和 F ′ F' F′具有不同的维度。
为了得到相应的输入与输出的转换,需要根据输入的feature至少一次线性变换得到输出的feature,所以我们需要对所有节点训练一个权值矩阵: W ∈ R F ′ × F W\in R^{F^{'}\times F} W∈RF′×F,这个权值矩阵就是输入与输出的F个feature与输出的F’个feature之间的关系:
h i ′ ⃗ = W h i ⃗ \vec{h_i^{'}}=\mathbf{W}\vec{h_i} hi′=Whi
为了获得足够的表达能力以将输入特征变换为更高级别的特征,需要至少一个可学习的线性变换。为此,作为初始步骤,一个共享的线性变换参数矩阵 W ∈ R F ′ × F \mathbf{W}\in R^{F^{'}\times F} W∈RF′×F被应用于每一个节点。
论文里说,self-attention是一种Global graph attention,会将注意力分配到图中所有的节点上,这种做法显然会丢失结构信息。通过self-attention注意力机制可以计算任意两个样本的关系,使一个样本用其他所有样本来表示,但是第一,基于空间相似假设,一个样本与一定范围内的样本关系较密切,第二,样本较多的时候,计算量非常大。为了解决这一问题,作者使用了一种 masked attention 的方法,对于一个样本来说只利用邻域内的样本计算注意力系数和新的表示,即仅将注意力分配到节点的一阶邻居节点集上。
针对每个节点执行 self-attention机制,机制 a a a为
a : R F ′ × R F ′ → R a:R^{F^{'}}\times R^{F^{'}}\to R a:RF′×RF′→R
计算注意力互相关系数attention coefficients:
e i j = a ( W h i ⃗ , W h j ⃗ ) (1) \tag{1} e_{ij}=a(\mathbf{W}\vec{h_i}, \mathbf{W}\vec{h_j}) eij=a(Whi,Whj)(1)
其中
为了使得注意力系数更容易计算和便于比较,引入了softmax对所有的 i i i的相邻节点 j j j进行正则化:
α i j = s o f t m a x j ( e i j ) = exp ( e i j ) ∑ k ∈ N i exp ( e i k ) (2) \tag{2} \alpha_{ij} = \mathrm{softmax}_j (e_{ij}) = \frac{\exp(e_{ij})}{\sum_{k \in \mathcal{N}_i} \exp(e_{ik})} αij=softmaxj(eij)=∑k∈Niexp(eik)exp(eij)(2)
其中
实验中,注意力机制 a a a是一个单层的前馈神经网络,通过权值向量来确定 a ⃗ ∈ R 2 F ′ \vec{\text{a}} \in \mathbb{R}^{2F'} a∈R2F′,并且加入了 LeakyRelu的非线性激活,这里小于零斜率为0.2。(回顾下几种Relu函数,relu:小于0就是0,大于零斜率为1;LRelu:小于零斜率固定一个值,大于零斜率为1;PRelu:小于零斜率可变,大于零斜率为1;还有CRelu,Elu,SELU)。
α i j = exp ( L e a k y R e L U ( a ⃗ T [ W h ⃗ i ∥ W h ⃗ j ] ) ) ∑ k ∈ N i exp ( L e a k y R e L U ( a ⃗ T [ W h ⃗ i ∥ W h ⃗ k ] ) ) (3) \tag{3} \alpha_{ij} = \frac{ \exp{ ( \mathrm{LeakyReLU} ( \vec{\text{a}}^T [\mathbf{W} \vec{h}_i \Vert \mathbf{W} \vec{h}_j ] ))}}{\sum_{k \in \mathcal{N_i}} \exp{(\mathrm{LeakyReLU}(\vec{\text{a}}^T [\mathbf{W} \vec{h}_i \Vert \mathbf{W} \vec{h}_k]))}} αij=∑k∈Niexp(LeakyReLU(aT[Whi∥Whk]))exp(LeakyReLU(aT[Whi∥Whj]))(3)
其中
下图就是表示 W h ⃗ i \mathbf{W} \vec{h}_i Whi和 W h ⃗ j \mathbf{W} \vec{h}_j Whj经过串联以后,再和权值向量 a ⃗ ∈ R 2 F ′ \vec{\text{a}} \in \mathbb{R}^{2F'} a∈R2F′相乘后,最后进行一个softmax归一化处理后的示意图。
这部分代码为
def forward(self, x):
# [B_batch,N_nodes,C_channels]
B, N, C = x.size()
# h = torch.bmm(x, self.W.expand(B, self.in_features, self.out_features)) # [B,N,C]
h = torch.matmul(x, self.W) # [B,N,C]
a_input = torch.cat([h.repeat(1, 1, N).view(B, N * N, C), h.repeat(1, N, 1)], dim=2).view(B, N, N,
2 * self.out_features) # [B,N,N,2C]
# temp = self.a.expand(B, self.out_features * 2, 1)
# temp2 = torch.matmul(a_input, self.a)
attention = self.leakyrelu(torch.matmul(a_input, self.a).squeeze(3)) # [B,N,N]
attention = F.softmax(attention, dim=2) # [B,N,N]
attention = F.dropout(attention, self.dropout, training=self.training)
h_prime = torch.bmm(attention, h) # [B,N,N]*[B,N,C]-> [B,N,C]
out = F.elu(h_prime + self.beta * h)
return out
得到归一化的注意力系数后,使用归一化的值计算对应特征的线性组合,作为每个顶点最后的输出特征(最后可以加一个非线性层, σ \sigma σ):
h ⃗ i ′ = σ ( ∑ j ∈ N i α i j W h ⃗ j ) (4) \tag{4} \vec{h}'_i = \sigma(\sum_{j \in \mathcal{N}_i} \alpha_{ij} \mathbf{W} \vec{h}_j) hi′=σ(j∈Ni∑αijWhj)(4)
h ⃗ i ′ \vec{h}'_i hi′就是GAT输出的节点 i i i 融合了邻域信息的新特征
为了使self-attention 的学习过程更稳定,发现使用 multi-head attention来扩展注意力机制是很有效的。
使用K个独立的 attention 机制执行公式式4这样的变换,然后他们的特征连(concatednated)在一起,就可以得到如下的输出:
h ⃗ i ′ = ∥ k = 1 K σ ( ∑ j ∈ N i α i j k W k h ⃗ j ) (5) \tag{5} \vec{h}'_i = \Vert^{K}_{k=1} \sigma(\sum_{j \in \mathcal{N}_i} \alpha^k_{ij} \mathbf{W}^k \vec{h}_j) hi′=∥k=1Kσ(j∈Ni∑αijkWkhj)(5)
其中
下图表示 K = 3 K=3 K=3时的multi-head attention机制示意图。例如此图,节点1在邻域中具有多端注意机制,不同的箭头样式表示独立的注意力计算,通过连接或平均每个head获取 h ⃗ 1 \vec{h}_1 h1。
对于最后一个卷积层,如果还是使用multi-head attention机制,那么就不采取连接的方式合并不同的attention机制的结果了,而是采用求平均的方式进行处理,即
h ⃗ i ′ = σ ( 1 K ∑ k = 1 K ∑ j ∈ N i α i j k W k h ⃗ j ) (6) \tag{6} \vec{h}'_i = \sigma(\frac{1}{K} \sum^K_{k=1} \sum_{j \in \mathcal{N}_i} \alpha^k_{ij} \mathbf{W}^k \vec{h}_j) hi′=σ(K1k=1∑Kj∈Ni∑αijkWkhj)(6)
实验分成两部分,transductive learning(半监督学习)和inductive learning(归纳学习)。
图结构的数据集,以及数据集之中的信息如下:
最后,使用t-SNE(Maaten & Hinton, 2008)在Cora数据集上进行一层GAT模型的输出变换图如下所示
图注意力模型GAT用注意力机制替代了图卷积中固定的标准化操作。下图和公式定义了如何对第 l l l层节点特征做更新得到第 l + 1 l+1 l+1层节点特征:
z i ( l ) = W ( l ) h i ( l ) (1) \tag{1} z_{i}^{(l)}=\mathbf{W}^{(l)} h_{i}^{(l)} zi(l)=W(l)hi(l)(1)
e i j ( l ) = LeakyReLU( a ⃗ ( l ) T ( z i ( l ) ∥ z j ( l ) ) ) (2) \tag{2} \left.e_{i j}^{(l)}=\text { LeakyReLU( } \vec{a}^{(l)^{T}}\left(z_{i}^{(l)} \| z_{j}^{(l)}\right)\right) eij(l)= LeakyReLU( a(l)T(zi(l)∥zj(l)))(2)
α i j ( l ) = exp ( e i j ( l ) ) ∑ k ∈ N ( i ) exp ( e i k ( l ) ) (3) \tag{3} \alpha_{i j}^{(l)}=\frac{\exp \left(e_{i j}^{(l)}\right)}{\sum_{k \in \mathcal{N}(i)} \exp \left(e_{i k}^{(l)}\right)} αij(l)=∑k∈N(i)exp(eik(l))exp(eij(l))(3)
h i ( l + 1 ) = σ ( ∑ j ∈ N ( i ) α i j ( l ) z j ( l ) ) (4) \tag{4} h_{i}^{(l+1)}=\sigma\left(\sum_{j \in \mathcal{N}(i)} \alpha_{i j}^{(l)} z_{j}^{(l)}\right) hi(l+1)=σ⎝⎛j∈N(i)∑αij(l)zj(l)⎠⎞(4)
multi-head attention机制
神似卷积神经网络里的多通道,GAT 引入了多头注意力来丰富模型的能力和稳定训练的过程。每一个注意力的头都有它自己的参数。如何整合多个注意力机制的输出结果一般有两种方式:
h i ( l + 1 ) = σ ( 1 k ∑ k = 1 K ∑ j ∈ N ( i ) α i j k W k h j ( l ) ) (6) \tag{6} h_{i}^{(l+1)}=\sigma\left(\frac{1}{k} \sum_{k=1}^{K} \sum_{j \in N(i)} \alpha_{i j}^{k} W^{k} h_{j}^{(l)}\right) hi(l+1)=σ⎝⎛k1k=1∑Kj∈N(i)∑αijkWkhj(l)⎠⎞(6)
对于上述公式的一些解释:
参考:https://github.com/dmlc/dgl/tree/master/examples/pytorch/gat
有错误的地方还望不吝指出,欢迎进群交流GNNs&GCNs(入群备注信息!!!,格式:姓名 -(学校或其他机构信息)- 研究方向)。
Graph Attention Network (GAT)
DGL博客 | 深入理解图注意力机制