自适应学习率
我们梯度下降在参数更新上,公式是 W t = W t − 1 − η g t , η 是学习率, g t 是梯度 W_t=W_{t-1}-\eta g_t,\eta是学习率,g_t是梯度 Wt=Wt−1−ηgt,η是学习率,gt是梯度。
最简单的梯度下降算法,会出现类似下图的情况,损失下不去,梯度来回震荡,收敛缓慢。究其原因是学习率太大,导致参数变化太大,但下一次为了降低损失,得到了反方向的梯度,最终表现为梯度来来回回。
下面这张图更好的做了对比,这张图是误差平面,蓝色点表示当w、b为对应的值时,对应的loss。而蓝色点连成线,就像一条等高线,与等高线垂直的方向就是loss下降最快,即梯度最大的方向。而与等高线平行的方向,梯度变化很小,几乎平坦,这种也称为“凸的”误差平面(即一个轴的方向梯度变化大,另一个轴的方向梯度几乎不变)。
我们要从A点到达黄X。当学习率过大时,参数(看纵轴)来回变动,一会大于0一会小于0。而学习率过小时,虽然一开始能缓慢地根据梯度变化趋势下降,但在平坦的方向上就几乎不会动了。
因此我们得到结论,学习率不能固定为一个初设值(或者说梯度不能直接乘一个固定值),应该根据当前情况动态调整,即自适应。如果在某一个方向上,梯度的值很小,非常平坦,我们会希望学习率调大一点;如果在某一个方向上非常陡峭,坡度很大,我们会希望学习率可以设得小一点。
AdaGrad(Adaptive Gradient)
我们还是保留 η \eta η 这个固定不变的超参数,但是我们不能让 Δ W t = η g t \Delta W_t=\eta g_t ΔWt=ηgt,我们需要 Δ W t = η σ t i g t i \Delta W_t=\frac{\eta}{\sigma_t^i}g_t^i ΔWt=σtiηgti,其中 t 还是表示第 t 次迭代,i 表示对于第 i 个参数,因为自适应的学习率,在每次迭代、每个参数上都不一样。重点是 σ t i \sigma_t^i σti 必须在梯度大时大,梯度小时小,这样被 η \eta η一除,就能满足梯度大时 Δ W \Delta W ΔW 小,梯度小时 Δ W \Delta W ΔW 大。
在Ada中, σ 0 i = ( g 0 i ) 2 , σ 1 i = 1 2 [ ( g 0 i ) 2 + ( g 1 i ) 2 ] , σ 2 i = 1 3 [ ( g 0 i ) 2 + ( g 1 i ) 2 + ( g 2 i ) 2 ] \sigma^i_0=\sqrt {(g_0^i)^2},\sigma^i_1=\sqrt {\frac{1}{2}[(g_0^i)^2+(g_1^i)^2]},\sigma^i_2=\sqrt {\frac{1}{3}[(g_0^i)^2+(g_1^i)^2+(g_2^i)^2]} σ0i=(g0i)2,σ1i=21[(g0i)2+(g1i)2],σ2i=31[(g0i)2+(g1i)2+(g2i)2],依此类推。即是使用到了过去所有梯度的均方根。如果梯度 g t i g_t^i gti较小,由于取平均值导致 σ t i \sigma_t^i σti减少,进而导致了学习率的增加,加速通过平坦路况。
RMSProp(Root Mean Squared propagation)
对于Ada,由于使用了历史梯度平方,且每个历史梯度都没有权重,历史的较大值会产生长远的影响。
RMSProp将Ada的取平均改为权重(衰减因子)。 σ 0 i = ( g 0 i ) 2 , σ 1 i = α ( σ 0 i ) 2 + ( 1 − α ) ( g 1 i ) 2 , σ 2 i = α ( σ 1 i ) 2 + ( 1 − α ) ( g 2 i ) 2 \sigma^i_0=\sqrt {(g_0^i)^2},\sigma^i_1=\sqrt {\alpha (\sigma_0^i)^2+(1-\alpha)(g_1^i)^2},σ^i_2=\sqrt {\alpha(\sigma_1^i)^2+(1-\alpha)(g_2^i)^2} σ0i=(g0i)2,σ1i=α(σ0i)2+(1−α)(g1i)2,σ2i=α(σ1i)2+(1−α)(g2i)2,依此类推,注意历史梯度用到的是 σ t − 1 i 而不是 g t − 1 i \sigma_{t-1}^i而不是g_{t-1}^i σt−1i而不是gt−1i。
通过设置较小的 α \alpha α,可以更看重最新算出的梯度。
Adam(Adaptive moment estimation)
最常用的优化器(optimizer),可以看作在RMSProp基础上,把梯度 g t i g_t^i gti换成动量 m t i m_t^i mti。
注意,虽然在 η σ t i m t i 中, σ t i 和 m t i \frac{\eta}{\sigma_t^i}m_t^i中,\sigma_t^i和m_t^i σtiηmti中,σti和mti都用到了历史梯度,但是前者只是标量,后者是向量,他们不会相互抵消。
学习率调度
上面的都是说让梯度乘上一个变化的值,但学习率还是固定的。而这里的新策略是学习率 η t \eta_t ηt 也是随时间变化的。
- 学习率衰减:随着训练进行,逐步减少学习率,尽量防止震荡以加快收敛。
- 预热:在训练初期使用较低的学习率,逐渐收集统计数据找到合理路径。之后逐渐增加以加快收敛。有一个Adam的预热版本RAdam。
分类问题
对于训练集,我们每个样本的y要表示该样本对应的类,我们可以使用one-hot编码,比如有n个类,当前样本类型是1,就用一个除第n维是1之外、其他维为0的n维向量表示。比如3个类,[0,1,0]表示该样本属于第二类。这个也可以看做一个概率分布,即这个样本属于第二类的概率为1。最后计算损失时,就可以用 y ^ \hat y y^和y计算相似度。
如果还是用回归的方式得到 y ^ \hat{y} y^,值很可能不是一个概率分布,n维每个值的和不等于1。所以这里需要用到归一化,我们使用softmax。 y i ′ = e x p ( y i ) ∑ j e x p ( y i ) , 其中, 0 < y i ′ < 1 , ∑ i y i ′ = 1 。 y'_i =\frac{exp(y_i)}{\sum_jexp(y_i)},其中,0<y'_i<1,\sum_i y'_i = 1。 yi′=∑jexp(yi)exp(yi),其中,0<yi′<1,∑iyi′=1。效果如下,同时softmax还会让原本大的值跟小的值的差距更大。注意当只有两个类的时候,sigmoid 和 softmax 是等价的。
那么接下来就要计算损失了。比较常用的是最小化交叉熵,其实也是极大似然。
e = − ∑ i y i l n y i ′ e=-\sum_i y_i ln y_i' e=−i∑yilnyi′
相比于均方误差的好处还没细看。只关注到了一个结论,交叉熵能更容易的利用优化器优化。
改变损失函数可以改变优化的难度
图像分类例子
代码见 Datawhale/LeeDL-HW3-CNN
例子使用了pytorch搭建了一个CNN
重点大概是
- 将图像加载为tensor,并对训练集进行数据增强
- 定义了一个cnn,里面的卷积层使用卷积核对图像提取特征,通过批归一化层处理后,过一下Relu激活函数,最后池化操作是取2*2像素内的Max值。
- 定义了一个全连接神经网络,对输入特征进行线性变换和Relu非线性变换。
- 前向传播时先将样本传入cnn,再传入fc获得最终 y ′ y' y′
- 使用了交叉熵作为损失函数,并使用了Adam优化器
进一步的优化方向
因为我不是搞cv的就不详细了解了,看个大概,太多太多了,但是确实确实很有用!有些在其他方向也能用到!