百度飞桨 第二周实践-学习率调参及loss可视化


作为一名小白,跟随老师和助教们的脚步一直走到了现在,感受到了AI的魅力,同时对于飞桨的简洁易用性有了进一步的理解。
本周的实践问题:
通过查阅API,使用衰减学习率,通过多次调参数,找到一个最佳的衰减步长,使得loss比原代码中下降的更快
请自行绘制修改学习率前后的loss衰减图
注意:

  • 原代码中仅需要更改学习率部分
  • 若loss下降效果不明显,可自行调大epoch_num至10

学习率调度器

在刚开始检索飞桨API关于衰减学习率关键词时,只找到了三个衰减Api。
在这里插入图片描述
直到查找到了中文Api功能分类.在这里插入图片描述
飞桨对于学习率参数优化有一个明确的名词-学习率调度器。

定义

当我们使用诸如梯度下降法等方式来训练模型时,一般会兼顾训练速度和损失(loss)来选择相对合适的学习率。但若在训练过程中一直使用一个学习率,训练集的损失下降到一定程度后便不再继续下降,而是在一定范围内震荡。其震荡原理如下图所示,即当损失函数收敛到局部极小值附近时,会由于学习率过大导致更新步幅过大,每步参数更新会反复越过极小值而出现震荡。
在这里插入图片描述
学习率调度器定义了常用的学习率衰减策略来动态生成学习率,学习率衰减函数以epoch或step为参数,返回一个随训练逐渐减小的学习率,从而兼顾降低训练时间和在局部极小值能更好寻优两个方面。

以上是飞桨对于学习率调度器的明确定义。
同时,飞桨支持以下的学习率衰减Api:

  • noam_decay: 诺姆衰减。
  • exponential_decay: 指数衰减,即每次将当前学习率乘以给定的衰减率得到下一个学习率。
  • natural_exp_decay: 自然指数衰减,即每次将当前学习率乘以给定的衰减率的自然指数得到下一个学习率。
  • inverse_time_decay: 逆时间衰减,即得到的学习率与当前衰减次数成反比。
  • polynomial_decay: 多项式衰减,即得到的学习率为初始学习率和给定最终学习之间由多项式计算权重定比分点的插值。
  • piecewise_decay: 分段衰减,即由给定step数分段呈阶梯状衰减,每段内学习率相同。
  • append_LARS: 通过Layer-wise Adaptive Rate Scaling算法获得学习率,相关算法请参考 《Train Feedfoward Neural Network with Layer-wise Adaptive Rate via Approximating Back-matching Propagation》 。
  • cosine_decay: 余弦衰减,即学习率随step数变化呈余弦函数。
  • linear_lr_warmup: 学习率随step数线性增加到指定学习率。

梯度优化算法

本代码中采用的是MomentumOptimizer优化器,即动量优化算法。
在查阅相关资料后对其有了进一步的理解。
在说明Momentum之前首先需要明白何为SGD,即训练时,每次只从一批训练样本中随机选取一个样本进行梯度下降;对随机梯度下降来说,只需要一次关注一个训练样本,一点点把参数朝着全局最小值的方向进行修改了。
但是其缺点也很明显,SGD 在 ravines 的情况下容易被困住, ravines 就是曲面的一个方向比另一个方向更陡,如图,这时 SGD 会发生震荡而迟迟不能接近极小值:

在这里插入图片描述
这时引入Momentum ,通过加入 α v t − 1 \alpha v_{t-1} αvt1 ,可以加速 SGD, 并且抑制震荡。

{ v t = α v t − 1 + η t Δ J ( W t , X ( i s ) , Y ( i s ) ) W t + 1 = W t − v t \left\{ \begin{aligned} & v_t = \alpha v_{t-1} + \eta_t \Delta J(W_t, X^{(i_s)}, Y^{(i_s)} ) \\ & W_{t+1} = W_t - v_t \end{aligned} \right. {vt=αvt1+ηtΔJ(Wt,X(is),Y(is))Wt+1=Wtvt
可以这样理解,当我们将一个小球从山上滚下来时,没有阻力的话,它的动量会越来越大,但是如果遇到了阻力,速度就会变小。
加入的这一项,可以使得梯度方向不变的维度上速度变快,梯度方向有所改变的维度上的更新速度变慢,这样就可以加快收敛并减小震荡。
**超参数设定值: **
α \alpha α - 动量因子
一般 α \alpha α 取值 0.9 左右。

MomentumOptimizer优化器

看看飞桨对于这类Api的设计。

class paddle.fluid.optimizer.MomentumOptimizer(learning_rate, momentum, parameter_list=None, use_nesterov=False, regularization=None, grad_clip=None, name=None)

** 参数:**

  • learning_rate (float|Variable) - 学习率,用于参数更新。作为数据参数,可以是浮点型值或含有一个浮点型值的变量。
  • momentum (float) - 动量因子。
  • parameter_list (list, 可选) - 指定优化器需要优化的参数。在动态图模式下必须提供该参数;在静态图模式下默认值为None,这时所有的参数都将被优化。
  • use_nesterov (bool,可选) - 赋能牛顿动量,默认值False。
  • regularization (WeightDecayRegularizer,可选) - 正则化方法。支持两种正则化策略: L1Decay 、 L2Decay 。如果一个参数已经在 ParamAttr 中设置了正则化,这里的正则化设置将被忽略; 如果没有在 ParamAttr 中设置正则化,这里的设置才会生效。默认值为None,表示没有正则化。
  • grad_clip (GradientClipBase, 可选) – 梯度裁剪的策略,支持三种裁剪策略: GradientClipByGlobalNorm 、 GradientClipByNorm 、 GradientClipByValue 。 默认值为None,此时将不进行梯度裁剪。
  • name (str, 可选) - 可选的名称前缀,一般无需设置,默认值为None。

代码中,学习率给了0.001,动量因子默认值0.9。我们需要做的就是将学习率由定值变为衰减的变量。

opt = fluid.optimizer.Momentum(learning_rate=0.001, momentum=0.9, parameter_list=model.parameters())

在这里插入图片描述
这是为采用衰减学习率的情况,我们需要做的就是加快其loss下降速率。

cosine_decay余弦衰减

本次采用余弦衰减法。
cosine_decay是近些年才提出的一种衰减策略,基本形状是余弦函数。其方法是基于2017年的论文实现的:SGDR: Stochastic Gradient Descent with Warm Restarts

计算步骤如下:

global_step = min(global_step, decay_steps)
cosine_decay = 0.5 * (1 + cos(pi * global_step / decay_steps))
decayed = (1 - alpha) * cosine_decay + alpha
decayed_learning_rate = learning_rate * decayed
使用 cosine decay 的衰减方式进行学习率调整。

alpha的作用可以看作是baseline,保证lr不会低于某个值。不同alpha的影响如下:在这里插入图片描述
可以看出loss下降速率明显提高。
飞桨中Api设计:

paddle.fluid.layers.cosine_decay(learning_rate, step_each_epoch, epochs)

参数:

  • learning_rate (Variable | float) - 初始学习率。
  • step_each_epoch (int) - 一次迭代中的步数。
  • epochs - 总迭代次数。

基于飞桨Api,未修前loss下降曲线趋势:开始较快,之后一直在震荡。故选取同样的初始学习率0.001,将一次迭代中的步数设为500.同样是5个epochs。代码如下:

opt = fluid.optimizer.Momentum(learning_rate=fluid.dygraph.CosineDecay(0.001, 500,5), momentum=0.9, parameter_list=model.parameters())

在这里插入图片描述
可以看出,修改后的loss比原代码下降的更快。达到了快速下降的要求。

绘制loss可视化

采用matplotlib进行绘制,只需提取出迭代次数序列和对应的loss序列即可。

if batch_id % 10 == 0:
print(“epoch: {}, batch_id: {}, loss is: {}”.format(epoch, batch_id, avg_loss.numpy()))
iters_train.append(iter1_train)
losses_train.append(avg_loss.numpy())
iter1_train = iter1_train + 10

然而,训练时是调用该函数下,训练结束后iters_train和losses_train直接清除。无法保留用于绘图,在这里我采用global 定义全局变量,保留这两个变量。

global iter1_train
iter1_train = 0
global iters_train
iters_train=[]
global losses_train
losses_train=[]

训练结束后,添加绘图代码即可。

import matplotlib.pyplot as plt
plt.figure()
plt.title(“train loss”, fontsize=24)
plt.xlabel(“iter”, fontsize=14)
plt.ylabel(“loss”, fontsize=14)
plt.plot(iters_train, losses_train,color=‘red’,label=‘train loss’)
plt.grid()
plt.show()

至此,第二周实践完成。

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值