迁移学习
迁移学习是一种机器学习的方法,指的是一个预训练的模型被重新用在另一个任务中,它专注于存储已有问题的解决模型,并将其利用在其他不同但相关问题上。例如我在A的场景下训练了一个模型,而B、C、D等场景与A类似,那么我们就可以把A的模型使用在这些类似场景上,A中的工作相当于做了预训练了。很多情况下迁移学习能够简化或降低模型构建的难度,节省训练时间、硬件消耗等,甚至还能取得不错的准确度。
Pytorch VGG16迁移学习实战
torchvision 包含流行的数据集、模型架构和用于计算机视觉的常见图像转换。因此我们调用VGG16这个图像领域的网络模型时,会用到torchvision来调用
首先需要调用torchvision中的models,通过models调用vgg16
from torchvision import models
model = models.vgg16(pretrained=True)
下图官方文档中对vgg16_bn的描述,pretrained=True即会返回一个预训练好的模型,VGG16在ImageNet上是224*224,之后只要将自己数据集中调整到符合vgg16要求即可了,同样也要注意vgg16的输出,因为它是基于ImageNet训练的,所以输出会是一个1000维的向量,之后就可以使用该模型做预测了,或者进行微调和二次训练。
函数vgg16_bn与函数vgg16的唯一区别在于vgg16_bn中添加了batch_normalization
网络结构调整
这里以二分类为例,我们需要将原先1000维的输出调整为2维。
为避免不必要的训练消耗,将参数的自动梯度设为false
for parma in model.parameters():
parma.requires_grad = False
首先我们先输出一下vgg16的网络结构
model._modules
<bound method Module.named_modules of 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) ) (avgpool): AdaptiveAvgPool2d(output_size=(7, 7)) (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) ) )>
可以看到最终的分类在classifier中,关键层是classifier[6],那我们就修改它
model.classifier[6] = nn.Linear(in_features=4096, out_features=2)
修改后梯度计算会恢复为默认的True,可以用同样的方法去冻结某个层参数的梯度计算以及修改模型中某一层的结构
参考
https://blog.csdn.net/weixin_43199584/article/details/105190965
|