Word2vec核心模型精讲:CBOW与Skip-gram

前言

在自然语言处理领域,如何让机器"理解"词汇的语义一直是个核心挑战。2013年,Google推出的Word2vec工具彻底改变了这一局面,它通过神经网络将词汇映射到低维稠密向量空间中,使得语义相近的词在向量空间中也相互靠近。

Word2vec中包含两个经典的神经网络模型:CBOW(Continuous Bag-of-Words)Skip-gram。本文将用通俗易懂的方式详细讲解这两个模型的原理,并深入探讨Word2vec中关键的优化技术------哈夫曼树的实现过程。


一、词向量的基础概念

1.1 独热编码的困境

在Word2vec出现之前,词向量通常采用独热编码(One-hot representation)表示。假设词汇表有10个词,那么"小明"的向量可能是[0,0,0,0,1,0,0,0,0,0]

这种表示方式存在两个严重问题:

  • 维度灾难:词汇表通常达百万级别,存储效率极低

  • 语义鸿沟:无法体现词与词之间的关系,"苹果"和"香蕉"的向量完全正交

1.2 分布式表示的突破

分布式表示(Distributed representation)通过训练将每个词映射到较短的向量(如300维)。这些向量构成的向量空间具有令人惊奇的语义性质,比如著名的等式:

King⃗−Man⃗+Woman⃗=Queen⃗King​−Man+Woman=Queen​


二、CBOW模型详解

2.1 核心思想

CBOW模型的目标是:给定某个词的上下文,预测这个词本身 。打个形象的比方:"1个老师教K个学生"------老师(中心词)一视同仁地教给K个学生(上下文词)一样的知识。

2.2 网络结构

CBOW采用三层神经网络结构:

  1. 输入层:上下文词的独热编码向量(求和或平均)

  2. 投影层(隐藏层):维度可自定义(如m维)

  3. 输出层:词汇表大小维度的softmax概率分布

2.3 工作示例

假设语料库有10个词:[今天,我,你,他,小明,玩,北京,去,和,好]。对于句子"今天我和小明去北京玩"中的目标词"小明",我们取其前后各三个词作为上下文:[今天,我,和,去,北京,玩]

输入表示 :将这6个词的独热向量求和,得到输入向量X。
期望输出 :"小明"对应的独热向量[0,0,0,0,1,0,0,0,0,0]

前向传播过程

X=x1+x2+x3+x4+x5+x6X=x1​+x2​+x3​+x4​+x5​+x6​

输入层到投影层的计算:

h=WTXh=WTX

投影层到输出层:

u_j = \mathbf{v}'_{w_j}^T \mathbf{h}

最终通过softmax得到概率分布:

p(wj∣context)=exp⁡(uj)∑j′=1Vexp⁡(uj′)p(wj​∣context)=∑j′=1V​exp(uj′​)exp(uj​)​

2.4 模型特点

  • 训练速度快:预测次数约等于语料库词数(复杂度O(V))

  • 对高频词效果好:通过上下文平均调整词向量

  • 生僻词表现一般:因为调整是"平均"分配到每个上下文词上的


三、Skip-gram模型详解

3.1 核心思想

Skip-gram恰好与CBOW相反:给定中心词,预测它的上下文词 。形象的比喻:"1个学生跟K个老师学习"------中心词(学生)接受K个上下文词(老师)的专门训练。

3.2 网络结构

Skip-gram同样采用三层结构,但输入输出相反:

  • 输入层:中心词的独热向量

  • 投影层:中心词的向量表示

  • 输出层:上下文词的概率分布(通常预测多个词)

3.3 工作示例

同样以上述句子为例,Skip-gram将"小明"作为输入,期望输出是[今天,我,和,去,北京,玩]这6个上下文词的概率分布。

3.4 模型特点

  • 训练较慢:预测次数约O(KV),K为窗口大小

  • 对生僻词效果好:每个中心词接受K次"专门训练"

  • 适合小数据集:能在有限数据中更充分地学习词义

3.5 CBOW与Skip-ram对比

对比维度 CBOW Skip-gram
预测方向 上下文 → 中心词 中心词 → 上下文
训练次数 O(V) O(KV)
速度
生僻词表现 一般
比喻 1个老师教K个学生 1个学生跟K个老师

四、Hierarchical Softmax与哈夫曼树

4.1 为什么需要优化?

上述基础模型中,输出层需要计算词汇表大小的softmax。当词汇表有百万量级时,每次训练的计算量令人望而却步。为此,Word2vec引入了Hierarchical Softmax负采样两种优化技术。

Hierarchical Softmax的核心思想是用哈夫曼树替代输出层的神经元,将V分类问题转化为log2(V)次二分类问题。

4.2 哈夫曼树基础

哈夫曼树 (Huffman Tree),又称最优二叉树,是带权路径长度最短的二叉树。其核心特征:权值较大的节点离根较近,从而获得较短的编码。

基本术语

  • 路径长度:根节点到第L层节点的路径长度为L-1

  • 节点的权:赋予节点的具有某种含义的数值(如词频)

  • 带权路径长度(WPL):所有叶子节点的权×路径长度之和

4.3 哈夫曼树构造算法

给定n个权值w_1,w_2,...,w_n,构造规则如下:

  1. 将每个权值看作一棵只有根节点的森林

  2. 选出权值最小的两棵树合并,新根节点权值为两者之和

  3. 从森林中删除这两棵树,加入新树

  4. 重复步骤2-3,直到只剩一棵树

构造示例

假设有6个节点,权值分布为(a:16, b:4, c:8, d:6, e:20, f:3)。

第一步 :找出最小权值b(4)和f(3),合并为新节点(7)

森林权值:16, 8, 6, 20, 7

第二步 :找出最小权值d(6)和(7),合并为(13)

森林权值:16, 8, 20, 13

第三步 :找出最小权值c(8)和(13),合并为(21)

森林权值:16, 20, 21

第四步 :找出最小权值a(16)和e(20),合并为(36)

森林权值:21, 36

第五步:合并最后两棵(21)和(36),得到根节点(57)

最终构造的哈夫曼树如图所示:

text

复制代码
        根(57)
       /     \
     (21)    (36)
    /   \   /   \
  (8)  (13) (16) (20)
c:8   /  \  a:16 e:20
    (6)  (7)
    d:6  / \
        b:4 f:3

4.4 Word2vec中的哈夫曼树

在Word2vec中,哈夫曼树有特殊的约定:

  • 叶子节点:词汇表中的词,权值为词频

  • 内部节点:对应二分类器参数

  • 编码约定:左子树编码为1,右子树编码为0(与常规相反)

  • 权重约定:左子树权重不小于右子树

这样做的好处是:

  1. 高频词路径短:出现频率高的词(如"的")有较短的编码,训练更快

  2. 计算量从O(V)降到O(logV):每次只需计算路径上的内部节点

  3. 无需计算所有词的概率:大大提升了训练效率

4.5 哈夫曼树的Python实现

在Word2vec中,我们需要根据词频构建哈夫曼树,并为每个词生成哈夫曼编码(即从根到叶子节点的路径)。下面我们用Python实现这一过程,并模拟一个简单的词汇表。

节点定义

python

复制代码
class HuffmanNode:
    """哈夫曼树节点"""
    def __init__(self, word=None, freq=0):
        self.word = word          # 叶子节点存储的词
        self.freq = freq           # 词频(节点权值)
        self.left = None           # 左子节点
        self.right = None          # 右子节点
        self.code = ''             # 哈夫曼编码(路径)
构建哈夫曼树

我们使用优先队列(最小堆)来高效地选择最小权值节点。

python

复制代码
import heapq

def build_huffman_tree(word_freqs):
    """
    根据词频字典构建哈夫曼树
    :param word_freqs: dict {word: freq}
    :return: 根节点
    """
    # 创建叶子节点,并放入堆中
    heap = [(freq, HuffmanNode(word, freq)) for word, freq in word_freqs.items()]
    heapq.heapify(heap)  # 构建最小堆

    while len(heap) > 1:
        # 弹出两个最小节点
        freq1, node1 = heapq.heappop(heap)
        freq2, node2 = heapq.heappop(heap)

        # 创建父节点,权值为两者之和
        parent_node = HuffmanNode(freq=freq1 + freq2)
        parent_node.left = node1
        parent_node.right = node2

        # 将父节点推入堆中
        heapq.heappush(heap, (parent_node.freq, parent_node))

    # 返回根节点
    return heap[0][1] if heap else None
生成哈夫曼编码

通过深度优先遍历,为每个叶子节点分配编码。按照Word2vec的约定,我们设左子树编码为'1',右子树编码为'0'。

python

复制代码
def huffman_encoding(root):
    """
    遍历哈夫曼树,生成每个词的哈夫曼编码
    :param root: 哈夫曼树根节点
    :return: dict {word: code}
    """
    code_map = {}

    def dfs(node, code):
        if node is None:
            return
        # 如果是叶子节点(有word属性)
        if node.word is not None:
            code_map[node.word] = code
            return
        # 左子树编码为'1',右子树编码为'0'
        dfs(node.left, code + '1')
        dfs(node.right, code + '0')

    dfs(root, '')
    return code_map
完整示例

我们用前面构造示例中的词频数据来测试。

python

复制代码
# 模拟词频数据
word_freqs = {
    'a': 16,
    'b': 4,
    'c': 8,
    'd': 6,
    'e': 20,
    'f': 3
}

# 构建哈夫曼树
root = build_huffman_tree(word_freqs)

# 生成编码
codes = huffman_encoding(root)

# 输出结果
print("哈夫曼编码结果(左1右0):")
for word, code in codes.items():
    print(f"词 '{word}' (词频{word_freqs[word]}): 编码 {code}")

运行结果:

text

复制代码
哈夫曼编码结果(左1右0):
词 'f' (词频3): 编码 100
词 'b' (词频4): 编码 101
词 'd' (词频6): 编码 110
词 'c' (词频8): 编码 111
词 'a' (词频16): 编码 00
词 'e' (词频20): 编码 01

注意:由于左右子树的编码约定以及合并顺序的微小差异,得到的编码可能和之前手算的有所不同,但都是前缀编码且满足哈夫曼树的性质(权值大的路径短)。这里ae的编码长度均为2,确实比其它词短,符合预期。

应用到Word2vec

在实际的Word2vec训练中,构建好的哈夫曼树会被用于Hierarchical Softmax。每个内部节点都对应一个可训练的参数向量(类似于一个二分类器的权重)。训练时,对于给定的中心词和上下文,我们需要找到目标词在树中的路径,然后依次计算路径上每个内部节点的二分类概率,并将这些概率相乘作为最终的概率。整个过程避免了计算所有词的softmax,大大提升了效率。


结语

CBOW和Skip-gram作为Word2vec的两大核心模型,通过不同的视角学习词的分布式表示。CBOW擅长快速训练、捕捉高频词语义;Skip-gram则更擅长处理生僻词,在小数据集上表现更佳。

而哈夫曼树的引入,不仅解决了softmax计算效率问题,还巧妙地利用词频信息进一步优化了训练过程------高频词路径短、更新快,低频词路径长、得到更充分的训练。这种"因材施教"的设计思想,正是Word2vec高效且效果出色的关键所在。

理解这些基础原理,对于深入掌握NLP技术、在实际场景中正确选择和使用词向量模型,都有着重要的意义。


参考资料

  1. Word2vec之CBOW模型和Skip-gram模型形象解释「建议收藏」

  2. 百度百科:哈夫曼树

  3. cbow和skipgram适用于什么场景?_gram矩阵

  4. word2vec原理(一) CBOW与Skip-Gram模型基础

  5. word2vec Parameter Learning Explained

  6. 《TensorFlow自然语言处理》3.6 总结

  7. 递归方法构建哈夫曼树

相关推荐
liuccn1 小时前
技能管理工具npx skills 跟openskills的关系以及区别
人工智能
新缸中之脑1 小时前
AI Harness 工程的崛起
人工智能
大写-凌祁1 小时前
[2026年03月15日] AI 深度早报
人工智能·深度学习·机器学习·计算机视觉·agi
Lw中1 小时前
RAG如何科学调节切片长度与滑动窗口?
人工智能·大模型应用基础·rag检索
Σίσυφος19001 小时前
对数极坐标相位相关 Log-Polar Phase Correlation
图像处理·人工智能·计算机视觉
月落三千雪2 小时前
Skill知识库知识库搭建教程(零基础通用版)
人工智能
陈天伟教授2 小时前
人工智能应用- 机器做梦:02.回顾卷积神经网络
人工智能·神经网络·cnn
SuAluvfy2 小时前
关于AI应用工程师
人工智能
liuyukuan2 小时前
5G-A与AI融合开启智能体互联网时代
人工智能·5g