Optimization
动量版SGD
SGD仍然还有一些问题:当损失函数在一个方向快速改变,另一个方向很慢地改变时,梯度下降会变成非常慢地一个过程
同时,SGD对于驻点和局部最小值的表现并不好,在那些地方会堵住。因此,现在考虑一种SGD+动量的方法:
现在的速度 = 摩擦系数 * 之前的速度+梯度
新的权重 = 旧的权重 - 学习率 * 新的速度
摩擦系数一般取0.9或0.99
Nesterov 动量
v t + 1 = ρ v t − α ∇ f ( x t + ρ v t ) x t + 1 = x t + v t + 1 \begin{aligned}v_{t+1} &=\rho v_{t}-\alpha \nabla f\left(x_{t}+\rho v_{t}\right) \\x_{t+1} &=x_{t}+v_{t+1}\end{aligned} vt+1xt+1=ρvt−α∇f(xt+ρvt)=xt+vt+1
相当于在动量改变前,我先用现在的速度到未来的位置看未来的梯度,这样就可以提前知道梯度的变化了。
换元后,可以看到是这样的
v t + 1 = ρ v t − α ∇ f ( x ~ t ) x ~ t + 1 = x ~ t − ρ v t + ( 1 + ρ ) v t + 1 = x ~ t + v t + 1 + ρ ( v t + 1 − v t ) \begin{aligned}v_{t+1} &=\rho v_{t}-\alpha \nabla f\left(\tilde{x}_{t}\right) \\\tilde{x}_{t+1} &=\tilde{x}_{t}-\rho v_{t}+(1+\rho) v_{t+1} \\&=\tilde{x}_{t}+v_{t+1}+\rho\left(v_{t+1}-v_{t}\right)\end{aligned} vt+1x~t+1=ρvt−α∇f(x~t)=x~t−ρvt+(1+ρ)vt+1=x~t+vt+1+ρ(vt+1−vt)
dx = compute_gradient(x)
old_v = v
v = rho * v - learning_rate * dx
x += -rho * old_v + (1 + rho) * v
AdaGrad
可以看到,这里加上了dx的平方作为梯度,可以起到加大步长的效果。但是,随着训练时间的延长,步长会越来越小。
因此,就会有新的RMSProp梯度更新法
RMSProp
这里是用了衰减率来限制住学习率不会随时间的延长而缩小
Adam
该算法集百家之所长,究极缝合怪算法
first_moment = 0
second_moment = 0
for t in range(1, num_iterations):
first_moment = beta1 * first_moment + (1 - beta1) * dx
second_moment= beta2 * second_moment + (1 - beta2) * dx * dx
first_unbias = first_moment / (1 - beta1 ** t)
second_unbias = second_moment / (1 - beta2 ** t)
x -= learning_rate * first_unbias / (np.sqrt(second_unbias) + 1e-7)
unbias存在的意义是first和second moment的值在开始的时候都是0,这会让更新的值存在一些不可控的影响
Adam在开始时,beta1 = 0.9, beta2 = 0.999, lr = 1e-3 或 5e-4 是一个不错的初始设置
学习率衰减
好的学习率是能非常快的收敛,并且慢慢地逼近loss最小值
因此,我们希望学习率在前期很大,后期慢慢变小。所以需要学习率衰减。
一阶优化-》二阶优化
一阶优化求的是当前坡度最大的方向,而二阶优化还会考虑到走了一步后,坡度是否会变得更大。
二阶优化收敛得更快,而且不需要学习率。
二阶泰勒展开,一元的时候即是这种情况
J ( θ ) ≈ J ( θ 0 ) + ( θ − θ 0 ) ⊤ ∇ θ J ( θ 0 ) + 1 2 ( θ − θ 0 ) ⊤ H ( θ − θ 0 ) J(\boldsymbol{\theta}) \approx J\left(\boldsymbol{\theta}_{0}\right)+\left(\boldsymbol{\theta}-\boldsymbol{\theta}_{0}\right)^{\top} \nabla_{\boldsymbol{\theta}} J\left(\boldsymbol{\theta}_{0}\right)+\frac{1}{2}\left(\boldsymbol{\theta}-\boldsymbol{\theta}_{0}\right)^{\top} \boldsymbol{H}\left(\boldsymbol{\theta}-\boldsymbol{\theta}_{0}\right) J(θ)≈J(θ0)+(θ−θ0)⊤∇θJ(θ0)+21(θ−θ0)⊤H(θ−θ0)
这是多元的情况
θ ∗ = θ 0 − H − 1 ∇ θ J ( θ 0 ) \boldsymbol{\theta}^{*}=\boldsymbol{\theta}_{0}-\boldsymbol{H}^{-1} \nabla_{\boldsymbol{\theta}} J\left(\boldsymbol{\theta}_{0}\right) θ∗=θ0−H−1∇θJ(θ0)
但该方法在深度学习时不常用,因为要求的海森矩阵太大了!
综上,Adam是默认的比较好的选择。
Model Ensembles
类似于用多个不同的独立模型来训练,最后测试时平均测试结果,大概可以多2%的准确率。
就好像,相比于1个人有a专业知识的人做一项工作,5个分别有a,b,c,d,e专业知识的人一起做一项工作效果会更好。
除了训练不同的模型,我们还可以将单个模型在不同时间点的状态保存下来,最后一起测试
正则化
平常使用的方法有L2、L1、L2+L1正则化。现在要介绍的是Dropout正则化。
意思是,在每一个前向传播的过程中,随机的将一些神经元置0.概率一般是0.5
为什么Dropout是一种好的方法?因为它通过随机置0,打断了原有某些特征的连接,可以防止过拟合
但同时,dropout也会让我们的输出随机。由测试时和训练时的数学期望可以推出,我们在测试时的dropout概率需要翻倍
同时,正则化还有另外的方法,可以将输入的数据进行翻转等微小地改动操作,或者随机地取某块区域进行训练。
还可以加入随机的噪声等。
迁移学习
在训练 / 使用CNN时不需要大量的数据!
我们根据需要取更改最后的几层即可。