基于tensorflow的RNN-LSTM(一)实现RNN
2017-09-19 11:28
561 查看
开始入门深度学习,在手推了RNN和LSTM的BP算法后(参考paper:Supervised Sequence Labelling with Recurrent Neural)。开始尝试用tensorflow实现RNN和LSTM以及基于其的一些衍生模型,在实现的过程中有一些思考和未解决的问题,在这里一并记录。
这里有必要先解释一下这些变量的含义,但是读者们大概率觉得枯燥,可以大致浏览下然后往下看,中途多次回顾即可。第一个变量num_steps,RNN循环的次数,由此可见深入理解这个变量对于理解代码所实现的RNN网络拓扑和RNN网络至关重要。第二个变量batch_size指的是批的大小,这个可以自己指定;num_classes是数字的类别,这里为2也即是0和1;state_size指隐藏层的神经元个数在图中是S内部的神经元数目;下一个是学习率,这个是应用于Adagrad算法的;最后一个是网络执行的次数。
先看原博客中给出的RNN结构图
这个图比较笼统,不易观察出batch_size、state_size等变量的对应关系,因此,我找到了第二张RNN结构图
我对这两张图的理解是:第一张图的P和第二张中的y是输出层,所不同的是第一张把真正的输出y进行了softmax处理得到了P;第一张的S和第二张的h都是隐藏层,其中上图的每一个S对应的下图三个小h(这里的“三个”在代码中用变量state_size表示);上图的X和下图的x都是输入层。
到此为止都比较宏观,读者可以在阅读代码时想一想开篇这一节所说的概念。
一些基本的Python语法这里不再赘述,原始数据的生成规则可以参看原博客,这个部分比较重要的是对原始数据的一个处理:x, y 从一个1000000的向量变成了如下图的格式
在代码的最后使用yield的函数生成一个迭代变量,留待后续使用enumerate函数进行处理。
仅仅处理到这一步还是不够的,在接下来的代码中可以看出
这里使用tf的占位符将x, y设定为shape为[batch_size, num_steps]([200, 5]); 并将init_state设置为shape为[200,4],接下来对x的处理,参看下图:
在模型训练之后会给出更完整的数据的shape变化图以及其与RNN内部单元的对应关系。
这一段定义了RNN网络的参数W和b,并且按照RNN的规则计算了中间层,并且加了一个softmax层,值得注意的是,在代码最后使用的是Adagrad算法进行梯度求解,去比较Adagrad和SGD是另一个宏大的课题,可以留给以后的系列文章去解决。
训练到这里可以给出网络的拓扑图如下:
在看图之前,先要说明一点是在下文中的shape的表示中,冒号前是抽象形式,冒号后是本例中的具象形式。明白这点之后,先看最底下,最底下就是一个x或X的shape(batch_size * num_steps : 200 * 5),省略号表示一共有batch_size行;接下来,经过tf.one_hot处理,成为了中间的shape,本质上就是把元素0变成了[1,0],把元素1变成了[0,1],变成了x_one_hot;然后再用tf.unstack处理得到了rnn_inputs,这个变量的shape是num_steps(目前是5)个(batch_size * num_classes : 200 * 2)。
花开两朵,各表一枝。现在在来看看本例实现的网络的拓扑结果,也即是图中上部。网络中共有num_steps个RNN单元,而为什么是这种形式,原博客有关截断的部分已经讲的很好了,这里不再赘述。具体来看每个RNN单元,首先是输入层x,输入层内有两个神经单元对应的是rnn_inputs中的one_hot表示形式的数据;接下来是中间层S及它的四个神经单元,这个是由state_size决定的;再往上是输出层y,也是两个神经单元,表示输出预测值的one_hot形式;最上面一层可以跟y层放在一起,我这里单独出来只是为了突出softmax。
为什么采用one_hot形式?如果直接用原始数据如何呢?如果采用word2ec形式又如何呢?
如果把num_steps扩大到和输入数据的维度一样大的程度,梯度爆炸会以怎样的形式出现?
比较Adagrad算法比SGD算法的优劣。
变量解释
本文的实现主要是依据这篇博客, 开篇作者便引入了五个变量:num_steps = 5 batch_size = 200 num_classes = 2 state_size = 8 learning_rate = 0.1 num_epochs = 1
这里有必要先解释一下这些变量的含义,但是读者们大概率觉得枯燥,可以大致浏览下然后往下看,中途多次回顾即可。第一个变量num_steps,RNN循环的次数,由此可见深入理解这个变量对于理解代码所实现的RNN网络拓扑和RNN网络至关重要。第二个变量batch_size指的是批的大小,这个可以自己指定;num_classes是数字的类别,这里为2也即是0和1;state_size指隐藏层的神经元个数在图中是S内部的神经元数目;下一个是学习率,这个是应用于Adagrad算法的;最后一个是网络执行的次数。
先看原博客中给出的RNN结构图
这个图比较笼统,不易观察出batch_size、state_size等变量的对应关系,因此,我找到了第二张RNN结构图
我对这两张图的理解是:第一张图的P和第二张中的y是输出层,所不同的是第一张把真正的输出y进行了softmax处理得到了P;第一张的S和第二张的h都是隐藏层,其中上图的每一个S对应的下图三个小h(这里的“三个”在代码中用变量state_size表示);上图的X和下图的x都是输入层。
到此为止都比较宏观,读者可以在阅读代码时想一想开篇这一节所说的概念。
数据处理
def gen_data(size=1000000): X = np.array(np.random.choice(2, size=(size, ))) Y = [] for i in range(size): threshold = 0.5 if X[i-3] == 1: threshold += 0.5 if X[i-8] == 1: threshold -= 0.25 if np.random.rand() > threshold: Y.append(0) else: Y.append(1) return X, np.array(Y) def gen_batch(raw_data, batch_size, num_steps): raw_x, raw_y = raw_data data_length = len(raw_x) batch_partition_length = data_length // batch_size data_x = np.zeros([batch_size, batch_partition_length], dtype = np.int32) data_y = np.zeros([batch_size, batch_partition_length], dtype = np.int32) for i in range(batch_size): data_x[i] = raw_x[batch_partition_length*i : batch_partition_length*(i+1)] data_y[i] = raw_y[batch_partition_length*i : batch_partition_length*(i+1)] epoch_size = batch_partition_length // num_steps for i in range(epoch_size): x = data_x[:, i*num_steps : (i+1)*num_steps] y = data_y[:, i*num_steps : (i+1)*num_steps] yield (x, y) def gen_epochs(n, num_steps): for i in range(n): yield gen_batch(gen_data(), batch_size, num_steps)
一些基本的Python语法这里不再赘述,原始数据的生成规则可以参看原博客,这个部分比较重要的是对原始数据的一个处理:x, y 从一个1000000的向量变成了如下图的格式
在代码的最后使用yield的函数生成一个迭代变量,留待后续使用enumerate函数进行处理。
仅仅处理到这一步还是不够的,在接下来的代码中可以看出
x = tf.placeholder(tf.int32, [batch_size, num_steps], name='input_placeholder') y = tf.placeholder(tf.int32, [batch_size, num_steps], name='label_placeholder') init_state = tf.zeros([batch_size, state_size]) x_one_hot = tf.one_hot(x, num_classes) rnn_inputs = tf.unstack(x_one_hot, axis=1)
这里使用tf的占位符将x, y设定为shape为[batch_size, num_steps]([200, 5]); 并将init_state设置为shape为[200,4],接下来对x的处理,参看下图:
在模型训练之后会给出更完整的数据的shape变化图以及其与RNN内部单元的对应关系。
模型构建
with tf.variable_scope('rnn_cell'): W = tf.get_variable('W', [num_classes+state_size, state_size]) b = tf.get_variable('b', [state_size], initializer=tf.constant_initializer(0.0)) def rnn_cell(rnn_input, state): with tf.variable_scope('rnn_cell', reuse=True): W = tf.get_variable('W', [num_classes+state_size, state_size]) b = tf.get_variable('b', [state_size], initializer=tf.constant_initializer(0.0)) return tf.tanh(tf.matmul(tf.concat([rnn_input, state], 1), W) + b) state = init_state rnn_outputs = [] for rnn_input in rnn_inputs: state = rnn_cell(rnn_input, state) rnn_outputs.append(state) final_state = rnn_outputs[-1] with tf.variable_sco 4000 pe('softmax'): W = tf.get_variable('W', [state_size, num_classes]) b = tf.get_variable('b', [num_classes], initializer=tf.constant_initializer(0.0)) logits = [tf.matmul(rnn_output, W) + b for rnn_output in rnn_outputs] predictions = [tf.nn.softmax(logit) for logit in logits] y_as_list = tf.unstack(y, num=num_steps, axis=1) losses = [tf.nn.sparse_softmax_cross_entropy_with_logits(labels=label, logits=logit) \ for logit, label in zip(logits, y_as_list)] total_loss = tf.reduce_mean(losses) train_step = tf.train.AdagradOptimizer(learning_rate).minimize(total_loss)
这一段定义了RNN网络的参数W和b,并且按照RNN的规则计算了中间层,并且加了一个softmax层,值得注意的是,在代码最后使用的是Adagrad算法进行梯度求解,去比较Adagrad和SGD是另一个宏大的课题,可以留给以后的系列文章去解决。
训练模型
def train_network(num_epochs, num_steps, state_size=state_size, verbose=True): with tf.Session() as sess: sess.run(tf.global_variables_initializer()) training_losses = [] for idx, epoch in enumerate(gen_epochs(num_epochs, num_steps)): # gen_epoch 获得1000(batch_size*num_steps)个数据, # 每个数据均为2维向量,表示为one_hot形式 training_loss = 0 training_state = np.zeros((batch_size, state_size)) if verbose : print("\nEPOCH", idx) for step, (X, Y) in enumerate(epoch): tr_losses, training_loss_, training_state, _ = \ sess.run([losses, total_loss, final_state, train_step], feed_dict={x: X, y: Y, init_state: training_state}) training_loss += training_loss_ step += 1 if step % 100 == 0 and step > 0: if verbose: print("Average loss at step", step, "for last", step , "steps:", training_loss/100) training_losses.append(training_loss/100) training_loss = 0 return training_losses training_losses = train_network(num_epochs, num_steps) plt.plot(training_losses) plt.show()
训练到这里可以给出网络的拓扑图如下:
在看图之前,先要说明一点是在下文中的shape的表示中,冒号前是抽象形式,冒号后是本例中的具象形式。明白这点之后,先看最底下,最底下就是一个x或X的shape(batch_size * num_steps : 200 * 5),省略号表示一共有batch_size行;接下来,经过tf.one_hot处理,成为了中间的shape,本质上就是把元素0变成了[1,0],把元素1变成了[0,1],变成了x_one_hot;然后再用tf.unstack处理得到了rnn_inputs,这个变量的shape是num_steps(目前是5)个(batch_size * num_classes : 200 * 2)。
花开两朵,各表一枝。现在在来看看本例实现的网络的拓扑结果,也即是图中上部。网络中共有num_steps个RNN单元,而为什么是这种形式,原博客有关截断的部分已经讲的很好了,这里不再赘述。具体来看每个RNN单元,首先是输入层x,输入层内有两个神经单元对应的是rnn_inputs中的one_hot表示形式的数据;接下来是中间层S及它的四个神经单元,这个是由state_size决定的;再往上是输出层y,也是两个神经单元,表示输出预测值的one_hot形式;最上面一层可以跟y层放在一起,我这里单独出来只是为了突出softmax。
展望
在本文中还有一些疑问留待以后解决:为什么采用one_hot形式?如果直接用原始数据如何呢?如果采用word2ec形式又如何呢?
如果把num_steps扩大到和输入数据的维度一样大的程度,梯度爆炸会以怎样的形式出现?
比较Adagrad算法比SGD算法的优劣。
相关文章推荐
- tensorflow 学习笔记12 循环神经网络RNN LSTM结构实现MNIST手写识别
- 深度学习(08)_RNN-LSTM循环神经网络-03-Tensorflow进阶实现
- TensorFlow实战12:实现基于LSTM的语言模型
- TensorFlow实现基于LSTM的语言模型
- Python语言基于Tensorflow实现RNN(预测)
- Tensorflow实现基于LSTM的文本分类方法
- tensorflow38《TensorFlow实战》笔记-07-02 TensorFlow实现基于LSTM的语言模型 code
- Tensorflow实例:实现基于LSTM的语言模型
- TensorFlow (RNN)深度学习 双向LSTM(BiLSTM)+CRF 实现 sequence labeling 序列标注问题 源码下载
- tensorflow实现基于LSTM的文本分类方法
- 解读tensorflow之rnn 的示例 ptb_word_lm.py 这两天想搞清楚用tensorflow来实现rnn/lstm如何做,但是google了半天,发现tf在rnn方面的实现代码或者教程
- cnn、rnn实现中文文本分类(基于tensorflow)
- TensorFlow (RNN)深度学习 双向LSTM(BiLSTM)+CRF 实现 sequence labeling 序列标注问题 源码下载
- tensorflow 学习专栏(七):使用RNN (LSTM)实现mnist手写数据集分类
- 深度学习之六,基于RNN(GRU,LSTM)的语言模型分析与theano代码实现
- 一文详解如何用 TensorFlow 实现基于 LSTM 的文本分类(附源码)
- 基于循环神经网络实现基于字符的语言模型(char-level RNN Language Model)-tensorflow实现
- 如何用 TensorFlow 实现基于 LSTM 的文本分类
- RNN-LSTM循环神经网络-03Tensorflow进阶实现
- Tensorflow实战学习(三十五)【实现基于LSTM语言模型】