深度之眼 PyTorch 训练营第 4 期 (9):torch.optim

15 篇文章 1 订阅
15 篇文章 3 订阅

1. 优化器

优化器就是根据导数对参数进行更新的类,不同的优化器本质上都是梯度下降法,只是在实现的细节上有所不同。类似的,PyTorch 里的所有优化器都继承自 torch.optim.Optimizer 这个基类。

torch.optim.Optimizer(params, defaults)

params 是优化器要优化的权重,是一个迭代器;defaults 是优化器在参数以外的默认参数,根据所被继承的类有所不同。

1.1 优化器的种类

  • torch.optim.SGD(params, lr=<required parameter>, momentum=0, dampening=0, weight_decay=0, nesterov=False)

基础优化器,可以使用 momentum 来避免陷入 local minima。

  • torch.optim.ASGD:SGD 的改进版,使用平均随机梯度下降。

下面的若干种优化器都来自于同一个算法:Adaptive Gradient estimation,自适应梯度估计。

  • torch.optim.Rprop:实现 resilient backpropagation algorithm,弹性方向传播。不适用于 mini-batch,因此现在较少使用。
  • torch.optim.Adagrad:Adagrad 是一种自适应优化方法,是自适应的为各个参数分配不同的学习率。这个学习率的变化,会受到梯度的大小和迭代次数的影响。梯度越大,学习率越小;梯度越小,学习率越大。缺点是训练后期,学习率过小,因为 Adagrad 累加之前所有的梯度平方作为分母。
  • torch.optim.Adadelta:实现 Adadelta 优化方法。Adadelta 是 Adagrad 的改进。Adadelta分母中采用距离当前时间点比较近的累计项,这可以避免在训练后期,学习率过小。
  • torch.optim.RMSprop:实现 RMSprop 优化方法(Hinton提出),RMS 是均方根(root meam square)的意思。RMSprop 和 Adadelta 一样,也是对 Adagrad 的一种改进。RMSprop 采用均方根作为分母,可缓解 Adagrad 学习率下降较快的问题。并且引入均方根,可以减少摆动。
  • torch.optim.Adam:Adam 是对上面的自适应算法的改进,是一种自适应学习率的优化方法,Adam 利用梯度的一阶矩估计和二阶矩估计动态的调整学习率。吴老师课上说过,Adam 是结合了 Momentum 和 RMSprop,并进行了偏差修正。
  • torch.optim.Adamax:Adamax对Adam增加了一个学习率上限的概念。
  • torch.optim.SparseAdam:由于稀疏张量的优化器。
  • torch.optim.LBFGS:实现L-BFGS(Limited-memory Broyden–Fletcher–Goldfarb–Shanno)优化方法。L-BFGS属于拟牛顿算法。L-BFGS是对BFGS的改进,特点就是节省内存。

1.2 创建优化器

可以看出,Adam 优化器是集大成的优化器,一般无脑使用 Adam 即可。本文以 Adam 为例。

torch.optim.Adam(params, lr=0.001, betas=(0.9, 0.999), eps=1e-08, weight_decay=0, amsgrad=False)
  • params (iterable):可用于迭代优化的参数或者定义参数组的dicts。
  • lr (float, optional) :学习率(默认: 1e-3)
  • betas (Tuple[float, float], optional):用于计算梯度的平均和平方的系数(默认:(0.9, 0.999))
  • eps (float, optional):为了提高数值稳定性而添加到分母的一个项(默认:1e-8)
  • weight_decay (float, optional):权重衰减(如 L2 惩罚,默认: 0)

对于 torch.optim.Adam 来说,只有 params 是必要的属性。可以以如下方法进行创建:

optimizer = optim.Adam(model.parameters(), lr=0.0001)

也可以指定每个参数选项。 只需传递一个可迭代的 dict 来替换先前可迭代的 Variable。dict 中的每一项都可以定义为一个单独的参数组,参数组用一个 params 键来包含属于它的参数列表。其他键应该与优化器接受的关键字参数相匹配,才能用作此组的优化选项。比如:

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

如上,model.base.parameters() 将使用 1e-2 的学习率,model.classifier.parameters() 将使用 1e-3 的学习率。0.9 的 momentum 作用于所有的 parameters。

1.3 优化器的属性

因为优化器都继承自 torch.optim.Optimizer,所以它们的属性相同。我们先构建一个优化器的实例:

>>> weight1 = torch.ones((2, 2))
>>> optimizer = torch.optim.Adam([weight], lr=1e-2)

>>> print(optimizer)
Adam (
Parameter Group 0
    amsgrad: False
    betas: (0.9, 0.999)
    eps: 1e-08
    lr: 0.01
    weight_decay: 0
)
  • param_group
    返回优化器的参数组。参数组是一个列表,每个元素是一个组的字典。
>>> print(optimizer.param_groups)
[{'params': [tensor([[1., 1.],
        [1., 1.]], requires_grad=True)], 'lr': 0.01, 'betas': (0.9, 0.999), 'eps': 1e-08, 'weight_decay': 0, 'amsgrad': False}]
  • add_param_group(param_group)
    添加参数组。
>>> weight2 = torch.zeros(2,2)
>>> optimizer.add_param_group({'params':weight2, 'lr':0.01})

>>> optimizer.param_groups
[{'params': [tensor([[1., 1.],
           [1., 1.]], requires_grad=True)],
  'lr': 0.01,
  'betas': (0.9, 0.999),
  'eps': 1e-08,
  'weight_decay': 0,
  'amsgrad': False},
 {'params': [tensor([[0., 0.],
           [0., 0.]])],
  'lr': 0.01,
  'betas': (0.9, 0.999),
  'eps': 1e-08,
  'weight_decay': 0,
  'amsgrad': False}]
  • state_dict()
    返回优化器的状态。这个属性与 param_group 的区别在于 state_dict() 的返回值包含了梯度的状态。
>>> optimizer.state_dict()
{'state': {}, # 进行反向传播以前梯度为空
 'param_groups': [{'lr': 0.01,
   'betas': (0.9, 0.999),
   'eps': 1e-08,
   'weight_decay': 0,
   'amsgrad': False,
   'params': [140685302219312]}]}

>>> optimizer.step()
>>> optimizer.state_dict()
{'state': {140685302219312: {'step': 1, # 反向传播以后有了状态
   'exp_avg': tensor([[0.1000, 0.1000],
           [0.1000, 0.1000]]),
   'exp_avg_sq': tensor([[0.0010, 0.0010],
           [0.0010, 0.0010]])}},
 'param_groups': [{'lr': 0.01,
   'betas': (0.9, 0.999),
   'eps': 1e-08,
   'weight_decay': 0,
   'amsgrad': False,
   'params': [140685302219312]},
  {'lr': 0.01,
   'betas': (0.9, 0.999),
   'eps': 1e-08,
   'weight_decay': 0,
   'amsgrad': False,
   'params': [140685312958784]}]}
  • load_state_dict(state_dict)
  • 载入已经保存的参数组。这个属性与模型的保存于载入一并介绍。
  • step()
    执行一次反向传播。
  • zero_grad()
    将优化器内存储的梯度清零。

2. 改变学习率

torch.optim.lr_scheduler 中提供了基于多种 epoch 数目调整学习率的方法。优化器需要被包含进 scheduler 实例里。调整学习率的函数有很多,这里仅列举了常用的 4 种。

>>> scheduler = ...(optimizer, ...) #优化器被包含进来
>>> for epoch in range(100):
>>>     train(...)
>>>     validate(...)
>>>     scheduler.step()
  • torch.optim.lr_scheduler.LambdaLR(optimizer, lr_lambda, last_epoch=-1):将每一个参数组的学习率设置为初始学习率 lr 的某个函数倍;
>>> # Assuming optimizer has two groups.
>>> lambda1 = lambda epoch: epoch // 30
>>> lambda2 = lambda epoch: 0.95 ** epoch
>>> scheduler = LambdaLR(optimizer, lr_lambda=[lambda1, lambda2])
>>> for epoch in range(100):
>>>     train(...)
>>>     validate(...)
>>>     scheduler.step()
  • torch.optim.lr_scheduler.MultiplicativeLR(optimizer, lr_lambda, last_epoch=-1):设置每个参数组的学习率为 l r ∗ λ n , n = e p o c h s t e p _ s i z e lr*\lambda^n,n=\frac{epoch}{step\_size} lrλn,n=step_sizeepoch
>>> lmbda = lambda epoch: 0.95
>>> scheduler = MultiplicativeLR(optimizer, lr_lambda=lmbda)
>>> for epoch in range(100):
>>>     train(...)
>>>     validate(...)
>>>     scheduler.step()
  • torch.optim.lr_scheduler.StepLR(optimizer, step_size, gamma=0.1, last_epoch=-1):设置每个参数组的学习率在每 step_size 时变化一次;
>>> # 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()
  • torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones, gamma=0.1, last_epoch=-1):设置每个参数组的学习率在达到 milestone 时变化。
>>> # Assuming optimizer uses lr = 0.05 for all groups
>>> # lr = 0.05     if epoch < 30
>>> # lr = 0.005    if 30 <= epoch < 80
>>> # lr = 0.0005   if epoch >= 80
>>> scheduler = MultiStepLR(optimizer, milestones=[30,80], gamma=0.1)
>>> for epoch in range(100):
>>>     train(...)
>>>     validate(...)
>>>     scheduler.step()
  • torch.optim.lr_scheduler.ExponentialLR(optimizer, gamma, last_epoch=-1):按照指数方式调整学习率: lr = lr ∗ g a m m a e p o c h \text{lr}=\text{lr}*gamma^{epoch} lr=lrgammaepoch
  • `
    它们的公共参数:
  • lr_lambda:描述学习率变化的匿名函数;
  • gamma:倍数系数;
  • last_epoch:最后一次 epoch 的索引,若为 -1 则为初始 epoch。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值