在用pytorch训练模型时,通常会在遍历epochs的过程中依次用到
optimizer.zero_grad()
,
loss.backward()
和
optimizer.step()
三个函数,如下所示:
model = MyModel()
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.001, momentum=0.9, weight_decay=1e-4)
for epoch in range(1, epochs):
for i, (inputs, labels) in enumerate(train_loader):
output= model(inputs)
loss = criterion(output, labels)
# compute gradient and do SGD step
optimizer.zero_grad()
loss.backward()
optimizer.step()
总得来说,这三个函数的作用是先将梯度归零(optimizer.zero_grad()),然后反向传播计算得到每个参数的梯度值(loss.backward()),最后通过梯度下降执行一步参数更新(optimizer.step())
接下来将通过源码分别理解这三个函数的具体实现过程。在此之前,先简要说明一下函数中常见的参数变量:
param_groups:
Optimizer类在实例化时会在构造函数中创建一个param_groups列表,列表中有num_groups个长度为6的param_group字典(num_groups取决于你定义optimizer时传入了几组参数),每个param_group包含了 ['params', 'lr', 'momentum', 'dampening', 'weight_decay', 'nesterov'] 这6组键值对。
param_group['params']:
由传入的模型参数组成的列表,即实例化Optimizer类时传入该group的参数,如果参数没有分组,则为整个模型的参数model.parameters(),每个参数是一个torch.nn.parameter.Parameter对象。
一、
optimizer.zero_grad():
def zero_grad(self):
r"""Clears the gradients of all optimized :class:`torch.Tensor` s."""
for group in self.param_groups:
for p in group['params']:
if p.grad is not None:
p.grad.detach_()
p.grad.zero_()
optimizer.zero_grad()函数会遍历模型的所有参数,通过p.grad.detach_()方法截断反向传播的梯度流,再通过p.grad.zero_()函数将每个参数的梯度值设为0,即上一次的梯度记录被清空。
因为训练的过程通常使用mini-batch方法,所以如果不将梯度清零的话,梯度会与上一个batch的数据相关,因此该函数要写在反向传播和梯度下降之前。
二、
loss.backward():
PyTorch的反向传播(即tensor.backward())是通过autograd包来实现的,autograd包会根据tensor进行过的数学运算来自动计算其对应的梯度。
具体来说,torch.tensor是autograd包的基础类,如果你设置tensor的requires_grads为True,就会开始跟踪这个tensor上面的所有运算,
如果你做完运算后使用tensor.backward(),所有的梯度就会自动运算,tensor的梯度将会累加到它的.grad属性里面去。
更具体地说,损失函数loss是由模型的所有权重w经过一系列运算得到的,若某个w的requires_grads为True,则w的所有上层参数(后面层的权重w)的.grad_fn属性中就保存了对应的运算,然后在使用loss.backward()后,会一层层的反向传播计算每个w的梯度值,并保存到该w的.grad属性中。
如果没有进行tensor.backward()的话,梯度值将会是None,因此loss.backward()要写在optimizer.step()之前。
三、
optimizer.step():
以SGD为例,torch.optim.SGD().step()源码如下:
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.clone(d_p).detach()
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
step()函数的作用是执行一次优化步骤,通过梯度下降法来更新参数的值。因为梯度下降是基于梯度的,所以
在执行optimizer.step()函数前应先执行loss.backward()函数来计算梯度。
注意:optimizer只负责通过梯度下降进行优化,而不负责产生梯度,梯度是tensor.backward()方法产生的。
参考:
https://www.cnblogs.com/Thinker-pcw/p/9630367.html
这三个函数的
作用
是将梯度归零(
optimize
r.
zero
_
grad
()),然后反向传播计算得到每个参数的梯度值(
loss
.back
war
d()),最后通过梯度下降执行一步参数更新(
optimize
r.
step
())。简单的说就是进来一个batch的数据,先将梯度归零,计算一次梯度,更新一次网络。另外一种:将**
optimize
r.
zero
_
grad
()放在
optimize
r.
step
()**后面,即梯度累加。获取
loss
:输入图像和标签,通过infer计算得到预测值,计算损失函数;
在深度学习和机器学习领域中,"
optimize
r"(优化器)是指一种用于优化模型参数以最小化损失函数的算法或工具。优化器的主要任务是更新模型的权重或参数,使其逐渐收敛到损失函数的最小值或局部最小值,从而提高模型的性能。优化器在训练神经网络等机器学习模型时非常重要,因为模型参数的更新通常依赖于损失函数的梯度。这三行代码通常组成了深度学习模型训练的核心循环。在整个训练过程中,它们会被重复执行多次,模型的参数会根据损失函数的梯度逐渐调整,以最小化损失并提高模型性能。
在用pytorch训练模型时,通常会在遍历epochs的过程中依次用到
optimize
r.
zero
_
grad
(),
loss
.back
war
d、和
optimize
r.
step
()、lr_scheduler.
step
()四个函数,使用如下所示:
train_loader=DataLoader(
train_dataset,
batch_size=2,
shuffle=True
model=myModel()
criterion=nn.CrossEntropy
Loss
()
转载自知乎:PyTorch中在反向传播前为什么要手动将梯度清零? - Pascal的回答 - 知乎
传统的训练函数,一个batch是这么训练的:
for i,(images,target) in enumerate(train_loader):
# 1. input output
images = images.cuda(non_blocking=True)
target ...
1. 前言优化器主要用在模型训练阶段,用于更新模型中可学习的参数。torch.optim[1]提供了多种优化器接口,比如Adam、RAdam、SGD、ASGD、LBFGS等,
Optimize
r是所有这些优化器的父类。2.
Optimize
r行为解析2.1 公共方法
Optimize
r是所有优化器的父类,它主要具有以下几类公共方法:方法名官方注解说明add_param_gro...
optimize
r.
zero
_
grad
()意思是把梯度置零,也就是把
loss
关于weight的导数变成0.
在学习pytorch的时候注意到,对于每个batch大都执行了这样的操作:
#
zero
the parameter
grad
ients
optimize
r.
zero
_
grad
()
# for
war
d + back
war
d + optim...
optimize
r.
zero
_
grad
() 功能
梯度初始化为零,把
loss
关于weight的导数变成0
为什么每一轮batch都需要设置
optimize
r.
zero
_
grad
根据pytorch中的back
war
d()函数的计算,当网络参量进行反馈时,梯度是被积累的而不是被替换掉。
但是在每一个batch时毫无疑问并不需要将两个batch的梯度混合起来累积,因此这里就需要每个batch设置一遍
zero
_
grad
了
每个batch必定执行的操作步骤
optimize
r.
zero
_
grad
() # 梯度初始
`
optimize
r.
step
()`是PyTorch中优化器对象的一个方法,用于更新模型的参数。在训练深度神经网络的过程中,我们需要通过反向传播算法计算每一个参数对损失函数的梯度,然后使用优化器更新参数,使得损失函数最小化。而`
optimize
r.
step
()`方法就是用于执行参数更新的。
例如,常用的优化算法如 Adam、SGD 等,都有自己的更新规则,
optimize
r.
step
() 会按照相应的规则更新网络参数的值。先使用
optimize
r.
zero
_
grad
() 用于清空优化器中的梯度,再前向传播,计算
loss
,再
loss
.back
war
d()计算梯度,再用
optimize
r.
step
()更新梯度。
loss
.back
war
d() 是 PyTorch 中用于自动求导的函数,它的主要
作用
是计算损失函数对模型参数的梯度,从而实现反向传播算法。
通过②和③的对比,能看出
optimize
r.
zero
_
grad
() 的
作用
是清除之前累积的梯度值。,lr 表示学习率 learning rate,减号表示沿着梯度的反方向进行更新;这一步会计算所有变量x的梯度值。3--
optimize
r.
zero
_
grad
()的用法。,一般在
loss
.back
war
d()前使用,即清除。2--
optimize
r.
step
()的用法。
作用
:清除优化器关于所有参数x的累计梯度值。1--
loss
.back
war
d()的用法。指的是上一个epoch累积的梯度。