人工智能之数学基础 信息论
第二章 核心度量
文章目录
- [人工智能之数学基础 信息论](#人工智能之数学基础 信息论)
- 前言
- 一、核心概念回顾:香农熵
- 二、交叉熵(Cross-Entropy)
- [1. 定义](#1. 定义)
- [2. 在分类任务中的形式](#2. 在分类任务中的形式)
- [三、KL 散度(相对熵)](#三、KL 散度(相对熵))
- [1. 定义](#1. 定义)
- [2. KL 散度 vs 交叉熵](#2. KL 散度 vs 交叉熵)
- 四、为什么分类任务用交叉熵作损失函数?
- [1. 理论优势](#1. 理论优势)
- [2. 与 MSE 对比(为何不用均方误差?)](#2. 与 MSE 对比(为何不用均方误差?))
- [五、Python 代码实现](#五、Python 代码实现)
- [1. 导入库](#1. 导入库)
- [2. 从零实现交叉熵与 KL 散度](#2. 从零实现交叉熵与 KL 散度)
- [3. 分类任务中的交叉熵(one-hot 形式)](#3. 分类任务中的交叉熵(one-hot 形式))
- [4. 与 PyTorch / TensorFlow 对比](#4. 与 PyTorch / TensorFlow 对比)
- [5. 可视化:交叉熵 vs 预测概率](#5. 可视化:交叉熵 vs 预测概率)
- [6. KL 散度实验:逼近真实分布](#6. KL 散度实验:逼近真实分布)
- [7. 多分类交叉熵的向量化实现(批量处理)](#7. 多分类交叉熵的向量化实现(批量处理))
- 六、高级话题:交叉熵与最大似然估计(MLE)
- 七、总结
- 后续
- 资料关注
前言
交叉熵(Cross-Entropy)和 KL 散度(Kullback-Leibler Divergence)是现代机器学习,尤其是深度学习分类任务的理论基石 。它们不仅定义了损失函数的形式,还揭示了模型学习的本质:让预测分布逼近真实分布。
本文将系统讲解:
- 交叉熵的定义与直觉
- KL 散度(相对熵)的数学本质
- 两者之间的深刻联系
- 为什么分类任务使用交叉熵作为损失函数?
- 配套 Python 代码实现(从零构建 + PyTorch/TensorFlow 对比 + 可视化)
一、核心概念回顾:香农熵
在深入交叉熵前,先回顾香农熵(Shannon Entropy):
H ( P ) = − ∑ x P ( x ) log P ( x ) H(P) = -\sum_{x} P(x) \log P(x) H(P)=−x∑P(x)logP(x)
- 表示真实分布 P 的不确定性(平均信息量)
- 单位:比特(以 2 为底)或纳特(以 ( e ) 为底)
✅ 例:公平硬币 P(H)=P(T)=0.5 → H§ = 1 比特
二、交叉熵(Cross-Entropy)
1. 定义
给定真实分布 P 和模型预测分布 Q ,交叉熵定义为:
H ( P , Q ) = − ∑ x P ( x ) log Q ( x ) H(P, Q) = -\sum_{x} P(x) \log Q(x) H(P,Q)=−x∑P(x)logQ(x)
- 直觉:用基于 Q 的编码方案去编码来自 P 的数据,所需的平均比特数
- 若 Q = P ,则 H(P, Q) = H§ (最优编码)
- 若 Q \\ne P ,则 H(P, Q) \> H§
📌 关键点 :交叉熵衡量的是用错误模型 Q 描述真实世界 P 的代价
2. 在分类任务中的形式
在多分类任务中:
- 真实标签 y 是 one-hot 向量(如 [ 0 , 0 , 1 , 0 ] [0, 0, 1, 0] [0,0,1,0])
- 模型输出 \\hat{y} 是概率分布(如 softmax 输出 [ 0.1 , 0.2 , 0.6 , 0.1 ] [0.1, 0.2, 0.6, 0.1] [0.1,0.2,0.6,0.1])
此时,交叉熵简化为:
H ( P , Q ) = − log Q ( y true ) H(P, Q) = -\log Q(y_{\text{true}}) H(P,Q)=−logQ(ytrue)
即:只关注真实类别的预测概率
✅ 例:真实类别是第 3 类(索引 2), \\hat{y}_2 = 0.6 → 损失 = -\\log(0.6) \\approx 0.51
三、KL 散度(相对熵)
1. 定义
KL 散度衡量两个分布 P 与 Q 的非对称差异:
D KL ( P ∥ Q ) = ∑ x P ( x ) log P ( x ) Q ( x ) = E x ∼ P [ log P ( x ) Q ( x ) ] D_{\text{KL}}(P \parallel Q) = \sum_{x} P(x) \log \frac{P(x)}{Q(x)} = \mathbb{E}_{x \sim P} \left[ \log \frac{P(x)}{Q(x)} \right] DKL(P∥Q)=x∑P(x)logQ(x)P(x)=Ex∼P[logQ(x)P(x)]
- 性质 :
- D_{\\text{KL}}(P \\parallel Q) \\geq 0
- D_{\\text{KL}}(P \\parallel Q) = 0 \\iff P = Q
- 非对称: D_{\\text{KL}}(P \\parallel Q) \\ne D_{\\text{KL}}(Q \\parallel P)
- 不是距离(不满足三角不等式)
💡 直觉:KL 散度是"用 Q 近似 P 所损失的信息量"
2. KL 散度 vs 交叉熵
展开 KL 散度:
D KL ( P ∥ Q ) = ∑ x P ( x ) log P ( x ) − ∑ x P ( x ) log Q ( x ) = − H ( P ) + H ( P , Q ) \begin{aligned} D_{\text{KL}}(P \parallel Q) &= \sum_x P(x) \log P(x) - \sum_x P(x) \log Q(x) \\ &= -H(P) + H(P, Q) \end{aligned} DKL(P∥Q)=x∑P(x)logP(x)−x∑P(x)logQ(x)=−H(P)+H(P,Q)
因此:
H ( P , Q ) = H ( P ) + D KL ( P ∥ Q ) \boxed{H(P, Q) = H(P) + D_{\text{KL}}(P \parallel Q)} H(P,Q)=H(P)+DKL(P∥Q)
🌟 核心结论:
- 最小化交叉熵 ⇨ 最小化 KL 散度(因为 H§ 是常数!)
- 模型训练的目标:让 Q \\to P ,即使 D_{\\text{KL}}(P \\parallel Q) \\to 0
四、为什么分类任务用交叉熵作损失函数?
1. 理论优势
- 梯度良好: \\frac{\\partial}{\\partial z_i} (-\\log \\hat{y}_j) 在 softmax 下有简洁形式
- 概率解释清晰:最大化真实类别的对数似然(MLE)
- 与信息论一致:最小化预测与真实的分布差异
2. 与 MSE 对比(为何不用均方误差?)
| 指标 | 交叉熵 | 均方误差(MSE) |
|---|---|---|
| 适用任务 | 分类(概率输出) | 回归(连续值) |
| 梯度饱和 | 无(尤其配合 softmax) | 有(sigmoid + MSE 梯度消失) |
| 优化目标 | 最大似然估计 | 最小平方误差 |
| 概率一致性 | ✅ | ❌ |
🔥 经典结论:分类任务应使用交叉熵,而非 MSE
五、Python 代码实现
1. 导入库
python
import numpy as np
import torch
import tensorflow as tf
import matplotlib.pyplot as plt
import seaborn as sns
plt.rcParams['font.sans-serif'] = ['SimHei']
sns.set(style="whitegrid")
2. 从零实现交叉熵与 KL 散度
python
def cross_entropy(p, q, eps=1e-15):
"""
计算离散分布 p 和 q 的交叉熵 H(p, q)
p, q: 一维 numpy 数组,表示概率分布(需归一化)
"""
q = np.clip(q, eps, 1 - eps) # 防止 log(0)
return -np.sum(p * np.log(q))
def kl_divergence(p, q, eps=1e-15):
"""计算 KL(P || Q)"""
q = np.clip(q, eps, 1 - eps)
p = np.clip(p, eps, 1 - eps)
return np.sum(p * np.log(p / q))
def entropy(p, eps=1e-15):
"""计算香农熵 H(p)"""
p = np.clip(p, eps, 1 - eps)
return -np.sum(p * np.log(p))
3. 分类任务中的交叉熵(one-hot 形式)
python
def categorical_cross_entropy_onehot(y_true, y_pred, eps=1e-15):
"""
y_true: one-hot 标签,shape=(n_classes,)
y_pred: 预测概率,shape=(n_classes,)
"""
y_pred = np.clip(y_pred, eps, 1 - eps)
return -np.sum(y_true * np.log(y_pred))
# 示例
y_true = np.array([0, 0, 1, 0]) # 真实类别:第3类
y_pred_good = np.array([0.1, 0.1, 0.7, 0.1]) # 预测较好
y_pred_bad = np.array([0.4, 0.3, 0.1, 0.2]) # 预测较差
loss_good = categorical_cross_entropy_onehot(y_true, y_pred_good)
loss_bad = categorical_cross_entropy_onehot(y_true, y_pred_bad)
print(f"好预测的损失: {loss_good:.4f}") # ≈ 0.3567
print(f"差预测的损失: {loss_bad:.4f}") # ≈ 2.3026
4. 与 PyTorch / TensorFlow 对比
python
# PyTorch
y_true_idx = torch.tensor([2]) # 真实类别索引
y_pred_logits = torch.tensor([[np.log(0.1), np.log(0.1), np.log(0.7), np.log(0.1)]])
loss_torch = torch.nn.CrossEntropyLoss()(y_pred_logits, y_true_idx)
print(f"PyTorch 损失: {loss_torch.item():.4f}")
# TensorFlow / Keras
y_true_tf = tf.constant([[0, 0, 1, 0]], dtype=tf.float32)
y_pred_tf = tf.constant([[0.1, 0.1, 0.7, 0.1]], dtype=tf.float32)
loss_tf = tf.keras.losses.categorical_crossentropy(y_true_tf, y_pred_tf)
print(f"TensorFlow 损失: {loss_tf.numpy()[0]:.4f}")
# 验证一致性
assert abs(loss_good - loss_torch.item()) < 1e-5
assert abs(loss_good - loss_tf.numpy()[0]) < 1e-5
print("✅ 自实现与主流框架一致")
⚠️ 注意:PyTorch 的
CrossEntropyLoss接收 logits(未 softmax) ,内部自动加 softmax;而我们的实现接收 概率。
5. 可视化:交叉熵 vs 预测概率
python
p_true = 1.0 # 真实概率(one-hot)
q_pred = np.linspace(0.01, 1.0, 100)
ce_loss = [-np.log(q) for q in q_pred]
plt.figure(figsize=(8, 5))
plt.plot(q_pred, ce_loss, 'b-', linewidth=2)
plt.axvline(1.0, color='r', linestyle='--', label='完美预测 (q=1)')
plt.title('交叉熵损失 vs 预测概率(真实类别概率=1)')
plt.xlabel('模型预测概率 $\\hat{y}_{true}$')
plt.ylabel('交叉熵损失 $-\\log(\\hat{y}_{true})$')
plt.legend()
plt.grid(True)
plt.show()
📈 观察:当 \\hat{y}*{\\text{true}} \\to 0 ,损失 → ∞;当 \\hat{y}*{\\text{true}} = 1 ,损失 = 0
6. KL 散度实验:逼近真实分布
python
# 真实分布 P:偏置硬币
p = np.array([0.9, 0.1])
# 一系列模型分布 Q
q_vals = np.linspace(0.1, 0.99, 50)
kl_vals = []
ce_vals = []
for q in q_vals:
q_dist = np.array([q, 1 - q])
kl_vals.append(kl_divergence(p, q_dist))
ce_vals.append(cross_entropy(p, q_dist))
# 绘图
plt.figure(figsize=(10, 4))
plt.subplot(1, 2, 1)
plt.plot(q_vals, kl_vals, 'r-', label='$D_{KL}(P \\parallel Q)$')
plt.axvline(0.9, color='k', linestyle='--', label='P=Q')
plt.title('KL 散度'); plt.xlabel('Q(正面)'); plt.legend()
plt.subplot(1, 2, 2)
plt.plot(q_vals, ce_vals, 'b-', label='$H(P, Q)$')
plt.axvline(0.9, color='k', linestyle='--')
plt.title('交叉熵'); plt.xlabel('Q(正面)'); plt.legend()
plt.tight_layout()
plt.show()
# 验证:H(P, Q) = H(P) + D_KL(P||Q)
h_p = entropy(p)
print(f"H(P) = {h_p:.4f}")
print(f"在 Q=P 时: H(P,Q) - D_KL = {ce_vals[np.argmin(np.abs(q_vals - 0.9))]:.4f} - {min(kl_vals):.4f} ≈ {h_p:.4f}")
7. 多分类交叉熵的向量化实现(批量处理)
python
def batch_categorical_cross_entropy(y_true, y_pred, eps=1e-15):
"""
y_true: shape=(N, C), one-hot
y_pred: shape=(N, C), 概率分布
返回: 平均损失
"""
y_pred = np.clip(y_pred, eps, 1 - eps)
losses = -np.sum(y_true * np.log(y_pred), axis=1)
return np.mean(losses)
# 测试批量
N, C = 32, 10
y_true_batch = np.eye(C)[np.random.choice(C, N)] # 随机 one-hot 标签
y_pred_batch = np.random.dirichlet([1]*C, size=N) # 随机概率 simplex
loss_batch = batch_categorical_cross_entropy(y_true_batch, y_pred_batch)
print(f"批量交叉熵损失: {loss_batch:.4f}")
六、高级话题:交叉熵与最大似然估计(MLE)
定理:最小化交叉熵 ⇨ 最大化对数似然
设数据集 {(x_i, y_i)}_{i=1}\^N ,模型输出 P(y \\mid x; \\theta)
- 对数似然 :
L ( θ ) = ∑ i = 1 N log P ( y i ∣ x i ; θ ) \mathcal{L}(\theta) = \sum_{i=1}^N \log P(y_i \mid x_i; \theta) L(θ)=i=1∑NlogP(yi∣xi;θ) - 平均交叉熵损失 :
J ( θ ) = − 1 N ∑ i = 1 N log P ( y i ∣ x i ; θ ) = − 1 N L ( θ ) \mathcal{J}(\theta) = -\frac{1}{N} \sum_{i=1}^N \log P(y_i \mid x_i; \theta) = -\frac{1}{N} \mathcal{L}(\theta) J(θ)=−N1i=1∑NlogP(yi∣xi;θ)=−N1L(θ)
✅ 因此:最小化交叉熵 = 最大化似然 → 模型学习真实条件分布
七、总结
| 概念 | 公式 | 在 ML 中的角色 |
|---|---|---|
| 交叉熵 H(P, Q) | -\\sum P \\log Q | 分类任务的标准损失函数 |
| KL 散度 D_{\\text{KL}}(P \\parallel Q) | \\sum P \\log(P/Q) | 衡量预测分布与真实分布的差异 |
| 关系 | H(P, Q) = H§ + D_{\\text{KL}}(P \\parallel Q) | 优化交叉熵 ⇨ 逼近距离最小化 |
| 分类损失 | -\\log Q(y_{\\text{true}}) | 只惩罚真实类别的预测置信度 |
💡 关键洞见:
- 交叉熵是 KL 散度的"可优化部分"(因 ( H§ ) 与模型无关);
- 深度学习分类器本质上是在拟合条件概率分布;
- 不要对分类任务使用 MSE------它缺乏概率解释且梯度不佳;
- 低交叉熵 ≠ 高准确率(可能过拟合或校准差),但它是优化的正确方向。
后续
python过渡项目部分代码已经上传至gitee,后续会逐步更新。
资料关注
公众号:咚咚王
gitee:https://gitee.com/wy18585051844/ai_learning
《Python编程:从入门到实践》
《利用Python进行数据分析》
《算法导论中文第三版》
《概率论与数理统计(第四版) (盛骤) 》
《程序员的数学》
《线性代数应该这样学第3版》
《微积分和数学分析引论》
《(西瓜书)周志华-机器学习》
《TensorFlow机器学习实战指南》
《Sklearn与TensorFlow机器学习实用指南》
《模式识别(第四版)》
《深度学习 deep learning》伊恩·古德费洛著 花书
《Python深度学习第二版(中文版)【纯文本】 (登封大数据 (Francois Choliet)) (Z-Library)》
《深入浅出神经网络与深度学习+(迈克尔·尼尔森(Michael+Nielsen)》
《自然语言处理综论 第2版》
《Natural-Language-Processing-with-PyTorch》
《计算机视觉-算法与应用(中文版)》
《Learning OpenCV 4》
《AIGC:智能创作时代》杜雨+&+张孜铭
《AIGC原理与实践:零基础学大语言模型、扩散模型和多模态模型》
《从零构建大语言模型(中文版)》
《实战AI大模型》
《AI 3.0》