第2章:概率与信息论(Probability and Information Theory)
一、导读
1.1 本章学习目标
第2章为深度学习提供概率论和信息论的数学基础。深度学习的核心任务之一是在不确定性下做出决策——模型需要对未知数据做出预测,同时量化自身的信心。概率论提供了描述不确定性的严格数学框架,而信息论则提供了度量信息量和不确定性的工具。
本章的核心学习目标包括:
- 掌握概率的基本规则:加法法则、乘法法则、条件概率、贝叶斯定理
- 理解常见概率分布:伯努利分布、多项式分布、高斯分布及其在深度学习中的应用
- 掌握边缘概率和条件概率的计算:理解如何从联合分布中推导边际和条件分布
- 理解信息论的核心概念:自信息、熵、交叉熵、KL散度
- 掌握最大似然估计的原理:理解参数估计的基本方法
- 了解结构化概率模型:条件独立性和贝叶斯网络的基本概念
1.2 为什么本章如此重要
深度学习中的模型本质上是在学习数据的概率分布。无论是分类任务中的类别概率、生成模型中的数据分布、还是强化学习中的策略分布,概率论都是不可或缺的工具。
具体来说:
- 分类任务:模型的输出是各类别的概率分布,训练目标是最大化正确类别的概率
- 损失函数:交叉熵损失是分类任务的标准损失函数,直接来源于信息论
- 生成模型:VAE、GAN等生成模型直接建模数据的概率分布
- 正则化:Dropout可以理解为对模型集成的近似贝叶斯推断
- 信息论度量:KL散度用于衡量分布差异,互信息用于特征选择
不理解概率论和信息论,就无法理解深度学习为什么这样设计损失函数、为什么用softmax、为什么交叉熵比均方误差更适合分类。
1.3 核心问题引导
在阅读本章时,请带着以下问题思考:
为什么深度学习中的分类任务几乎都用交叉熵损失而不是均方误差?
贝叶斯定理在深度学习中有哪些应用?先验和似然分别对应什么?
信息熵的物理意义是什么?为什么熵越大表示不确定性越高?
KL散度和交叉熵有什么关系?为什么交叉熵可以作为损失函数?
最大似然估计和最小化交叉熵有什么关系?
为什么高斯分布在深度学习中如此重要?
二、核心概念详解
2.1 概率基础
2.1.1 概率的公理化定义
概率是描述不确定事件的数学工具。Kolmogorov 公理化定义:
- 非负性:P(A) ≥ 0
- 归一性:P(Ω) = 1(样本空间的概率为1)
- 可加性:互斥事件 A、B,P(A∪B) = P(A) + P(B)
import numpy as np
# 离散概率分布
probabilities = np.array([0.1, 0.3, 0.4, 0.2])
print(f"概率之和: {np.sum(probabilities)}") # 1.0
# 连续概率分布(概率密度函数)
from scipy.stats import norm
x = np.linspace(-3, 3, 100)
pdf = norm.pdf(x, loc=0, scale=1)
# 概率密度函数的积分为1
from scipy.integrate import quad
integral, _ = quad(lambda x: norm.pdf(x, 0, 1), -np.inf, np.inf)
print(f"概率密度积分: {integral:.4f}") # 1.02.1.2 条件概率与贝叶斯定理
条件概率:在事件B发生的条件下,事件A发生的概率:
P(A|B) = P(A∩B) / P(B)贝叶斯定理:
P(A|B) = P(B|A) · P(A) / P(B)其中:
- P(A) 是先验概率(prior)
- P(A|B) 是后验概率(posterior)
- P(B|A) 是似然(likelihood)
- P(B) 是证据(evidence)
# 贝叶斯定理示例:疾病检测
# 假设某疾病发病率为0.1%,检测准确率99%,假阳性率5%
P_disease = 0.001 # 先验概率
P_positive_disease = 0.99 # 灵敏度(真阳性率)
P_positive_no_disease = 0.05 # 假阳性率
# 全概率公式
P_positive = (P_positive_disease * P_disease +
P_positive_no_disease * (1 - P_disease))
# 贝叶斯定理:检测阳性时真正患病的概率
P_disease_positive = P_positive_disease * P_disease / P_positive
print(f"检测阳性时患病的概率: {P_disease_positive:.4f}") # 约0.0194在深度学习中的应用:贝叶斯定理是贝叶斯深度学习的基础。先验对应正则化项,似然对应数据拟合项,后验对应训练后的模型参数分布。
2.1.3 边缘概率
从联合分布中消除某些变量,得到边缘分布:
P(A) = Σ_B P(A, B) (离散情况)
P(A) = ∫ P(A, B) dB (连续情况)# 边缘概率示例
# 联合概率分布
joint_prob = np.array([
[0.1, 0.2, 0.1],
[0.15, 0.25, 0.2]
])
# 边缘概率 P(X)
P_X = np.sum(joint_prob, axis=1) # [0.4, 0.6]
# 边缘概率 P(Y)
P_Y = np.sum(joint_prob, axis=0) # [0.25, 0.45, 0.3]2.2 常见概率分布
2.2.1 伯努利分布
伯努利分布是二值随机变量的分布:
P(X=1) = p, P(X=0) = 1-p
E[X] = p, Var(X) = p(1-p)from scipy.stats import bernoulli
p = 0.7
X = bernoulli(p)
# 生成样本
samples = X.rvs(size=10)
print(f"样本: {samples}")
# 概率质量函数
print(f"P(X=0) = {X.pmf(0):.1f}") # 0.3
print(f"P(X=1) = {X.pmf(1):.1f}") # 0.7在深度学习中的应用:二分类任务的输出可以建模为伯努利分布,sigmoid函数的输出就是参数p。
2.2.2 多项式分布(分类分布)
多项式分布是伯努利分布的多类别推广:
P(X=i) = p_i, Σp_i = 1from scipy.stats import multinomial
# 6面骰子的概率
n = 1
probs = [1/6] * 6
X = multinomial(n, probs)
# 生成样本
samples = X.rvs(size=5)
print(f"样本:\n{samples}")在深度学习中的应用:多分类任务的输出用softmax函数转化为分类分布。
import torch
import torch.nn.functional as F
# softmax 将 logits 转化为概率分布
logits = torch.tensor([2.0, 1.0, 0.1])
probs = F.softmax(logits, dim=0)
print(f"概率分布: {probs}") # 和为1
print(f"概率之和: {probs.sum()}") # 1.02.2.3 高斯分布(正态分布)
高斯分布是深度学习中最重要的连续分布:
N(x|μ, σ²) = (1/√(2πσ²)) · exp(-(x-μ)²/(2σ²))from scipy.stats import norm
import matplotlib.pyplot as plt
# 不同参数的高斯分布
x = np.linspace(-5, 5, 200)
fig, axes = plt.subplots(1, 2, figsize=(12, 4))
# 不同均值
for mu in [-2, 0, 2]:
axes[0].plot(x, norm.pdf(x, mu, 1), label=f'μ={mu}')
axes[0].set_title('不同均值的高斯分布')
axes[0].legend()
# 不同方差
for sigma in [0.5, 1.0, 2.0]:
axes[1].plot(x, norm.pdf(x, 0, sigma), label=f'σ={sigma}')
axes[1].set_title('不同方差的高斯分布')
axes[1].legend()
plt.tight_layout()
plt.savefig('gaussian_distributions.png', dpi=150)
plt.show()在深度学习中的应用:
- 权重初始化:He初始化、Xavier初始化都基于高斯分布
- Batch Normalization:假设中间层的激活值近似高斯分布
- VAE:隐变量服从标准高斯分布
- 噪声注入:训练时添加高斯噪声作为正则化
2.2.4 指数分布与拉普拉斯分布
from scipy.stats import expon, laplace
x = np.linspace(-3, 3, 200)
# 指数分布(用于L2正则化的先验)
# 拉普拉斯分布(用于L1正则化的先验)
plt.plot(x, laplace.pdf(x, 0, 1/np.sqrt(2)), label='Laplace')
plt.plot(x, norm.pdf(x, 0, 1), label='Gaussian')
plt.legend()
plt.title('Laplace vs Gaussian 先验')
plt.show()在深度学习中的应用:拉普拉斯分布作为权重的先验时,MAP估计等价于L1正则化;高斯分布作为先验时,等价于L2正则化。
2.3 信息论基础
2.3.1 自信息(Self-Information)
自信息度量单个事件的"信息量"或"惊讶程度":
I(x) = -log P(x)概率越小的事件,发生时带来的信息量越大。
def self_information(p):
return -np.log2(p)
# 抛硬币:正面朝上的信息量
print(f"公平硬币正面的信息量: {self_information(0.5):.2f} bits") # 1.0 bit
# 罕见事件的信息量
print(f"概率0.01事件的信息量: {self_information(0.01):.2f} bits") # 6.64 bits2.3.2 信息熵(Entropy)
信息熵是随机变量不确定性的度量,等于自信息的期望:
H(X) = -Σ P(x) log P(x) = E[I(X)]def entropy(p):
"""计算离散分布的熵"""
return -np.sum(p * np.log2(p + 1e-10))
# 均匀分布的熵最大
p_uniform = np.array([0.25, 0.25, 0.25, 0.25])
print(f"均匀分布的熵: {entropy(p_uniform):.2f} bits") # 2.0 bits
# 确定性分布的熵为0
p_certain = np.array([1.0, 0.0, 0.0, 0.0])
print(f"确定性分布的熵: {entropy(p_certain):.2f} bits") # 0.0 bits
# 一般分布
p_general = np.array([0.5, 0.3, 0.15, 0.05])
print(f"一般分布的熵: {entropy(p_general):.2f} bits") # 约1.49 bits在深度学习中的应用:
- 熵越大,分布越均匀,不确定性越高
- 决策树使用信息增益(熵的减少)作为分裂标准
- 强化学习中用熵正则化鼓励探索
2.3.3 交叉熵(Cross-Entropy)
交叉熵度量用分布q编码来自分布p的数据所需的平均额外比特数:
H(p, q) = -Σ P(x) log Q(x)def cross_entropy(p, q):
"""计算交叉熵"""
return -np.sum(p * np.log(q + 1e-10))
# 真实分布
p = np.array([0.7, 0.2, 0.1])
# 模型预测分布
q_good = np.array([0.65, 0.25, 0.10])
q_bad = np.array([0.1, 0.8, 0.1])
print(f"好的预测的交叉熵: {cross_entropy(p, q_good):.4f}")
print(f"差的预测的交叉熵: {cross_entropy(p, q_bad):.4f}")在深度学习中的应用:交叉熵是分类任务的标准损失函数。最小化交叉熵等价于最大化似然。
import torch
import torch.nn as nn
# PyTorch 中的交叉熵损失
# 注意:nn.CrossEntropyLoss 内部包含了 softmax
logits = torch.tensor([[2.0, 1.0, 0.1]]) # 未经softmax的logits
target = torch.tensor([0]) # 真实类别
criterion = nn.CrossEntropyLoss()
loss = criterion(logits, target)
print(f"交叉熵损失: {loss.item():.4f}")2.3.4 KL散度(Kullback-Leibler Divergence)
KL散度度量两个分布之间的"距离"(注意:不是真正的距离,不对称):
D_KL(P||Q) = Σ P(x) log(P(x)/Q(x)) = H(P, Q) - H(P)def kl_divergence(p, q):
"""计算KL散度"""
return np.sum(p * np.log((p + 1e-10) / (q + 1e-10)))
p = np.array([0.5, 0.3, 0.2])
q = np.array([0.4, 0.4, 0.2])
print(f"D_KL(P||Q) = {kl_divergence(p, q):.4f}")
print(f"D_KL(Q||P) = {kl_divergence(q, p):.4f}")
# 注意:KL散度不对称在深度学习中的应用:
- VAE:用KL散度约束隐变量分布接近标准高斯
- 知识蒸馏:用KL散度度量学生模型和教师模型分布的差异
- 策略梯度:TRPO/PPO用KL散度约束策略更新幅度
# VAE 中的 KL 散度
def vae_kl_loss(mu, log_var):
"""VAE中隐变量与标准正态分布的KL散度"""
# 解析形式:-0.5 * Σ(1 + log(σ²) - μ² - σ²)
kl = -0.5 * torch.sum(1 + log_var - mu.pow(2) - log_var.exp())
return kl2.4 最大似然估计
2.4.1 原理
最大似然估计(MLE)是参数估计的基本方法。给定观测数据,找到使数据出现概率最大的参数:
θ_MLE = argmax_θ P(data|θ) = argmax_θ Π P(x_i|θ)取对数后变为求和(数值更稳定):
θ_MLE = argmax_θ Σ log P(x_i|θ)2.4.2 高斯分布的MLE
# 高斯分布的最大似然估计
data = np.random.randn(1000) * 2 + 3 # 真实均值3,标准差2
# MLE 估计
mu_mle = np.mean(data)
sigma_mle = np.std(data)
print(f"真实参数: μ=3, σ=2")
print(f"MLE估计: μ={mu_mle:.3f}, σ={sigma_mle:.3f}")2.4.3 MLE与交叉熵的关系
最小化交叉熵等价于最大化似然。这解释了为什么交叉熵是分类任务的标准损失函数。
import torch
import torch.nn.functional as F
# 二分类的MLE等价于最小化二元交叉熵
# 模型输出概率 p(y=1|x)
# 对数似然:Σ[y_i * log(p_i) + (1-y_i) * log(1-p_i)]
# 负对数似然 = 二元交叉熵
logits = torch.tensor([1.5, -0.5, 2.0, -1.0])
targets = torch.tensor([1.0, 0.0, 1.0, 0.0])
# 方法1:直接计算负对数似然
probs = torch.sigmoid(logits)
nll = -torch.mean(targets * torch.log(probs) + (1-targets) * torch.log(1-probs))
# 方法2:使用BCELoss
bce = F.binary_cross_entropy_with_logits(logits, targets)
print(f"负对数似然: {nll.item():.4f}")
print(f"BCE损失: {bce.item():.4f}")
# 两者相等2.5 结构化概率模型
2.5.1 条件独立
如果 P(A,B|C) = P(A|C)·P(B|C),则A和B在给定C的条件下独立。条件独立可以大幅简化概率模型。
# 朴素贝叶斯假设:特征在给定类别下条件独立
# P(x1, x2, ..., xn | y) = Π P(xi | y)2.5.2 贝叶斯网络
贝叶斯网络用有向无环图表示变量之间的条件独立关系。
# 简单的贝叶斯网络:天气 -> 洒水器 -> 草地湿
# P(Weather, Sprinkler, WetGrass) =
# P(Weather) · P(Sprinkler|Weather) · P(WetGrass|Weather, Sprinkler)
# 朴素贝叶斯分类器
from sklearn.naive_bayes import GaussianNB
X = np.random.randn(100, 5)
y = np.random.randint(0, 3, 100)
nb = GaussianNB()
nb.fit(X, y)
predictions = nb.predict(X[:5])
print(f"预测: {predictions}")三、实战案例
3.1 案例一:交叉熵损失函数的手动实现
import numpy as np
def softmax(logits):
"""数值稳定的softmax"""
exp_logits = np.exp(logits - np.max(logits, axis=1, keepdims=True))
return exp_logits / np.sum(exp_logits, axis=1, keepdims=True)
def cross_entropy_loss(logits, targets):
"""交叉熵损失函数"""
batch_size = logits.shape[0]
probs = softmax(logits)
# 取对数(加小常数防止log(0))
log_probs = np.log(probs + 1e-10)
# 取正确类别的对数概率
correct_log_probs = log_probs[np.arange(batch_size), targets]
# 平均损失
loss = -np.mean(correct_log_probs)
return loss
def cross_entropy_gradient(logits, targets):
"""交叉熵损失对logits的梯度"""
batch_size = logits.shape[0]
probs = softmax(logits)
# 梯度 = probs - one_hot(targets)
grad = probs.copy()
grad[np.arange(batch_size), targets] -= 1
grad /= batch_size
return grad
# 测试
logits = np.array([[2.0, 1.0, 0.1],
[0.5, 2.0, 0.3],
[1.0, 0.5, 2.0]])
targets = np.array([0, 1, 2])
loss = cross_entropy_loss(logits, targets)
grad = cross_entropy_gradient(logits, targets)
print(f"交叉熵损失: {loss:.4f}")
print(f"梯度:\n{grad}")
# 数值梯度验证
epsilon = 1e-5
numerical_grad = np.zeros_like(logits)
for i in range(logits.shape[0]):
for j in range(logits.shape[1]):
logits_plus = logits.copy()
logits_plus[i, j] += epsilon
logits_minus = logits.copy()
logits_minus[i, j] -= epsilon
numerical_grad[i, j] = (cross_entropy_loss(logits_plus, targets) -
cross_entropy_loss(logits_minus, targets)) / (2 * epsilon)
print(f"数值梯度:\n{numerical_grad}")
print(f"梯度差异: {np.max(np.abs(grad - numerical_grad)):.2e}")3.2 案例二:KL散度在VAE中的应用
import torch
import torch.nn.functional as F
def vae_loss(recon_x, x, mu, log_var):
"""VAE的完整损失函数"""
# 重构损失(二元交叉熵)
recon_loss = F.binary_cross_entropy(recon_x, x, reduction='sum')
# KL散度损失
# D_KL(N(μ, σ²) || N(0, 1)) = -0.5 * Σ(1 + log(σ²) - μ² - σ²)
kl_loss = -0.5 * torch.sum(1 + log_var - mu.pow(2) - log_var.exp())
return recon_loss + kl_loss, recon_loss, kl_loss
# 模拟VAE训练
batch_size = 32
input_dim = 784
latent_dim = 20
# 模拟数据
x = torch.rand(batch_size, input_dim)
recon_x = torch.rand(batch_size, input_dim) # 模拟重构
mu = torch.randn(batch_size, latent_dim)
log_var = torch.randn(batch_size, latent_dim) * 0.1
total_loss, recon_loss, kl_loss = vae_loss(recon_x, x, mu, log_var)
print(f"总损失: {total_loss.item():.2f}")
print(f"重构损失: {recon_loss.item():.2f}")
print(f"KL损失: {kl_loss.item():.2f}")
# 调整KL权重(β-VAE)
beta = 4.0
total_loss_beta = recon_loss + beta * kl_loss
print(f"β-VAE总损失 (β={beta}): {total_loss_beta.item():.2f}")3.3 案例三:最大似然估计与过拟合
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import norm
# 生成数据
np.random.seed(42)
true_mu = 2.0
true_sigma = 1.0
n_samples = 20
data = np.random.randn(n_samples) * true_sigma + true_mu
# 最大似然估计
mu_mle = np.mean(data)
sigma_mle = np.std(data)
# 贝叶斯估计(带先验)
prior_mu = 0.0
prior_sigma = 2.0
# 后验均值是先验均值和MLE的加权平均
weight = n_samples * prior_sigma**2 / (n_samples * prior_sigma**2 + sigma_mle**2)
mu_bayes = weight * prior_mu + (1 - weight) * mu_mle
# 可视化
x = np.linspace(-2, 6, 200)
plt.figure(figsize=(10, 6))
plt.hist(data, bins=10, density=True, alpha=0.5, label='数据直方图')
plt.plot(x, norm.pdf(x, true_mu, true_sigma), 'g-', linewidth=2, label='真实分布')
plt.plot(x, norm.pdf(x, mu_mle, sigma_mle), 'b--', linewidth=2, label=f'MLE: μ={mu_mle:.2f}, σ={sigma_mle:.2f}')
plt.plot(x, norm.pdf(x, mu_bayes, true_sigma), 'r:', linewidth=2, label=f'Bayes: μ={mu_bayes:.2f}')
plt.xlabel('x')
plt.ylabel('概率密度')
plt.title('最大似然估计 vs 贝叶斯估计')
plt.legend()
plt.savefig('mle_vs_bayes.png', dpi=150)
plt.show()
print(f"真实参数: μ={true_mu}, σ={true_sigma}")
print(f"MLE估计: μ={mu_mle:.4f}, σ={sigma_mle:.4f}")
print(f"贝叶斯估计: μ={mu_bayes:.4f}")四、本章小结
本章介绍了深度学习中必需的概率论和信息论知识:
概率基础:条件概率、贝叶斯定理、边缘概率是理解生成模型和贝叶斯方法的基础。
概率分布:伯努利分布、分类分布、高斯分布是深度学习中最常见的分布。softmax函数将logits转化为分类分布,sigmoid将logit转化为伯努利分布的参数。
信息论:熵度量不确定性,交叉熵度量分布差异,KL散度度量分布间的"距离"。交叉熵是分类任务的标准损失函数,KL散度在VAE和知识蒸馏中扮演核心角色。
最大似然估计:参数估计的基本方法。最小化交叉熵等价于最大化似然,这为分类任务使用交叉熵损失提供了理论依据。
结构化模型:条件独立假设可以大幅简化概率模型。朴素贝叶斯和贝叶斯网络是条件独立的典型应用。
概率论和信息论是深度学习的理论基石。理解它们,才能明白为什么模型这样设计、损失函数为什么这样选择、正则化为什么有效。
五、思考与练习
思考题
为什么分类任务用交叉熵损失比均方误差更好?从梯度的角度分析。
信息熵和热力学熵有什么联系和区别?
KL散度为什么不满足三角不等式?什么情况下可以替代为真正的距离度量?
贝叶斯定理中的先验选择对结果有什么影响?如何选择合理的先验?
最大似然估计为什么容易过拟合?贝叶斯方法如何解决这个问题?
编程练习
交叉熵实现:手动实现softmax和交叉熵损失,与PyTorch的实现对比,确保数值一致性。
KL散度可视化:绘制两个高斯分布之间的KL散度随参数变化的热力图。
MLE vs MAP:实现高斯分布的MLE和MAP估计,比较不同先验对结果的影响。
信息增益:在决策树中实现基于信息增益的特征选择。
β-VAE实验:改变β值,观察KL散度和重构质量的权衡。