AlexNet损失函数优化实战:从交叉熵到自定义损失函数的性能对比

1次阅读
没有评论

共计 2343 个字符,预计需要花费 6 分钟才能阅读完成。

image.webp

1. 背景与问题分析

在图像分类任务中,AlexNet 作为经典的卷积神经网络,默认使用交叉熵损失函数(Cross-Entropy Loss)。然而,当我们将 AlexNet 应用到非 ImageNet 数据集时,可能会遇到以下问题:

AlexNet 损失函数优化实战:从交叉熵到自定义损失函数的性能对比

  • 类别不平衡 :交叉熵损失假设所有类别同等重要,但在实际数据中,某些类别可能样本极少,导致模型偏向多数类。
  • 噪声标签 :交叉熵对错误标签非常敏感,容易导致模型过拟合到噪声数据。
  • 边界模糊 :对于相似类别(如不同犬种),交叉熵可能无法学到足够的区分性特征。

2. 损失函数对比与选择

2.1 交叉熵损失(Cross-Entropy)

公式表示:
$$\mathcal{L}{CE} = -\sum^N y_i \log(p_i)$$

适用于:
– 标准多分类任务
– 类别分布均衡的数据集

2.2 Hinge Loss(多分类 SVM 损失)

公式表示:
$$\mathcal{L}{Hinge} = \sum + 1)$$} \max(0, s_j – s_{y_i

特点:
– 更关注决策边界
– 对噪声相对鲁棒

2.3 Focal Loss

公式表示:
$$\mathcal{L}_{Focal} = -(1-p_t)^\gamma \log(p_t)$$

优势:
– 通过 $\gamma$ 参数降低易分类样本的权重
– 特别适合类别不平衡场景

3. PyTorch 实现详解

3.1 基础设置

import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms

# 确保 GPU 可用
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

3.2 自定义 Focal Loss 实现

class FocalLoss(nn.Module):
    def __init__(self, gamma=2, reduction='mean'):
        super().__init__()
        self.gamma = gamma
        self.reduction = reduction

    def forward(self, inputs, targets):
        # 计算标准交叉熵
        ce_loss = F.cross_entropy(inputs, targets, reduction='none')

        # 计算概率 pt
        pt = torch.exp(-ce_loss)

        # 计算 focal loss
        focal_loss = (1 - pt)**self.gamma * ce_loss

        if self.reduction == 'mean':
            return focal_loss.mean()
        elif self.reduction == 'sum':
            return focal_loss.sum()
        return focal_loss

3.3 训练流程关键代码

# 数据加载
train_loader = torch.utils.data.DataLoader(
    datasets.CIFAR10('../data', train=True, download=True,
                   transform=transforms.Compose([transforms.RandomHorizontalFlip(),
                       transforms.ToTensor(),
                       transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
                   ])),
    batch_size=128, shuffle=True)

# 模型初始化
model = AlexNet().to(device)

# 选择损失函数
criterion = FocalLoss(gamma=2)  # 可替换为 nn.CrossEntropyLoss() 或自定义 HingeLoss

# 优化器
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)

# 训练循环
for epoch in range(50):
    model.train()
    for batch_idx, (data, target) in enumerate(train_loader):
        data, target = data.to(device), target.to(device)

        optimizer.zero_grad()
        output = model(data)
        loss = criterion(output, target)
        loss.backward()
        optimizer.step()

4. 实验对比与分析

我们在 CIFAR-10 数据集上进行了三组对比实验:

  1. 收敛速度
  2. Focal Loss 前期收敛较慢,但后期表现稳定
  3. Hinge Loss 需要更精细的学习率调整

  4. 测试准确率

  5. 标准交叉熵:89.2%
  6. Focal Loss(γ=2):90.1%
  7. Hinge Loss:88.7%

  8. 抗干扰性

  9. 对测试集加入 10% 噪声标签后:
    • 交叉熵准确率下降 12%
    • Focal Loss 仅下降 7%

5. 实践建议与避坑指南

  • 梯度裁剪 :自定义损失函数时建议添加
    torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
  • 学习率调整
  • Focal Loss 需要较小的初始学习率(如 0.01)
  • Hinge Loss 建议配合学习率衰减
  • 多 GPU 训练 :确保损失值在不同 GPU 间正确同步

6. 延伸思考方向

  1. 细粒度分类 :如何设计考虑类内差异的损失函数?可以尝试:
  2. 引入中心损失(Center Loss)
  3. 结合度量学习(Metric Learning)

  4. 模型压缩场景 :在剪枝 / 量化过程中:

  5. 是否需要调整损失函数?
  6. 如何保持剪枝后的模型判别能力?

通过本次实验,我们发现没有 ” 最好 ” 的损失函数,只有最适合特定场景的选择。建议读者根据实际任务需求进行针对性的设计和调优。

正文完
 0
评论(没有评论)