共计 2161 个字符,预计需要花费 6 分钟才能阅读完成。
背景痛点:损失函数为什么重要?
在 BP 神经网络(Backpropagation Neural Network)的训练过程中,损失函数(Loss Function)就像导航仪一样,告诉模型当前预测结果与真实值的偏差程度。没有它,网络就不知道如何调整参数来减少错误。但在实际应用中,我们常常会遇到几个典型问题:

- 梯度消失(Vanishing Gradient):当使用某些损失函数(如均方误差)配合 sigmoid 激活函数时,反向传播的梯度可能会指数级减小,导致深层网络参数几乎不更新。
- 过拟合(Overfitting):模型在训练集上表现很好,但在测试集上表现糟糕,这时候损失函数可能需要配合正则化项来约束参数。
- 收敛速度慢 :不合适的损失函数会导致模型需要更多迭代才能达到最优,浪费计算资源。
技术对比:交叉熵损失 vs. 均方误差
均方误差(MSE, Mean Squared Error)
数学表达式:
$$ L_{MSE} = \frac{1}{N}\sum_{i=1}^N (y_i – \hat{y}_i)^2 $$
特点 :
– 对异常值敏感(因为平方放大误差)
– 输出为连续值时效果好(如房价预测)
– 易导致梯度消失(尤其在输出层使用 sigmoid 时)
交叉熵损失(CrossEntropy)
数学表达式(二分类):
$$ L_{CE} = -\frac{1}{N}\sum_{i=1}^N [y_i \log(\hat{y}_i) + (1-y_i)\log(1-\hat{y}_i)] $$
特点 :
– 分类任务的首选(尤其输出层用 softmax 时)
– 梯度计算更稳定(避免 sigmoid 导致的梯度饱和)
– 天然适应概率输出(0~1 之间的值)
核心实现:PyTorch 代码演示
均方误差实现
import torch
import torch.nn as nn
# 假设 batch_size=4,输出维度 =1(如回归问题)predictions = torch.tensor([[1.1], [2.4], [0.8], [3.2]], dtype=torch.float32)
targets = torch.tensor([[1.0], [2.0], [1.0], [3.0]], dtype=torch.float32)
loss_fn = nn.MSELoss() # 内置实现会自动处理维度
loss = loss_fn(predictions, targets)
loss.backward() # 自动计算梯度并反向传播
交叉熵损失实现
# 假设 batch_size=4,类别数 =3(如分类问题)# 注意:输入不需要 softmax,PyTorch 的 CrossEntropyLoss 会自动处理
logits = torch.randn(4, 3) # 原始输出(未归一化)targets = torch.tensor([0, 2, 1, 0]) # 类别标签
loss_fn = nn.CrossEntropyLoss()
loss = loss_fn(logits, targets)
loss.backward()
调优指南:生产环境技巧
- 学习率与损失函数配合
- MSE 通常需要更小的学习率(如 1e-4),因为梯度可能较大
- CrossEntropy 可以使用稍大学习率(如 1e-3)
-
建议配合学习率调度器(如
torch.optim.lr_scheduler.StepLR) -
正则化项添加
# L2 正则化(权重衰减)optimizer = torch.optim.SGD(model.parameters(), lr=0.01, weight_decay=1e-5) # L1 正则化需要手动实现 l1_lambda = 0.001 l1_norm = sum(p.abs().sum() for p in model.parameters()) loss = loss + l1_lambda * l1_norm -
类别不平衡处理
# 假设类别 0 样本是类别 1 的 5 倍 weights = torch.tensor([1.0, 5.0]) loss_fn = nn.CrossEntropyLoss(weight=weights)
避坑建议
- 分类任务误用 MSE:
- 会导致模型过度关注“绝对正确”而非“相对概率”
-
特别在多分类任务中,MSE 会使优化目标偏离
-
激活函数与损失函数不匹配 :
nn.CrossEntropyLoss已经包含 log_softmax,输出层不应再加 softmax- MSE 通常搭配线性输出层(无激活函数)
延伸思考
- 自定义损失函数 :
- 如何设计一个损失函数,使得模型在医疗诊断中更关注“假阴性”?
-
参考代码结构:
class CustomLoss(nn.Module): def __init__(self, penalty=2.0): super().__init__() self.penalty = penalty # 对漏诊的惩罚系数 def forward(self, inputs, targets): # 实现你的业务逻辑 ... -
优化器组合实验 :
- Adam 优化器 +CrossEntropy 在图像分类中的表现
-
对比 SGD+MSE 在时间序列预测中的效果
-
损失曲线分析 :
- 如果训练损失下降但验证损失上升,可能发生了什么?
- 如何通过损失曲线判断学习率是否合适?
总结
损失函数的选择不是机械性的,需要根据任务类型(分类 / 回归)、数据分布(是否平衡)、模型结构(深度 / 激活函数)综合判断。建议从简单实现开始,通过可视化监控训练过程,逐步调整到最佳组合。
