Day 25 递回神经网路 RNN 、梯度下降与梯度消失

介绍

递回神经网路 RNN (recurrent neural networks)是神经网路的一种,它是一种循环的网路,最常被用来处理时间和序列相关的问题。简单的架构如图所示:

在上面的示例图中,我们能够看到神经网路区块 A 在读取输入 https://chart.googleapis.com/chart?cht=tx&chl=%24x_t%24 後,将会输出一个值 https://chart.googleapis.com/chart?cht=tx&chl=%24h_t%24。而每次读取过的值都会有部份传递至下一次读取时的区块 A 里。而 RNN 便是透过这样子的循环,来将资讯从上一步传递至下一步。

经过上面的介绍後我们就不难理解为何 RNN 常常备用来处理时间和序列相关的问题了,因为下一个的输出能够考虑上一个的资讯嘛!这就像是我们吃完早餐後才会吃中餐;吃完中餐後才会吃晚餐一样,RNN 是能够考虑"序列"的先後关系的。

然而 RNN 有相当严重的问题,叫作 梯度消失梯度爆炸,这个我们晚点再提。

昨天我们有说过,为了得知预测结果究竟与实际答案差了多少,於是科学家设计了代价函数,并希望代价函数愈小愈好,对吧?那我们该如何快速求出最小的代价函数呢?答案是梯度下降法。

梯度下降法 (Gradient Descent)

梯度下降是一种能够快速找出最小代价函数的方法。高中数学有教过,我们可以利用微分的技术来求函数的最大值与最小值。因此当我们的变数是线性关系时,我们就能够用梯度下降法来快速的求出代价函数 J 的最小值,如图:

目前主流的方法便是随机选择一个斜率为初始值,然後在每次迭代时使用一个样本对参数进行更新(mini-batch size =1),我们称呼这种方法为随机梯度下降法(Stochastic Gradient Descent)。

但是,现实的变数往往不会那麽刚好呈线性关系。因此当我们在做梯度下降时,很容易找到局部最小值而非全域最小值,如图:

当然遇到这种情况也有解法,例如批量梯度下降(Batch Gradient Descent),但是每迭代一步,都要用到训练集所有的资料。当然还有其他方法,例如牛顿法、momentum 或是 Adam 。

总之,如何找到最低最小的最佳解一直都是科学家们想要尝试解决的目标,在实际应用时通常会根据问题的使用情境而有所不同,这时我们就需要透过不同的方式来解决,例如限制迭代次数或是设置学习率等,只要找到属於自己最佳的优化方式就可以了!

梯度消失与梯度爆炸

下图是一张简单的深度网路模型:

首先,我们假设每一层网路激活後的输出为https://chart.googleapis.com/chart?cht=tx&chl=%24%5Cdisplaystyle%20f_%7Bi%7D(x)%24 ,i 为第 i 层,x 代表第 i 层的输入,https://chart.googleapis.com/chart?cht=tx&chl=%24%5Cdisplaystyle%20f%24 为激活函数,我们便能得出:
本层输出=https://chart.googleapis.com/chart?cht=tx&chl=%24f%24(上层输出 * 本层权重 + 偏置)
https://chart.googleapis.com/chart?cht=tx&chl=%24f_%7Bi%2B1%7D%3Df(f_%7Bi%7D%20%20w_%7Bi%2B1%7D%2Bb_%7Bi%2B1%7D)%24

简写为:https://chart.googleapis.com/chart?cht=tx&chl=%24f_%7Bi%2B1%7D%3Df(f_%7Bi%7D%20w_%7Bi%2B1%7D)%24

以此类推的话,假设今天我们的隐藏层超级简单只有三层,那我们从输入层经过隐藏层到输出层的前向传播公式为:
https://chart.googleapis.com/chart?cht=tx&chl=%24f(w_1)%3Df(w_3f_2(w_2f_1(w_1)))%24

现在我们对 https://chart.googleapis.com/chart?cht=tx&chl=%24w_1%24 求梯度,根据连锁律,我们可以推倒出
https://chart.googleapis.com/chart?cht=tx&chl=%24%7B%5Cdisplaystyle%20%7B%5Cpartial%20f%20%5Cover%20%5Cpartial%20w_1%7D%3D%7B%5Cpartial%20f3%20%5Cover%20%5Cpartial%20f2%7D%7Bw_3%7D%7B%5Cpartial%20f_2%20%5Cover%20%5Cpartial%20f_1%7D%7Bw_2%7D%7B%5Cpartial%20f_1%20%5Cover%20w_1%7D%7D%24

可以看出,https://chart.googleapis.com/chart?cht=tx&chl=%24w_1%24 求梯度就是反向从输出层到输入层的用连锁律求导

而假如我们使用标准化初始 https://chart.googleapis.com/chart?cht=tx&chl=%24w%24,那麽各个层次的相乘都是0-1之间的小数,而激活函数 https://chart.googleapis.com/chart?cht=tx&chl=%24f%24 的导数也是 0~1 之间的数(例如 sigmoid 激活函数),那麽在神经网络反向传播中,当梯度由後往前传时,其连乘後结果会变的很小,最後变为零。此时,浅层的神经网络权重得不到更新,而随着隐藏层数目的增加,分类准确率反而下降了。这种称呼这种情况为梯度消失

若我们初始化的 https://chart.googleapis.com/chart?cht=tx&chl=%24w%24 是很大的数,https://chart.googleapis.com/chart?cht=tx&chl=%24w%24 大到乘以激活函数的导数都大於 1 ,那麽连乘後,可能会导致求导的结果很大,使得学习不稳定,参数变化太大导致无法获取最优参数。这种称呼这种情况为梯度爆炸

因此,梯度消失问题和梯度爆炸问题一般会随着神经网络层数的增加变得越来越明显。现在我们回头看 RNN 就不难发现它的问题:
只要输入的资料太长,RNN 就容易记不住前面的资料导致梯度消失;而过长的资料导致在调整权重时可能一个不小心就会引发梯度爆炸。然而我们使用神经网路的目的,不就是希望能够让电脑学习更多资料,好让电脑预测的精准度超过使用演算法的机器学习吗?该怎麽样才能在输入大量资料让神经网路进行学习时不引发梯度消失和梯度爆炸?

另外,RNN 的设计结构其实相当仰赖前面所学的资讯,可是只要输入的资料一长,随着权重更新 RNN 可能就会忘记前面学到的资讯了!(我们称呼这种问题为"长期依赖(Long-Term Dependencies)")

明天就让我们来讲讲改良後的 RNN 结构:长短期记忆网路 LSTM 吧!


<<:  误打误撞跳到网路组

>>:  Day 27:碰到困难问题,演算法也救不了?

Ubuntu - Ubuntu 查看 CPU 温度

Ubuntu - Ubuntu 查看 CPU 温度 参考资料 网址如下: How to Get CP...

D1 - 前言

目前在工作上主要会使用两套资料库,这段时间累积了对於维运上的经验以及渐渐摸熟在程序使用上的眉角。但是...

课堂笔记 - 深度学习 Deep Learning (1)

前导介绍 说到深度学习, 首先需要了解什麽是类神经网路和它的操作方法。 类神经网路,顾名思义就是仿...

Day 1 Introduction

前情提要 我是 siriuskoan,在这三十天内会把一些关於 flask 的知识写成文章,以供自己...

使用Quartz.Net达成Asp.Net Core长时程执行

Web应用程序本身的机制并不适合用来作为执行需要长时程运行的需求,而这类需求却很常见,而常见的解决方...