目录
1.快速了解的例子:
(1)假设所有节点的初始特征都是[1, 0, 0] ,那么AX的结果是:
(2) 的结果是:
(3) 总结:
2.计算结构系数的例子
(1)源代码的计算形式是:
(2) 正常的AX是:
(3) A转置以后发现和上面的源代码的 X 是一致的;仅仅展示转换后的结果;
3.总结:
1.快速了解的例子:
来看这个例子:
目标节点是有向边箭头指向的点。在有向图中,每条有向边都有一个起点和一个终点,起点被称为源节点,终点被称为目标节点。箭头从源节点指向目标节点,表示数据或信息从源节点流向目标节点。
(1)假设所有节点的初始特征都是[1, 0, 0] ,那么AX的结果是:
可以看到每一行的结果表示的是从目标节点传出的信息的和
(2) 的结果是:
这里每一行的结果才是从源节点(邻居节点)传入目标节点的信息。
(3) 总结:
pytorch geometric中为何要将稀疏邻接矩阵写成转置的形式adj_t?
原因就是:
- 首先
pytorch geometric
的边信息可以有两种存储模式,第一种是edge_index
,它的shape是[2, N]
,其中N
是边的数目。第一个N
维的元素存储边的原点的信息,称为source
,第二个N
维的元素存储边的目标点的信息,称为target。
举个例子,如果我们有以下这样一张有向图,那么edge_index
是这样的:tensor([[1, 2, 3, 4], [0, 0, 0, 0]])
,边是(1,0), (2,0), (3,0), (3,0)
- 如果以上的图是无向图的话,那么0这个节点也指向1,2,3,4这几个节点,edge_index则应该是这样的: tensor([[1, 2, 3, 4,0, 0, 0, 0], [0, 0, 0, 0, 1, 2, 3, 4]]),边是(1,0), (2,0), (3,0), (3,0), (0,1), (0,2), (0,3), (0,4)。edge_index这么写的原因是,在pytorch geometric中,用scatter一类的方式可以很方便地实现,从source到target,这种默认的边传递方式。(当然传递方式你也可以改成从target传递到source。)
pytorch geometric
的边信息的第二种存储模式是adj_t
,它是一个sparse tensor
。这里我们看到作者在adj
后面加上了t
,说明它是邻接矩阵的转置。为什么要写成转置呢,我们接着上面edge_index
讲- edge_index中信息传递是source to target,也就是edge_index[0] to edge_index[1],而adj计算的是将原图的有向边的方向调转以后的新图:然后得到新图上从邻居节点到目标节点聚合的消息。所以在做矩阵计算传递信息的时候,作者将 adj 转换成adj_t ,并且将它作为默认形式,这样计算的也就是从源节点到目标节点的信息和,这样就保持了一致。
2.计算结构系数的例子
节点的度数作为节点的初始特征
传入各节点的消息(不算自己):
- 0:[0,1,0]*0.5+[0,1,0]*0.5 = [0, 1, 0]
- 1: [0,1,0]*0.5+[0,1,0]*0.5 = [0, 1, 0]
- 2: [0,1,0]*0.5+[1,0,0]*0,5 =[1/2, 1/2, 0]
- 3: [0,1,0]*1/3+[0,1,0]U*1/3+[0,0,1]*1/3=[0, 2/3, 1/3]
- 4: [0,1,0]*0.5+[0,1,0]*0.5 = [0, 1, 0]
- 5: [1,0,0]*1= [1,0,0]
- 6: [0,1,0]*0.5+[1,0,0]*0,5 =[1/2, 1/2, 0]
(1)源代码的计算形式是:
这里的A不是标准的A,是weight,在计算的结构系数时候,weight[node][index]表示的是邻居 index 对与目标节点 node的重要程度。结果是:
(2) 正常的AX是:
计算的将原图的有向边的方向调转以后的新图:然后得到新图上从邻居节点到目标节点聚合的消息。
(3) A转置以后发现和上面的源代码的 X 是一致的;仅仅展示转换后的结果;
所以源代码的计算结果没错的。我的思路也是对的。
算的是正儿八经的原图的从源节点(邻居节点)到目标节点的信息。
3.总结:
- 对于无向图来说,A默认边上的权重都为1,所以A和A的转置结果一致,其中在PYG中,有向图还是作为有向图去处理了,上边edge_index的例子就是最好的说明。
- 当遇到有向图,尤其是节点之间互相有边,边上的权重还不一样,那么就要注意将A转换为A的转置进行矩阵乘法。
参考的文章有:
pytorch geometric中为何要将稀疏邻接矩阵写成转置的形式adj_t_pytorch中的稀疏矩阵为什么要转置-CSDN博客