# RNN循环神经网络

## RNN循环神经网络

* [返回顶层目录](https://luweikxy.gitbook.io/machine-learning-notes/summary#目录)
* [为什么需要RNN](#为什么需要RNN)
* [RNN原理](https://github.com/luweikxy/machine-learning-notes/tree/f34dc7b5d30459ed1818fb464b76cce4771decc1/content/deep-learning/recurrent-neural-network/*RNN%E5%8E%9F%E7%90%86/README.md)
* [RNN的不同架构](https://github.com/luweikxy/machine-learning-notes/tree/f34dc7b5d30459ed1818fb464b76cce4771decc1/content/deep-learning/recurrent-neural-network/*RNN%E7%9A%84%E4%B8%8D%E5%90%8C%E6%9E%B6%E6%9E%84/README.md)
  * [多层Deep的RNN](https://github.com/luweikxy/machine-learning-notes/tree/f34dc7b5d30459ed1818fb464b76cce4771decc1/content/deep-learning/recurrent-neural-network/*%E5%A4%9A%E5%B1%82Deep%E7%9A%84RNN/README.md)
  * [Elman和Jordan网络架构](https://github.com/luweikxy/machine-learning-notes/tree/f34dc7b5d30459ed1818fb464b76cce4771decc1/content/deep-learning/recurrent-neural-network/*Elman%E5%92%8CJordan%E7%BD%91%E7%BB%9C%E6%9E%B6%E6%9E%84/README.md)
  * [双向RNN](https://github.com/luweikxy/machine-learning-notes/tree/f34dc7b5d30459ed1818fb464b76cce4771decc1/content/deep-learning/recurrent-neural-network/*%E5%8F%8C%E5%90%91RNN/README.md)

## 为什么需要RNN

以订票系统的填空（slot filling）为例，比如一个智慧订票系统，往往需要slot filling技术。

假设订票系统需要根据人说的话得到两个slot：`目的地`和`到达时间`。

![slot-filling](https://3298324061-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LpO5sn2FY1C9esHFJmo%2F-M0x7xw9H7qY6-mlKm0S%2F-M0x-q3kFrpAo_KMKRCe%2Fslot-filling.jpg?generation=1582647476136196\&alt=media)

这个问题我们首先想到可以用全连接网络（FNN：FeedForword Neural Network）来解决。

这个全连接网络的输入是一个词汇，比如把台北变为一个Embedding（OneHot、N-gram、Word2vec）输入到神经网络里。然后希望输出是一个概率，即属于所有slot的几率。

但是只有这样是不够的，全连接网络不能解决这个问题。为什么呢？

如果有两个输入：

```
arrive Taipei on November 2nd
leave Taipei on November 2nd
```

但对于全连接神经网络来说，输入一样，输出也会一样。输入`Taipei`，要么输出是`目的地`的几率最高，要么是`出发地`的几率最高，没有办法有时候让`目的地`的几率最高，有时候让`出发地`的几率最高，那怎么办呢？

**这个时候，我们就希望神经网络是有记忆力的**。

![book-tiket](https://3298324061-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LpO5sn2FY1C9esHFJmo%2F-M0x7xw9H7qY6-mlKm0S%2F-M0x-q3pnmlhScJyd_1s%2Fbook-tiket.jpg?generation=1582647477148705\&alt=media)

如果神经网络是有记忆力的，它会记得在看到红色`Taipei`这个词之前，就已经看过`arrive`这个词汇；它会记得在看到绿色`Taipei`这个词之前，就已经看过`leave`这个词汇。它会根据这段话的上下文，产生不同的输出。

**如果神经网络是有记忆力的，这样就可以解决输入同样的词汇，但是输出必须不同这个问题**。那么这种有记忆力的神经网络，就叫做Recurrnt Neural Network(RNN)。

## RNN原理

每次前向神经网络里的隐藏层的神经元产生输出（下图中的$$a\_1$$和$$a\_2$$）后，都会被存到memory中去，然后当下一个input输入后，隐藏层的输入不仅仅考虑$$x\_1$$和$$x\_2$$，还会考虑上一次的隐藏层输出存在memory中的值。

![rnn.jpg](https://3298324061-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LpO5sn2FY1C9esHFJmo%2F-M0x7xw9H7qY6-mlKm0S%2F-M0x-q45zBSjbMjE791Y%2Frnn.jpg?generation=1582647486338402\&alt=media)

那具体过程是怎样的呢？用一个简单的例子来说明会比较清楚。

假设如下图所示的所有权值都是1，所有的神经元都没有bias，假设所有的激活函数都是线性的，假设input是sequence，具体值如下图中所示，假设memory的初始值是0。

![rnn-example1.jpg](https://3298324061-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LpO5sn2FY1C9esHFJmo%2F-M0x7xw9H7qY6-mlKm0S%2F-M0x-q4Bsf2_JZeeGN5O%2Frnn-example1.jpg?generation=1582647485182388\&alt=media)

然后如下图所示**隐藏层的值2被写到memory中**，接下来再输入第二个单词的embedding，那么**隐藏层的输入有四个**，加权的结果是6，输出的结果也是6。

![rnn-example2](https://3298324061-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LpO5sn2FY1C9esHFJmo%2F-M0x7xw9H7qY6-mlKm0S%2F-M0x-q4Gai1xvZDJallV%2Frnn-example2.jpg?generation=1582647480186854\&alt=media)

由上图可以看出，输入是一样的，但是输出是可能不一样的，因为存在memory中的值是不一样的。

接下来，如下图所示上图中隐藏层的输出6就会被存到memory中去，memory中的值就由2变为6。隐藏层的输入有四个（6+6+2+2=16），所以隐层的输出就是16。

![rnn-example3](https://3298324061-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LpO5sn2FY1C9esHFJmo%2F-M0x7xw9H7qY6-mlKm0S%2F-M0x-q4LbuhEuLMRARc6%2Frnn-example3.jpg?generation=1582647475235773\&alt=media)

所以因为memory的存在，**任意调换sequence的顺序，那么输出就会不一样**。比如把sequence的最后一个单词挪到最前面去，则输出是会完全不一样的。所以，**RNN会考虑输入的seqence的顺序**。

**example**：

现在RNN的原理就讲完了，下面还是用前面的订票系统来距离说明。

![rnn-example4](https://3298324061-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LpO5sn2FY1C9esHFJmo%2F-M0x7xw9H7qY6-mlKm0S%2F-M0x-q4RPkCpxVDVHDIM%2Frnn-example4.jpg?generation=1582647479460838\&alt=media)

上面并不是三个网络，而是同一个神经网络，是同一个网络在三个不同的时间点被使用了三次。

所以，有了memory以后，我们希望输入同一个词汇，输出不同的概率这个问题，就有可能解决。

如下图所示，同样是输入`Taipei`，但是因为红色`Taipei`前面接`leave`，绿色`Taipei`前面接`arrive`，因为`leave`和`arrive`它们的embedding不一样，所以隐层的输出也会不同，存在memory里面的值也会不同。所以虽然现在两个$$x^2$$是一模一样的，但是因为存在memory里面的值不同，所以隐层的输出就会不一样，所以最后的输出也就会不一样。

![rnn-example5](https://3298324061-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LpO5sn2FY1C9esHFJmo%2F-M0x7xw9H7qY6-mlKm0S%2F-M0x-q4Tg6X-F2eRK9AL%2Frnn-example5.jpg?generation=1582647484475514\&alt=media)

## RNN的不同架构

### 多层Deep的RNN

RNN当然也可以有很多层，如下图所示

![rnn-structure](https://3298324061-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LpO5sn2FY1C9esHFJmo%2F-M0x7xw9H7qY6-mlKm0S%2F-M0x-q4VXX47FNstOJ6l%2Frnn-structure1.jpg?generation=1582647482558972\&alt=media)

### Elman和Jordan网络架构

前面我们讲的都是Elman网络架构，Jordan网络往memory中存的是output的值。Jordan网络可以得到比较好的性能，因为Elman网络的隐藏层是没有target的，比较难控制它学到了什么信息，但是Jordan网络的输出y是有target的，可以对放在memory中的是什么东西比较清楚的。

![rnn-structure2](https://3298324061-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LpO5sn2FY1C9esHFJmo%2F-M0x7xw9H7qY6-mlKm0S%2F-M0x-q4axDdELu3hVIxv%2Frnn-structure2.jpg?generation=1582647478151991\&alt=media)

### 双向RNN

RNN的读取方向不仅可以是按照句子的顺序，也可以是反过来的。

可以同时train一个正向的RNN和逆向的RNN，然后把两个RNN的隐藏层都拿出来接给一个输出层，得到最后的输出y。

![rnn-structure3](https://3298324061-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LpO5sn2FY1C9esHFJmo%2F-M0x7xw9H7qY6-mlKm0S%2F-M0x-q4c2wv07xEjtT1P%2Frnn-structure3.jpg?generation=1582647481723445\&alt=media)

用双向RNN的好处，就是网络产生输出的时候，看的范围比较广。如果只有正向的RNN，在产生$$y^{t+1}$$的时候，网络只看过$$x^1$$一直到$$x^{t+1}$$，但是如果是双向的RNN，在产生$$y^{t+1}$$的时候，网络不只是看过$$x^1$$一直到$$x^{t+1}$$，也看了从句尾一直到$$x^{t+1}$$。就是说，**网络是看了整个sequence后，才决定输出是什么**，会比只看句子的一半得到更好的性能。

## RNN的梯度消失问题

RNN的缺陷是梯度消失问题，即便是LSTM也只能缓解该问题。

![rnn-vanishing-gradient](https://3298324061-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LpO5sn2FY1C9esHFJmo%2F-M1sMW0HR87G3MeMM3Yw%2F-M1sMYYeHQ6NnfAwjznN%2Frnn-vanishing-gradient.png?generation=1583641153721457\&alt=media)

## 参考资料

* [李宏毅教授讲解 RNN LSTM的视频](http://speech.ee.ntu.edu.tw/~tlkagk/courses/ML_2017/Lecture/RNN1.mp4)
* [B站李宏毅深度学习RNN2019](https://www.bilibili.com/video/av73798762?p=43)

本文参考了该视频。两个视频都一样。

* [Recurrent Neural Networks (RNN) - The Vanishing Gradient Problem](https://www.superdatascience.com/blogs/recurrent-neural-networks-rnn-the-vanishing-gradient-problem)
* [paper: On the difficulty of training recurrent neural networks](http://proceedings.mlr.press/v28/pascanu13.pdf?source=post_page---------------------------)

"RNN的梯度消失问题"参考该博客，paper没看，但是觉得有用。

\===

[完全图解RNN、RNN变体、Seq2Seq、Attention机制](https://zhuanlan.zhihu.com/p/28054589)

[seq2seq学习笔记](https://blog.csdn.net/jerr__y/article/details/53749693)

RNN基础 对于RNN，我看到讲得最通俗易懂的应该是Andrej发的博客： The Unreasonable Effectiveness of Recurrent Neural Networks

这里有它的中文翻译版本： 递归神经网络不可思议的有效性

如果想了解 LSTM 的原理，可以参考这篇文章：（译）理解 LSTM 网络 （Understanding LSTM Networks by colah）。 下面的连接中对RNN还有BPTT（RNN的反向传播算法），LSTM和GRU的原理和实现讲解得也是非常棒： <http://www.wildml.com/2015/09/recurrent-neural-networks-tutorial-part-1-introduction-to-rnns/>

[Visualizing memorization in RNNs](https://distill.pub/2019/memorization-in-rnns/)

[谁能用比较通俗有趣的语言解释RNN和LSTM？](https://www.zhihu.com/question/314002073)

[一文读懂LSTM和循环神经网络](https://zhuanlan.zhihu.com/p/35878575)

[深度学习循环神经网络详解](https://zhuanlan.zhihu.com/p/37428697)

[【深度学习之美】循环递归RNN，序列建模套路深（入门系列之十三）](https://yq.aliyun.com/articles/169880?spm=a2c4e.11153940.blogcont86580.22.152919797EqPuO)

[【Deep Learning】通俗大白话详述RNN理论和LSTM理论](https://mp.weixin.qq.com/s/3Rpq1EvYi-_9wvJ5fUB5dQ)

[深度学习实战教程(五)：循环神经网络](https://cuijiahua.com/blog/2018/12/dl-11.html)

[The Ultimate Guide to Recurrent Neural Networks (RNN)](https://www.superdatascience.com/blogs/the-ultimate-guide-to-recurrent-neural-networks-rnn)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://luweikxy.gitbook.io/machine-learning-notes/recurrent-neural-network.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
