一、循环序列模型
本小节主要总结一下RNN与LSTM的不同之处:
标准RNN,在利用反向传播求导时,会产生梯度连乘的现象,从而引起梯度消失,会梯度爆炸的问题,因此,标准RNN很难拥有长程记忆,无法学到序列中蕴含的间隔时间较长的规律。
与RNN相比,LSTM能够有效解决这个问题。
需要指出的是:在大多数情况下,RNN和LSTM是可以相互互换的,因此在很多论文以及文档中都会看到类似于“RNN(LSTM)”这样的表述,意思是两者可以相互替换。
关于各类RNN的原理,在此不赘述,详情查看:序列模型。
二、在Tensorflow中实现CharRNN
(一) Tensorflow 中 RNN的实现方法
1、实现RNN的基本单元 RNNCell
RNNCell是Tensorflow中RNN的基本单元,它是一个抽象类,不能直接使用。在本节中,将介绍它的两个可以直接使用的子类:BasicRNNCell,BasicLSTMCell,前者是一个最基本的RNN,后者是一个LSTM。
学习RNNCell需要重点关注3点:
- 类方法:call
- 类属性:state_size
- 类属性:output_size
所有RNNCell的子类都会实现一个call函数,利用call()可以实现RNN的单步计算,它的调用形式为:(output, next_state) = call(input,state),其中,output为第i个时间序列RNN单元的输出,next_state为第i+1个时间序列RNN单元的“输入隐含层单元”,input为第i个时间序列RNN单元的输入x,state为第i个时间序列RNN单元的“输入隐含层单元”。
RNNCell的类属性state_size和output_size分别规定了隐含层的大小和输出向量的大小。
在Tensorflow中定义一个基本RNN单元的方法如下:
import tensorflow as tf
#定义一个BasicRNNCell实例
rnn_cell = tf.nn.rnn_cell.BasicRNNCell(num_units=128) #num_units为隐层包含的隐单元个数
#利用call函数
output,h1 = rnn_cell.call(input,h0)
#打印output_size
print(rnn_cell.output_size)
#打印隐层大小
print(rnn_cell.state_size)
2、对RNN进行堆叠MultiRNNCell
单层RNN性能有限,实际中,往往需要多层的RNN堆叠。将x输入第一层RNN后得到的隐层状态h1,相当于第二层RNN的输入,第二层RNN得到的隐层状态h2又相当于第三层RNN的输入,依次类推。在Tensorflow中,可以使用tf.nn.rnn_cell.MultiRNNCell()对RNN进行堆叠,相应的示例程序如下:
#首先定义一个返回BasicRNNCell的函数
def get_a_cell():
return tf.nn.rnn_cell.BasicRNNCell(num_units = 128)
#对3层RNN单元进行堆叠
cell = tf.nn.rnn_cell.MultiRNNCell([get_a_cell() for _ in range(3)])
#得到的cell 可以调用call() , state_size, output_size
output,h1 = cell.call(input,h0)
print(cell.output_size)
print(cell.state_szie)
3、BasicRNNCell 和 BasicLSTMCell的output
需要注意的一点是:BasicRNNCell 和 BasicLSTMCell的output与隐状态是一回事,因此,output_size = state_size,如果Net处理的是分类问题的话,则需要对上述2个子类返回的Output在单独添加softmax层才能得到最后的分类概率输出。
4、使用tf.nn.dynamic_rnn展开时间维度
对于单个的RNNCell,使用它的call函数运算时,只是在序列时间上前进了一步,如果序列长度为n,则要调用n次call函数。比较麻烦,为此,Tensorflow提供了一个tf.nn.dynamic_rnn(),使用该函数就相当于调用了n次call(),即通过(h0,x1,x2,…,xn)可直接得到(h1,h2,…,hn)。
具体示例如下:
#inputs: shape = (batch_size,time_steps,input_size)
#initial_state: shape = (batch_size,state_size)
outputs,finall_state = tf.nn.dynamic_rnn(cell,inputs,initial_state=initial_state)
#outputs: shape = (batch_size,time_steps,cell.output_size)
#finall_state: shape = (batch_size,cell.state_size)
至此,得到outputs之后,可以对其作进一步变换(eg:添加softmax()),进而,可以得到损失,开始训练模型。
(二) 在Tensorflow中实现CharRNN
model.py 定义CharRNN模型
train.py 对CharRNN进行训练
sample.py 测试训练好的CharRNN性能