随机游走DeepWalk

wen IT资讯 20

本文目录导读:

随机游走DeepWalk

  1. 核心思想:用“句子”来理解“网络”
  2. 算法步骤 (三个主要阶段)
  3. 数学与公式 (简要)
  4. 优缺点分析
  5. 代码实现 (Python 伪代码)

这是一个非常经典且重要的图表示学习(Graph Embedding)算法。

我们会从核心思想算法步骤数学原理以及优缺点几个方面详细讲解。

核心思想:用“句子”来理解“网络”

DeepWalk 的核心思想非常巧妙:将图(网络)中的节点类比为自然语言中的单词,将随机游走生成的节点序列类比为句子。

在自然语言处理(NLP)中,Word2Vec 算法可以从大量的文本语料中学习到每个单词的向量表示,并且语义相近的词在向量空间中的距离也近。

DeepWalk 借鉴了这一思路:

  • 节点(Node) $\leftrightarrow$ 单词(Word)
  • 随机游走路径(Random Walk Sequence) $\leftrightarrow$ 句子(Sentence)
  • 图(Graph) $\leftrightarrow$ 语料库(Corpus)

通过这种方式,DeepWalk 将图的结构信息转化为 Word2Vec 模型可以处理的数据形式。

算法步骤 (三个主要阶段)

DeepWalk 的算法流程可以概括为以下三步:

生成随机游走序列

这是最关键的一步,对于图中的每一个节点,我们都会以它为起点,进行多次固定长度的随机游走。

  • 输入: 图 $G = (V, E)$,$V$ 是节点集合,$E$ 是边集合。
  • 过程: 假设我们在节点 $v_i$,随机选择一个邻居 $v_j$,移动到 $v_j$,然后从 $v_j$ 再次随机选择一个邻居(可能是 $v_i$,也可能不是),如此重复 $\omega$ 次($\omega$ 是游走长度)。
  • 输出: 一系列节点序列 ${v_1, v2, ..., v\omega}$。

为什么用随机游走?

  1. 局部与全局信息:短游走捕捉局部邻域结构,多次游走覆盖全局拓扑。
  2. 并行化:可以从不同的起点同时进行多次游走,计算效率高。
  3. 灵活性:适用于无权图和有权图(例如在有权图中,可以依据边的权重决定邻居的选择概率)。

将序列输入 SkipGram 模型

将生成的随机游走序列输送给 Word2Vec 中的 SkipGram 模型。

  • 目标: 给定一个中心节点(中心词),预测其上下文窗口(大小设为 $k$)内的相邻节点(上下文词)。
  • 例如,窗口大小为 $2$,序列为 $[v_3, v_1, \mathbf{v_2}, v_5, v_4]$,中心节点 $v_2$ 的上下文就是 $v_1, v_3, v_5, v_4$。
  • 模型优化: 最大化在给定中心节点 $v_i$ 的情况下,出现其上下文节点 $v_j$ 的概率 $P(v_j | v_i)$。

学习节点向量表示

通过训练 SkipGram 模型,模型的隐藏层权重就会成为每个节点的向量表示。

  • 输出: 一个 $|V| \times d$ 的矩阵 $\Phi$,$d$ 是向量的维度(超参数)。
  • 最终结果: 对于每个节点 $v_i$,我们得到一个 $d$ 维的稠密向量 $\Phi(v_i)$。

数学与公式 (简要)

DeepWalk 的损失函数(目标)可以表示为:

最大化整个语料库(所有随机游走序列)的对数似然函数:

$$ \max{\Phi} \sum{v \in V} \sum_{u \in N(v)} \log P(u | \Phi(v)) $$

  • $\Phi(v)$ 是节点 $v$ 的嵌入向量(我们要学习的参数)。
  • $N(v)$ 是节点 $v$ 的上下文节点集合(即随机游走序列中,在 $v$ 前后各 $k$ 个窗口内的节点)。

如何计算 $P(u | \Phi(v))$?

SkipGram 模型通常使用 Softmax 函数:

$$ P(u | \Phi(v)) = \frac{e^{\Phi(u) \cdot \Phi(v)}}{\sum_{w \in V} e^{\Phi(w) \cdot \Phi(v)}} $$

由于分母需要计算所有节点与中心节点的点积,计算量非常大($O(|V|)$),实际应用中通常使用 Hierarchical Softmax(层级Softmax,利用霍夫曼树)或 Negative Sampling(负采样)来加速训练。

优缺点分析

优点

  1. 无监督学习:不需要任何节点标签,仅依赖图的结构信息。
  2. 可扩展性强:随机游走可以轻松并行化,适用于大规模图(如社交网络、网页链接图)。
  3. 简单有效:算法思路清晰,实现简单(直接调用 networkx + gensim 即可完成)。
  4. 局部与全局:能够同时捕捉图的局部邻域信息和全局社区结构。

缺点

  1. 仅利用结构信息:无法利用节点的属性特征(如用户年龄、商品价格、文本内容等)。
  2. 同质性偏好:倾向于让结构上相近(属于同一社区或紧密相连)的节点具有相似的表示,对于结构等价(相距较远但拥有相似功能,如两个不同城市的“警察局”)的节点表现一般。
  3. 无法处理动态图:如果图结构发生变化(节点或边增删),需要重新运行整个算法。
  4. 无权重敏感性:标准的 DeepWalk 在处理有权图时,仅仅将权重作为随机游走的概率依据,而不是直接学习权重的语义影响。

代码实现 (Python 伪代码)

import networkx as nx
from gensim.models import Word2Vec
import random
class DeepWalk:
    def __init__(self, graph, walk_length, num_walks, embedding_size=128, window_size=10):
        self.graph = graph
        self.walk_length = walk_length
        self.num_walks = num_walks
        self.embedding_size = embedding_size
        self.window_size = window_size
        self.model = None
    def random_walk(self, start_node):
        """生成一条以start_node为起点的随机游走序列"""
        walk = [start_node]
        for _ in range(self.walk_length - 1):
            current_node = walk[-1]
            neighbors = list(self.graph.neighbors(current_node))
            if not neighbors:
                break
            next_node = random.choice(neighbors) # 随机选择邻居
            walk.append(next_node)
        return [str(node) for node in walk] # 转换为字符串以符合Word2Vec输入
    def generate_corpus(self):
        """生成所有随机游走序列(语料库)"""
        walks = []
        nodes = list(self.graph.nodes())
        for _ in range(self.num_walks):
            random.shuffle(nodes) # 打乱节点顺序以减少偏差
            for node in nodes:
                walks.append(self.random_walk(node))
        return walks
    def train(self):
        """使用Word2Vec训练节点嵌入"""
        corpus = self.generate_corpus()
        # 使用Gensim的Word2Vec
        self.model = Word2Vec(
            sentences=corpus, 
            vector_size=self.embedding_size, 
            window=self.window_size, 
            min_count=0, 
            sg=1, # Skip-Gram
            workers=4
        )
        print("DeepWalk训练完成!")
        return self.model
    def get_embedding(self, node):
        """获取节点的向量表示"""
        return self.model.wv[str(node)]
# 示例用法
if __name__ == "__main__":
    # 创建一个简单的图
    G = nx.karate_club_graph() # 空手道俱乐部图
    dw = DeepWalk(G, walk_length=20, num_walks=10)
    model = dw.train()
    # 获取节点0的嵌入向量
    embedding = dw.get_embedding(0)
    print("节点0的嵌入向量维度:", len(embedding))
    print("节点0的嵌入向量(前10维):", embedding[:10])
  • 一句话总结:DeepWalk 通过随机游走将图结构转化为“句子”,再利用 Word2Vec 学习节点的向量表示。
  • 应用场景:社交网络分析、推荐系统(用户-物品图)、节点分类、链接预测、网络可视化。
  • 后续发展:DeepWalk 开创了图嵌入的先河,其后的 Node2Vec 通过引入广度优先(BFS)和深度优先(DFS)的偏好参数,改进了随机游走策略,再后来的 GCN (图卷积网络) 和 GAT (图注意力网络) 则是引入了深度学习神经网络的方法,进一步提升了性能和表达能力。

抱歉,评论功能暂时关闭!