本文主要是介绍白话RNN系列(五),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
前文,对于LSTM的结构进行了系统的介绍,本文,通过一个MNIST_data的例子,争取能够把LSTM的基本使用来吃透。
import tensorflow as tf
import input_data
# 导入 MINST 数据集
# from tensorflow.examples.tutorials.mnist import input_data
# one_hot=True,代表输入的是one-hot向量
mnist = input_data.read_data_sets("/MNIST_data/", one_hot=True)
# 每次输入的是一个28维的向量
n_input = 28 # MNIST data 输入 (img shape: 28*28)
# LSTM的循环体会循环28次
n_steps = 28 # timesteps
# 隐藏层神经元的数目是128
n_hidden = 128 # hidden layer num of features
n_classes = 10 # MNIST 列别 (0-9 ,一共10类)
这里需要注意,因为MNIST_data的输入实际上是一个784维的向量,来自于一张28*28大小的手写字体图片,我们设定n_steps为循环次数,而n_input代表每次会输入28个特征,也就是一行的数据。
必须要注意这两个28的区别。
# 定义初始输入的占位符
# None 其实代表的是一个批次会输入多少个数据
# n_steps 即上面的28 ,代表会循环输入28次
# n_input 值为28 ,代表每个循环内会输入28 * 1维度的向量
x = tf.placeholder("float", [None, n_steps, n_input])
# y是最终的分类结果,n_classes = 10 ,代表有10个分类
y = tf.placeholder("float", [None, n_classes])
这里,定义我们的初步输入x和y,但实际上,我们真正输入的内容还不是x和y,而是下面的x1:
# 上文,得到我们输入的x 是28 *28 维度的矩阵
# 这里,通过unstack,拆分成28 列,每一列都是28 * 1维度的列向量
x1 = tf.unstack(x, axis=1)
对于这里,我的理解是,x是28 * 28的矩阵,每一行对应图片的一行,每一列对应于图片中的一列,通过unstack方式,切分得到的每个list,实际上内部是图片的一列元素(这在当前行=列的情况下无影响),但具体使用的时候,还是需要严格区分两个28的分别作用。
到这里,我们得到了每次输入的列向量,是28 * 1维度的列向量。
# 通过tensorflow初始化一个LSTMCell
# n_hidden 代表隐藏层的节点数
# forget_bias 即遗忘门中的偏置,默认为1,可以不写
lstm_cell = tf.nn.rnn_cell.LSTMCell(n_hidden, forget_bias=1.0, name='basic_lstm_cell')
# 使用静态运行的方式得到我们的输出和隐藏状态
outputs, states = tf.contrib.rnn.static_rnn(lstm_cell, x1, dtype=tf.float32)
LSTMCell的初始化过程中,指定隐藏层神经元的数目即可;此处,我们以静态运行的状态启动,输入的x1为28 * 1维度的列向量。
# 加入一个全连接
# 得到n_classes=10 的输出用于结果分类
pred = tf.contrib.layers.fully_connected(outputs[-1], n_classes, activation_fn=None)
全连接,得到10 * 1的列向量,用于输出分类结果。
接下来,我们看下训练过程:
step = 1# Keep training until reach max iterations# batch_size 为128 ,代表每次输入128张图片进行训练# training_iters 为100000 ,定义了我们的训练次数while step * batch_size < training_iters:# 至于图片是怎么读取的,关系应该不大# 生成的其实是128 * 784的部分,对于x来说# 对于batch_Y来说,得到的是128 * 1的向量batch_x, batch_y = mnist.train.next_batch(batch_size)# 为什么会是128 * 784的数据# Reshape data to get 28 seq of 28 elements# 数据解析为128个,后面是28 * 28维的向量batch_x = batch_x.reshape((batch_size, n_steps, n_input))# Run optimization op (backprop)sess.run(optimizer, feed_dict={x: batch_x, y: batch_y})if step % display_step == 0:# 计算批次数据的准确率acc = sess.run(accuracy, feed_dict={x: batch_x, y: batch_y})# Calculate batch lossloss = sess.run(cost, feed_dict={x: batch_x, y: batch_y})print("Iter " + str(step * batch_size) + ", Minibatch Loss= " + \"{:.6f}".format(loss) + ", Training Accuracy= " + \"{:.5f}".format(acc))step += 1print(" Finished!")
里面有几个变量,我们没有定义,在这里补充下:
learning_rate = 0.001
training_iters = 100000
batch_size = 128
display_step = 10# Define loss and optimizer
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(logits=pred, labels=y))
optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost)
学习率,迭代次数,批次大小,display_step用于为我们确定多少步输出一次精确度:
OK,到这里我们把代码重新梳理一遍:
我们每个批次输入了batch_size = 128 的数据量,而每个数据,实际上是28 * 28 大小的矩阵,通过unstack方式,将其转化为28 个list,每个list再进行reshape,转化为28 * 1的列向量,最终作为LSTM的输入:
接着,我们搭建了num_units=128 的LSTMCell,其输出后面紧跟着一个全连接神经网络,得到最后的输出;再经过一轮softmax,得到最后的输出结果。
简化来说,我们只要能够确定清楚自己输入向量的维度,很轻松就能够使用LSTM完成我们的任务。
全部代码在此处;
# -*- coding: utf-8 -*-
import tensorflow as tfimport input_data# 导入 MINST 数据集
# from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("/MNIST_data/", one_hot=True)
n_input = 28 # MNIST data 输入 (img shape: 28*28)
n_steps = 28 # timesteps
n_hidden = 128 # hidden layer num of features
n_classes = 10 # MNIST 列别 (0-9 ,一共10类)# 这里对于上面都要整体说明下
# 这里的输入当成28个时间段,每段内容都是28个值,使用unstack将原始的输入28 * 28 调整成具有28个元素的list
# 每个元素为1 * 28的数组,这28个时序一次送入RNN中
# 由于是批次操作,所以每次都会取该批次中所有图片的一行作为一个时间序列输入tf.reset_default_graph()# tf Graph input
# 确认人家的输入和输出时怎么得到的
# 这里输入的好像是批次个数:然后step应该是max_times,即最多有多少个时序
# 每个时序输入的其实是28个
# 构建出来的n_steps=28
# n_input = 28x = tf.placeholder("float", [None, n_steps, n_input])
y = tf.placeholder("float", [None, n_classes])# 1真的是按照列切分的
# 的确是按照列切分的
# x本身是28 * 28的,现在切割成28个列,每列都是28个元素,算是一个样本
x1 = tf.unstack(x, axis=1)# 1 BasicLSTMCell
# 先构建一个包含128个cell的类lstm_cell, 然后将变形后的x1放进去生成节点outputs
# 最后通过全连接生成pred, 最后使用softmax进行分类
# 这128个cell是怎么定义出来的?lstm_cell = tf.nn.rnn_cell.LSTMCell(n_hidden, forget_bias=1.0, name='basic_lstm_cell')
outputs, states = tf.contrib.rnn.static_rnn(lstm_cell, x1, dtype=tf.float32)# 通过全连接形成的十个分类,即10 * 1的向量
# 然后通过softmax方式,与真正的输出进行交叉熵合作
pred = tf.contrib.layers.fully_connected(outputs[-1], n_classes, activation_fn=None)learning_rate = 0.001
training_iters = 100000
batch_size = 128
display_step = 10# Define loss and optimizer
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(logits=pred, labels=y))
optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost)# Evaluate model
correct_pred = tf.equal(tf.argmax(pred, 1), tf.argmax(y, 1))
accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32))# 启动session
with tf.Session() as sess:sess.run(tf.global_variables_initializer())step = 1# Keep training until reach max iterations# 这里的batch_size = 128 ,代表每次会输出128个数据进行训练# training_iters为100000while step * batch_size < training_iters:# 这里的数据,应该是横向的,一行是一个图片的数据# 至于图片是怎么读取的,关系应该不大# 生成的其实是128 * 784的部分,对于x来说# 对于batch_Y来说,得到的是128 * 1的向量batch_x, batch_y = mnist.train.next_batch(batch_size)# 为什么会是128 * 784的数据# Reshape data to get 28 seq of 28 elements# 看来理解还是不透彻,如何这么实现reshape的?# 自行解析成三维的数据# 后面的数据会自行解析成二维的部分# 数据解析为128个,后面是28 * 28维的向量batch_x = batch_x.reshape((batch_size, n_steps, n_input))# Run optimization op (backprop)out = sess.run(outputs, feed_dict={x: batch_x, y: batch_y})print(out[-1].shape)sess.run(optimizer, feed_dict={x: batch_x, y: batch_y})if step % display_step == 0:# 计算批次数据的准确率acc = sess.run(accuracy, feed_dict={x: batch_x, y: batch_y})# Calculate batch lossloss = sess.run(cost, feed_dict={x: batch_x, y: batch_y})print("Iter " + str(step * batch_size) + ", Minibatch Loss= " + \"{:.6f}".format(loss) + ", Training Accuracy= " + \"{:.5f}".format(acc))step += 1print(" Finished!")# 计算准确率 for 128 mnist test imagestest_len = 128test_data = mnist.test.images[:test_len].reshape((-1, n_steps, n_input))test_label = mnist.test.labels[:test_len]print("Testing Accuracy:", \sess.run(accuracy, feed_dict={x: test_data, y: test_label}))
这篇关于白话RNN系列(五)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!