此博文是我们在完成实战五·用RNN(LSTM)做手写数字识别的基础上使用BiRNN(LSTM)结构,进一步提升模型的准确率,1000steps准确率达到99%。
tf.nn.static_bidirectional_rnn 函数原型
tf.nn.static_bidirectional_rnn( cell_fw, cell_bw, inputs, initial_state_fw=None, initial_state_bw=None, dtype=None, sequence_length=None, scope=None )
输入值介绍:
cell_fw:用于前向传播的RNNCell.
cell_bw: 用于反向传播的RNNCell.
inputs: A length T list of inputs, each a tensor of shape [batch_size, input_size], or a nested tuple of such elements.(输入 数据为list类型,list中元素为Tensor,每个Tensor的shape为[batch_size, input_size],如有batch_size个文档,每个文档的单词数量为1000,每个单词的词向量维度为100,则该inputs为list(1000tensor(batch_size100)))
initial_state_fw: (optional)前向RNN的初始状态。 This must be a tensor of appropriate type and shape [batch_size, cell_fw.state_size]. If cell_fw.state_size is a tuple, this should be a tuple of tensors having shapes [batch_size, s] for s in cell_fw.state_size.。
initial_state_bw: (optional) Same as for initial_state_fw, but using the corresponding properties of cell_bw.
dtype: (optional) The data type for the initial state. Required if either of the initial states are not provided.
sequence_length: (optional) An int32/int64 vector, size [batch_size], containing the actual lengths for each of the sequences.
scope: VariableScope for the created subgraph; defaults to “bidirectional_rnn”
输出值介绍:
A tuple (outputs, output_state_fw, output_state_bw) where: outputs is a length T list of outputs (one for each input), which are depth-concatenated forward and backward outputs. output_state_fw is the final state of the forward rnn. output_state_bw is the final state of the backward rnn.
主体结构仿照实战五·用RNN(LSTM)做手写数字识别,修改的地方加了备注信息,推荐对比实战五来看。
import os os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE" import time import tensorflow as tf import numpy as np import pandas as pd import matplotlib.pyplot as plt import cv2 from tensorflow.examples.tutorials.mnist import input_data mnist=input_data.read_data_sets("./2RNN/data",one_hot=True) train_rate=0.002 train_step=1001 batch_size=1000 display_step=10 frame_size=28 sequence_length=28 hidden_num=128 n_classes=10 """其中: train_rate是学习速率,这是一个超参数,目前由经验设置的,当然也可以自适应。 batch_size:每批样本数,rnn也可以使用随机梯度下降进行训练,一批批的灌数据进去,而不是每一次把整个数据集都灌进去。 sequence_size:每个样本序列的长度。因为我们希望把一个28x28的图片当做一个序列输入到rnn进行训练,所以我们需要对图片进行序列化。一种最方便的方法就是我们认为行与行之间存在某些关系,于是把图片的每一行取出来当做序列的一个维度。所以这里sequence_size就是设置为28。 反映到图1里面就是左边循环图展开后右图从左往右xi的数目。 rnn cell number frame_size:序列里面每一个分量的大小。因为每个分量都是一行像素,而一行像素有28个像素点。所以frame_size为28。 反映到图1里面就是最下变的输入中每个xi都是一个长度为frame_size的向量或矩阵。input cell number hidden_num:隐层个数,经验设置为5 反映到图1里面就是从下往上数的有hidden_num个隐层单元。 n_classes:类别数,10个数字就是设置为10咯""" x=tf.placeholder(dtype=tf.float32,shape=[None,sequence_length*frame_size],name="inputx") y=tf.placeholder(dtype=tf.float32,shape=[None,n_classes],name="expected_y") weights=tf.Variable(tf.random_normal(shape=[2*hidden_num,n_classes]))#因为是双向,输出形状为(-1,2*hidden_num) bias=tf.Variable(tf.fill([n_classes],0.1)) """注意:weights是整个网络的最后一层,它的形状为hidden_numXn_class,至于为什么是这个形状,我们下面来说。 bias最后一层的偏置""" #定义RNN网络 def RNN(x,weights,bias): x = tf.reshape(x,shape=[-1,sequence_length,frame_size]) #把输入转换为static_bidirectional_rnn接受的形状:输入 数据为list类型,list中元素为Tensor,每个Tensor的shape为[batch_size, input_size] #先把数据x 的第一维度与第二维度互换 x = tf.transpose(x,[1,0,2]) #变形为(-1,frame_size)形状 x = tf.reshape(x,shape=[-1,frame_size]) #拆分为list,list中元素为Tensor,每个Tensor的shape为[batch_size, input_size] x = tf.split(x,sequence_length) lstm_fw_cell = tf.nn.rnn_cell.BasicLSTMCell(hidden_num) # 正向RNN,输出神经元数量为128 lstm_bw_cell = tf.nn.rnn_cell.BasicLSTMCell(hidden_num) # 反向RNN,输出神经元数量为128 output, fw_state, bw_state = tf.nn.static_bidirectional_rnn(lstm_fw_cell, lstm_bw_cell, x, dtype=tf.float32) print(len(output)) #生成hidden_num个隐层的RNN网络 #这是一个深度RNN网络,对于每一个长度为sequence_length的序列[x1,x2,x3,...,]的每一个xi,都会在深度方向跑一遍RNN,每一个都会被这hidden_num个隐层单元处理。 h = tf.matmul(output[int(sequence_length/2)],weights)+bias#output长度为sequence_length,我们取中间位置的输出,双向的结果都可以兼顾到 #此时output就是一个[batch_size,sequence_length,rnn_cell.output_size]形状的tensor return (h) #我们取出最后每一个序列的最后一个分量的输出output[:,-1,:],它的形状为[batch_size,rnn_cell.output_size]也就是:[batch_size,hidden_num]所以它可以和weights相乘。这就是2.5中weights的形状初始化为[hidden_num,n_classes]的原因。然后再经softmax归一化。 predy=RNN(x,weights,bias) cost=tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=predy,labels=y)) opt=tf.train.AdamOptimizer(train_rate).minimize(cost) correct_pred=tf.equal(tf.argmax(predy,1),tf.argmax(y,1)) accuracy=tf.reduce_mean(tf.to_float(correct_pred)) testx,testy=mnist.test.next_batch(batch_size) saver=tf.train.Saver() with tf.Session() as sess: srun = sess.run init = tf.global_variables_initializer() srun(init) for t in range(train_step): batch_x,batch_y=mnist.train.next_batch(batch_size) _cost_val,_ = srun([cost,opt],{x:batch_x,y:batch_y}) if(t%display_step==0): accuracy_val, cost_val = srun([accuracy,cost],{x:testx,y:testy}) print(t,cost_val,accuracy_val) saver.save(sess,'./2RNN/ckpt1/mnist1.ckpt',global_step=train_step)
0 2.531533 0.168 10 0.8894601 0.699 20 0.6328424 0.796 30 0.46291852 0.856 ... 970 0.022114469 0.992 980 0.03192995 0.99 990 0.021659942 0.988 1000 0.023274422 0.992
通过此次实战,我们把RNN结构改进成BiRNN结构,成功将准确率进一步提升。 表明,在合适的情况下,使用BiRNN较于普通的RNN会有一定效果的提升。
本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。
我来说两句