预备知识
比较经典的博客:Understanding LSTM Networks
中文版:理解LSTM网络
TensorFlow相关函数
unstack
1 | unstack(value, num=Nonde, axis=0, name='unstack') |
将rank-R维的tensor分解为R-1维(会降维)的list。以一个常见的需要RNN处理的[batch_size, timesteps, n_input]为例,由于tensorflow.contrib.rnn.static_rnn的输入是[batch_size, n_input], 所以使用unstack可以轻松的将原始输入转化为需要的shape。
transpose
1 | transpose(a, perm=None, name='transpose') |
For example:
1 | x = tf.constant([[1, 2, 3], [4, 5, 6]]) |
split
1 | split(value, num_or_size_splits, axis=0, num=None, name='split') |
将tensor按照axis的维度分解为子tensor的list(不会降维)。
static_rnn VS dynamic_rnn
TensorFlow中内置的rnn有两种:tf.contrib.rnn.static_rnn(之前版本是tf.nn.rnn)和tf.nn.dynamic_rnn
static_rnn会创建一个展开的rnn,但是其长度是固定的,也就是说,如果你第一次传进去的shape是200 timesteps的,那么就会创建一个静态的含有200次循环的rnn cell。这会导致两个问题:1. 创建过程会比较耗时 2. 一旦创建好了之后,就不可以再传入比第一次更长的timesteps的sequence了。
而dynamic_rnn解决了这个问题,它内部实现的时候是动态的创建rnn的循环图的。
所以,比较推荐使用dunamic_rnn来创建rnn或者相关的网络
TensorFlow Code
mnist 数据集
TensorFlow中内置了mnist数据集,本文使用该数据集作为LSTM用于分类的例子
1 | from nnlayers.BasicLSTMLayer import BasicLSTMLayer |
设置数据集的training次数、mnist的label数量、batch_size、time_steps&num_input(mnist中数据为28*28的图片)、num_hidden等参数
1 | epochs = 10 |
初始化网络rnn输入和输出之后全连接层的参数1
2
3
4
5
6x = tf.placeholder('float', [None, timesteps, num_input])
y = tf.placeholder('float', [None, num_classes])
layer = {'weights': tf.Variable(tf.random_normal([num_hidden, num_classes])),
'biases': tf.Variable(tf.random_normal([num_classes]))}
lstm_layer = BasicLSTMLayer(None, 'test_lstm_layer', None, None,
**{'num_hidden': num_hidden, 'input': x, 'timesteps': timesteps})
LSTM的两种实现
static_rnn
1 | x = tf.unstack(x, timesteps, 1) |
dynamic_rnn
1 | lstm_cell = rnn.BasicLSTMCell(num_hidden, forget_bias=1.0) |
对LSTM输出结果的处理
1 | # 如果使用static_rnn实现的话,这句话就不需要: |
将以上步骤串起来通过Session进行计算
1 | with tf.Session() as sess: |
完成!最终的training Accuracy:
1 | …… |