
本教程详细介绍了在pytorch中对预训练vgg-19模型进行微调的两种核心策略:一是更新所有网络层的权重以适应新任务;二是冻结大部分层,仅微调分类器中的特定全连接层(fc1和fc2)。文章提供了清晰的代码示例,指导读者如何有效管理模型参数的梯度计算,并针对不同微调场景给出实践建议,旨在帮助开发者高效地将vgg-19应用于各类图像分类任务。
深度学习模型在大型数据集(如ImageNet)上进行预训练后,通常具有强大的特征提取能力。将这些预训练模型应用于特定任务,即所谓的“微调”(Fine-tuning),是一种常见且高效的策略。VGG-19作为经典的卷积神经网络之一,其预训练权重是进行图像分类任务的良好起点。本教程将深入探讨在PyTorch中如何灵活地对VGG-19模型进行微调,包括更新所有层权重和仅更新特定分类器层权重两种场景。
VGG-19模型结构概述
在进行微调之前,了解VGG-19的模型结构至关重要。一个典型的PyTorch torchvision.models 中的VGG-19模型包含三个主要部分:
- features: 卷积层和池化层组成的特征提取器。
- avgpool: 自适应平均池化层,将特征图尺寸统一。
- classifier: 全连接层组成的分类器。
我们主要关注classifier部分,其典型结构如下:
(classifier): Sequential(
(0): Linear(in_features=25088, out_features=4096, bias=True) # 通常被称为FC1
(1): ReLU(inplace=True)
(2): Dropout(p=0.5, inplace=False)
(3): Linear(in_features=4096, out_features=4096, bias=True) # 通常被称为FC2
(4): ReLU(inplace=True)
(5): Dropout(p=0.5, inplace=False)
(6): Linear(in_features=4096, out_features=1000, bias=True) # 原始输出层,对应ImageNet的1000个类别
)其中,classifier[0] 和 classifier[3] 分别对应VGG-19分类器中的第一个和第二个全连接层(FC1和FC2),而 classifier[6] 是最终的输出层。
策略一:微调所有网络层权重
当目标数据集与预训练数据集(如ImageNet)差异较大,或者任务要求模型学习更高级别的抽象特征时,可以考虑微调VGG-19模型的所有层权重。这意味着模型的所有参数都将在训练过程中进行更新。
实现步骤:
- 加载预训练VGG-19模型。
- 确保所有层的 requires_grad 属性都设置为 True。对于加载的预训练模型,默认情况下通常就是 True。
- 根据目标任务的类别数量,替换模型的最终分类层。
示例代码:
import torch.nn as nn
from torchvision import models
from torchvision.models import VGG19_Weights # PyTorch 0.13+ 推荐使用 weights 参数
# 1. 加载预训练VGG-19模型
# 使用 VGG19_Weights.IMAGENET1K_V1 加载在ImageNet上预训练的权重
vgg19_full_finetune_model = models.vgg19(weights=VGG19_Weights.IMAGENET1K_V1)
# 2. 确保所有层都参与梯度计算(默认即为True,但显式设置更清晰)
for param in vgg19_full_finetune_model.parameters():
param.requires_grad = True
# 3. 替换最终分类层以适应新的类别数量
# 假设你的数据集有 num_classes 个类别
num_classes = 10 # 示例:替换为你的实际类别数量
in_features = vgg19_full_finetune_model.classifier[6].in_features # 获取原输出层的输入特征数
vgg19_full_finetune_model.classifier[6] = nn.Linear(in_features, num_classes)
# 现在,vgg19_full_finetune_model 的所有层(包括新替换的最后一层)都将参与训练和权重更新。这种方法允许模型在整个网络层面上学习与新任务相关的特征,但需要更多计算资源和更长的训练时间,并可能更容易出现过拟合。
策略二:仅微调分类器中的特定全连接层 (FC1和FC2)
当目标数据集与预训练数据集相似,或者计算资源有限时,一种更高效的策略是冻结模型的特征提取部分,仅微调分类器中的特定层,例如FC1和FC2,并替换最终输出层。这种方法利用了预训练模型强大的特征提取能力,同时允许分类器适应新任务。
实现步骤:
- 加载预训练VGG-19模型。
- 首先冻结模型中所有层的权重(将 requires_grad 设置为 False)。
- 然后,解除对FC1 (classifier[0]) 和 FC2 (classifier[3]) 层的冻结,使其权重可以在训练中更新。
- 替换最终分类层 (classifier[6]) 以适应新的类别数量,新替换的层默认 requires_grad 为 True。
示例代码:
import torch.nn as nn
from torchvision import models
from torchvision.models import VGG19_Weights
# 1. 加载预训练VGG-19模型
vgg19_partial_finetune_model = models.vgg19(weights=VGG19_Weights.IMAGENET1K_V1)
# 2. 冻结所有层的权重
for param in vgg19_partial_finetune_model.parameters():
param.requires_grad = False
# 3. 解冻FC1 (classifier[0]) 和 FC2 (classifier[3]) 的权重
for param in vgg19_partial_finetune_model.classifier[0].parameters():
param.requires_grad = True
for param in vgg19_partial_finetune_model.classifier[3].parameters():
param.requires_grad = True
# 4. 替换最终分类层以适应新的类别数量
# 假设你的数据集有 num_classes 个类别
num_classes = 10 # 示例:替换为你的实际类别数量
in_features = vgg19_partial_finetune_model.classifier[6].in_features # 获取原输出层的输入特征数
vgg19_partial_finetune_model.classifier[6] = nn.Linear(in_features, num_classes)
# 新替换的 nn.Linear 层默认其参数 requires_grad=True,因此它将参与训练。
# 现在,只有 FC1、FC2 和新替换的最后一层将参与训练和权重更新。这种策略能够显著减少需要训练的参数数量,从而加快训练速度,降低过拟合风险,尤其适用于目标数据集较小的情况。
关键考虑与注意事项
- pretrained 参数的更新:从PyTorch 0.13版本开始,pretrained=True 参数已被弃用,推荐使用 weights 参数并指定具体的预训练权重枚举,例如 weights=VGG19_Weights.IMAGENET1K_V1。
-
替换最终分类层的重要性:
- 类别数量匹配:如果你的任务类别数量与ImageNet的1000个类别不同,则必须替换最终输出层以匹配你的任务。
- 任务特异性:即使你的任务恰好有1000个类别,但这些类别与ImageNet的类别很可能不同。替换并重新训练输出层有助于模型更好地学习区分你特定任务中的类别。
- 避免从头训练整个分类器:如果你选择完全替换 classifier 为一个新的 nn.Sequential 结构,那么新的 classifier 将不包含任何预训练权重,需要从头开始训练,这通常不如仅替换最后一层并利用前面FC层的预训练权重有效。
- 优化器配置:在微调过程中,可以为不同层设置不同的学习率。例如,冻结的层不需要优化器更新,而新添加的层或解冻的层可以采用较高的学习率,而预训练的解冻层可以采用较低的学习率。
- 数据预处理:微调时,应使用与预训练模型相同或相似的数据预处理方式(如图像尺寸、归一化参数)。
- 训练循环:无论采用哪种策略,都需要一个标准的PyTorch训练循环,包括定义损失函数、优化器,进行前向传播、计算损失、反向传播和参数更新。
总结
VGG-19模型微调提供了强大的灵活性,以适应各种图像分类任务。通过本教程,我们了解了两种主要的微调策略:
- 全网络微调:适用于目标任务与预训练任务差异较大,或需要模型学习更深层特征的情况。
- 部分层微调(仅FC1和FC2):适用于目标任务与预训练任务相似,或计算资源有限,旨在快速适应新任务同时保留预训练特征提取能力的情况。
在实践中,通常建议从部分层微调开始,如果模型性能不佳,再逐步尝试解冻更多的层进行微调。替换最终分类层是微调任务中几乎必不可少的一步,它确保模型能够正确地输出目标任务的类别预测。理解并熟练运用这些微调技术,将极大地提升你在PyTorch中处理图像分类问题的效率和效果。










