信息熵与交叉熵实战:从编码到PyTorch损失函数的3个关键推导
信息熵与交叉熵实战:从编码到PyTorch损失函数的3个关键推导
1. 信息论基础:从编码视角理解熵的本质
当我们谈论信息熵时,本质上是在讨论"用最优方式编码信息所需的最小平均比特数"。这个观点由克劳德·香农在1948年提出,它揭示了概率与信息之间的深刻联系。
信息量的数学定义:对于一个发生概率为p的事件,其信息量I(p) = -log₂p。这个对数函数的选择不是随意的——它确保了独立事件的信息量具有可加性。例如:
- 一个公平硬币抛掷的结果(p=0.5)包含I=1比特的信息
- 一个八面骰子掷出特定数字(p=1/8)包含I=3比特的信息
熵的物理意义:信息熵H(X)是随机变量X所有可能取值的信息量的期望:
def entropy(prob_dist): return -np.sum(prob_dist * np.log2(prob_dist))考虑以下三种概率分布的熵对比:
| 分布类型 | 概率向量 | 熵值(比特) |
|---|---|---|
| 确定分布 | [1.0, 0.0, 0.0] | 0.0 |
| 均匀分布 | [0.33, 0.33, 0.34] | ~1.58 |
| 偏斜分布 | [0.9, 0.05, 0.05] | ~0.57 |
熵的重要性质:当分布越接近均匀时熵越大,完全确定时熵为零。这解释了为什么压缩随机数据比压缩规律性强的数据更困难。
2. 交叉熵的推导与最大似然估计
交叉熵是机器学习中最重要的概念之一,它衡量了两个概率分布之间的"距离"。从编码角度理解:
- 用真实分布P的最优编码时,平均码长为H(P)
- 用近似分布Q的编码来传达P的信息时,平均码长为H(P,Q)
数学定义: H(P,Q) = -Σp(x)logq(x)
在深度学习中,最小化交叉熵等价于最大化似然函数。让我们通过一个分类问题来理解这点:
假设我们有:
- 真实标签分布P:one-hot编码 [0,0,1]
- 模型预测分布Q:softmax输出 [0.1,0.2,0.7]
交叉熵计算为: H(P,Q) = -(0log0.1 + 0log0.2 + 1*log0.7) = -log0.7 ≈ 0.3567
PyTorch中的实现方式:
import torch.nn as nn loss_fn = nn.CrossEntropyLoss() # 内置了softmax outputs = model(inputs) loss = loss_fn(outputs, labels)三种典型分布的交叉熵计算对比:
二分类问题(sigmoid输出): H(P,Q) = -[y*logŷ + (1-y)*log(1-ŷ)]
多分类问题(softmax输出): H(P,Q) = -Σy_i*logŷ_i
回归问题(高斯假设): 当假设输出服从高斯分布时,最小化MSE等价于最小化交叉熵
3. 从理论到实践:PyTorch中的自定义损失函数
理解理论后,我们可以深入实现层面。标准的交叉熵损失有时需要调整,例如处理类别不平衡或特殊任务需求。
自定义加权交叉熵实现:
class WeightedCrossEntropy(nn.Module): def __init__(self, weights): super().__init__() self.weights = torch.tensor(weights) def forward(self, inputs, targets): log_probs = -F.log_softmax(inputs, dim=1) loss = self.weights[targets] * log_probs.gather(1, targets.unsqueeze(1)) return loss.mean() # 使用示例 weights = [1.0, 2.0, 1.5] # 给不同类别不同权重 criterion = WeightedCrossEntropy(weights)KL散度与交叉熵的关系: KL(P||Q) = H(P,Q) - H(P)
在PyTorch中可以直接计算:
kl_loss = nn.KLDivLoss(reduction='batchmean') output = F.log_softmax(model_out, dim=1) loss = kl_loss(output, target_distribution)实际训练中的技巧:
- 数值稳定性:添加微小epsilon防止log(0)
- 标签平滑:防止模型对标签过度自信
- 温度系数:调整softmax输出的"锐度"
# 标签平滑示例 def label_smoothing(targets, n_classes, smoothing=0.1): with torch.no_grad(): targets = targets * (1 - smoothing) + smoothing / n_classes return targets4. 高级应用:互信息与特征学习
互信息I(X;Y)=H(X)-H(X|Y)衡量两个变量间的统计依赖性。在现代深度学习中,它被用于:
- 无监督表示学习(如Deep InfoMax)
- 特征选择
- 生成模型的评估
互信息估计的PyTorch实现:
class MutualInfoEstimator(nn.Module): def __init__(self, input_dim): super().__init__() self.net = nn.Sequential( nn.Linear(input_dim*2, 256), nn.ReLU(), nn.Linear(256, 1)) def forward(self, x, y): # 联合样本得分 joint = torch.cat([x, y], dim=1) t = self.net(joint) # 边缘乘积样本得分 shuffled_y = y[torch.randperm(y.size(0))] marginal = torch.cat([x, shuffled_y], dim=1) t_margin = self.net(marginal) # 互信息下界估计 mi = t.mean() - torch.log(t_margin.exp().mean() + 1e-6) return mi在实际项目中,理解这些基础概念如何转化为代码至关重要。例如在图像分类任务中,交叉熵损失的选择直接影响模型收敛速度和最终性能。一个经验法则是:对于类别不平衡数据,使用加权交叉熵;当需要比较两个完整分布时,使用KL散度;而在自监督学习中,互信息最大化成为强大的学习目标。