欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Tensorflow学习笔记(四)

程序员文章站 2024-01-22 11:19:58
...

RNN手写数字识别

一:RNN概述

RNN是一类用于处理序列数据的神经网络。序列数据,即后面的数据与前面的数据有关系。

二:标准RNN的前向传播过程

Tensorflow学习笔记(四)
X是输入,h是隐藏层,o是输出,L是损失函数,y是训练集对应的标签。
这些元素右上角带的t代表t时刻的状态,其中需要注意的是,单元h在t时刻的表现不仅由此刻的输入决定,还受t时刻之前时刻的影响。V、W、U是权值,同一类型的权连接权值相同。
前向传播算法公式(对于t时刻)
Tensorflow学习笔记(四)
其中 Tensorflow学习笔记(四)为**函数,一般来说会选择tanh函数,b为偏置。
t时刻的输出:
Tensorflow学习笔记(四)
最终模型的预测输出:
Tensorflow学习笔记(四)
其中σ()为**函数,通常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的结构如下图。不同于 单一神经网络层,这里是有四个,以一种非常特殊的方式进行交互。
Tensorflow学习笔记(四)
(2)LSTM的核心思想
LSTM 的关键就是细胞状态,水平线在图上方贯穿运行。

细胞状态类似于传送带。直接在整个链上运行,只有一些少量的线性交互。信息在上面流传保持不变会很容易。如下图。
Tensorflow学习笔记(四)
LSTM 有通过精心设计的称作为“门”的结构来去除或者增加信息到细胞状态的能力。门是一种让信息选择式通过的方法。他们包含一个 sigmoid 神经网络层和一个按位的乘法操作。Sigmoid 层输出 0到1之间的数值,描述每个部分有多少量可以通过。0代表“不许任何量通过”,1就指“允许任意量通过”!

LSTM 拥有三个门,来保护和控制细胞状态。

(3)LSTM的步骤

  1. 决定我们会从细胞状态中丢弃什么信息,结果用ft表示。这个决定通过一个称为忘记门层完成。该门会读取 ht-1 和 xt,输出一个在 0 到 1 之间的数值给每个在细胞状态 Ct-1中的数字。1 表示“完全保留”,0 表示“完全舍弃”。
    Tensorflow学习笔记(四)
  2. 确定什么样的新信息被存放在细胞状态中。这里包含两个部分。第一,sigmoid层被称为“输入门层”决定什么值我们将要更新,用it表示。然后,一个tanh层创建一个新的候选值向量,Ct*,会被加入到状态中。
    Tensorflow学习笔记(四)
  3. 更新旧细胞状态,Ct-1更新为Ct。前两步已决定我们要抛弃的、要保留的信息。把旧状态与 Ct-1相乘,丢弃掉我们确定需要丢弃的信息。接着加上itCt.
    Tensorflow学习笔记(四)
  4. 确定输出值。首先我们运行一个sigmoid层来确定细胞状态的哪个部分将输出出去,用ot表示。接着,我们把细胞状态通过tanh处理(得到一个在0到1之间的值)并将他和sigmoid门的输出相乘,最终仅仅会输出我们确定输出的那部分。
    Tensorflow学习笔记(四)

五: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

六:函数及方法

  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,表示返回的状态用元祖表示。

  2. zero_state(batch_size,dtype):为上述BasicLSTMCell中state_is_tuple的初始化状态函数,batch_size:输入样本批次的数目。

  3. 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 循环神经网络(分类例子)