指数加权平均 (exponentially weighted averges)
先说一下指数加权平均, 公式如下:
v t = β v t − 1 + ( 1 − β ) θ t v_{t}=\beta v_{t-1}+(1-\beta) \theta_{t} vt=βvt−1+(1−β)θt
- θ t \theta_t θt 是第t天的观测值
- v t v_t vt 是用来替代 θ t \theta_t θt的估计值,也就是加权平均值
- β \beta β 超参数
设 β = 0.9 \beta = 0.9 β=0.9 , 那么公式可以化简为:
v 100 = 0.1 ∗ θ t + 0.1 ∗ 0.9 ∗ θ 99 + 0.1 ∗ 0. 9 2 θ 98 + … + 0.1 ∗ 0. 9 99 θ 1 v_{100} = 0.1 * \theta_t + 0.1 * 0.9 * \theta_{99} + 0.1 * 0.9^{2} \theta_{98}+\ldots+0.1 * 0.9^{99} \theta_{1} v100=0.1∗θt+0.1∗0.9∗θ99+0.1∗0.92θ98+…+0.1∗0.999θ1
它考虑到了之前所有观测值,但是事件越靠近的观测值权重越大,时间越久远的观测值权重就很小了。
在 β = 0.9 \beta = 0.9 β=0.9时,很多资料认为 0. 9 10 ≈ 0.35 ≈ 1 / e 0.9^{10} \approx 0.35 \approx 1 / e 0.910≈0.35≈1/e, 把这个数当成一个分界点,权重降低到这个分界点之下就可以忽略不计,而 β 1 1 − β ≈ 1 / e \beta^{\frac{1}{1-\beta}} \approx 1 / e β1−β1≈1/e , 所以把上面两个公式合到一起就可以认为指数加权平均就是最近 N = 1 1 − β N=\frac{1}{1-\beta} N=1−β1天的加权平均值
所以
- β \beta β 越小, 加权平均的数据越少,就容易出现震荡
- β \beta β 越大, 加权平均考虑的数据就越多,当出现震荡的时候会由于历史数据的权重导致震荡的幅度减小
Batch Gradient Descent (BGD)
BGD使用整个数据集来计算梯度,这里的损失函数是所有输入的样本数据的loss的和,单个样本的loss可以用交叉熵或者均方误差来计算。
θ
=
θ
−
η
⋅
∇
θ
J
(
θ
)
\theta=\theta-\eta \cdot \nabla_{\theta} J(\theta)
θ=θ−η⋅∇θJ(θ)
缺点是每次更新数据都需要计算整个数据集,速度很慢,不能实时的投入数据更新模型。对于凸函数可以收敛到全局最小值,对于非凸函数只能收敛到局部最小值。这是最朴素的优化器了
Stochastic Gradient Descent(SGD)
由于BGD计算梯度太过费时,SGD每次只计算一个样本的loss,然后更新参数。计算时可以先打乱数据,然后一条一条的将数据输入到模型中
θ
=
θ
−
η
⋅
∇
θ
J
(
θ
;
x
(
i
)
;
y
(
i
)
)
\theta=\theta-\eta \cdot \nabla_{\theta} J\left(\theta ; x^{(i)} ; y^{(i)}\right)
θ=θ−η⋅∇θJ(θ;x(i);y(i))
他的缺点是更新比较频繁,会有严重的震荡。
当我们稍微减小learning rate, SGD和BGD的收敛性是一样的
Mini-Batch Gradient Descent (MBGD)
每次接收batch个样本,然后计算它们的loss的和。
θ
=
θ
−
η
⋅
∇
θ
J
(
θ
;
x
(
i
:
i
+
n
)
;
y
(
i
:
i
+
n
)
)
\theta=\theta-\eta \cdot \nabla_{\theta} J\left(\theta ; x^{(i: i+n)} ; y^{(i: i+n)}\right)
θ=θ−η⋅∇θJ(θ;x(i:i+n);y(i:i+n))
对于鞍点, BGD会在鞍点附近停止更新,而MSGD会在鞍点周围来回震荡。
Monentum SGD
加入了v的概念,起到一个类似惯性的作用。在更新梯度的时候会照顾到之前已有的梯度。这里的
v
t
v_t
vt就是梯度的加权平均
v
t
=
γ
v
t
−
1
+
η
∇
θ
J
(
θ
)
θ
=
θ
−
v
t
\begin{array}{l} v_{t}=\gamma v_{t-1}+\eta \nabla_{\theta} J(\theta) \\ \theta=\theta-v_{t} \end{array}
vt=γvt−1+η∇θJ(θ)θ=θ−vt
它可以在梯度方向不变的维度上使速度变快,在梯度方向有所改变的维度上更新速度更慢,可以抵消某些维度的摆动,加快收敛并减小震荡。 γ \gamma γ一般取值为0.9
Nesterov Accelerated Gradient
它用
θ
−
γ
v
t
−
1
\theta-\gamma v_{t-1}
θ−γvt−1来近似估计下一步
θ
\theta
θ会到达的位置
v
t
=
γ
v
t
−
1
+
η
∇
θ
J
(
θ
−
γ
v
t
−
1
)
θ
=
θ
−
v
t
\begin{array}{l} v_{t}=\gamma v_{t-1}+\eta \nabla_{\theta} J\left(\theta-\gamma v_{t-1}\right) \\ \theta=\theta-v_{t} \end{array}
vt=γvt−1+η∇θJ(θ−γvt−1)θ=θ−vt
能够让算法提前看到前方的地形梯度,如果前面的梯度比当前位置的梯度大,那我就可以把步子迈得比原来大一些,如果前面的梯度比现在的梯度小,那我就可以把步子迈得小一些
这个算法的公式竟然可以转化为下面的等价的公式:
d
i
=
β
d
i
−
1
+
g
(
θ
i
−
1
)
+
β
[
g
(
θ
i
−
1
)
−
g
(
θ
i
−
2
)
]
θ
i
=
θ
i
−
1
−
α
d
i
\begin{array}{l} d_{i}=\beta d_{i-1}+g\left(\theta_{i-1}\right)+\beta\left[g\left(\theta_{i-1}\right)-g\left(\theta_{i-2}\right)\right] \\ \theta_{i}=\theta_{i-1}-\alpha d_{i} \end{array}
di=βdi−1+g(θi−1)+β[g(θi−1)−g(θi−2)]θi=θi−1−αdi
后面的梯度相减可以认为是梯度的导数,也就是loss的二阶导数。也就是用二阶导数判断了一下曲线的趋势。其中 γ \gamma γ一般取值为0.9
Adagrad (Adaptive gradient algorithm)
可以对低频的参数做较大的更新,对高频的参数做较小的更新。
θ t + 1 , i = θ t , i − η G t , i i + ϵ ⋅ g t , i \theta_{t+1, i}=\theta_{t, i}-\frac{\eta}{\sqrt{G_{t, i i}+\epsilon}} \cdot g_{t, i} θt+1,i=θt,i−Gt,ii+ϵη⋅gt,i
这个算法很有意思,G是在某个维度上,t从0开始到现在的所有梯度的平方和。所以对于经常更新的参数,学习率会越来越小,而对于不怎么更新的参数,他的学习率会变得相对更高。
θ \theta θ一般设置为0.01,他的缺点是分母会不断累计,最终学习率会变得非常小。如果初始梯度很大,会导致学习率变得很小。它适合用于稀疏数据。
Adadelta
对Adagrad的改进,对某个维度的历史维度进行平方、相加、开方
E [ g 2 ] t = ρ ∗ E [ g 2 ] t − 1 + ( 1 − ρ ) ∗ g t 2 E\left[g^{2}\right]_{t}=\rho * E\left[g^{2}\right]_{t-1}+(1-\rho) * g_{t}^{2} E[g2]t=ρ∗E[g2]t−1+(1−ρ)∗gt2
x t + 1 = x t − η E [ g 2 ] t + ϵ ∗ g t x_{t+1}=x_{t}-\frac{\eta}{\sqrt{E\left[g^{2}\right]_{t}+\epsilon}} * g_{t} xt+1=xt−E[g2]t+ϵη∗gt
R M S ( g t ) = E [ g 2 ] t + ϵ R M S\left(g_{t}\right)=\sqrt{E\left[g^{2}\right]_{t}+\epsilon} RMS(gt)=E[g2]t+ϵ
解决了历史梯度一直累加导致的学习率下降问题, ϵ \epsilon ϵ 是为了方式分母为0加上的极小值, r h o rho rho一般取值为0.9
Adaptive Moment Estimation (Adam)
同时考虑了梯度的平方和梯度的指数衰减。建议 β 1 \beta_1 β1=0.9, β 2 \beta_2 β2=0.999, η \eta η=10e-8
m t = β 1 m t − 1 + ( 1 − β 1 ) g t m_{t}=\beta_{1} m_{t-1}+\left(1-\beta_{1}\right) g_{t} mt=β1mt−1+(1−β1)gt
v t = β 2 v t − 1 + ( 1 − β 2 ) g t 2 v_{t}=\beta_{2} v_{t-1}+\left(1-\beta_{2}\right) g_{t}^{2} vt=β2vt−1+(1−β2)gt2
m ^ t = m t 1 − β 1 t , v ^ t = v t 1 − β 2 t \begin{array}{l} \hat{m}{t}=\frac{m{t}}{1-\beta_{1}^{t}}, \hat{v}{t}=\frac{v{t}}{1-\beta_{2}^{t}} \end{array} m^t=1−β1tmt,v^t=1−β2tvt
θ t + 1 = θ t − η v ^ t + ϵ m ^ t \theta_{t+1}=\theta_{t}-\frac{\eta}{\sqrt{\hat{v}_{t}}+\epsilon} \hat{m}_{t} θt+1=θt−v^t+ϵηm^t
Adam取得了比其他方法更好的效果
总结
如果数据是稀疏的,就用自适用方法,即 Adagrad, Adadelta, RMSprop, Adam。
参考资料:
https://www.cnblogs.com/guoyaohua/p/8542554.html
https://arxiv.org/pdf/1609.04747.pdf