首頁  >  文章  >  後端開發  >  python中怎麼使用tensorflow建構長短時記憶LSTM

python中怎麼使用tensorflow建構長短時記憶LSTM

WBOY
WBOY轉載
2023-05-22 12:32:141334瀏覽

LSTM簡介

1、RNN的梯度消失問題

在過去的時間裡我們學習了RNN循環神經網絡,其結構示意圖是這樣的:

python中怎麼使用tensorflow建構長短時記憶LSTM

其存在的最大問題是,當w1、w2、w3這些值小於0時,如果一句話夠長,那麼其在神經網路進行反向傳播與前向傳播時,存在梯度消失的問題。

0.925=0.07,如果一句話有20到30個字,那麼第一個字的隱含層輸出傳遞到最後,將會變成原來的0.07倍,比起最後一個字的影響,大大降低。

其具體情況是這樣的:

python中怎麼使用tensorflow建構長短時記憶LSTM

長短時記憶網路就是為了解決梯度消失的問題出現的。

2、LSTM的結構

原始RNN的隱藏層只有一個狀態h,從頭傳遞到尾,它對於短期的輸入非常敏感。

如果我們再增加一個狀態c,讓它來保存長期的狀態,問題就可以解決了。

對於RNN和LSTM而言,其兩個step單元的對比如下。

python中怎麼使用tensorflow建構長短時記憶LSTM

我們把LSTM的結構按照時間維度展開:

python中怎麼使用tensorflow建構長短時記憶LSTM

我們可以看出,在n時刻,LSTM的輸入有三個:
 

1、當下時刻網路的輸入值;
 

2、上一刻LSTM的輸出值;
 

3、上​​一時刻的單元狀態。

LSTM的輸出有兩個:
 

1、此時LSTM輸出值;
 

2、當下時刻的單元狀態。

3、LSTM獨特的閘門結構

LSTM用兩個閘門來控制單元狀態cn的內容:
 

1、遺忘閘(forget gate),它決定了上一刻的單元狀態cn-1有多少保留到當下時刻;
 

2、輸入閘門(input gate),它決定了當前時刻網路的輸入c’n有多少保存到單元狀態。

LSTM用一個閘門來控制目前輸出值hn的內容:
 

輸出閘門(output gate),它決定了當前時刻單元狀態cn有多少輸出。

python中怎麼使用tensorflow建構長短時記憶LSTM

tensorflowLSTM的相關函數

tf.contrib.rnn.BasicLSTMCell

tf.contrib.rnn.BasicLSTMCell(
    num_units,
    forget_bias=1.0,
    state_is_tuple=True,
    activation=None,
    reuse=None,
    name=None,
    dtype=None
)

#num_units:RNN單元中的神經元數量,即輸出神經元數量。

forget_bias:偏移增加了忘記門。手動將恢復的CudnnLSTM訓練檢查點(checkpoint)設定為0.0。

state_is_tuple:如果為True,則接受和傳回的狀態是c_state和m_state的2-tuple;如果為False,則他們沿著列軸連接。 False即將棄用。

activation:激活函數。

reuse:描述是否在現有範圍中重複使用變數。如果現有範圍已經具有給定變數且不為True,則會引發錯誤。

name:圖層的名稱。

dtype:該層的資料型態。

使用時,可以定義為:

lstm_cell = tf.contrib.rnn.BasicLSTMCell(self.cell_size, forget_bias=1.0, state_is_tuple=True)

在定義完成後,可以進行狀態初始化:

self.cell_init_state = lstm_cell.zero_state(self.batch_size, dtype=tf.float32)

tf.nn.dynamic_rnn

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
)
  • cell:上文所定義的lstm_cell。

  • inputs:RNN輸入。如果time_major==false(預設),則必須是如下shape的tensor:[batch_size,max_time,…]或此類元素的嵌套元組。如果time_major==true,則必須是如下形狀的tensor:[max_time,batch_size,…]或此類元素的嵌套元組。

  • 向量的大小由 sequence_length 參數決定,其類型為 Int32/Int64。用於在超過批次元素的序列長度時複製通過狀態和零輸出。因此,它更多的是為了性能而不是正確性。

  • initial_state:上述定義的_init_state。

  • dtype:資料型態。

  • parallel_iterations:並行運行的迭代次數。那些不具有任何時間依賴性並且可以並行運行的操作將是。這個參數用時間來交換空間。較大的值會消耗更多的內存,但運算速度更快,而較小的值則使用較少的內存,但需要更長的計算時間。

  • time_major:输入和输出tensor的形状格式。这些张量的形状必须为[max_time, batch_size, depth],若表述正确,则它为真。这些张量的形状必须是[batch_size,max_time,depth],如果为假。time_major=true可以提高效率,因为它避免了在RNN计算的开头和结尾进行转置操作。默认情况下,此函数为False,因为大多数的 TensorFlow 数据以批处理主数据的形式存在。

  • scope:创建的子图的可变作用域;默认为“RNN”。

在LSTM的最后,需要用该函数得出结果。

self.cell_outputs, self.cell_final_state = tf.nn.dynamic_rnn(
	lstm_cell, self.l_in_y, initial_state=self.cell_init_state, time_major=False)

返回的是一个元组 (outputs, state):

outputs:LSTM的最后一层的输出,是一个tensor。如果为time_major== False,则它的shape为[batch_size,max_time,cell.output_size]。如果为time_major== True,则它的shape为[max_time,batch_size,cell.output_size]。

states:states是一个tensor。state是最终的状态,也就是序列中最后一个cell输出的状态。一般情况下states的形状为 [batch_size, cell.output_size],但当输入的cell为BasicLSTMCell时,states的形状为[2,batch_size, cell.output_size ],其中2也对应着LSTM中的cell state和hidden state。

整个LSTM的定义过程为:

    def add_input_layer(self,):
        #X最开始的形状为(256 batch,28 steps,28 inputs)
        #转化为(256 batch*28 steps,128 hidden)
        l_in_x = tf.reshape(self.xs, [-1, self.input_size], name='to_2D') 

        #获取Ws和Bs
        Ws_in = self._weight_variable([self.input_size, self.cell_size])
        bs_in = self._bias_variable([self.cell_size])

        #转化为(256 batch*28 steps,256 hidden) 
        with tf.name_scope('Wx_plus_b'):
            l_in_y = tf.matmul(l_in_x, Ws_in) + bs_in
        
        # (batch * n_steps, cell_size) ==> (batch, n_steps, cell_size)
        # (256*28,256)->(256,28,256)
        self.l_in_y = tf.reshape(l_in_y, [-1, self.n_steps, self.cell_size], name='to_3D')

    def add_cell(self):
        #神经元个数
        lstm_cell = tf.contrib.rnn.BasicLSTMCell(self.cell_size, forget_bias=1.0, state_is_tuple=True)

        #每一次传入的batch的大小
        with tf.name_scope('initial_state'):
            self.cell_init_state = lstm_cell.zero_state(self.batch_size, dtype=tf.float32)

        #不是主列
        self.cell_outputs, self.cell_final_state = tf.nn.dynamic_rnn(
            lstm_cell, self.l_in_y, initial_state=self.cell_init_state, time_major=False)
    
    def add_output_layer(self):
        #设置Ws,Bs
        Ws_out = self._weight_variable([self.cell_size, self.output_size])
        bs_out = self._bias_variable([self.output_size])
        # shape = (batch,output_size)
        # (256,10)
        with tf.name_scope('Wx_plus_b'):
            self.pred = tf.matmul(self.cell_final_state[-1], Ws_out) + bs_out

全部代码

该例子为手写体识别例子,将手写体的28行分别作为每一个step的输入,输入维度均为28列。

import tensorflow as tf 
from tensorflow.examples.tutorials.mnist import input_data
import numpy as np

mnist = input_data.read_data_sets("MNIST_data",one_hot = "true")

BATCH_SIZE = 256     # 每一个batch的数据数量
TIME_STEPS = 28      # 图像共28行,分为28个step进行传输
INPUT_SIZE = 28      # 图像共28列
OUTPUT_SIZE = 10     # 共10个输出
CELL_SIZE = 256      # RNN 的 hidden unit size,隐含层神经元的个数
LR = 1e-3            # learning rate,学习率

def get_batch():    #获取训练的batch
    batch_xs,batch_ys = mnist.train.next_batch(BATCH_SIZE)      
    batch_xs = batch_xs.reshape([BATCH_SIZE,TIME_STEPS,INPUT_SIZE])
    return [batch_xs,batch_ys]

class LSTMRNN(object):  #构建LSTM的类
    def __init__(self, n_steps, input_size, output_size, cell_size, batch_size):
        self.n_steps = n_steps 
        self.input_size = input_size
        self.output_size = output_size
        self.cell_size = cell_size
        self.batch_size = batch_size

        #输入输出
        with tf.name_scope('inputs'):
            self.xs = tf.placeholder(tf.float32, [None, n_steps, input_size], name='xs')
            self.ys = tf.placeholder(tf.float32, [None, output_size], name='ys')
        #直接加层
        with tf.variable_scope('in_hidden'):
            self.add_input_layer()
        #增加LSTM的cell
        with tf.variable_scope('LSTM_cell'):
            self.add_cell()
        #直接加层
        with tf.variable_scope('out_hidden'):
            self.add_output_layer()
        #计算损失值
        with tf.name_scope('cost'):
            self.compute_cost()
        #训练
        with tf.name_scope('train'):
            self.train_op = tf.train.AdamOptimizer(LR).minimize(self.cost)
        #正确率计算
        self.correct_pre = tf.equal(tf.argmax(self.ys,1),tf.argmax(self.pred,1))
        self.accuracy = tf.reduce_mean(tf.cast(self.correct_pre,tf.float32))

    def add_input_layer(self,):
        #X最开始的形状为(256 batch,28 steps,28 inputs)
        #转化为(256 batch*28 steps,128 hidden)
        l_in_x = tf.reshape(self.xs, [-1, self.input_size], name='to_2D') 

        #获取Ws和Bs
        Ws_in = self._weight_variable([self.input_size, self.cell_size])
        bs_in = self._bias_variable([self.cell_size])

        #转化为(256 batch*28 steps,256 hidden) 
        with tf.name_scope('Wx_plus_b'):
            l_in_y = tf.matmul(l_in_x, Ws_in) + bs_in
        
        # (batch * n_steps, cell_size) ==> (batch, n_steps, cell_size)
        # (256*28,256)->(256,28,256)
        self.l_in_y = tf.reshape(l_in_y, [-1, self.n_steps, self.cell_size], name='to_3D')

    def add_cell(self):
        #神经元个数
        lstm_cell = tf.contrib.rnn.BasicLSTMCell(self.cell_size, forget_bias=1.0, state_is_tuple=True)

        #每一次传入的batch的大小
        with tf.name_scope('initial_state'):
            self.cell_init_state = lstm_cell.zero_state(self.batch_size, dtype=tf.float32)

        #不是主列
        self.cell_outputs, self.cell_final_state = tf.nn.dynamic_rnn(
            lstm_cell, self.l_in_y, initial_state=self.cell_init_state, time_major=False)
    
    def add_output_layer(self):
        #设置Ws,Bs
        Ws_out = self._weight_variable([self.cell_size, self.output_size])
        bs_out = self._bias_variable([self.output_size])
        # shape = (batch,output_size)
        # (256,10)
        with tf.name_scope('Wx_plus_b'):
            self.pred = tf.matmul(self.cell_final_state[-1], Ws_out) + bs_out

    def compute_cost(self):
        self.cost =  tf.reduce_mean(
            tf.nn.softmax_cross_entropy_with_logits(logits = self.pred,labels = self.ys)
            )

    def _weight_variable(self, shape, name='weights'):
        initializer = np.random.normal(0.0,1.0 ,size=shape)
        return tf.Variable(initializer, name=name,dtype = tf.float32)

    def _bias_variable(self, shape, name='biases'):
        initializer = np.ones(shape=shape)*0.1
        return tf.Variable(initializer, name=name,dtype = tf.float32)


if __name__ == '__main__':
    #搭建 LSTMRNN 模型
    model = LSTMRNN(TIME_STEPS, INPUT_SIZE, OUTPUT_SIZE, CELL_SIZE, BATCH_SIZE)
    sess = tf.Session()

    sess.run(tf.global_variables_initializer())
    
    #训练10000次
    for i in range(10000):
        xs, ys = get_batch()  #提取 batch data
        if i == 0:
        #初始化data
            feed_dict = {
                    model.xs: xs,
                    model.ys: ys,
            }
        else:
            feed_dict = {
                model.xs: xs,
                model.ys: ys,
                model.cell_init_state: state    #保持 state 的连续性
            }
        
        #训练
        _, cost, state, pred = sess.run(
            [model.train_op, model.cost, model.cell_final_state, model.pred],
            feed_dict=feed_dict)
        
        #打印精确度结果
        if i % 20 == 0:
            print(sess.run(model.accuracy,feed_dict = {
                    model.xs: xs,
                    model.ys: ys,
                    model.cell_init_state: state    #保持 state 的连续性
            }))

以上是python中怎麼使用tensorflow建構長短時記憶LSTM的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:yisu.com。如有侵權,請聯絡admin@php.cn刪除