3.9 PyTorch网络模型的修改及使用
PyTorch 提供了多个预训练的网络模型,涵盖了广泛的计算机视觉任务,如图像分类、目标检测、语义分割等。这些预训练模型在 ImageNet 等大型数据集上进行了训练,并可以直接用于迁移学习或微调。
3.9.1 常见的现有Pytorch网络模型
- 分类模型
这些模型在图像分类任务中表现非常好,可以在 ImageNet 数据集上进行微调。
- ResNet 系列:
- ResNet18、ResNet34、ResNet50、ResNet101、ResNet110、ResNet152
- ResNet 引入了残差连接,解决了深度网络训练中的退化问题,广泛应用于各种视觉任务。
- VGG 系列:
- VGG11、VGG13、VGG16、VGG19
- VGG 模型有着简单而深度的结构,通常用于图像分类任务。
- DenseNet 系列:
- DenseNet121、DenseNet169、DenseNet201、DenseNet161
- DenseNet 使用密集连接,每一层与前面的所有层相连,能够更有效地利用特征。
- Inception 系列:
- Inception v3
- Inception 模型通过并行的卷积核不同尺寸的卷积来捕捉图像的多尺度特征。
- MobileNet 系列:
- MobileNetV2、MobileNetV3
- 适用于轻量级应用,能够在移动设备或嵌入式设备上进行高效推理。
- AlexNet:
- 经典的卷积神经网络,曾经在 ImageNet 上取得突破性进展,适用于图像分类。
- EfficientNet 系列:
- EfficientNet B0 到 B7
- 高效的神经网络架构,通过自动化搜索来优化网络的深度、宽度和分辨率。
- SqueezeNet:
- 一个轻量级的网络模型,通过减少模型的参数量来降低计算需求。
- 目标检测模型
PyTorch 提供了目标检测的预训练模型,适用于检测图像中的物体。
- Faster R-CNN:
- 一种基于区域卷积神经网络 (R-CNN) 的目标检测模型,广泛应用于检测任务。
- Mask R-CNN:
- 扩展了 Faster R-CNN,在目标检测的基础上加入了实例分割功能。
- RetinaNet:
- 采用焦点损失函数,改进了处理前景和背景样本的不均衡问题。
- YOLO(You Only Look Once):
- 通过一个网络直接输出目标的位置和类别,实现快速且准确的目标检测。
- 语义分割模型
语义分割任务是将图像中的每个像素分配一个标签。
- FCN (Fully Convolutional Network):
- 用于像素级的图像分割。
- U-Net:
- U-Net 架构常用于医学图像的语义分割,具有编码-解码的结构。
- DeepLabV3:
- 用于语义分割的深度学习模型,特别是在捕捉图像中的边缘和细节上表现出色。
- 图像生成模型
这些模型常用于图像生成、修复、增强等任务。
- Generative Adversarial Networks (GAN):
- 用于生成与训练数据分布相似的图像。PyTorch 提供了许多不同种类的 GAN 模型,例如 DCGAN、WGAN 等。
- Pix2Pix:
- 用于图像到图像的转换任务,如图像修复或风格迁移。
- CycleGAN:
- 用于无监督的图像到图像的转换,如将马的照片转换成斑马的照片等。
- Transformer 模型
随着 Transformer 在自然语言处理(NLP)中的成功,越来越多的 Transformer 网络架构也被应用于计算机视觉任务。
- Vision Transformer (ViT):
- 使用 Transformer 架构来处理图像,近年来在多个任务中表现出色。
- DeiT (Data-efficient Image Transformer):
- 通过优化训练过程使得 Vision Transformer 可以在较少数据下进行有效训练。
3.9.2 现有网络模型的修改与使用
为了方便讲解,我们选取分类模型Vgg16来进行讲解:
VGG16 是一种卷积神经网络(CNN)架构,由牛津大学视觉几何组(Visual Geometry Group,简称 VGG)提出。它在 2014 年的 ImageNet 图像分类挑战中表现非常出色,因此被广泛使用。VGG16 网络模型的名字中的 “16” 表示该网络包含 16 层权重(包括卷积层和全连接层)。
- 方法:
torchvision.models.vgg16(*, weights: Optional[VGG16_Weights] = None, progress: bool = True, **kwargs: Any)
- 参数:
1.weights (VGG16_Weights, optional):指定是否使用预训练的权重。可以选择使用 ImageNet 预训练的权重(VGG16_Weights.DEFAULT)或不使用(None)。
2.progress (bool, optional):控制是否显示下载进度条。默认为 True,表示显示进度条,False 表示不显示。
3.kwargs:传递给 VGG 基类的额外参数,常见的包括:
num_classes: 分类数目(默认为 1000)。
batch_norm: 是否使用批归一化(默认为 False)。
- 使用和修改步骤
1. 选择是否训练好的模型
# 加载预训练的 VGG16 模型
model = model.vgg16(weights=model.VGG16_Weights.DEFAULT)
# 加载没有预训练权重的 VGG16 模型(从头开始训练)
model_no_weights = model.vgg16(weights=None)
Vgg(
...
(classifier): Sequential(
(0): Linear(in_features=25088, out_features=4096, bias=True)
(1): ReLU(inplace=True)
(2): Dropout(p=0.5, inplace=False)
(3): Linear(in_features=4096, out_features=4096, bias=True)
(4): ReLU(inplace=True)
(5): Dropout(p=0.5, inplace=False)
(6): Linear(in_features=4096, out_features=1000, bias=True)
)
)
2. 选择要训练的数据集:CIFAR10
data = torchvision.datasets.CIFAR10('data-train', train=False, transform=torchvision.transforms.ToTensor(), download=True)
data_loader = DataLoader(data, batch_size=1)
3. 修改模型:对于要训练的CIFAR10只有10个特征,因此需要修改原有模型
方法一:使用 add_module 添加新的全连接层
model.classifier.add_module('add_Linear', nn.Linear(4096, 10))
"""add_module 允许你动态地向模型的某个部分(这里是 classifier)添加新层,通常是为了扩展或修改模型。
这种方式是将新层添加到模型结构的末尾。"""
方法二:直接修改模型的输出层
model.classifier[6] = nn.Linear(4096, 10)
在这里,model.classifier[6] 是指 VGG16 模型中的第七个层(注意,索引从0开始)。这个位置是VGG16模型的最后一个全连接层。我们直接将该层替换为一个新的全连接层,输出大小为 10,即CIFAR-10的类别数。
3.9.3 网络模型的保存与读取
在 PyTorch 中,保存模型的方式有两种:保存整个模型(包括结构和参数)和仅保存模型的参数(state_dict
)。以下是对你提供的两种方式的详细解释:
class Net(nn.Module):
def __init__(self) -> None:
super().__init__()
self.conv = nn.Conv2d(3, 16, 3)
def forward(self, input):
return self.conv(input)
net = Net()
1. 方式一:保存整个模型(结构和参数)
torch.save(net, 'model/save_model_method1.pth')
解释:
- 这种方式会保存整个模型(包括模型的架构、参数以及优化器状态等)。这意味着你可以直接加载这个文件,并恢复整个模型。
- 保存后,加载时不需要重新定义模型架构,PyTorch 会自动恢复整个模型。
- 但缺点是它依赖于特定的模型类定义,意味着如果你迁移到不同的环境或修改了模型的定义,可能会出现问题。
加载模型:
# 加载整个模型
model = torch.load('model/saveModel1.pth')
2. 方式二:仅保存模型的参数(state_dict
)
torch.save(net.state_dict(), 'model/save_model_method2.pth')
解释:
- 这种方式只保存模型的参数(即
state_dict
),不保存模型的架构。state_dict
包含了模型的所有可训练参数,如权重、偏置等。 - 保存
state_dict
后,加载时你需要先定义模型的结构,然后加载参数到模型中。
加载模型:
# 重新初始化模型
model = MyModel() # 确保你定义了模型的结构
# 加载保存的 state_dict
model.load_state_dict(torch.load('model/saveModel2.pth'))
- 方式一(保存整个模型):
- 适用于需要方便地保存和恢复整个模型的情况。
- 依赖于模型类的定义,跨环境迁移时可能会出现问题。
- 方式二(保存
state_dict
):- 推荐的做法,通常用于保存训练好的模型的参数。
- 需要在加载时手动定义模型结构。
- 更加灵活,能够避免依赖于模型定义的版本问题。