PyTorch
所谓迁移学习,就是能让现有的模型算法稍加调整即可应用于一个新的领域和功能的一项技术。

1、加载训练好的模型

  1. import torchvision
  2. # Gives easier dataset managment and creates mini batches
  3. from torch.utils.data import DataLoader
  4. # Has standard datasets we can import in a nice way
  5. import torchvision.datasets as datasets
  6. # Transformations we can perform on our dataset
  7. import torchvision.transforms as transforms
  8. # Load pretrain model & modify it
  9. model = torchvision.models.vgg16(pretrained=True)
  10. print(model)

Pytorch Transfer Learning - 图1

2、特征层处理

  1. train_dataset = datasets.CIFAR10(
  2. root="dataset/", train=True, transform=transforms.ToTensor(), download=True
  3. )
  4. train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True)
  5. model2 = model.features
  6. model2.eval()
  7. train = next(iter(train_loader))
  8. print(len(train))
  9. x = train[0].to(device)
  10. y = train[1].to(device)
  11. y_pred = model2(x)
  12. print(y_pred.shape)
  13. # torch.Size([64, 512, 1, 1])

结果是在所有的conv层之后,avgpool层的输入是1x1(即512x1x1) (avgpool工作的维度,即1x1),所以这里不需要执行avgpool(理论上可以应用大小为1x1的avgpool,而不是使用自定义Identity层,结果是一样的)。
顺便说一下,avgpool的参数是“output_size”,而不是“kernel_size”。这意味着它保证最终输出是请求的大小。在这种情况下,1x1将被复制为7x7,这没有任何好处。

  1. class Identity(nn.Module):
  2. def __init__(self):
  3. super(Identity, self).__init__()
  4. def forward(self, x):
  5. return x

因此可以训练以下模型:

  1. # Load pretrain model & modify it
  2. model = torchvision.models.vgg16(pretrained=True)
  3. model.avgpool = Identity()
  4. model.classifier = nn.Linear(512,10)
  5. # 如果只想改变classifier中的某一层,
  6. # 可用model.classifier[i]=nn.Linear() 或者nn.Relu(),
  7. # i是某层所在的索引,本模型中classifier有7层

结果如下:
Pytorch Transfer Learning - 图2

3、训练部分模型

  1. # 如果不想训练整个模型,可将模型的参数的梯度设置为False。
  2. for param in model.parameters():
  3. param.requires_grad = False
  4. # 同时对需要训练的部分重新设置网络。
  5. model.avgpool = Identity()
  6. model.classifier = nn.Sequential(
  7. nn.Linear(512, 100), nn.ReLU(), nn.Linear(100, num_classes)
  8. )