本文参考
PyTorch 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 beVariables
) 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
Optimizer
s also support specifying per-parameter options. To do this, instead of passing an iterable ofVariable
s, pass in an iterable ofdict
s. 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,第一个的params
key 对应的是model.base.parameters()
,而没有对Optimizer
的其他参数进行具体指定。第二个dict的params
key对应的是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 Gradient
,LBFGS
等需要多次重新计算函数,所以需要传入一个闭包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)
具体的各个优化算法的数学原理在此不表,详参手写的笔记本。
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
之前。
注:以上部分参考官方文档批示。
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.
参数说明
以下是实例:
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=lr∗gamma
如果觉得文章对您有帮助的话,可以点个赞,是对博主最大的肯定!