文章目录
1. 学习任务
《node2vec: Scalable Feature Learning for Networks》
1.1 论文结构
1.2 研究背景
图是一种描述复杂数据的模型(任意的节点数量、复杂的关系) vs 图片(CNN)、文本结构(word2vec)
snap数据集 - 链接 是Jure等人不间断收集的网络数据集,极大地 推动社交网络领域的发展。
研究涵盖:节点分类(node classification)、边预测(link prediction)、社群检测(community detection)、网络营销(viral marketing)、网络相似度(network similarity)
2. node2vec 结构框架
Network embedding 学习目标
- 给定图
G = (V, E)
,目标是去学习一个映射 f : u → R d f: u \rightarrow \mathbb{R}^{d} f:u→Rd
论文核心:通过随机游走策略生成 N S ( u ) \mathcal{N}_{S}(u) NS(u)
2.1 优化目标
node2vec 的优化目标 类似Skip-gram
,给定顶点
u
u
u,在低维空间中最大化其邻居
N
S
(
u
)
\mathcal{N}_{S}(u)
NS(u) 的对数似然函数
max
f
∑
u
∈
V
log
Pr
(
N
S
(
u
)
∣
f
(
u
)
)
\max _{f} \sum_{u \in V} \log \operatorname{Pr}\left(\mathcal{N}_{S}(u) \mid f(u)\right)
fmaxu∈V∑logPr(NS(u)∣f(u))
假设邻居节点
N
S
(
u
)
\mathcal{N}_{S}(u)
NS(u) 之间互不影响,
Pr
(
N
S
(
u
)
∣
f
(
u
)
)
=
∑
n
i
∈
N
S
(
u
)
Pr
(
n
i
∣
f
(
u
)
)
⇒
\operatorname{Pr} (N_{S}(u) \mid f(u))=\sum_{n_{i} \in N_{S}(u)} \operatorname{Pr}\left(n_{i} \mid f(u)\right) \quad\Rightarrow \quad
Pr(NS(u)∣f(u))=ni∈NS(u)∑Pr(ni∣f(u))⇒
log
Pr
(
N
S
(
u
)
∣
f
(
u
)
)
=
∑
n
i
∈
N
S
(
u
)
log
Pr
(
f
(
n
i
)
∣
f
(
u
)
)
\log \operatorname{Pr} (N_{S}(u) \mid f(u))=\sum_{n_{i} \in N_{S}(u)} \log \operatorname{Pr}\left(f\left(n_{i}\right) \mid f(u)\right)
logPr(NS(u)∣f(u))=ni∈NS(u)∑logPr(f(ni)∣f(u))
通过softmax
函数来建模条件概率
σ
(
z
)
j
=
e
z
j
∑
k
=
1
K
e
z
k
for
j
=
1
,
…
,
K
\sigma(\mathbf{z})_{j}=\frac{e^{z_{j}}}{\sum_{k=1}^{K} e^{z_{k}}} \quad \text { for } j=1, \ldots, K
σ(z)j=∑k=1Kezkezj for j=1,…,K
Pr
(
f
(
n
i
)
∣
f
(
u
)
)
=
exp
(
f
(
n
i
)
⋅
f
(
u
)
)
∑
v
∈
V
exp
(
f
(
v
)
⋅
f
(
u
)
)
\operatorname{Pr}\left(f\left(n_{i}\right) \mid f(u)\right)=\frac{\exp \left(f\left(n_{i}\right) \cdot f(u)\right)}{\left.\sum_{v \in V} \exp (f(v) \cdot f(u)\right)}
Pr(f(ni)∣f(u))=∑v∈Vexp(f(v)⋅f(u))exp(f(ni)⋅f(u))
最后node2vec
优化函数为:
max
f
∑
u
∈
V
[
−
log
Z
u
+
∑
n
i
∈
N
S
(
u
)
f
(
n
i
)
⋅
f
(
u
)
]
\max _{f} \sum_{u \in V}\left[-\log Z_{u}+\sum_{n_{i} \in N_{S}(u)} f\left(n_{i}\right) \cdot f(u)\right]
fmaxu∈V∑⎣⎡−logZu+ni∈NS(u)∑f(ni)⋅f(u)⎦⎤
优化函数中的常数对结果无影响,可省略。其中 Z u = ∑ v ∈ V exp ( f ( u ) ⋅ f ( v ) ) Z_{u}=\sum_{v \in V} \exp (f(u) \cdot f(v)) Zu=∑v∈Vexp(f(u)⋅f(v))
2.2 一阶相似性与二阶相似性
文章中使用BFS
、DFS
两种策略采样得到的邻居
N
S
(
u
)
\mathcal{N}_{S}(u)
NS(u)
一阶相似性与二阶相似性描述-参考链接
一阶相似性:在Node2Vec
中也叫做 同质性(homophily)。一阶相似性捕捉的是图中实际存在的结构,比如两个节点由一条边相连,则这两个节点应该具有相似的表示。按照Node2Vec
中的说法,高度互连且属于相似网络集群或社区的节点表示应该比较相近。一阶相似性往往可以通过对节点的DFS
遍历得到。
二阶相似性:在Node2Vec
中也叫做 结构对等性(structural equivalence)。在网络中具有相似结构的节点表示应该相近,它并不强调两个节点是否在图中存在连接,即使两个节点离得很远,但由于结构上相似(连接的邻居节点相似),它们的表示也应该相似,所以二阶相似性可以发现不同的社区。二阶相似性可以通过对节点的BFS
遍历得到。
2.3 Random Walk
传统的random walk
不具备探索节点不同类型领域的能力,本文中认为网络同时具备 结构相似性[通过BFS] 和 同质/社群相似性[通过DFS]
传统的random walk
:给定源点
u
u
u,采样一个长度为
l
l
l 的随机游走序列,序列起始顶点为
c
0
=
u
c_0=u
c0=u,
c
i
c_i
ci 的采样策略为:
P
(
c
i
=
x
∣
c
i
−
1
=
v
)
{
π
v
,
x
Z
,
if
(
v
,
x
)
∈
E
0
,
else
P\left(c_{i}=x \mid c_{i-1}=v\right)\left\{\begin{array}{ll} \frac{\pi_{v, x}}{Z}, & \text { if }(v, x) \in E \\ 0, & \text { else } \end{array}\right.
P(ci=x∣ci−1=v){Zπv,x,0, if (v,x)∈E else
其中 π v , x \pi_{v, x} πv,x为非归一化的、从顶点 v v v 转移到顶点 x x x 的概率, Z Z Z 为归一化常数。
2.4 Biased Random Walk - 2nd order
-
d
t
x
d_{tx}
dtx:
t
t
t、
x
x
x之间的最短路径,
p
p
p、
q
q
q 控制了从源点
V
离开其邻居的快慢。
图中T
时刻处于V
点,由T-1
时刻从t
位置转移过来。此时看上一时刻(T-1
)处的t
点到其他四个点(
t
,
X
1
,
X
2
,
X
3
t, X_1,X_2,X_3
t,X1,X2,X3)的距离,分别为 0,1,2,2;对应的概率分别为
1
p
,
1
,
1
q
,
1
q
\frac{1}{p},1,\frac{1}{q},\frac{1}{q}
p1,1,q1,q1。
超参数的理解
p
值大:对应的
α
\alpha
α小,倾向不回溯,降低了2-hop
的冗余度;p
值小:倾向回溯,采样序列集中在起始点的周围。
q > 1
:则
α
=
1
q
<
1
\alpha=\frac{1}{q} < 1
α=q1<1,转移到
X
1
X_1
X1概率大,BFS
占主导;q < 1
:DFS
占主导。
2.5 alias sampling
Darts, Dice, and Coins: Sampling from a Discrete Distribution-The Alias Method - 链接
具体理解可查看 Alias method:时间复杂度O(1)的离散采样方法 - 链接
附录
1. 图结构中 BFS、DFS
定义一个无向图,如下图所示。参考链接 -CSDN-黄蜜桃-Python图的BFS与DFS
# 定义图结构
graph = {
"A": ["B","C"],
"B": ["A", "C", "D"],
"C": ["A", "B", "D","E"],
"D": ["B", "C", "E","F"],
"E": ["C", "D"],
"F": ["D"],
}
1.1 图的广度优先遍历 BFS
# BFS: 使用queue队列, FIFO 先进先出
def BFS(Graph, vertex):
queue = []
queue.append(vertex) # 首节点添加
seen = set() # 集合中存储已访问过的节点
seen.add(vertex)
res = list()
while queue:
temp = queue.pop(0) # 队首元素出队
res.append(temp)
adjnodes = Graph[temp] # 获取邻接点; 不同的存储结构,得到邻接点的方式不一样
for node in adjnodes:
if node not in seen:
queue.append(node)
seen.add(node)
return res
1.2 图的深度优先遍历 DFS
# DFS: 使用 stack 栈
def DFS(Graph, vertex):
stack = []
stack.append(vertex) # 添加首节点
seen = set()
seen.add(vertex)
res = list()
while stack:
temp = stack.pop() # 栈顶元素
res.append(temp)
adjnodes = Graph[temp] # 获取邻接点;
for node in adjnodes:
if node not in seen:
stack.append(node)
seen.add(node)
return res