关系图卷积网络(Relational-GCN)
前面的示例描述了GCN在无向和无类型图上的行为。如前所述,更新过程基于以下步骤(在以下说明中,为简单起见,不考虑节点度)。
通过将(i)单热点特征矩阵与(ii)权重矩阵相乘,可以实现投影步骤(或线性变换)。
(i)2D矩阵(n,n),用于定义表示节点的独热向量。
(ii)定义隐藏特征的2D矩阵(n,h)。当前矩阵仅编码一种类型的关系。
将邻接矩阵(i)与投影步骤产生的矩阵(ii)相乘,即可实现一个聚合步骤。
(i)2D对称矩阵(n,n),描述无向和无类型的边。
(ii)投影步骤产生的2D矩阵(n,h)。
为了扩展GCN层以编码KG结构,我们需要将我们的数据表示为有向图和多类型图。更新/聚合过程与上一个类似,但是组成部分稍微复杂一些。下面提供了有关执行步骤的详细信息。
通过将(i)独热点特征矩阵与(ii)权重张量相乘,可以实现投影步骤。
(i)定义节点初始特征的2D矩阵(n,n)。
(ii)描述节点隐藏特征的3D张量(r,n,h)。该张量能够通过堆叠大小为(n,h)的r批矩阵来编码不同的关系。每个批都编码单个类型的关系。
投影步骤将不再是矩阵的简单乘法,而是批次矩阵乘法,其中(i)与(ii)的每一批相乘。
聚合步骤,是通过将(i)(有向)邻接张量乘以(ii)由投影步骤得出的张量而实现的。
(i)描述有向和r型边的3D张量(r,n,n)。该张量由r批邻接矩阵(n,n)组成。每个邻接矩阵根据特定类型的关系描述节点之间的边。而且,与无向图的邻接矩阵相比,这些邻接矩阵中的每一个都不对称,因为它编码特定的边缘方向。
(ii)由上述投影步骤产生的3D张量(r,n,h)。
就像投影步骤一样,聚合阶段包括一个批处理矩阵乘法。每批(i)乘以每批(ii)。此汇总定义了每个批次的GCN转换。在该过程的最后,必须将批次加在一起(R-GCN),以获得根据不同关系类型并入邻域聚合的节点表示。
以下代码示例显示了R-GCN层的行为,该行为编码具有两种类型的边(或关系)的有向和多类型图或KG。
###Recall: One-hotvectorrepresentationofnodes (n,n) print(X)-----[[0.0.1.0.0.] #Node1 [0.1.0.0.0.] ... [0.0.0.0.1.] [1.0.0.0.0.] [0.0.0.1.0.]] ###Numberofrelationtypes (r) num_rels=2###Weightmatrixofrelationnumber1 (n,n) ##InitializationaccordingtoGlorotandBengio (2010)) W_rel1=np.random.uniform(-np.sqrt(1./h),np.sqrt(1./h),(n,h)) print(W_rel1) -----[[-0.46378913-0.091097070.52872529] [ 0.038295970.22156061-0.2130242 ] [ 0.215352720.38639244-0.55623279] [ 0.288841780.564488160.28655701] [-0.253521440.334031-0.45815514]] ###Weightmatrixofrelationnumber2 (n,h) ##RandominitializationwithuniformdistributionW_rel2=np.random.uniform(1/100, 0.5, (n,h)) print(W_rel2) -----[[0.229467830.45521180.15387093] [0.151009920.0737140.01948981] [0.342629410.113697780.14011786] [0.250870850.036147650.29131763] [0.0818970.298759710.3528816 ]] ###Tensorincludingbothweightmatrices (r,n,h) W_rels=np.concatenate((W_rel1, W_rel2)) W_rels=np.reshape(W_rels,(num_rels, n, h)) print(W_rels) -----[[[-0.46378913-0.091097070.52872529] [ 0.038295970.22156061-0.2130242 ] [ 0.215352720.38639244-0.55623279] [ 0.288841780.564488160.28655701] [-0.253521440.334031-0.45815514]] [[ 0.229467830.45521180.15387093] [ 0.151009920.0737140.01948981] [ 0.342629410.113697780.14011786] [ 0.250870850.036147650.29131763] [ 0.0818970.298759710.3528816 ]]] ###Lineartrasformationwithbatchmatrixmultiplication (r,n,h) L_0_rels=np.matmul(X, W_rels) print(L_0_rels) -----[[[ 0.215352720.38639244-0.55623279] #Node1 (3rdrowofW_rel1) [ 0.038295970.22156061-0.2130242 ] [-0.253521440.334031-0.45815514] [-0.46378913-0.091097070.52872529] [ 0.288841780.564488160.28655701]] [[ 0.342629410.113697780.14011786] #Node1 (3rdrowofW_rel2) [ 0.151009920.0737140.01948981] [ 0.0818970.298759710.3528816 ] [ 0.229467830.45521180.15387093] [ 0.250870850.036147650.29131763]]] ###Adjacencymatrixofrelationnumber1 (n,n) A_rel1=np.random.randint(2, size=(n, n)) np.fill_diagonal(A, 0) #Noself_loopprint(A_rel1) -----[[01111] #ConnectionstoNode1withRel1 [11001] #ConnectionstoNode2withRel1 [10010] [00111] [11010]] ###Adjacencymatrixofrelationnumber2 (n,n) A_rel2=np.random.randint(3,size=(n,n)) np.fill_diagonal(A_rel2, 0) #NoselfloopA_rel2[A_rel2>1] =0-----[[00010] #ConnectionstoNode1withRel2 [10000] #ConnectionstoNode2withRel2 [10011] [00000] [01000]] ###Tensorincludingbothadjacencymatrices (r,n,n) A_rels=np.concatenate((A_rel1, A_rel2)) A_rels=np.reshape(A_rels, (num_rels, n, n)) print(A_rels) -----[[[01111] #ConnectionstoNode1withRel1 [11001] [10010] [00111] [11010]] [[00010] #ConnectionstoNode2withRel2 [10000] [10011] [00000] [01000]]] ### (GCN) Neighborhooddiffusionforeachtypededge (r,n,h) ND_GCN=np.matmul(A_rels, L_0_rels) print(ND_GCN) -----[[[-0.390172821.02898270.14410296] #UpdatedNode1withRel1 [ 0.542490471.17244121-0.48269997] [-0.248436410.29529538-0.0275075 ] [-0.428468790.807422090.35712716] [-0.210140430.51685598-0.2405317 ]] [[ 0.229467830.45521180.15387093] #UpdatedNode1withRel2 [ 0.342629410.113697780.14011786] [ 0.822968090.605057220.58530642] [ 0.0.0. ] [ 0.151009920.0737140.01948981]]] ### (R-GCN) AggregationofGCN (n,h) RGCN=np.sum(ND_GCN, axis=0) print(RGCN) -----[[-0.160704991.484194490.29797389] UpdatedNode1(Rel1+Rel2) [ 0.885119881.28613899-0.34258211] [ 0.574531680.90035260.55779892] [-0.428468790.807422090.35712716] [-0.059130520.59056998-0.22104189]] ###Testoftheaggregationassert(RGCN[0,0] ==L_0_rels[0,1,0] +L_0_rels[0,2,0] +L_0_rels[0,3,0] +L_0_rels[0,4,0] +L_0_rels[1,3,0])
你可以从这个例子中注意到,邻域扩散(GCN)的结果是一个大小为(r, n,h)的3D张量,而不是一个大小为(n,h)的2D矩阵。原因是,对于每种类型的关系,邻居扩散都是以一种单独的方式进行的。R-GCN层对GCN所实现的每种关系类型的节点表示进行聚合。为了阐明这个方面,考虑节点1的聚合表示
[-0.160704991.484194490.29797389]
这个向量是由节点1的更新表示与关系1相加得到的
[-0.390172821.02898270.14410296]
与关系2的节点1的更新表示
[ 0.229467830.45521180.15387093]
本节中描述的代码可以在数学上形式化如下:
描述R-GCN层执行的各向同性聚合的功能。与先前的功能相比,此聚合包括进一步的求和运算,该运算包括节点i和j之间的不同类型的边缘(E_ij)。为了简单起见,省略了节点的度数
总结
R-GCN代表了强大的图神经体系结构,可对诸如KG之类的多关系数据进行编码。在以后的文章中,我将向您展示如何利用这种编码能力在KG中执行特定任务,包括节点分类和链接预测。
如果要直接运行和测试代码,可以在此处下载可用的笔记本:
https://github.com/giuseppefutia/notebooks/blob/main/rgcn.ipynb
以下研究论文提供了有关R-GCN架构的更多详细信息: