Pytorch Note56 Fine-tuning 通过微调进行迁移学习

Pytorch Note56 Fine-tuning 通过微调进行迁移学习

文章目录


全部笔记的汇总贴: Pytorch Note 快乐星球

通过微调进行迁移学习

前面我们介绍了如何训练卷积神经网络进行图像分类,可能你已经注意到了,训练一个卷积网络是特别耗费时间的,特别是一个比较深的卷积网络,而且可能因为训练方法不当导致训练不收敛的问题,就算训练好了网络,还有可能出现过拟合的问题,所以由此可见能够得到一个好的模型有多么困难。

有的时候,我们的数据集还特别少,这对于我们来讲无异于雪上加霜,因为少的数据集意味着非常高的风险过拟合,那么我们有没有办法在某种程度上避免这个问题呢?其实现在有一种方法特别流行,大家一直在使用,那就是微调(fine-tuning),在介绍微调之前,我们先介绍一个数据集 ImageNet。

ImageNet

ImageNet 是一个计算机视觉系统识别项目,是目前世界上最大的图像识别数据库,由斯坦福大学组织建立,大约有 1500 万张图片,2.2 万中类别,其中 ISLVRC 作为其子集是学术界中使用最为广泛的公开数据集,一共有 1281167 张图片作为训练集,50000 张图片作为验证集,一共是 1000 分类,是目前测试网络性能的标杆。

我们说的这个数据集有什么用呢?我们又不关心这个数据集,但是对于我们自己的问题,我们有没有办法借助 ImageNet 中的数据集来提升模型效果,比如我们要做一个猫狗分类器,但是我们现在只有几百张图片,肯定不够,ImageNet 中有很多关于猫狗的图片,我们如果能够把这些图片拿过来训练,不就能够提升模型性能了吗?

但是这种做法太麻烦了,从 ImageNet 中寻找这些图片就很困难,如果做另外一个问题又要去找新的图片,所以直接找图片并不靠谱,那么有没有办法能够让我们不去找这些图片,又能使用这些图片呢?

非常简单,我们可以使用在 ImageNet 上训练好的网路,然后把这个网络在放到我们自己的数据集上进行训练不就好了。这个方法就叫做微调,这十分形象,相当于把一个已经很厉害的模型再微调到我们自己的数据集上来,也可称为迁移学习。

迁移学习的方法非常简单,将预训练的模型导入,然后将最后的分类全连接层换成适合我们自己问题的全连接层,然后开始训练,可以固定卷积层的参数,也可以不固定进行训练,最后能够非常有效的得到结果

pytorch 一直为我们内置了前面我们讲过的那些著名网络的预训练模型,不需要我们自己去 ImageNet 上训练了,模型都在 torchvision.models 里面,比如我们想使用预训练的 50 层 resnet,就可以用 torchvision.models.resnet50(pretrained=True) 来得到

下面我们用一个例子来演示一些微调

import sys
sys.path.append('..')

import numpy as np

import torch
from torch import nn
from torch.autograd import Variable
from torch.utils.data import DataLoader

from torchvision import models
from torchvision import transforms as tfs
from torchvision.datasets import ImageFolder

首先我们点击下面的链接获得数据集,终端可以使用

wget https://download.pytorch.org/tutorial/hymenoptera_data.zip

下载完成之后,我们将其解压放在程序的目录下,这是一个二分类问题,区分蚂蚁和蜜蜂

我们可以可视化一下图片,看看你能不能区分出他们来

import os
from PIL import Image
import matplotlib.pyplot as plt
%matplotlib inline
root_path = './hymenoptera_data/train/'
im_list = [os.path.join(root_path, 'ants', i) for i in os.listdir(root_path + 'ants')[:4]]
im_list += [os.path.join(root_path, 'bees', i) for i in os.listdir(root_path + 'bees')[:5]]

nrows = 3
ncols = 3
figsize = (8, 8)
_, figs = plt.subplots(nrows, ncols, figsize=figsize)
for i in range(nrows):
    for j in range(ncols):
        figs[i][j].imshow(Image.open(im_list[nrows*i+j]))
        figs[i][j].axes.get_xaxis().set_visible(False)
        figs[i][j].axes.get_yaxis().set_visible(False)
plt.show()

Pytorch Note56 Fine-tuning 通过微调进行迁移学习

定义数据预处理

# 定义数据预处理
train_tf = tfs.Compose([
    tfs.RandomResizedCrop(224),
    tfs.RandomHorizontalFlip(),
    tfs.ToTensor(),
    tfs.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) # 使用 ImageNet 的均值和方差
])

valid_tf = tfs.Compose([
    tfs.Resize(256),
    tfs.CenterCrop(224),
    tfs.ToTensor(),
    tfs.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
])
# 使用 ImageFolder 定义数据集
train_set = ImageFolder('./hymenoptera_data/train/', train_tf)
valid_set = ImageFolder('./hymenoptera_data/val/', valid_tf)
# 使用 DataLoader 定义迭代器
train_data = DataLoader(train_set, 25, True, num_workers=4)
valid_data = DataLoader(valid_set, 32, False, num_workers=4)

使用预训练的模型

# 使用预训练的模型
net = models.resnet50(pretrained=True)
print(net)
ResNet(
  (conv1): Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)
  (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  (relu): ReLU(inplace=True)
  (maxpool): MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False)
  (layer1): Sequential(
    (0): Bottleneck(
      (conv1): Conv2d(64, 64, kernel_size=(1, 1), stride=(1, 1), bias=False)
      (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (conv3): Conv2d(64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)
      (bn3): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
      (downsample): Sequential(
        (0): Conv2d(64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)
        (1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      )
    )
    (1): Bottleneck(
      (conv1): Conv2d(256, 64, kernel_size=(1, 1), stride=(1, 1), bias=False)
      (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (conv3): Conv2d(64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)
      (bn3): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
    )
    (2): Bottleneck(
      (conv1): Conv2d(256, 64, kernel_size=(1, 1), stride=(1, 1), bias=False)
      (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (conv3): Conv2d(64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)
      (bn3): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
    )
  )
  (layer2): Sequential(
    (0): Bottleneck(
      (conv1): Conv2d(256, 128, kernel_size=(1, 1), stride=(1, 1), bias=False)
      (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (conv3): Conv2d(128, 512, kernel_size=(1, 1), stride=(1, 1), bias=False)
      (bn3): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
      (downsample): Sequential(
        (0): Conv2d(256, 512, kernel_size=(1, 1), stride=(2, 2), bias=False)
        (1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      )
    )
    (1): Bottleneck(
      (conv1): Conv2d(512, 128, kernel_size=(1, 1), stride=(1, 1), bias=False)
      (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (conv3): Conv2d(128, 512, kernel_size=(1, 1), stride=(1, 1), bias=False)
      (bn3): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
    )
    (2): Bottleneck(
      (conv1): Conv2d(512, 128, kernel_size=(1, 1), stride=(1, 1), bias=False)
      (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (conv3): Conv2d(128, 512, kernel_size=(1, 1), stride=(1, 1), bias=False)
      (bn3): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
    )
    (3): Bottleneck(
      (conv1): Conv2d(512, 128, kernel_size=(1, 1), stride=(1, 1), bias=False)
      (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (conv3): Conv2d(128, 512, kernel_size=(1, 1), stride=(1, 1), bias=False)
      (bn3): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
    )
  )
  (layer3): Sequential(
    (0): Bottleneck(
      (conv1): Conv2d(512, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)
      (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (conv3): Conv2d(256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False)
      (bn3): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
      (downsample): Sequential(
        (0): Conv2d(512, 1024, kernel_size=(1, 1), stride=(2, 2), bias=False)
        (1): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      )
    )
    (1): Bottleneck(
      (conv1): Conv2d(1024, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)
      (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (conv3): Conv2d(256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False)
      (bn3): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
    )
    (2): Bottleneck(
      (conv1): Conv2d(1024, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)
      (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (conv3): Conv2d(256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False)
      (bn3): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
    )
    (3): Bottleneck(
      (conv1): Conv2d(1024, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)
      (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (conv3): Conv2d(256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False)
      (bn3): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
    )
    (4): Bottleneck(
      (conv1): Conv2d(1024, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)
      (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (conv3): Conv2d(256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False)
      (bn3): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
    )
    (5): Bottleneck(
      (conv1): Conv2d(1024, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)
      (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (conv3): Conv2d(256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False)
      (bn3): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
    )
  )
  (layer4): Sequential(
    (0): Bottleneck(
      (conv1): Conv2d(1024, 512, kernel_size=(1, 1), stride=(1, 1), bias=False)
      (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (conv3): Conv2d(512, 2048, kernel_size=(1, 1), stride=(1, 1), bias=False)
      (bn3): BatchNorm2d(2048, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
      (downsample): Sequential(
        (0): Conv2d(1024, 2048, kernel_size=(1, 1), stride=(2, 2), bias=False)
        (1): BatchNorm2d(2048, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      )
    )
    (1): Bottleneck(
      (conv1): Conv2d(2048, 512, kernel_size=(1, 1), stride=(1, 1), bias=False)
      (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (conv3): Conv2d(512, 2048, kernel_size=(1, 1), stride=(1, 1), bias=False)
      (bn3): BatchNorm2d(2048, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
    )
    (2): Bottleneck(
      (conv1): Conv2d(2048, 512, kernel_size=(1, 1), stride=(1, 1), bias=False)
      (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (conv3): Conv2d(512, 2048, kernel_size=(1, 1), stride=(1, 1), bias=False)
      (bn3): BatchNorm2d(2048, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
    )
  )
  (avgpool): AdaptiveAvgPool2d(output_size=(1, 1))
  (fc): Linear(in_features=2048, out_features=1000, bias=True)
)
# 打出第一层的权重
print(net.conv1.weight)

将最后的全连接层改成二分类

# 将最后的全连接层改成二分类
net.fc = nn.Linear(2048, 2)
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(net.parameters(), lr=1e-2, weight_decay=1e-4)

训练模型

from utils import old_train
Acc, Loss, Lr = old_train(net, train_data, valid_data, 20, optimizer, criterion)
Epoch [  1/ 20]  Train Loss:0.590047  Train Acc:68.32% Test Loss:0.414566  Test Acc:79.43%  Learning Rate:0.010000	Time 00:20
Epoch [  2/ 20]  Train Loss:0.401846  Train Acc:81.60% Test Loss:0.198879  Test Acc:93.58%  Learning Rate:0.010000	Time 00:13
Epoch [  3/ 20]  Train Loss:0.234594  Train Acc:90.82% Test Loss:0.170969  Test Acc:94.83%  Learning Rate:0.010000	Time 00:14
Epoch [  4/ 20]  Train Loss:0.222330  Train Acc:90.80% Test Loss:0.167808  Test Acc:95.28%  Learning Rate:0.010000	Time 00:15
Epoch [  5/ 20]  Train Loss:0.156525  Train Acc:93.87% Test Loss:0.154961  Test Acc:95.28%  Learning Rate:0.010000	Time 00:15
Epoch [  6/ 20]  Train Loss:0.101500  Train Acc:97.07% Test Loss:0.151929  Test Acc:94.65%  Learning Rate:0.010000	Time 00:14
Epoch [  7/ 20]  Train Loss:0.125870  Train Acc:95.87% Test Loss:0.135658  Test Acc:95.45%  Learning Rate:0.010000	Time 00:14
Epoch [  8/ 20]  Train Loss:0.104806  Train Acc:97.20% Test Loss:0.128553  Test Acc:95.45%  Learning Rate:0.010000	Time 00:13
Epoch [  9/ 20]  Train Loss:0.134583  Train Acc:94.00% Test Loss:0.140324  Test Acc:94.83%  Learning Rate:0.010000	Time 00:14
Epoch [ 10/ 20]  Train Loss:0.102864  Train Acc:96.40% Test Loss:0.136546  Test Acc:94.83%  Learning Rate:0.010000	Time 00:16
Epoch [ 11/ 20]  Train Loss:0.069651  Train Acc:98.00% Test Loss:0.140122  Test Acc:94.65%  Learning Rate:0.010000	Time 00:17
Epoch [ 12/ 20]  Train Loss:0.091097  Train Acc:96.80% Test Loss:0.126392  Test Acc:96.08%  Learning Rate:0.010000	Time 00:15
Epoch [ 13/ 20]  Train Loss:0.099716  Train Acc:94.80% Test Loss:0.131765  Test Acc:94.65%  Learning Rate:0.010000	Time 00:16
Epoch [ 14/ 20]  Train Loss:0.084522  Train Acc:97.87% Test Loss:0.124556  Test Acc:95.45%  Learning Rate:0.010000	Time 00:15
Epoch [ 15/ 20]  Train Loss:0.077379  Train Acc:96.40% Test Loss:0.130561  Test Acc:96.08%  Learning Rate:0.010000	Time 00:14
Epoch [ 16/ 20]  Train Loss:0.066754  Train Acc:97.60% Test Loss:0.117638  Test Acc:95.45%  Learning Rate:0.010000	Time 00:15
Epoch [ 17/ 20]  Train Loss:0.093839  Train Acc:97.07% Test Loss:0.107425  Test Acc:94.83%  Learning Rate:0.010000	Time 00:16
Epoch [ 18/ 20]  Train Loss:0.044568  Train Acc:98.40% Test Loss:0.117701  Test Acc:95.45%  Learning Rate:0.010000	Time 00:16
Epoch [ 19/ 20]  Train Loss:0.040038  Train Acc:99.60% Test Loss:0.125794  Test Acc:95.45%  Learning Rate:0.010000	Time 00:14
Epoch [ 20/ 20]  Train Loss:0.046786  Train Acc:98.40% Test Loss:0.129580  Test Acc:95.45%  Learning Rate:0.010000	Time 00:14
from utils import plot_history
plot_history(20, Acc, Loss, Lr)

Pytorch Note56 Fine-tuning 通过微调进行迁移学习
Pytorch Note56 Fine-tuning 通过微调进行迁移学习
Pytorch Note56 Fine-tuning 通过微调进行迁移学习

预测

下面我们来可视化预测的结果

net = net.eval() # 将网络改为预测模式

读一张蚂蚁的图片

im1 = Image.open('./hymenoptera_data/train/ants/0013035.jpg')
im1

Pytorch Note56 Fine-tuning 通过微调进行迁移学习

im = valid_tf(im1) # 做数据预处理
out = net(Variable(im.unsqueeze(0)).cuda())
pred_label = out.max(1)[1].data[0]
print('predict label: {}'.format(train_set.classes[pred_label]))
predict label: ants

可以看到预测的结果是对的

小练习

小练习:看看上面的网络预测过程,多尝试几张图片进行预测

使用预训练的模型

# 保持前面的卷积层参数不变
net = models.resnet50(pretrained=True)
for param in net.parameters():
    param.requires_grad = False # 将模型的参数设置为不求梯度
net.fc = nn.Linear(2048, 2)

optimizer = torch.optim.SGD(net.fc.parameters(), lr=1e-2, weight_decay=1e-4)
Acc, Loss, Lr = old_train(net, train_data, valid_data, 20, optimizer, criterion)
Epoch [  1/ 20]  Train Loss:0.698645  Train Acc:58.46% Test Loss:0.337921  Test Acc:89.38%  Learning Rate:0.010000	Time 00:10
Epoch [  2/ 20]  Train Loss:0.405959  Train Acc:78.97% Test Loss:0.367483  Test Acc:81.25%  Learning Rate:0.010000	Time 00:11
Epoch [  3/ 20]  Train Loss:0.498462  Train Acc:75.60% Test Loss:0.242778  Test Acc:94.47%  Learning Rate:0.010000	Time 00:10
Epoch [  4/ 20]  Train Loss:0.260202  Train Acc:92.15% Test Loss:0.230207  Test Acc:90.45%  Learning Rate:0.010000	Time 00:10
Epoch [  5/ 20]  Train Loss:0.264511  Train Acc:92.27% Test Loss:0.339598  Test Acc:84.50%  Learning Rate:0.010000	Time 00:10
Epoch [  6/ 20]  Train Loss:0.235563  Train Acc:95.07% Test Loss:0.191060  Test Acc:94.83%  Learning Rate:0.010000	Time 00:10
Epoch [  7/ 20]  Train Loss:0.261545  Train Acc:87.35% Test Loss:0.198911  Test Acc:93.85%  Learning Rate:0.010000	Time 00:09
Epoch [  8/ 20]  Train Loss:0.305734  Train Acc:87.22% Test Loss:0.178782  Test Acc:95.45%  Learning Rate:0.010000	Time 00:09
Epoch [  9/ 20]  Train Loss:0.186689  Train Acc:92.40% Test Loss:0.187927  Test Acc:93.68%  Learning Rate:0.010000	Time 00:10
Epoch [ 10/ 20]  Train Loss:0.267986  Train Acc:87.62% Test Loss:0.193842  Test Acc:93.68%  Learning Rate:0.010000	Time 00:09
Epoch [ 11/ 20]  Train Loss:0.186078  Train Acc:94.40% Test Loss:0.176513  Test Acc:95.28%  Learning Rate:0.010000	Time 00:10
Epoch [ 12/ 20]  Train Loss:0.163462  Train Acc:95.35% Test Loss:0.190156  Test Acc:93.85%  Learning Rate:0.010000	Time 00:10
Epoch [ 13/ 20]  Train Loss:0.177957  Train Acc:93.87% Test Loss:0.189092  Test Acc:93.22%  Learning Rate:0.010000	Time 00:09
Epoch [ 14/ 20]  Train Loss:0.158989  Train Acc:95.35% Test Loss:0.183712  Test Acc:92.95%  Learning Rate:0.010000	Time 00:10
Epoch [ 15/ 20]  Train Loss:0.207236  Train Acc:92.00% Test Loss:0.178122  Test Acc:91.70%  Learning Rate:0.010000	Time 00:10
Epoch [ 16/ 20]  Train Loss:0.213432  Train Acc:91.35% Test Loss:0.174111  Test Acc:92.95%  Learning Rate:0.010000	Time 00:10
Epoch [ 17/ 20]  Train Loss:0.165621  Train Acc:93.47% Test Loss:0.223445  Test Acc:90.20%  Learning Rate:0.010000	Time 00:11
Epoch [ 18/ 20]  Train Loss:0.173697  Train Acc:95.60% Test Loss:0.189305  Test Acc:92.43%  Learning Rate:0.010000	Time 00:10
Epoch [ 19/ 20]  Train Loss:0.161865  Train Acc:94.82% Test Loss:0.195919  Test Acc:92.43%  Learning Rate:0.010000	Time 00:10
Epoch [ 20/ 20]  Train Loss:0.201205  Train Acc:90.80% Test Loss:0.147868  Test Acc:95.45%  Learning Rate:0.010000	Time 00:09

可以看到只训练验证集的准确率也可以达到比较高,但是 loss 跳动比较大,因为更新的参数太少了,只有全连接层的参数

不使用预训练的模型

# 不使用预训练的模型
net = models.resnet50()
net.fc = nn.Linear(2048, 2)

optimizer = torch.optim.SGD(net.parameters(), lr=1e-2, weight_decay=1e-4)
# 打出第一层的权重
print(net.conv1.weight)
Acc, Loss, Lr = old_train(net, train_data, valid_data, 20, optimizer, criterion)
Epoch [  1/ 20]  Train Loss:3.789299  Train Acc:48.63% Test Loss:3.342654  Test Acc:56.25%  Learning Rate:0.010000	Time 00:13
Epoch [  2/ 20]  Train Loss:2.933025  Train Acc:52.04% Test Loss:1.512564  Test Acc:51.95%  Learning Rate:0.010000	Time 00:14
Epoch [  3/ 20]  Train Loss:1.754535  Train Acc:56.44% Test Loss:1.211804  Test Acc:57.03%  Learning Rate:0.010000	Time 00:16
Epoch [  4/ 20]  Train Loss:1.517341  Train Acc:56.17% Test Loss:1.086264  Test Acc:58.10%  Learning Rate:0.010000	Time 00:17
Epoch [  5/ 20]  Train Loss:1.025034  Train Acc:58.21% Test Loss:2.929851  Test Acc:56.25%  Learning Rate:0.010000	Time 00:15
Epoch [  6/ 20]  Train Loss:1.249750  Train Acc:55.26% Test Loss:1.022647  Test Acc:56.25%  Learning Rate:0.010000	Time 00:14
Epoch [  7/ 20]  Train Loss:0.941940  Train Acc:60.99% Test Loss:1.043641  Test Acc:61.40%  Learning Rate:0.010000	Time 00:14
Epoch [  8/ 20]  Train Loss:0.674788  Train Acc:67.39% Test Loss:0.872586  Test Acc:66.65%  Learning Rate:0.010000	Time 00:15
Epoch [  9/ 20]  Train Loss:0.652783  Train Acc:67.09% Test Loss:1.197592  Test Acc:68.15%  Learning Rate:0.010000	Time 00:14
Epoch [ 10/ 20]  Train Loss:0.796914  Train Acc:57.71% Test Loss:1.370682  Test Acc:52.75%  Learning Rate:0.010000	Time 00:14
Epoch [ 11/ 20]  Train Loss:0.772965  Train Acc:67.14% Test Loss:3.495006  Test Acc:56.25%  Learning Rate:0.010000	Time 00:16
Epoch [ 12/ 20]  Train Loss:1.378554  Train Acc:54.74% Test Loss:2.399912  Test Acc:71.72%  Learning Rate:0.010000	Time 00:15
Epoch [ 13/ 20]  Train Loss:1.027114  Train Acc:65.24% Test Loss:1.286589  Test Acc:72.97%  Learning Rate:0.010000	Time 00:16
Epoch [ 14/ 20]  Train Loss:0.920177  Train Acc:64.69% Test Loss:1.315045  Test Acc:70.05%  Learning Rate:0.010000	Time 00:16
Epoch [ 15/ 20]  Train Loss:0.641859  Train Acc:70.06% Test Loss:0.649205  Test Acc:62.48%  Learning Rate:0.010000	Time 00:15
Epoch [ 16/ 20]  Train Loss:0.603328  Train Acc:68.84% Test Loss:0.824622  Test Acc:68.53%  Learning Rate:0.010000	Time 00:15
Epoch [ 17/ 20]  Train Loss:0.722805  Train Acc:61.54% Test Loss:1.698193  Test Acc:56.25%  Learning Rate:0.010000	Time 00:14
Epoch [ 18/ 20]  Train Loss:0.707589  Train Acc:66.84% Test Loss:0.767266  Test Acc:62.65%  Learning Rate:0.010000	Time 00:15
Epoch [ 19/ 20]  Train Loss:0.846025  Train Acc:63.52% Test Loss:0.677937  Test Acc:69.30%  Learning Rate:0.010000	Time 00:16
Epoch [ 20/ 20]  Train Loss:0.638594  Train Acc:71.12% Test Loss:0.693861  Test Acc:68.53%  Learning Rate:0.010000	Time 00:16

通过上面的结果可以看到,使用预训练的模型能够非常快的达到 95% 左右的验证集准确率,而不使用预训练模型只能到 70% 左右的验证集准确率,所以使用一个预训练的模型能够在较小的数据集上也取得一个非常好的效果,因为对于图片识别分类任务,最底层的卷积层识别的都是一些通用的特征,比如形状、纹理等等,所以对于很多图像分类、识别任务,都可以使用预训练的网络得到更好的结果。

上一篇:java – Cassandra CQL无法插入(在输入时没有可行的替代方案)


下一篇:spark学习指南