前言:
写这篇博客的目的是一开始想要使用Tensorflow建立一个image caption模型,在一开始觉得不就是一个LSTM模型,因为之前有用Tensorflow实现过CNN结构,所以觉得并不会很难。但实际上,在这个过程中也遇到了不少困难。
按照我自己的学习顺序,这个系列的博客将分为三个部分,最终将构建一个基于Tensorflow的简单的image caption模型:
- 就是本篇博客,搬运于另一个博主,加上了自己的理解做了一些扩展性的,主要是对语言模型有关的注释。这篇博客主要是为了了解一些LSTM一些基本的结构。
- 这个系列第二篇部分,同样搬运于另一个博主,这篇博客将《tensorflow 实战》用Tensorflows实现的循环神经网络语言模型大大简化,增加了书上例子的可读性,在我学习的过程中给了我很多帮助。
- 这个系列的第三部分,也是最后一部分,参考了上述两篇博客和Assignment3中的部分,最后算是整合成了一个符合自己预期的模型,也是自己收获最多的一部分。
- 最后感谢所有我在学习过程中互联网上间接或直接提供帮助的朋友,世界因为你们而美好。无法一一罗列,所有参考资料会放在文章最后
第一部分 基本的LSTM结构
在这个部分,将使用MNSIT_data数据集和LSTM构建一个基本的分类模型。直接上代码,具体内容见代码中的注释,代码中有些不好理解的部分,可见文末的一些链接中。
'''读取数据'''
from __future__ import print_function
import tensorflow as tf
from tensorflow.contrib import rnn
# Import MNIST data
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("./MNIST_data", one_hot=True)
#看看数据的样子
print(mnist.train.images.shape)
print(tf.__version__)
# (55000, 784)
# 1.3.0
'''预先定义一些参数'''
lr = 1e3
batch_size = tf.placeholder(tf.int32,[]) #这样可以使用不同的batch_size
input_size = 28 #每个时刻输入的特征的维度,如果是语言模型,可以理解为词向量的维度
timestep_size = 28 # 时序的长度。在语言模型中
hidden_size = 256 # 隐含层节点数
layer_num = 2 # LSTM layer的层数
class_num = 10 # 最后输出分类的类别,在语言模型中,这个参数就是单词表的大小。
# 输入输出
_X = tf.placeholder(tf.float32, [None, 784])
y = tf.placeholder(tf.float32, [None, class_num])
keep_prob= tf.placeholder(tf.float32, [])
'''构建模型'''
# 先处理数据,将[None,784] => [batchsize,timestep_size,input_size]
#实际上输入可以直接规定成这样的格式
X = tf.reshape(_X,[-1,timestep_size, input_size])
# 构建模型有两种方法,
#法一:
#定义一个LSTM_cell
# lstm_cell = rnn.BasicLSTMCell(
# hidden_size,
# forget_bias = 1.0,
# state_is_tuple = True
# )
# lstm_cell = rnn.DropoutWrapper(
# cell = lstm_cell,
# input_keep_prob = 1.0,
# output_keep_prob = keep_prob
# )
# #多层LSTM
# mlstm_cell = rnn.MultiRNNCell([lstm_cell] * layer_num, state_is_tuple = True)
#法二:
##上边注释的等价于
def lstm_cell():
cell = rnn.LSTMCell(hidden_size, reuse=tf.get_variable_scope().reuse)
return rnn.DropoutWrapper(cell, output_keep_prob = keep_prob)
mlstm_cell = tf.contrib.rnn.MultiRNNCell([lstm_cell() for _ in range(layer_num)], state_is_tuple = True)
#lstm的传播过程中会保存中间的状态, state_is_tuple的意思就是回返回一个元祖(c_state,m_state),其中分别代表
#(主线的状态,支线的状态),
#下边是对state进行初始化, 这是全0,也可以自定义 ,但这为什么是batch_size大小的呢/.?????
init_state = mlstm_cell.zero_state(batch_size, dtype=tf.float32)
#outputs 一个list.保留每一步的output
#state = (c_state,m_state),只保留最后一次的状态 这个实际上并不太懂
# 在这里state[1] = output[-1]
#time_major : 每一个时间步是不是在主要的维度,比如现在X.shape = [batch_size,timestep_size, input_size]
# 中时间点在第二个位置,也就是次要的维度,所以这里time_major为False
# outputs, state = tf.nn.dynamic_rnn(mlstm_cell, inputs = X , initial_state = init_state, time_major = False)
# h_state = state[-1][1]
outputs = list()
state = init_state
with tf.variable_scope('RNN'):
for timestep in range(timestep_size):
if timestep > 0:
tf.get_variable_scope().reuse_variables()
# 这里的state保存了每一层 LSTM 的状态
(cell_output, state) = mlstm_cell(X[:, timestep, :],state)
outputs.append(cell_output)
h_state = outputs[-1]
'''定义输出层和损失、准确率'''
#定义输出与softmax链接的权重
W = tf.Variable(tf.truncated_normal([hidden_size , class_num], stddev = 0.1), dtype = tf.float32)
bias = tf.Variable(tf.constant(0.1,shape = [class_num]), dtype = tf.float32)
y_pre = tf.nn.softmax(tf.matmul(h_state, W) + bias)
cross_entropy = -tf.reduce_mean(y * tf.log(y_pre))
train_op = tf.train.AdamOptimizer(lr).minimize(cross_entropy)
correct_prediction = tf.equal(tf.argmax(y_pre,1), tf.argmax(y,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
'''训练过程'''
sess = tf.Session()
sess.run(tf.global_variables_initializer())
for i in range(2000):
_batch_size = 128
batch = mnist.train.next_batch(_batch_size)
if (i+1)%200 == 0:
train_accuracy = sess.run(accuracy, feed_dict={
_X:batch[0], y: batch[1], keep_prob: 1.0, batch_size: _batch_size})
# 已经迭代完成的 epoch 数: mnist.train.epochs_completed
print("Iter%d, step %d, training accuracy %g" % ( mnist.train.epochs_completed, (i+1), train_accuracy))
sess.run(train_op, feed_dict={_X: batch[0], y: batch[1], keep_prob: 0.5, batch_size: _batch_size})
# 计算测试数据的准确率
print("test accuracy %g" % sess.run(accuracy, feed_dict={
_X: mnist.test.images, y: mnist.test.labels, keep_prob: 1.0, batch_size:mnist.test.images.shape[0]}))
不好理解的部分:
1. RNN里的正则化
2. tf.contrib.rnn.DropoutWrapper的理解