神经网络基础篇
本章内容主要描述了在机器学习中的前向传播,反向求导的原理与计算,常见的激活函数和损失函数,以及在网络训练过程中过拟合,梯度消失/爆炸等产生的原理以及解决方案。本人也在学习过程中,如果有错误之处,请各位多多指教。
1.1 神经网络的前向传播
我们首先定义如下图所示的神经网络,为了简单起见,所有的层都不加偏置。其中,\(X\) 表示输入层,\(Z_{i}^{j}\) 表示第 \(j\) 个隐含层的所有神经元,\(W^{j}\) 表示第 \(j\) 层的权重。
因此:
\]
所以:
\]
最终的 \(Loss\) 函数可以表示为:\(Loss = \dfrac{1}{2}(y^{i} – y_{out})^{2}\)
在训练过程中,我们要保证 \(Loss\) 越小越好,因此采用梯度下降的方法来求解网络的参数 \(W = [w_{11}^{1},w_{21}^{1},…,w_{21}^{3}]\),于是就需要求解 \(Loss\) 对所有参数的偏导数 \(\nabla L(w) = [\dfrac{\partial L(w)}{\partial w_{11}^{1}}, \dfrac{\partial L(w)}{\partial w_{12}^{1}},…\dfrac{\partial L(w)}{\partial w_{21}^{3}}]^{T}\),于是权重更新公式可以写为:
\]
1.2 神经网络的反向求导
在上一节中, 我们大致对神经网络的梯度更新有了了解,其中最核心的部分就是求出损失函数对权重 \(w_{ij}^{l}\) 的导数。由于网上大多数资料都是生搬硬套,因此我们以计算 \(W^{1}\) 的导数为例,对整个反向求导过程进行细致的剖析。如下图所示:
其中,\(w_{jk}^{l}\) 表示从第 \(l\) 层的第 \(j\) 个节点到第 \(l+1\) 层中的第 \(k\) 个节点的权重,根据前向传播的计算我们可以得到:
y_{out} \sim (w_{11}^3 w_{11}^2 + w_{21}^3 w_{12}^2 ) w_{21}^1 x_{2}, \dfrac{\partial y_{out}}{\partial w_{21}^1} = (w_{11}^3 w_{11}^2 + w_{21}^3 w_{12}^2 )x_{2} \\
y_{out} \sim (w_{11}^3 w_{21}^2 + w_{21}^3 w_{22}^2 ) w_{12}^1 x_{1}, \dfrac{\partial y_{out}}{\partial w_{12}^1} = (w_{11}^3 w_{21}^2 + w_{21}^3 w_{22}^2 )x_{1}; \quad
y_{out} \sim (w_{11}^3 w_{21}^2 + w_{21}^3 w_{22}^2 ) w_{22}^1 x_{1}, \dfrac{\partial y_{out}}{\partial w_{22}^1} = (w_{11}^3 w_{21}^2 + w_{21}^3 w_{22}^2 )x_{2} \\
y_{out} \sim (w_{11}^3 w_{31}^2 + w_{21}^3 w_{32}^2 ) w_{13}^1 x_{1}, \dfrac{\partial y_{out}}{\partial w_{13}^1} = (w_{11}^3 w_{31}^2 + w_{21}^3 w_{32}^2 )x_{1}; \quad
y_{out} \sim (w_{11}^3 w_{31}^2 + w_{21}^3 w_{32}^2 ) w_{23}^1 x_{2}, \dfrac{\partial y_{out}}{\partial w_{23}^1} = (w_{11}^3 w_{31}^2 + w_{21}^3 w_{32}^2 )x_{2}
\]
用矩阵表示为:
\]
因此,整个反向传播的过程如下:
首先计算:\(\dfrac{\partial L}{\partial W^{3}} = \dfrac{\partial L}{\partial y_{out}}\odot (\dfrac{\partial y_{out}}{\partial W^{3}})^{T} = \dfrac{\partial L}{\partial y_{out}}\odot [\dfrac{\partial y_{out}}{\partial w_{11}^{3}},\dfrac{\partial y_{out}}{\partial w_{12}^{3}}]^{T} = \dfrac{\partial L}{\partial y_{out}} \odot (Z^{2})^{T}\)
然后计算:\(\dfrac{\partial L}{\partial W^{2}} = \dfrac{\partial L}{\partial y_{out}} (\dfrac{\partial y_{out}}{\partial Z^{2}} \odot \dfrac{\partial Z^{2}}{\partial W^{2}})^{T} = \dfrac{\partial L}{\partial y_{out}}(\dfrac{\partial y_{out}}{\partial Z^{2}}\odot Z^{1})^{T} = \dfrac{\partial L}{\partial y_{out}}(W^{3}\odot Z^{1})^{T}\)
最后计算:\(\dfrac{\partial L}{\partial W^{1}} = \dfrac{\partial L}{\partial y_{out}} (\dfrac{\partial y_{out}}{\partial Z^{2}} \dfrac{\partial Z^{2}}{\partial Z^{1}}\odot \dfrac{\partial Z^{1}}{\partial W^{1}})^{T} = \dfrac{\partial L}{\partial W^{1}} (W^{3}W^{2}\odot X)^{T}\)
为了方便计算,反向传播通过使用计算图的形式在 Tensorflow,PyTorch 等深度学习框架中实现,将上述过程绘制成计算图如下:
根据计算图,可以轻而易举地计算出损失函数对每个变量的导数。
1.3 激活函数
1.3.1 sigmoid 激活函数
我们通常就用其中最常用的logistic函数来代指sigmoid函数:
\]
特点:sigmoid函数和阶跃函数非常相似,但是解决了光滑和连续的问题,同时它还成功引入了非线性。由于其值域处在0~1,所以往往被用到二分类任务的输出层做概率预测。
缺点:
- 当输入值大于3或者小于-3时,梯度就非常接近0了,在深层网络中,这非常容易造成“梯度消失”(也就是反向传播时误差难以传递到前面一层)而使得网络很难训练。
- 其解析式中含有幂运算,计算机求解时相对来讲比较耗时。
1.3.2 Softmax 激活函数
Softmax 又称归一化指数函数, 适用于只有一个正确答案多类别分类问题(例如手写数字)。构建分类器,解决只有唯一正确答案的问题时,用Softmax函数处理各个原始输出值。
\]
Softmax函数是二分类函数Sigmoid在多分类上的推广,目的是将多分类的结果以概率的形式展现出来。直白来说就是将原来的输出映射成为 (0,1) 的值,而这些值的累和为1(满足概率的性质),我们就可以选取概率最大(也就是值对应最大的)结点,作为我们的预测目标。
1.3.3 tanh函数
\]
这个tanh函数又被称作双曲正切函数,可以看出它的函数范围是(-1,1)而均值为0。
缺点:该函数依旧没有解决梯度消失和幂运算的问题。
1.3.4 ReLu函数
ReLu函数是当前最常用的一个激活函数,尤其是在卷积神经网络和层次较深的神经网络中。
\]
优点:
- 解决了gradient vanishing问题 (在正区间),因为大于0的梯度始终为1
- 计算速度非常快,只需要判断输入是否大于0,不含数学运算
- 收敛速度远快于 sigmoid 和 tanh
缺点:对于小于0的这部分值,梯度会迅速降为0而不再影响网络训练。这会造成部分神经元从来不被激活,也称作“死区”。
1.3.5 Leaky ReLu
y_{i} & i f, & y_{i}>0 \\
0.01 * y_{i} & \text { if, } & y_{i} \leq 0
\end{array}\right.
\]
将 \(x<=0\) 部分调整为 \(f(x)=αx\), 其中 \(α\) 一般设为一个较小的正数如 0.01 或 0.001。
特点:将小于0部分的梯度从零提高到 \(α\),给了这些被抑制部分一定参与网络训练的可能。在 PReLU 中,将参数 \(\alpha\) 作为可学习的参数,从而避免了 Leaky ReLu 中的 \(\alpha\) 选择问题。
1.4 损失函数
1.4.1 L1 和 L2 损失函数
平均绝对误差(L1 Loss): 平均绝对误差(Mean Absolute Error,MAE) 是指模型预测值f(x)和真实值y之间距离的平均值,其公式如下:
\]
均方误差MSE (L2 Loss):均方误差(Mean Square Error,MSE)是模型预测值f(x) 与真实样本值y 之间差值平方的平均值,其公式如下
\]
1.4.2 交叉熵(Cross Entropy)损失函数
\]
这里的 \(y\) 代表真实值,0或1,\(y_{out}\) 代表预测值/估计值,值为一个概率,取值范围0~1,那么对某个输出节点来讲,所对应的 \(y\) 只有两种情况,即:\(y=0,\quad y=1\)。于是:
- 当 \(y=0\) 时,\(L=-log(1-y_{out})\),要保证 \(L\) 最小,那么 \(y_{out}\) 必须为0;
- 当 \(y=1\) 时,\(L=-log(y_{out})\),要保证 \(L\) 最小,那么 \(y_{out}\) 必须为1。
所以,交叉熵损失函数的目的就是要使得每一个样本属于其真实值的概率最大化,其函数图像如下所示:
从上图可以看出,相对于 MSE 做多分类任务的损失函数,使用交叉熵的优点为:用平方误差损失函数,误差增大参数的梯度会增大,但是当误差很大时,参数的梯度就会又减小了。而使用交叉熵损失作为函数,误差越大参数的梯度也越大,能够快速收敛。
1.4.3 不同分类问题的损失函数选择
- 二分类 Sigmoid函数 二分类交叉熵损失函数(binary_crossentropy)
- 多分类 Softmax函数 多类别交叉熵损失函数(categorical_crossentropy)
- 多标签分类 Sigmoid函数 二分类交叉熵损失函数(binary_crossentropy)
1.5 优化算法
由于在之前的文章中就系统介绍过优化算法,为了本章节系统知识的完整性,在这里简单地列举一些内容,有兴趣了解的请参考://www.cnblogs.com/zhaozhibo/p/15098452.html。
1.5.1 一阶方法
- SGD:在每轮迭代中,随机优化某一条训练数据上的损失函数。由于单个样本并不能代表全体样本的趋势,造成损失函数严重震荡,影响准确性。后来改进为批量梯度下降。
- Momentum:更新的时候在一定程度上保留之前更新的方向,同时利用当前batch的梯度微调最终的更新方向,使算法具有一定的摆脱局部最优解的能力。
- AdaGrad:将参数的梯度之和作为分母,从而实现:1)对于经常更新的参数,不希望被单个样本影响太大,希望学习速率慢一些;2)对于偶尔更新的参数,希望学习速率大一些。
- RMSProp:在AdaGrad的基础上,不累积全部历史梯度,而只关注过去一段时间窗口的下降梯度。
- Adam:Adam = RMSProp+Momentum,除了像 RMSprop 一样存储了过去梯度的平方的指数衰减平均值 ,也像 momentum 一样保持了过去梯度的指数衰减平均值。
1.5.2 二阶方法
- 牛顿法:目标函数必须具有连续的一、二阶偏导数,海海森矩阵必须正定,且计算量大,每次迭代都要计算海森矩阵和它的逆矩阵。
- 拟牛顿法:不⽤⼆阶偏导数而构造出可以近似海森矩阵或者海森矩阵的逆的正定对称阵,在拟⽜顿的条件下优化目标函数。不同的构造⽅法就产生了不同的拟牛顿法。
1.6 过拟合
过拟合(overfitting)是指在模型参数拟合过程中,在训练集上准确度很高而在测试集上准确度很低。
从数学角度上来理解过拟合产生原因:神经网络就是根据输入数据 \(X\), 通过学习权重 \(W\) 来将 \(X\) 映射到所希望的输出 \(Y\)。因此整个过程可以描述为:
\]
实际上,在深度学习训练中,输入特征 \(X\) 的维度 \(n\) 远远大于方程组的个数 \(m\),因此上述方程存在无穷多解,最后的结果就容易掉进非正常的局部最优解(过拟合解)中。因此,过拟合的解决办法主要有两个方面:
增加方程个数:即增加样本量
- 翻转,旋转,缩方,平移;
- 上下采样,图像融合,平移等。
减少特征维度:
- 减少模型复杂度,使用更小的网络;
- 在loss中添加正则化项,使部分权重为0,缩小解空间,从而减少求出过拟合解的可能性;
- 采取 dropout,随机失活部分权重;
- 添加 batch normalization 层;
- 使用 PCA 等方法对特征进行降维。
1.7 梯度爆炸与梯度消失
1.7.1 梯度消失
在反向传播中由于链式求导法则的连乘,如果乘数都比较小趋于0,最终传递到网络输入层的梯度会变得很小,导致梯度更新缓慢甚至不更新(梯度消失)。
梯度消失的原因:(1)隐藏层的层数过多;(2)采用了不合适的激活函数(sigmoid)
1.7.2 梯度爆炸
在反向传播中由于链式求导法则的连乘,如果乘数都比较大,最终传递到网络输入层的梯度会变得很大(梯度爆炸)。
梯度爆炸的原因:(1)隐藏层的层数过多;(2)权重的初始化值过大
1.7.3 梯度爆炸与梯度消失的解决方案
- 用ReLU、Leaky-ReLU、P-ReLU、R-ReLU、Maxout等替代sigmoid函数;
- 用Batch Normalization;
- 预训练+微调;
- 使用残差网络。