PyTorch学习笔记:torch.optim---Optimizer以及lr_scheduler

本文参考
PyTorch optim文档

1 概述

1.1 PyTorch文档:torch.optim解读

下图是optim的文档

TORCH.OPTIM

torch.optim is a package implementing various optimization algorithms. Most commonly used methods are already supported, and the interface is general enough, so that more sophisticated ones can be also easily integrated in the future.

torch.optim简介
torch.optim是PyTorch实现的一个包,里面有各种各样的优化算法,大部分常用的优化算法都已经被支持,接口也十分通用,所以可以用来集成实现更加复杂的系统。

How to use an optimizer

To use torch.optim you have to construct an optimizer object, that will hold the current state and will update the parameters based on the computed gradients.

如何使用PyTorch提供的optimizer
通过torch.optim来创建一个Optimizer对象,这个对象中会保存当前的状态,并且会根据计算的梯度值更新参数。

Constructing it

To construct an Optimizer you have to give it an iterable containing the parameters (all should be Variables) to optimize. Then, you can specify optimizer-specific options such as the learning rate, weight decay, etc.

NOTE

If you need to move a model to GPU via .cuda(), please do so before constructing optimizers for it. Parameters of a model after .cuda() will be different objects with those before the call.
In general, you should make sure that optimized parameters live in consistent locations when optimizers are constructed and used.

构造Optimizer
构造Optimizer时,需要传入一个包含需要进行优化的所有参数的iterable对象,所有参数都必须是Variables类型。随后可以进一步设置optimizer的其他具体参数,如learning rate, weight decay, etc.
注意:
如果需要将模型移到cuda上(通过.cuda命令),那么必须先移动模型,再对模型构造optimizer。因为调用.cuda前的模型参数与调用.cuda后的模型参数不同。
通常来讲,在使用Optimizer对参数进行优化时,需要保证构造和使用时,被优化的参数保存在同一位置。

以下是实例:

Example:

optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)
optimizer = optim.Adam([var1, var2], lr=0.0001)
Per-parameter options

Optimizers also support specifying per-parameter options. To do this, instead of passing an iterable of Variables, pass in an iterable of dicts. Each of them will define a separate parameter group, and should contain a params key, containing a list of parameters belonging to it. Other keys should match the keyword arguments accepted by the optimizers, and will be used as optimization options for this group.

NOTE

You can still pass options as keyword arguments. They will be used as defaults, in the groups that didn’t override them. This is useful when you only want to vary a single option, while keeping all others consistent between parameter groups.

Per-parameter option
我个人翻译为逐参数选项。Optimizer在构造的时候同样支持对每个参数进行指定。要实现这种功能,我们不再传入一个含有Variable类型参数的iterable对象,而是传入一个dict字典类型的iterable对象。每个字典都定义了一个参数组,该参数组的key值是"params",而对应的值为一个包含参数的列表。同样的可以利用字典的键值对Optimizer的其他参数进行指定,但是key必须与Optimizer构造器传参时的关键字一致。这些指定的Optimizer的参数会被单独应用于该字典中的params这些参数。
注意:你仍然可以在构造器中以关键字方式传入参数,这些参数将被当做默认值使用,如果一组参数没有override这个参数,那么就将自动使用默认的参数值。
以下是实例:

For example, this is very useful when one wants to specify per-layer learning rates:

optim.SGD([
               {'params': model.base.parameters()},
               {'params': model.classifier.parameters(), 'lr': 1e-3}
           ], lr=1e-2, momentum=0.9)

This means that model.base’s parameters will use the default learning rate of 1e-2, model.classifier’s parameters will use a learning rate of 1e-3, and a momentum of 0.9 will be used for all parameters.

对于上面这个例子,首先我们可以看到,传入了一个dict的列表。列表中有两个dict,第一个的paramskey 对应的是model.base.parameters(),而没有对Optimizer的其他参数进行具体指定。第二个dict的paramskey对应的是model.classifier.parameters(),此外还有一个键值对,说明了lr的值为1e-3。而在列表之外同时又传入了lr=1e-2,momentum=0.9,这两个值将作为默认值来使用。所以整个Optimizer中,base's parameters将使用默认的学习率1e-2,默认的动量超参数0.9;而classifier.parameters()将使用其dict中提供的学习率1e-3,momentum仍然使用默认值。

Taking an optimization step

All optimizers implement a step() method, that updates the parameters. It can be used in two ways:

optimizer.step()

This is a simplified version supported by most optimizers. The function can be called once the gradients are computed using e.g. backward().

采取优化步骤
所有的Optimizer都实现了step()方法,该方法可以用于更新参数。可以通过两种方式使用.step()进行优化:

第一种方式:optimizer.step()
该方法是一个简化后的版本,被大多数optimizer所支持。该函数一般在所有梯度值被更新(或者被计算)后进行调用,如在.backward()后进行调用。

以下是例子:

Example:

for input, target in dataset:
   optimizer.zero_grad()
   output = model(input)
   loss = loss_fn(output, target)
   loss.backward()
   optimizer.step()
optimizer.step(closure)

Some optimization algorithms such as Conjugate Gradient and LBFGS need to reevaluate the function multiple times, so you have to pass in a closure that allows them to recompute your model. The closure should clear the gradients, compute the loss, and return it.

第二种方式:optimizer.step(closure)
有一些优化算法例如Conjugate GradientLBFGS等需要多次重新计算函数,所以需要传入一个闭包closure,闭包中应该实现的操作有:清零梯度,计算损失并返回。
以下是例子:

Example:

for input, target in dataset:
   def closure():
       optimizer.zero_grad()
       output = model(input)
       loss = loss_fn(output, target)
       loss.backward()
       return loss
   optimizer.step(closure)

具体的各个优化算法的数学原理在此不表,详参手写的笔记本。

2 如何调整学习率

torch.optim.lr_scheduler模块,提供了一些根据训练次数来调整学习率(learning rate)的方法,一般情况下我们会设置随着epoch的增大而逐渐减小学习率,从而达到更好的训练效果。
torch.optim.lr_scheduler.ReduceLROnPlateau提供了一些基于训练中某些测量值使得学习率动态下降的办法。

学习率的调整应该放在optimizer更新之后,参考模板:

define scheduler
for epoch in range(1000):
    train(...)
    validate(...)
    scheduler.step()

注意: 在PyTorch 1.1.0之前的版本,学习率的调整应该被放在optimizer更新之前,如果我们1.1.0之后仍然将学习率的调整(即scheduler.step())放在optimizer’s update(即optimizer.step)之前,那么learning rate schedule的第一个值将被跳过。所以如果某个代码是在1.1.0之前的版本开发,移植到高版本进行运行,发现效果变差,可以检查是否将scheduler.step()放在了optimizer.step之前。

注:以上部分参考官方文档批示。

2.1 torch.optim.lr_scheduler.StepLR

首先贴上官方文档:

torch.optim.lr_scheduler.StepLR(optimizer, step_size, gamma=0.1, last_epoch=-1, verbose=False)

Decays the learning rate of each parameter group by gamma every step_size epochs. Notice that such decay can happen simultaneously with other changes to the learning rate from outside this scheduler. When last_epoch=-1, sets initial lr as lr.

StepLR可以根据超参数gamma每隔固定的step_size就衰减learning_rate一次。需要说明的是,这种对learning_rate的更新可以与外界的其他变化同时进行。当last_epoch = -1时,将lr置为初始值。

Parameters

  • optimizer (Optimizer) – Wrapped optimizer.
  • step_size (int) – Period of learning rate decay.
  • gamma (float) – Multiplicative factor of learning rate decay. Default: 0.1.
  • last_epoch (int) – The index of last epoch. Default: -1.
  • verbose (bool) – If True, prints a message to stdout for each update. Default: False.

参数说明

  • optimizer(Optimizer) -----用于指定scheduler的应用对象。
  • step_size(int)-----用于指定步长,即几次迭代之后进行一次decay
  • gamma(float)-----学习率衰减的乘法因子,默认值为0.1
  • last_epoch(int)-----更新的边界index,当等于这个值的时候,重置lr,默认为-1
  • verbose(bool)-----如果为True,每次decay会向stdout输出一条信息。默认为false.

以下是实例:

Example

# Assuming optimizer uses lr = 0.05 for all groups
# lr = 0.05     if epoch < 30
# lr = 0.005    if 30 <= epoch < 60
# lr = 0.0005   if 60 <= epoch < 90
# ...
scheduler = StepLR(optimizer, step_size=30, gamma=0.1)
for epoch in range(100):
    train(...)
    validate(...)
    scheduler.step()

可见:每经过一个step_size

l r = l r ∗ g a m m a lr = lr*gamma lr=lrgamma


如果觉得文章对您有帮助的话,可以点个赞,是对博主最大的肯定!

  • 14
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
torch.optim.lr_scheduler.LambdaLRPyTorch中的学习率调度器。它允许我们通过自定义函数来调整优化器的学习率。具体来说,我们可以定义一个接受一个整数参数epoch并返回一个浮点数的函数,该函数的返回值将作为相应时期的学习率因子。也就是说,如果在第epoch个时期调用该函数,那么这个时期的学习率将被设置为当前学习率乘上lr_lambda(epoch)的返回值。我们可以通过传入优化器对象和lr_lambda函数来创建一个LambdaLR对象,然后在训练过程中使用scheduler.step()来更新学习率。\[2\] 举个例子,假设我们想每3个epoch将学习率减半,我们可以定义一个规则函数,如下所示: ```python import torch from torch import nn import math class Net(nn.Module): def __init__(self): super().__init__() self.conv = nn.Conv2d(in_channels=1, out_channels=1, kernel_size=2, stride=1, padding=0) def forward(self, x): out = self.conv(x) return out net = Net() def rule(epoch): lamda = math.pow(0.5, int(epoch / 3)) return lamda optimizer = torch.optim.SGD(\[{'params': net.parameters(), 'initial_lr': 0.1}\], lr=0.1) scheduler = torch.optim.lr_scheduler.LambdaLR(optimizer, lr_lambda=rule) for i in range(9): print("lr of epoch", i, "=>", scheduler.get_lr()) optimizer.step() scheduler.step() ``` 在这个例子中,我们定义了一个包含一个卷积层的神经网络模型Net,并定义了一个规则函数rule,该函数根据epoch的值返回一个学习率因子。然后,我们创建了一个SGD优化器对象optimizer和一个LambdaLR学习率调度器对象scheduler,并在每个epoch中使用optimizer.step()来更新模型参数,使用scheduler.step()来更新学习率。最后,我们打印出每个epoch的学习率。\[3\] #### 引用[.reference_title] - *1* *2* [【pytorchtorch.optim.lr_scheduler.LambdaLR() 学习率调整](https://blog.csdn.net/weixin_37804469/article/details/110939799)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Pytorch lr_scheduler.LambdaLR()的简单理解与用法](https://blog.csdn.net/qq_40714949/article/details/126287769)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值