查看全课大纲(第 3 / 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.跨媒体信息检索与未来展望
信息论基础:信息熵与交叉熵
小象实战讲义 · 自然语言处理
信息论是自然语言处理乃至整个机器学习领域的数学基石之一。它为我们提供了一套严谨的数学工具,用以量化“信息”本身,并衡量概率分布之间的差异。本节我们将深入探讨信息熵与交叉熵这两个核心概念,理解它们如何从物理学的“熵”概念演化而来,并最终成为机器学习中至关重要的损失函数。掌握这些知识,是后续学习语言模型、词表示、乃至深度学习模型的基础。
💡 核心导读
- 信息熵:量化一个随机事件或一个概率分布所包含的平均信息量(不确定性)。概率越均匀,熵越大;概率越集中,熵越小。
- 交叉熵:衡量两个概率分布之间的差异。在机器学习中,常被用作损失函数,驱动模型学习到的分布逼近真实分布。
- KL散度:交叉熵与信息熵之差,专门用于度量两个分布间的“距离”,但它不对称。
- 应用连接:交叉熵损失是分类任务(如情感分析、语言模型)中最常用的目标函数,其背后原理正是最小化模型预测分布与真实标签分布之间的差异。
从物理熵到信息熵
熵的物理起源
“熵”(Entropy)最初是热力学和统计物理中的概念,用于描述系统的混乱或无序程度。一个高度有序、结构化的系统(如整齐排列的晶体)熵值较低;而一个混乱、无序的系统(如气体分子均匀扩散)熵值较高。著名的物理学家薛定谔在《生命是什么》一书中,将生命体描述为一个高度有序(低熵)的状态,而死亡则是一个熵增的过程。
香农的信息论
现代信息论的奠基者克劳德·香农(Claude Shannon)创造性地将“熵”的概念引入通信领域,用以量化“信息”。他提出,信息是用来消除不确定性的东西。一个事件发生的概率越小,它发生时带来的“信息量”就越大;反之,一个必然发生的事件(概率为1)带来的信息量为0。
基于这一直观理解,香农定义了单个事件 的信息量(自信息)为: 其中 是事件 发生的概率。以2为底的对数使得信息量的单位是“比特”(bit)。
信息熵的定义
信息量衡量的是单个事件的信息。对于一个随机变量 ,它有多个可能的取值 ,每个取值对应一个概率 。我们更关心这个随机变量整体的平均信息量,即信息熵,定义为所有可能事件信息量的期望值:
对于连续随机变量,对应概念是微分熵(differential entropy,常记 ):
需要注意:微分熵与离散熵不是一回事——它可以取负值,也不继承离散熵的非负性等全部性质;下面“越均匀熵越大、越集中熵越小”的解释,针对的是有限离散分布及固定取值集合。
让我们通过代码直观感受一下:
# 示例1:计算不同概率分布的信息熵
import math
# 定义一个计算熵的函数
def entropy(prob_list):
"""计算离散概率分布的熵(以2为底)"""
h = 0.0
for p in prob_list:
if p > 0: # 避免log(0)的错误
h -= p * math.log2(p)
return h
# 分布1:有一定偏向性
prob1 = [0.7, 0.1, 0.1, 0.1]
h1 = entropy(prob1)
print(f"分布 {prob1} 的熵为: {h1:.4f} bits")
# 分布2:极端集中(几乎确定是A)
prob2 = [0.97, 0.01, 0.01, 0.01]
h2 = entropy(prob2)
print(f"分布 {prob2} 的熵为: {h2:.4f} bits")
# 分布3:完全均匀(不确定性最大)
prob3 = [0.25, 0.25, 0.25, 0.25]
h3 = entropy(prob3)
print(f"分布 {prob3} 的熵为: {h3:.4f} bits")分布 [0.7, 0.1, 0.1, 0.1] 的熵为: 1.3568 bits
分布 [0.97, 0.01, 0.01, 0.01] 的熵为: 0.2419 bits
分布 [0.25, 0.25, 0.25, 0.25] 的熵为: 2.0000 bits从结果可以看出,分布越集中(如 prob2),熵越小;分布越均匀(如 prob3),熵越大,达到了最大值2比特(因为这里有4种等可能状态,需要2比特来编码)。
交叉熵与KL散度
交叉熵的定义
信息熵衡量的是一个分布自身的不确定性。而交叉熵(Cross-Entropy)则用于衡量两个概率分布之间的差异。给定真实分布 和模型预测分布 ,交叉熵定义为:
注意,这里对数的内部是预测分布 的概率,但求期望时用的是真实分布 的概率。交叉熵可以理解为:使用基于 的编码方案,来对来自 分布的数据进行编码,所需的平均比特数。
KL散度:分布间的“距离”
为了更纯粹地衡量两个分布 和 的差异,Kullback 和 Leibler 提出了以两人姓氏命名的 Kullback-Leibler散度(KL Divergence),也称为相对熵:
KL散度具有以下重要性质:
- 非负性:,当且仅当 时等号成立。这可以通过詹森不等式证明。
- 不对称性:一般不保证 ,两个方向通常并不相等( 时两边同为 0)。因此它不是一个真正的“距离”度量,但能有效衡量用 来近似 时造成的信息损失。
三者的关系
交叉熵、信息熵和KL散度之间存在一个优雅的关系:
推导:
这个关系非常关键:真实分布 的信息熵 是固定值。因此,最小化交叉熵 ,等价于最小化KL散度 ,也就是让预测分布 尽可能地逼近真实分布 。
# —— 重新构建上文用到的微型数据(本节各代码块相互独立,可单独运行)
import math
def entropy(prob_list):
"""计算离散概率分布的熵(以2为底)"""
h = 0.0
for p in prob_list:
if p > 0: # 避免log(0)的错误
h -= p * math.log2(p)
return h
prob1 = [0.7, 0.1, 0.1, 0.1]
h1 = entropy(prob1)
# 示例2:计算交叉熵和KL散度,验证 H(P,Q) = H(P) + D_KL(P||Q)
def cross_entropy(p_list, q_list):
"""计算分布P和Q之间的交叉熵;P>0 而 Q=0 时为 +∞"""
ce = 0.0
for p, q in zip(p_list, q_list):
if p > 0:
if q == 0:
return math.inf
ce -= p * math.log2(q)
return ce
def kl_divergence(p_list, q_list):
"""计算分布P和Q之间的KL散度 D_KL(P||Q);P>0 而 Q=0 时为 +∞"""
kl = 0.0
for p, q in zip(p_list, q_list):
if p > 0:
if q == 0:
return math.inf
kl += p * math.log2(p / q)
return kl
# 定义真实分布P和两个不同的预测分布Q1, Q2
P = [0.7, 0.3]
Q1 = [0.6, 0.4] # 接近P
Q2 = [0.9, 0.1] # 远离P
h_p = entropy(P)
ce1 = cross_entropy(P, Q1)
kl1 = kl_divergence(P, Q1)
ce2 = cross_entropy(P, Q2)
kl2 = kl_divergence(P, Q2)
print(f"真实分布 P 的熵 H(P): {h_p:.4f} bits")
print(f"\n预测分布 Q1: {Q1}")
print(f"交叉熵 H(P, Q1): {ce1:.4f} bits")
print(f"KL散度 D_KL(P||Q1): {kl1:.4f} bits")
print(f"验证 H(P) + D_KL(P||Q1) = {h_p + kl1:.4f} bits (应与 H(P,Q1) 相等)")
print(f"\n预测分布 Q2: {Q2}")
print(f"交叉熵 H(P, Q2): {ce2:.4f} bits")
print(f"KL散度 D_KL(P||Q2): {kl2:.4f} bits")
print(f"验证 H(P) + D_KL(P||Q2) = {h_p + kl2:.4f} bits (应与 H(P,Q2) 相等)")真实分布 P 的熵 H(P): 0.8813 bits
预测分布 Q1: [0.6, 0.4]
交叉熵 H(P, Q1): 0.9125 bits
KL散度 D_KL(P||Q1): 0.0312 bits
验证 H(P) + D_KL(P||Q1) = 0.9125 bits (应与 H(P,Q1) 相等)
预测分布 Q2: [0.9, 0.1]
交叉熵 H(P, Q2): 1.1030 bits
KL散度 D_KL(P||Q2): 0.2217 bits
验证 H(P) + D_KL(P||Q2) = 1.1030 bits (应与 H(P,Q2) 相等)可以看到,当预测分布 更接近真实分布 时,交叉熵和KL散度都更小。关系式 也得到了验证。
交叉熵作为机器学习损失函数
从理论到实践
在分类任务中,我们通常有:
- 真实分布 :通常是 One-Hot 编码 的标签。例如,对于一个三分类问题,类别2的真实标签是 。
- 预测分布 :模型(例如一个Softmax层)输出的概率分布,如 。
我们的目标是让 逼近 。由于 是常数(One-Hot编码的熵为0,因为只有一个位置是1,其余为0,计算可得 ),因此最小化交叉熵损失 就直接等价于最小化 ,即让预测分布对准真实分布。
对于单个样本,其交叉熵损失为: 其中 是类别数, 是真实标签在类别 上的值(0或1), 是模型预测为类别 的概率。
一个简化的情感分析示例
假设我们有一个二分类情感分析任务(正面/负面)。对于一个句子,经过模型(如逻辑回归)和Sigmoid函数后,我们得到一个标量预测概率 ,表示其为正面的概率。真实标签 为1(正面)或0(负面)。
此时,交叉熵损失函数为:
这被称为二元交叉熵损失。工程实现常采用自然对数,此时损失单位为 nat;换底只相差一个正常数因子,不改变损失最小时的最优参数。
# —— 重新构建上文用到的微型数据(本节各代码块相互独立,可单独运行)
import math
def entropy(prob_list):
"""计算离散概率分布的熵(以2为底)"""
h = 0.0
for p in prob_list:
if p > 0: # 避免log(0)的错误
h -= p * math.log2(p)
return h
prob1 = [0.7, 0.1, 0.1, 0.1]
h1 = entropy(prob1)
def cross_entropy(p_list, q_list):
"""计算分布P和Q之间的交叉熵;P>0 而 Q=0 时为 +∞"""
ce = 0.0
for p, q in zip(p_list, q_list):
if p > 0:
if q == 0:
return math.inf
ce -= p * math.log2(q)
return ce
def kl_divergence(p_list, q_list):
"""计算分布P和Q之间的KL散度 D_KL(P||Q);P>0 而 Q=0 时为 +∞"""
kl = 0.0
for p, q in zip(p_list, q_list):
if p > 0:
if q == 0:
return math.inf
kl += p * math.log2(p / q)
return kl
P = [0.7, 0.3]
Q1 = [0.6, 0.4] # 接近P
Q2 = [0.9, 0.1] # 远离P
h_p = entropy(P)
ce1 = cross_entropy(P, Q1)
kl1 = kl_divergence(P, Q1)
ce2 = cross_entropy(P, Q2)
kl2 = kl_divergence(P, Q2)
# 示例3:二元交叉熵损失计算
def binary_cross_entropy(y_true, y_pred):
"""计算单个样本的二元交叉熵损失"""
# 避免log(0)导致无穷大,对预测值进行微小裁剪
epsilon = 1e-12
y_pred = max(min(y_pred, 1 - epsilon), epsilon)
loss = -(y_true * math.log(y_pred) + (1 - y_true) * math.log(1 - y_pred))
return loss
# 假设模型对三个样本的预测概率
predictions = [0.9, 0.3, 0.6]
true_labels = [1, 0, 1] # 正面,负面,正面
print("样本 | 真实标签 | 预测概率 | 交叉熵损失")
print("-" * 40)
total_loss = 0
for i, (y, y_hat) in enumerate(zip(true_labels, predictions)):
loss = binary_cross_entropy(y, y_hat)
total_loss += loss
print(f"{i+1:^4} | {y:^8} | {y_hat:^10.2f} | {loss:.4f}")
average_loss = total_loss / len(predictions)
print(f"\n平均交叉熵损失: {average_loss:.4f}")样本 | 真实标签 | 预测概率 | 交叉熵损失
----------------------------------------
1 | 1 | 0.90 | 0.1054
2 | 0 | 0.30 | 0.3567
3 | 1 | 0.60 | 0.5108
平均交叉熵损失: 0.3243可以看到,当预测正确且置信度高时(样本1,预测正面概率0.9,真实为正面),损失很小;样本2也预测正确(正面概率0.3,即负面概率0.7,与真实标签负面一致),但正确类别的置信度0.7低于样本1的0.9,因此损失更大;样本3同样预测正确,但置信度较低,损失也较大。模型训练的过程就是通过梯度下降等优化算法,调整参数,使这个平均损失最小化。
交叉熵与语言模型
在自然语言处理中,交叉熵损失有着更广泛的应用。在语言模型任务中,我们的目标是预测下一个词的概率分布。给定一个词序列 ,语言模型需要输出词汇表 中所有词作为下一个词 的概率分布 。
而“真实分布” 是什么?在训练时,我们知道下一个词实际是 ,因此真实分布是一个在 上概率为1的One-Hot分布。
语言模型的训练目标就是最小化其预测分布 与真实One-Hot分布 之间的交叉熵。以2为底计算平均交叉熵 时,困惑度 ;若改用自然对数,则 。这一指数形式就是后面会学到的衡量语言模型好坏的重要指标——困惑度(Perplexity)。
# 伪代码示意:语言模型中的交叉熵计算(概念层面)
# 假设词汇表 V = {"我", "爱", "自然", "语言", "处理"}
# 给定上下文:"我 爱"
# 真实下一个词:"自然"
# 语言模型(如n-gram或神经网络)输出预测分布 Q
Q = {"我": 0.05, "爱": 0.05, "自然": 0.6, "语言": 0.2, "处理": 0.1}
# 真实分布 P (One-Hot)
P = {"我": 0.0, "爱": 0.0, "自然": 1.0, "语言": 0.0, "处理": 0.0}
# 交叉熵损失 H(P, Q) = -1 * log2(0.6) ≈ 0.737 bits
# 模型的目标是让这个损失在所有训练样本上平均最小化。📝 动手练一练
- 概念辨析:信息熵、交叉熵、KL散度三者之间有何区别与联系?为什么在分类任务中,最小化交叉熵损失是合理的?
- 手算练习:假设一个三分类问题的真实标签为类别 B(One-Hot编码为
[0, 1, 0])。模型A的预测概率为[0.2, 0.7, 0.1],模型B的预测概率为[0.1, 0.8, 0.1]。请计算两个模型对于该样本的交叉熵损失(以2为底)。哪个模型的预测更好?损失值相差多少?
👉 点击查看参考答案
区别与联系:
- 信息熵 :衡量单个分布 自身的不确定性。是固有属性。
- KL散度 :衡量两个分布 和 之间的差异(非对称)。。
- 交叉熵 :衡量使用分布 来编码来自分布 的数据所需的平均比特数。
- 核心关系:。
- 在分类任务中:真实标签分布 通常是 One-Hot 编码,其信息熵 。因此,最小化交叉熵 就等价于最小化 KL 散度 ,即直接让模型预测分布 逼近真实分布 。这就是其作为损失函数的数学原理。
手算练习:
- 对于模型A: bits。
- 对于模型B: bits。
- 模型B的损失更小(0.3219 < 0.5146),因此模型B的预测更好。
- 损失值相差约 bits。
本章小结
本节我们建立了自然语言处理中至关重要的信息论基础。我们从物理中的“熵”概念出发,理解了香农如何用它来量化信息。信息熵衡量不确定性,交叉熵衡量两个分布的差异,而KL散度则是这种差异的纯粹度量。最重要的洞见在于,对于固定的真实分布(如分类任务中的One-Hot标签),最小化交叉熵等价于让预测分布逼近真实分布,这使其天然地成为机器学习和深度学习中最核心的损失函数之一。
📋 行动清单
- 理解信息熵的公式 并能解释其含义。
- 掌握交叉熵 与 KL散度 的定义及关系 。
- 能够解释为什么交叉熵可以作为分类任务的损失函数,并会计算简单情况下的交叉熵损失值。
—— 小象教研组