DNN损失函数和**函数的选择
现对DNN损失函数和**函数的搭配与选择进行梳理:
(1)均方差损失函数+Sigmoid**函数
首先回顾下Sigmoid**函数的表达式为:
σ(z)的函数图像如下:
从图上可以看出,对于Sigmoid,当z的取值越来越大后,函数曲线变得越来越平缓,意味着此时的导数σ′(z)也越来越小。同样的,当z的取值越来越小时,也有这个问题。仅仅在z取值为0附近时,导数σ′(z)的取值较大。
- Sigmoid的这个曲线意味着在大多数时候,我们的梯度变化值很小,导致我们的W,b更新到极值的速度较慢,也就是我们的算法收敛速度较慢。那么有什么什么办法可以改进呢?
(2)使用交叉熵损失函数+Sigmoid**函数改进DNN算法收敛速度
二分类时每个样本的交叉熵损失函数的形式:
这个损失函数的学名叫交叉熵。
当使用交叉熵时,我们输出层的梯度情况:
可见此时我们的梯度表达式里面已经没有了σ′(z),作为一个特例,回顾一下我们上一节均方差损失函数时在
梯度,
- 对比两者在第L层的
梯度表达式,就可以看出,使用交叉熵,得到的
梯度表达式没有了σ′(z),梯度为预测值和真实值的差距,这样求得的,的地图也不包含σ′(z),因此避免了反向传播收敛速度慢的问题。
- 通常情况下,如果我们使用了sigmoid**函数,交叉熵损失函数肯定比均方差损失函数好用。
(3) 使用对数似然损失函数和softmax**函数进行DNN分类输出
前面都假设输出是连续可导的值。但是如果是分类问题,那么输出是一个个的类别,那我们怎么用DNN来解决这个问题呢?
比如假设我们有一个三个类别的分类问题,这样我们的DNN输出层应该有三个神经元,假设第一个神经元对应类别一,第二个对应类别二,第三个对应类别三,这样我们期望的输出应该是(1,0,0),(0,1,0)和(0,0,1)这三种。即样本真实类别对应的神经元输出应该无限接近或者等于1,而非改样本真实输出对应的神经元的输出应该无限接近或者等于0。或者说,我们希望输出层的神经元对应的输出是若干个概率值,这若干个概率值即我们DNN模型对于输入值对于各类别的输出预测,同时为满足概率模型,这若干个概率值之和应该等于1。
DNN分类模型要求是输出层神经元输出的值在0到1之间,同时所有输出值之和为1。很明显,现有的普通DNN是无法满足这个要求的。但是我们只需要对现有的全连接DNN稍作改良,即可用于解决分类问题。在现有的DNN模型中,我们可以将输出层第i个神经元的**函数定义为如下形式:
其中,nL是输出层第L层的神经元个数,或者说我们的分类问题的类别数。很容易看出,所有的都是在(0,1) 之间的数字,所有的
之和为1。
下面这个例子清晰的描述了softmax**函数在前向传播算法时的使用:
对于用于分类的softmax**函数,对应的损失函数一般都是用对数似然函数,即:
其中的取值为0或者1,如果某一训练样本的输出为第i类。则=1,其余的j≠i都有=0。由于每个样本只属于一个类别,所以这个对数似然函数可以简化为:
其中ii即为训练样本真实的类别序号。
可见损失函数只和真实类别对应的输出有关,这样假设真实类别是第i类,则其他不属于第i类序号对应的神经元的梯度导数直接为0。对于真实类别第i类,他对应的第j个w链接对应的梯度计算为:
同样的可以得到的梯度表达式为:
可见,梯度计算也很简洁,也没有第一节说的训练速度慢的问题。
(4)梯度爆炸梯度消失与ReLU**函数
学习DNN,经常听说梯度爆炸和梯度消失两个词。尤其是梯度消失,是限制DNN与深度学习的一个关键障碍,目前也没有完全攻克。
什么是梯度爆炸和梯度消失呢?从理论上说都可以写一篇论文出来。不过简单理解,就是在反向传播的算法过程中,由于我们使用了是矩阵求导的链式法则,有一大串连乘,如果连乘的数字在每层都是小于1的,则梯度越往前乘越小,导致梯度消失,而如果连乘的数字在每层都是大于1的,则梯度越往前乘越大,导致梯度爆炸。
比如反向传播算法里面提到的δ的计算,可以表示为:
如果不巧我们的样本导致每一层的都小于1,则随着反向传播算法的进行,我们的
会随着层数越来越小,甚至接近越0,导致梯度几乎消失,进而导致前面的隐藏层的W,b参数随着迭代的进行,几乎没有大的改变,更谈不上收敛了。这个问题目前没有完美的解决办法。
- 而对于梯度爆炸,则一般可以通过调整我们DNN模型中的初始化参数得以解决。
- 对于无法完美解决的梯度消失问题,目前有很多研究,一个可能部分解决梯度消失问题的办法是使用ReLU(Rectified Linear Unit)**函数,ReLU在卷积神经网络CNN中得到了广泛的应用,在CNN中梯度消失似乎不再是问题。那么它是什么样子呢?其实很简单,比我们前面提到的所有**函数都简单,表达式为:
-
也就是说大于等于0则不变,小于0则**后为0。ReLU**函数对梯度消失问题有一定程度的解决,尤其是在CNN模型中。
(5)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,这里就不多提了。