引言
本文主要讲解了在进行深度学习时一些实用的提示。是李宏毅 深度学习-Tips for Trainning DNN的笔记。
深度学习的方法
经过三步骤后得到一个神经网络,接下来判断在训练集上的表现如何?如果结果不好则回头看看三个步骤哪里出了问题;如果在训练集上的正确率很好,则拿训练集来试试,如果此时在测试集上的准确率不好,则说明是过拟合了;如果在训练集和测试集都得到很好的结果话,就说明这个网络是比较nice的。
不要错怪过拟合
在上图右56层的网络的错误率比20层的还要高,不能这样就说是过拟合导致的。从上图左可以看到在训练集上20层的结果本来就比56层的就好,说明这个网络没有训练好。
训练集上的结果不好与测试集上的结果不好是不一样的,有不同的途径可以解决这些问题。比如Dropout可以用于解决由于参数多而样本少导致的过拟合问题。
针对这些问题的解决方法可以有上面几种,比如如果在训练集上的结果不好,我们可以尝试换一个激活函数。
在手写数字识别中,激活函数就从Sigmoid
换到了relu
。
激活函数是Sigmoid
的情况下,当隐藏层的数量到了9,10层的时候,整个准确率就不忍直视了。见深度学习实例——Keras实现手写数字识别
造成上面这种情况有个原因是梯度消失问题(Vanishing Gradient Problem)
当网络很深的时候,靠近输入层的前面几层中的参数(权重和偏差)对最后损失函数的影响很小,而在靠近输出层的几层中的参数影响很大。
所以会发现在靠近输入的地方参数更新很慢,而靠近输出的地方参数更新很快。在输入的地方参数几乎还是随机初始值的时候,输出的地方参数已经收敛了。
∂ C ∂ w = ? Δ C Δ w \frac{\partial C}{\partial w} = ?\frac{\Delta C}{\Delta w} ∂w∂C=?ΔwΔC 参数 w w w对总损失的影响程度可以理解为,当对参数 w w w进行微调时,比如改变 Δ w \Delta w Δw对总损失的改变量 Δ C \Delta C ΔC有多大。
比如我们调整了靠近输入层参数,调整了很大的
Δ
w
\Delta w
Δw,这可以直接影响临近网络层输出的值,但是由于Sigmoid
函数的特性,这个影响会逐层衰减的。
观察它的函数图像就知道了。
它会把负无穷大到正无穷大强行压缩到0和1之间,如果有很大的输入变化,通过该函数后得到的输出变化会很小。而每通过一层的Sigmoid
函数,它的影响又一次衰减,最后对总损失的影响也就很小了。
那怎么解决这个问题呢,有人提出了修正线性单元函数(ReLU)。
ReLU
z z z是这个激活函数的输入, a a a是这个激活函数的输出,如果输入大于零,输出就等于输入;如果输入小于零,输出就是0.
选择这个激活函数的理由有下:
- 计算很快
- 生物上的原因
- 等同于无穷多不同偏差
Sigmoid
函数叠加的结果 - 可以解决梯度消失问题
这是一个用ReLU
作激活函数的神经网络。根据它的性质,我们知道,它的输出无非就是两种,一是零,二是输入值。在输出值等于输入值的情况下,就是线性的(
a
=
z
a=z
a=z)。
输出是零的神经元其实是不会影响整个输出的,因此可以直接拿掉它们,得到下面这样的图:
整个看起来就是一个很瘦长的线性网络,并且在输入等于输出时,不会出现梯度消失问题。
但是有个问题是,当我们使用ReLU
时,整个网络就变成了线性的了吗?
我们用深度学习就是不想要我们的函数是一个线性的,希望它是一个比较复杂的非线性的。
其实整个网络还是非线性的。怎么说呢,ReLU
虽然在大于零的区间是线性的,在小于等于零的部分也是线性的,但是它整体不是线性的,因为不是一条直线。
的确对于单一的样本A,经过由ReLU
激活函数所构成的神经网络,其过程确实可以等价是经过了一个线性变换M1,
但是对于样本B,在经过同样的网络时,由于每个神经元是否激活(0或者wx+b)与样本A经过时情形不同了(不同样本),
因此B所经历的线性变换M2并不等于M1。因此,ReLU
构成的神经网络虽然对每个样本都是线性变换,
但是不同样本之间经历的线性变换M并不一样,所以整个样本空间在经过ReLU
构成的网络时其实是经历了非线性变换的。
ReLU
还有很多变种,比如一种是这样的。
在ReLU
中,当输入小于零时,微分是0,这样就无法更新参数了。这个变种就是为了解决这个问题,当输入小于零时,
输出还是有一点点值,比如乘上
0.01
0.01
0.01。但是为什么乘以
0.01
0.01
0.01呢,不是其他的呢。因此又有人提出了参数化的ReLU
其中 α \alpha α也可以通过训练数据的梯度下降方法学习出来。
还有人提出了叫做Maxout
的函数。
Maxout
ReLU
是Maxout
的一种特例。它是可以自学习的激活函数。用个例子来解释它。
假设有两个输入,经过权重和偏差得到输出。本来这些输出是需要传给激活函数来得到一个新值的,但是现在并不这么做。
把输出事先分组,每个组里面选出最大的输出值。
可以把上面红色框框起来的部分说成就是神经元,接下来 7 , 1 7,1 7,1又乘上不同的权重,得到不同的输出,同样继续分组,选最大者
实际上组内的数量也是可以超过2的。
我们上面为什么说ReLU
是Maxout
的一种特例呢。
在ReLU
中是这样计算激活函数的输出值
a
a
a的,如果看
x
x
x和
a
a
a的关系,可以如下图绿线所示:
蓝线是 x x x和 z z z的关系。
如果用Maxout
,我们增加一组参数
w
=
0
,
b
=
0
w=0,b=0
w=0,b=0,得到输出
z
2
z_2
z2,然后选则
z
1
,
z
2
z_1,z_2
z1,z2比较大的当成输出
a
a
a:
如果我们看 z 1 z_1 z1和 x x x的关系,得到下图蓝线,看 x x x和 z 2 z_2 z2的关系得到水平的红线:
那再经过选取较大的操作后,实际的输出 a a a和 x x x的关系如绿线所示:
所以看以看出Maxout
能做到ReLU
做到的事情,并且ReLU
做不到的事情,它也可以做到。
比如第二组参数中 w , b w,b w,b不取0,比如取其他一个非零值 w ′ , b ′ w^\prime,b^\prime w′,b′,就可以得到下面这个函数图形:
而这个激活函数长什么样子,是由参数 w , b , w ′ , b ′ w,b,w^\prime,b^\prime w,b,w′,b′决定的,而这些参数是可学习的,因此说它是一个自学习的激活函数。
随着分组内的元素个数不同,它的图形也不同
接下来的问题是Maxout
如何训练呢
因为有个max
,因此它不能微分啊。其实还是可以的,假设我们用红框框出来比较大的值。
对应的输出 a a a就会成了线性的。我们可以拿掉在较大PK中被干掉的权重,就成了下图:
假设给定上面这个一个比较细长的神经网络,既可以用反向传播算法进行训练。但问题是那些没被训练到的被拿掉的权重怎么办。其实因为我们有不同的样本,会得到不同的
z
z
z值,max
值也不一样,也就是整个网络的结构也就不一样,最后每个权重和偏差实际上都会被训练到。
Adagrad 学习率
在机器学习入门之梯度下降中,我们已经探讨过Adagrad学习率
知道参数 w w w的更新会考虑到过去所有的梯度值。但在深度学习中,情况会更加复杂。损失函数的图形可能是任何形状
甚至在同一个方向上(同一个参数
w
w
w),不同区域所需的学习率都不同。因此需要动态调整学习率的方法。
Adagrad有个进阶版,叫RMSProp
RMSProp
这个方法是这么做的
w 1 ← w 0 − η σ 0 g 0 w^1 \leftarrow w^0 - \frac{\eta}{\sigma^0}g^0 w1←w0−σ0ηg0
把固定的学习率 η \eta η除上一个值 σ \sigma σ,第一次的时候 σ 0 = g 0 \sigma^0=g^0 σ0=g0,就是第一次算出的梯度值,在算出新的梯度 g 1 g^1 g1后:
w 2 ← w 1 − η σ 1 g 1 w^2 \leftarrow w^1 - \frac{\eta}{\sigma^1}g^1 w2←w1−σ1ηg1
新的
σ
\sigma
σ值变成了这样计算:
σ
1
=
α
(
σ
0
)
2
+
(
1
−
α
)
(
g
1
)
2
\sigma^1=\sqrt{\alpha(\sigma^0)^2 + (1-\alpha)(g^1)^2}
σ1=α(σ0)2+(1−α)(g1)2
而
α
\alpha
α的值是可以自己调整的。
w 3 ← w 2 − η σ 2 g 2 w^3 \leftarrow w^2 - \frac{\eta}{\sigma^2}g^2 w3←w2−σ2ηg2
这时 σ 2 \sigma^2 σ2是这样计算的: σ 2 = α ( σ 1 ) 2 + ( 1 − α ) ( g 2 ) 2 \sigma^2=\sqrt{\alpha(\sigma^1)^2 + (1-\alpha)(g^2)^2} σ2=α(σ1)2+(1−α)(g2)2
这和原来的Adagrad不一样,原来的Adagrad是计算 g 0 , g 1 , g 2 g^0,g^1,g^2 g0,g1,g2的平方和求均值再开根号。
巧妙之处在于RMSProp可以调整 α \alpha α值,如果设成小一点,就是说更相信新的梯度而无视旧的梯度。
这解决了学习率的问题,那除了这个问题,在做深度学习的时候还可能会卡在局部最小值上。
寻找神经网络最佳参数
可能卡在上面这几种情况,梯度就为0了,也就是参数不更新了。
其实在有很多参数的神经网络中,几乎没有这个问题,可以看成是很平滑的。
我们也可以探讨下如何解决局部最小值问题,我们知道在我们真实世界中,是有惯性的,当一个铁球从山顶滚下来的时候,哪怕到了一个凹点,也可能会因为惯性继续滚动,从而达到真正的最低点。
那么在做梯度下降的时候,如何加上这个惯性呢。
选一个初始值 θ 0 \theta^0 θ0,用 v 0 v^0 v0记录前一个时间点移动的方向。
接下来计算在 θ 0 \theta^0 θ0的梯度,现在要移动的方向并不是红色箭头的方向,而是 v 1 = λ v 0 − η Δ L ( θ 0 ) v^1=\lambda v^0 - \eta \Delta L(\theta^0) v1=λv0−ηΔL(θ0)
因为第一步时还没有惯性,因此还没影响,我们来看第二步
会因为惯性的影响而走的方向是 θ 2 \theta^2 θ2,其中绿线虚线是上一步走的方向,也就是惯性方向。整个过程如下图所示:
在第 i i i个时间点移动的量其实是过去所有算出来的梯度的总和。
我们看 v 2 v^2 v2, v 2 v^2 v2里面同时有 θ 0 \theta^0 θ0和 θ 1 \theta^1 θ1算出来的梯度。这两个梯度的权重也不一样,越之前的梯度对现在方向的影响越小,但是还有一定的影响。
在最后的时候,惯性建议我们继续向右走。这样有可能跳出局部最小点,而走到全局最小点。但是还是有可能跳不出去。
Adam
Adma可以看成是RMSProp+Momentum
在这个算法中,首先要初始惯性 m 0 m_0 m0,而 v 0 v_0 v0是RMSprop中的。
然后算出梯度
g
t
g_t
gt,根据它来算出新的
m
t
m_t
mt,就是现在要走的方向(考虑了过去走的方向加上梯度),
接下来算出
v
t
v_t
vt,它是过去的
v
t
−
1
v_t-1
vt−1加上梯度的平方,
然后把它们都除以一个值,
最后更新
θ
\theta
θ
Early Stopping
如果在训练集中的表现很好,但是在测试集中的表示不好,要怎么做呢?上图介绍了三个方法,这小节先来学习第一个方法。
如果学习率调整的恰当的话,总误差在训练集上会随着不停的训练而变小。因为训练集合测试集不一样,有可能在训练集上总误差减小的时候,在测试集上反而增大。
如果你知道在测试集上总误差的变化,那么应该停在测试集上总误差最小的地方,而不是训练集上总误差最小的地方。
但我们不会真的直到测试集总误差的变化,一般用一个验证集(Validation set)来模拟测试集上的变化。
Regularization(正则化)
正则化重新定义损失函数
假设原来的损失函数是 L ( θ ) L(\theta) L(θ),正则化就是在原来的损失函数基础上加了一些东西(惩罚项)生成一个新的损失函数:
L ′ ( θ ) = L ( θ ) + λ 1 2 ∣ ∣ θ ∣ ∣ 2 L^\prime(\theta) = L(\theta) + \lambda \frac{1}{2}||\theta||_2 L′(θ)=L(θ)+λ21∣∣θ∣∣2
这个叫L2的正则化 ∣ ∣ θ ∣ ∣ 2 = ( w 1 ) 2 + ( w 2 ) 2 + ⋯ ||\theta||_2=(w_1)^2+(w_2)^2 + \cdots ∣∣θ∣∣2=(w1)2+(w2)2+⋯的作用是使得图像更加平滑,防止抖动。
梯度: ∂ L ′ ∂ w = ∂ L ∂ w + λ w \frac{\partial L^\prime}{\partial w}=\frac{\partial L}{\partial w} + \lambda w ∂w∂L′=∂w∂L+λw
现在更新参数会:
w
t
+
1
→
w
t
−
η
∂
L
′
∂
w
=
w
t
−
η
(
∂
L
∂
w
+
λ
w
t
)
=
(
1
−
η
λ
)
w
t
−
η
∂
L
∂
w
w^{t+1} \rightarrow w^t - \eta \frac{\partial L^\prime}{\partial w} = w^t - \eta \left(\frac{\partial L}{\partial w} + \lambda w^t \right) \\ = (1-\eta \lambda)w^t -\eta \frac{\partial L}{\partial w}
wt+1→wt−η∂w∂L′=wt−η(∂w∂L+λwt)=(1−ηλ)wt−η∂w∂L
(
1
−
η
λ
)
(1-\eta \lambda)
(1−ηλ)中,假设
η
λ
=
0.01
\eta \lambda=0.01
ηλ=0.01,会使得每次更新
w
t
w^t
wt都变小一点。
L1的正则化就是 ∣ ∣ θ ∣ ∣ 1 = ∣ w 1 ∣ + ∣ w 2 ∣ + ⋯ ||\theta||_1=|w_1| +|w_2| + \cdots ∣∣θ∣∣1=∣w1∣+∣w2∣+⋯ 其中两个竖线是绝对值
L ′ ( θ ) = L ( θ ) + λ 1 2 ∣ ∣ θ ∣ ∣ 1 L^\prime(\theta) = L(\theta) + \lambda \frac{1}{2}||\theta||_1 L′(θ)=L(θ)+λ21∣∣θ∣∣1
梯度: ∂ L ′ ∂ w = ∂ L ∂ w + λ s g n ( w ) \frac{\partial L^\prime}{\partial w}=\frac{\partial L}{\partial w} + \lambda sgn(w) ∂w∂L′=∂w∂L+λsgn(w)
对于sgn
函数,如果
w
w
w是正数,它输出是
1
1
1,;如果是负数,它输出是
−
1
-1
−1,它的图像如下:
更新参数:
w
t
+
1
→
w
t
−
η
∂
L
′
∂
w
=
w
t
−
η
(
∂
L
∂
w
+
λ
s
g
n
(
w
t
)
)
=
w
t
−
η
∂
L
∂
w
−
η
λ
s
g
n
(
w
t
)
w^{t+1} \rightarrow w^t - \eta \frac{\partial L^\prime}{\partial w} = w^t - \eta \left(\frac{\partial L}{\partial w} + \lambda sgn(w^t) \right) \\ = w^t -\eta \frac{\partial L}{\partial w} - \eta\lambda sgn(w^t)
wt+1→wt−η∂w∂L′=wt−η(∂w∂L+λsgn(wt))=wt−η∂w∂L−ηλsgn(wt)
如果
w
t
w^t
wt是正的,
η
λ
s
g
n
(
w
t
)
\eta\lambda sgn(w^t)
ηλsgn(wt)就是正的,会减去一些;如果
w
t
w^t
wt是负的,
η
λ
s
g
n
(
w
t
)
\eta\lambda sgn(w^t)
ηλsgn(wt)也是负的,就会加上一些正数,整个负的变小。