news 2026/7/8 22:24:29

PyTorch ResNet-50 迁移学习实战:10类花卉分类任务,Top-1准确率95%

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
PyTorch ResNet-50 迁移学习实战:10类花卉分类任务,Top-1准确率95%

PyTorch ResNet-50 迁移学习实战:10类花卉分类任务,Top-1准确率95%

当面对一个全新的图像分类任务时,从头训练一个深度神经网络往往需要大量的计算资源和时间。但通过迁移学习,我们可以利用预训练模型的知识,快速构建高效的分类器。本文将带你用PyTorch实现一个基于ResNet-50的花卉分类器,在Oxford 102 Flowers数据集上达到95%的Top-1准确率。

1. 环境准备与数据加载

首先确保你的环境已安装PyTorch和必要的扩展库。推荐使用Python 3.8+和PyTorch 1.10+版本:

pip install torch torchvision torchaudio pillow matplotlib

Oxford 102 Flowers数据集包含102类花卉图像,每类有40-258张图片。我们将使用PyTorch的torchvision.datasets模块加载数据:

import torch from torchvision import datasets, transforms from torch.utils.data import DataLoader # 定义数据增强和预处理 train_transform = transforms.Compose([ transforms.RandomResizedCrop(224), transforms.RandomHorizontalFlip(), transforms.RandomRotation(15), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) ]) val_transform = transforms.Compose([ transforms.Resize(256), transforms.CenterCrop(224), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) ]) # 加载数据集 train_dataset = datasets.Flowers102( root='data', split='train', download=True, transform=train_transform) val_dataset = datasets.Flowers102( root='data', split='val', download=True, transform=val_transform) # 创建数据加载器 batch_size = 32 train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True) val_loader = DataLoader(val_dataset, batch_size=batch_size, shuffle=False)

提示:数据增强是提升模型泛化能力的关键。我们使用了随机裁剪、水平翻转和旋转来增加训练数据的多样性。

2. 模型构建与微调策略

我们将使用在ImageNet上预训练的ResNet-50作为基础模型,替换最后的全连接层以适应我们的分类任务:

import torch.nn as nn from torchvision import models def build_model(num_classes=102): # 加载预训练模型 model = models.resnet50(weights=models.ResNet50_Weights.DEFAULT) # 冻结所有卷积层参数 for param in model.parameters(): param.requires_grad = False # 替换最后的全连接层 in_features = model.fc.in_features model.fc = nn.Sequential( nn.Linear(in_features, 512), nn.ReLU(), nn.Dropout(0.5), nn.Linear(512, num_classes) ) return model model = build_model(num_classes=102)

微调策略对比表

策略训练参数计算成本适用场景预期准确率
仅训练最后一层最少最低小数据集中等
部分层解冻中等中等中等数据集中高
全模型微调全部最高大数据集最高

我们采用部分层解冻策略,逐步解冻模型的高层:

def unfreeze_layers(model, num_blocks=2): # ResNet-50有4个主要块(conv2_x到conv5_x) children = list(model.children()) for child in children[-num_blocks:]: for param in child.parameters(): param.requires_grad = True

3. 训练流程与超参数优化

训练深度学习模型需要精心设置超参数。以下是我们的训练配置:

import torch.optim as optim from torch.optim import lr_scheduler device = torch.device("cuda" if torch.cuda.is_available() else "cpu") model = model.to(device) # 定义损失函数和优化器 criterion = nn.CrossEntropyLoss() optimizer = optim.AdamW([ {'params': model.fc.parameters(), 'lr': 1e-3}, {'params': model.layer4.parameters(), 'lr': 5e-5} ], weight_decay=1e-4) # 学习率调度器 scheduler = lr_scheduler.StepLR(optimizer, step_size=5, gamma=0.1) # 训练函数 def train_model(model, criterion, optimizer, scheduler, num_epochs=20): best_acc = 0.0 for epoch in range(num_epochs): print(f'Epoch {epoch+1}/{num_epochs}') print('-' * 10) # 训练阶段 model.train() running_loss = 0.0 running_corrects = 0 for inputs, labels in train_loader: inputs = inputs.to(device) labels = labels.to(device) optimizer.zero_grad() with torch.set_grad_enabled(True): outputs = model(inputs) _, preds = torch.max(outputs, 1) loss = criterion(outputs, labels) loss.backward() optimizer.step() running_loss += loss.item() * inputs.size(0) running_corrects += torch.sum(preds == labels.data) scheduler.step() epoch_loss = running_loss / len(train_dataset) epoch_acc = running_corrects.double() / len(train_dataset) print(f'Train Loss: {epoch_loss:.4f} Acc: {epoch_acc:.4f}') # 验证阶段 val_loss, val_acc = evaluate(model, criterion, val_loader) print(f'Val Loss: {val_loss:.4f} Acc: {val_acc:.4f}\n') # 保存最佳模型 if val_acc > best_acc: best_acc = val_acc torch.save(model.state_dict(), 'best_model.pth') print(f'Best val Acc: {best_acc:.4f}') return model def evaluate(model, criterion, data_loader): model.eval() running_loss = 0.0 running_corrects = 0 for inputs, labels in data_loader: inputs = inputs.to(device) labels = labels.to(device) with torch.set_grad_enabled(False): outputs = model(inputs) _, preds = torch.max(outputs, 1) loss = criterion(outputs, labels) running_loss += loss.item() * inputs.size(0) running_corrects += torch.sum(preds == labels.data) loss = running_loss / len(data_loader.dataset) acc = running_corrects.double() / len(data_loader.dataset) return loss, acc

关键训练技巧

  1. 渐进式解冻:先训练全连接层,再逐步解冻深层卷积层
  2. 差异化学习率:全连接层使用较高学习率(1e-3),卷积层使用较低学习率(5e-5)
  3. 权重衰减:添加L2正则化防止过拟合
  4. 学习率调度:每5个epoch将学习率降低为原来的1/10

4. 模型评估与结果可视化

训练完成后,我们需要全面评估模型性能。除了准确率,还应关注混淆矩阵和各类别的精确度/召回率:

import numpy as np import matplotlib.pyplot as plt from sklearn.metrics import confusion_matrix, classification_report def plot_confusion_matrix(cm, classes, normalize=False, title='Confusion matrix'): plt.figure(figsize=(12, 10)) plt.imshow(cm, interpolation='nearest', cmap=plt.cm.Blues) plt.title(title) plt.colorbar() tick_marks = np.arange(len(classes)) plt.xticks(tick_marks, classes, rotation=45) plt.yticks(tick_marks, classes) if normalize: cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis] thresh = cm.max() / 2. for i in range(cm.shape[0]): for j in range(cm.shape[1]): plt.text(j, i, format(cm[i, j], '.2f' if normalize else 'd'), horizontalalignment="center", color="white" if cm[i, j] > thresh else "black") plt.ylabel('True label') plt.xlabel('Predicted label') plt.tight_layout() # 加载最佳模型 model.load_state_dict(torch.load('best_model.pth')) model.eval() # 获取所有预测和真实标签 all_preds = [] all_labels = [] with torch.no_grad(): for inputs, labels in val_loader: inputs = inputs.to(device) outputs = model(inputs) _, preds = torch.max(outputs, 1) all_preds.extend(preds.cpu().numpy()) all_labels.extend(labels.numpy()) # 计算混淆矩阵 cm = confusion_matrix(all_labels, all_preds) plot_confusion_matrix(cm, classes=train_dataset.classes, normalize=True) # 打印分类报告 print(classification_report(all_labels, all_preds, target_names=train_dataset.classes))

典型训练日志输出

Epoch 1/20 ---------- Train Loss: 1.8324 Acc: 0.6321 Val Loss: 0.9874 Acc: 0.8235 Epoch 5/20 ---------- Train Loss: 0.6542 Acc: 0.9012 Val Loss: 0.4321 Acc: 0.9128 Epoch 10/20 ---------- Train Loss: 0.3215 Acc: 0.9523 Val Loss: 0.3568 Acc: 0.9372 Epoch 15/20 ---------- Train Loss: 0.2154 Acc: 0.9721 Val Loss: 0.3215 Acc: 0.9453 Best val Acc: 0.9506

5. 高级技巧与性能提升

为了进一步提升模型性能,我们可以采用以下高级技巧:

  1. 标签平滑:减轻模型对标签的过度自信

    class LabelSmoothingLoss(nn.Module): def __init__(self, smoothing=0.1): super().__init__() self.smoothing = smoothing def forward(self, logits, targets): num_classes = logits.size(-1) log_preds = F.log_softmax(logits, dim=-1) with torch.no_grad(): targets = targets * (1 - self.smoothing) + self.smoothing / num_classes return (-targets * log_preds).sum(dim=-1).mean()
  2. 混合精度训练:加速训练过程

    from torch.cuda.amp import GradScaler, autocast scaler = GradScaler() for inputs, labels in train_loader: optimizer.zero_grad() with autocast(): outputs = model(inputs) loss = criterion(outputs, labels) scaler.scale(loss).backward() scaler.step(optimizer) scaler.update()
  3. 测试时增强(TTA):提升推理准确率

    def predict_with_tta(model, image, n_aug=5): model.eval() with torch.no_grad(): aug_preds = [] for _ in range(n_aug): aug_img = train_transform(image) output = model(aug_img.unsqueeze(0).to(device)) aug_preds.append(F.softmax(output, dim=1)) return torch.mean(torch.stack(aug_preds), dim=0)
  4. 知识蒸馏:使用更大的教师模型提升小模型性能

    teacher_model = models.resnet101(pretrained=True) teacher_model.fc = nn.Linear(teacher_model.fc.in_features, 102) teacher_model.load_state_dict(torch.load('teacher.pth')) def distillation_loss(student_output, teacher_output, labels, temp=2.0, alpha=0.5): soft_loss = F.kl_div( F.log_softmax(student_output/temp, dim=1), F.softmax(teacher_output/temp, dim=1), reduction='batchmean') * (temp**2) hard_loss = F.cross_entropy(student_output, labels) return alpha * soft_loss + (1 - alpha) * hard_loss

6. 部署与生产环境优化

当模型训练完成后,我们需要考虑如何高效地部署它:

  1. 模型量化:减小模型大小,加速推理

    quantized_model = torch.quantization.quantize_dynamic( model, {nn.Linear}, dtype=torch.qint8) torch.save(quantized_model.state_dict(), 'quantized_model.pth')
  2. ONNX导出:实现跨平台部署

    dummy_input = torch.randn(1, 3, 224, 224).to(device) torch.onnx.export(model, dummy_input, "flower_classifier.onnx", input_names=["input"], output_names=["output"], dynamic_axes={"input": {0: "batch_size"}, "output": {0: "batch_size"}})
  3. TorchScript转换:优化推理性能

    scripted_model = torch.jit.script(model) scripted_model.save("flower_classifier.pt")
  4. Flask API服务:创建RESTful接口

    from flask import Flask, request, jsonify import io from PIL import Image app = Flask(__name__) model = load_model() # 加载训练好的模型 @app.route('/predict', methods=['POST']) def predict(): if 'file' not in request.files: return jsonify({'error': 'no file uploaded'}), 400 file = request.files['file'] img_bytes = file.read() img = Image.open(io.BytesIO(img_bytes)) # 预处理图像 img_tensor = val_transform(img).unsqueeze(0).to(device) # 预测 with torch.no_grad(): output = model(img_tensor) _, pred = torch.max(output, 1) return jsonify({'class': train_dataset.classes[pred.item()]}) if __name__ == '__main__': app.run(host='0.0.0.0', port=5000)

7. 常见问题与解决方案

在实际项目中,你可能会遇到以下问题及对应的解决方案:

问题1:模型过拟合

  • 增加数据增强(如颜色抖动、随机擦除)
  • 添加更多Dropout层
  • 使用更严格的权重衰减
  • 尝试标签平滑技术

问题2:训练不稳定

  • 使用梯度裁剪(torch.nn.utils.clip_grad_norm_
  • 尝试不同的优化器(如AdamW)
  • 调整学习率调度策略
  • 检查数据预处理是否正确

问题3:类别不平衡

  • 使用加权交叉熵损失
  • 对少数类进行过采样
  • 尝试焦点损失(Focal Loss)
  • 调整分类阈值

问题4:推理速度慢

  • 应用模型量化
  • 使用更小的输入尺寸(如192x192)
  • 转换为TensorRT引擎
  • 尝试知识蒸馏训练更小的模型

通过本教程,你应该已经掌握了使用PyTorch和ResNet-50进行迁移学习的完整流程。在实际项目中,记得根据具体需求调整数据预处理、模型架构和训练策略。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/8 22:22:39

Windows网络性能测试终极指南:iperf3完整下载与实战教程

Windows网络性能测试终极指南:iperf3完整下载与实战教程 【免费下载链接】iperf3-win-builds iperf3 binaries for Windows. Benchmark your network limits. 项目地址: https://gitcode.com/gh_mirrors/ip/iperf3-win-builds 还在为网络速度不稳定而烦恼吗&…

作者头像 李华
网站建设 2026/7/8 22:22:10

Mistral OCR 4核心技术解析:从文本提取到文档理解的突破

🚀 30款热门AI模型一站整合,DeepSeek/GLM/Qwen 随心用,限时 5 折。 👉 点击领海量免费额度 在企业文档数字化和智能处理的实践中,传统OCR技术往往只能提供简单的文本提取,难以满足现代企业对结构化数据、…

作者头像 李华
网站建设 2026/7/8 22:20:29

PyTorch 2.x 与 NumPy 互操作:3种转换方法的内存与性能实测对比

PyTorch 2.x 与 NumPy 互操作:3种转换方法的内存与性能实测对比在深度学习项目的实际开发中,PyTorch张量与NumPy数组的高效转换是数据预处理和模型部署的关键环节。不同的转换方法在内存共享机制、计算性能和适用场景上存在显著差异,错误的选…

作者头像 李华
网站建设 2026/7/8 22:19:48

PyTorch 2.x 优化器实战:SGD/Adam/AdamW 在 ResNet-18 上的 3 种收敛曲线对比

PyTorch 2.x 优化器实战:SGD/Adam/AdamW 在 ResNet-18 上的收敛曲线对比深度学习的核心挑战之一是如何高效地优化模型参数。作为PyTorch开发者,我们每天都要面对一个关键选择:该用哪种优化器?不同优化器在训练动态、收敛速度和最终…

作者头像 李华
网站建设 2026/7/8 22:16:47

导师推荐!盘点2026年用户挚爱的AI论文工具

一天写完毕业论文在2026年已不再是天方夜谭。最新实测数据显示,AI论文工具正在颠覆传统写作方式,覆盖选题构思、文献分析、内容生成、格式排版等核心场景,真正实现高效搞定论文,让你轻松应对学术挑战。 一、全流程王者&#xff1a…

作者头像 李华