基于PyTorch的深度学习——迁移学习4

微调 = 在预训练模型的基础上,继续训练(更新)部分或全部原有参数 + 新加的层,以适应新任务。此外预先训练的网络参数也会被更新,但会使用较小的学习率以防止预先训练好的参数发生较大的改变。

python 复制代码
# 使用预训练模型
net = models.resnet18(pretrained=True)
print(net)

ResNet(
  (conv1): Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)
  (bn1): BatchNorm2d(64, ...)
  (relu): ReLU(inplace=True)
  (maxpool): MaxPool2d(kernel_size=3, stride=2, padding=1, ...)
  (layer1): Sequential(...)   # 2 个 BasicBlock
  (layer2): Sequential(...)   # 2 个 BasicBlock
  (layer3): Sequential(...)   # 2 个 BasicBlock
  (layer4): Sequential(...)   # 2 个 BasicBlock
  (avgpool): AdaptiveAvgPool2d(output_size=(1, 1))
  (fc): Linear(in_features=512, out_features=1000, bias=True)
)

net.fc = torch.nn.Linear(512, 10)  # 改为 10 类

常用的方法是固定底层的参数,调整一些顶层或具体层的参数。这样做的好处是可以减少训练参数的数量,同时也有助于克服过拟合现象的发生。

python 复制代码
import torch
import torch.nn as nn
import torchvision
import torchvision.transforms as transforms
import torchvision.models as models

# ==============================
# 1. 加载预训练模型(推荐新写法)
# ==============================
net = models.resnet18(weights=models.ResNet18_Weights.DEFAULT)

# ==============================
# 2. 修改最后的分类层(CIFAR-10 有 10 类)
# ==============================
num_classes = 10
net.fc = nn.Linear(net.fc.in_features, num_classes)  # 原来是 512 → 1000,现在改为 512 → 10

# ==============================
# 3. 【可选但推荐】冻结底层,只微调高层(减少过拟合,加快训练)
# ==============================
# 冻结前几层(通用特征提取器)
for param in net.conv1.parameters():
    param.requires_grad = False
for param in net.bn1.parameters():
    param.requires_grad = False
for param in net.layer1.parameters():
    param.requires_grad = False
for param in net.layer2.parameters():
    param.requires_grad = False

# layer3、layer4 和 fc 默认保持 requires_grad=True(可训练)

# ==============================
# 4. 定义数据变换(适配 ResNet 输入 224x224)
# ==============================
transform_train = transforms.Compose([
    transforms.Resize(256),
    transforms.RandomCrop(224),
    transforms.RandomHorizontalFlip(),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])

transform_test = 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])
])

# ==============================
# 5. 加载 CIFAR-10 数据集
# ==============================
trainset = torchvision.datasets.CIFAR10(root='./data', train=True,
                                        download=True, transform=transform_train)
testset = torchvision.datasets.CIFAR10(root='./data', train=False,
                                       download=True, transform=transform_test)

trainloader = torch.utils.data.DataLoader(trainset, batch_size=32, shuffle=True, num_workers=2)
testloader = torch.utils.data.DataLoader(testset, batch_size=32, shuffle=False, num_workers=2)

# ==============================
# 6. 定义损失函数和优化器(分层学习率)
# ==============================
criterion = nn.CrossEntropyLoss()

# 对不同层使用不同的学习率:新层用大 lr,预训练层用小 lr
optimizer = torch.optim.SGD([
    {'params': net.fc.parameters(),       'lr': 1e-3},   # 新分类头,学习率大些
    {'params': net.layer4.parameters(),   'lr': 1e-4},   # 高层微调
    {'params': net.layer3.parameters(),   'lr': 1e-5},   # 中层微调(更小心)
], momentum=0.9, weight_decay=1e-4)

# ==============================
# 7. 训练循环(简化版)
# ==============================
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
net.to(device)

num_epochs = 10
for epoch in range(num_epochs):
    net.train()
    running_loss = 0.0
    correct = 0
    total = 0

    for inputs, labels in trainloader:
        inputs, labels = inputs.to(device), labels.to(device)

        optimizer.zero_grad()
        outputs = net(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()

        running_loss += loss.item()
        _, predicted = outputs.max(1)
        total += labels.size(0)
        correct += predicted.eq(labels).sum().item()

    train_acc = 100. * correct / total
    print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {running_loss/len(trainloader):.4f}, Train Acc: {train_acc:.2f}%')

    # 验证阶段
    net.eval()
    correct_test = 0
    total_test = 0
    with torch.no_grad():
        for inputs, labels in testloader:
            inputs, labels = inputs.to(device), labels.to(device)
            outputs = net(inputs)
            _, predicted = outputs.max(1)
            total_test += labels.size(0)
            correct_test += predicted.eq(labels).sum().item()
    
    test_acc = 100. * correct_test / total_test
    print(f'>>> Test Accuracy: {test_acc:.2f}%')

print('Finished Fine-tuning!')
相关推荐
乾元9 小时前
身份与访问:行为生物识别(按键习惯、移动轨迹)的 AI 建模
运维·网络·人工智能·深度学习·安全·自动化·安全架构
love you joyfully9 小时前
告别“人多力量大”误区:看AI团队如何通过奖励设计实现协作韧性
人工智能·深度学习·神经网络·多智能体
happyprince9 小时前
2026年02月08日热门论文
人工智能·深度学习·计算机视觉
芷栀夏9 小时前
CANN ops-math:面向 AI 计算的基础数学算子开发与高性能调用实战指南
人工智能·深度学习·神经网络·cann
心疼你的一切17 小时前
昇腾CANN实战落地:从智慧城市到AIGC,解锁五大行业AI应用的算力密码
数据仓库·人工智能·深度学习·aigc·智慧城市·cann
chian-ocean18 小时前
量化加速实战:基于 `ops-transformer` 的 INT8 Transformer 推理
人工智能·深度学习·transformer
水月wwww18 小时前
【深度学习】卷积神经网络
人工智能·深度学习·cnn·卷积神经网络
杜子不疼.18 小时前
CANN_Transformer加速库ascend-transformer-boost的大模型推理性能优化实践
深度学习·性能优化·transformer
前端摸鱼匠19 小时前
YOLOv8 环境配置全攻略:Python、PyTorch 与 CUDA 的和谐共生
人工智能·pytorch·python·yolo·目标检测
renhongxia119 小时前
如何基于知识图谱进行故障原因、事故原因推理,需要用到哪些算法
人工智能·深度学习·算法·机器学习·自然语言处理·transformer·知识图谱