一、代码步骤
1.导入相应的包
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
2.数据集导入以及其他参数制定
#载入数据集
mnist=input_data.read_data_sets("MNIST_data/",one_hot=True)
#输入图片是28*28
#图片不是28*28嘛,那样的话,每次输入28个像素,需要输入28次,这就是下面两个变量的意思
n_inputs=28#输入一行,一行有28个数据
max_time=28#一共28行
lstm_size=100#100个隐层单元
n_classes=10#10个分类
batch_size=50#每批次50个样本
n_batch=mnist.train.num_examples//batch_size#计算一共有多少个批次
#这里的none表示第一个维度可以是任意的长度
x=tf.placeholder(tf.float32,[None,784])
#正确的标签
y=tf.placeholder(tf.float32,[None,10])
#初始化权值
weights=tf.Variable(tf.truncated_normal([lstm_size,n_classes],stddev=0.1))#[100,10]
#初始化偏置值
biases=tf.Variable(tf.constant(0.1,shape=[n_classes]))
3.定义RNN网络
#定义RNN网络
def RNN(X,weights,biases):
#inputs=[batch_size,max_time,n_inputs]
inputs=tf.reshape(X,[-1,max_time,n_inputs])#50*784 =》50*28*28
#定义LSTM基本CELL 基础的LSTM循环网络单元
#__init__(
# num_units,
#
# forget_bias=1.0,
#
# state_is_tuple=True,
#
# activation=None,
#
# reuse=None,
#
# name=None,
#
# dtype=None
#
# )
# num_units: int类型,LSTM单元中的神经元数量,即输出神经元数量
# forget_bias: float类型,偏置增加了忘记门。从CudnnLSTM训练的检查点(checkpoin)
# 恢复时,必须手动设置为0.0。
# state_is_tuple: 如果为True,则接受和返回的状态是c_state和m_state的2 - tuple;如果为False,则他们沿着列轴连接。后一种即将被弃用。
# activation: 内部状态的激活函数。默认为tanh
# reuse: 布尔类型,描述是否在现有范围中重用变量。如果不为True,并且现有范围已经具有给定变量,则会引发错误。
# name: String类型,层的名称。具有相同名称的层将共享权重,但为了避免错误,在这种情况下需要reuse = True.
# dtype: 该层默认的数据类型。默认值为None表示使用第一个输入的类型。在call之前build被调用则需要该参数。
lstm_cell=tf.nn.rnn_cell.BasicLSTMCell(lstm_size)#n_neurons=lstm_size=100
#final_state[0]是cell state
#final_state[1]是hidden_state 与最后的输出有关
#tf.nn.dynamic_rnn(
# cell,
# inputs,
# sequence_length=None,
# initial_state=None,
# dtype=None,
# parallel_iterations=None,
# swap_memory=False,
# time_major=False,
# scope=None
# )
# inputs:[50*28*28]即[batch_size,step,input_size]
#按照规定,outputs是最后一层的输出,即为[batch_size,step,n_neurons]n_neurons是神经元的个数
#按照规定,final_state是每一层的最后一个step的输出,其实本程序只是用了一个隐藏层,因为是LSTM长短时记忆网络,所以因此我们的states包含1个LSTMStateTuple,
# 每一个表示每一层的最后一个step的输出,这个输出有两个信息,一个是h表示短期记忆信息,一个是c表示长期记忆信息。尺寸为[batch_size,n_neurons]
#所以,ouputs是[50,28,100],final_state每个LSTMStateTuple都包含c,h两个矩阵,都是[50*100]
#给大家举例看一个形状:这里的[batch_size,step,n_neurons]是[4,2,5] h c的尺寸分别是[4,5]
#outputs_val:
# [[[1.2949290e-04 0.0000000e+00 2.7623639e-04 0.0000000e+00 0.0000000e+00]
# [9.4675866e-05 0.0000000e+00 2.0214770e-04 0.0000000e+00 0.0000000e+00]]
#
# [[4.3100454e-06 4.2123037e-07 1.4312843e-06 0.0000000e+00 0.0000000e+00]
# [0.0000000e+00
# 0.0000000e+00
# 0.0000000e+00
# 0.0000000e+00
# 0.0000000e+00]]
#
# [[0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00]
# [0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00]]
#
# [[0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00]
# [0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00]]]
#
# states_val:
# (LSTMStateTuple(
# c=array([[0., 0., 0.04676079, 0.04284539, 0.],
# [0., 0., 0.0115245, 0., 0.],
# [0., 0., 0., 0., 0.],
# [0., 0., 0., 0., 0.]],
# dtype=float32),
# h=array([[0., 0., 0.00035096, 0.04284406, 0.],
# [0., 0., 0.00142574, 0., 0.],
# [0., 0., 0., 0., 0.],
# [0., 0., 0., 0., 0.]],
# dtype=float32)),
# LSTMStateTuple(
# c=array([[0.0000000e+00, 1.0477135e-02, 4.9871090e-03, 8.2785974e-04,
# 0.0000000e+00],
# [0.0000000e+00, 2.3306280e-04, 0.0000000e+00, 9.9445322e-05,
# 5.9535629e-05],
# [0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00,
# 0.0000000e+00],
# [0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00,
# 0.0000000e+00]], dtype=float32),
# h=array([[0.00000000e+00, 5.23016974e-03, 2.47756205e-03, 4.11730434e-04,
# 0.00000000e+00],
# [0.00000000e+00, 1.16522635e-04, 0.00000000e+00, 4.97301044e-05,
# 2.97713632e-05],
# [0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,
# 0.00000000e+00],
# [0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,
# 0.00000000e+00]], dtype=float32)),
# LSTMStateTuple(
# c=array([[1.8937115e-04, 0.0000000e+00, 4.0442235e-04, 0.0000000e+00,
# 0.0000000e+00],
# [8.6200516e-06, 8.4243663e-07, 2.8625946e-06, 0.0000000e+00,
# 0.0000000e+00],
# [0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00,
# 0.0000000e+00],
# [0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00,
# 0.0000000e+00]], dtype=float32),
# h=array([[9.4675866e-05, 0.0000000e+00, 2.0214770e-04, 0.0000000e+00,
# 0.0000000e+00],
# [4.3100454e-06, 4.2123037e-07, 1.4312843e-06, 0.0000000e+00,
# 0.0000000e+00],
# [0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00,
# 0.0000000e+00],
# [0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00,
# 0.0000000e+00]], dtype=float32))
# - --------------------
# 版权声明:本文为CSDN博主「小T是我」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明。
# 原文链接:https: // blog.csdn.net / junjun150013652 / article / details / 81331448
outputs,final_state=tf.nn.dynamic_rnn(lstm_cell,inputs,dtype=tf.float32)
#所以final_state[1]代表的就是LSTMStateTuple里的h,final_state[0]代表的是c
results=tf.matmul(final_state[1],weights)+biases#返回[50,10]
return results
4.损失函数、优化器、准确率
#计算RNN的返回结果
prediction=RNN(x,weights,biases)
#损失函数
cross_entropy=tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=prediction,labels=y))
#使用AdamOptimizer进行优化
train_step=tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
#结果存放在一个布尔型列表中
correct_prediction=tf.equal(tf.argmax(y,1),tf.argmax(prediction,1))
#求准确率
accuracy=tf.reduce_mean(tf.cast(correct_prediction,tf.float32))
#初始化
init=tf.global_variables_initializer()
5.开始训练
with tf.Session() as sess:
sess.run(init)
for epoch in range(6):
for batch in range(n_batch):
batch_xs,batch_ys=mnist.train.next_batch(batch_size)
sess.run(train_step,feed_dict={x:batch_xs,y:batch_ys})
acc=sess.run(accuracy,feed_dict={x:mnist.test.images,y:mnist.test.labels})
print("Iter "+str(epoch)+", Testing Accuracy= "+str(acc))
二、流程介绍
我们是分批次导入的数据,每批次导入50个样本,然后将样本reshape成为[50,28,28],即[batch_size,step,input_size],定义100个lstm神经元,即n_neurons=100。重点是下面这一句:
outputs,final_state=tf.nn.dynamic_rnn(lstm_cell,inputs,dtype=tf.float32)
关于tf.nn.dynamic_run()函数,
tf.nn.dynamic_rnn(
cell,
inputs,
sequence_length=None,
initial_state=None,
dtype=None,
parallel_iterations=None,
swap_memory=False,
time_major=False,
scope=None
)
第一个参数是神经元,第二个参数是咱们输入的矩阵是50*28*28([batch_size,step,input_size]),这个函数的第一个返回值outputs是最后一层的输出,返回值格式为[batch_size,step,n_neurons]是[50,28,100],本次我们只用了一个隐藏层,所以就是这一层是输出,而final_state是每一层最后一个step的输出,本次只有一个隐藏层,所以只返回一个LSTMStateTuple,如果有多个层,则返回多个。而每个LSTMStateTuple则包括两个矩阵,h表示短期记忆信息,c表示长期记忆信息,每个矩阵的尺寸为[batch_size,n_neurons],即[50,100]。
#给大家举例看一个形状:这里的[batch_size,step,n_neurons]是[4,2,5] h c的尺寸分别是[4,5]
#outputs_val:
# [[[1.2949290e-04 0.0000000e+00 2.7623639e-04 0.0000000e+00 0.0000000e+00]
# [9.4675866e-05 0.0000000e+00 2.0214770e-04 0.0000000e+00 0.0000000e+00]]
#
# [[4.3100454e-06 4.2123037e-07 1.4312843e-06 0.0000000e+00 0.0000000e+00]
# [0.0000000e+00
# 0.0000000e+00
# 0.0000000e+00
# 0.0000000e+00
# 0.0000000e+00]]
#
# [[0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00]
# [0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00]]
#
# [[0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00]
# [0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00]]]
#
# states_val:
# (LSTMStateTuple(
# c=array([[0., 0., 0.04676079, 0.04284539, 0.],
# [0., 0., 0.0115245, 0., 0.],
# [0., 0., 0., 0., 0.],
# [0., 0., 0., 0., 0.]],
# dtype=float32),
# h=array([[0., 0., 0.00035096, 0.04284406, 0.],
# [0., 0., 0.00142574, 0., 0.],
# [0., 0., 0., 0., 0.],
# [0., 0., 0., 0., 0.]],
# dtype=float32)),
# LSTMStateTuple(
# c=array([[0.0000000e+00, 1.0477135e-02, 4.9871090e-03, 8.2785974e-04,
# 0.0000000e+00],
# [0.0000000e+00, 2.3306280e-04, 0.0000000e+00, 9.9445322e-05,
# 5.9535629e-05],
# [0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00,
# 0.0000000e+00],
# [0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00,
# 0.0000000e+00]], dtype=float32),
# h=array([[0.00000000e+00, 5.23016974e-03, 2.47756205e-03, 4.11730434e-04,
# 0.00000000e+00],
# [0.00000000e+00, 1.16522635e-04, 0.00000000e+00, 4.97301044e-05,
# 2.97713632e-05],
# [0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,
# 0.00000000e+00],
# [0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,
# 0.00000000e+00]], dtype=float32)),
# LSTMStateTuple(
# c=array([[1.8937115e-04, 0.0000000e+00, 4.0442235e-04, 0.0000000e+00,
# 0.0000000e+00],
# [8.6200516e-06, 8.4243663e-07, 2.8625946e-06, 0.0000000e+00,
# 0.0000000e+00],
# [0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00,
# 0.0000000e+00],
# [0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00,
# 0.0000000e+00]], dtype=float32),
# h=array([[9.4675866e-05, 0.0000000e+00, 2.0214770e-04, 0.0000000e+00,
# 0.0000000e+00],
# [4.3100454e-06, 4.2123037e-07, 1.4312843e-06, 0.0000000e+00,
# 0.0000000e+00],
# [0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00,
# 0.0000000e+00],
# [0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00,
# 0.0000000e+00]], dtype=float32))
所以在这里,final_state[1]是h,final_state[0]是c,返回的都是一个[50,100]的矩阵。
综上所述,outputs返回的是一个[50,28,100],final_state返回的是一个[50,100]的矩阵。
tf.matmul(final_state[1],weights)+biases返回的就是一个[50,10]的结果标签矩阵。每一行都是一个一维独热编码矩阵,只有分类结果为1,其他都为0,后面的代码就比较好理解了。