【AI】Word2Vec和现代LLM的embedding
Word2Vec
Word2Vec 原论文的核心贡献在于提出了两种新的模型架构(CBOW 和 Skip-gram),它们去掉了传统神经网络语言模型(NNLM)中计算量最大的“非线性隐藏层”,从而极大地提高了训练效率,使得在十亿级词量的语料上训练成为可能。
1. 核心训练原理:去除隐藏层
传统的神经网络语言模型(NNLM)结构是:输入层 -> 投影层 -> 隐藏层(非线性) -> 输出层。作者指出,大部分计算复杂度来自于那个非线性隐藏层。为了加速,Word2Vec 的训练模型直接去掉了隐藏层,变成了:输入层 -> 投影层(共享) -> 输出层(Log-linear分类器)
所有的模型都使用**随机梯度下降(Stochastic Gradient Descent, SGD)和反向传播(Backpropagation)**进行训练。
2. 两种具体的训练架构
A. CBOW 模型 (Continuous Bag-of-Words)
它的逻辑是:根据“上下文”来预测“中间词”。
- 输入 (Input): 当前词周围的上下文单词(包括历史词和未来词)。例如,对于句子 “The cat sits on the mat”,如果预测 “sits”,输入就是 “The”, “cat”, “on”, “the” 。
- 投影 (Projection): 所有输入上下文单词的向量被**求和(或平均)**投影到同一个位置。
- 注意: 因为是求和/平均,所以词的顺序丢失了(这就是为什么叫 Bag-of-Words,词袋模型)。
- 输出 (Output): 预测当前的中间词。
- 训练目标: 最大化正确分类当前中间词的概率。
B. Skip-gram 模型 (Continuous Skip-gram)
它的逻辑是:根据“中间词”来预测“周围词”。
- 输入 (Input): 当前的一个词。
- 输出 (Output): 预测该词前后一定范围内的上下文单词。
- 作者发现增加预测范围(Range)能提高向量质量,但也会增加计算量。
- 实验中通常使用 C=10 的距离。
- 采样策略: 离当前词越远的词,通常相关性越低。因此训练时,作者对距离较远的词进行降权采样(给予较小的权重)。
- 具体过程: 如果选定范围 C=5C=5C=5,对于每一个训练词,随机选一个数 R∈[1,C]R \in [1, C]R∈[1,C],然后使用当前词去预测其前后 RRR 个词。这意味着对于一个输入词,网络要进行 R×2R \times 2R×2 次分类任务。
3. 关键的加速技巧:Hierarchical Softmax
在输出层,如果直接计算词汇表中所有词(比如 100 万个词)的概率(Softmax),计算量是巨大的(O(V)O(V)O(V))。为了解决这个问题,论文使用了 Hierarchical Softmax(分层 Softmax)。
- 原理: 将词汇表组织成一棵 Huffman 树(哈夫曼树)。
- 效果:
- 高频词被分配较短的二进制编码,位于树的较浅层。
- 计算概率不再需要遍历整个词汇表,只需要沿着树的路径走到叶子节点。
- [cite_start]复杂度从 VVV 降低到了 log2(V)log_2(V)log2(V)。
- 具体优势: 对于 100 万词的词汇表,这带来了巨大的速度提升。由于去掉了隐藏层,模型的瓶颈主要在输出层的 Softmax 归一化上,因此这个技术至关重要。
4. 训练参数与环境设置
- 优化算法: 使用带有 Adagrad 自适应学习率的 Mini-batch 异步梯度下降 。
- 学习率 (Learning Rate): 初始学习率设为 0.025,并在训练过程中线性递减,直到训练结束时接近 0。
- 训练轮数 (Epochs):
- 对于小数据集或对比实验,通常训练 3 个 Epoch。
- 但在大数据集上,作者发现训练 1 个 Epoch(只过一遍数据)就能得到比 3 个 Epoch 更好或相当的结果,因为数据量足够大。
- 并行化: 基于 Google 的 DistBelief 框架进行分布式训练,使用 50 到 100 个模型副本并行更新参数。
总结
简单来说,Word2Vec 的训练之所以“Efficient”(高效),是因为:
- 架构极简: 砍掉了计算昂贵的非线性隐藏层。
- 数学优化: 使用 Hierarchical Softmax 将输出层的计算复杂度从线性级降为对数级。
- 任务设计: 利用 CBOW(上下文测中心词)或 Skip-gram(中心词测上下文)作为“假想任务”来训练权重,这些权重最终就是我们想要的词向量。
word2vec训练方法
word2vec原论文非常详细地描述了两种模型架构(CBOW 和 Skip-gram)是如何组织数据进行训练的。核心思想都是基于**“滑动窗口”(Sliding Window)**来构建训练样本,但两者的方向相反。
为了方便理解,我们假设有一句话:
“The quick brown fox jumps over the lazy dog”
下面详细拆解这两种模型具体是怎么构造输入(Input)和标签(Label)的。
1. CBOW (Continuous Bag-of-Words)
逻辑: 给我上下文,我来填中间的空。
- 输入组织 (Input):
- 论文中设定了一个上下文窗口大小。例如,选取中间词前后各 4 个词(共 8 个词)作为输入。
- 模型读取这 8 个上下文单词的向量。
- 关键步骤(Projection): 这些输入向量在投影层被**求和(Sum)**或平均。因为是求和,所以词的顺序被丢弃了(这就叫 Bag-of-Words,词袋)。
- 标签组织 (Label):
- 标签就是当前窗口中心的那个词(中间词)。
- 具体案例:
如果窗口中心是 “jumps”:- 输入:
{"The", "quick", "brown", "fox", "over", "the", "lazy", "dog"} - 标签:
"jumps" - 训练: 这是一个多分类问题。输入这 8 个词的向量和 -> 预测输出是 “jumps” 的概率最大化。
- 输入:
2. Skip-gram (Continuous Skip-gram)
逻辑: 给我中间词,我来猜它旁边可能出现什么词。
这是论文重点推荐的架构,虽然训练更慢,但在语义任务上表现更好。
- 输入组织 (Input):
- 当前的中间词作为唯一的输入。
- 标签组织 (Label):
- 标签是该词前后一定范围内的上下文单词。
- 这意味着,一个输入词会产生多个训练样本(一对一的映射)。
- 关键细节:动态窗口机制 (Dynamic Window Size)
论文中提到了一个非常具体的训练细节,常被忽略:- 虽然设定了最大距离 CCC(例如 C=10C=10C=10),但对于每一个训练样本,模型会先随机选一个数字 RRR(1<R<C1 < R < C1<R<C) 。
- 然后使用当前词去预测前后各 RRR 个词。
- 为什么要随机 RRR? 作者认为,离得越远的词,关系越弱。通过这种随机窗口机制,距离较远的词被选中的概率会降低(降权采样),从而让模型更关注紧邻的词。
- 具体案例:
如果当前词是 “fox”,假设随机到的 R=2R=2R=2:- 样本 1: 输入
"fox"-> 标签"brown"(前一个词) - 样本 2: 输入
"fox"-> 标签"quick"(前两个词) - 样本 3: 输入
"fox"-> 标签"jumps"(后一个词) - 样本 4: 输入
"fox"-> 标签"over"(后两个词) - 训练: 这变成了 4 个独立的分类任务(R×2R \times 2R×2 个分类) [cite: 149]。
- 样本 1: 输入
3. 训练的核心:怎么算“标签”的概率?
如果词表有 100 万个词,通常的 Softmax 需要计算 100 万次才能知道哪个概率最大,这太慢了。论文中使用了 Hierarchical Softmax (分层 Softmax) 来加速 。
- 构建哈夫曼树 (Huffman Tree):
- 整个词表被组织成一棵二叉树。
- 频率高的词(如 “the”)靠近根节点(编码短),频率低的词靠近叶子节点。
- 标签的本质:
- 训练时的“标签”不再是一个 One-hot 向量,而是从树根走到该词叶子节点的一条路径。
- 模型不需要计算 100 万个输出,只需要计算这条路径上的每一个分叉口(二分类)往左走还是往右走。
- 计算量从 VVV 变成了 log2(V)log_2(V)log2(V)。对于 100 万词表,只需要计算约 20 次二分类,而不是 100 万次多分类。
总结流程
- 取词: 从语料库中滑动取出一段文字。
- 定架构:
- 如果是 CBOW:把周围词的向量加起来,去预测中间词在哈夫曼树上的路径。
- 如果是 Skip-gram:拿中间词的向量,逐个去预测周围词在哈夫曼树上的路径。
- 反向传播: 如果预测路径错了(比如该往左却预测往右),就通过 SGD 调整输入词的向量(Input Vector)和树节点的参数。
- 最终产物: 我们并不关心预测得准不准,我们要的是训练好的输入层向量,这就是 Word2Vec 词向量。
Skip-gram的小tricky
在传统的函数拟合(Regression)思维中,如果一个输入 xxx 既要等于 y1y_1y1 又要等于 y2y_2y2,模型确实会感到困惑(通常会收敛到两者的均值)。
但在 Skip-gram 模型中,这种情况不仅不会让模型“跑飞”,反而是它能够捕捉丰富语义的关键所在。
原因主要有以下三点:
1. 目标是“概率分布”而非“单一值”
Skip-gram 并不是在做一个简单的函数映射(如 f(x)=yf(x) = yf(x)=y),它做的是概率密度估计。
- 直观理解: 当输入是“苹果”时,模型并不是被迫在“手机”和“水果”之间二选一。它的任务是学习到:
- P(手机∣苹果)P(\text{手机} | \text{苹果})P(手机∣苹果) 的概率很高。
- P(水果∣苹果)P(\text{水果} | \text{苹果})P(水果∣苹果) 的概率也很高。
- P(卡车∣苹果)P(\text{卡车} | \text{苹果})P(卡车∣苹果) 的概率很低。
- 数学机制: 输出层使用的是 Softmax(或者近似的 Hierarchical Softmax),它的输出总和为 1。只要“手机”和“水果”经常出现在“苹果”周围,模型就会调整参数,让这两个词的输出概率都变大,同时压低其他不相关词的概率。
2. 梯度的“微调”与“合力”
训练是基于随机梯度下降 (SGD) 进行的。这意味着模型不会因为一次冲突的更新就崩塌,而是通过无数次微小的调整寻找平衡点。
- 场景模拟:
- 遇到样本
(苹果, 手机):模型把“苹果”的向量往“手机”的方向拉一点点。 - 遇到样本
(苹果, 水果):模型把“苹果”的向量往“水果”的方向再拉一点点。 - 遇到样本
(苹果, 乔布斯):模型把“苹果”的向量往“乔布斯”的方向又拉一点点。
- 遇到样本
- 最终结果: 经过数十亿次这样的训练,“苹果”的向量最终会停留在所有这些相关词的**“重心”**位置。
- 几何意义: 这样训练出来的“苹果”向量,在向量空间中会同时靠近“手机”、“水果”和“乔布斯”。这就是为什么 Skip-gram 能学会单词的多种含义(多义词特性)。
3. 一对多正是 Skip-gram 的优势
论文作者在结果对比中发现,Skip-gram 在语义任务上的表现比 CBOW 更好 。
- CBOW 的做法(平均化): CBOW 把上下文的所有词(手机、水果、乔布斯)加起来取平均,合成一个向量作为输入,去预测“苹果” 。这实际上是一种**平滑(Smoothing)**操作,它模糊了上下文的具体细节。
- Skip-gram 的做法(精细化): 它强迫输入词(苹果)必须能够独立地预测每一个上下文词。这意味着“苹果”的向量必须非常强壮,包含足够的信息量来分别应对不同的上下文。
总结
模型不会“跑飞”,是因为:
- 任务性质: 它是分类任务(提升相关词的概率),不是回归任务,允许由一个输入对应多个高概率的输出。
- 数据规模: 在海量数据(如 10 亿词)的支撑下,噪声会被抵消,只有稳定的共现关系(Co-occurrence)会被保留在向量中。
- 距离权重: 论文还提到,为了防止模型被太远的、不相关的词带偏,他们对距离较远的上下文词进行了降权采样(Sampling less from distant words)。
所以,“一对多”不仅不是 bug,反而是 Skip-gram 能够学出高质量、蕴含丰富语义关系的词向量的核心 Feature。
词表大小的演化
2013 年的 Word2Vec 论文中使用的词表非常大(100 万甚至更多),而现代大语言模型(LLM,如 GPT-4、Llama 3 等)的词表规模通常在 3 万到 12.8 万之间。
造成这种巨大差异的核心原因在于分词方式(Tokenization)的演变。
1. Word2Vec 时代的“词”是“整词”(Whole Word)
在这篇论文中,作者将每一个独立的单词视为一个原子单位(Atomic Unit) 。这意味着:
- 形态变化被视为不同词: 单词的不同形态(如单复数、时态)在词表中是完全独立的条目。例如,“apple”和“apples”是两个词;“go”、“going”、“went”也是三个完全不同的词。为了捕捉这些词之间的关系(如论文中提到的
big - bigger这种类比关系),模型必须为每一个变体都单独学习一个向量。 - 无法处理未登录词(OOV): 这种方法必须尽可能收录更多的词。如果词表太小,很多生僻词就会变成
<UNK>(未知词)。因此,为了覆盖 60 亿词的语料库 ,作者不得不使用极大的词表,论文中明确提到他们将词表限制在最频繁的 100 万个词 ,甚至提到在分布式框架下可以支持“基本上无限大小的词表” 。 - 硬性截断: 即便用了 100 万的词表,依然是基于频率截断的,这意味着极其罕见的词(人名、地名、拼写错误)依然会被丢弃。
2. 现代 LLM 使用的是“子词”(Subword)
现在的模型(如 BERT, GPT, Llama)普遍使用 BPE (Byte-Pair Encoding) 或 WordPiece 等子词分词技术。
- 化整为零: 现代模型不再把“单词”作为最小单位,而是把词拆开。
- 例如:“unhappiness” 可能被拆成
un+happi+ness。 - “apples” 可能被拆成
apple+s。
- 例如:“unhappiness” 可能被拆成
- 词表极其紧凑: 因为大部分单词都可以由常见的“字根”或“词缀”拼凑出来,现代 LLM 只需要 5 万到 10 万左右的 Token(词元)就能覆盖几乎所有语言的表达,甚至包括从未见过的生造词。
- 不再需要“百万级”词表: 依靠组合能力,现代 LLM 用更少的参数实现了更强的泛化能力。
总结
Word2Vec 论文中之所以出现 100 万这样巨大的词表,是因为当时还没有广泛应用子词分词技术,必须“死记硬背”每一个单词的每一个形态。
正如论文中自己承认的局限性:“目前的模型没有任何关于单词形态(morphology)的输入信息”。这正是现代 LLM 通过子词技术解决的问题。
更多推荐

所有评论(0)