跳至主要內容

optimizer优化器

Genhiy...大约 3 分钟AI优化器

指数加权平均

我们考虑以下场景:你开了一家店,需要根据前几年的收入预测今年收入,也就是序列数据的预测问题。这时候最简单的就是取平均值,但是这样就损失了序列数据的特点,即时间上越靠近现在,其数值对当前的影响越大。此时,我们可以使用指数加权平均:

V0=0Vt=βVt1+(1β)θt \begin{aligned}&V_0=0\\&V_t=\beta V_{t-1}+(1-\beta)\theta_t\end{aligned}

也即:

V0=0,β=0.7V1=0.7V0+0.3θ1V2=0.7V1+0.3θ2V3=0.7V2+0.3θ3V4=0.7V3+0.3θ4V5=0.7V4+0.3θ5V6=0.7V5+0.3θ6 \begin{aligned} &V_{0}=0, \beta=0.7 \\ &V_{1}=0.7V_{0}+0.3\theta_{1} \\ &V_{2}=0.7V_{1}+0.3\theta_{2} \\ &V_{3}=0.7V_{2}+0.3\theta_{3} \\ &V_{4}=0.7V_{3}+0.3\theta_{4} \\ &V_5=0.7V_4+0.3\theta_5 \\ &V_6=0.7V_5+0.3\theta_6 \end{aligned}

代入可得:

V6=0.7(0.7V4+0.3θ5)+0.3θ6V6=0.72V4+0.30.7θ5+0.3θ6V6=0.72(0.7V3+0.3θ4)+0.30.7θ5+0.3θ6V6=0.73V3+0.30.72θ4+0.30.7θ5+0.3θ6=0.343V3+0.147θ4+0.21θ5+0.3θ6 \begin{aligned} &V_{6} =0.7(0.7V_4+0.3\theta_5)+0.3\theta_6 \\ &V_{6} =0.7^2V_4+0.3*0.7\theta_5+0.3\theta_6 \\ &V_{6} =0.7^2(0.7V_3+0.3\theta_4)+0.3*0.7\theta_5+0.3\theta_6 \\ &V_{6} =0.7^3V_3+0.3*0.7^2\theta_4+0.3*0.7\theta_5+0.3\theta_6 \\ &=0.343V_{3}+0.147\theta_{4}+0.21\theta_{5}+0.3\theta_{6} \end{aligned}

所以我们能够看到,之前的数值将以指数模式衰减,所以被称之为指数加权平均。

但是,当我们计算每天的V时,我们会发现,前几天的V会偏小,因为我们的V是按0进行初始化的,这时,我们进行一些修正:

Vtcorrect=Vt1βt V_t^{correct}=\frac{V_t}{1-\beta^t}

θV1βtVcorrect第一天100300.3100第二天11455.20.51108.2第三天11874.040857112.6第四天11786.90.76114.3第五天12096.830.852116.4第六天122104.380.942110.8第七天???? \begin{array}{|c|c|c|c|c|c|} \hline&\theta&V&1-\beta^t&V^{correct} \\ \hline\text{第一天}&100&30&0.3&100 \\ \hline\text{第二天}&114&55.2&0.51&108.2 \\ \hline\text{第三天}&118&74.04&0857&112.6 \\ \hline\text{第四天}&117&86.9&0.76&114.3 \\ \hline\text{第五天}&120&96.83&0.852&116.4 \\ \hline\text{第六天}&122&104.38&0.942&110.8 \\ \hline\text{第七天}&?&?&?&? \\ \hline\end{array}

Momentum

在神经网络中,我们会计算各个参数的梯度,然后朝梯度的反方向更新参数,但是这时候有一个问题,神经网络参数很多,参数梯度有时大有时小,有时正有时负,这会让我们的训练不稳定。那么如何稳定梯度呢?我们可以用梯度的指数加权平均来更新参数:

gw=Lwgb=LbVw=βVw+(1β)gwβ=0.9Vb=βVb+(1β)gbwt+1=wtrVwbt+1=btrVb \begin{aligned} &g_{w}=\frac{\partial L}{\partial w}\quad g_{b}=\frac{\partial L}{\partial b} \\ &V_{w}=\beta V_{w}+(1-\beta)g_{w}\quad\beta=0.9 \\ &V_{b}=\beta V_{b}+(1-\beta)g_{b} \\ &w_{t+1}=w_{t}-rV_{w} \\ &b_{t+1}=b_{t}-rV_{b} \end{aligned}

RMSProp

RMSProp想解决神经网络不同参数梯度大小不同的问题,其想法是让每个参数的梯度除以一个代表这个梯度平均大小的值,这样各个参数的梯度就差不多大了,训练就稳定了。

方式是计算每个参数梯度平方的指数加权平均值,然后在更新参数时,用当前的参数除以指数加权平均值的平方根,此时由于防止除0,所以加入了一个很小的正值:

gw=Lwgb=LbSw=βSw+(1β)gw2β=0.9Sb=βSb+(1β)gb2wt+1=wtrgwSw+εbt+1=btrgbSb+ε \begin{aligned} &g_{w}=\frac{\partial L}{\partial w}\quad g_{b}=\frac{\partial L}{\partial b} \\ &S_{w}=\beta S_{w}+(1-\beta)g_{w}{}^{2}\quad\beta=0.9\\ &S_{b}=\beta S_{b}+(1-\beta){g_{b}}^{2}\\ &w_{t+1}=w_{t}-r\frac{g_{w}}{\sqrt{S_{w}}+\varepsilon}\quad b_{t+1}=b_{t}-r\frac{g_{b}}{\sqrt{S_{b}}+\varepsilon} \end{aligned}

Adam

Adam就是将Momentum和RMSProp进行了结合,并对指数加权平均值进行了修正:

gw=LwVw=β1Vw+(1β1)gwβ1=0.9Sw=β2Sw+(1β2)gw2β2=0.999Vwcorrect=Vw1β1tSwcorrect=Sw1β2tWt+1=wtrVWcorrectSWcorrect+ε \begin{aligned} &g_{w} =\frac{\partial L}{\partial w} \\ &V_{w}=\beta_{1}V_{w}+(1-\beta_{1})g_{w}\quad\beta_{1}=0.9 \\ &S_{w}=\beta_{2}S_{w}+(1-\beta_{2})g_{w}^{2}\quad\beta_{2}=0.999 \\ &V_{w}^{correct}=\frac{V_{w}}{1-{\beta_{1}}^{t}} \\ &S_{w}^{correct}=\frac{S_{w}}{1-{\beta_{2}}^{t}} \\ &W_{t+1} =w_{t}-r\frac{V_{W}^{correct}}{\sqrt{S_{W}^{correct}}+\varepsilon} \end{aligned}

AdamW

AdamW其实就是在Adam的基础上加了个weight decay:

Wt+1=WtrVcorrectSwcorrect+εrλWt W_{t+1}=W_{t}-r\frac{Vcorrect}{\sqrt{S_{w}^{correct}}+\varepsilon}-r\lambda W_{t}

另外注意,无论是Adam还是AdamW,他们都需要针对每个参数额外保存两个值SwS_{w}VwV_{w},每个值都需要用float32来存储,如果参数用float16存储,这两个值占用大小将是参数量的4倍。