pytorch optimizer.step()和loss.backward()和scheduler.step()的关系与区别

疑问:

optimizer的step为什么不能放在mini-batch那个循环之外,optimizer.step和loss.backward的区别;

解惑:

首先需要明确optimizer优化器的作用,形象地说,优化器就是需要根据网络反向传播的梯度信息来更新网络参数,以起到降低loss函数计数值的作用,这也是机器学习中最一般的方法论。

从优化器的作用出发,需要使得优化器能够起作用,主要需要两个东西:1.优化器需要知道当前的网络的参数空间,这也是为什么在训练文件中,正式开始训练之前需要将网络参数放到优化器里面,比如使用Pytorch的话总会出现类似如下的代码:

 2. 需要知道反向传播的梯度信息,我们还是从代码入手,如下所示是pytorch中SGD优化算法的step()函数具体写法,具体SGD的写法放在参考部分。

 1 def step(self, closure=None):
 2         """Performs a single optimization step.
 3         Arguments:
 4             closure (callable, optional): A closure that reevaluates the model
 5                 and returns the loss.
 6         """
 7         loss = None
 8         if closure is not None:
 9             loss = closure()
10 
11         for group in self.param_groups:
12             weight_decay = group['weight_decay']
13             momentum = group['momentum']
14             dampening = group['dampening']
15             nesterov = group['nesterov']
16 
17             for p in group['params']:
18                 if p.grad is None:
19                     continue
20                 d_p = p.grad.data
21                 if weight_decay != 0:
22                     d_p.add_(weight_decay, p.data)
23                 if momentum != 0:
24                     param_state = self.state[p]
25                     if 'momentum_buffer' not in param_state:
26                         buf = param_state['momentum_buffer'] = d_p.clone()
27                     else:
28                         buf = param_state['momentum_buffer']
29                         buf.mul_(momentum).add_(1 - dampening, d_p)
30                     if nesterov:
31                         d_p = d_p.add(momentum, buf)
32                     else:
33                         d_p = buf
34 
35                 p.data.add_(-group['lr'], d_p)
36 
37         return loss

从上面的代码可以看到step这个函数使用的是参数空间(param_groups)中的grad,也就是当前参数空间对应的梯度,这也就解释了为什么optimizer使用之前需要zero清零,因为如果不清零,那么使用的这个grad就同上一个Mini-batch有关,这不是我们需要的结果。再回过头来看,我们知道optimizer更新参数空间需要基于反向梯度,因为,当调用optimizer.step()的时候应当在loss.backward()之后。这也是经常会碰到的,代码示意如下:

 loss.backward()在前

optimizer.step()在后。顺序不可颠倒。

那么为什么optimizer.step()需要放在每个batch训练中,而不是epoch训练中,这是因为mini-batch训练模式是嘉定每一个训练集就只有mini-batch大小,因此实际上可以将每一次Mini-batch看做是一次训练,一次训练更新一次参数空间,因为optimizer.step()放在每个Mini-batch中。

scheduler.step()按照pytorch的定义是用来更新优化器学习率的,一般是按照epoch为单位进行更换,即多少个epoch后更换一次学习率,因而scheduler.step()放在epoch这个大循环中。

Pytorch SGD代码:https://github.com/pytorch/pytorch/blob/cd9b27231b51633e76e28b6a34002ab83b0660fc/torch/optim/sgd.py#L63

原文连接:https://blog.csdn.net/xiaoxifei/article/details/87797935

原文地址:https://www.cnblogs.com/elitphil/p/15543074.html