机器学习之优化器
优化器这个名字是 optimizer 这个单词的翻译,他是一个用来更新模型参数的函数,其核心法则是下面这个公式:
θ t = θ t − 1 − α ⋅ g t \theta_{t}=\theta_{t-1}-\alpha\cdot g_t θt=θt−1−α⋅gt
θ t \theta_t θt 是第 t t t 轮训练时的参数, α \alpha α 是学习率, g t g_t gt 是 t t t 轮训练时的梯度。
这就是随机梯度下降算法,简称 SGD。设置学习率是为了防止梯度下降过快,模型训练的目标就是让损失函数达到极小值。当梯度特别大时,参数更新的步幅也会特别大,导致出现震荡,永远到不了最小值处。模型训练就像盲人摸象,需要一点一点摸索前进,因此学习率一般设置为一个小于 1 的值。
g t = ∇ θ L ( θ t ) g_t=\nabla_{\theta}L(\theta_t) gt=∇θL(θt) ,所谓梯度就是损失函数对参数 θ \theta θ 的偏导数。导数有正有负,它揭示了函数的变化趋势,这个趋势不仅有方向,还有大小。在模型训练过程中,损失函数 L L L 是模型参数 θ \theta θ 的函数,因为在训练期间,输入是已知的,模型参数才是未知的变量,预测时刚好反过来。
不同的优化器核心结构都是一样的,它们的区别体现在对 α \alpha α 和 g t g_t gt 的修改上,事实上也只有这两个地方能动动手脚,核心还是梯度。
评价优化器好与不好的指标就是收敛速度和稳定性,所有围绕梯度下降公式的优化也都是针对这两点进行的。乱花渐欲迷人眼,只需盯住这两点。
Momentum
中文叫动量算法,其核心思想是对梯度做了一个指数加权平均。
g t = ∇ θ L ( θ t ) v t = β ⋅ v t − 1 + ( 1 − β ) ⋅ g t θ t = θ t − 1 − α ⋅ v t \begin{aligned} g_t &= \nabla_\theta L(\theta_t) \\ v_t &= \beta\cdot v_{t-1}+(1-\beta)\cdot g_t \\ \theta_t &= \theta_{t-1}-\alpha\cdot v_t \end{aligned} gtvtθt=∇θL(θt)=β⋅vt−1+(1−β)⋅gt=θt−1−α⋅vt
其实就是对梯度做了一个平滑,经过指数加权平均的梯度能下降的更平滑,防止异常梯度带来的振荡干扰。
RMSProp
全称 Root Mean Square Propagation,均方根传播算法。它调整的是学习率。
g t = ∇ θ L ( θ t ) v t = β ⋅ v t − 1 + ( 1 − β ) ⋅ g t 2 θ t = θ t − 1 − α v t + ϵ ⋅ g t \begin{aligned} g_t&=\nabla_\theta L(\theta_t) \\ v_t&=\beta\cdot v_{t-1}+(1-\beta)\cdot g^2_t \\ \theta_t&=\theta_{t-1}-\frac{\alpha}{\sqrt{v_t}+\epsilon}\cdot g_t \end{aligned} gtvtθt=∇θL(θt)=β⋅vt−1+(1−β)⋅gt2=θt−1−vt+ϵα⋅gt
它在学习率上除以了一个 v t \sqrt{v_t} vt ,而 v t v_t vt 是梯度的平方的指数加权平均,分母中的 ϵ \epsilon ϵ 是一个非常小的非零值,用来防止除零错误。取 g t 2 g_t^2 gt2 做指数加权平均是为了让 v t v_t vt 始终为正,因为它的作用和 α \alpha α 一样,只能修改梯度的大小,不能修改梯度的方向。
Adam
全称 Adaptive Moment Estimation,它同时修改了梯度和学习率。
g t = ∇ θ L ( θ t ) m t = β 1 ⋅ m t − 1 + ( 1 − β 1 ) ⋅ g t v t = β 2 ⋅ v t − 1 + ( 1 − β 2 ) ⋅ g t 2 m ^ t = m t 1 − β 1 t v ^ t = v t 1 − β 2 t θ t = θ t − 1 − α v ^ t + ϵ ⋅ m ^ t \begin{aligned} g_t&=\nabla_\theta L(\theta_t) \\ m_t&=\beta_1\cdot m_{t-1}+(1-\beta_1)\cdot g_t \\ v_t&=\beta_2\cdot v_{t-1}+(1-\beta_2)\cdot g_t^2 \\ \hat{m}_t&=\frac{m_t}{1-\beta_1^t} \\ \hat{v}_t&=\frac{v_t}{1-\beta_2^t} \\ \theta_t&=\theta_{t-1}-\frac{\alpha}{\sqrt{\hat{v}_t}+\epsilon}\cdot \hat{m}_t \end{aligned} gtmtvtm^tv^tθt=∇θL(θt)=β1⋅mt−1+(1−β1)⋅gt=β2⋅vt−1+(1−β2)⋅gt2=1−β1tmt=1−β2tvt=θt−1−v^t+ϵα⋅m^t
Adam 基本上就是 Momentum 和 RMSProp 的结合,但是它在平滑后的梯度上又除了一个 ( 1 − β t ) (1-\beta^t) (1−βt) ,随着训练次数的增加, ( 1 − β t ) (1-\beta^t) (1−βt) 越来越接近 1, m ^ t \hat{m}_t m^t 也就越来越接近 m t m_t mt , v t v_t vt 也是同理,也就是说,它加快了刚开始时的训练速度。
Axon 中的那些优化器
Axon 中用到的优化器实际上并不在 Axon 库当中,而是在 Polaris 库中,可以点击这里查看,每个优化器都给出了论文链接。
adabelief
它也是一种自适应梯度优化器。
g t = ∇ θ L ( θ t ) m t = β 1 ⋅ m t − 1 + ( 1 − β 1 ) ⋅ g t s t = β 2 ⋅ s t − 1 + ( 1 − β 2 ) ⋅ ( g t − m t ) 2 + ϵ m ^ t = m t 1 − β 1 t s ^ t = s t 1 − β 2 t θ t = θ t − 1 − α s ^ t + ϵ ⋅ m ^ t \begin{aligned} g_t&=\nabla_\theta L(\theta_t) \\ m_t&=\beta_1\cdot m_{t-1}+(1-\beta_1)\cdot g_t \\ s_t&=\beta_2\cdot s_{t-1}+(1-\beta_2)\cdot (g_t-m_t)^2+\epsilon \\ \hat{m}_t&=\frac{m_t}{1-\beta_1^t} \\ \hat{s}_t&=\frac{s_t}{1-\beta_2^t} \\ \theta_t&=\theta_{t-1}-\frac{\alpha}{\sqrt{\hat{s}_t}+\epsilon}\cdot \hat{m}_t \end{aligned} gtmtstm^ts^tθt=∇θL(θt)=β1⋅mt−1+(1−β1)⋅gt=β2⋅st−1+(1−β2)⋅(gt−mt)2+ϵ=1−β1tmt=1−β2tst=θt−1−s^t+ϵα⋅m^t
它这里用来调整学习率的是 s t s_t st ,它是梯度与平滑后梯度之差的加权平均,这就是所谓的 Belief,当梯度变化不大时就大步走,当梯度变化很大时就小步走,比如梯度发生反转时就小步前进。 m ^ t \hat m_t m^t 和 s ^ t \hat s_t s^t 的作用和 adam 是一样的。
adagrad
也是一种自适应梯度下降算法,它修改的是学习率。
g t = ∇ θ L ( θ t ) s t i = s t − 1 i + g t 2 θ t = θ t − 1 − α s t i + ϵ g t \begin{aligned} g_t&=\nabla_\theta L(\theta_t) \\ s_t^i&=s_{t-1}^i+g_t^2 \\ \theta_t &= \theta_{t-1}-\frac{\alpha}{\sqrt{s_t^i}+\epsilon}g_t \end{aligned} gtstiθt=∇θL(θt)=st−1i+gt2=θt−1−sti+ϵαgt
它直接对每个参数累加梯度的平方,让后用这个平方和来修改学习率,随着训练的进行,平方和会不断累加,学习率持续下降,最后自动停止学习。
adam
即前面讲过的 Adam 优化器。
adamw
它是 Adam 优化器的优化版,最后的 “W” 表示的是 weight decay,权重衰减。它前面 m t m_t mt 、 v t v_t vt 等的计算和 Adam 是一样的,不同的地方在于最后的参数更新上。
θ t = θ t − 1 − α v ^ t + ϵ m ^ t − α λ θ t \theta_t=\theta_{t-1}-\frac{\alpha}{\sqrt{\hat{v}_t}+\epsilon}\hat{m}_t-\alpha\lambda\theta_t θt=θt−1−v^t+ϵαm^t−αλθt
lamb
他也是一种已 Adam 为基础的优化器,针对大规模训练优化,防止大 batch 下梯度爆炸或消失。
g t = ∇ θ L ( θ t ) m t = β 1 ⋅ m t − 1 + ( 1 − β 1 ) ⋅ g t v t = β 2 ⋅ v t − 1 + ( 1 − β 2 ) ⋅ g t 2 m ^ t = m t 1 − β 1 t v ^ t = v t 1 − β 2 t r t = η v ^ t + ϵ m ^ t w n o r m a l = ∥ θ t − 1 ∥ 2 g n o r m a l = ∥ r t ∥ 2 θ t = θ t − 1 − w n o r m a l g n o r m a l + ϵ r t \begin{aligned} g_t&=\nabla_\theta L(\theta_t) \\ m_t&=\beta_1\cdot m_{t-1}+(1-\beta_1)\cdot g_t \\ v_t&=\beta_2\cdot v_{t-1}+(1-\beta_2)\cdot g_t^2 \\ \hat{m}_t&=\frac{m_t}{1-\beta_1^t} \\ \hat{v}_t&=\frac{v_t}{1-\beta_2^t} \\ r_t&=\frac{\eta}{\sqrt{\hat{v}_t}+\epsilon}\hat{m}_t \\ w_{normal}&=\|\theta_{t-1}\|_2 \\ g_{normal}&=\|r_t\|_2 \\ \theta_t&=\theta_{t-1}-\frac{w_{normal}}{g_{normal}+\epsilon}r_t \end{aligned} gtmtvtm^tv^trtwnormalgnormalθt=∇θL(θt)=β1⋅mt−1+(1−β1)⋅gt=β2⋅vt−1+(1−β2)⋅gt2=1−β1tmt=1−β2tvt=v^t+ϵηm^t=∥θt−1∥2=∥rt∥2=θt−1−gnormal+ϵwnormalrt
这里 ∥ x ∥ 2 \|x\|_2 ∥x∥2 表示向量 x x x 的 L 2 L2 L2 范数,其实也就是向量的模长。
noisy_sgd
就像它的名字那样,就是在随机梯度下降算法中加入噪声,帮助模型跳出局部最小值点。
θ t = θ t − 1 − α ⋅ g t + ϵ \theta_{t}=\theta_{t-1}-\alpha\cdot g_t+\epsilon θt=θt−1−α⋅gt+ϵ
radam
radam也是个优化版的 adam,”r” 就是 rectified 的首字母。它其实是个分段函数,设置了一个修正因子 ρ \rho ρ ,当 ρ < 4 \rho<4 ρ<4 时,切换到 SGD 算法,否则使用 Adam 算法。
ρ t = 2 β 2 t − 1 \rho_t=\frac{2}{\beta_2^t}-1 ρt=β2t2−1
rmsprop
即前面讲过的 RMSProp 优化器
sgd
最原始的梯度下降。
yogi
他也是一个基于 Adam 的自适应优化器,他与 Adam 的区别在于二阶估计矩 v t v_t vt 的计算方式。
v t = v t − 1 − ( 1 − β 2 ) ⋅ s i g n ( v t − 1 − g t 2 ) ⋅ g t 2 v_t=v_{t-1}-(1-\beta_2)\cdot sign(v_{t-1}-g_t^2)\cdot g_t^2 vt=vt−1−(1−β2)⋅sign(vt−1−gt2)⋅gt2
s i g n sign sign 是个符号函数:
x = { 1 if x > 0 0 if x = 0 − 1 if x < 0 x=\begin{cases} 1&\text{if}\enspace x>0\\ 0&\text{if}\enspace x=0\\ -1&\text{if}\enspace x<0 \end{cases} x=⎩ ⎨ ⎧10−1ifx>0ifx=0ifx<0