[转] RNN 中为什么要采用 tanh,而不是 ReLU 作为激活函数?
为什么CNN用ReLU
Sigmoid的导数范围在内,如果采用Sigmoid作为激活函数,多个小于1的导数连续相乘容易引起梯度消失。
tanh的导数范围在内,虽然导数可以达到1,但是在边缘区域仍然有梯度消失的问题。
ReLU的正半轴不存在梯度消失问题,负半轴的存在可以带来一定的稀疏性,但是也会带来梯度消失问题,可以用LeakyReLU和PReLU等方法缓解。此外,ReLU的计算量远远小于Sigmoid和tanh。
为什么RNN用tanh
在LSTM和GRU中,内部的各种门多采用sigmoid激活函数,因为需要确定“0-1”的各种状态;而隐状态的激活函数多采用tanh。
RNN的每个时间步的权重是相同的,bp过程相当于权重的连续相乘,因此比CNN更容易出现梯度消失和梯度爆炸,因此采用tanh比较多。tanh也会出现梯度消失和梯度爆炸,但是相比于Sigmoid好很多了。理论上ReLU+梯度裁切也可以。
作者:何之源
链接:https://www.zhihu.com/question/61265076/answer/186347780
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
来尝试回答下。其实题主的问题可以拆分成下面两个部分:
- 为什么在CNN等结构中将原先的sigmoid、tanh换成ReLU可以取得比较好的效果?
- 为什么在RNN中,将tanh换成ReLU不能取得类似的效果?
先来简单讨论下第一个问题。设输入数据为 ,对 的卷积操作就可以看做是 (如果不理解为什么,可以参考这个答案的前半部分:如何理解深度学习中的deconvolution networks?)。我们设第一层卷积的参数为 ,第二层卷积的参数是 ,依次类推。又设激活函数为 ,每一层卷积在经过激活函数前的值为 ,经过激活函数后的值为 。
按照上面的表示,在CNN中,输入 ,第一层的输出就是 ,第二层的输出就是 ,第三层的输出就是 。设最终损失为 ,我们来尝试从第三层开始,用BP算法推导一下损失对参数 的偏导数,看看会发生什么。
为了简洁起见,略过求导过程,最后的结果为 。我们常常说原始神经网络的梯度消失问题,这里的 、 就是梯度消失的“罪魁祸首”。例如sigmoid的函数,它的导数的取值范围是(0, 0.25],也就是说对于导数中的每一个元素,我们都有 , ,小于1的数乘在一起,必然是越乘越小的。这才仅仅是3层,如果10层的话, 根据 ,第10层的误差相对第一层卷积的参数 的梯度将是一个非常小的值,这就是所谓的“梯度消失”。
ReLU函数的改进就是它使得 , , ,这样的话只要一条路径上的导数都是1,无论神经网络是多少层,这一部分的乘积都始终为1,因此深层的梯度也可以传递到浅层中。
那为什么同样的方法在RNN中不奏效呢?其实这一点Hinton在它的IRNN论文里面(arxiv:[1504.00941] A Simple Way to Initialize Recurrent Networks of Rectified Linear Units)是很明确的提到的:
也就是说在RNN中直接把激活函数换成ReLU会导致非常大的输出值。为了讲清楚这一点,我们先用同上面相似的符号把原始的RNN表示出来:
,
在这个表示中,RNN每个阶段的输入是 ,和CNN每一层使用独立的参数 不同,原始的RNN在每个阶段都共享一个参数 。如果我们假设从某一层开始输入 和偏置 都为0,那么最后得到的输出就是 ,这在某种程度上相当于对参数矩阵 作连乘,很显然,只要 有一个大于1的特征值,在经过若干次连乘后都会导致结果是一个数值非常庞大的矩阵。
另外一方面,将激活函数换成ReLU也不能解决梯度在长程上传递的问题。同样考虑 对 的导数。在CNN中,每一层的参数 是互相独立的,然而RNN中 参与了每个时间段的运算,因此 对 导数更复杂,写出来是 。我们可以看下最后 这部分,使用ReLU后,当梯度可以传递时,有 ,但这个式子中还是会有两个 的连乘。在更长程上,就会有更多 的连乘。对于CNN来说,这个部分是 进行连乘,一方面它们都是稀疏矩阵,另一方面 互不相同,很大程度上都能抵消掉梯度爆炸的影响。
最后,IRNN在RNN上使用了ReLU,取得了比较好的结果,其中的原因在于,它对 和 取了比较特殊的初值: , 。这样在梯度的式子 中W尽管会连乘,但是会类似于单位矩阵 的连乘,不会引起太明显的梯度数值变化。另外一方面,也不会引起非常大的输出值(这点可以自行带入表达式验证)。
以上,如果有哪里说的不对的,还烦请各位大佬批评指正。