LINE、SDNE和struc2vec图嵌入算法学习笔记

news2024/11/19 9:37:43

引言

在cs224w课程中,我先后总结了deepwalk、node2vec,这两种算是最经典也是最主流的做法,而在 图节点嵌入相关算法学习笔记 中,从头至尾,将一些经典算法用wiki的数据集复现了一下,所以本篇博文,主要想提及一下之前有用到,但不是很懂原理的算法,不过这里就不会总结得跟之前的deepwalk、node2vec这么详细,只做个人理解并且能说明当前算法过程的总结。

LINE

LINE介绍

真实世界的信息网络中,能观察到的直接链接仅占很小的比例,大部分链接都因观察不到而缺失。比如社交网络中,很多线下的关系链并没有百分之百同步到线上。如果顶点 v v v u u u 的链接发生缺失,则其一阶邻近度为 0,即使实际上它们关系非常密切。因此仅仅依靠一阶邻近度不足以描述网络的全局结构,我们需要寻找方法来解决这种因为大部分链接缺失导致的网络稀疏问题。

2014年的DeepWalk就是利用这种特征关系,采用了随机游走,来模拟这种二阶相似性,可它并没有提出相应的概率公式,LINE补充了这个方面,并一起提出了一阶相似性,如下图所示:

在这里插入图片描述

一阶相似性

网络中的一阶相似性是两个顶点之间的局部点对的相似度。对于有边 ( u , v ) (u,v) (u,v) 连接的每对顶点,该边的权重 W u v W_{uv} Wuv 表示 u u u v v v之间的一阶相似性,如果在 u u u v v v之间没有观察到边,他们的一阶相似性为0

二阶相似度

二阶相似度表示节点邻域结构的相似性,它能够了表征全局的网络结构。数学上,让 p u = ( w u , 1 , . . . , w u , ∣ V ∣ ) p_{u} = (w_{u,1},...,w_{u,|V|}) pu=(wu,1,...,wu,V) 表示一阶附近 u u u与所有其他的顶点,那么 u u u v v v之间的二阶相似性由 p u p_{u} pu p v p_{v} pv之间的相似性来决定。即如果两个节点共享许多邻居,则它们趋于相似,如果没有一个顶点同时和 u u u v v v连接,那么二阶相似性是0.

这里举个例子,如上图所示:

  • 顶点 67 是直接相连,拥有较高的一阶相似度,因此相互之间关系密切。映射到低维空间时,这两个顶点的相似度应该较高。
  • 顶点 65 有相同的邻居结点,拥有较高的二阶相似度,因此关系也很密切。映射到低维空间时,这两个顶点的相似度也应该较高。

一般正常情况下,二阶相似度的点往往要比一阶多得多,这在下一节的SDNE论文中有根据arxiv−GrQc数据集中体现,如下图:

在这里插入图片描述

LINE 创新点

这里参考LINE:Large-scale Information Network Embedding阅读笔记

作为2015年的论文,LINE算法是作为对标deepwalk的,在deepwalk基础上补充的二阶相似度,以及提出了一阶相似度。

LINE模型的一阶相似性: 对每个无向边 ( i , j ) (i,j) (i,j),定义顶点 v i v_{i} vi v j v_{j} vj 的概率联合分布公式为:

p 1 ( v i , v j ) = 1 1 + exp ⁡ ( − u ⃗ i T ⋅ u ⃗ j ) p_{1}\left(v_{i}, v_{j}\right)=\frac{1}{1+\exp \left(-\vec{u}_{i}^{T} \cdot \vec{u}_{j}\right)} p1(vi,vj)=1+exp(u iTu j)1

其中 u ⃗ i ∈ R d \vec{u}_{i} \in R^{d} u iRd 为顶点 v i v_{i} vi 的低维表达向量。

中间过程可以去看论文,大概就是为了在低维空间中保留一阶相似度,一个简单直接的方法是最小化目标函数,然后作者采用了 KL 散度作为两个分布的距离函数,因此最小化目标函数为:

O 1 = − ∑ ( i , j ) ∈ E w i , j × log ⁡ p 1 ( v i , v j ) O_{1}=-\sum_{(i, j) \in E} w_{i, j} \times \log p_{1}\left(v_{i}, v_{j}\right) O1=(i,j)Ewi,j×logp1(vi,vj)

LINE模型的二阶相似性: 二阶相似性假定与其他顶点共享邻居顶点的两个点彼此相似(无向有向均可),一个向量 u u u u ′ u^{'} u分别表示顶点本身和其他顶点的特定“上下文”,意为二阶相似。对于每个有向边 ( i , j ) (i,j) (i,j),我们首先定义由生成“上下文”的概率:

p 2 ( v j ∣ v i ) = exp ⁡ ( u ⃗ j ′ T ⋅ u ⃗ i ) ∑ k = 1 ∣ V ∣ exp ⁡ ( u ⃗ k ′ T ⋅ u ⃗ i ) p_{2}\left(v_{j} \mid v_{i}\right)=\frac{\exp \left(\vec{u}_{j}^{\prime T} \cdot \vec{u}_{i}\right)}{\sum_{k=1}^{|V|} \exp \left(\vec{u}_{k}^{\prime T} \cdot \vec{u}_{i}\right)} p2(vjvi)=k=1Vexp(u kTu i)exp(u jTu i)

这个公式在node2vec论文中也被提及了,不过是作为特征空间对称性假设进行推导,这里的推导还是以优化最小化一个目标函数:

O 2 = ∑ i ∈ V λ i d ( p ^ 2 ( ⋅ ∣ v i ) , p 2 ( ⋅ ∣ v i ) ) O_{2}=\sum_{i \in V} \lambda_{i} d\left(\hat{p}_{2}\left(\cdot \mid v_{i}\right), p_{2}\left(\cdot \mid v_{i}\right)\right) O2=iVλid(p^2(vi),p2(vi))

其中 d ( , ) d(,) d(,)为两种分布之间的距离, λ i \lambda_{i} λi来表示网络中顶点 i i i的声望,然后考虑计算资源问题,所以这里就提出了负采样策略,即:

J p o s ( u , v ) = − log ⁡ ( σ ( s ( f ( u ) , f ( v ) ) ) ) − ∑ i = 1 K E v n   P n ( v ) [ log ⁡ ( σ ( − s ( f ( u ) , f ( v n ) ) ) ) ] J_{pos}(u, v) = -\log(\sigma(s(f(u), f(v)))) - \sum_{i=1}^{K} E_{v_n ~ P_n(v)} [\log(\sigma(-s(f(u), f(v_n))))] Jpos(u,v)=log(σ(s(f(u),f(v))))i=1KEvn Pn(v)[log(σ(s(f(u),f(vn))))]

而上述函数又可通过采用异步随机梯度下降算法(ASGD)来优化。每一步中,ASGD算法对小批量边缘进行抽样,然后更新模型参数。但是这也带来一个问题,如果我们根据小权重的边缘选择较大的学习率,那么大权重的边上的梯度就会爆炸式的过大,如果我们根据具有较大权重的边选择学习小的速率,那么小权重上的边的梯度将变得太小。因此边缘采样同样要优化。从起始边缘采样并将采样的边缘作为二进制边缘,其中采样概率与原始边缘的权重成比例。

这里可以对比我之前的node2vec笔记一起看,代码复现的话可以参照图节点嵌入相关算法学习笔记 中,使用wiki数据集,用浅梦大佬的ge包进行了测试。

LINE优缺点

优点:

  • 基于deepwalk,保留节点之间的一阶相似性(first-order proximity)和二阶相似性(second-order proximity)
  • 可以处理上亿级别的大规模网络(论文中后续有所证明)
  • 采用负采样的方式对模型进行优化,以及利用 Alias table加速采样过程。(我之前一直以为node2vec先用来着,原来还早一年)

缺点:

  • 它不能处理动态变化的网络,因为需要重新计算所有顶点的嵌入。
  • 不能很好处理多阶相似度,或者说高阶相似度,不能捕获到。
  • 需要大量的内存和计算资源

另外我参考的知乎贴的评论中,有一个大佬对LINE算法提出了很多质疑,并提出了LINE的一阶和二阶相似性都是等价于矩阵分解的,具体证明参照论文:https://arxiv.org/pdf/1707.05926.pdf

这里Mark一下,之后有时间回头看看。

SDNE

SDNE介绍

虽然上节中LINE解决了deepwalk中的很多问题,但是它依然是一个基于浅层模型网络 embedding 的方法,由于浅层模型的表达能力有限,所以这些方法很难捕获高度非线性的网络结构,因此得到的是次优(非最优)的网络 representation

当然,还有几个亘古不变的问题,论文中又把deepwalk中提到的几个难点复述了一下,即 non-linearstructure-preservingsparsity。但这波算是解决了non-linear,其它还是沿用LINE,做了一些创新。

SDNE(Structural Deep Network Embedding )是和node2vec并列的工作,均发表在2016年的KDD会议中。可以看作是基于LINE的扩展,同时也是第一个将深度学习应用于网络表示学习中的方法。 它使用一个自动编码器结构来同时优化1阶和2阶相似度(LINE是分别优化的),学习得到的向量表示能够保留局部和全局结构,并且对稀疏网络具有鲁棒性。

创新点

SDNE模型采用多层神经网络将输入数据映射到高度非线性的潜在空间来捕获高度非线性的网络结构,模型结构如下图:
在这里插入图片描述
其中,从 x i x_{i} xi y i ( K ) y_{i}^{(K)} yi(K)是编码器,从 y i ( K ) y_{i}^{(K)} yi(K) x ^ i \hat{x}_{i} x^i是解码器, y i ( K ) y_{i}^{(K)} yi(K)是节点 i i i 的embedding向量,SDNE是基于给定图转化的邻接矩阵和深度自编码器来保留二阶相似度。编码器的公式为:

y i ( 1 ) = σ ( W ( 1 ) x i + b ( 1 ) ) y i ( k ) = σ ( W ( k ) y i ( k − 1 ) + b ( k ) ) , k = 2 , … , K \begin{array}{c} y_{i}^{(1)}=\sigma\left(W^{(1)} x_{i}+b^{(1)}\right) \\ \\ y_{i}^{(k)}=\sigma\left(W^{(k)} y_{i}^{(k-1)}+b^{(k)}\right), k=2, \ldots, K \end{array} yi(1)=σ(W(1)xi+b(1))yi(k)=σ(W(k)yi(k1)+b(k)),k=2,,K

其中, σ ( . . . ) \sigma(...) σ(...) 为非线性激活函数, { W ( k ) , b ( k ) } k = 1 , ⋯   , K \left\{\mathbf{W}^{(k)}, {\mathbf{b}}^{(k)}\right\}_{k=1, \cdots, K} {W(k),b(k)}k=1,,K 为编码器参数。

假设假设解码器为 K + 1 K+1 K+1 层,则解码过程为:

y → ^ i ( K ) = σ ( W ^ ( K ) y → i ( K ) + b → ^ ( K ) ) y → ^ i ( K − 1 ) = σ ( W ^ ( K − 1 ) y → ^ i ( K ) + b → ^ ( K − 1 ) ) . . . y → ^ i ( 1 ) = σ ( W ^ ( 1 ) y → ^ i ( 2 ) + b → ^ ( 1 ) ) x → ^ i = σ ( W ^ ( 0 ) y → ^ i ( 1 ) + b → ^ ( 0 ) ) \begin{array}{l} \hat{\overrightarrow{\mathbf{y}}}_{i}^{(K)}=\sigma\left(\hat{\mathbf{W}}^{(K)} \overrightarrow{\mathbf{y}}_{i}^{(K)}+\hat{\overrightarrow{\mathbf{b}}}^{(K)}\right) \\ \hat{\overrightarrow{\mathbf{y}}}_{i}^{(K-1)}=\sigma\left(\hat{\mathbf{W}}^{(K-1)} \hat{\overrightarrow{\mathbf{y}}}_{i}^{(K)}+\hat{\overrightarrow{\mathbf{b}}}^{(K-1)}\right) \\ ... \\ \hat{\overrightarrow{\mathbf{y}}}_{i}^{(1)}=\sigma\left(\hat{\mathbf{W}}^{(1)} \hat{\overrightarrow{\mathbf{y}}}_{i}^{(2)}+\hat{\overrightarrow{\mathbf{b}}}^{(1)}\right) \\ \hat{\overrightarrow{\mathbf{x}}}_{i}=\sigma\left(\hat{\mathbf{W}}^{(0)} \hat{\overrightarrow{\mathbf{y}}}_{i}^{(1)}+\hat{\overrightarrow{\mathbf{b}}}^{(0)}\right) \\ \end{array} y ^i(K)=σ(W^(K)y i(K)+b ^(K))y ^i(K1)=σ(W^(K1)y ^i(K)+b ^(K1))...y ^i(1)=σ(W^(1)y ^i(2)+b ^(1))x ^i=σ(W^(0)y ^i(1)+b ^(0))

其中,上述的参数变为了与编码器相反的解码器参数。

所以最终自编码器的损失函数为:

L 2 n d = ∑ i = 1 n ∥ x ^ i − x i ∥ 2 2 L_{2 n d}=\sum_{i=1}^{n}\left\|\hat{x}_{i}-x_{i}\right\|_{2}^{2} L2nd=i=1nx^ixi22

但由于图的稀疏性,往往非零元素远远少于零元素的数量的,而如果直接输入到神经网络中,结果也会更加离散,倾向于0这也是一个不错的结果,所以作者这里提出了一个带权损失函数,即给非零元素赋予比零元素更大的误差,为:

L 2 n d = ∑ i = 1 n ∥ ( x ^ i − x i ) ⊙ b i ∥ 2 2 = ∥ ( X ^ − X ) ⊙ B ∥ F 2 L_{2 n d}=\sum_{i=1}^{n}\left\|\left(\hat{x}_{i}-x_{i}\right) \odot \mathbf{b}_{\mathbf{i}}\right\|_{2}^{2}=\|(\hat{X}-X) \odot B\|_{F}^{2} L2nd=i=1n(x^ixi)bi22=(X^X)BF2

其中 ⊙ \odot Hadamard(逐元素积), b i b_{i} bi 为:

b i , j = { 1 ,  if  x i , j = 0 β ,  else  b_{i, j}=\left\{\begin{array}{ll} 1, & \text { if } x_{i, j}=0 \\ \beta, & \text { else } \end{array}\right. bi,j={1,β, if xi,j=0 else 

即:

  • 若顶点 v i v_{i} vi v j v_{j} vj 存在链接( S i , j ≠ 0 S_{i,j}\ne 0 Si,j=0),则误差权重为 β \beta β,其中 β > 1 \beta > 1 β>1 为超参数。
  • 若顶点 v i v_{i} vi v j v_{j} vj 不存在链接 ( S i , j = 0 S_{i,j} = 0 Si,j=0),则误差权重为1

这是无监督的部分,通过自编码器保存了网络的全局结构,而有监督的部分则是保留网络的局部结构,因为一阶相似度可以表示网络的局部结构。

用一个拉普拉斯特征映射捕获一阶相似度(上述框架图中中间横向部分),若顶点 v i v_{i} vi v j v_{j} vj 之间存在边,那他们的Embedding的结果 y ( K ) y^{(K)} y(K) 也接近,则直接给出损失函数为:

L 1 s t = ∑ i , j = 1 n s i , j ∥ y i ( K ) − y j ( K ) ∥ 2 2 = ∑ i , j = 1 n s i , j ∥ y i − y j ∥ 2 2 L_{1 s t}=\sum_{i, j=1}^{n} s_{i, j}\left\|\mathbf{y}_{\mathbf{i}}{ }^{(K)}-\mathbf{y}_{\mathbf{j}}{ }^{(K)}\right\|_{2}^{2}=\sum_{i, j=1}^{n} s_{i, j}\left\|\mathbf{y}_{\mathbf{i}}-\mathbf{y}_{\mathbf{j}}\right\|_{2}^{2} L1st=i,j=1nsi,j yi(K)yj(K) 22=i,j=1nsi,jyiyj22

该损失函数参考了Laplacian Eigenmaps思想,所以论文后又写成了:

L 1 s t = ∑ i , j = 1 n ∥ y i − y j ∥ 2 2 = 2 tr ⁡ ( Y T L Y ) L_{1 s t}=\sum_{i, j=1}^{n}\left\|\mathbf{y}_{i}-\mathbf{y}_{j}\right\|_{2}^{2}=2 \operatorname{tr}\left(Y^{T} L Y\right) L1st=i,j=1nyiyj22=2tr(YTLY)

其中 L L L是图对应的拉普拉斯矩阵,S是邻接矩阵,关于这个公式的具体说明我去找了篇论文,即:

Laplacian Eigenmaps from Sparse, Noisy Similarity
Measurements (https://arxiv.org/pdf/1603.03972v2.pdf)

总结就是Laplacian Eigenmaps是一种图嵌入方法,它利用图的拉普拉斯算子的特征值和特征向量来得到数据点的低维表示。

最后,为同时保留一阶邻近度和二阶邻近度,SDNE 提出了一个半监督学习模型,其目标函数为:

L m i x = L 2 n d + α L 1 s t + ν L r e g L_{m i x}=L_{2 n d}+\alpha L_{1 s t}+\nu L_{r e g} Lmix=L2nd+αL1st+νLreg

其中, L r e g L_{reg} Lreg 是正则化项, α \alpha α为控制1阶损失的参数 , v v v为控制正则化项的参数。

复现SDNE算法的demo可以见:

https://github.com/CyrilZhao-sudo/SDNE

因为浅梦大佬的SDNE用的tensorflow版本实在太低,目前基本已经无法再跑了,如果不降级。

这里我引出论文中一张tsne降维图,感觉很不错:

在这里插入图片描述

SDNE算法的优缺点

关于这个,其实我在看论文和找下论文笔记的时候,相对LINE和node2vec,优缺点都是很明显的,因为算line的更进一步。

优点:

  • 它是第一个将深度学习应用于图嵌入的方法,可以利用神经网络的强大表达能力来学习高度非线性的网络结构。
  • 它可以同时优化一阶邻近度和二阶邻近度,捕捉图的局部和全局结构,同时保持节点嵌入的稀疏性和平滑性。
  • 它同LINE一样,可以处理大规模的图数据,因为使用了梯度下降。

缺点:

  • 它需要调整很多超参数,比如隐藏层的数量、大小、激活函数等,这些参数会影响模型的效果和效率。
  • 它不能处理动态变化的图数据,因为它是基于批量训练的方法,如果图结构发生变化,就需要重新训练模型。
  • 它不能处理带有节点属性或者边权重的图数据,因为它只考虑了节点之间是否存在边,而没有考虑边或者节点本身的信息。

struc2vec

struc2vec介绍

在stuc2vec之前的图嵌入算法,如DeepWalk、LINE、SDNE等,都是基于近邻相似假设的,即认为图中相邻或者接近的节点具有相似的特征或者属性。其中DeepWalk,Node2Vec通过随机游走在图中采样顶点序列来构造顶点的近邻集合。LINE显式的构造邻接点对和顶点的距离为1的近邻集合。SDNE使用邻接矩阵描述顶点的近邻结构。

然而,在一些应用场景中,我们更关心节点的结构相似性,即节点在图中所处的拓扑位置和角色是否相似,而不是它们是否直接连接或者共享邻居。

比如说 几种常见的Graph Embedding方法 提到在蚂蚁金服风控模型使用struc2vec相比node2vec有质的提升,这是因为在风控领域,你可信并不能代表你的邻居可信(有些“大 V”节点的邻居众多),但是一个直观的感觉是,如果两个人在图中处于相似的地位(比如两个“大 V”),那么这两个人应该都可信或都不可信,并且一般来说这样两个人(节点)相距较远。

论文中引用的图与例子为:

在这里插入图片描述
其中 v v v u u u 顶点扮演相似的角色(具有相似的局部结构),但是它们在网络上相距甚远。由于它们的邻域不相交,似乎之前的算法就无法很好的捕获它们的结构相似性,文中提到的是structural equivalence,所以,论文《struc2vec: Learning Node Representations from Structural Identity》提出了一个学习结构等效性的无监督学习框架——struc2vec。

struc2vec创新点

本节也不算创新点,因为整个算法都不走之前的路了,直接提出了很多全新的概念。整体来讲,说复杂也不复杂,但说简单很多细节又需要很多前置条件,我这里简单讲下我觉得比较有意思的点,之后有时间把整篇再过一遍。

Dynamic Time Warping(DTW)

首先,为了表示结构相似性,论文直接就开始定义了一些符号:

  • R k ( u ) R_{k}(u) Rk(u)表示了节点 u u u k k k级邻域。

  • s ( S ) s(S) s(S) 则表示节点的集合 S ⊂ V S⊂V SV 的度数序列。

  • g ( D 1 , D 2 ) g(D_{1},D_{2}) g(D1,D2)度量了两个度数序列D1,D2之间的距离

  • f k ( u , v ) f_{k}(u,v) fk(u,v)表示了u,v两节点之间,k级邻域(距离小于等于k的节点和所有它们之间的边)的结构距离。

然后直接给出公式衡量节点 u u u v v v 之间的相似度:

f k ( u , v ) = f k − 1 ( u , v ) + g ( s ( R k ( u ) ) , s ( R k ( v ) ) ) , k ≥ 0  and  ∣ R k ( u ) ∣ , ∣ R k ( v ) ∣ > 0 f_{k}(u, v)=f_{k-1}(u, v)+g\left(s\left(R_{k}(u)\right), s\left(R_{k}(v)\right)\right), k \geq 0 \text { and }\left|R_{k}(u)\right|,\left|R_{k}(v)\right|>0 fk(u,v)=fk1(u,v)+g(s(Rk(u)),s(Rk(v))),k0 and Rk(u),Rk(v)>0

这是一个递归式,可以认为 f k ( u , v ) f_{k}(u,v) fk(u,v) 值越小,则节点 u u u v v v 结构相似度越高。

而这里的 g ( s ( R k ( u ) ) , s ( R k ( v ) ) ) g\left(s\left(R_{k}(u)\right), s\left(R_{k}(v)\right)\right) g(s(Rk(u)),s(Rk(v))) 的计算,其实就是用的DTW算法。

关于DTW算法,从我个人理解角度来看,整体其实就是动态规划,只不过动态规划是一种解决最优化的通用算法,而DTW算法是一种利用动态规划算法来计算两个时序列之间相似度的方法。具体的我们来复习一波动态转移方程,公式为:

d p [ i ] [ j ] = grid ⁡ [ i ] [ j ] + { min ⁡ ( d p [ i − 1 ] [ j ] , d p [ i ] [ j − 1 ] ) ( i > 0 , j > 0 ) d p [ i − 1 ] [ j ] ( i > 0 , j = 0 ) d p [ i ] [ j − 1 ] ( i > 0 , j > 0 ) 0 ( i = 0 , j = 0 ) d p[i][j]=\operatorname{grid}[i][j]+\left\{\begin{array}{c} \min (d p[i-1][j], d p[i][j-1]) \quad(i>0, j>0) \\ d p[i-1][j] \quad(i>0, j=0) \\ d p[i][j-1] \quad(i>0, j>0) \\ 0 \quad(i=0, j=0) \end{array}\right. dp[i][j]=grid[i][j]+ min(dp[i1][j],dp[i][j1])(i>0,j>0)dp[i1][j](i>0,j=0)dp[i][j1](i>0,j>0)0(i=0,j=0)

具体的可以看一道例题,因为我也LeetCode很久没刷了,这里找回一下,在LeetCode中比较经典的剑指 Offer 12. 矩阵中的路径

给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。说明: 一个机器人每次只能向下或者向右移动一步。
在这里插入图片描述
其中,输入:

输入:grid = [[1,3,1],[1,5,1],[4,2,1]]
输出:7
解释:因为路径 13111 的总和最小。

该题就是一道很标准的动态规划示例题,根据LeetCode中的明了分析过程 简单dp 矩阵的最小路径和 题解:

  • 问题: 从左上角到左下角的最小路径和。子问题:从左上角到任意位置的最小路径和。

  • 状态定义: f ( i , j ) f(i,j) f(i,j) 是从左上角 ( 0 , 0 ) (0,0) (0,0) 到当前位置 ( i , j ) (i,j) (i,j) 的最小路径和。

  • 转移方程: 左一位置和上一位置的最短路径和的最小值,再加上当前位置的值,就是当前位置的最短路径和。
    f ( i , j ) = min ⁡ { f ( i − 1 , j ) , f ( i , j − 1 ) } + arr ⁡ [ i ] [ j ] f(i, j)=\min \{f(i-1, j), f(i, j-1)\}+\operatorname{arr}[i][j] f(i,j)=min{f(i1,j),f(i,j1)}+arr[i][j]

  • 初始值:最左一列和第一行的所有位置都必须作为初始值,防止转移方程越界。
    f ( 0 , j ) = f ( 0 , j − 1 ) + arr ⁡ [ 0 ] [ j ] f ( i , 0 ) = f ( i − 1 , 0 ) + arr ⁡ [ i ] [ 0 ] \begin{aligned} f(0, j) & =f(0, j-1)+\operatorname{arr}[0][j] \\ \\ f(i, 0) & =f(i-1,0)+\operatorname{arr}[i][0] \end{aligned} f(0,j)f(i,0)=f(0,j1)+arr[0][j]=f(i1,0)+arr[i][0]

  • 返回值:返回数组右下角的值 f ( m − 1 , n − 1 ) f(m-1,n-1) f(m1,n1)

则python的代码为:

class Solution:
    def minPathSum(self, grid: List[List[int]]) -> int:
        if not grid or not grid[0]:
            return 0
        
        rows, columns = len(grid), len(grid[0])
        dp = [[0] * columns for _ in range(rows)]
        dp[0][0] = grid[0][0]
        for i in range(1, rows):
            dp[i][0] = dp[i - 1][0] + grid[i][0]
        for j in range(1, columns):
            dp[0][j] = dp[0][j - 1] + grid[0][j]
        for i in range(1, rows):
            for j in range(1, columns):
                dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j]
        
        return dp[rows - 1][columns - 1]

而DTW只不过是还多了一种状态,递推公式为:

L min ⁡ ( i , j ) = min ⁡ { L min ⁡ ( i , j − 1 ) , L min ⁡ ( i − 1 , j ) , L min ⁡ ( i − 1 , j − 1 ) } + M ( i , j ) L_{\min }(i, j)=\min \left\{L_{\min }(i, j-1), L_{\min }(i-1, j), L_{\min }(i-1, j-1)\right\}+M(i, j) Lmin(i,j)=min{Lmin(i,j1),Lmin(i1,j),Lmin(i1,j1)}+M(i,j)

具体的以及例子可以看如下两篇:
动态时间规整(DTW)算法简介 (例子和图很形象)
动态时间规整-DTW算法(该算法的提出到原理都很清晰,带python代码)

以上总结一句话,DTW可以用来衡量两个不同长度且含有重复元素的的序列的距离(距离的定义可以自己设置)。

文章基于此提出一种压缩表示方法,对于序列中出现的每一个度,计算该度在序列里出现的次数。压缩后的有序度序列存储的是(度数,出现次数)这样的二元组。具体计算公式为:

dist ⁡ ( a , b ) = ( max ⁡ ( a 0 , b 0 ) min ⁡ ( a 0 , b 0 ) − 1 ) max ⁡ ( a 1 , b 1 ) \operatorname{dist}(\boldsymbol{a}, \boldsymbol{b})=\left(\frac{\max \left(a_{0}, b_{0}\right)}{\min \left(a_{0}, b_{0}\right)}-1\right) \max \left(a_{1}, b_{1}\right) dist(a,b)=(min(a0,b0)max(a0,b0)1)max(a1,b1)

其中 a = ( a 0 , a 1 )  and  b = ( b 0 , b 1 )  是作为元组 in  A ′  and  B ′ \boldsymbol{a}=\left(a_{0}, a_{1}\right) \text { and } \boldsymbol{b}=\left(b_{0}, b_{1}\right) \text { 是作为元组 in } A^{\prime} \text { and } B^{\prime} a=(a0,a1) and b=(b0,b1) 是作为元组 in A and B A ′  and  B ′ A^{\prime} \text { and } B^{\prime} A and B 是压缩之后的元组序列

biased random walk

利用 M M M 生成节点的上下文的过程:带偏的随机游走(biased random walk)。

  • 每次采样时,首先决定是在当前层游走,还是切换到上下层的层游走。
  • 若决定在当前层游走,设当前处于第k层,则从顶点 u u u 到顶点 v v v 的概率为:

p k ( u , v ) = e − f k ( u , v ) Z k ( u ) p_{k}(u, v)=\frac{e^{-f_{k}(u, v)}}{Z_{k}(u)} pk(u,v)=Zk(u)efk(u,v)

其中 p k ( u , v ) = e − f k ( u , v ) Z k ( u ) Z k ( u ) = ∑ v ∈ V , v ≠ u e − f k ( u , v ) p_{k}(u, v)=\frac{e^{-f_{k}(u, v)}}{Z_{k}(u)}Z_{k}(u)=\sum_{v \in V, v \neq u} e^{-f_{k}(u, v)} pk(u,v)=Zk(u)efk(u,v)Zk(u)=vV,v=uefk(u,v) 是第k层中关于顶点u的归一化因子。

通过在图M中进行随机游走,每次采样的顶点更倾向于选择与当前顶点结构相似的顶点。因此,采样生成的上下文顶点很可能是结构相似的顶点,这与顶点在图中的位置无关。

若决定切换不同的层,假设在往上( k − 1 k - 1 k1)层概率上 1 − q 1-q 1q,则换到 k + 1 k+1 k+1 层的概率为:

p k ( u k , u k + 1 ) = w ( u k , u k + 1 ) ( u k , u k + 1 ) + ( u k , u k − 1 ) p_k(u_k, u_{k+1}) = \frac{w(u_k, u_{k+1})}{(u_k, u_{k+1})+(u_k, u_{k-1})} pk(uk,uk+1)=(uk,uk+1)+(uk,uk1)w(uk,uk+1)

而换到 k − 1 k−1 k1 层的概率为:

p k ( u k , u k − 1 ) = 1 − p k ( u k , u k + 1 ) p_k(u_k, u_{k-1}) = 1 - p_k(u_k, u_{k+1}) pk(uk,uk1)=1pk(uk,uk+1)

Constructing the context graph

根据上一节的DTW距离定义,对于每一个 k k k 我们都可以计算出两个顶点之间的一个距离,现在要做的是通过上一节得到的顶点之间的有序度序列距离来构建一个层次化的带权图(用于后续的随机游走)。

我们定义在某一层k中两个顶点的边权为 w k ( u , v ) = e − f k ( u , v ) , k = 0 , … , k ∗ w_{k}(u, v)=e^{-f_{k}(u, v)}, k=0, \ldots, k^{*} wk(u,v)=efk(u,v),k=0,,k

因为 f k ( u , v ) f_k(u,v) fk(u,v) 最小是0,那么边的权重 w k ( u , v ) w_{k}(u,v) wk(u,v) 的取值范围是 ( 0 , 1 ] (0,1] (0,1] ,当等于1时,代表两个节点结构相同。

通过有向边将属于不同层次的同一顶点连接起来,具体来说,对每个顶点,都会和其对应的上层顶点( k − 1 k-1 k1层)还有下层顶点( k + 1 k+1 k+1层)相连。边权定义为:

w ( u k , u k + 1 ) = l o g ( Γ k ( u ) + e ) , k = 0 , … , k ∗ − 1 w(u_k,u_{k+1})=log(\Gamma_k(u)+e), k=0,…,k^∗−1 w(uk,uk+1)=log(Γk(u)+e),k=0,,k1

w ( u k , u k − 1 ) = 1 , k = 1 , … , k ∗ w(u_k,u_{k-1})=1,k=1,…,k^∗ w(uk,uk1)=1,k=1,,k

其中 Γ k ( u ) \Gamma_k(u) Γk(u) 代表了指向节点 u u u 的权重大于 k k k 层图平均权重的边的数量:

Γ k ( u ) = ∑ v ∈ V 1 ( w k ( u , v ) > w k ‾ ) \Gamma_k(u)=\sum_{v \in V} \mathbb{1}(w_k(u,v) > \overline{w_k}) Γk(u)=vV1(wk(u,v)>wk)

struc2vec的优缺点

优点:

  • 它可以有效地区分不同层次的结构相似性,例如角色相似性和社区相似性
  • 它可以利用现有的序列嵌入方法,如word2vec,来学习节点的向量表示

缺点:

  • 它需要计算图中所有节点对之间的结构距离,这可能会导致较高的时间和空间复杂度
  • 它需要设置一些超参数,如随机游走长度、步数、窗口大小等,这可能会影响嵌入结果

关于上述三个点,在我参考中的浅梦大佬已经对这些进行了复现,写得十分形象了,比如说我上面感兴趣的DTW,这里代码为:

def compute_dtw_dist(part_list, degreeList, dist_func):
    dtw_dist = {}
    for v1, nbs in part_list:
        lists_v1 = degreeList[v1]  # lists_v1 :orderd degree list of v1
        for v2 in nbs:
            lists_v2 = degreeList[v2]  # lists_v1 :orderd degree list of v2
            max_layer = min(len(lists_v1), len(lists_v2))  # valid layer
            dtw_dist[v1, v2] = {}
            for layer in range(0, max_layer):
                dist, path = fastdtw(
                    lists_v1[layer], lists_v2[layer], radius=1, dist=dist_func)
                dtw_dist[v1, v2][layer] = dist
    return dtw_dist

def _compute_structural_distance(self, max_num_layers, workers=1, verbose=0,):
	pass

因为DTW在python中是有一个包的,就叫fastdtw,那就能直接 s ( R k ( u ) ) s(R_{k}(u)) s(Rk(u)),然后接着计算顶点对之间的距离。具体见参考链接。

另外,本篇中只是引出了三种比较主流的算法(因为github复现的多,emmm),另外的如下图所示,感兴趣的可以再继续研究,当然先排除graphGAN,在我上一篇图嵌入算法实践中,发现这是个无法复现的算法,如果想究其原因,去看看issue上各种比deepwalk还低的embed分数就知道了。

在这里插入图片描述

参考与推荐

https://arxiv.org/pdf/1503.03578.pdf

[1]. LINE: Large-scale Information Network Embedding

[2]. Structural Deep Network Embedding

[3]. struc2vec: Learning Node Representations from Structural
Identity

[4]. Laplacian Eigenmaps from Sparse, Noisy Similarity
Measurements

[5]. https://www.huaxiaozhuan.com/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0/chapters

[6]. 【Graph Embedding】Struc2Vec:算法原理,实现和应用

[7]. Deep Learning on Graphs: A Survey

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/388555.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2023版会声会影电脑配置要求及功能介绍

可能大家已经看到网络上关于会声会影2023新版的一些消息,今天coco玛奇朵在这里分享2023新版公布信息。会声会影2023中文版功能非常强大的视频编辑软件,非常专业的使用效果,会声会影2023可以针对剪辑电影进行使用,非常强大的色彩校…

借助CatGPT让turtlesim小乌龟画曲线

注意这里是CatGPT,不等同OpenAI的ChatGPT,但是用起来十分方便,效果也还行。详细说明ROS机器人turtlesim绘制曲线需要注意哪些ROS机器人turtlesim绘制曲线需要注意以下几点:绘制曲线前需要设置好turtlesim的初始位置和方向&#xf…

【matplotlib】条形图及垂线显示小技巧 |一些有用参考帖子收集

最近在画图。一方面看论文看思路,一方面用数据跑图出论文雏形。 有些帖子写得很好,不记录的话下次还想看就只能随缘了。 帖子 博客:nxf_rabbit75 matplotlib技巧—9.共享坐标轴、创建多个subplot、调整横坐标、放置文本框、latext文字、平移…

组播详解及示例代码

写在前面 由于公司业务需要用到组播实现,这里就记录下学习过程。在学习组播之前,我们先来看看另外两种数据包传输方式:单播和广播。 单播:简单来说就是数据一对一发送,如果需要给多个主机发送数据时,就需…

Unity入门精要02---纹理

纹理和材质不可分割 本节知识结构 实践:简单贴一张纹理到模型上 首先在属性处添加相关属性 Properties {_Color ("Color Tint", Color) (1, 1, 1, 1)_MainTex ("Main Tex", 2D) "white" {}//加入纹理_Specular ("Specular&q…

虚拟机VirtualBox下载与安装+虚拟机配置

1、虚拟机VirtualBox下载与安装官网地址:Oracle VM VirtualBox进入官网,点击左侧Dwonlaods点击Windows hosts,开始下载3.打开文件.出现报错:Oracle VM VirtualBox 7.0.4 needs the Microsoft Visual C 2019 Redistributable Packa…

转义字符\033(设置终端的字体显示效果)

以下内容源于网络资源的学习与整理,如有侵权请告知删除。 参考博客 命令行特殊显示效果\033和发声音\007_华硕他哥的博客-CSDN博客 \033格式:指定输出格式_51CTO博客_wkt格式 一、\033的说明 在关于ASCII字符的那些事儿中提到,ASCII字符可以使用前面…

2023年天津医科大学临床医学院专升本专业课考试通知

天津医科大学到临床医学院2023年高职升本科专业课考试通知一、考试时间、地点 天津医科大学临床医学院2023年高职升本科考试定于2023年3月25日举行,考试地点为天津市滨海新区大港学苑路167号天津医科大学临床医学院教学楼。 二、准考证打印开放时间 本次考试打印准考…

3.4笔试总结

感觉题目好难没有做过这种类型的填空题真的是给应届实习生做的题吗第一大题 填空题一开始题目放在pdf里,我都没看清题目想干嘛其实题目看起来复杂.如果仔细读题意还是能做出几个空,无奈我太过紧张浪费了好几分钟空档时间public class Main { public static boolean isRegularMa…

内核角度谈谈Linux进程和线程

目录前言内核对进程和线程的表示创建进程的过程创建线程的过程创建进程和线程的异同揭秘 do_fork 系统调用结论前言 昨天面试的时候,面试官问我了个平平淡淡的问题–>“聊聊Linux中进程和线程”; 相比大家不管是在考试还是面试中或多或少都遇到过这个问题&…

python高德地图+58租房网站平台源码

wx供重浩:创享日记 对话框发送:python地图 免费获取完整源码源文件说明文档配置教程等 在PyCharm中运行《高德地图58租房》即可进入如图1所示的高德地图网页。 具体的操作步骤如下: (1)打开地图网页后,在编…

xgboost:防止过拟合的方法收缩和特征列、采样

xgboost除了第2.1节中提到的正则化目标之外,还使用了另外两种技术来进一步防止过拟合1。 目录shrinkage[^1]Column Subsampling[^2]shrinkage2 第一种技术是由弗里德曼提出的收缩。在树提升的每一步之后,收缩率以η因子的比例缩放新添加的权重。与随机优…

Scrapy框架(高效爬虫)

文章目录一、环境配置二、创建项目三、scrapy数据解析四、基于终端指令的持久化存储1、基于终端指令2、基于管道3、数据同时保存至本地及数据库4、基于spider爬取某网站各页面数据5、爬取本页和详情页信息(请求传参)6、图片数据爬取ImagesPipeline五、中…

IP欺骗种类有哪些?

每台计算机都有一个IP地址,发送的任何数据都被分成许多块(“数据包”),每个数据包单独传输,当这些数据包到达链的末端时,就会重新组装并作为一个整体呈现。此外,每个数据包还有其可识别信息&…

4、High-Resolution Image Synthesis with Latent Diffusion Models

简介github地址diffusion model明显的缺点是耗费大量的时间、计算资源,为此,论文将其应用于强大的预训练自编码器的潜在空间 ,这是首次允许在复杂性降低和细节保存之间达到一个近乎最佳的点,极大地提高了视觉保真度。通过在模型架…

操作系统复习题

什么是线程? 线程(Thread):轻量级进程,是操作系统进行调度的最小单位。一个线程是一个任务(一个程序段)的一次执行过程。线程不占有内存空间,它包括在进程的内存空间中。在同一个进程…

自然语言处理历史最全预训练模型(部署)汇集分享

什么是预训练模型?预练模型是其他人为解决类似问题而创建的且已经训练好的模型。代替从头开始建立模型来解决类似的问题,我们可以使用在其他问题上训练过的模型作为起点。预训练的模型在相似的应用程序中可能不是100%准确的。本文整理了自然语…

踩坑:maven打包失败的解决方式总结

Maven打包失败原因总结如下: 失败原因1:无法使用spring-boot-maven-plugin插件 使用spring-boot-maven-plugin插件可以创建一个可执行的JAR应用程序,前提是应用程序的parent为spring-boot-starter-parent。 需要添加parent的包spring-boot…

QML组件

一个QML文件定义了一个独立的、顶级的QML组件。 一个QML组件就是一个模板,被QML运行环境解释来创建一个带有一些预定义行为的对象。 一个独立的QML组件可以运行多次来禅城多个对象,每个对象都可以称为该组件的实例。 例子: 在项目中添加一…

Redis基础入门

文章目录前言一、redis是什么?二、安装步骤1.下载安装包2.安装三、Redis的数据类型redis是一种高级的key-value的存储系统,其中的key是字符串类型,尽可能满足如下几点:字符串(String)列表(List)集合(Set,不允许出现重复…