迁移学习的思路是利用预训练模型的卷积部分(卷积基)提取数据集的图片特征,然后重新练最后的全连接部分(分类器),迁移学习的特征提取部分(卷积基)不能发生变化。
迁移学习的思路有3步:
(1)冻结预训练模型的卷积基
(2)根据问题重新设置分类器,如需要分2类,则out_features=2
(3)用自己的数据训练设置好的分类器,注意:只优化分类器参数
torchvision提供了可以加载的预训练模型:
alexnet
convnex
densenet
efficientnet
feature_extraction
googlenet
inception
mnasnet
mobilenet
mobilenetv2
mobilenetv3
regnet
使用代码:
import torchvision
方法1:
model = torchvision.models.vgg16(pretrained=True) # pretrained=True表式仅仅加载网络结构,而不加载网络参数
# 方法2
model = models.vgg16(weights= models.VGG16_Weights.DEFAULT)
print(model)
输出如下:
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)
...
(5): Dropout(p=0.5, inplace=False)
(6): Linear(in_features=4096, out_features=1000, bias=True)
)
)
冻结卷积基的参数,避免模型参数被破坏,准确率下降
for param in model.features.parameters():
param.requires_grad = False
model.classifier[-1].out_features = 4 # 4分类
model = model.to(device) # 模型传入型芯片,一般GPU上
loss_fn = nn.CrossEntropyLoss() #根据具体问题自定义
optimizer = torch.optim.Adam(model.classifier.parameters(), lr=0.0001) #注意这里只优化分类器参数
....接训练代码