深度神经网络损失函数和反向传导

2021/12/22 23:53:10

本文主要是介绍深度神经网络损失函数和反向传导,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

       之前对于深度神经网络的学习,主要集中于如何更改模型结构,以及了解模型结构不同部分所起到的作用和原理。虽然对于注意力机制、GAT、LSTM、Transformer等不同结构的实现原理有了很好的了解,但是对于神经网络的损失函数和反向传导过程的理解程度较为差劲,如何设计损失函数可以更好地适应任务以及Max Pooling如何反向传导等问题一时语塞不知如何作答。回想起正好一年前看的吴恩达老师的视频,虽然对理论基础有了一定的了解,但是了解程度较为浅薄,并且由于时间紧迫并未将老师全部的视频看完吃透,现如今对于魔改模型有了一定的了解,因此非常有必要更加彻底地了解吃透损失函数和各个模块反向传导的数学原理。

反向传播

参考:神经网络反向传播算法公式推导 (描述正常全连接层的梯度变化)

反向传播(Backpropagation, 缩写为BP)是“误差反向传播”的简称,是一种与最优化方法(例如:梯度下降法)结合使用的,用来训练神经网络的常见方法。

该方法对网络中所有权重计算损失函数的梯度,这个梯度会反馈给最优化方法,用来更新权值以最小化损失函数。反向传播算法会先按前向传播方式计算每个结点的输出值,然后再按反向传播遍历图的方式计算损失函数值相对于每个参数的偏导数。

反向传播算法基于梯度下降的思想,以目标负梯度方向对参数进行调整,参数的更新为w = w - \alpha \frac{\partial Loss}{\partial w},根据链式求导法则,可以对所有的参数进行更新。我们可以将整个深度网络视为是一个复合的非线性多元函数f(x),我们最终的目的是希望这个多元函数可以很好地完成输入到输出之间的映射。假设不同的输入,输出的最优解是g(x),那么优化深度网络就是为了寻找到合适的权值,满足Loss = L(g(x), f(x))取得到极小值点,比如最简单的损失函数Loss = \left \| g(x) - f(x) \right \|_{2}^{2}。我们最优的权值就是为了寻找函数的最小值点,对于数学中寻找最小值的问题,采用梯度下降的方法最为合适。

导数、偏导数、方向导数、梯度

参考:梯度与梯度下降法

导数

导数反映的是函数y = f(x)在某一点处沿x轴正方向的变化率。

偏导数

导数与偏导数本质是一样的,都是当自变量的变化量趋于0时,函数值的变化量与自变量变化量比值的极限。直观而言,偏导数就是函数在某一点上沿坐标轴正方向的变化率 。偏导数指的是多元函数在某一点处沿某一坐标轴正方向的变化率。

 方向导数

导数、偏导数表达的是函数沿坐标轴正方向的变化率。方向导数表达的是函数的某一点在趋近方向上的导数值。方向导数就是函数在特定方向上的变化率。

梯度

梯度表明函数在变量空间的某一点处,沿着哪一个方向有最大的变化率?函数在某一点的梯度是这样一个向量,它的方向与取得最大方向导数的方向一致,而它的模为方向导数的最大值。

  • 梯度是一个向量,有方向有大小
  • 梯度的方向是最大方向导数的方向
  • 梯度的值是最大方向导数的值

梯度下降法

既然在变量空间的某一点处,函数沿梯度方向具有最大的变化率,那么在优化目标函数的时候,自然沿着负梯度方向去减小函数值,以达到优化函数的目标。既然梯度是偏导数的集合

同时梯度和偏导数都是向量,那么参考向量运算法则,在每个变量轴上减小对应变量值即可,梯度下降法描述如下:

特殊结构反向传播

参考:CNN中一些特殊环节的反向传播

传统神经网络无论隐层还是激活函数都是可导的,可以计算出导数函数。然而在深度神经网络中存在一些不可导的特殊结构(ReLU激活函数,池化采样......),故需搞懂特殊结构的导数计算。

(1)ReLU函数的导数计算

由于ReLU函数在 x = 0 处是不可微的,因此深度学习框架的代码直接将其在 x = 0 处的导数置为1,所以ReLU的导数就变成:

\delta_{ReLU(x)} = 1, x >= 0; \delta_{ReLU(x)} = 0, x < 0

ReLU激活函数相比较于Sigmoid函数的作用

  • 防止梯度弥散(sigmoid导数在正负饱和区梯度接近于0, 所以会造成梯度弥散,而ReLU函数在大于0的部分梯度为常熟,故不会产生梯度弥散现象)
  • 稀疏激活性(ReLU函数在负半区的导数为0,所以神经元激活值进入负半区,梯度变为0,神经元不会经历训练,即所谓的稀疏性)
  • 加快计算(ReLU导数计算更快,程序实现为if-else语句,而sigmoid导数需要进行浮点四则运算)

注:ReLU激活函数非线性映射能力弱,通常ReLU函数需要配合batchnorm函数使用。batchnorm是一个非线性映射的过程,也算起到非线性映射的作用。

(2)Pooling池化操作的反向梯度传播

因为Pooling操作使得feature map的尺寸发生变化,故池化操作将一个像素的梯度传递给多个像素,但是需要保证传递的loss(或梯度)总和不变,故mean pooling和max pooling的反向传播也是不同的。

mean pooling

反向传播的过程就是把某个元素的梯度等分成n份分配给前一层,这样就保证池化层前后的梯度之和保持不变。

max pooling

max pooling的前向传播是把patch中最大的值传递给下一层,而其他像素的值直接被舍弃。故反向传播也就是把梯度直接传给前一层某一个像素,而其他像素不接受梯度,置为0。

池化层的作用

  • 特征不变性:汇合操作使得模型更关注是否存在某些特征,而不是特征具体位置,可以看作是一种很强的先验,使得特征学习包含某种程度自由度,能容忍一些特征微小的位移(支持平移、旋转、拉伸不变性)
  • 特征降维:可以保留相应的特征,主要用来降低维度(max pooling能使误差稀疏,mean pooling能使误差均摊)
  • 防止过拟合:由于该层没有参数,故不需要学习

注:增加感受野,减少噪声,精简主要特征;提高模型非线性;减少计算量

梯度爆炸梯度消失

参考:机器学习中的梯度消失、爆炸原因及其解决方法

梯度消失情况:(1)深层网络 (2)采用不合适的激活函数(eq: sigmoid)

梯度爆炸情况:一般出现在深层网络和权值初始化值太大

从深层网络角度而言,不同的层学习的速度差异很大,表现为网络中靠近输出的层学习的情况较快,靠近输入的层学习得较慢。因此,梯度消失、爆炸,其根本原因在于反向传播训练法则。

从激活函数角度而言,如果激活函数选择不合适(sigmoid, tanh等),梯度会消失明显,很容易发生梯度消失。

梯度消失、爆炸解决方案

(1)梯度裁剪、正则化

梯度裁剪方案主要针对梯度爆炸提出来的,其思想是设置一个梯度剪切阈值,在更新梯度的时候,如果梯度超过这个阈值,那么就将其强制限制在这个范围内,这样可以防止梯度爆炸。

权重正则化(weights regularization)用来解决梯度爆炸的问题,较为常见的是l1正则、l2正则。正则化是通过对网络权重做正则限制过拟合,正则项在损失函数的形式:Loss = (y - W^{T}x)^{2} + \alpha \left \| W \right \|^{2},其中,\alpha是指正则项系数,因此,如果发生梯度爆炸,权值的范数会变得非常大,通过正则化项,可以部分限制梯度爆炸的发生。

(2)relu、leakrelu、elu等激活函数

在正值情况下,激活函数的导数为1,不存在梯度消失爆炸的问题,每层网络可以得到相同的更新速度,relu、leakreul、elu因此应运而生。

(3)batchnorm、layernorm

Batchnorm目前已经被广泛应用到各大网络中,具有加速网络收敛速度,提升训练稳定性的效果。Batchnorm本质上是解决反向传播过程中的梯度问题。Batchnorm全名batch normalization,简称BN,即批规范化,通过规范化操作将输出信号规范化以保证网络的稳定性。

正向传播过程f_{2} = f_{1}(W^{T}x + b),在反向传播过程中,\frac{\partial f2}{\partial w} = \frac{\partial f2}{\partial f1} x,反向传播的式子中有x存在,x的大小影响了梯度的消失和爆炸,batchnorm就是通过对每一层的输出规范为均值和方差一致的方法,消除了x带来的放大缩小的影响,进而解决梯度消失和爆炸的问题。

(4)残差结构

损失函数

参考:交叉熵损失函数 、损失函数设计

损失函数用来评价模型的预测值真实值不一样的程度,损失函数越好,通常模型的性能越好,不同的模型使用的损失函数一般也不尽相同。

在机器学习建模时,尤其是传统方法中能自由发挥的地方除了各种特征工程外,也就是目标函数的设计。损失函数、代价函数和目标函数三者之间的关系大概是

preview

损失函数的设计要考虑符合问题所选定的ground truth, 如果有多个ground truth,还需要做好trade-off。同时,损失函数要求有合理的梯度,可以被求解。 

问题:在图片分类任务中,为什么采用交叉熵损失函数,而不使用均方误差损失函数

Mean Squared Error(均方误差)

均方误差损失是一种比较常见的损失函数,其定义为:MSE = \frac{1}{n} \sum_{i}^{n} (\hat{y_{i}} - y_{i})^{2},主要原因在分类问题中,使用sigmoid/softmax得到概率,配合MSE损失函数时,采用梯度下降法进行学习时,会出现模型一开始训练时,学习速率非常慢的情况。

Cross Entropy Loss Function(交叉熵损失函数)

二分类,模型最后需要预测的结果只有两种情况,对于每个类别我们预测得到的概率为p1-p

L = \frac{1}{N}\sum_{i}^{} L_{i} = \frac{1}{N}\sum_{i}^{} -[y_{i} log(p_{i}) + (1 - y_{i}) log(1 - p_{i})]

其中:y_{i} -- 表示样本i的label,正类为1,负类为0;p_{i} -- 表示样本i预测为正类的概率

多分类,情况实际上就是对二分类的扩展:

L = \frac{1}{N} \sum_{i}^{} L_{i} = - \frac{1}{N} \sum_{i} \sum_{c=1}^{M}y_{ic}log(p_{ic})

其中:M -- 类别的数量;y_{ic} -- 符号函数(0 或 1),如果样本i的真实类别等于c取1, 否则取0;p_{ic} -- 观测样本i属于类别c的预测概率

该交叉熵损失函数是凸函数,求导时能够得到全局最优值。

交叉熵损失函数常用于分类问题中,特别是在神经网络做分类问题时,也经常使用交叉熵作为损失函数,此外,由于交叉熵涉及到计算每个类别的概率,所以交叉熵几乎每次都和sigmoid(softmax)函数一起出现。整个模型预测、获得损失和学习的过程:

1)神经网络最后一层得到每个类别的分数scores(logits)

2)该得分经过sigmoid(softmax)函数获得概率输出

3)模型预测的类别概率输出与真实类别的one hot形式进行交叉熵损失函数的计算。

在用梯度下降法做参数更新的时候,模型学习的速度取决于两个值:一、学习率;二、偏导值。其中,学习率是我们需要设置的超参数,故我们重点关注偏导值。

缺点

Softmax loss的两个缺点:1、随着分类数目的增大,分类层的线性变化矩阵参数也随着增大。2、对于封闭集分类问题,学习到的特征是可分离的。        sigmoid(softmax)+ cross-entropy loss擅长于学习类间的信息,因为它采用类间竞争机制,它只关心对于正确标签预测概率的准确性,而忽略了其他非正确标签的差异,导致学习到的特征比较散。基于该问题的优化有(对softmax进行改进, 如L-Softmax、SM-Softmax、AM-Softmax等)

常见损失函数

损失函数是一个非负实数函数,用来量化模型预测和真实标签之间的差异。

1)平方损失函数(MSE)

J(\theta) = \frac{1}{2} (y - \bar{y})^{2},简单直观,易于求导,通常用于回归任务。

2)绝对值损失函数(MAE)

J(\theta) = | y - \bar{y}|, 导数不连续(对异常值不敏感;梯度始终相同,可能导致神经网络不收敛)

3)Huber损失函数

Huber Loss是一种用于回归问题的有参损失函数,其结合了MSE(处处可导)和MAE(对异常值不敏感)的优点。当预测偏差小于delta时,采用平方误差;当预测偏差大于delta时,采用线性误差。其中delta是需要确定的超参数。

Huber Loss定义如下:

preview

但是要求损失函数二阶可导的情况下Huber Loss似乎存在问题,此时使用Psuedo-Huber Loss代替。(Xgboost)

preview

 4)Hinge损失函数

preview

Hinge Loss通常用于分类问题,比如SVM。其中,Y为目标值(-1 或 +1),f(x)是分类器输出的预测值,并不直接是类标签。当Y和f(x)的符号相同时, 并且| f(x) | \geq 1时,hinge loss为0, 当Y和f(x)的符号相反时,hinge loss随着f(x)的增大线性增大。

5)交叉熵损失函数



这篇关于深度神经网络损失函数和反向传导的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程