信息论基础

为什么学信息论?
你在训练分类模型时用的 CrossEntropyLoss(交叉熵损失),名字里就有"熵"。信息论告诉你这个损失函数到底在度量什么,以及为什么它对分类任务这么有效。
学习目标
- 理解信息量和熵——不确定性的度量
- 理解交叉熵——衡量两个分布的差异
- 理解 KL 散度——一个分布到另一个分布的"距离"
- 用 Python 计算和可视化
历史背景:信息论这一节最关键的起点是什么?
这一节最值得知道的历史节点是:
| 年份 | 论文 | 关键作者 | 它最重要地解决了什么 |
|---|---|---|---|
| 1948 | A Mathematical Theory of Communication | Claude Shannon | 系统提出了信息量、熵和现代信息论主线 |
对新人来说,最值得先记的 是:
香农让“信息到底有多少”第一次可以被严格度量。
所以你这一节看到的:
- 信息量
- 熵
- 交叉熵
不是散碎概念,而是都站在同一条信息论主线上。
先说一个很重要的学习预期
这一节对新人来说最容易卡住的点是:
- 名字听起来很抽象
- 公式看起来像“数学中的数学”
但这里真正最重要的,不是先把所有定义背熟,而是先看懂:
- 为什么“越意外,信息量越大”
- 为什么“越不确定,熵越大”
- 为什么分类损失最后会和这些量连在一起
你可以把这节先理解成:
给“模型到底有多确定、预测到底差多远”找一套更精确的语言。
先建立一张地图
这一节看起来最不像“概率课”,但它和模型训练其实联系非常紧。
所以这节课真正想讲的是:
- 为什么“越意外的事,信息量越大”
- 为什么一个分布越不确定,熵越大
- 为什么交叉熵会成为分类任务的核心损失函数
一、信息量——"惊讶程度"
1.1 直觉
一条消息包含的信息量 = 它有多出人意料。
- "太阳从东边升起" → 信息量 ≈ 0(完全不意外)
- "今天北京下雪了"(夏天) → 信息量很大(非常意外)
- "今天北京下雪了"(冬天) → 信息量中等
概率越低的事件,发生时带来的信息量越大。
1.1.1 一个更适合新人的类比
你可以先把信息量想成:
- “这件事有多值得我惊讶一下”
比如:
- 太阳明天升起,不值得惊讶
- 夏天下雪,就很值得惊讶
所以信息量最值得先记的,不是公式,而是:
越不常见的事,一旦发生,带来的信息就越多。
1.2 数学定义
信息量 = -log2(概率)
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['Arial Unicode MS']
plt.rcParams['axes.unicode_minus'] = False
# 不同概率对应的信息量
probs = np.linspace(0.01, 1, 100)
info = -np.log2(probs)
plt.figure(figsize=(8, 5))
plt.plot(probs, info, color='steelblue', linewidth=2)
plt.xlabel('事件概率')
plt.ylabel('信息量(比特)')
plt.title('信息量 = -log₂(概率)')
plt.grid(True, alpha=0.3)
# 标注几个关键点
for p, label in [(1.0, '必然事件'), (0.5, '抛硬币'), (0.01, '罕见事件')]:
i = -np.log2(p)
plt.annotate(f'{label}\np={p}, info={i:.1f}bit',
xy=(p, i), fontsize=10,
xytext=(p+0.15, i+0.5),
arrowprops=dict(arrowstyle='->', color='gray'))
plt.show()
| 事件概率 | 信息量 | 直觉 |
|---|---|---|
| 1.0 | 0 bit | 必然发生,没有信息 |
| 0.5 | 1 bit | 抛一次硬币,1 比特信息 |
| 0.25 | 2 bit | 猜中一个两位二进制数 |
| 0.01 | 6.64 bit | 很意外,信息量大 |
二、熵——平均不确定性
2.1 直觉
熵(Entropy)= 一个分布的"平均信息量"= 系统的"平均不确定性"。
2.1.1 熵最值得先记住的,不是定义,而是“混乱程度”
可以先把熵想成:
- 你在做判断前到底有多拿不准
如果一个系统总是几乎确定:
- 熵就低
如果一个系统每次都很难猜:
- 熵就高
所以熵的最朴素意义,其实就是:
平均不确定性有多大。
2.2 公式与计算
H(X) = -Σ p(x) × log2(p(x))
def entropy(probs):
"""计算熵(以比特为单位)"""
probs = np.array(probs)
# 避免 log(0)
probs = probs[probs > 0]
return -np.sum(probs * np.log2(probs))
# 例 1:公平硬币(最大不确定性)
h1 = entropy([0.5, 0.5])
print(f"公平硬币的熵: {h1:.3f} bit") # 1.0
# 例 2:不公平硬币
h2 = entropy([0.9, 0.1])
print(f"不公平硬币(0.9, 0.1)的熵: {h2:.3f} bit") # 0.469
# 例 3:必然事件(无不确定性)
h3 = entropy([1.0, 0.0])
print(f"必然事件的熵: {h3:.3f} bit") # 0.0
# 例 4:公平骰子
h4 = entropy([1/6]*6)
print(f"公平骰子的熵: {h4:.3f} bit") # 2.585
2.3 可视化:硬币的熵随 p 变化
p_values = np.linspace(0.001, 0.999, 1000)
entropies = [-p * np.log2(p) - (1-p) * np.log2(1-p) for p in p_values]
plt.figure(figsize=(8, 5))
plt.plot(p_values, entropies, color='steelblue', linewidth=2)
plt.xlabel('正面概率 p')
plt.ylabel('熵 H (bit)')
plt.title('二元分布的熵:p=0.5 时最大(最不确定)')
plt.axvline(x=0.5, color='red', linestyle='--', alpha=0.5, label='p=0.5(最大熵)')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
关键洞察:p = 0.5 时熵最大(最不确定),p = 0 或 1 时熵为 0(完全确定)。
2.4 熵在 AI 中的应用
| 应用 | 说明 |
|---|---|
| 决策树 | 用信息增益(熵的减少量)选择最佳分割特征 |
| 模型输出 | 分类模型输出概率分布的熵越低,模型越"自信" |
| 数据压缩 | 熵是数据压缩的理论下限 |
| 语言模型 | 困惑度(Perplexity) = 2^(交叉熵),衡量模型好坏 |
三、交叉熵——衡量"预测有多准"
3.1 直觉
交叉熵 = 用分布 Q 来编码分布 P 的数据,平均每个样本需要多少比特。
3.1.1 一个更适合新人的说法
你也可以暂时把交叉熵理解成:
- 预测分布和真实分布到底差得有多离谱
这对初学者来说已经足够有用了。
因为后面你在分类模型里真正关心的也是:
- 模型到底有没有把正确类别放到更高概率上
如果 Q 和 P 完全一样 → 交叉熵 = P 的熵(最小值) 如果 Q 和 P 差异大 → 交叉熵远大于 P 的熵
3.2 公式与计算
H(P, Q) = -Σ p(x) × log2(q(x))
def cross_entropy(p, q):
"""计算交叉熵"""
p, q = np.array(p), np.array(q)
# 避免 log(0)
q = np.clip(q, 1e-10, 1)
return -np.sum(p * np.log2(q))
# 真实分布 P
P = [0.7, 0.2, 0.1] # 三分类问题
# 预测分布 Q(不同质量的预测)
Q_good = [0.65, 0.25, 0.10] # 好预测
Q_bad = [0.33, 0.33, 0.34] # 差预测(均匀猜)
Q_wrong = [0.1, 0.1, 0.8] # 错误预测
print(f"P 的熵: {entropy(P):.4f}")
print(f"好预测交叉熵: {cross_entropy(P, Q_good):.4f}")
print(f"差预测交叉熵: {cross_entropy(P, Q_bad):.4f}")
print(f"错误预测交叉熵: {cross_entropy(P, Q_wrong):.4f}")