在自然语言处理(NLP)的初期,我们面临一个最根本的问题:如何将人类语言中的词语(一种符号表示)转化为计算机能够处理的数值形式。最直观、最简单的解决方案就是独热编码。
独热编码是一种将分类变量(Categorical Data)映射为二进制向量的方法。其核心在于:为词典中的每一个唯一词分配一个唯一的整数索引,并使用一个稀疏二进制向量来表示它。这个向量的长度等于词典的大小,其中只有对应词索引的那一维度为1,其他所有维度都为0。
让我们从一个最简单的微型词典开始。假设我们的整个词典只包含四个词:["猫", "狗", "手机", "苹果"]。
通过独热编码,我们将每个词转化为一个4维向量,如下表所示:
| 词语 (Token) | 索引 (Index) | 独热编码向量 (One-Hot Vector) |
|---|---|---|
| 猫 | 0 | [1, 0, 0, 0] |
| 狗 | 1 | [0, 1, 0, 0] |
| 手机 | 2 | [0, 0, 1, 0] |
| 苹果 | 3 | [0, 0, 0, 1] |
这个过程就像是为每个词发放了一张独一无二的“身份证”。计算机通过检查“身份证”上唯一为1的位置,就能准确无误地识别出是哪个词。
尽管简单有效,独热编码的两个固有缺陷使其无法胜任更复杂的语义理解任务:
维度灾难 (Curse of Dimensionality)
现实世界的词典规模巨大,通常包含数万甚至数十万个单词。这意味着每个词向量都会是一个数万维的向量,其中仅有一个1,其余全是0。这种极高的维度和极度的稀疏性会导致计算效率极其低下,对存储和计算资源都是巨大的浪费。
语义鸿沟 (Semantic Gap)
这是最核心的问题。任何两个不同的独热编码向量都是相互正交的。在数学上,我们通过计算向量的点积(或余弦相似度)来衡量其相似性。对于任意两个不同的词向量,它们的点积始终为0。
| 比较词语对 | 向量点积 | 人类认知的相似度 | 模型计算的相似度 |
|---|---|---|---|
“猫” 和 “狗” | 0 | 高 (同为宠物) | 0 (完全不相似) |
“猫” 和 “手机” | 0 | 极低 | 0 (完全不相似) |
如上表所示,独热编码完全无法捕获“猫”和“狗”在语义上相近这一至关重要的语义关系。
独热编码成功地将词语转换成了数值形式,为后续处理奠定了基础。但它仅仅解决了词的身份识别问题,就像一个学生花名册,只能告诉我们“谁是谁”,而无法告诉我们“谁和谁关系好”、“谁和谁属于同一个小组”。这种表示方法的局限性促使研究者们去寻找能够揭示词语之间关系的更优表示方案,从而引出了后续基于统计和学习的词嵌入方法。
为了捕获语义,我们必须超越词本身,去分析它与其它词或文档的共现关系。LSA的核心是:首先构建一个描述词与文档关系的统计矩阵(如TF-IDF矩阵),然后使用奇异值分解(SVD)等矩阵分解技术对这个高维稀疏矩阵进行降维,从而在低维的“潜在语义空间”中表示词语,意思相近的词在这个空间中的位置会彼此靠近。
假设我们有一个微型语料库,包含3个文档:
• D1: "猫 吃 鱼" (主题:宠物)
• D2: "狗 吃 肉" (主题:宠物)
• D3: "程序员 写 代码" (主题:科技)
我们的词典包含以上所有词:[“猫”, “吃”, “鱼”, “狗”, “肉”, “程序员”, “写”, “代码”]。
我们首先统计每个词在每个文档中出现的次数(Term Frequency)。
| D1 | D2 | D3 | |
|---|---|---|---|
| 猫 | 1 | 0 | 0 |
| 吃 | 1 | 1 | 0 |
| 鱼 | 1 | 0 | 0 |
| 狗 | 0 | 1 | 0 |
| 肉 | 0 | 1 | 0 |
| 程序员 | 0 | 0 | 1 |
| 写 | 0 | 0 | 1 |
| 代码 | 0 | 0 | 1 |
IDF用于降低常见词的权重。其公式为:IDF(t) = log(文档总数 / 包含词t的文档数) + 1(常见变体之一)。
| 词 | 出现文档数 | IDF计算 | IDF值 |
|---|---|---|---|
| 猫 | 1 | log(3/1)+1 ≈ 1.477 | 1.477 |
| 吃 | 2 | log(3/2)+1 ≈ 1.176 | 1.176 |
| 鱼 | 1 | log(3/1)+1 ≈ 1.477 | 1.477 |
| 狗 | 1 | log(3/1)+1 ≈ 1.477 | 1.477 |
| 肉 | 1 | log(3/1)+1 ≈ 1.477 | 1.477 |
| 程序员 | 1 | log(3/1)+1 ≈ 1.477 | 1.477 |
| 写 | 1 | log(3/1)+1 ≈ 1.477 | 1.477 |
| 代码 | 1 | log(3/1)+1 ≈ 1.477 | 1.477 |
“吃”出现了2次,所以IDF值较低,符合其作为常见词的特性。
将TF矩阵中的每个值乘以其对应的IDF值,得到最终的TF-IDF矩阵 X。
| 词语 | 文档1 (D1) | 文档2 (D2) | 文档3 (D3) |
|---|---|---|---|
| 猫 | 1.477 | 0.0 | 0.0 |
| 吃 | 1.176 | 1.176 | 0.0 |
| 鱼 | 1.477 | 0.0 | 0.0 |
| 狗 | 0.0 | 1.477 | 0.0 |
| 肉 | 0.0 | 1.477 | 0.0 |
| 程序员 | 0.0 | 0.0 | 1.477 |
| 写 | 0.0 | 0.0 | 1.477 |
| 代码 | 0.0 | 0.0 | 1.477 |
这就是我们构建的原始统计矩阵 X。它的行是词,列是文档。此时,“猫”和“狗”的向量仍然是正交的([1.477, 0, 0] 和 [0, 1.477, 0]),没有直接语义关联。
SVD可以将矩阵 X 分解为三个矩阵的乘积:X = U * Σ * V^T。
• 降维操作: 我们只保留奇异值矩阵 Σ 中最大的 k 个奇异值(比如k=2),并相应地截取 U 和 V^T 矩阵。这个过程相当于找到了数据中最重要的两个“潜在主题”。
• 最终结果: 截取后的 U 矩阵(8x2)的每一行,就是对应词的2维新向量。假设降维后,我们得到:
◦ vec(“猫”) = [0.85, 0.1]
◦ vec(“狗”) = [0.82, 0.08]
◦ vec(“程序员”) = [0.05, 0.89]
◦ vec(“代码”) = [0.07, 0.92]
• 语义捕获: 我们可以看到,“猫”和“狗”的新向量在第一维上的值很高且非常接近,而在第二维上值很低。这表明它们共同属于第一个潜在主题(我们可以解释为“宠物主题”)。
• “程序员”和“代码” 在第二维上的值很高且接近,共同属于第二个潜在主题(“科技主题”)。
• 降维成功: 我们将每个词从一个8维的稀疏向量(在3个文档上的TF-IDF)压缩成了一个2维的稠密向量,并且语义信息得到了保留和凸显。
• 优点: 成功将统计信息转化为语义向量,解决了独热编码的“语义鸿沟”和“维度灾难”问题。
• 局限:
◦ 计算复杂: SVD分解在大矩阵上计算成本非常高。
◦ 多义词困境: 一个词在矩阵中只有一个全局表示。例如,如果语料库中还有“苹果公司”的文档,词“苹果”的向量将是“水果”和“公司”意义的混合体,无法区分。
面对LSA等全局统计方法的局限性,研究者们开始探索新的范式。2013年,谷歌团队推出的Word2Vec模型引发了一场革命。其核心思想从一个全新的角度出发:让模型通过完成“预测任务”来学习词向量,而非直接统计共现频率。
Word2Vec的基本假设是分布式语义:一个词的语义由其频繁出现的上下文来决定。它摒弃了构建和分解庞大矩阵的繁重流程,转而训练一个简单的神经网络来完成一个看似简单的任务:根据一个词,预测其上下文中的其他词(或反之)。在成功完成这个预测任务的过程中,模型“顺便”学习到了高质量、富含语义的词向量。
Word2Vec提供了两种具体的预测策略,如同两种不同的语言游戏,并有明确的数学目标。
| 模型 | 输入 (Input) | 输出 (Output) | 类比 | 目标 |
|---|---|---|---|---|
| CBOW | 上下文词 (Context Words) | 中心词 (Target Word) | 完形填空 | 最大化 |
| Skip-gram | 中心词 (Target Word) | 上下文词 (Context Words) | 猜邻居 | 最大化 |
原始的Skip-gram模型计算开销很大,因为它需要为每个训练样本更新整个词典大小规模的权重(通过Softmax)。负采样是一项关键的技术创新,极大地提升了训练效率。
("天气", "今天"))。k个(例如,5个)非上下文词,与中心词组成负样本对(如 ("天气", "皮鞋")、("天气", "哲学"))。通过上述方式训练出的词向量空间,涌现出了精美的数学规律,最著名的例子是词汇类比关系:
vec("国王") - vec("男人") + vec("女人") ≈ vec("女王")
这意味着,“国王”与“男人”的向量差异,在很大程度上等同于“女王”与“女人”的向量差异。模型不仅捕捉到了词语之间的相似性,更捕捉到了复杂的语义和语法关系(如性别、时态、国家-首都等)。
| 类比关系 | 示例算式 | 预期结果 |
|---|---|---|
| 性别 | vec(男人) - vec(女人) ≈ vec(国王) - vec(?) | 女王 |
| 国家-首都 | vec(中国) - vec(北京) ≈ vec(日本) - vec(?) | 东京 |
| 动词时态 | vec(做) - vec(做了) ≈ vec(吃) - vec(?) | 吃了 |
优点:
局限:
Word2Vec的革命性在于,它通过一个巧妙的“预测任务”框架,将词向量的学习转化为一个高效且强大的优化过程。它产出的词向量首次清晰地展现了词语之间丰富的语义关系,为NLP领域带来了突破性进展。然而,其“静态向量”的固有缺陷也清晰地指明了下一个需要攻克的方向:如何让词的表示能够根据其所在的上下文进行动态调整?这直接引领了我们走向下一个时代——上下文嵌入。
Word2Vec的静态表示瓶颈清晰地指向了下一个突破点:一个词的语义高度依赖于其所在的上下文。真正的理解不在于“词是什么”,而在于“词在当下被如何使用”。这一思想催生了以BERT为代表的上下文嵌入技术,它依托Transformer架构,彻底改变了NLP的范式。
上下文嵌入的核心思想是革命性的:不再为每个词分配一个固定的向量,而是让模型根据目标词在句子中的完整上下文,动态地生成其表示。
这一切的技术基石是Google在2017年提出的Transformer模型架构,其核心是自注意力机制(Self-Attention)。
BERT (Bidirectional Encoder Representations from Transformers) 是上下文嵌入最著名的代表。其成功源于两个关键设计:
通过在海量语料上完成这些预训练任务,BERT学到了强大的语言表示能力。开发者可以下载这个“预训练好”的模型,用自己的数据对其进行微调(Fine-tuning),即可高效地应用于各种下游任务(如情感分析、问答系统)。
考虑以下两个句子:
Sentence A: "苹果发布了新款手机。"Sentence B: "她买了一个红苹果。"让我们对比Word2Vec和BERT的不同表现:
| 模型 | “苹果”在 Sentence A 中的向量 | “苹果”在 Sentence B 中的向量 | 是否相同? | 含义 |
|---|---|---|---|---|
| Word2Vec | vec_apple | vec_apple | ✅ 是 | 静态向量,无法区分多义词 |
| BERT | vec_apple_tech | vec_apple_fruit | ❌ 否 | 动态向量,根据上下文生成 |
BERT的处理过程:
vec_apple_tech 会编码丰富的公司、科技、产品等语义信息。vec_apple_fruit 会编码丰富的水果、食物、颜色等语义信息。相似度计算:
similarity(vec_apple_tech, vec_apple_fruit) 的值会较低,因为BERT认为它们在不同语境下含义不同。similarity(vec_apple_tech, vec_华为) 的值可能会较高,因为它们在同一语境(科技公司)下是相似的。similarity(vec_apple_fruit, vec_香蕉) 的值可能会较高,因为它们在同一语境(水果)下是相似的。这完美解决了一词多义问题,使模型的语义理解能力达到了前所未有的高度。
上下文嵌入的崛起具有里程碑式的意义:
从独热编码的“身份证”,到LSA的“社交圈分析”,再到Word2Vec的“预测游戏”,最终到BERT的“情境化理解”,词表示技术的发展是一部追求更精准、更动态语义的进化史。
上下文嵌入并非终点。当前的研究正朝着更高效、更轻量的模型架构(如ELECTRA、DeBERTa)发展,并积极迈向多模态融合的新阶段——尝试将文本的嵌入与图像、音频的嵌入对齐在同一个空间内,为实现真正意义上的通用人工智能(AGI)持续探索。
至此,词语的数字化之旅已从简单的符号映射,走向了对丰富语义的深度刻画。
本文作者:pnightowl
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!