模型微调技术

一、迁移学习中的常见技巧:微调(fine-tuning)

1.1 概念

  1. 将在大数据集上训练得到的weights作为特定任务(小数据集)的初始化权重,重新训练该网络(根据需要,修改全连接层输出);至于训练的方式可以是:
    1.微调所有层;
    2.固定网络前面几层权重,只微调网络的后面几层,这样做有两个原因:A. 避免因数据量小造成过拟合现象;B.CNN前几层的特征中包含更多的一般特征(比如,边缘信息,色彩信息等),这对许多任务来说是非常通用的,但是CNN后面几层的特征学习注重高层特征,也就是语义特征,这是针对于数据集而言的,不同的数据集后面几层学习的语义特征也是完全不同的;

1.2 步骤

  1. 在源数据集上训练神经网络模型或将已经在大数据集上训练好的模型保存的模型,即源模型;
  2. 创建新的神经网络模型,即目标模型。这将复制源模型上的所有模型设计(即模型层数设计)及其参数(输出层除外)。假定模型参数包含从源数据集中学到的知识,这些知识也将适用于目标数据集;
  3. 想目标模型中添加输出层,其输出类别数目是目标数据集中的类别数, 然后随机初始化该层的模型参数;
  4. 在目标数据集上训练目标模型,输出层从头开始训练,其他所有层的参数将根据源模型的参数进行微调。

在这里插入图片描述

1.3 训练

  • 源数据集远复杂于目标数据,通常微调效果更好;
  • 通常使用更小的学习率和更少的数据迭代;

1.4 实现

#热狗识别
#导入所需包
from d2l import torch as d2l
from torch import nn
import torchvision
import torch
import os
%matplotlib inline
#获取数据集
"""
我们使用的热狗数据集来源于网络。 
该数据集包含1400张热狗的“正类”图像,以及包含尽可能多的其他食物的“负类”图像。
含着两个类别的1000张图片用于训练,其余的则用于测试。
"""
d2l.DATA_HUB['hotdog'] = (d2l.DATA_URL + 'hotdog.zip',
                         'fba480ffa8aa7e0febbb511d181409f899b9baa5')

data_dir = d2l.download_extract('hotdog')
print(data_dir)
#输出..\data\hotdog
train_imgs=torchvision.datasets.ImageFolder(os.path.join(data_dir,'train'))
test_imgs=torchvision.datasets.ImageFolder(os.path.join(data_dir,'test'))
hotdogs=[train_imgs[i][0] for i in range(8)]
not_hotdogs=[train_imgs[-i-1][0] for i in range(8)]
d2l.show_images(hotdogs+not_hotdogs,2,8,scale=1.4)

在这里插入图片描述

# 使用RGB通道的均值和标准差,以标准化每个通道
"""
在训练期间,我们首先从图像中裁切随机大小和随机长宽比的区域,然后将该区域缩放为\(224*224\)输入图像。 
在测试过程中,我们将图像的高度和宽度都缩放到256像素,然后裁剪中央\(224*224\)区域作为输入。
此外,对于RGB(红、绿和蓝)颜色通道,我们分别标准化每个通道。 
具体而言,该通道的每个值减去该通道的平均值,然后将结果除以该通道的标准差。
"""
normalize=torchvision.transforms.Normalize([0.485,0.456,0.406],
                                           [0.229,0.224,0.225])
train_augs=torchvision.transforms.Compose([torchvision.transforms.RandomResizedCrop(224),#随机裁剪,并resize成224
                                          torchvision.transforms.RandomHorizontalFlip(),
                                          torchvision.transforms.ToTensor(),
                                          normalize])
test_augs=torchvision.transforms.Compose([torchvision.transforms.Resize(256),
                                          torchvision.transforms.CenterCrop(224),#将图片从中心裁剪成224*224
                                          torchvision.transforms.ToTensor(),
                                          normalize])
#我们使用在ImageNet数据集上预训练的ResNet-18作为源模型。 在这里,我们指定pretrained=True以自动下载预训练的模型参数。 
#如果你首次使用此模型,则需要连接互联网才能下载。
pretrained_net=torchvision.models.resnet18(pretrained=True)
"""
预训练的源模型实例包含许多特征层和一个输出层fc(全连接层)。 
此划分的主要目的是促进对除输出层以外所有层的模型参数进行微调。 
下面给出了源模型的成员变量fc。
"""
pretrained_net.fc
#输出
#Linear(in_features=512, out_features=1000, bias=True)
finetune_net=torchvision.models.resnet18(pretrained=True)
finetune_net.fc=nn.Linear(finetune_net.fc.in_features,2)#全连接层的输入神经元数量是特征数量,因为是2分类,所以输出是2
nn.init.xavier_uniform_(finetune_net.fc.weight)#随机初始化全连接层权重
#Parameter containing:
tensor([[ 0.0378,  0.0630, -0.0080,  ..., -0.0220, -0.0511,  0.0959],
        [ 0.0556,  0.0227, -0.0262,  ..., -0.1059, -0.0171,  0.0051]],
       requires_grad=True)
#微调模型
# 如果param_group=True,输出层中的模型参数将使用十倍的学习率
def train_fine_tuning(net, learning_rate, batch_size=128, num_epochs=5,
                      param_group=True):
    train_iter = torch.utils.data.DataLoader(torchvision.datasets.ImageFolder(
        os.path.join(data_dir, 'train'), transform=train_augs),
        batch_size=batch_size, shuffle=True)
    test_iter = torch.utils.data.DataLoader(torchvision.datasets.ImageFolder(
        os.path.join(data_dir, 'test'), transform=test_augs),
        batch_size=batch_size)
    devices = d2l.try_all_gpus()
    loss = nn.CrossEntropyLoss(reduction="none")
    if param_group:
        params_1x = [param for name, param in net.named_parameters()
             if name not in ["fc.weight", "fc.bias"]]
        trainer = torch.optim.SGD([{'params': params_1x},
                                   {'params': net.fc.parameters(),
                                    'lr': learning_rate * 10}],
                                lr=learning_rate, weight_decay=0.001)
    else:
        trainer = torch.optim.SGD(net.parameters(), lr=learning_rate,
                                  weight_decay=0.001)
    d2l.train_ch13(net, train_iter, test_iter, loss, trainer, num_epochs,
                   devices)
train_fine_tuning(finetune_net, 5e-5)                  

在这里插入图片描述

#为了进行比较,我们定义了一个相同的模型,但是将其所有模型参数初始化为随机值。 
#由于整个模型需要从头开始训练,因此我们需要使用更大的学习率。
scratch_net = torchvision.models.resnet18()
scratch_net.fc = nn.Linear(scratch_net.fc.in_features, 2)
train_fine_tuning(scratch_net, 5e-4, param_group=False)

在这里插入图片描述

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值