NNLM：意外诞生词嵌入的神经网络语言模型

n-gram 之后的重要技术是 NNLM（Neural Network Language Model），由Yoshua Bengio等人在 2003 年提出，原本只是想用神经网络改进语言建模，却意外地发明了词嵌入。

表示问题：从顺序编码到 one-hot

在深入 NNLM 之前，需要先理解一个更基础的问题：如何让计算机理解词汇？

机器学习发展初期，研究者面临一个根本性问题：计算机只能理解数字，但现实世界中大量的数据是分类别的。比如性别有男 / 女，颜色有红 / 绿 / 蓝 / 黑等等。

最初的想法很简单粗暴：给每个类别分配一个数字。比如性别类中男 = 1、女 = 2，颜色类中红 = 1、绿 = 2、蓝 = 3。但这种顺序编码有个严重问题 —— 它隐含了实体之间的大小关系和距离关系。

举个例子，如果红 = 1、绿 = 2、蓝 = 3，在机器学习中进行距离计算时：

红色和绿色之间的距离：|1-2|=1

红色和蓝色之间的距离：|1-3|=2

绿色和蓝色之间的距离：|2-3|=1

模型会认为红色和绿色更相似，红色和蓝色差异较大。但其实红绿蓝三原色之间应该是等距离关系，没有谁更接近谁。

为了解决这种语义歧义问题，one-hot 编码应运而生。它的核心思想是用向量的正交性表示类别的独立性。还是以红绿蓝为例：

红：[1, 0, 0]

绿：[0, 1, 0]

蓝：[0, 0, 1]

每个类别都是一个正交向量，彼此之间距离相等，没有隐含的大小关系。这种思想对应了线性代数中的基向量概念 —— 每个类别都是高维空间中的一个标准基向量，互相正交且模长相等。

one-hot 的困境

one-hot 编码解决了顺序编码的问题，但带来了新的困扰：

维度灾难：对于一个拥有 10000 个词的词汇表，使用 one-hot 编码需要 10000 维的向量空间。现实中的词汇表往往更大，编码空间会变得非常庞大。

稀疏性：当维度过大时，整个向量中有效信息特别少。一个 10000 维的向量里只有 1 个位置是 1，其余全是 0，这种稀疏性不利于计算和存储。

语义鸿沟：one-hot 彻底抛弃了实体之间真正的关联关系。比如 "狗" 和 "猫" 都是动物，语义上有相似性，但在 one-hot 编码中它们的距离和 "狗" 与 "汽车" 的距离是一样的。

这些问题在语言建模中尤为突出。无论是 n-gram 的精确匹配方法，还是神经网络中的 one-hot 编码，都无法捕捉词汇间的语义相似性，导致模型泛化能力差。

NNLM 的解决思路

NNLM 的出现同时解决了两个问题：n-gram 的维度诅咒和 one-hot 编码的局限性。

n-gram 面临的维度诅咒：当测试的词序列在训练数据中从未出现过时，传统方法很难给出合理的概率估计。就像背书一样，只能记住见过的句子模式，遇到新的组合就无能为力。

NNLM 的想法很巧妙：如果一个词序列由语义相似的词组成，即使这个序列从未见过，也应该得到较高的概率。比如说，如果模型见过 "I love cats"，那么对于 "I adore dogs" 也应该给出合理的概率，因为 "love" 和 "adore"、"cats" 和 "dogs" 在语义上是相似的。

要实现这种能力，模型需要学习词汇之间的相似性，而这就需要将词汇表示为某种连续的向量空间，而不是 one-hot 那种离散的正交向量。

NNLM 的工作机制

NNLM 的架构并不复杂，由两层 MLP 组成。它同时学习两个东西：每个词的向量表示，以及基于这些向量的概率预测。

嵌入层：从稀疏到密集的转换

假设要预测句子中的下一个词，NNLM 先把前面几个词（比如前 3 个词）的 one-hot 向量通过一个嵌入矩阵 C 转换成低维的密集向量：ai=C Wi a_i = CW_iai​=CWi​
假设词汇表大小是 V=10000，嵌入维度是 d=300，那么 C 就是一个 300×10000 的矩阵。当我们有一个词的 one-hot 向量Wi W_iWi​（维度是 10000×1，只有第 j 位是 1，其余都是 0）时，矩阵乘法C Wi CW_iCWi​实际上就是取出矩阵 C 的第 j 列，得到一个 300 维的向量。
换句话说，嵌入矩阵 C 的每一列对应词汇表中一个词的向量表示。训练开始时这些向量是随机初始化的，但随着训练的进行，语义相似的词会逐渐在这个 300 维空间中聚集在一起。

拼接层：构建上下文表示

接下来把这些词向量拼接起来，形成完整的上下文表示：
X=concat(a 1,a 2,a 3)X = \text{concat}(a_1, a_2, a_3)X=concat(a1​,a2​,a3​)
如果每个词向量是 300 维，拼接 3 个词后，X XX就变成了 900 维的向量。

为什么是简单拼接而不是相加或者其他操作？
拼接保留了词序信息，让模型能够区分 "A B C" 和 "B A C" 这样的不同组合。

隐藏层：非线性特征提取

拼接好的向量 X 被送入隐藏层进行非线性变换：
h=tanh⁡(W 1 X+b 1)h = \tanh(W_1X + b_1)h=tanh(W1​X+b1​) 这个隐藏层的作用是提取更高级的特征。线性变换W 1 X+b 1 W_1X + b_1W1​X+b1​将 900 维的输入映射到隐藏层维度（比如 500 维），然后tanh tanhtanh激活函数引入非线性。

为什么需要非线性？
如果没有激活函数，整个网络就是一系列线性变换的组合，等价于一个单层的线性模型，表达能力会大打折扣。tanh 函数能够让模型学习到词汇组合的复杂模式。

输出层：概率分布计算

最后，隐藏层的输出被映射到词汇表大小的向量，然后通过 softmax 得到概率分布：
P(w 4∣w 1,w 2,w 3)=softmax(W 2 h+b 2)P(w_4|w_1,w_2,w_3) = \text{softmax}(W_2h + b_2)P(w4​∣w1​,w2​,w3​)=softmax(W2​h+b2​)
这里W 2 W_2W2​是 500×10000 的矩阵，将隐藏层的 500 维输出映射到 10000 维（词汇表大小）。softmax softmaxsoftmax函数确保所有词的概率和为 1：
P(wi)=exp⁡(zi)∑j=1 V exp⁡(zj)P(w_i) = \frac{\exp(z_i)}{\sum_{j=1}^{V} \exp(z_j)}P(wi​)=∑j=1V​exp(zj​)exp(zi​)​
其中zi z_izi​是第 i 个词对应的 logit 值（得分）。

参数更新

训练时使用交叉熵损失函数，目标是最大化正确词的概率。反向传播会同时更新所有参数：W 1,b 1,W 2,b 2 W_1, b_1, W_2, b_2W1​,b1​,W2​,b2​，以及最关键的嵌入矩阵 C。

嵌入矩阵 C 的更新是最重要的部分。为了更好地预测下一个词，梯度会 "鼓励" 语义相似的词在向量空间中距离更近。比如，如果 "cat" 和 "dog" 经常出现在相似的上下文中，它们的向量表示就会逐渐靠近。

维度变化的完整流程
整个过程中的维度变化是这样的：

输入：3 个 10000 维的 one-hot 向量
嵌入后：3 个 300 维的密集向量
拼接后：1 个 900 维的向量
隐藏层：1 个 500 维的向量
输出层：1 个 10000 维的概率分布

这样的架构能够学习到语义相似性，是因为模型被迫在有限的嵌入空间中为每个词找到合适的位置，而预测任务会自然地将出现在相似上下文中的词聚集在一起。

意外的收获

当时 Bengio 他们的主要目标是改进语言建模，但训练完模型后发现，那个嵌入矩阵 C 学到了非常有意思的东西。相似的词确实在向量空间中聚集在一起，而且这些向量还能进行数学运算，比如著名的 king - man + woman ≈ queen。

这个发现一举解决了 one-hot 编码的三个主要问题：

维度问题：从 10000 维降到几百维

稀疏性问题：变成了密集向量

语义鸿沟问题：相似词在空间中距离相近

虽然当时还没有 "词嵌入" 这个专门术语，但这个想法很快就被其他研究者注意到了。2008 年，Collobert 和 Weston 证明了预训练词向量在下游任务中的威力。到了 2013 年，Mikolov 等人发布了 Word2Vec 工具包，专门用来学习词向量，这时候词嵌入技术才真正普及开来。

Word2Vec 简化了 NNLM 的架构，提出了两种模型：CBOW（根据上下文预测目标词）和 Skip-gram（根据目标词预测上下文）。Skip-gram 在小数据集和稀有词上表现更好，CBOW 训练更快，在频繁词上效果更佳。

NNLM 的优势和局限

相比 n-gram，NNLM 最大的优势就是泛化能力。在 Bengio 他们的实验中，NNLM 在两个文本语料库上都显著超越了当时最先进的 trigram 模型。而且词嵌入这个 "副产品" 后来证明价值巨大。

但 NNLM 也有不少问题。

首先是计算复杂度，训练神经网络比简单的 n-gram 计数要慢得多。其次，虽然不再受马尔可夫假设限制，但还是只能看固定长度的历史，无法处理任意长的上下文。另外，每个词只有一个固定的向量表示，处理不了多义词的问题。

还有一个实际的问题是在大词表上计算 softmax 很慢。

这些问题启发了后续的研究。

一些思考

从表示学习的角度看，NNLM 证明了：好的表示是解决问题的关键。从顺序编码到 one-hot 再到词嵌入，每一步都在优化数据的表示方式，而表示的改进往往能带来性能的显著提升。

技术的进步是渐进的，每一代都在前一代的基础上解决问题。顺序编码解决了基本的数值化问题，one-hot 解决了语义歧义问题，词嵌入解决了稀疏性和语义相似性问题。并且，有时结果可能不是那么重要，反而是过程才是最重要的，就像由 NNLM 衍生的Word2Vec一样。