在之前的文章了,我们学习了SGD,以及在其基础上加了一阶动量的SGD Momentum,还有在其基础上加了二阶动量的AdaGrad、AdaDelta、RMSProp。那么自然而然就会想到把一阶动量和二阶动量结合起来,这样就形成了我们常用的优化器Adam:Adaptive+Momentum。


类似于Momentum,Adam使用了一阶动量的窗口衰减累加,公式如下:

m_{t}=\beta_{1}\cdot m_{t-1}+(1-\beta _{1}))\cdot g_{t}

其中,m_{t}为当前step的一阶动量,m_{t-1}为上一个step的一阶动量,\beta _{1}为历史一阶动量保留率

类似于RMSProp,Adam使用了二阶动量的窗口衰减累加,公式如下:

V_{t}=\beta_{2}\cdot V_{t-1}+(1-\beta _{2}))\cdot g_{t}^{2}

其中,V_{t}为当前step的二阶动量,V_{t-1}为上一个step的二阶动量,\beta _{2}为历史二阶动量的衰减率。

最终的更新公式为:

\Delta w _{t}=\alpha \cdot \frac{m_{t}}{\sqrt{V_{t}+\epsilon }}

其中,\epsilon为增加分母稳定性的系数,\alpha为学习率。


其实我们回过头看,Adam其实存在可能不收敛的问题。因为对SGD而言,学习率是固定的,但是一般会使用scheduler使得学习率不断衰减,所以最终是会收敛的。而对AdaGrad而言,二阶动量的不断累加会导致学习率不断趋近于0最终收敛(虽然不一定能到最优解)。但是对Adam来说,由于二阶动量的突变性,可能在后期时引起学习率的震荡。


Adam的伪代码流程如下,可以看到两个输入的参数\beta _{1}\beta _{2}就是我们常设置的两个超参数,一班设为0.9和0.999。同时我们可以看到伪代码里分别对m_{t}V_{t}除以1-\beta,这一步其实是在做偏差纠正,因为当t=0的时候,并没有历史向量,所以m_{t}V_{t}的系数直接为1-\beta,这就意味着当\beta较大的时候,更新速度较慢,所以除以一个系数来进行纠正。

以下代码为pytorch官方Adam的代码。

 

业务合作/学习交流+v:lizhiTechnology

?如果想要了解更多优化器相关知识,可以参考我的专栏和其他相关文章:

优化器_Lcm_Tech的博客-CSDN博客

【优化器】(一) SGD原理 & pytorch代码解析_sgd优化器-CSDN博客

【优化器】(二) AdaGrad原理 & pytorch代码解析_adagrad优化器-CSDN博客

【优化器】(三) RMSProp原理 & pytorch代码解析_rmsprop优化器-CSDN博客

【优化器】(四) AdaDelta原理 & pytorch代码解析_adadelta里rho越大越敏感-CSDN博客

【优化器】(五) Adam原理 & pytorch代码解析_adam优化器-CSDN博客

【优化器】(六) AdamW原理 & pytorch代码解析-CSDN博客

【优化器】(七) 优化器统一框架 & 总结分析_mosec优化器优点-CSDN博客

如果想要了解更多深度学习相关知识,可以参考我的其他文章:

【损失函数】(一) L1Loss原理 & pytorch代码解析_l1 loss-CSDN博客

【图像生成】(一) DNN 原理 & pytorch代码实例_pytorch dnn代码-CSDN博客