这一讲我们来看看 RNN,关于 RNN 其实前面 CS20 和 CS230 都有比较详细介绍,这里主要看看 PyTorch 如何快速实现。
更新历史
2019.11.11: 完成初稿
语言模型与循环神经网络
所谓语言模型,简单来说就是给定一句话,给出这句话可能出现的概率。这里有一个重点概念叫 n-gram,也就是基于 n-1 阶马尔科夫链的概率语言模型,我们可以根据实际需要调整 n,来达到计算复杂度和模型准确性的平衡。
循环神经网络可以参考下图:
我们可以基于字符来构建语言模型,如下:
注:更深入的理解,可以参考
【CS20-TF4DL】09 RNN 与语言模型
【CS230-DL】13 循环神经网络
语言模型数据集
这一节我们主要是来处理数据集,将其转化成 char-RNN 所需的输入格式,这里我们用的数据集是周杰伦前十张专辑(《Jay》到《跨时代》)中的歌词。
具体的处理流程参考代码:
实际执行训练时,我们需要对数据进行采样,这里就分为随机采样和相邻采样:
随机采样:相邻的两个随机小批量在原始序列上位置不一定相邻,所以我们不能用前一个的隐藏状态来预测下一个的。在训练时,每次随机采样都需要重新初始化隐藏状态
相邻采样:和随机采样选取方式不同,是相邻的,所以我们可以用前一个的隐藏状态来预测下一个的。但这样的问题在于迭代次数增加,梯度计算开销会增大。
对应的采样代码如下:
注:不同的采样,也对应不同的神经网络训练的实现
实现循环神经网络
和之前一样,我们同样会自己写一个,然后再利用框架写一个,代码如下:
31_char_rnn_raw.py
32_char_rnn_torch.py
需要关注的点:
梯度裁剪:避免梯度爆炸
困惑度:perplexity,即交叉熵损失函数的指数,有效模型的困惑度必须小于类别个数 vocab_size。最好是 1
通过时间反向传播是反向传播在 RNN 中的具体应用,当总的时间步数较大或者当前时间步数较小时,RNN 的梯度容易出现衰减或爆炸
门控循环单元 GRU
GRU 为了能够更好地捕捉时间序列中时间步距离较大的依赖关系,另一种常用的是 LSTM。
GRU 引入了 reset gate 和 update gate 两个概念,改变了 RNN 中隐藏状态的计算方式(原来就是普通的全连接)。如下图所示:
具体的公式这里不列了,总结一下就是:
重置门 – 捕捉短期依赖关系
更新门 – 捕捉长期依赖关系
我们同样自己实现一个,用框架实现一个,代码如下:
长短期记忆 LSTM
相比于 GRU,LSTM 引入了三个门:输入门、遗忘门和输出门,结果如下图所示:
要点:
LSTM 的隐藏层包括隐藏状态和记忆细胞。只有隐藏状态会传递到输出层
LSTM 的三个门可以控制信息的流动
LSTM 可以应对循环神经网络的中的梯度衰减问题,并更好地捕捉时间序列中时间步数较大的依赖关系
我们同样自己实现一个,用框架实现一个,代码如下:
35_lstm_raw.py
36_lstm_torch.py
深度循环神经网络
前面介绍的 RNN 中只有一个单向的隐藏层,如果包含多个隐藏层,就叫做深度循环神经网络,如下图所示:
具体的公式不赘述,感兴趣的同学可以自行学习
双向循环神经网络
简单来说就是不仅前面的词会影响后面的词,后面的词也会影响前面的词,如下图所示:
具体的公式不赘述,感兴趣的同学可以自行学习
Be First to Comment