《动手学深度学习》之微调(热狗识别)_乾巽的博客-程序员秘密_热狗识别

技术标签: python  pytorch深度学习  机器学习  深度学习  神经网络  

参考微调(fine tuning)
在这里插入图片描述
下面以热狗识别为例
我们将基于一个小数据集对在ImageNet数据集上训练好的ResNet模型进行微调。该小数据集含有数千张包含热狗和不包含热狗的图像。我们将使用微调得到的模型来识别一张图像中是否包含热狗。

一.导入包或模块


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

import sys
sys.path.append("..") 
import d2lzh_pytorch as d2l

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

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

将下载好的zip文件解压到代码所在文件夹下
解压得到两个文件夹hotdog/train和hotdog/test。
这两个文件夹下面均有hotdog和not-hotdog两个类别文件夹,每个类别文件夹里面是图像文件。

data_dir = 'hotdog'
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张负类图像。

hotdogs = [train_imgs[i][0] for i in range(8)]
not_hotdogs = [train_imgs[-i-1][0] for i in range(8)]  #not_hotdogs文件夹里从后面读回来
print(train_imgs[1])     #'tuple' object
print(train_imgs[1][0])  #'Image' object
d2l.show_images(hotdogs + not_hotdogs, 2, 8, scale=1.4)

在这里插入图片描述
在训练时,我们先从图像中裁剪出随机大小和随机高宽比的一块随机区域,
然后将该区域缩放为高和宽均为224像素的输入。
测试时,我们将图像的高和宽均缩放为256像素,
然后从中裁剪出高和宽均为224像素的中心区域作为输入。
此外,我们对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作为源模型

下载并加载预训练的模型参数
Downloading: “https://download.pytorch.org/models/resnet18-5c106cde.pth”,直接打开这个链接下载到本代码所在文件夹下

pretrained_net = models.resnet18(pretrained=False)

print(pretrained_net.fc)  #最后的输出个数等于目标数据集的类别数1000

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

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

pretrained_net的fc层就被随机初始化了,但是其他层依然保存着预训练得到的参数。
由于是在很大的ImageNet数据集上预训练的,所以参数已经足够好,
因此一般只需使用较小的学习率来微调这些参数,
而fc中的随机初始化参数一般需要更大的学习率从头训练
PyTorch可以方便的对模型的不同部分设置不同的学习参数,
我们在下面代码中将fc的学习率设为已经预训练过的部分的10倍。

# map函数配合匿名函数使用
# x = list(map(lambda a:a*10,range(0,10))) # 序列中的每个元素乘以10
output_params = list(map(id, pretrained_net.fc.parameters()))    #id()函数用于获取对象的内存地址
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)

四.微调模型

def train_fine_tuning(net, optimizer, batch_size=20, 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()
    d2l.train(train_iter, test_iter, net, loss, optimizer, device, num_epochs)
train_fine_tuning(pretrained_net, optimizer)

在这里插入图片描述
五.比较
定义一个相同的模型,但将它的所有模型参数都初始化为随机值。由于整个模型都需要从头训练,我们可以使用较大的学习率

scratch_net = models.resnet18(pretrained=False, num_classes=2)
lr = 0.1
optimizer = optim.SGD(scratch_net.parameters(), lr=lr, weight_decay=0.001)
train_fine_tuning(scratch_net, optimizer)

在这里插入图片描述
这里看到下面的效果更好一点
不过按照原来作者给出的结果是上面的会好一点,可能是batch_size的问题,作者的batch_size= 128,我的为20,调大一点会好很多,但是还是得看内存

d2lzh_pytorch

完整代码如下

# -*- coding: utf-8 -*-
"""
Created on Sun Feb  9 10:47:16 2020

@author:"""
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


import sys
sys.path.append("d2lzh_pytorch.py") 
import d2lzh_pytorch as d2l

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

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

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

hotdogs = [train_imgs[i][0] for i in range(8)]
not_hotdogs = [train_imgs[-i-1][0] for i in range(8)]  #not_hotdogs文件夹里从后面读回来
print(train_imgs[1])     #'tuple' object
print(train_imgs[1][0])  #'Image' object
d2l.show_images(hotdogs + not_hotdogs, 2, 8, scale=1.4)


# 指定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来自动下载并加载预训练的模型参数。
# 在第一次使用时需要联网下载模型参数。
# Downloading: "https://download.pytorch.org/models/resnet18-5c106cde.pth",直接打开这个链接下载到本代码所在文件夹下
pretrained_net = models.resnet18(pretrained=False)

print(pretrained_net.fc)  #最后的输出个数等于目标数据集的类别数1000

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

# map函数配合匿名函数使用
# x = list(map(lambda a:a*10,range(0,10))) # 序列中的每个元素乘以10
output_params = list(map(id, pretrained_net.fc.parameters()))    #id()函数用于获取对象的内存地址
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)

#batch_size 可以继续调大,得看自己电脑CUDA 内存
def train_fine_tuning(net, optimizer, batch_size=20, 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()
    d2l.train(train_iter, test_iter, net, loss, optimizer, device, num_epochs)
# train_fine_tuning(pretrained_net, optimizer)
scratch_net = models.resnet18(pretrained=False, num_classes=2)
lr = 0.1
optimizer = optim.SGD(scratch_net.parameters(), lr=lr, weight_decay=0.001)
train_fine_tuning(scratch_net, optimizer)



版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_44291388/article/details/104233606

智能推荐

2_从MLP到AE_刘一五的博客-程序员秘密

最简单的AutoEncoder不过是一个拥有瓶颈层(bottleneck layer)的MLP 【1】 ,所以在神经网络的结构上只需要做出一点改动即可。其功能是通过将输入信息作为学习目标,对输入信息进行表征学习(representation learning)。...

Vue-vue-router解决权限问题_the_renaissance的博客-程序员秘密

在vue项目中,与后端的数据交互只能通过ajxa。在解决用户权限问题上,后台的拦截器可以拦截需要登陆的请求。在vue项目中,我们也可以vue-router的导航守卫功能实现场景描述假设有一个场景,首页页面访问不需要校验用户权限,因为用户未登录无法判断其权限。访问管理后台页面时,如果用户没有登陆自动跳转到登陆页面,这种实现效果类似与后台的拦截器。在vue项目中,我们如何实现这种效果...

js----笔记_weixin_30404405的博客-程序员秘密

1.注意: oTxt.innerHTML='<h2>那年印象</h2><p>'+this.index+'月'+aInnerText[this.index]+'<p>' ;如果想让this.index+1则写成oTxt.innerHTML='<h2>那年印象</h2><p>'+(this.ind...

hive 配置用户名_HIVE2 :beeline连接设置用户名和密码注意问题_weixin_39816024的博客-程序员秘密

beeline connect有几种方式,见hive-site.xml,缺省为NONE。hive.server2.authenticationNONEExpects one of [nosasl, none, ldap, kerberos, pam, custom].Client authentication types.NONE: no authentication checkLDAP: LDA...

中国科学院计算机研究所千人,理化所人才库----中国科学院理化技术研究所_九罭之魚的博客-程序员秘密

1.X. X. Jiang, Y. Yang, M. S. Molokeev, P. F. Gong, F. Liang, S. H. Wang, L. Liu, X. Wu, X. D. Li, Y. C. Li, S. F. Wu, W. Li, Y. C. Wu, Z. S. Lin*, “Zero Linear Compressibility in the Non-dense Borate...

JDBC的使用(二):PreparedStatement接口;ResultSet接口(获取结果集);例题:SQL注入..._diku9497的博客-程序员秘密

ResultSet接口:类似于一个临时表,用来暂时存放数据库查询操作所获得的结果集。getInt(), getFloat(), getDate(), getBoolean(), getString(), getObject(), next(),:将指针向下移一行。例一:(输入用户名和密码验证是否登录成功):用Statement接口会导致,SQL注入!下图是代码:p...

随便推点

用ACCESS做网络版程序_宋哥的博客-程序员秘密_access如何开发网络程序

iamlaosong文Access的性能决定了其使用范围主要是个人应用,但也不排除做一些网络应用。即便是网络应用,也是一些轻数据量的简单应用,主要是提升日常办公效率。方法如下: 一、直接把access文件放到网络中的共享目录中这种方法最简单,只要创建一个共享目录,将所有access文件拷贝到这个目录中,局域网中的其他机器只要打开这个共享目录中的access文件就可以了。为方便使用,使用...

Android oppo或者vivio双击应用被切换到后台_码农之今天的砖特别烫手的博客-程序员秘密

Android oppo或者vivio双击应用被切换到后台当时遇到这个现象我真是懵逼了,在应用很多地方双击,应用直接“”闪退“”了,而且控制台没有任何的报错信息项目面临上线,突然出现这么大的bug,基本要死翘翘了,各种试错,都没用,后来我想,是不是根本就没崩溃。我把进程任务切出来,应用果然没有崩溃当时就发飙,找到测试就是一顿怼,但是问题还是要解决,因为应用双击切到后台,对用户来说就是闪退。我到网上各种找,就没有遇到过这个问题。虽然我知道肯定和系统相关。但是真心不知道哪里配置有问题后来我各种试错,

收藏 | 一文总结70篇论文,帮你透彻理解神经网络的剪枝算法_数据派THU的博客-程序员秘密

来源:DeepHub IMBA本文约9500字,建议阅读10+分钟本文为你详细介绍神经网络剪枝结构、剪枝标准和剪枝方法。无论是在计算机视觉、自然语言处理还是图像生成方面,深度神经网络...

计算机三级网络技术分值占比,全国计算机等级考试三级考试题型及分值比例_清木一阳的博客-程序员秘密

对于全国计算机等级考试三级考试题型及分值比例的内容,最近很多人很困惑,一直在咨询小编,今天华律网小编针对该问题,梳理了以下内容,希望可以帮您答疑解惑。1、三级网络题型及分值比例:上机考试,考试时长120分钟,满分100分(1)单选题(每小题1分,共40分)(2)综合题(每空2分,共40分)(3)应用题(共20分)2、三级数据库题型及分值比例:上机考试,考试时长120分钟,满分100分(1)单选题[...

Unity街机横版格斗(恐龙快打)插件-Beat Em Up Template 3D 1.3(附下载连接)_锦秀年华@ARVR的博客-程序员秘密_恐龙快打3d版

导入插件后打开Game场景可看到自带的Demo场景的结构是非常简洁的,就设置几个东西就可以做成爽爆的打击感强烈的横版格斗游戏,小时候很喜欢玩《恐龙快打》,经常会幻想自己设置游戏关卡的话会怎样设置,有一这个插件,这个幻想真的可以实现了。下来贴几张使用时的截图,本人使用unity217.4.25f导入插件包测试。敌人的代码中包括了相关的招试等的设置,有点unity基础的人都能看懂,我就不多介绍了。这里值得提醒一下的就是插件中只提供一个关卡,如果自己编辑了多个关卡要如何切换到下一关呢?很简单,只需要在

剖析Bean处理器之BeanNameAutoProxyCreator_jinshiyill的博客-程序员秘密

1.BeanNameAutoProxyCreator实现“AOP”效果代码片段123456789101112131415161718192021222324

推荐文章

热门文章

相关标签