损失函数衡量模型预测与真实标签的差距,是训练优化的目标。选择正确的损失函数对模型性能至关重要。本课深入分析回归和分类中各种损失函数的数学性质与适用场景。
L_MSE = (1/N) Σᵢ(yᵢ - ŷᵢ)²
导数:∂L/∂ŷ = (2/N)(ŷ - y)
MSE对大误差惩罚更重(平方),因此对异常值敏感。
L_MAE = (1/N) Σᵢ|yᵢ - ŷᵢ|
导数:∂L/∂ŷ = sign(ŷ - y)
MAE对异常值更鲁棒,但在0点不可导,收敛可能较慢。
L_δ(r) = { 0.5r², if |r| ≤ δ ; δ(|r| - 0.5δ), if |r| > δ }
其中 r = y - ŷ,通常 δ = 1.0
Huber结合了MSE和MAE的优点:小误差用MSE(平滑),大误差用MAE(鲁棒)。
import torch
import torch.nn as nn
import torch.nn.functional as F
import math
# 常见损失函数演示
print("=== 回归损失函数 ===")
# 模拟数据
pred = torch.tensor([2.5, 0.0, 2.1, 7.8])
target = torch.tensor([3.0, -0.5, 2.0, 8.0])
mse = F.mse_loss(pred, target)
mae = F.l1_loss(pred, target)
huber = F.smooth_l1_loss(pred, target)
print(f"预测值: {pred.tolist()}")
print(f"真实值: {target.tolist()}")
print(f"MSE Loss: {mse.item():.6f}")
print(f"MAE Loss: {mae.item():.6f}")
print(f"Huber Loss: {huber.item():.6f}")
# MSE vs MAE 对异常值的敏感性
print("\n=== 异常值敏感性 ===")
pred_clean = torch.tensor([1.0, 2.0, 3.0, 4.0])
target_clean = torch.tensor([1.1, 2.2, 2.8, 4.5])
pred_outlier = torch.tensor([1.0, 2.0, 3.0, 100.0])
target_outlier = torch.tensor([1.1, 2.2, 2.8, 4.5])
print(f"无异常值: MSE={F.mse_loss(pred_clean, target_clean):.4f}, MAE={F.l1_loss(pred_clean, target_clean):.4f}")
print(f"有异常值: MSE={F.mse_loss(pred_outlier, target_outlier):.4f}, MAE={F.l1_loss(pred_outlier, target_outlier):.4f}")
print(f"MSE对异常值放大倍数: {F.mse_loss(pred_outlier, target_outlier)/F.mse_loss(pred_clean, target_clean):.1f}x")
print(f"MAE对异常值放大倍数: {F.l1_loss(pred_outlier, target_outlier)/F.l1_loss(pred_clean, target_clean):.1f}x")
二分类:L_BCE = -[y·log(ŷ) + (1-y)·log(1-ŷ)]
多分类:L_CE = -Σₖ yₖ·log(ŷₖ)
L_FL = -αₜ(1-pₜ)^γ · log(pₜ)
γ(聚焦参数)降低易分类样本的损失权重,让模型关注难样本。
import torch
import torch.nn as nn
import torch.nn.functional as F
import math
print("=== 分类损失函数 ===")
# 二分类
logits = torch.tensor([0.8, -0.5, 1.2, -2.0])
labels = torch.tensor([1.0, 0.0, 1.0, 0.0])
bce = F.binary_cross_entropy_with_logits(logits, labels)
print(f"二分类 BCE Loss: {bce.item():.6f}")
# 手动计算BCE
probs = torch.sigmoid(logits)
manual_bce = -(labels * torch.log(probs + 1e-8) + (1-labels) * torch.log(1-probs + 1e-8)).mean()
print(f"手动计算 BCE: {manual_bce.item():.6f}")
# 多分类
logits_multi = torch.tensor([[2.0, 1.0, 0.1], [0.5, 2.5, 0.3], [0.1, 0.2, 3.0]])
labels_multi = torch.tensor([0, 1, 2])
ce = F.cross_entropy(logits_multi, labels_multi)
print(f"\n多分类 Cross Entropy Loss: {ce.item():.6f}")
# 手动计算
probs_multi = F.softmax(logits_multi, dim=1)
print(f"Softmax概率: {probs_multi.tolist()}")
manual_ce = 0
for i in range(3):
manual_ce -= torch.log(probs_multi[i, labels_multi[i]] + 1e-8)
manual_ce /= 3
print(f"手动计算 CE: {manual_ce.item():.6f}")
# Focal Loss演示
print("\n=== Focal Loss vs CE Loss ===")
gamma = 2.0
for conf in [0.9, 0.7, 0.5, 0.3]:
ce_val = -math.log(conf) if conf > 0 else 20.0
fl_val = (1 - conf)**gamma * ce_val
print(f"正确类概率={conf:.1f}: CE={ce_val:.4f}, Focal={fl_val:.4f}, 压缩比={fl_val/ce_val:.4f}")
| 任务 | 推荐损失 | 说明 |
|---|---|---|
| 回归(无异常值) | MSE | 平滑梯度,收敛快 |
| 回归(有异常值) | Huber / MAE | 对异常值鲁棒 |
| 二分类 | BCE with Logits | 数值稳定 |
| 多分类 | Cross Entropy | 标准选择 |
| 类别不平衡 | Focal Loss | 关注难样本 |
| 标签平滑 | Label Smoothing CE | 防止过自信 |
标准标签: y = [0, 0, 1, 0, ...] (one-hot)
平滑标签: y' = (1-ε)·y + ε/K = [ε/K, ε/K, 1-ε+ε/K, ε/K, ...]
ε通常取0.1,K为类别数
防止模型过度自信,提高泛化能力
L = (1-y)·0.5·d² + y·0.5·max(0, m-d)²
y=0: 相似样本,拉近距离d
y=1: 不相似样本,推远到至少margin m
用于度量学习和自监督学习
D_KL(P||Q) = Σ P(x)·log(P(x)/Q(x))
衡量两个分布的差异(非对称!)
VAE中用作正则项:迫使学到的分布接近先验
💡 设计损失函数的核心原则:
💡 推荐资源:
用PyTorch实现Focal Loss,在不同γ值下对比训练效果。
实现Label Smoothing交叉熵,理解为什么它能提高模型泛化能力。
设计一个多任务损失函数,同时优化分类和回归目标。
实际实现中,数值稳定性至关重要:
❌ 不稳定: -log(p) → 当p→0时,log(0)=-∞
✅ 稳定: binary_cross_entropy_with_logits → 内部用log-sum-exp技巧
❌ 不稳定: softmax后接log → 两次近似
✅ 稳定: cross_entropy直接从logits计算 → LogSoftmax+NLLLoss
当同时优化多个损失时,如何平衡权重?
类别权重: w_c = N / (C × N_c),给少数类更大权重
Focal Loss: 降低易分类样本权重,关注难样本
过采样/欠采样: 直接调整数据分布
理解本课内容需要将其置于更大的知识网络中。每个核心概念都不是孤立的,它们相互关联、相互支撑:
建立正确的直觉比记住公式更重要:
1. 维度直觉:高维空间中,数据分布与低维直觉截然不同(维度诅咒)
2. 信息瓶颈:神经网络逐层压缩信息,保留任务相关的、丢弃无关的
3. 流形假设:高维数据实际分布在低维流形上,学习即发现流形结构
4. 偏差-方差权衡:简单模型欠拟合(高偏差),复杂模型过拟合(高方差)
本课作为神经网络基础阶段的核心内容,与前后课程紧密关联:
| 关联课程 | 关联点 | 协同效应 |
|---|---|---|
| 前序课程 | 提供了本课的基础知识 | 循序渐进的理解 |
| 后续课程 | 本课内容是后续的基础 | 逐步构建能力 |
| 平行课程 | 同一阶段的互补知识 | 多角度深入理解 |
| 实战项目 | 综合运用所有知识 | 理论与实践结合 |
💡 准备面试时,确保能回答以下问题:
掌握本课内容后,可以通过以下方式继续深入:
你已经掌握了如何为不同任务选择和设计损失函数。
损失函数定义了学习目标——目标对了,学习才有方向!