Tensorflow学习笔记(四)
RNN手写数字识别
一:RNN概述
RNN是一类用于处理序列数据的神经网络。序列数据,即后面的数据与前面的数据有关系。
二:标准RNN的前向传播过程
X是输入,h是隐藏层,o是输出,L是损失函数,y是训练集对应的标签。
这些元素右上角带的t代表t时刻的状态,其中需要注意的是,单元h在t时刻的表现不仅由此刻的输入决定,还受t时刻之前时刻的影响。V、W、U是权值,同一类型的权连接权值相同。
前向传播算法公式(对于t时刻):
其中 为**函数,一般来说会选择tanh函数,b为偏置。
t时刻的输出:
最终模型的预测输出:
其中σ()为**函数,通常RNN用于分类,故这里一般用softmax函数。
三:RNN的训练方法——BPTT
BPTT(back-propagation through time)算法是常用的训练RNN的方法,其实本质还是BP算法,只不过RNN处理时间序列数据,所以要基于时间反向传播,故叫随时间反向传播。BPTT的中心思想和BP算法相同,沿着需要优化的参数的负梯度方向不断寻找更优的点直至收敛。综上所述,BPTT算法本质还是BP算法,BPTT算法本质还是梯度下降法,那么求各个参数的梯度便成了此算法的核心。
由于选择的**函数sigmoid 导数范围为(0,0.25]和tanh的导数范围为(0,1],都小于1,所以随着神经网络层数的增加,会导致“梯度消失”。下面介绍LSTM长短期记忆网络,其一定程度上解决了梯度消失问题。
四:LSTM(Long short-term memory)
长短期记忆网络是RNN的一种变体,RNN由于梯度消失的原因只能有短期记忆,LSTM网络通过精妙的门控制将短期记忆与长期记忆结合起来,并且一定程度上解决了梯度消失的问题。
(1)长期依赖(Long-Term Dependencies)问题
RNN 的关键点之一就是他们可以用来连接先前的信息到当前的任务上,例如使用过去的视频段来推测对当前段的理解。
但是同样会有一些更加复杂的场景。假设我们试着去预测“I grew up in France… I speak fluent French”最后的词。当前的信息建议下一个词可能是一种语言的名字,但是如果我们需要弄清楚是什么语言,我们是需要先前提到的离当前位置很远的 France 的上下文的。这说明相关信息和当前预测位置之间的间隔就肯定变得相当的大。
不幸的是,在这个间隔不断增大时,RNN 会丧失学习到连接如此远的信息的能力。
LSTM就没有这个问题,可以学习长期依赖。对以前学习的内容进行选择抛弃,对当前学习的内容进行选择学习。从而克服短期记忆。
LSTM的结构如下图。不同于 单一神经网络层,这里是有四个,以一种非常特殊的方式进行交互。
(2)LSTM的核心思想
LSTM 的关键就是细胞状态,水平线在图上方贯穿运行。
细胞状态类似于传送带。直接在整个链上运行,只有一些少量的线性交互。信息在上面流传保持不变会很容易。如下图。
LSTM 有通过精心设计的称作为“门”的结构来去除或者增加信息到细胞状态的能力。门是一种让信息选择式通过的方法。他们包含一个 sigmoid 神经网络层和一个按位的乘法操作。Sigmoid 层输出 0到1之间的数值,描述每个部分有多少量可以通过。0代表“不许任何量通过”,1就指“允许任意量通过”!
LSTM 拥有三个门,来保护和控制细胞状态。
(3)LSTM的步骤
- 决定我们会从细胞状态中丢弃什么信息,结果用ft表示。这个决定通过一个称为忘记门层完成。该门会读取 ht-1 和 xt,输出一个在 0 到 1 之间的数值给每个在细胞状态 Ct-1中的数字。1 表示“完全保留”,0 表示“完全舍弃”。
- 确定什么样的新信息被存放在细胞状态中。这里包含两个部分。第一,sigmoid层被称为“输入门层”决定什么值我们将要更新,用it表示。然后,一个tanh层创建一个新的候选值向量,Ct*,会被加入到状态中。
- 更新旧细胞状态,Ct-1更新为Ct。前两步已决定我们要抛弃的、要保留的信息。把旧状态与 Ct-1相乘,丢弃掉我们确定需要丢弃的信息。接着加上itCt.
- 确定输出值。首先我们运行一个sigmoid层来确定细胞状态的哪个部分将输出出去,用ot表示。接着,我们把细胞状态通过tanh处理(得到一个在0到1之间的值)并将他和sigmoid门的输出相乘,最终仅仅会输出我们确定输出的那部分。
五:RNN手写数字识别实例
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
# load data
mnist=input_data.read_data_sets('数据集位置',one_hot=True)
lr=0.001
training_iters=100000 #循环次数
batch_size=128
n_inputs=28 #MNIST data input(img shape:28*28)
n_steps=28
n_hidden_units=128 #neurons in hidden layer
n_classes=10 #MINST classes(0-9)
#tf Graph input
x=tf.placeholder(tf.float32,[None,n_steps,n_inputs])
y=tf.placeholder(tf.float32,[None,n_classes])
#define weights
weights={
#(28,128)
'in':tf.Variable(tf.random_normal([n_inputs,n_hidden_units])),
#(128,10)
'out':tf.Variable(tf.random_normal([n_hidden_units,n_classes]))
}
biases={
#(128,)
'in':tf.Variable(tf.constant(0.1,shape=[n_hidden_units,])),
#(10,)
"out":tf.Variable(tf.constant(0.1,shape=[n_classes,]))
}
def RNN(X,weights,biases):
#hidden layer for input to cell
############################################
#X(128 batch,28 steps,28 inputs)-->(128*28,28 inputs)
X=tf.reshape(X,[-1,n_inputs])
#X_in:(128 batch* 28 steps,128 hidden)
X_in=tf.matmul(X,weights['in'])+biases['in']
#X_in -->(128 batch, 28 steps, 128 hidden)
X_in=tf.reshape(X_in,[-1,n_steps,n_hidden_units])
#cell
#############################################
lstm_cell=tf.nn.rnn_cell.BasicLSTMCell(n_hidden_units,forget_bias=1.0,state_is_tuple=True)
#lstm cell is divided into two parts(c_state,m_state)
_init_state=lstm_cell.zero_state(batch_size,dtype=tf.float32)
#time_major如果是True,output的维度是[steps, batch_size, depth],
#如果是False就是[batch_size, steps, depth]。就是和输入是一样的
outputs,states=tf.nn.dynamic_rnn(lstm_cell,X_in,initial_state=_init_state,time_major=False)
#hidden layer for output as the final results
##############################################
results=tf.matmul(states[1],weights['out'])+biases['out']
# # or
# # unpack to list[(batch,outputs)..]*steps
# outputs=tf.unpck(tf.transpose(outputs,[1,0,2])) #states is the outputs
# results=tf.matmul(outputs[-1],weights['out'])+biases['out']
return results
pred=RNN(x,weights,biases)
cost=tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=pred,labels=y))
train_op=tf.train.AdamOptimizer(lr).minimize(cost)
correct_pred=tf.equal(tf.argmax(pred,1),tf.argmax(y,1))
accuracy=tf.reduce_mean(tf.cast(correct_pred,tf.float32))
init=tf.initialize_all_variables()
with tf.Session() as sess:
sess.run(init)
step=0
while step*batch_size<training_iters:
batch_xs,batch_ys=mnist.train.next_batch(batch_size)
batch_xs=batch_xs.reshape([batch_size,n_steps,n_inputs])
sess.run([train_op],feed_dict={
x:batch_xs,
y:batch_ys,
})
if step%20==0:
print(sess.run(accuracy,feed_dict={
x:batch_xs,
y:batch_ys,
}))
step+=1
六:函数及方法
-
tf.nn.rnn_cell.BasicLSTMCell(n_hidden, forget_bias=1.0, state_is_tuple=True):
n_hidden:神经元个数。forget_bias:忘记系数,若为1则不会忘记任何信息;若为0则都忘记。State_is_tuple:默认为true,表示返回的状态用元祖表示。 -
zero_state(batch_size,dtype):为上述BasicLSTMCell中state_is_tuple的初始化状态函数,batch_size:输入样本批次的数目。
-
tf.nn.dynamic_rnn(cell,inputs,sequence_length,initial_state,dtype,parallel_state,swap_memory,time_major,scope):
cell:RNN cell的一个实例
inputs:RNN的输入
time_major:若是True,output的维度为[steps,batch_size,depth];若是False,则维度为[batch_size,steps,depth]
sequence_length: (可选)大小为[batch_size],数据的类型是int32/int64向量。如果当前时间步的index超过该序列的实际长度时,则该时间步不进行计算,RNN的state复制上一个时间步的,同时该时间步的输出全部为零
initial_state: (可选)RNN的初始state(状态)。如果cell.state_size(一层的RNNCell)是一个整数,那么它必须是一个具有适当类型和形状的张量[batch_size,cell.state_size]。
参考文献资料
1.理解LSTM网络
2.RNN
3.RNN LSTM 循环神经网络(分类例子)