AlexNet损失函数详解:从理论到PyTorch实战

1次阅读
没有评论

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

image.webp

1. AlexNet 与损失函数的重要性

2012 年 ImageNet 竞赛中,AlexNet 以超越第二名 10.8% 的绝对优势夺冠,标志着深度学习在计算机视觉领域的突破。该网络成功的关键之一,是采用交叉熵损失函数替代传统的均方误差(MSE)。这种选择使得模型在 1000 类分类任务中,能更有效地处理类别间竞争关系和学习特征判别性。

AlexNet 损失函数详解:从理论到 PyTorch 实战

2. 交叉熵损失原理剖析

2.1 数学定义

给定真实标签 $y$ 和预测概率 $\hat{y}$,交叉熵损失定义为:
$$L = -\sum_{i=1}^C y_i \log(\hat{y}_i)$$
其中 $C$ 为类别数,$y_i$ 为 one-hot 编码的真实标签。

2.2 对比实验

通过 MNIST 数据集对比不同损失函数:

损失函数 测试准确率 训练收敛速度
MSE 97.2% 慢(需 50 轮)
交叉熵 98.6% 快(20 轮)

交叉熵的优势在于:
– 梯度与误差成正比,避免 MSE 的梯度消失问题
– 对错误预测惩罚更大,加速模型修正

3. PyTorch 完整实现

3.1 数据预处理

import torchvision.transforms as transforms

transform = transforms.Compose([transforms.Resize(256),
    transforms.CenterCrop(224),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406], 
                         std=[0.229, 0.224, 0.225])
])

3.2 模型定义

import torch.nn as nn

class AlexNet(nn.Module):
    def __init__(self, num_classes=1000):
        super().__init__()
        self.features = nn.Sequential(nn.Conv2d(3, 64, kernel_size=11, stride=4, padding=2),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=3, stride=2),
            # ... 其他层省略
        )
        self.classifier = nn.Sequential(nn.Dropout(),
            nn.Linear(256 * 6 * 6, 4096),
            nn.ReLU(),
            # ... 全连接层
        )

    def forward(self, x):
        x = self.features(x)
        x = torch.flatten(x, 1)
        x = self.classifier(x)
        return x

3.3 多 GPU 训练

model = AlexNet().cuda()
model = nn.DataParallel(model)  # 多卡并行

criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)

# 训练循环
for inputs, labels in train_loader:
    inputs, labels = inputs.cuda(), labels.cuda()
    outputs = model(inputs)
    loss = criterion(outputs, labels)  # 自动聚合各 GPU 计算结果
    loss.backward()
    optimizer.step()

4. 实战技巧

4.1 学习率调整

使用 torch.optim.lr_scheduler 监控损失曲线:

scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='min', factor=0.1, patience=5)

# 每个 epoch 后调用
scheduler.step(val_loss)

4.2 Focal Loss 实现

class FocalLoss(nn.Module):
    def __init__(self, alpha=0.25, gamma=2):
        super().__init__()
        self.alpha = alpha
        self.gamma = gamma

    def forward(self, inputs, targets):
        BCE_loss = F.cross_entropy(inputs, targets, reduction='none')
        pt = torch.exp(-BCE_loss)
        loss = self.alpha * (1-pt)**self.gamma * BCE_loss
        return loss.mean()

4.3 梯度裁剪

torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=5.0)

5. 延伸思考

  1. 当类别数量达到 10 万级时,如何优化交叉熵的计算效率?
  2. 在目标检测任务中,如何设计同时包含分类和定位的复合损失函数?
  3. 自监督学习中,对比损失(Contrastive Loss)与交叉熵有何本质区别?

通过本文的代码实践和理论分析,读者应该能够理解损失函数在深度学习中的核心作用。建议尝试在 CIFAR-10 等小规模数据集上修改损失函数,观察模型性能的变化规律。

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