pytorch深度学习-微调(fine tuning)

微调(fine tuning)

首先举一个例子,假设我们想从图像中识别出不同种类的椅子,然后将购买链接推荐给用户。一种可能的方法是先找出100种常见的椅子,为每种椅子拍摄1,000张不同角度的图像,然后在收集到的图像数据集上训练一个分类模型。这个椅子数据集虽然可能比Fashion-MNIST数据集要庞大,但样本数仍然不及ImageNet数据集中样本数的十分之一。这可能会导致适用于ImageNet数据集的复杂模型在这个椅子数据集上过拟合。同时,因为数据量有限,最终训练得到的模型的精度也可能达不到实用的要求

为了应对上述问题,一个显而易见的解决办法是收集更多的数据。然而,收集和标注数据会花费大量的时间和资金。例如,为了收集ImageNet数据集,研究人员花费了数百万美元的研究经费。虽然目前的数据采集成本已降低了不少,但其成本仍然不可忽略。

另外一种解决办法是应用迁移学习(transfer learning),将从源数据集学到的知识迁移到目标数据集上。例如,虽然ImageNet数据集的图像大多跟椅子无关,但在该数据集上训练的模型可以抽取较通用的图像特征,从而能够帮助识别边缘、纹理、形状和物体组成等。这些类似的特征对于识别椅子也可能同样有效。

接下来就需要介绍迁移学习中的一种常用技术:微调(fine tuning)。如下图所示,微调由以下4步构成。

  • 在源数据集(如ImageNet数据集)上预训练一个神经网络模型,即源模型。
  • 创建一个新的神经网络模型,即目标模型。它复制了源模型上除了输出层外的所有模型设计及其参数。我们假设这些模型参数包含了源数据集上学习到的知识,且这些知识同样适用于目标数据集。我们还假设源模型的输出层跟源数据集的标签紧密相关,因此在目标模型中不予采用。
  • 为目标模型添加一个输出大小为目标数据集类别个数的输出层,并随机初始化该层的模型参数。
  • 在目标数据集(如椅子数据集)上训练目标模型。我们将从头训练输出层而其余层的参数都是基于源模型的参数微调得到的

值得注意,但是并不难理解的是,当目标数据集远小于源数据集时,微调有助于提升模型的泛化能力。

fine tuning的具体例子

接下来我们来实践一个具体的例子:热狗识别。我们将基于一个小数据集对在ImageNet数据集上训练好的ResNet模型进行微调。该小数据集含有数千张包含热狗和不包含热狗的图像。我们将使用微调得到的模型来识别一张图像中是否包含热狗。

首先,导入实验所需的包或模块。torchvision的models包提供了常用的预训练模型。如果希望获取更多的预训练模型,可以使用使用pretrained-models.pytorch仓库。

%matplotlib inline
import torch
from torch import nn, optim
from torch.utils.data import Dataset, DataLoader
import torchvision
from torchvision.datasets import ImageFolder
from torchvision import transforms
from torchvision import models
import os
from matplotlib import pyplot as plt
import timedevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
获取数据集

点击下载热狗数据集,它含有1400张包含热狗的正类图像,和同样多包含其他食品的负类图像。各类的1000张图像被用于训练,其余则用于测试。

我们首先将压缩后的数据集下载到路径data_dir之下,然后在该路径将下载好的数据集解压,得到两个文件夹hotdog/train和hotdog/test。这两个文件夹下面均有hotdog和not-hotdog两个类别文件夹,每个类别文件夹里面是图像文件。

data_dir = './data_set'
os.listdir(os.path.join(data_dir, "hotdog")) # ['train', 'test']

创建两个ImageFolder实例来分别读取训练数据集和测试数据集中的所有图像文件。

train_imgs = ImageFolder(os.path.join(data_dir, 'hotdog/train'))
test_imgs = ImageFolder(os.path.join(data_dir, 'hotdog/test'))

画出前8张正类图像和最后8张负类图像。可以看到,它们的大小和高宽比各不相同。

def show_images(imgs, num_rows, num_cols, scale=2):figsize = (num_cols * scale, num_rows * scale)_, axes = plt.subplots(num_rows, num_cols, figsize=figsize)for i in range(num_rows):for j in range(num_cols):axes[i][j].imshow(imgs[i * num_cols + j])axes[i][j].axes.get_xaxis().set_visible(False)axes[i][j].axes.get_yaxis().set_visible(False)return axeshotdogs = [train_imgs[i][0] for i in range(8)]
not_hotdogs = [train_imgs[-i - 1][0] for i in range(8)]
show_images(hotdogs + not_hotdogs, 2, 8, scale=1.4);
  • 在训练时,我们先从图像中裁剪出随机大小和随机高宽比的一块随机区域,然后将该区域缩放为高和宽均为224像素的输入。
  • 测试时,我们将图像的高和宽均缩放为256像素,然后从中裁剪出高和宽均为224像素的中心区域作为输入。
  • 此外,我们对RGB(红、绿、蓝)三个颜色通道的数值做标准化:每个数值减去该通道所有数值的平均值,再除以该通道所有数值的标准差作为输出。
    指定RGB三个通道的均值和方差来将图像通道归一化
# 指定RGB三个通道的均值和方差来将图像通道归一化
normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
train_augs = transforms.Compose([transforms.RandomResizedCrop(size=224),transforms.RandomHorizontalFlip(),transforms.ToTensor(),normalize])test_augs = transforms.Compose([transforms.Resize(size=256),transforms.CenterCrop(size=224),transforms.ToTensor(),normalize])

需要注意的是:在使用预训练模型时,一定要和预训练时作同样的预处理

定义和初始化模型

使用在ImageNet数据集上预训练的ResNet-18作为源模型。这里指定pretrained=True来自动下载并加载预训练的模型参数。在第一次使用时需要联网下载模型参数。

pretrained_net = models.resnet18(pretrained=True)

不管你是使用的torchvision的models还是pretrained-models.pytorch仓库,默认都会将预训练好的模型参数下载到你的home目录下.torch文件夹。你可以通过修改环境变量TORCH_MODEL_ZOO来更改下载目录: export TORCH_MODEL_ZOO="/local/pretrainedmodels" 。

另外比较常使用的方法是,在其源码中找到下载地址直接浏览器输入地址下载,下载好后将其放到环境变量$TORCH_MODEL_ZOO所指文件夹即可,这样比较快

打印源模型的成员变量fc。作为一个全连接层,它将ResNet最终的全局平均池化层输出变换成ImageNet数据集上1000类的输出。

print(pretrained_net.fc)

如果你使用的是其他模型,那可能没有成员变量fc(比如models中的VGG预训练模型),所以正确做法是查看对应模型源码中其定义部分,这样既不会出错也能加深我们对模型的理解。

可见此时pretrained_net最后的输出个数等于目标数据集的类别数1000。所以我们应该将最后的fc成修改我们需要的输出类别数:

pretrained_net.fc = nn.Linear(512, 2)
print(pretrained_net.fc)

此时,pretrained_net的fc层就被随机初始化了,但是其他层依然保存着预训练得到的参数。由于是在很大的ImageNet数据集上预训练的,所以参数已经足够好,因此一般只需使用较小的学习率来微调这些参数,而fc中的随机初始化参数一般需要更大的学习率从头训练

PyTorch可以方便的对模型的不同部分设置不同的学习参数,我们在下面代码中将fc的学习率设为已经预训练过的部分的10倍。

output_params = list(map(id, pretrained_net.fc.parameters()))
feature_params = filter(lambda p: id(p) not in output_params, pretrained_net.parameters())lr = 0.01
optimizer = optim.SGD([{'params': feature_params},{'params': pretrained_net.fc.parameters(), 'lr': lr * 10}],lr=lr, weight_decay=0.001)
微调模型

先定义一个使用微调的训练函数train_fine_tuning以便多次调用。

def train(train_iter, test_iter, net, loss, optimizer, device, num_epochs):net = net.to(device)print("training on ", device)batch_count = 0for epoch in range(num_epochs):train_l_sum, train_acc_sum, n, start = 0.0, 0.0, 0, time.time()for X, y in train_iter:X = X.to(device)y = y.to(device)y_hat = net(X)l = loss(y_hat, y) optimizer.zero_grad()l.backward()optimizer.step()train_l_sum += l.cpu().item()train_acc_sum += (y_hat.argmax(dim=1) == y).sum().cpu().item()n += y.shape[0]batch_count += 1test_acc = evaluate_accuracy(test_iter, net)print('epoch %d, loss %.4f, train acc %.3f, test acc %.3f, time %.1f sec'% (epoch + 1, train_l_sum / batch_count, train_acc_sum / n, test_acc, time.time() - start))
def train_fine_tuning(net, optimizer, batch_size=128, num_epochs=5):train_iter = DataLoader(ImageFolder(os.path.join(data_dir, 'hotdog/train'), transform=train_augs),batch_size, shuffle=True)test_iter = DataLoader(ImageFolder(os.path.join(data_dir, 'hotdog/test'), transform=test_augs),batch_size)loss = torch.nn.CrossEntropyLoss()train(train_iter, test_iter, net, loss, optimizer, device, num_epochs)
开始训练(微调)
train_fine_tuning(pretrained_net, optimizer)

理论上可以执行了哈,但是我的pc显存太小,溢出了,建议使用显存10G以上的GPU进行训练

  • 迁移学习将从源数据集学到的知识迁移到目标数据集上。微调是迁移学习的一种常用技术。
  • 目标模型复制了源模型上除了输出层外的所有模型设计及其参数,并基于目标数据集微调这些参数。而目标模型的输出层需要从头训练。
  • 一般来说,微调参数会使用较小的学习率,而从头训练输出层可以使用较大的学习率。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/507951.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

c语言封闭曲线分割平面_高手的平面课堂:8种常用的设计排版方式,告别通宵加班...

重复、对比、对齐以及亲密性是传统平面排版的四大原则,即将元素重复运用(包括颜色、形状、材质、字体、空间关系等)以增加画面的条理性和整体性;避免页面上的元素形态与关系构建过于相似;画面上的每一元素都应该与另一个元素存在某种视觉联系…

我的世界java版和基岩版对比_基岩版Beta1.11.0.1发布

本帖来自好游快爆-我的世界精选推荐原帖作者:好游快爆用户3302482我的世界基岩版1.11.0.1测试版发布了,Minecraft基岩版1.11仍未发布,1.11.0.1为测试版本,Beta版本可能不稳定,并不代表最终版本质量,请在加入测试版之前…

机器人电焊电流电压怎么调_【华光】HG1000型电焊机现场校准仪

机器简介HG-1000型电焊机现场校准仪是依据检定规程JJG124-2005《电流表、电压表、功率表和电阻表检定规程》、JJG(航天)38-1987《直流标准电流源检定规程》、JJG(航天)51-1999《交流标准电流源检定规程》的要求而设计的校准设备。主要用来校验各种用电焊机(如交流手…

循环机换变速箱油教程_变速箱油用循环机换还是重力换更好?一次讲清楚,新手司机学学...

现在换变速箱油有些只要几百块钱,有些要一两千,之所以差价这么大是因为这里面涉及到换变速箱油时用什么方法去换油的问题。目前比较常见换油法是重力换油法和循环换油法。重力换油法就跟平时换机油是一样的,把变速箱底部的螺丝拧开之后让油滴…

mongodb python 存文件_Python保存MongoDB上的文件到本地的方法介绍

本文实例讲述了Python保存MongoDB上的文件到本地的方法。分享给大家供大家参考,具体如下:MongoDB上的文档通过GridFS来操作,Python也可以通过pymongo连接MongoDB数据库,使用pymongo模块的gridfs方法操作文档。以下示例是把MongoDB…

mongodb 监控权限_MongoDB - 监控

随着MongoDB中保存的数据越来越多,对MongoDB服务状态的监控也越来越重要,经常关注服务是否健康,才能防止故障以及优化。1.静态监控db.serverStatus()使用mongo命令进入shell客户端后输入以下命令可以查看MongoDB服务的状态,有助于…

pytorch深度学习-机器视觉-目标检测和边界框简介

机器视觉之目标检测和边界框简介 在图像分类任务里,我们假设图像里只有一个主体目标,并关注如何识别该目标的类别。然而,很多时候图像里有多个我们感兴趣的目标,我们不仅想知道它们的类别,还想得到它们在图像中的具体…

消防荷载楼板按弹性还是塑性计算_第二节 消防登高面、消防救援场地和灭火救援窗...

一、定义1、消防登高面:登高消防车能够靠近高层主体建筑,便于消防车作业和消防人员进入高层建筑进行抢救人员和扑救火灾的建筑立面称为该建筑的消防登高面,也称建筑的消防扑救面。2、消防救援场地:在高层建筑的消防登高面一侧&…

深度学习-词嵌入(word2vec)

词嵌入(word2vec) 自然语言是一套用来表达含义的复杂系统。在这套系统中,词是表义的基本单元。顾名思义,词向量是用来表示词的向量,也可被认为是词的特征向量或表征。把词映射为实数域向量的技术也叫词嵌入&#xff0…

ggplot2箱式图两两比较_作图技巧024篇ggplot2在循环中的坑

“ggplot2在循环中的输出”生活科学哥-R语言科学 2020-12-23 8:28ggplot2用过之后,你肯定会爱上它;结合一些不错的包,可以得到非常有展现力的图片,但是呢,有时也会碰到一些奇怪的情况。今天来们来看看,其中…

深度学习-自然语言处理中的近似训练

自然语言处理中的近似训练 跳字模型的核心在于使用softmax运算得到给定中心词wcw_cwc​来生成背景词wow_owo​的条件概率 P(wo∣wc)exp(uo⊤vc)∑i∈Vexp(ui⊤vc).P(w_o \mid w_c) \frac{\text{exp}(\boldsymbol{u}_o^\top \boldsymbol{v}_c)}{ \sum_{i \in \mathcal{V}} \te…

pytorch-word2vec的实例实现

word2vec的实例实现 实现词嵌入word2vec中的跳字模型和近似训练中的负采样以及二次采样(subsampling),在语料库上训练词嵌入模型的实现。 首先导入实验所需的包或模块。 import collections import math import random import sys import …

pytorch-LSTM的输入和输出尺寸

LSTM的输入和输出尺寸 CLASS torch.nn.LSTM(*args, **kwargs)Applies a multi-layer long short-term memory (LSTM) RNN to an input sequence. For each element in the input sequence, each layer computes the following function: 对于一个输入序列实现多层长短期记忆的…

python中的[-1]、[:-1]、[::-1]、[n::-1]

import numpy as np anp.random.rand(4) print(a)[0.48720333 0.67178384 0.65662903 0.40513918]print(a[-1]) #取最后一个元素 0.4051391774882336print(a[:-1]) #去除最后一个元素 [0.48720333 0.67178384 0.65662903]print(a[::-1]) #逆序 [0.40513918 0.65662903 0.67178…

torchtext.data.Field

torchtext.data.Field 类接口 class torchtext.data.Field(sequentialTrue, use_vocabTrue, init_tokenNone, eos_tokenNone, fix_lengthNone, dtypetorch.int64, preprocessingNone, postprocessingNone, lowerFalse, tokenizeNone, tokenizer_languageen, include_lengthsF…

np.triu

np.triu numpy.triu(m, k0) Upper triangle of an array. Return a copy of a matrix with the elements below the k-th diagonal zeroed. 返回一个矩阵的上三角矩阵,第k条对角线以下的元素归零 例如: import numpy as np np.triu(np.ones([4,4]), …

python读取json格式的超参数

python读取json格式的超参数 json文件: {"full_finetuning": true,"max_len": 180,"learning_rate": 3e-5,"weight_decay": 0.01,"clip_grad": 2,"batch_size": 30,"epoch_num": 20,"…

python缺少标准库_干货分享:Python如何自动导入缺失的库

很多同学在写Python项目时会遇到导入模块失败的情况:ImportError: No module named xxx或者ModuleNotFoundError: No module named xxx。导入模块失败通常分为两种:一种是导入自己写的模块(即以 .py 为后缀的文件),另一种是导入三方库。接下来…

.val()数据乱码_【目标检测数据集】PASCAL VOC制作

【VOC20072012】数据集地址:https://pjreddie.com/projects/pascal-voc-dataset-mirror/PASCAL VOC为图像识别和分类提供了一整套标准化的优秀的数据集,用于构建和评估用于图像分类(Classification),检测(O…

pytorch-多GPU训练(单机多卡、多机多卡)

pytorch-多GPU训练(单机多卡、多机多卡) pytorch 单机多卡训练 首先是数据集的分布处理 需要用到的包: torch.utils.data.distributed.DistributedSampler torch.utils.data.DataLoader torch.utils.data.Dataset DistributedSampler这个…