Re0:读论文 PPNP/APPNP Predict then Propagate: Graph Neural Networks meet Personaliz

260 阅读12分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第12天

本文首发于CSDN。

诸神缄默不语-个人CSDN博文目录

PPNP官方网站:PPNP - Data Analytics and Machine Learning Group

@[toc]

1. 模型构造思路

整体思路: message passing系模型都很难将聚集的邻居扩大,也就是多卷几层扩大感受野。一是因为聚合求平均太多层会平滑,即over-smoothing问题,本文主要关注这一问题;二是因为层数增多也会增多参数,但是这一问题可以用共享参数解决,本文重点不在此,但本文提出的方法也成功减少了参数。 message passing本质是Laplacian smoothing,message passing系GNN(如GCN等)会出现over-smoothing问题,即如果网络层数增多,各节点的嵌入都会趋于相近,就无法反映各节点的自有特征。 因此这些模型无法加深层数,只能在较近的邻居之间传播信息,限制其表示能力。但是在需要更多信息,尤其是对于边缘节点(实证结果见Appendix I)和有标签节点较少(实证结果见Figure 3和Appendix H)时,就是需要远程传播信息,所以本文提出了能够更远、更深传播信息而不over-smooth的 PPNP / APPNP 模型。 原始GCN节点之间的影响程度与随机游走分布成比例,随机游走最终会趋于稳定,所以GCN节点影响程度也会趋于相同。PageRank得分即随机游走稳定分布,会得到全图的结构信息。而使用以根节点为teleport set 的 Personalized PageRank(PPR)方法能得到各节点独有的局部结构信息,这样就能保存住各节点的独有信息。 本文提出的PPNP将predict和propagate阶段拆开,在predict阶段仅用节点特征来进行预测,在propagate阶段用PPR对预测值进行信息传递,这样能在远程传播中仍然保留节点局部信息,而且不需要过多的参数。 PPNP使PPR收敛至稳定状态。由于PPNP计算代价过高,在此基础上提出了代价较小的近似模型APPNP,只迭代有限次PPR。

PPR引入的思路: 根据[JK][^1],GNN中节点 xxyy 的influence score:I(x,y)=ijZyiXxjI(x,y)=\sum_i\sum_j\frac{\partial\mathbf{Z}_{yi}}{\partial\mathbf{X}_{xj}}xx 特征各项元素对 yy 嵌入各项元素的影响程度的加总,感觉很有点经济学弹性概念内味[^2])。在k层GCN中,I(x,y)Prw(xy,k)I(x,y)∝P_{rw'}(x\rightarrow y,k)(一个经微调的(没说咋调的,看意思应该是把转移矩阵换成 A~^\hat{\tilde{A}}?)从 xx 开始的random walk distribution)。 在 kk\rightarrow\infty 且图 irreducible and aperiodic 时,该值会趋于一个与 xx 无关的稳定分布(Plim(y)P_{lim}(\rightarrow y)),这个分布可通过 πlim=A~^ πlim\pi_{lim}=\hat{\tilde{\mathbf{A}}}\ \pi_{lim} 计算得到。也就是说任何节点对该节点的影响程度最后会是一个相同的值,这样跟节点的局部信息就无关了。 这样证明了GCN和RW的关系(我没仔细看JK文章,反正APPNP逻辑应该是这样),此外根据[BP][^3] 我们知道原始PageRank就是随机游走的稳定分布(πpr=Arw πpr\pi_{pr}=\mathbf{A}_{rw}\ \pi_{pr}),体现整个图的全局结构。PPR的结果则会考虑到我们感兴趣的节点集,而APPNP本文对根节点感兴趣,也就相当于跑了个RWR(Random Walk with Restart)(πppr(ix)=(1α)A~^πppr(ix)+α ix\pi_{ppr}(\mathbf{i}_x)=(1-\alpha)\hat{\tilde{\mathbf{A}}}\pi_{ppr}(\mathbf{i}_x)+\alpha\ \mathbf{i}_x)。 这样从每个节点开始随机游走直至稳定最后得到的PPR就能保存根节点局部结构信息。I(x,y)I(x,y) ∝ PPR πppr(ix)y\pi_{ppr}(\mathbf{i}_x)_y 与根节点有关。

2. Notation和模型介绍

2.1 notation

图\ &G=(V,E) \\ &n=|V| \\ &m=|E| \\ 节点特征\ &\mathbf{X}\in\mathbb{R}^{n\times f} \\ 节点标签(独热编码)&\mathbf{Y}\in\mathbb{R}^{n\times c} \\ 邻接矩阵\ &\mathbf{A} \\ &\tilde{\mathbf{A}}=\mathbf{A}+\mathbf{I}_n \\ &\tilde{\mathbf{D}}_{ii}=\sum_j\tilde{\mathbf{A}}_{ij} \\ &\mathbf{A}_{rw}=\mathbf{A}\mathbf{D}^{-1} \\ &\hat{\tilde{\mathbf{A}}}=\tilde{\mathbf{D}}^{-\frac{1}{2}}\tilde{\mathbf{A}}\tilde{\mathbf{D}}^{-\frac{1}{2}} \\ \text{influence score}\ &I(x,y)=\sum_i\sum_j\frac{\partial\mathbf{Z}_{yi}}{\partial\mathbf{X}_{xj}} \\ 随机游走分布\ &P \\ \text{随机游走稳定分布/PageRank/PPR}\ &\pi \end{aligned}$$ (那个$\tilde{\mathbf{D}}$我用的是GCN的写法,就是度矩阵。因为我没看懂PPNP本文的写法里面那个$\delta$是啥东西?但是它说用的是GCN里面的表示法,所以我就去GCN那边抄公式了) ## 2.2 PPNP公式 predict:$\mathbf{H}_{i,:}=f_\theta(\mathbf{X}_{i,:})$ $f$:仅使用每个节点的特征建立神经网络模型,神经网络参数为 $\theta$,得到预测结果 $\mathbf{H}\in\mathbb{R}^{n\times c}$。 propagate:$\mathbf{Z}_{\text{PPNP}}=\text{softmax}\Big(\alpha\big(\mathbf{I}_n-(1-\alpha)\hat{\tilde{\mathbf{A}}}\big)^{-1}\mathbf{H}\Big)$ 这里的 $\hat{\tilde{\mathbf{A}}}$ 可以替换成任何propagation matrix(例如 $\mathbf{A}_{rw}$)<font color='red'>(我的理解是可以换成任何一个可作为状态转移矩阵的stochastic matrix)</font> ## 2.3 APPNP公式 PPR矩阵 $\Pi_{\text{ppr}}=\alpha\big(\mathbf{I}_n-(1-\alpha)\hat{\tilde{\mathbf{A}}}\big)^{-1}$ 是个稠密矩阵,PPNP的复杂度达 $\mathcal{O}(n^2)$ <font color='red'>(其实矩阵稀疏和稠密这块我也还不了解,就大概看起来是这么一回事吧)</font> <font color='red'>(就我感觉这个简化写法就类似于PageRank的power iteration不迭代到收敛,但是在论文中提到了topic-sensitive PageRank,我没看那个论文,所以不理解这部分含义。总之逻辑大概就是模拟RWR)</font> $\mathbf{Z}^{(0)}=\mathbf{H}=f_\theta(\mathbf{X})$ $\mathbf{Z}^{(k+1)}=(1-\alpha)\hat{\tilde{\mathbf{A}}}\mathbf{Z}^{(k)}+\alpha\mathbf{H}$ $\mathbf{Z}^{(K)}=\text{softmax}\big((1-\alpha)\hat{\tilde{\mathbf{A}}}\mathbf{Z}^{(K-1)}+\alpha\mathbf{H}\big)$ 其中 $k\in[0,K-2]$ prediction matrix $\mathbf{H}$ 同时作为 starting vector 和 teleport set 保持矩阵稀疏度,而且不会构建出 $n\times n$ 的大方阵。 APPNP只有线性复杂度。 迭代收敛证明见Appendix B。 # 3. 详细的数学推导和证明 ## 3.1 message passing系GNN的over-smoothing问题 就我之前对此问题的理解就很直觉,就是感受野越广,各节点邻居重叠越大,所以得到的结果就越像(就,一样的邻居嘛……)。(来自cs224w,可参考我之前撰写的笔记:[cs224w(图机器学习)2021冬季课程学习笔记9 Graph Neural Networks 2: Design Space](https://blog.csdn.net/PolarisRisingWar/article/details/117989170)) 在本文中提到GCN本质上是Laplacian smoothing,给了两篇参考文献: [Qimai Li, Zhichao Han, and Xiao-Ming Wu. Deeper Insights Into Graph Convolutional Networks for Semi-Supervised Learning. In AAAI, 2018.](https://arxiv.org/abs/1801.07606) [Keyulu Xu, Chengtao Li, Yonglong Tian, Tomohiro Sonobe, Ken-ichi Kawarabayashi, and Stefanie Jegelka. Representation Learning on Graphs with Jumping Knowledge Networks. In ICML, 2018.](http://proceedings.mlr.press/v80/xu18c/xu18c.pdf) 就我简单看了一下第一篇作者自己写的介绍:[Laplacian Smoothing and Graph Convolutional Networks – Qimai's Home](https://liqimai.github.io/blog/AAAI-18/),<font color='red'>实话实说,没有看懂。就我委实没有搞懂拉普拉斯矩阵那一堆是在搞什么</font> 然后第二篇也是提出influence score $I(x,y)$ 的那篇论文。论文里与之相关的内容我在第一部分和3.2部分写了。 ## 3.2 GCN收敛,RW极限,PageRank和PPR,influence score PageRank的矩阵表达式、power iteration等可参考我之前写的博文:[cs224w(图机器学习)2021冬季课程学习笔记4 Link Analysis: PageRank (Graph as Matrix)](https://blog.csdn.net/PolarisRisingWar/article/details/117455491) 随着GCN层数增加,influence score $I(x,y)$ 与RW的分布成正比,这个分布随着迭代数(层数)增加,最后会收敛到与起始节点无关的稳定状态。 RW的极限分布 $\pi$ 与起始节点(根节点)无关,这个极限分布也是PageRank的结果 $\pi$。 *** 原始PageRank迭代式:$\pi=\mathbf{A}_{rw}\cdot \pi$ ($\mathbf{A}_{rw}=\mathbf{A}\mathbf{D}^{-1}$) 带自环 + teleport set(图中任一节点)的PageRank迭代式:$\pi=(1-\alpha)\tilde{\mathbf{A}}_{rw}\cdot \pi+\alpha\left[\dfrac{1}{N}\right]_{N}$ ($\tilde{\mathbf{A}}_{rw}=\tilde{\mathbf{A}}\tilde{\mathbf{D}}^{-1}$,$\left[\dfrac{1}{N}\right]_{N}$ 是每个元素都是 $\dfrac{1}{N}$ 的向量) * * * 本文使用的PPR的teleport就是根节点:$\pi_{ppr}(\mathbf{i}_x)=(1-\alpha)\hat{\tilde{\mathbf{A}}}\pi_{ppr}(\mathbf{i}_x)+\alpha\ \mathbf{i}_x$&emsp;① ($\hat{\tilde{\mathbf{A}}}=\tilde{\mathbf{D}}^{-\frac{1}{2}}\tilde{\mathbf{A}}\tilde{\mathbf{D}}^{-\frac{1}{2}}$) (<font color='red'>我就是看不懂为什么能这样换转移矩阵!</font>) PPR能够保留初始节点的信息,这事在直觉上还挺明显的,就你一直在试图往回跳嘛,那最后的稳定状态肯定是跟teleport set有关的。 <font color='red'>严谨证明不知道有没有,我还没看PageRank和主题PageRank的论文。</font> 上式做线性转换易得:$\pi_{ppr}(\mathbf{i}_x)=\alpha\big[\mathbf{I}_n-(1-\alpha)\hat{\tilde{\mathbf{A}}}\big]^{-1}\mathbf{i}_x$ 用单位阵 $I$ 代替指示向量 $\mathbf{i}_x$: PPR矩阵:$\Pi_{ppr}(\mathbf{i}_x)=\alpha\big[\mathbf{I}_n-(1-\alpha)\hat{\tilde{\mathbf{A}}}\big]^{-1}$ 逆必存在,证明见Appendix A。 PPR矩阵对应行列的元素就是对应节点之间的influence score。 PPNP公式就是直接用PPR矩阵左乘 $\mathbf{H}$(predict输出)。 就相当于直接求以 $\mathbf{H}$ 为starting vector的RWR(以根节点为teleport set的PPR)的最终稳定分布。 APPNP公式就是用①式进行跑RWR,以 $\mathbf{H}$ 作为teleport set和初始starting vector。 直觉大概可以理解为通过RWR把信息传播到K(迭代数)层邻居上。 通过Appendix B证明APPNP迭代最终收敛到PPNP公式上。 ## 3.3 $\mathbf{A}_{rw}$ 和 $\hat{\tilde{\mathbf{A}}}$ <font color='red'>反正都能拿来当RW的转移矩阵,而且公式里写明了可以互换。但是具体咋回事我还妹整明白。<br> $\mathbf{A}_{rw}$ 的话我能理解,因为PageRank的公式就是这么写的,就是 $r_j=\sum\limits_{i\rightarrow j}\dfrac{1}{d_i}\cdot r_i$嘛。 带上自环就是带上自环了嘛。<br> $\hat{\tilde{\mathbf{A}}}$ 是咋回事?GCN那块数学我就没看懂,难道我还要再磨一趟GCN吗…… 这玩意它满足stochastic matrix的要求不我都妹整明白。 如果用 $\hat{\tilde{\mathbf{A}}}$ 的话,我把三部分拆开(没管自环)做了一下矩阵乘法,迭代式就变成了(我没考虑有向边的情况,所以ij顺序可能是写反的):$r_j=\sum_i\dfrac{1}{\sqrt{d_i}}(\sum_j\dfrac{1}{\sqrt{d_j}}\cdot A_{ji})\cdot r_i$ ……虽然看上去还挺规整的,但这是个什么玩意啊?<br><br> (补一个来自学长的指导: $\hat{\tilde{\mathbf{A}}}$ 可视为 $\mathbf{A}_{rw}$ 的一个变体) $$\mathbf{X}^{\prime} = \mathbf{\hat{D}}^{-1/2} \mathbf{\hat{A}} \mathbf{\hat{D}}^{-1/2} \mathbf{X} \mathbf{\Theta} \\ \mathbf{x}^{\prime}_i = \mathbf{\Theta} \sum_{j \in \mathcal{N}(v) \cup \{ i \}} \frac{e_{j,i}}{\sqrt{\hat{d}_j \hat{d}_i}} \mathbf{x}_j \\ \text{(公式源自PyG的GCNConv文档)}$$ 就,be like:![在这里插入图片描述](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/60efe318d1dc460d85b9bf89c1fef158~tplv-k3u1fbpfcp-zoom-1.image) </font> 顺带一提: PageRank用的是$AD^{-1}$,所以上图是按发出信息方的度数算;如果用$D^{-1}A$就应该是按接收信息方的度数算了。 马尔科夫假设那块我还没搞懂,但是我看说$D^{-1}A$是row-stachastic matrix,$AD^{-1}$是column-stochastic matrix(如果我没搞错的话),所以应该都能拿来作为转移矩阵,都能收敛? 然后$D^{-\frac{1}{2}}AD^{-\frac{1}{2}}$是对称归一化,也能收敛。 大概就这样理解吧,我搞够了。 ## 3.4 附录A:证明 $\Pi_{\text{ppr}}$ 存在 即证明 $\mathbf{I}_n-(1-\alpha)\hat{\tilde{\mathbf{A}}}$ 存在逆矩阵。 即证明 $\det\Big(\mathbf{I}_n-(1-\alpha)\hat{\tilde{\mathbf{A}}}\Big)\neq0$ 即证明 $\det\Big(\dfrac{1}{1-\alpha}\mathbf{I}_n-\hat{\tilde{\mathbf{A}}}\Big)\neq0$ 如果 $\dfrac{1}{1-\alpha}$ 不是 $\hat{\tilde{\mathbf{A}}}$ 的特征值,上式就恒成立。 ∵ $\alpha<1$ 恒成立 ∴ $\dfrac{1}{1-\alpha}>1$ 恒成立 证明一下 $\hat{\tilde{\mathbf{A}}}$ 和 row-stachastic matrix $\mathbf{A}_{rw}$ 特征值相同: ![在这里插入图片描述](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/348bf8b3d7f34b73a1f364692b6a4294~tplv-k3u1fbpfcp-zoom-1.image) 因为 row-stachastic matrix 的最大特征值为1(<font color='red'>根据Gershgorin circle theorem可证,我也不知道这个是啥</font>),所以 $\dfrac{1}{1-\alpha}>1$ 不可能是 $\hat{\tilde{\mathbf{A}}}$ 的特征值,所以原式可证。 ## 3.5 附录B:证明APPNP收敛于PPNP 还没看,待补。 # 4. 实验结果 还没写,待补。 # 5. 代码实现和复现 ## 5.1 论文官方实现 [klicperajo/ppnp: PPNP & APPNP models from "Predict then Propagate: Graph Neural Networks meet Personalized PageRank" (ICLR 2019)](https://github.com/klicperajo/ppnp) 还没看,待补。 ## 5.2 PyG官方实现 APPNP类,官方文档:[torch_geometric.nn — pytorch_geometric 1.7.2 documentation](https://pytorch-geometric.readthedocs.io/en/latest/modules/nn.html#torch_geometric.nn.conv.APPNP) 源代码:[torch_geometric.nn.conv.appnp — pytorch_geometric 1.7.2 documentation](https://pytorch-geometric.readthedocs.io/en/latest/_modules/torch_geometric/nn/conv/appnp.html) 他这个用MessagePassing实现的基类我就没太看懂……就是,唉,当年GCN那个怎么从矩阵拆成向量形式的我就没搞懂,这个我就更没搞懂了! 我看这个实现逻辑里面用到了 `gcn_norm()` 这个函数,这个我查了一下是GCNConv类里面用到的函数。GCNConv源代码在这里:[torch_geometric.nn.conv.gcn_conv — pytorch_geometric 1.7.2 documentation](https://pytorch-geometric.readthedocs.io/en/latest/_modules/torch_geometric/nn/conv/gcn_conv.html) 然后呢我也没咋看懂这个的实现逻辑。就……意思应该是计算 $\hat{\tilde{\mathbf{A}}}$,但是,妈的,他到底是咋搞的啊! 我寻摸着,这个类的实现逻辑大概是:用 `gcn_norm()` 计算出 $\hat{\tilde{\mathbf{A}}}$,然后用MessagePassing基类的 `propage()` 方法来计算公式,叠个dropout,以上过程实现K次(顺序我也没搞懂,因为我没看懂)。 ## 5.3 我自己写的复现 还没加dropout。 还没优化。 ### 5.3.1 APPNP:dense Tensor ```python class APPNP_self1(torch.nn.Module): #参考PyG设置的参数什么的 #就PyG设置的就是没有predict部分,所以我也把predict部分放在GNNStack里面了 #就我想了一下,我觉得用MessagePassing类不方便,就还是用torch的Module类了 def __init__(self,K,alpha): #别的参数暂时省略 super(APPNP_self1,self).__init__() self.K=K self.alpha=alpha def forward(self, x, edge_index): #首先尝试使用dense_tensor,如果不行再转sparse_tensor (row, col)= edge_index node_num=max(row.max(),col.max())+1 adj = torch.zeros((node_num,node_num)) adj=adj.to(hp['device']) adj[row, col] = torch.ones(row.numel()).to(hp['device']) self_loop=torch.eye(adj.size()[0]).to(hp['device']) #自环 adj=adj+self_loop #\slide{A} degree_vector=torch.sum(adj,dim=1).cpu() #度矩阵 degree_vector=1/np.sqrt(degree_vector) #D-1/2 degree_matrix=torch.diag(degree_vector).to(hp['device']) adj=torch.mm(degree_matrix,adj) adj=torch.mm(adj,degree_matrix) #\hat{\slide{A}} H=x.clone() Z=x.clone() for k in range(self.K-1): Z=torch.mm(adj,Z) Z=Z*(1-self.alpha) Z=Z+self.alpha*H Z=torch.mm(adj,Z) Z=Z*(1-self.alpha) Z=Z+self.alpha*H Z=F.log_softmax(Z, dim=1) return Z ``` 在CPU上跑得贼慢,在GPU上OOM了…… ### 5.3.1 APPNP:稀疏矩阵 我用的是PyTorch的稀疏矩阵(torch.sparse),文档:[torch.sparse — PyTorch 1.9.0 documentation](https://pytorch.org/docs/stable/sparse.html) 我参考了一下PyG和论文官方实现,PyG用的是torch_sparse,这个库他妈的没有文档就算了,GitHub项目里面代码连个注释都没有。大佬是真的牛逼,他怎么做到自己写的代码自己看得懂的?…… 论文官方用的是scipy的稀疏矩阵,这个我还没有了解过。 ```python def edge_index2sparse_tensor(edge_index,node_num): sizes=(node_num,node_num) v=torch.ones(edge_index[0].numel()).to(hp['device']) #边数 return torch.sparse_coo_tensor(edge_index, v, sizes) class APPNP_self2(torch.nn.Module): def __init__(self,K,alpha): #别的参数暂时省略 super(APPNP_self2,self).__init__() self.K=K self.alpha=alpha def forward(self, x, edge_index): node_num=x.size()[0] edge_index, _ = pyg_utils.add_self_loops(edge_index,num_nodes=node_num) #添加自环(\slide{A}) adj=edge_index2sparse_tensor(edge_index,node_num) #将\slide{A}转换为稀疏矩阵 degree_vector=torch.sparse.sum(adj,0) #度数向量 degree_vector=degree_vector.to_dense().cpu() degree_vector=1/np.sqrt(degree_vector) degree_matrix=torch.diag(degree_vector).to(hp['device']) adj=torch.sparse.mm(adj.t(),degree_matrix.t()) adj=adj.t() adj=torch.mm(adj,degree_matrix) adj=adj.to_sparse() H=x.clone() for k in range(self.K-1): x=torch.mm(adj,x) x=x*(1-self.alpha) x=x+self.alpha*H x=torch.mm(adj,x) x=x*(1-self.alpha) x=x+self.alpha*H x=F.log_softmax(x, dim=1) return x ``` ### 5.3.3 PPNP 还没写,待补。 ## 5.4 复现实验结果对比 [APPNP和C&S复现](https://github.com/PolarisRisingWar/all-notes-in-one/blob/main/APPNP%E5%92%8CC%26S%E5%A4%8D%E7%8E%B0.ipynb) 未完待续。 # 6. 参考资料 1. 我参考了这两篇讲解同一论文的博文: 1. [APPNP_fnoi2014xtx的博客-CSDN博客](https://blog.csdn.net/fnoi2014xtx/article/details/107567629) 3. [APPNP:一个更强大的用于半监督分类的图卷积网络模型 - 知乎](https://zhuanlan.zhihu.com/p/149161553) 2. 关于拉普拉斯矩阵平滑这一概念(没看懂……不是,主要是没搞懂拉普拉斯平滑跟message passing的关系,拉普拉斯平滑本身感觉就是一种正则化方式了): 1. [神奇的拉普拉斯平滑(Laplacian Smoothing)及其在正则化上的应用~_love模式识别-CSDN博客_拉普拉斯平滑](https://blog.csdn.net/wsj998689aa/article/details/40303561) 2. [谈谈自己对正则化的一些理解~_love模式识别-CSDN博客_对正则化的理解](https://blog.csdn.net/wsj998689aa/article/details/39547771) 3. [拉普拉斯平滑(Laplacian smoothing)_潜心学习的渣渣的博客-CSDN博客_拉普拉斯平滑](https://blog.csdn.net/weixin_43868020/article/details/106602799) 3. [JK 《Representation Learning on Graphs with Jumping Knowledge Networks》](http://proceedings.mlr.press/v80/xu18c/xu18c.pdf) 的一些讲解博文。不过都没讲解在APPNP论文中强调的influence score问题,我简单浏览了一下原文,好像influence score和RW相关的问题还要见《Random Walks on Graphs》一文,我一看,妈耶,一篇40多页的综述…… 1. [读书笔记3:Representation Learning on Graphs with Jumping Knowledge Networks_b224618的博客-CSDN博客](https://blog.csdn.net/b224618/article/details/81125622) 2. [论文分享 |Jumping Knowledge Networks_geek_wh2016的博客-CSDN博客](https://blog.csdn.net/geek_wh2016/article/details/81297106) 4. [BP 《The PageRank Citation Ranking: Bringing Order to the Web》](http://web.mit.edu/6.033/2004/wwwdocs/papers/page98pagerank.pdf) 5. Random Walks on Graphs: A Survey, Combinatorics, Paul Erdos is Eighty 40多页的综述,搞我呢,以后有缘了再看吧。 [^1]: [JK 《Representation Learning on Graphs with Jumping Knowledge Networks》](http://proceedings.mlr.press/v80/xu18c/xu18c.pdf) [^2]: 要说为什么我现在看到偏导就会想到弹性……那只能回忆起一个夏天,我一开始学微积分就被灌输了弹性概念,从此经济学的弹性永远与数学的导数与偏导概念如影相随,萦绕我心。 第一印象害死人。 [^3]: [BP 《The PageRank Citation Ranking: Bringing Order to the Web》](http://web.mit.edu/6.033/2004/wwwdocs/papers/page98pagerank.pdf)