如果不使用激活函数,那么在神经网络中,每一层的节点的输入都是上一层输出的线性函数。那么神经网络不论有多少层,输出的都是输入的线性组合,这时候网络的逼近或者说表达能力就十分有限了,所以引入了非线性函数作为激活函数,增强网络的表达能力,使其能够逼近于任何函数。
s i g m o i d = σ ( x ) = 1 1 + e − x sigmoid = \sigma(x)=\frac{1}{1+e^{-x}} sigmoid=σ(x)=1+e−x1
优点:
缺点:
import numpy as np
class SigmoidActivator(object):
def forward(self, weighted_input):
return 1.0/(1.0 + np.exp(-weighted_input))
def backward(self, output):
return output * (1 - output)
t a n h ( x ) = e x − e − x e x + e − x tanh(x) = \frac{e^x-e^{-x}}{e^x+e^{-x}} tanh(x)=ex+e−xex−e−x
优点:
缺点:
class TanhActivator(object):
def forward(self, weighted_input):
return 2.0/(1.0 + np.exp(-2 * weighted_input)) - 1.0
def backward(self, output):
return 1 - output * output
r e l u ( x ) = m a x ( 0 , x ) relu(x)=max(0,x) relu(x)=max(0,x)
优点:
缺点
改进
class ReLUActivator(object):
def forward(self, weighted_input):
return weighted_input[weighted_input<0] = 0
def backward(self, output):
grad[output > 0] = 1
gard[output <= 0] = 0
return gard
定义: ReLU在负数区域被kill的现象叫做神经元坏死现象。当 x < 0 x<0 x<0 的时候,梯度为0。这个神经元及之后的神经元梯度都为0,不再对任何数据有所响应,导致相应的参数永远不会更新。
原因: 产生神经元坏死的原因有两个,一个是参数初始化问题,另一个是学习率太高导致在训练过程中参数更新太大导致权重成为了负数。
解决办法:
以sigmoid函数及tanh函数为例子,解释非0均值问题带来的影响
首先需要给收敛速度做一个诠释。模型的最优解即是模型参数的最优解。通过逐轮迭代,模型参数会被更新到接近其最优解。这一过程中,迭代轮次多,则我们说模型收敛速度慢;反之,迭代轮次少,则我们说模型收敛速度快。
深度学习一般的学习方法是反向传播。简单来说,就是通过链式法则,求解全局损失函数 L L L 对于某一参数 w w w 的偏导数(梯度),而后辅以学习率 η \eta η,向梯度的反方向更新参数 w w w w ← w − η ⋅ ∂ L ∂ w w \leftarrow w -\eta \cdot \frac{\partial L}{\partial w} w←w−η⋅∂w∂L
考虑学习率 η \eta η 是全局设置的超参数,参数更新的核心步骤就是计算 ∂ L ∂ w \frac{\partial L}{\partial w} ∂w∂L。再考虑到对于某个神经元来说,其输入和输出的关系是 f ( x ; w , b ) = f ( z ) = f ( ∑ i w i x i + b ) f(x;w,b)=f(z)=f(\sum_i w_ix_i+b) f(x;w,b)=f(z)=f(i∑wixi+b)
因此,对于参数 w i w_i wi 来说 ∂ L ∂ w i = ∂ L ∂ f ∂ f ∂ z ∂ z ∂ w i = x i ⋅ ∂ L ∂ f ∂ f ∂ z \frac{\partial L}{\partial w_i}= \frac{\partial L}{\partial f} \frac{\partial f}{\partial z} \frac{\partial z}{\partial w_i}=x_i \cdot \frac{\partial L}{\partial f} \frac{\partial f}{\partial z} ∂wi∂L=∂f∂L∂z∂f∂wi∂z=xi⋅∂f∂L∂z∂f
因此,参数更新的步骤可以变为 w i ← w i − η x i ⋅ ∂ L ∂ f ∂ f ∂ z w_i \leftarrow w_i - \eta x_i \cdot \frac{\partial L}{\partial f} \frac{\partial f}{\partial z} wi←wi−ηxi⋅∂f∂L∂z∂f
由于 w i w_i wi 是上一轮迭代的结果,此处可以视为常数,而 η \eta η 是模型超参数,参数 w i w_i wi 的更新方向实际上由 x i ⋅ ∂ L ∂ f ∂ f ∂ z x_i \cdot \frac{\partial L}{\partial f} \frac{\partial f}{\partial z} xi⋅∂f∂L∂z∂f 决定。
又考虑到 ∂ L ∂ f ∂ f ∂ z \frac{\partial L}{\partial f} \frac{\partial f}{\partial z} ∂f∂L∂z∂f 对于所有的 w i w_i wi 来说是常数,因此各个 w i w_i wi 更新方向之间的差异,完全由对应的输入值 x i x_i xi 的符号决定的。
至此,为了描述的方便,我们以二维的情况为例,神经元的描述为 f ( x ; w , b ) = f ( w 0 x 0 + w 1 x 1 + b ) f(x;w,b)=f(w_0x_0+w_1x_1+b) f(x;w,b)=f(w0x0+w1x1+b)
现在假设,参数 w 0 , w 1 w_0,w_1 w0,w1 的最优解 w 0 ∗ , w 1 ∗ w_0^*,w_1^* w0∗,w1∗ 满足条件 { w 0 < w 0 ∗ w 1 ≥ w 1 ∗ \begin{cases} &w_0
这也就是说,我们希望 w 0 w_0 w0 适当的增大,但是希望 w 1 w_1 w1 适当减小。考虑到上一小节提到的更新方向的问题,这就必然要求 x 0 x_0 x0 和 x 1 x_1 x1 符号相反。
但是在 sigmoid 函数中,输出值恒为正。这也就是说,如果上一级神经元采用 Sigmoid 函数作为激活函数,那么我们无法做到 x 0 x_0 x0 和 x 1 x_1 x1 符号相反,此时,模型为了收敛,不得不走Z字形逼近最优解。
如图所示,模型参数走绿色箭头能够最快收敛,但由于输入值的符号总是为正,所以模型参数可能走类似红色折线的箭头。如此一来,使用 Sigmoid 函数作为激活函数的神经网络,收敛速度就会慢上不少了。
详见《深度学习中的归一化方法简介(BN、LN、IN、GN)》
在机器学习的模型中,如果模型的参数太多,而训练样本又太少,训练出来的模型很容易产生过拟合的现象。在训练神经网络的时候经常会遇到过拟合的问题,过拟合具体表现在:模型在训练数据上损失函数较小,预测准确率较高;但是在测试数据上损失函数比较大,预测准确率较低。
过拟合是很多机器学习的通病。如果模型过拟合,那么得到的模型几乎不能用。为了解决过拟合问题,一般会采用模型集成的方法,即训练多个模型进行组合。此时,训练模型费时就成为一个很大的问题,不仅训练多个模型费时,测试多个模型也是很费时。
综上所述,训练深度神经网络的时候,总会遇到两大缺点:
(1)容易过拟合
(2)费时
Dropout可以比较有效的缓解过拟合的发生,在一定程度上达到正则化的效果。
在正向传播的时候,以一定的概率 P 使某些神经元停止工作,即是输出为0;在反向传播的时候,这部分神经元的参数不会更新。具体过程如下:
以 P 的概率随机丢失掉一部分神经元。训练时在特征上乘以 1 1 − p \frac{1}{1-p} 1−p1,或者测试是在特征上乘以 1 − p 1-p 1−p。或者测试的时候在权重上乘以 1 − p 1-p 1−p 以求得到同样的期望。
因为对于一个神经元的输出 x x x,其期望为 0 ⋅ p + ( 1 − p ) x = ( 1 − p ) x 0\cdot p+(1-p)x=(1-p)x 0⋅p+(1−p)x=(1−p)x,这样才能与以P概率丢掉的期望相同。
所有的神经元都参与传播。
(1)取平均的作用。 这种“综合起来取平均”的策略(bagging)通常可以有效防止过拟合问题。因为不同的网络可能产生不同的过拟合,取平均则有可能让一些“相反的”拟合互相抵消。dropout掉不同的隐藏神经元就类似在训练不同的网络,随机删掉一半隐藏神经元导致网络结构已经不同,整个dropout过程就相当于对很多个不同的神经网络取平均。而不同的网络产生不同的过拟合,一些互为“反向”的拟合相互抵消就可以达到整体上减少过拟合。
(2)减少神经元之间复杂的共适应关系。 dropout 会导致两个神经元不会总是同时出现在一个神经网络中,这也就是希望我们的网络不会对特定的网络片段过于敏感,而是学习的更加鲁棒的共有特征。
(3)Dropout类似于性别在生物进化中的角色。 物种为了生存往往会倾向于适应这种环境,环境突变则会导致物种难以做出及时反应,性别的出现可以繁衍出适应新环境的变种,有效的阻止过拟合,即避免环境改变时物种可能面临的灭绝。
感受野指的是卷积神经网络每一层输出的特征图上的像素点在原始图像上映射的区域大小。
n o u t = [ n i n + 2 p − k s ] + 1 n_{out}=[\frac{n_{in}+2p-k}{s}]+1 nout=[snin+2p−k]+1
其中, s s s 为步长, p p p 为 padding 的大小, k k k 为卷积核的大小, n i n n_{in} nin 是输入特征图的大小, n o u t 为 输 出 特 征 图 的 大 小 n_{out}为输出特征图的大小 nout为输出特征图的大小。 j o u t = j i n ∗ s j_{out}=j_{in}*s jout=jin∗s r o u t = r i n + ( k − 1 ) ∗ j i n r_{out}=r_{in}+(k-1)*j_{in} rout=rin+(k−1)∗jin
其中, r i n r_{in} rin 代表上层感受野的大小, j j j 是两相邻特征的距离。
参数量 n u m b e r = K × K × C × O + O + 2 × O number=K\times K \times C \times O+ O +2 \times O number=K×K×C×O+O+2×O
其中, K K K 是卷积核的大小, C C C 是输入的通道数, O O O 是输出的通道数, + O +O +O 是指的偏置, 2 × O 2 \times O 2×O 指的 batchnorm 的参数。
(1)得到输出层的一个像素点,进行 C i n × K 1 × K 2 C_{in} \times K_1 \times K_2 Cin×K1×K2 次乘法,所以总乘法 C i n × K 1 × K 2 × ( C o u t × H o u t × W o u t ) C_{in} \times K_1 \times K_2\times (C_{out} \times H_{out} \times W_{out}) Cin×K1×K2×(Cout×Hout×Wout)
(2)为了得到输出的特征图的某一个位置的像素值,需要加法次数为 C i n × ( K 1 × K 2 − 1 ) + ( C i n − 1 ) + 1 = C i n × K 1 × K 2 C_{in} \times (K_1 \times K_2-1) +(C_{in}-1) +1=C_{in} \times K_1 \times K_2 Cin×(K1×K2−1)+(Cin−1)+1=Cin×K1×K2
其中,第一部分表示在某一个通道进行 K 1 × K 2 K_1 \times K_2 K1×K2 大小的卷积核需要 K 1 × K 2 − 1 K_1 \times K_2-1 K1×K2−1 次加法。每个通道都卷积之后,得到 C i n C_{in} Cin 个数,接下来需要 C i n − 1 C_{in}-1 Cin−1次加法,最后偏置再加上1。
(3)综上所述,需要的加法和乘法数量为 ( C i n × K 1 × K 2 ) × ( C o u t × H o u t × W o u t ) × 2 (C_{in} \times K_1 \times K_2) \times (C_{out} \times H_{out} \times W_{out}) \times 2 (Cin×K1×K2)×(Cout×Hout×Wout)×2
(1)网络退化
在增加网络层数的过程中,训练精度逐渐趋于饱和,继续增加层数,训练精度就会出现下降的情况,而这种下降并不是过拟合造成的,因为其训练误差与测试误差都很大。
神经网络的非线性映射函数(激活函数)使得特征随着前向传播无法完整的保留。因此,使得神经网络不忘初心,能够完整保留特征信息的能力叫做恒等映射。
(2)残差学习
通过前面的分析可以知道,如果深层网络的后面拥有恒等映射的能力,那么模型就可以转化为一个浅层的网络,从而防止网络退化的现象出现。而 resnet 就是使用了残差连接的方式实现了网络的恒等映射: H ( x ) = F ( x ) + x H(x) = F(x)+x H(x)=F(x)+x
当然,这里的一个残差块儿至少要有两个层,如果只有一层的话 y = F ( x ) + x = W x + x = ( W + 1 ) x y=F(x)+x=Wx+x=(W+1)x y=F(x)+x=Wx+x=(W+1)x
残差连接相当于没有起到任何的作用。
(3)解决了什么问题
在 t = 1 时刻,初始化 s 0 s_0 s0,随机初始化 u , v , w u,v,w u,v,w 得到: h 1 = U x 1 + W s 0 h_1=Ux_1+Ws_0 h1=Ux1+Ws0 s 1 = f ( h 1 ) s_1=f(h_1) s1=f(h1) o 1 = g ( V s 1 ) o_1=g(Vs_1) o1=g(Vs1) 其中, f , g f,g f,g 都为激活函数,一般来讲, f f f 为 t a n h tanh tanh 函数, g g g 为 s o f t m a x softmax softmax 函数
缺点:
(1) 遗忘门
通过一个 s i g m o i d sigmoid sigmoid 来决定细胞状态需要丢掉的信息
(2)输入门
(3)更新细胞状态
更新 c t − 1 c_{t-1} ct−1,得到 c t c_t ct,通过遗忘门忘记 c t − 1 c_{t-1} ct−1 中的一部分,通过输入门选择增加的信息
(4)输出门
更新完细胞状态后,根据输入的 h t − 1 , x t h_{t-1},x_t ht−1,xt 来判断输出细胞状态的特征,通过 s i g m o i d sigmoid sigmoid 函数判断丢弃还是保留
RNN中之所以会产生梯度消失问题,是因为其梯度是多个小于1的值连乘导致的。而LSTM 使用累加的形式进行计算,所以导数也是累加的形式,从而解决了梯度消失的问题。
C t = f t ∗ C t − 1 + i t ∗ C t ~ C_t=f_t * C_{t-1}+i_t*\tilde{C_t} Ct=ft∗Ct−1+it∗Ct~ ∂ C t ∂ C t − 1 = f t + C t − 1 ∗ ∂ f t ∂ C t − 1 + ⋯ \frac{\partial C_t}{\partial C_{t-1}}=f_t+C_{t-1}*\frac{\partial f_t}{\partial C_{t-1}}+\cdots ∂Ct−1∂Ct=ft+Ct−1∗∂Ct−1∂ft+⋯
其中, f t f_t ft 这一项在 [0,1] 之间,所以不存在梯度消失的问题。