DeepWalk: Online Learning of Social Representations
Github整理代码链接,欢迎讨论和交流,觉得有用的可以Star一下。
1.主要思想
Deepwalk是一种将随机游走(Random walk)和Word2Vec两种算法相结合的图表示算法。网络的输入是一张图或者一个网络,输出为网络中顶点的低维向量表示(Embedding)。图1(b)为了可视化将向量映射到二维平面上,相同颜色的顶点具有更近的距离。
引入Word2Vec的原因,随机游走的路径集合中的顶点频率和NLP中语料库的词频分布比较相似。
2.总体流程
①输入一张图,随机给定当前访问起始点,从邻居中随机采样顶点作为下一个顶点,重复此过程,直到访问序列长度和序列个数满足预设条件
②获得顶点访问序列后,采用Word2vec中的Skip-Gram模型进行向量学习,将离散的网络节点向量化,最大化节点共现,就能得到每个节点的Embedding,在计算上使用Hierarchical Softmax进行优化,降低计算复杂度
2.1 Random walk
如图3红色线段所示,以V1顶点为起始点,每次从邻居顶点中随机选择一个顶点作为下一步顶点,游走8步到达V9顶点,即可得到一条顶点数为9的随机游走路径。n个顶点不断重复随机游走k条路径构成一个k*n大小的路径集合。
2.2 Skip-Gram
2.2.1 介绍
NLP中Word2Vec中Skip-Gram目的是将一个高维的onehot向量映射到一个低维连续的向量。将该方式引入图嵌入上,将路径集合中的不重复的顶点构成大小为V的字典,方便以onehot方式表达每个顶点,将随机游走得到的一条路径看作一个序列,例如V1->V2->V3-V4->V5->V6->V7->V8->V9序列长度为9。
Skip-Gram主要思想是利用中心词预测其上下文单词,最大化上下文共现,设置窗口 w w w(句子中当前词与预测词之间的最大距离)大小为4,用中心顶点V5预测其前面4个顶点和后面4个顶点(称之为上下文),公式中 x i x_i xi为顶点的向量表达,最大化优化目标P(x1,x2,x3,x4,x6,x7,x8,x9|x5)。
2.2.2 举例
以图3为例,图中总共包含10个不重复顶点,构成大小为10的字典。V1->V2->V3-V4->V5->V6->V7->V8->V9序列输入Skip-Gram模型,输入V5在字典中onehot表达向量x5,预测V1,V2,V3,V4,V6,V7,V8,V9的表达向量x1,x2,x3,x4,x6,x7,x8,x9,如图5所示(图中D为需要映射的维度)
-
输入:V5在字典中onehot表达向量x5=[0,0,0,0,1,0,0,0,0,0],维度1x10
-
映射:x5经过10xD的映射得到1xD的向量(V5的Embedding表达),再经过8个Dx10的映射得到8个1x10维度的向量,8个维度1x10的向量是预测得到的上下文的表达向量
-
输出:8个1x10维度的向量分别经过softmax归一化得到1X10维度的概率值,如第一个向量对应着x1,应该索引0的概率值最大;第二个向量对应着x2,应该索引1的概率值最大,依次类推。如果该向量表示顶点不是我们需要预测的,则会反向传播更新映射矩阵,经过训练模型得到一个最优解,此时输入onehot向量经过10xD的映射得到1xD的向量即该输入顶点的Embedding表达。
2.3 数学公式推导
2.3.1 优化目标
最大化优化目标:
P
(
V
1
,
V
2
,
V
3
,
V
4
,
V
6
,
V
7
,
V
8
,
V
9
∣
V
5
)
=
P
(
V
1
∣
V
5
)
⋅
P
(
V
2
∣
V
5
)
⋅
P
(
V
3
∣
V
5
)
⋅
P
(
V
4
∣
V
5
)
⋅
P
(
V
6
∣
V
5
)
⋅
P
(
V
7
∣
V
5
)
⋅
P
(
V
8
∣
V
5
)
⋅
P
(
V
9
∣
V
5
)
P(V_1,V_2,V_3,V_4,V_6,V_7,V_8,V_9|V_5)=P(V_1|V_5)·P(V_2|V_5)·P(V_3|V_5)·P(V_4|V_5)·P(V_6|V_5)·P(V_7|V_5)·P(V_8|V_5)·P(V_9|V_5)
P(V1,V2,V3,V4,V6,V7,V8,V9∣V5)=P(V1∣V5)⋅P(V2∣V5)⋅P(V3∣V5)⋅P(V4∣V5)⋅P(V6∣V5)⋅P(V7∣V5)⋅P(V8∣V5)⋅P(V9∣V5)
通过对向量内积做softmax,计算两个顶点的条件概率,a为中心顶点,b为上下文顶点,N为字典大小:
P
(
x
b
∣
x
a
)
=
e
x
p
(
x
b
T
x
a
)
∑
i
∈
N
e
x
p
(
x
i
T
x
a
)
P(x_b|x_a)=\frac{exp(x_b^Tx_a)}{\sum_{i \in N}^{}{exp(x_{i}^Tx_a)}}
P(xb∣xa)=∑i∈Nexp(xiTxa)exp(xbTxa)
由中心顶点预测上下文的条件概率,T表示中心顶点的位置,w表示窗口大小:
∏
t
=
1
T
∏
−
w
≤
i
≤
w
;
i
≠
0
P
(
x
t
+
i
∣
x
t
)
\prod_{t=1}^{T}\prod_{-w \leq i \leq w;i\neq0}P({x_{t+i}|{x_t})}
t=1∏T−w≤i≤w;i=0∏P(xt+i∣xt)
最大化上式,得到最大化上下文的输出概率。为了方便计算,用对数函数变换求函数的最小值
−
∑
t
=
1
T
∑
−
w
≤
i
≤
w
;
i
≠
0
l
o
g
P
(
x
t
+
i
∣
x
t
)
-\sum_{t=1}^{T}\sum_{-w\leq i \leq w;i\neq0}logP({x_{t+i}|{x_t})}
−t=1∑T−w≤i≤w;i=0∑logP(xt+i∣xt)
将公式(2)带入公式(4)得:
L
=
−
∑
t
=
1
T
∑
−
w
≤
j
≤
w
;
j
≠
0
(
(
x
t
+
j
)
T
x
t
−
l
o
g
∑
i
∈
N
e
x
p
(
x
i
T
x
t
)
)
L=-\sum_{t=1}^{T}\sum_{-w \leq j \leq w;j\neq0}((x_{t+j})^Tx_t-log\sum_{i \in N}^{}{exp(x_{i}^Tx_t)})
L=−t=1∑T−w≤j≤w;j=0∑((xt+j)Txt−logi∈N∑exp(xiTxt))
得到优化目标函数,采用梯度下降法更新参数,最小化目标函数得到最优解。但是式(1)在计算softmax时,如果N很大,分母计算量会很大,所以采用层序softmax(Hierarchical Softmax)进行优化,将计算复杂度从
O
(
N
)
O(N)
O(N)降低到
O
(
l
o
g
(
N
)
)
O(log(N))
O(log(N))
2.3.2 Hierarchical Softmax优化计算量
在Hierarchical Softmax之前需要通过语料建立霍夫曼树,霍夫曼树的简单构建过程如图6所示,若有A、B、C、D四个顶点,顶点在语料库中出现频率分别为5、7、2、13,每次取频率最小的两个顶点或者汇合后的父顶点进行相加汇合成新的顶点:
-
在自然语言处理中,是统计整个语料库中每个单词的词频进行构建霍夫曼树
-
在图表示中有两种方式构建霍夫曼树:
- 通过统计整个随机游走的路径集合中每个顶点的频率进行构建
- 通过统计每个顶点的度作为顶点的频率进行构建
为了避免要计算所有词的softmax概率,word2vec采用霍夫曼树来代替从隐藏层到输出softmax层的映射。霍夫曼树的根节点对应输入的顶点表达向量,所有内部节点(图7中灰色节点)就类似之前神经网络隐藏层的神经元,而所有叶子节点就类似于之前神经网络softmax输出层的神经元,叶子节点的个数就是字典的大小。在霍夫曼树中,隐藏层到输出层的softmax映射不是一下子完成的,而是沿着霍夫曼树一步步完成的,因此这种softmax取名为"Hierarchical Softmax"。由于使用霍夫曼树是高频的节点靠近根节点,这样高频节点会更快被找到,这符合贪心优化思想。
计算过程:
霍夫曼树从根节点出发,在每个节点处都会进行一个二分类,下一步是左子树还是右子树(向左标记为0、向右标记为1),每个节点都有一个参数
θ
\theta
θ用于传递和更新,直到到达叶子节点。将二分类的过程用sigmod函数进行映射(见公式6),sigmod的含义是期望每个输入值投影后为1的概率。
P
(
y
=
1
∣
x
)
=
1
1
+
e
−
θ
T
x
P(y=1|x)=\frac{1}{1+e^{-\theta^Tx}}
P(y=1∣x)=1+e−θTx1
如图8所示,以从根节点
x
i
x_i
xi到
x
3
x_3
x3为例,首先经过左子树到达隐藏节点
h
1
h_1
h1,接着向下经过右子树到达隐藏节点
h
2
h_2
h2,最后经过左子树到达
x
3
x_3
x3。计算见公式7,对比公式2的分母,公式7不需要计算字典中的每个节点,这样计算量会小很多,将计算复杂度从
O
(
N
)
O(N)
O(N)降低到
O
(
l
o
g
(
N
)
)
O(log(N))
O(log(N))。所以采用Hierarchical Softmax优化计算量,用公式7代替公式2进行模型传播计算。
P
(
x
3
∣
x
i
)
=
(
1
−
1
1
+
e
−
θ
i
T
x
i
)
(
1
1
+
e
−
θ
1
T
h
1
)
(
1
−
1
1
+
e
−
θ
2
T
h
2
)
P(x_3|x_i)=(1-\frac{1}{1+e^{-\theta_i^Tx_i}})(\frac{1}{1+e^{-\theta_1^Th_1}})(1-\frac{1}{1+e^{-\theta_2^Th_2}})
P(x3∣xi)=(1−1+e−θiTxi1)(1+e−θ1Th11)(1−1+e−θ2Th21)
3.代码实现和实验
3.1 代码实现
原文中代码逻辑如图9所示,分为两个部分:Deepwalk主体和SkipGram;实际工程上的代码逻辑与之不同,具体可以参照作者源码[1]
算法1:
-
输入:由点 V V V和边 E E E构成的图 G G G;参数设置:SkipGram窗口大小 w w w、词向量维度 d d d、每个顶点游走路径数 γ \gamma γ、游走路径长度 t t t
-
输出:所有顶点的向量表达矩阵 Φ \Phi Φ,维度为 V × d V\times d V×d
1.初始化获取 Φ \Phi Φ,在7中会更新 Φ \Phi Φ
2.根据游走路径集合中顶点频率或者顶点出度构建霍夫曼树
3.外循环,每个顶点游走路径数 γ \gamma γ
4.打乱所有顶点
5-6.内循环,每个顶点随机游走,每次游走路径长度 t t t
7.游走路径看作一个序列,输入SkipGram模型进行向量学习,更新顶点的向量表达 Φ \Phi Φ
算法2:
-
输入:向量表达矩阵 Φ \Phi Φ、随机游走路径 W v i W_{vi} Wvi、窗口大小 w w w
-
输出:更新向量表达矩阵 Φ \Phi Φ
1.外循环整个游走路径 W v i W_{vi} Wvi,路径中的每个顶点都会作为中心顶点,输入SkipGram2-3.内循环距离中心顶点 w w w的联合概率,联合概率添加负号,转变成最小优化
4.使用梯度下降法更新 Φ \Phi Φ
Deepwalk随机游走主要代码:
# _*_ coding: utf-8 _*_
"""
Time: 2020/9/9 17:50
Author: Cheng Ding(Deeachain)
Version: V 0.1
File: deepwalk.py
Describe: Write during the internship at Hikvison, Github link: https://github.com/Deeachain/GraphEmbeddings
"""
def random_walk(self, path_length, alpha=0, rand=random.Random(), start=None):
""" Returns a truncated random walk.
path_length: Length of the random walk.
alpha: probability of restarts.
start: the start node of the random walk.
"""
G = self
if start:
path = [start]
else:
# Sampling is uniform w.r.t V, and not w.r.t E
path = [rand.choice(list(G.keys()))]
while len(path) < path_length:
cur = path[-1]
if len(G[cur]) > 0:
if rand.random() >= alpha:
path.append(rand.choice(G[cur])) # G[cur]为顶点cur的邻居节点集合
else:
path.append(path[0])
else:
break
return [str(node) for node in path]
3.2 实验
原文中的数据集[2]总共有三个,均是社交网络:
-
BlogCatalog data of 10,312 nodes, 333, 983 links, and 39 categories.
-
Flickr Data of 80,513 nodes, 5, 899, 882 links, and 195 categories.
-
YouTube Data of 1, 138, 499 nodes, 2, 990, 443 links and 47 categories.
以上三个数据格式是.mat,通过处理最终能够得到点和边的信息并保存到本地,但在作者源代码中没有都使用。整理代码采用了另外的三个公开数据集,分别是:Cora数据集由机器学习论文组成,总共有2708篇论文,应用关系有5429个,论文总共七类(基于案例、遗传算法、神经网络、概率方法、强化学习、规则学习、理论);DBLP数据集也是引文网络组成的图,只选用了4类;BlogCatalog数据集是Blog用户之间关系构成的社交网络,相关详细参数见表1
数据集 | cora | dblp | BlogCatalog |
---|---|---|---|
V | 2708 | 17725 | 10312 |
E | 5429 | 105781 | 333983 |
Class | 7 | 4 | 39 |
实验参数:
- Deepwalk:词向量维度 d = 128 d=128 d=128、每个顶点游走路径数 γ = 50 \gamma=50 γ=50、游走路径长度 t = 20 t=20 t=20、 E p o c h = 5 Epoch=5 Epoch=5、SkipGram窗口大小 w = 10 w=10 w=10
- Line:词向量维度
d
=
128
d=128
d=128、二阶相似度生成128维词向量、
E
p
o
c
h
=
150
Epoch=150
Epoch=150、
l
r
=
0.005
lr=0.005
lr=0.005、
n
u
m
_
n
e
g
a
t
i
v
e
=
5
num\_negative=5
num_negative=5。(目前Line模型存在一定问题,不能复现论文效果。)
- Cora数据集有向图实验,一阶相似度:节点分类 f 1 = 0.44 f1=0.44 f1=0.44,可视化能区分一部分节点;二阶相似度节点分类 f 1 = 0.52 f1=0.52 f1=0.52,,可视化能区分一部分节点
- COra数据集无向图实验,一阶相似度:节点分类 f 1 = 0.48 f1=0.48 f1=0.48,可视化能区分一部分节点;二阶相似度节点分类 f 1 = 0.62 f1=0.62 f1=0.62,,可视化能区分一部分节点
- Node2vec:词向量维度 d = 128 d=128 d=128、返回参数 p = 0.25 p=0.25 p=0.25、输入输出参数 q = 0.25 q=0.25 q=0.25( p 、 q ∈ ( 0.25 , 0.5 , 1 , 2 , 4 ) p、q\in ({0.25,0.5,1,2,4}) p、q∈(0.25,0.5,1,2,4)文中实验证明 p p p和 q q q越小越好)、每个顶点游走路径数 γ = 50 \gamma=50 γ=50、游走路径长度 t = 20 t=20 t=20、 E p o c h = 5 Epoch=5 Epoch=5、SkipGram窗口大小 w = 10 w=10 w=10
Deepwalk通过Randomwalk随机游走得到路径集合,接着SkipGram模型学习顶点的Embedding,最后使用Embedding设计顶点分类任务。数据集划分80%的数据用于训练,20%用于评估,分类任务使用SVM分类,得到顶点的分类指标f1-score如表2所示。
cora(无向图) | dblp(无向图) | |
---|---|---|
Deepwalk(f1-micro) | 0.8542 | 0.8327 |
Line(f1-micro) | 0.6218 | 0.6262 |
Node2vec(f1-micro) | 0.8690 | 0.8386 |
节点Embedding表达在空间维度上,相同类别的节点距离会越靠近,最后将学习得到的Embedding进行可视化展示。可视化使用的是TSNE实现,将向量降维到二维平面上。可视化效果如图10所示。
参考和引用
[1] 作者源代码链接
[2] 原文数据集链接(mat格式)
[3] 整理代码参考链接