RNN之tensorflow-BasicLSTMCell+mnist手写字符数据集分类+github完整代码
一、原理部分
关于RNN的详细介绍,请看博文
详解循环神经网络RNN原理+tensorflow实现
关于LSTM:
我们知道RNN包含了之前任意时刻的输入,但是这样会造成梯度消失或者梯度爆炸,同时不能够很好地学习特征,因此采用LSTM
(1)对输入(x,h)控制(通过乘以sigmod后[0-1]的小数);
(2)控制之前“积累”状态需要遗忘的程度;
(3)控制当前时间步是否需要输出。
来达到更加灵活的控制。
框图如下:
详见如下两篇博文,讲述很详细。
BasicLSTMCell中num_units参数解释
下面这篇文章对tf.nn.rnn_cell.BasicLSTMCell类中关于如何得到上图所示变量的过程解释很清楚。
深度学习笔记2:关于LSTM神经网络输入输出的理解
二、代码详解
1、代码分析
一共包含两个文件
一个是RNN_LSTM_Classfication.py
一个是simple_RNN.py
RNN_LSTM_Classfication.py
头文件以及数据载入,数据载入解释见博文tensorflow运行卷积神经网络的一些ERROR
from tensorflow import keras, Session, transpose, global_variables_initializer
from modular.simple_RNN import simple_RNN
from modular.compute_accuracy import compute_accuracy
from modular.random_choose import corresponding_choose
(train_x_image, train_y), (test_x_image, test_y) = keras.datasets.mnist.load_data(path='/home/xiaoshumiao/.keras/datasets/mnist.npz')
train_y = keras.utils.to_categorical(train_y)
test_y=keras.utils.to_categorical(test_y)
参数设置
epochs = 1000
n_classes = 10
batch_size = 200#number
chunk_size = 28
n_chunk = 28
rnn_size = 128#the lenth of a hidden_neural_layer or the number of hidden_neural
learning_rate = 0.001
实例一个自己定义的RNN类
rnn = simple_RNN(chunk_size, n_chunk, rnn_size, batch_size, n_classes, learning_rate)
Sessin()
with Session() as sess:
sess.run(global_variables_initializer())
for i in range(epochs):
train_data = corresponding_choose(train_x_image, batch_size, m=0)
train_x_betch = train_data.row_2(train_x_image) / 255.
train_y_betch = train_data.row(train_y)
sess.run(rnn.train,feed_dict={rnn.X:train_x_betch,rnn.y:train_y_betch})
if i % 20 ==0:
test_data = corresponding_choose(test_x_image, 200, m=0)
test_x_betch = test_data.row_2(test_x_image) / 255.
test_y_betch = test_data.row(test_y)
b = sess.run(rnn.result, feed_dict={rnn.X: test_x_betch})
c = sess.run(compute_accuracy(b, transpose(test_y_betch)))
print(c)
simple_RNN.py
头文件导入
from tensorflow import placeholder,float32,transpose, nn, reduce_mean, multiply, log, reduce_sum, train
from add_layer import add_layer
from tensorflow.python.ops.rnn import dynamic_rnn
数据输入
class simple_RNN(object):
def __init__(self,chunk_size,n_chunk,hidden_chunk_size, batch_size, n_class, learning_rate):
self.X = placeholder(float32,[None,n_chunk,chunk_size])#200,28,28
self.y = placeholder(float32,[None, n_class])
定义一个cell
初始化状态值(结构见上面的两篇链接)
构建rnn计算图并得到最后一个时间步输出。
self.LSTM_cell = nn.rnn_cell.BasicLSTMCell(hidden_chunk_size, forget_bias=1.0, state_is_tuple=True)
self.init_state = self.LSTM_cell.zero_state(batch_size, float32)
self.output, self.states = dynamic_rnn(self.LSTM_cell, self.X, initial_state=self.init_state, dtype=float32)
得到输出后连接一层全连接层,得到10维输出。
self.result = add_layer(transpose(self.states[1]), hidden_chunk_size, n_class, activation_function=nn.softmax)
用训练全连接网络的方法训练全连接层的输出
self.loss = reduce_mean(-reduce_sum(multiply(transpose(self.y),log(self.result)),reduction_indices=[0]))
self.train = train.AdamOptimizer(learning_rate).minimize(self.loss)
2、问题解决
(1)、
第一个问题也是困扰很久的问题,因为我是根据莫烦python学习的RNN,根据莫烦老师的讲解,我们先手动计算得到因层128维向量,然后再带入cell。但是我查阅博文发现,tf.nn.rnn_cell.BasicLSTMCell函数中的num_units就是定义的隐层神经元个数(着这因层输出向量的维数),而在构建RNN计算图dynamic_rnn的时候,我们需要输入的却是原始数据。同时参考上面链接的两篇博客,LSTM的输入是原始数据和上一时刻的隐含神经元输出。所以综上所述,我们不需要实现手动计算隐层神经元的结果。
同时,在tf.nn.rnn_cell.BasicLSTMCell中可以找到
因此,不需要对输入数据做处理。
(2)、
test_data = corresponding_choose(test_x_image, 200, m=0)
一开始测试的时候样本batch_size和训练样本不符合,所以也设置200,或者再改都可以。
(3)、
初始化变量的时候,不要用别的,就老老实实用
global_variables_initializer()
三、实验结果+github
实现结果如下:
总体来看实验结果还很可观的。
完整代码(调用的其他自己写的库文件),以及一些其他程序注释,需要注意的地方,都一并放在github上,有需要的可以去看一下。
https://github.com/wangjunhe8127/tensorflow-BasicLSTMCell-mnist
May the force be with you!