pytorch finetuning 自己的图片进行训练操作
作者:nancheng911 发布时间:2023-03-17 00:46:53
一、pytorch finetuning 自己的图片进行训练
这种读取图片的方式用的是torch自带的 ImageFolder,读取的文件夹必须在一个大的子文件下,按类别归好类。
就像我现在要区分三个类别。
#perpare data set
#train data
train_data=torchvision.datasets.ImageFolder('F:/eyeDataSet/trainData',transform=transforms.Compose(
[
transforms.Scale(256),
transforms.CenterCrop(224),
transforms.ToTensor()
]))
print(len(train_data))
train_loader=DataLoader(train_data,batch_size=20,shuffle=True)
然后就是fine tuning自己的网络,在torch中可以对整个网络修改后,训练全部的参数也可以只训练其中的一部分,我这里就只训练最后一个全连接层。
torchvision中提供了很多常用的模型,比如resnet ,Vgg,Alexnet等等
# prepare model
mode1_ft_res18=torchvision.models.resnet18(pretrained=True)
for param in mode1_ft_res18.parameters():
param.requires_grad=False
num_fc=mode1_ft_res18.fc.in_features
mode1_ft_res18.fc=torch.nn.Linear(num_fc,3)
定义自己的优化器,注意这里的参数只传入最后一层的
#loss function and optimizer
criterion=torch.nn.CrossEntropyLoss()
#parameters only train the last fc layer
optimizer=torch.optim.Adam(mode1_ft_res18.fc.parameters(),lr=0.001)
然后就可以开始训练了,定义好各种参数。
#start train
#label not one-hot encoder
EPOCH=1
for epoch in range(EPOCH):
train_loss=0.
train_acc=0.
for step,data in enumerate(train_loader):
batch_x,batch_y=data
batch_x,batch_y=Variable(batch_x),Variable(batch_y)
#batch_y not one hot
#out is the probability of eatch class
# such as one sample[-1.1009 0.1411 0.0320],need to calculate the max index
# out shape is batch_size * class
out=mode1_ft_res18(batch_x)
loss=criterion(out,batch_y)
train_loss+=loss.data[0]
# pred is the expect class
#batch_y is the true label
pred=torch.max(out,1)[1]
train_correct=(pred==batch_y).sum()
train_acc+=train_correct.data[0]
optimizer.zero_grad()
loss.backward()
optimizer.step()
if step%14==0:
print('Epoch: ',epoch,'Step',step,
'Train_loss: ',train_loss/((step+1)*20),'Train acc: ',train_acc/((step+1)*20))
测试部分和训练部分类似这里就不一一说明。
这样就完整了对自己网络的训练测试,完整代码如下:
import torch
import numpy as np
import torchvision
from torchvision import transforms,utils
from torch.utils.data import DataLoader
from torch.autograd import Variable
#perpare data set
#train data
train_data=torchvision.datasets.ImageFolder('F:/eyeDataSet/trainData',transform=transforms.Compose(
[
transforms.Scale(256),
transforms.CenterCrop(224),
transforms.ToTensor()
]))
print(len(train_data))
train_loader=DataLoader(train_data,batch_size=20,shuffle=True)
#test data
test_data=torchvision.datasets.ImageFolder('F:/eyeDataSet/testData',transform=transforms.Compose(
[
transforms.Scale(256),
transforms.CenterCrop(224),
transforms.ToTensor()
]))
test_loader=DataLoader(test_data,batch_size=20,shuffle=True)
# prepare model
mode1_ft_res18=torchvision.models.resnet18(pretrained=True)
for param in mode1_ft_res18.parameters():
param.requires_grad=False
num_fc=mode1_ft_res18.fc.in_features
mode1_ft_res18.fc=torch.nn.Linear(num_fc,3)
#loss function and optimizer
criterion=torch.nn.CrossEntropyLoss()
#parameters only train the last fc layer
optimizer=torch.optim.Adam(mode1_ft_res18.fc.parameters(),lr=0.001)
#start train
#label not one-hot encoder
EPOCH=1
for epoch in range(EPOCH):
train_loss=0.
train_acc=0.
for step,data in enumerate(train_loader):
batch_x,batch_y=data
batch_x,batch_y=Variable(batch_x),Variable(batch_y)
#batch_y not one hot
#out is the probability of eatch class
# such as one sample[-1.1009 0.1411 0.0320],need to calculate the max index
# out shape is batch_size * class
out=mode1_ft_res18(batch_x)
loss=criterion(out,batch_y)
train_loss+=loss.data[0]
# pred is the expect class
#batch_y is the true label
pred=torch.max(out,1)[1]
train_correct=(pred==batch_y).sum()
train_acc+=train_correct.data[0]
optimizer.zero_grad()
loss.backward()
optimizer.step()
if step%14==0:
print('Epoch: ',epoch,'Step',step,
'Train_loss: ',train_loss/((step+1)*20),'Train acc: ',train_acc/((step+1)*20))
#print('Epoch: ', epoch, 'Train_loss: ', train_loss / len(train_data), 'Train acc: ', train_acc / len(train_data))
# test model
mode1_ft_res18.eval()
eval_loss=0
eval_acc=0
for step ,data in enumerate(test_loader):
batch_x,batch_y=data
batch_x,batch_y=Variable(batch_x),Variable(batch_y)
out=mode1_ft_res18(batch_x)
loss = criterion(out, batch_y)
eval_loss += loss.data[0]
# pred is the expect class
# batch_y is the true label
pred = torch.max(out, 1)[1]
test_correct = (pred == batch_y).sum()
eval_acc += test_correct.data[0]
optimizer.zero_grad()
loss.backward()
optimizer.step()
print( 'Test_loss: ', eval_loss / len(test_data), 'Test acc: ', eval_acc / len(test_data))
二、PyTorch 利用预训练模型进行Fine-tuning
在Deep Learning领域,很多子领域的应用,比如一些动物识别,食物的识别等,公开的可用的数据库相对于ImageNet等数据库而言,其规模太小了,无法利用深度网络模型直接train from scratch,容易引起过拟合,这时就需要把一些在大规模数据库上已经训练完成的模型拿过来,在目标数据库上直接进行Fine-tuning(微调),这个已经经过训练的模型对于目标数据集而言,只是一种相对较好的参数初始化方法而已,尤其是大数据集与目标数据集结构比较相似的话,经过在目标数据集上微调能够得到不错的效果。
Fine-tune预训练网络的步骤:
1. 首先更改预训练模型分类层全连接层的数目,因为一般目标数据集的类别数与大规模数据库的类别数不一致,更改为目标数据集上训练集的类别数目即可,一致的话则无需更改;
2. 把分类器前的网络的所有层的参数固定,即不让它们参与学习,不进行反向传播,只训练分类层的网络,这时学习率可以设置的大一点,如是原来初始学习率的10倍或几倍或0.01等,这时候网络训练的比较快,因为除了分类层,其它层不需要进行反向传播,可以多尝试不同的学习率设置。
3.接下来是设置相对较小的学习率,对整个网络进行训练,这时网络训练变慢啦。
下面对利用PyTorch深度学习框架Fine-tune预训练网络的过程中涉及到的固定可学习参数,对不同的层设置不同的学习率等进行详细讲解。
1. PyTorch对某些层固定网络的可学习参数的方法:
class Net(nn.Module):
def __init__(self, num_classes=546):
super(Net, self).__init__()
self.features = nn.Sequential(
nn.Conv2d(1, 64, kernel_size=3, stride=2, padding=1),
nn.BatchNorm2d(64),
nn.ReLU(inplace=True),
nn.Conv2d(64, 64, kernel_size=3, stride=1, padding=1),
nn.BatchNorm2d(64),
nn.ReLU(inplace=True),
)
self.Conv1_1 = nn.Sequential(
nn.Conv2d(64, 64, kernel_size=3, stride=1, padding=1),
nn.BatchNorm2d(64),
nn.ReLU(inplace=True),
nn.Conv2d(64, 64, kernel_size=3, stride=1, padding=1),
nn.BatchNorm2d(64),
)
for p in self.parameters():
p.requires_grad=False
self.Conv1_2 = nn.Sequential(
nn.Conv2d(64, 64, kernel_size=3, stride=1, padding=1),
nn.BatchNorm2d(64),
nn.ReLU(inplace=True),
nn.Conv2d(64, 64, kernel_size=3, stride=1, padding=1),
nn.BatchNorm2d(64),
)
如上述代码,则模型Net网络中self.features与self.Conv1_1层中的参数便是固定,不可学习的。这主要看代码:
for p in self.parameters():
p.requires_grad=False
插入的位置,这段代码前的所有层的参数是不可学习的,也就没有反向传播过程。也可以指定某一层的参数不可学习,如下:
for p in self.features.parameters():
p.requires_grad=False
则 self.features层所有参数均是不可学习的。
注意,上述代码设置若要真正生效,在训练网络时需要在设置优化器如下:
optimizer = torch.optim.SGD(filter(lambda p: p.requires_grad, model.parameters()), args.lr,
momentum=args.momentum,
weight_decay=args.weight_decay)
2. PyTorch之为不同的层设置不同的学习率
model = Net()
conv1_2_params = list(map(id, model.Conv1_2.parameters()))
base_params = filter(lambda p: id(p) not in conv1_2_params,
model.parameters())
optimizer = torch.optim.SGD([
{'params': base_params},
{'params': model.Conv1_2.parameters(), 'lr': 10 * args.lr}], args.lr,
momentum=args.momentum, weight_decay=args.weight_decay)
上述代码表示将模型Net网络的 self.Conv1_2层的学习率设置为传入学习率的10倍,base_params的学习没有明确设置,则默认为传入的学习率args.lr。
注意:
[{'params': base_params}, {'params': model.Conv1_2.parameters(), 'lr': 10 * args.lr}]
表示为列表中的字典结构。
这种方法设置不同的学习率显得不够灵活,可以为不同的层设置灵活的学习率,可以采用如下方法在adjust_learning_rate函数中设置:
def adjust_learning_rate(optimizer, epoch, args):
lre = []
lre.extend([0.01] * 10)
lre.extend([0.005] * 10)
lre.extend([0.0025] * 10)
lr = lre[epoch]
optimizer.param_groups[0]['lr'] = 0.9 * lr
optimizer.param_groups[1]['lr'] = 10 * lr
print(param_group[0]['lr'])
print(param_group[1]['lr'])
上述代码中的optimizer.param_groups[0]就代表[{'params': base_params}, {'params': model.Conv1_2.parameters(), 'lr': 10 * args.lr}]中的'params': base_params},optimizer.param_groups[1]代表{'params': model.Conv1_2.parameters(), 'lr': 10 * args.lr},这里设置的学习率会把args.lr给覆盖掉,个人认为上述代码在设置学习率方面更灵活一些。上述代码也可如下变成实现(注意学习率随便设置的,未与上述代码保持一致):
def adjust_learning_rate(optimizer, epoch, args):
lre = np.logspace(-2, -4, 40)
lr = lre[epoch]
for i in range(len(optimizer.param_groups)):
param_group = optimizer.param_groups[i]
if i == 0:
param_group['lr'] = 0.9 * lr
else:
param_group['lr'] = 10 * lr
print(param_group['lr'])
下面贴出SGD优化器的PyTorch实现,及其每个参数的设置和表示意义,具体如下:
import torch
from .optimizer import Optimizer, required
class SGD(Optimizer):
r"""Implements stochastic gradient descent (optionally with momentum).
Nesterov momentum is based on the formula from
`On the importance of initialization and momentum in deep learning`__.
Args:
params (iterable): iterable of parameters to optimize or dicts defining
parameter groups
lr (float): learning rate
momentum (float, optional): momentum factor (default: 0)
weight_decay (float, optional): weight decay (L2 penalty) (default: 0)
dampening (float, optional): dampening for momentum (default: 0)
nesterov (bool, optional): enables Nesterov momentum (default: False)
Example:
>>> optimizer = torch.optim.SGD(model.parameters(), lr=0.1, momentum=0.9)
>>> optimizer.zero_grad()
>>> loss_fn(model(input), target).backward()
>>> optimizer.step()
__ http://www.cs.toronto.edu/%7Ehinton/absps/momentum.pdf
.. note::
The implementation of SGD with Momentum/Nesterov subtly differs from
Sutskever et. al. and implementations in some other frameworks.
Considering the specific case of Momentum, the update can be written as
.. math::
v = \rho * v + g \\
p = p - lr * v
where p, g, v and :math:`\rho` denote the parameters, gradient,
velocity, and momentum respectively.
This is in contrast to Sutskever et. al. and
other frameworks which employ an update of the form
.. math::
v = \rho * v + lr * g \\
p = p - v
The Nesterov version is analogously modified.
"""
def __init__(self, params, lr=required, momentum=0, dampening=0,
weight_decay=0, nesterov=False):
if lr is not required and lr < 0.0:
raise ValueError("Invalid learning rate: {}".format(lr))
if momentum < 0.0:
raise ValueError("Invalid momentum value: {}".format(momentum))
if weight_decay < 0.0:
raise ValueError("Invalid weight_decay value: {}".format(weight_decay))
defaults = dict(lr=lr, momentum=momentum, dampening=dampening,
weight_decay=weight_decay, nesterov=nesterov)
if nesterov and (momentum <= 0 or dampening != 0):
raise ValueError("Nesterov momentum requires a momentum and zero dampening")
super(SGD, self).__init__(params, defaults)
def __setstate__(self, state):
super(SGD, self).__setstate__(state)
for group in self.param_groups:
group.setdefault('nesterov', False)
def step(self, closure=None):
"""Performs a single optimization step.
Arguments:
closure (callable, optional): A closure that reevaluates the model
and returns the loss.
"""
loss = None
if closure is not None:
loss = closure()
for group in self.param_groups:
weight_decay = group['weight_decay']
momentum = group['momentum']
dampening = group['dampening']
nesterov = group['nesterov']
for p in group['params']:
if p.grad is None:
continue
d_p = p.grad.data
if weight_decay != 0:
d_p.add_(weight_decay, p.data)
if momentum != 0:
param_state = self.state[p]
if 'momentum_buffer' not in param_state:
buf = param_state['momentum_buffer'] = torch.zeros_like(p.data)
buf.mul_(momentum).add_(d_p)
else:
buf = param_state['momentum_buffer']
buf.mul_(momentum).add_(1 - dampening, d_p)
if nesterov:
d_p = d_p.add(momentum, buf)
else:
d_p = buf
p.data.add_(-group['lr'], d_p)
return loss
经验总结:
在Fine-tuning时最好不要隔层设置层的参数的可学习与否,这样做一般效果饼不理想,一般准则即可,即先Fine-tuning分类层,学习率设置的大一些,然后在将整个网络设置一个较小的学习率,所有层一起训练。
至于不先经过Fine-tune分类层,而是将整个网络所有层一起训练,只是分类层的学习率相对设置大一些,这样做也可以,至于哪个效果更好,没评估过。当用三元组损失(triplet loss)微调用softmax loss训练的网络时,可以设置阶梯型的较小学习率,整个网络所有层一起训练,效果比较好,而不用先Fine-tune分类层前一层的输出。
来源:https://blog.csdn.net/xiexu911/article/details/81227126


猜你喜欢
- 导语学习一下golang权限控制,保留一下demo代码作为参考Casbin是什么Casbin是一个强大的、高效的开源访问控制框架,其权限管理
- 在 玉伯 的文章 《一道大题目,嘿嘿》 中有这样一段代码:[] == ![]也许很多同学迷惑:咦,这个如何转换呢?首先,我们了解下逻辑 NO
- Python操作注册表步骤之1.打开注册表对注册表进行操作前,必须打开注册表。在Python中,可以使用以下两个函数:RegOpenKey和
- 前言现在很多的直播平台或者视频平台都会用到弹幕加强和观众的互动效果,那么如何用JS实现这样的效果呢,用一个初学者的方法记录下这个方法,欢迎大
- 小程序中英文混合排序问题在开发一个手机联系人列表的功能时,遇到需求是需要将联系人列表按照拼音顺序排序。而联系人列表是会出现中英文混合的情况。
- 内容摘要:在网页制作中,有许多的术语,例如:CSS、HTML、DHTML、XHTML等等。在下面的文章中我们将会用到一些有关于HTML的基本
- 背景在爬取网站数据时,我们通常会遇到一些动态渲染页面的网站。传统的静态网站我们可以直接通过 requests.get() 函数获取页面源代码
- 最近做了一个小项目,里面有一个需求需要添加一个动态进度条,进度条的样式就类似于水波来回起伏的那种形状,下面就是最初的展示效果(有一点区别,这
- 在python中,普通的列表list和numpy中的数组array是不一样的,最大的不同是:一个列表中可以存放不同类型的数据,包括int、f
- 这篇文章主要介绍了python代码如何实现余弦相似性计算,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的
- 简要pyinstaller模块主要用于python代码打包成exe程序直接使用,这样在其它电脑上即使没有python环境也是可以运行的。用法
- 本文实例讲述了Python实现的数据结构与算法之基本搜索。分享给大家供大家参考。具体分析如下:一、顺序搜索顺序搜索 是最简单直观的搜索方法:
- 1.遍历列表需要对列表中的每个元素都执行相同的操作时,可使用for 循环:magicians = ['alice','
- 桑基图简介很多时候,我们需要一种必须可视化数据如何在实体之间流动的情况。例如,以居民如何从一个国家迁移到另一个国家为例。这里演示了有多少居民
- Python 安装Graphviz 详细教程Python安装Graphviz画图器首先,要明确他是一个独立的软件,如果大家用pip的方法装了
- 本文实例为大家分享了Django文件上传与下载的具体代码,供大家参考,具体内容如下Django1.4首先是上传:#settings.pyME
- 每次卷积神经网络训练的结果都只保存了最后一部分,查阅了一下相关资料,发现是定义saver时采用的默认值,这里进行如下设置: saver =
- HTTP(HyperTextTransferProtocol)是超文本传输协议的缩写,它用于传送WWW方式的数据,关于HTTP协议的详细内容
- 一、当我们用Python matplot时作图时,一些数据需要以百分比显示,以更方便地对比模型的性能提升百分比。二、借助matplotlib
- 开发高质量软件的过程中,我们经常会为每个函数编写测试,这样在开发过程中运行这些测试的时候就比较方便,doctest是一个python标准库自