查看全课大纲(第 18 / 69 节)
- 1.NLP 的研究领域、应用与学习路径
- 2.自然语言的基本术语
- 3.信息论基础:信息熵与交叉熵
- 4.语言的进化与语义变迁
- 5.主观概率、客观概率与条件概率
- 6.贝叶斯原理与推理
- 7.随机变量:二项式、期望方差与联合概率
- 8.常见概率分布
- 9.辛普森悖论与贝叶斯解题实例
- 10.语言模型:语言概率与词袋模型
- 11.n-gram 语言模型(二元 / 三元 / N-Gram)
- 12.语言模型评价:交叉熵、困惑度与插值
- 13.朴素贝叶斯文本分类:垃圾邮件
- 14.拼写检查
- 15.中文分词:构词法、最大匹配、最优路径与 Jieba
- 16.词表示问题与语义相似度
- 17.TF-IDF 权重处理
- 18.One-Hot 表达与词表示的局限
- 19.Word2Vec 核心思想
- 20.Word2Vec 训练过程
- 21.Skip-gram 模型详解
- 22.词性标注任务与标注方法(规则 + N-Gram)
- 23.EM 算法与混合模型
- 24.高斯混合模型 GMM
- 25.从混合模型到隐马尔可夫模型
- 26.隐马尔可夫模型(HMM)推导与维特比解码
- 27.线性链条件随机场 CRF
- 28.贝叶斯网络与图模型
- 29.隐马尔可夫链与 HMM 推导
- 30.PLSA 主题模型
- 31.LSI 与 SVD 向量表达
- 32.LDA 与狄利克雷分布
- 33.主题模型实验复现(困惑度 / 分类 / 相似度 / 延展)
- 34.上下文无关文法(CFG)与句法分析
- 35.概率上下文无关文法 PCFG
- 36.统计机器翻译:词对齐与翻译模型
- 37.统计机器翻译中的对齐模型与参数估计
- 38.从统计机器翻译到神经机器翻译
- 39.神经元与反向传播速览(指向深度学习课)
- 40.CNN 原理及其在 NLP 中的应用
- 41.循环神经网络的基本原理与 Elman / Jordan 网络
- 42.LSTM:长短期记忆网络的核心思想与分步实现
- 43.Encoder-Decoder 框架
- 44.Seq2Seq 与早期注意力机制
- 45.注意力机制的背景与动机
- 46.注意力模型实现原理与匹配函数
- 47.记忆网络:组成与计算
- 48.注意力机制的应用与历史延展
- 49.Transformer 结构:Encoder-Decoder 栈与 Self-Attention
- 50.Multi-Head Attention、FFNN 与位置编码
- 51.层归一化、损失函数与 Universal Transformer 延展
- 52.预训练范式:从 ELMo 到 BERT
- 53.BERT 与掩码语言模型
- 54.BERT 下游任务微调与 GLUE 口径
- 55.GPT 与自回归语言建模
- 56.GPT-1 到 GPT-4 的演进
- 57.指令微调与 RLHF
- 58.分词器:BPE、WordPiece 与中文词表
- 59.上下文窗口与长文本处理
- 60.能力边界、成本与适用场景
- 61.文本分类实战:从朴素贝叶斯到逻辑回归
- 62.命名实体识别实战
- 63.文本生成与摘要实战
- 64.语义检索与向量库实战
- 65.RAG 知识库问答
- 66.NLP 评估指标:BLEU / ROUGE / BERTScore 与人工评估
- 67.幻觉与事实性问题
- 68.文本与知识结合(知识图谱压缩)
- 69.跨媒体信息检索与未来展望
One-Hot 表达与词表示的局限
小象实战讲义 · 自然语言处理
在自然语言处理中,如何将离散的符号(如单词)转化为计算机能够理解和计算的数学形式,是构建所有模型的第一步。本节我们将从最直观的 One-Hot 表示入手,探讨其原理、优势与核心局限,并引出构建更优词表示(词嵌入)的通用思想。理解本节内容,是后续学习 Word2Vec 等现代词向量方法的重要基础。
💡 核心导读
- One-Hot 表示:将词汇表中的每个词映射为一个唯一的、长度为词汇表大小的二进制向量。
- 核心局限:向量维度高且稀疏,无法表达词与词之间的任何语义关系(正交性)。
- 嵌入矩阵:一种将高维 One-Hot 向量映射到低维稠密向量的参数矩阵,是词嵌入学习的核心。
- 通用嵌入学习框架:通过定义评分函数和损失函数,联合学习嵌入矩阵和词间关系参数,使学到的向量能反映词的语义。
从离散符号到向量表示
自然语言文本本质上是离散符号(如单词、字符)的序列。要让机器学习模型处理文本,我们必须先将这些符号转化为数值向量。最朴素、最直接的方法就是 One-Hot 表示。
假设我们有一个包含 个词的词汇表 。对于词汇表中的第 个词,其 One-Hot 向量是一个 维的向量,其中只有第 个位置为 1,其余位置均为 0。
例如,词汇表 = {“猫”, “狗”, “兔子”},则它们的 One-Hot 表示分别为:
- “猫”:
- “狗”:
- “兔子”:
# 示例:One-Hot 编码
vocabulary = ["猫", "狗", "兔子"]
word_to_index = {word: i for i, word in enumerate(vocabulary)}
def one_hot_encode(word):
vec = [0] * len(vocabulary)
vec[word_to_index[word]] = 1
return vec
print("词汇表:", vocabulary)
print("\"猫\"的 One-Hot 向量:", one_hot_encode("猫"))
print("\"狗\"的 One-Hot 向量:", one_hot_encode("狗"))
print("\"兔子\"的 One-Hot 向量:", one_hot_encode("兔子"))词汇表: ['猫', '狗', '兔子']
"猫"的 One-Hot 向量: [1, 0, 0]
"狗"的 One-Hot 向量: [0, 1, 0]
"兔子"的 One-Hot 向量: [0, 0, 1]One-Hot 表示简单明了,能唯一标识每个词。在传统的信息检索(IR) 和文档分类任务中,文档和查询常被表示为词向量的叠加(如词袋模型)。然而,这种表示方法存在几个根本性的问题:
- 维度灾难:向量维度等于词汇表大小 ,对于大规模语料( 可达数十万甚至百万),向量极其高维。
- 稀疏性:每个向量中仅有一个非零元素,计算和存储效率低下。
- 语义缺失(正交性):任意两个不同的 One-Hot 向量是正交的(内积为0)。这意味着从数学上看,“猫”和“狗”的相似度与“猫”和“飞机”的相似度没有任何区别,完全无法反映词之间的语义关联。
迈向语义表示:分布假说与计数方法
为了获得能表达语义相似度的词表示,我们引入分布假说(Distributional Hypothesis):一个词的含义可以由其上下文(即经常与其共同出现的词)来定义。正如语言学家 J.R. Firth (1957) 所言:“You shall know a word by the company it keeps.”
基于此假说,一种直观的方法是计数法(Count-Based Methods):
- 定义一个上下文词基础词汇表 。
- 设定一个窗口大小 (例如,左右各2个词)。
- 在语料库中,统计每个目标词上下文中出现的基础词汇表 中词的次数。
- 用这些计数构成目标词的向量表示。
示例: 假设上下文基础词汇表 = {“咬”, “可爱”, “毛茸茸”, “大声”, “喵”, “呼噜”, “跑”, “小”}。 给定句子片段:
- “… and the cute kitten purred and then …”
- “… the cute furry cat purred and miaowed …”
- “… that the small kitten miaowed and she …”
- “… the loud furry dog ran and bit …”
我们可以统计出:
- “kitten”(小猫)的上下文词:{“可爱”, “呼噜”, “小”, “喵”}
- “cat”(猫)的上下文词:{“可爱”, “毛茸茸”, “喵”, “呼噜”}
- “dog”(狗)的上下文词:{“大声”, “毛茸茸”, “跑”, “咬”}
将其转化为计数向量(顺序按 ):
- “小猫”:
- “猫”:
- “狗”:
# 示例:基于窗口的上下文词计数(一种简单的计数方法)
context_vocab = ["咬", "可爱", "毛茸茸", "大声", "喵", "呼噜", "跑", "小"]
context_to_idx = {c: i for i, c in enumerate(context_vocab)}
# 模拟的上下文计数向量 (|C|维)
# 行:目标词;列:上下文词;值:共现次数
cooccurrence_counts = {
"小猫": [0, 1, 0, 0, 1, 1, 0, 1], # 上下文: 可爱, 喵, 呼噜, 小
"猫": [0, 1, 1, 0, 1, 1, 0, 0], # 上下文: 可爱, 毛茸茸, 喵, 呼噜
"狗": [1, 0, 1, 1, 0, 0, 1, 0], # 上下文: 咬, 毛茸茸, 大声, 跑
}
print("上下文基础词汇表:", context_vocab)
print("\n目标词的上下文计数向量:")
for word, vec in cooccurrence_counts.items():
print(f"{word}: {vec}")上下文基础词汇表: ['咬', '可爱', '毛茸茸', '大声', '喵', '呼噜', '跑', '小']
目标词的上下文计数向量:
小猫: [0, 1, 0, 0, 1, 1, 0, 1]
猫: [0, 1, 1, 0, 1, 1, 0, 0]
狗: [1, 0, 1, 1, 0, 0, 1, 0]现在,我们可以计算词之间的相似度,例如使用余弦相似度: 计算可得,“小猫”和“猫”的相似度会高于“猫”和“狗”的相似度,这更符合我们的语义直觉。
然而,简单的计数向量仍有问题:高频但无信息量的上下文词(如“的”、“是”)会主导向量表示。因此需要引入TF-IDF、点互信息(PMI) 等方法进行加权归一化,以突出有区分度的上下文。
嵌入矩阵:连接 One-Hot 与稠密表示
学习到的计数向量(维度为 )可以按行排列,形成一个矩阵 ,其中每一行对应一个目标词的向量。这个矩阵 被称为嵌入矩阵(Embedding Matrix)。
这里有一个关键的联系:我们可以通过 One-Hot 向量 与 嵌入矩阵 的乘法,来查找某个词的稠密向量表示。
设词汇表 的大小为 ,我们希望得到维度为 的词向量( 通常远小于 和 )。我们定义一个可学习的嵌入矩阵 。注意,这里 的每一列对应一个词的向量(与计数矩阵按行排列的约定不同,这只是一种设计选择,转置即可等价)。
对于一个词 ,其 One-Hot 向量为 (一个 维向量,只有对应词索引的位置为1)。那么,该词的稠密向量表示 可以通过下式获得:
由于 仅在索引 处为1,这个矩阵乘法的结果就是 的第 列。这相当于用 One-Hot 向量作为“索引”,从嵌入矩阵中“取出”对应的词向量。
import numpy as np
# 模拟一个小的嵌入矩阵 E (d=3, |V|=3)
# 列0对应"猫",列1对应"狗",列2对应"兔子"
np.random.seed(42) # 固定随机种子保证输出确定性
d = 3
vocabulary = ["猫", "狗", "兔子"]
E = np.random.randn(d, len(vocabulary)).round(4) # 随机初始化,保留4位小数
print("嵌入矩阵 E (每一列是一个词的向量):")
print(E)
print("\n通过矩阵乘法获取词向量:")
# "狗"的 One-Hot 向量是 [0,1,0]
one_hot_dog = np.array([0, 1, 0])
v_dog = E.dot(one_hot_dog)
print(f"\"狗\"的 One-Hot 向量: {one_hot_dog}")
print(f"\"狗\"的稠密向量 v_dog = E · one_hot_dog: {v_dog}")
print(f"直接取 E 的第1列: {E[:, 1]}")
print("两者相等吗?", np.allclose(v_dog, E[:, 1]))嵌入矩阵 E (每一列是一个词的向量):
[[ 0.4967 -0.1383 0.6477]
[ 1.523 -0.2342 -0.2341]
[ 1.5792 0.7674 -0.4695]]
通过矩阵乘法获取词向量:
"狗"的 One-Hot 向量: [0 1 0]
"狗"的稠密向量 v_dog = E · one_hot_dog: [-0.1383 -0.2342 0.7674]
直接取 E 的第1列: [-0.1383 -0.2342 0.7674]
两者相等吗? True因此,词嵌入(Word Embedding) 的核心任务,就是学习到一个好的嵌入矩阵 ,使得其列向量(即词向量)能够捕捉丰富的语义和语法信息。
神经嵌入模型的通用框架
如何学习这个嵌入矩阵 呢?Collobert 等人(2011)的工作提出了一个通用的神经嵌入模型框架,其思想影响深远,直接启发了后来的 Word2Vec。该框架不依赖于具体的神经网络结构,其通用流程如下:
- 收集实例:从语料中收集目标词 的每个出现实例 。
- 收集上下文:对于每个实例 ,收集其上下文词 (例如,使用固定大小的窗口)。
- 定义评分函数:定义一个可学习的评分函数 。该函数衡量在给定参数下,目标词 与其上下文 共现的“合理性”或“分数”。参数包括:
- :嵌入矩阵,决定每个词用什么向量表示。
- :描述词与词之间关系(或上下文预测关系)的其他模型参数。
- 定义损失函数:基于评分函数,定义一个损失函数 。例如,我们可以希望真实观察到的 对的得分尽可能高,而随机构造的“负样本”对的得分尽可能低。
- 估计参数:通过优化算法(如随机梯度下降)最小化损失函数,同时更新嵌入矩阵 和关系参数 。
- 产出嵌入:训练完成后,矩阵 就是我们所需的词嵌入矩阵。
以 Collobert & Weston 2011 年的模型为例:
- 他们将句子中每个词通过嵌入矩阵 转换为向量。
- 在词向量序列上应用一个浅层卷积,以捕捉局部上下文特征。
- 卷积的输出再通过一个多层感知机(MLP) 映射为一个标量分数。
- 整个网络(卷积核、MLP权重)构成了参数 ,与 一同训练。
这个框架的要点在于: 负责词的表示, 负责词间关系的建模,两者通过一个可微分的评分函数和损失函数联合优化,最终目标是使学到的词向量(即 )能够很好地服务于我们定义的上下文预测任务。
这为下一节即将深入讲解的 Word2Vec(包括 CBOW 和 Skip-gram 模型)奠定了理论基础。Word2Vec 可以看作是这个通用框架下,评分函数和网络结构极其简化的一个特例,它去掉了复杂的卷积和深层MLP,仅用简单的线性层和 softmax(或负采样)就取得了惊人的效果。
📝 动手练一练
- 概念辨析:One-Hot 表示和基于计数方法的分布式向量表示,各自最主要的优点和缺点是什么?为什么说后者是迈向“语义”表示的关键一步?
👉 点击查看参考答案
One-Hot 表示:
- 优点:简单、唯一,能明确区分词汇表中的每一个词。
- 缺点:
- 维度高且稀疏:维度等于词汇表大小,存储和计算效率低。
- 语义缺失(正交性):任意两个不同词的向量内积为0,无法表达任何语义相似度。从模型角度看,“猫”和“狗”的关系与“猫”和“飞机”没有区别。
基于计数的分布式向量表示:
- 优点:
- 维度可控:向量维度等于上下文特征数(),可远小于词汇表大小。
- 蕴含语义:基于分布假说,通过共享的上下文特征,语义相近的词(如“猫”和“狗”)会拥有相似的向量,从而可以通过余弦相似度等度量计算语义关联。
- 缺点:
- 仍然可能高维:当上下文词汇表 很大时,维度依然不低。
- 共现矩阵稀疏:对于大规模语料,词-上下文共现矩阵非常稀疏。
- 权重问题:需要 TF-IDF、PMI 等方法处理高频但无信息的上下文词。
- 静态表示:一旦从语料中统计完毕,向量就固定了,无法随着新任务动态调整。
关键一步:基于计数的方法首次将词的表示与其上下文分布联系起来,这直接体现了“一个词的含义由其上下文决定”的分布假说,从而让向量表示包含了语义信息,是词表示从“标识符”走向“含义载体”的根本转变。
- 手算理解:假设嵌入矩阵 如下,词汇表 = [“A”, “B”, “C”, “D”]。 请计算词“C”(其 One-Hot 向量为 )通过 得到的稠密向量 。并验证它是否等于 的第3列(索引从0开始)。
👉 点击查看参考答案
词“C”的 One-Hot 向量为 。
计算 :
的第3列(索引为2,对应第三个词“C”)是 。
两者相等,均为 。这验证了“通过 One-Hot 向量与嵌入矩阵相乘来获取词向量”的操作,本质上是从矩阵中选取对应列。
本章小结
本节我们深入探讨了词表示的起点与核心挑战。One-Hot 编码作为最基本的表示方法,因其高维稀疏和语义缺失的固有局限,无法满足现代 NLP 的需求。为了获得蕴含语义的稠密向量,我们引入了基于分布假说的计数方法,并从中抽象出嵌入矩阵的概念——一个将高维 One-Hot 向量映射到低维语义空间的可学习参数矩阵。最后,我们介绍了神经嵌入模型的通用框架,该框架通过联合优化嵌入矩阵(定义词表示)和关系参数(定义上下文预测),为学习高质量词向量提供了蓝图。这为我们接下来学习里程碑式的 Word2Vec 模型做好了充分的理论准备。
📋 行动清单
- 理解 One-Hot 表示的原理,并能手动为小词汇表构造 One-Hot 向量。
- 明确说出 One-Hot 表示的至少两个核心局限(高维稀疏、语义正交)。
- 掌握“嵌入矩阵”的概念,理解其如何通过矩阵乘法连接 One-Hot 向量与稠密词向量。
- 了解神经嵌入模型通用框架(收集实例、评分、优化)的核心思想,知道参数 和 分别负责什么。
—— 小象教研组