网站首页 > 技术文章 正文
在之前的《学习笔记六:DNN前向传播算法与后向传播算法》中,我们对DNN的前向反向传播算法进行了数学推导以及总结。里面使用的损失函数为均方差,而激活函数为sigmoid。实际上DNN可以使用的损失函数和激活函数却有不少。那么这些损失函数和激活函数又该如何选择呢?下面就对DNN损失函数和激活函数的选择做一个总结。
一、均方差损失函数+sigmoid激活函数的问题
在讲反向传播算法时,我们使用均方差损失函数和Sigmoid激活函数做了实例,首先我们就来看看均方差+Sigmoid的组合有什么问题
首先来回顾一下Sigmoid激活函数的表达式为:
(1)
的函数图像如下:
从上图可以看到,对于Sigmoid,当z的取值越来越大后,函数曲线变得越来越平缓,意味着此时的倒数越来越小(导数的几何意义就是切线斜率,可以看到切线斜率越来越小)。同样,当z的取值越来越小时,也存在这个问题。仅仅当z取值在0附近时,倒数取值较大。
在上篇讲的均方差+Sigmoid的反向传播算法中,每一层向前地推都要乘以,得到梯度变化值。Sigmoid的这个曲线意味着在大多数时候,我们的梯度变化很小,导致我们的W,b更新到极值的速度比较慢,也就是算法收敛比较慢,那么我们有什么办法可以改进呢?
首先我们可以想到,既然是Sigmoid导致的收敛速度比较慢,那我们换一个激活函数不就行了吗?但这也只是一种选择,通常来说,我们是用另一种选择,那就是使用交叉熵损失函数来代替均方差损失函数。
二、使用交叉熵损失函数+Sigmoid激活函数来改经DNN算法收敛速度
首先我们来看每个样本的交叉熵损失函数的形式:
(2)
其中,为向量内积
使用了交叉熵损失函数,就能解决Sigmoid函数导数变化大多数时候反向传播算法慢的问题吗?我们来看看使用交叉熵时,我们输出层的梯度情况:
(3)
求偏导过程中需要注意的推导:
可见此时我们的梯度表达式里面已经没有。作为一个特例,回顾一下在上一篇中提到的均方差损失函数关于的梯度:
(4)
对比两者在第L层的梯度表达式,就可以看出,使用交叉熵,得到的梯度表达式没有了,梯度为预测值和准确值的差距,这样求得的的梯度也不包含,因此避免了反向传播的L层收敛速度漫的问题。
通常情况下,如果我们使用了Sigmoid激活函数,交叉熵肯定要比均方差损失函数好用一些。
注:根据BP算法:
(5)
在后面一层层反向传播时,还是需要计算后面每层的激活函数的导数。那么其实交叉熵损失函数只在输出层L不需要计算激活函数的导数,在后面的层层反向传播计算时还是需要的。所以说这个方法可以一定程度减小梯度消失的问题,并不能完全消除。
三、使用对数似然损失函数和softmax激活函数进行DNN分类输出
前面我们讲的所有DNN相关知识中,我们都假设输出是连续可导的值。但是如果是分类问题,那么输出是一个个的类别,那我们怎么用DNN来解决这个问题呢?
比如假设我们有一个三个类别的分类问题,这样我们的DNN输出层应该有三个神经元,假设第一个神经元对应类别一,第二个对应类别二,第三个对应类别三,这样我们期望的输出应该是(1,0,0),(0,1,0)和(0,0,1)这三种。即样本真实类别对应的神经元输出应该无限接近或者等于1,而非真实类别样本对应的神经元的输出应该无限接近或者等于0。或者说,我们希望输出层的神经元对应的输出是若干个概率值,这若干个概率值即我们DNN模型对于输入值对于各类别的输出预测,同时为满足概率模型,这若干个概率值之和应该等于1。
DNN分类模型要求是输出层神经元输出的值在0到1之间,同时所有输出值之和为1。很明显,现有的普通DNN是无法满足这个要求的。但是我们只需要对现有的全连接DNN稍作改良,即可用于解决分类问题。在现有的DNN模型中,我们可以将输出层第i个神经元的激活函数定义为如下形式:
(6)
其中是输出层的神经元个数,或者说是我们分类问题的类别数量。
很容易就可以看出,所有的a_i^L都是在(0,1)之间的数字,而作为归一化因子保障了所有的之和为1。
这个方法很简洁漂亮,仅仅只需要将输出层的激活函数从Sigmoid之类的函数转变为上式的激活函数即可。上式这个激活函数就是我们的softmax激活函数。它在多分类问题中有广泛的应用。
下面这个例子清晰地描述了softmax激活函数在前向传播算法时的使用。假设我们的输出层为三个神经元,而未激活的输出为3,1和-3,我们求出各自的指数表达式为:20,2.7和0.05,我们的归一化因子即为22.75,这样我们就求出了三个类别的概率输出分布为0.88,0.12和0。
用纸笔计算也很简单:
概率计算(激活):
从上面可以看出,将softmax用于前向传播算法是很简单的。那么在反向传播算法时还简单吗?反向传播的梯度好计算吗?答案是Yes!
对于用于分类的softmax激活函数,对应的损失函数一般都是用对数似然函数,即:
(7)
其中的取值为0或者1,如果某一训练样本的输出为第i类,则 = 1,其余的都有。由于每个样本只属于一个类,所以这个对数似然函数可以简化为:
(8)
其中i为训练真实样本的类别序号。
可见损失函数只和真实类别对应的输出有关,这样假设真实类别是第i类,则其它不属于第i类序号对应的设计院的梯度导数直接为0.对于真实类别第i类,对应的第j个w链接对应的梯度为:
(9)
这里需要补充一下:最后一层的激活函数是softmax函数,因此才会有上述公式的形式,也就是说,只有对于做softmax激活的神经元的前面的权重W才会有(9)的梯度形式。再往前的神经元,可以是其他的激活函数。
同样的可以得到的梯度表达式为:
(10)
当然,1输出层的梯度为:
(11)
其中i为样本真实类别。可见,梯度计算也很简洁,也没有第一节说的训练速度慢的问题。
观察公式(11),得出一个结论:对于真实类别位置,反向传播的梯度是要-1,而不是真实类别的位置,反向传播的梯度为0。
举个例子,假如我们对于第2类的训练样本,通过前向算法计算的未激活输出为(1,5,3),则我们得到softmax激活后的概率输出为:(0.015,0.866,0.117)。由于我们的类别是第二类,则反向传播的梯度应该为:(0.015,0.866-1,0.117)。
当softmax输出层的反向传播计算完以后,后面的普通DNN层的反向传播计算和之前讲的普通DNN没有区别。
四、梯度爆炸梯度消失与ReLU激活函数
学习DNN,大家一定听说过梯度爆炸和梯度消失两个词。尤其是梯度消失,是限制DNN与深度学习的一个关键障碍,目前也没有完全攻克。
什么是梯度爆炸和梯度消失呢?从理论上说都可以写一篇论文出来。不过简单理解,就是在反向传播的算法过程中,由于我们使用了是矩阵求导的链式法则,有一大串连乘,如果连乘的数字在每层都是小于1的,则梯度越往前乘越小,导致梯度消失,而如果连乘的数字在每层都是大于1的,则梯度越往前乘越大,导致梯度爆炸。
比如我们之前看到的的计算:
如果不巧我们的样本导致每一层都小于1,则随着反向传播算法的进行,我们的会随着层数越来越小,甚至接近于0,导致梯度几乎消失,进而导致前面的隐藏层的W,b参数随着迭代的进行,几乎没有很大的改变,更谈不上收敛了。这个问题目前还没有完美的解决办法。
而对于梯度爆炸,则一般可以通过调整我们DNN模型中的初始化参数得以解决。
对于无法完美解决的梯度消失问题,目前有很多研究,一个可能部分解决梯度消失问题的办法是使用ReLU(Rectified Linear Unit)激活函数,ReLU在卷积神经网络CNN中得到了广泛的应用,在CNN中梯度消失似乎不再是问题。那么它是什么样子呢?其实很简单,比我们前面提到的所有激活函数都简单,表达式为:
也就是说大于等于0则不变,小于0则激活后为0。就这么一玩意就可以解决梯度消失?至少部分是的。具体的原因现在其实也没有从理论上得以证明。
五、DNN其他激活函数
除了上面提到的激活函数,DNN常用的激活函数还有:
(1)tanh:这个是sigmoid的变种,表达式为:
tanh激活函数和Sigmoid激活函数的关系为:
tanh和sigmoid对比主要的特点是它的输出落在了[-1,1],这样输出可以进行标准化。同时tanh的曲线在较大时变得平坦的幅度没有sigmoid那么大,这样求梯度变化值有一些优势。当然,要说tanh一定比sigmoid好倒不一定,还是要具体问题具体分析。
(2)softplus:这个就是sigmoid函数的原函数,表达式为
它的导数就是Sigmoid函数,softplus的函数图像与ReLU类似。他出现的比ReLU更早,可视为ReLu的鼻祖。
(3)PReLU:从名字就可以看出它是ReLU的变种,特点是如果未激活值小于0,不是简单粗暴的直接变为0,而是进行一定幅度的缩小。如下图。当然,由于ReLU的成功,有很多的跟风者,有其他各种变种ReLU,这里就不多提了。
六、DNN损失函数和激活函数小结:
上面我们对DNN损失函数和激活函数做了详细的讨论,重要的点有:
(1)如果使用sigmoid激活函数,则交叉熵损失函数一般肯定比均方差损失函数好。
(2)如果是DNN用于分类,则一般在输出层使用softmax激活函数和对数似然损失函数。
(3)ReLU激活函数对梯度消失问题有一定程度的解决,尤其是在CNN模型中。
(4)对于梯度爆炸的问题,一般可以通过调整DNN初始化参数来解决。
以上内容学习参考自刘建平Pinard-博客园的笔记,学习并加入了个人理解
猜你喜欢
- 2024-10-23 信号识别中的对抗攻击技术 信号识别算法
- 2024-10-23 机器学习中的应用—Logistic 回归
- 2024-10-23 以淘宝女装分类为例:AI产品经理要不要懂算法?
- 2024-10-23 2022年关于损失函数的5篇最新论文推荐
你 发表评论:
欢迎- 02-26Docker目录说明之 /var/lib/docker
- 02-26家用nas最常用的docker容器及部署方法
- 02-26Docker快速上手笔记
- 02-26怎样在Python中操作Docker容器?
- 02-26手把手教你搭建LLM模型知识库,开启AI智慧大门
- 02-26Docker容器是个啥?和VM有什么区别?
- 02-26Docker入门指南:从新手到容器大师
- 02-26带你一文搞懂 Docker
- 最近发表
- 标签列表
-
- oraclesql优化 (66)
- 类的加载机制 (75)
- feignclient (62)
- 一致性hash算法 (71)
- dockfile (66)
- 锁机制 (57)
- javaresponse (60)
- 查看hive版本 (59)
- phpworkerman (57)
- spark算子 (58)
- vue双向绑定的原理 (68)
- springbootget请求 (58)
- docker网络三种模式 (67)
- spring控制反转 (71)
- data:image/jpeg (69)
- base64 (69)
- java分页 (64)
- kibanadocker (60)
- qabstracttablemodel (62)
- java生成pdf文件 (69)
- deletelater (62)
- com.aspose.words (58)
- android.mk (62)
- qopengl (73)
- epoch_millis (61)
本文暂时没有评论,来添加一个吧(●'◡'●)