0%

【动手学深度学习】4 循环神经网络

这一讲我们来看看 RNN,关于 RNN 其实前面 CS20 和 CS230 都有比较详细介绍,这里主要看看 PyTorch 如何快速实现。


更新历史

  • 2019.11.11: 完成初稿

语言模型与循环神经网络

所谓语言模型,简单来说就是给定一句话,给出这句话可能出现的概率。这里有一个重点概念叫 n-gram,也就是基于 n-1 阶马尔科夫链的概率语言模型,我们可以根据实际需要调整 n,来达到计算复杂度和模型准确性的平衡。

循环神经网络可以参考下图:

我们可以基于字符来构建语言模型,如下:

注:更深入的理解,可以参考

语言模型数据集

这一节我们主要是来处理数据集,将其转化成 char-RNN 所需的输入格式,这里我们用的数据集是周杰伦前十张专辑(《Jay》到《跨时代》)中的歌词。

具体的处理流程参考代码:

实际执行训练时,我们需要对数据进行采样,这里就分为随机采样和相邻采样:

  • 随机采样:相邻的两个随机小批量在原始序列上位置不一定相邻,所以我们不能用前一个的隐藏状态来预测下一个的。在训练时,每次随机采样都需要重新初始化隐藏状态
  • 相邻采样:和随机采样选取方式不同,是相邻的,所以我们可以用前一个的隐藏状态来预测下一个的。但这样的问题在于迭代次数增加,梯度计算开销会增大。

对应的采样代码如下:

注:不同的采样,也对应不同的神经网络训练的实现

实现循环神经网络

和之前一样,我们同样会自己写一个,然后再利用框架写一个,代码如下:

需要关注的点:

  • 梯度裁剪:避免梯度爆炸
  • 困惑度:perplexity,即交叉熵损失函数的指数,有效模型的困惑度必须小于类别个数 vocab_size。最好是 1
  • 通过时间反向传播是反向传播在 RNN 中的具体应用,当总的时间步数较大或者当前时间步数较小时,RNN 的梯度容易出现衰减或爆炸

门控循环单元 GRU

GRU 为了能够更好地捕捉时间序列中时间步距离较大的依赖关系,另一种常用的是 LSTM。

GRU 引入了 reset gate 和 update gate 两个概念,改变了 RNN 中隐藏状态的计算方式(原来就是普通的全连接)。如下图所示:

具体的公式这里不列了,总结一下就是:

  • 重置门 - 捕捉短期依赖关系
  • 更新门 - 捕捉长期依赖关系

我们同样自己实现一个,用框架实现一个,代码如下:

长短期记忆 LSTM

相比于 GRU,LSTM 引入了三个门:输入门、遗忘门和输出门,结果如下图所示:

要点:

  • LSTM 的隐藏层包括隐藏状态和记忆细胞。只有隐藏状态会传递到输出层
  • LSTM 的三个门可以控制信息的流动
  • LSTM 可以应对循环神经网络的中的梯度衰减问题,并更好地捕捉时间序列中时间步数较大的依赖关系

我们同样自己实现一个,用框架实现一个,代码如下:

深度循环神经网络

前面介绍的 RNN 中只有一个单向的隐藏层,如果包含多个隐藏层,就叫做深度循环神经网络,如下图所示:

具体的公式不赘述,感兴趣的同学可以自行学习

双向循环神经网络

简单来说就是不仅前面的词会影响后面的词,后面的词也会影响前面的词,如下图所示:

具体的公式不赘述,感兴趣的同学可以自行学习