对VGG16进行迁移学习

1.什么是VGG16

        VGG16 是一个经典的卷积神经网络(CNN)架构,由牛津大学视觉几何组(Visual Geometry Group)在2014年提出。VGG16的名字来源于它的深度——16个权重层(13个卷积层和3个全连接层)。

        VGG16 结构:
        卷积层:VGG16由多个卷积层组成,卷积核大小固定为3x3,步幅为1,padding保持输入大小不变。每经过几个卷积层后,使用2x2的最大池化层(Max Pooling)来减小特征图的尺寸。
        全连接层:在卷积层之后,VGG16有3个全连接层,最后一个全连接层输出1000维的向量(用于ImageNet分类任务中的1000个类)。
        激活函数:每个卷积层和全连接层后都使用ReLU激活函数。
        总参数量:VGG16的参数量大约为138百万,尽管结构相对简单,但由于其深度和较大的网络尺寸,计算需求较高。
        VGG16在图像分类任务中表现非常好,是许多计算机视觉任务的基础架构。

2.对VGG16进行修改

        首先加载出VGG16原始结构:

import torch
import torchvision
from torchvision import datasets, transforms, models
from torch.utils.data import Dataset, DataLoader
from torch import nn

# datasets = torchvision.datasets.ImageNet("E:\\PyCharm_Project\\Pytorch_2.3.1\\ALL_Datasets\\ImageNet",split = 'train',download=True , transform = torchvision.transforms.ToTensor())

vgg16 = torchvision.models.vgg16(pretrained=True)
print(vgg16)

        获得以下模型结构:

VGG(
  (features): Sequential(
    (0): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (1): ReLU(inplace=True)
    (2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (3): ReLU(inplace=True)
    (4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (5): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (6): ReLU(inplace=True)
    (7): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (8): ReLU(inplace=True)
    (9): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (10): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (11): ReLU(inplace=True)
    (12): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (13): ReLU(inplace=True)
    (14): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (15): ReLU(inplace=True)
    (16): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (17): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (18): ReLU(inplace=True)
    (19): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (20): ReLU(inplace=True)
    (21): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (22): ReLU(inplace=True)
    (23): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (24): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (25): ReLU(inplace=True)
    (26): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (27): ReLU(inplace=True)
    (28): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (29): ReLU(inplace=True)
    (30): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  )
  (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)
  )
)

修改操作 1:改变输入通道数

# 修改第一层卷积层的输入通道数
vgg16.features[0] = nn.Conv2d(in_channels=4, out_channels=64, kernel_size=3, padding=1)

 得到

VGG(
  (features): Sequential(
    (0): Conv2d(4, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))  # 输入通道数从3改为4
    (1): ReLU(inplace=True)

修改操作 2:调整全连接层

        调整最后一个全连接层(classifier)的输出,使模型适应不同的分类任务。例如,从原来的1000类改为10类:

# 替换最后的全连接层
vgg16.classifier[6] = nn.Linear(in_features=4096, out_features=10)
(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=10, bias=True)  # 输出类别从1000改为10
  )

 修改操作 3:插入新的层

        在模型中插入新层,例如在全连接层之间加入一个 BatchNorm 层来稳定训练过程:

# 在全连接层的第二层之后插入一个 BatchNorm 层
new_classifier = list(vgg16.classifier)
new_classifier.insert(4, nn.BatchNorm1d(4096))

# 更新模型的全连接层
vgg16.classifier = nn.Sequential(*new_classifier)
(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): BatchNorm1d(4096, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)  # 插入的 BatchNorm 层
    (5): ReLU(inplace=True)
    (6): Dropout(p=0.5, inplace=False)
    (7): Linear(in_features=4096, out_features=10, bias=True)
  )

修改操作 4:使用自定义的激活函数 

 用 LeakyReLU 替换掉原来的 ReLU 激活函数,可以这样做:

# 替换所有的 ReLU 激活函数为 LeakyReLU
for i, layer in enumerate(vgg16.features):
    if isinstance(layer, nn.ReLU):
        vgg16.features[i] = nn.LeakyReLU(inplace=True)

for i, layer in enumerate(vgg16.classifier):
    if isinstance(layer, nn.ReLU):
        vgg16.classifier[i] = nn.LeakyReLU(inplace=True)

# 输出修改后的模型结构
print(vgg16)
VGG(
  ...
  (features): Sequential(
    (0): Conv2d(4, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (1): LeakyReLU(inplace=True)  # ReLU 改为 LeakyReLU
    ...
  )
  (classifier): Sequential(
    (0): Linear(in_features=25088, out_features=4096, bias=True)
    (1): LeakyReLU(inplace=True)  # ReLU 改为 LeakyReLU
    ...
  )
)

修改操作 5:增加或删除层 

可以直接增加或删除模型中的层。例如,删除最后一个卷积层:

# 删除最后一个卷积层
vgg16.features = nn.Sequential(*list(vgg16.features.children())[:-1])
    (25): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (26): ReLU(inplace=True)
    (27): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (28): ReLU(inplace=True)  # 最后一个卷积层已删除
    (29): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  )

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值