tensorflow(七)——基於RNN、LSTM進行正弦函數sin預測

一、基礎知識

RNN:存儲了隱藏層的輸出作爲下一次的輸入,網絡具有時序信息

雙向RNN:正向反向傳遞上一層的記憶,組合形成輸出

從RNN到LSTM:RNN存在梯度消失,梯度爆炸的現象,所以對記憶體的存儲更新做了修改,原來RNN是無限制更新記憶體的值,而LSTM對記憶體的存入,取出以及保存都通過門來限制。

梯度消失、梯度爆炸:是由反向傳播鏈式求導法則中的連乘導致的,導數\權重初始化\網絡深度\不恰當的非線性方法等因素一疊加,就會導致靠近輸入層的地方發生梯度消失、梯度爆炸的問題

https://blog.csdn.net/raojunyang/article/details/79962665

https://blog.csdn.net/sinat_32502811/article/details/82716426

LSTM:有三個門,輸入門、輸出門、遺忘門,所用的激活函數多爲sigmoid(輸出在0到1之間,符合門的性質)

中間藍色的c爲記憶體,輸入門控制輸入響應f(Zi),可使輸入無效;遺忘門控制記憶體c,可使之前的記憶無效,輸出門控制記憶體的響應,可使輸出無效。

二、應用場景

    文本自動生成(寫詩、寫歌詞),客服機器人

文本自動生成機器人

參考理解鏈接:https://blog.csdn.net/irving_zhang/article/details/76664998

工程代碼:https://github.com/jinfagang/tensorflow_poems

 

三、LSTM實例說明

本例來源及更多LSTM的簡單示例及函數說明,詳見:https://blog.csdn.net/xierhacker/article/details/78772560

本例取了一個sin函數的y點,利用前幾個點來預測後一個點的值,幾個點間具有時序的聯繫。建立的網絡是兩層LSTM。

有意思的是,從自己展開RNN代碼來看,輸入是按照序列一個個輸入的,不是一下子全輸進去((cell_output, state) = multi_lstm(X_p[:, timestep, :], state))。與全連接網絡及cnn不同,lstm的輸入是一個batch內一個個按照序列輸入的(例如輸入x1、h0得到h1)。

下圖一展示了多次迭代中測試結果,下圖二是進行50次迭代後的結果,50次後已能基本擬合。

網絡有兩個隱藏層,從輸入到輸出的大小爲:

【(None,Time_steps,1),30,1,(None,1)】

 

    

import numpy as np
import tensorflow as tf
import tensorflow.contrib.rnn as rnn
import matplotlib.pyplot as plt

TIME_STEPS=10
BATCH_SIZE=128
HIDDEN_UNITS1=30
HIDDEN_UNITS=1
LEARNING_RATE=0.001
EPOCH=50

TRAIN_EXAMPLES=11000
TEST_EXAMPLES=1100

#------------------------------------Generate Data-----------------------------------------------#
#generate data
#數據的生成先利用linspace生成等分割點,再根據sin函數得到弦值,每個batch都是訓練數據爲前TIME_STEPS個數,標籤爲後一個數,也就是用前幾個數預測後一個數據
#訓練數據和測試數據的linespace分別取了[0,100],[100,110],這樣就不同了
def generate(seq):
    X=[]
    y=[]
    for i in range(len(seq)-TIME_STEPS):
        X.append([seq[i:i+TIME_STEPS]])
        y.append([seq[i+TIME_STEPS]])
    return np.array(X,dtype=np.float32),np.array(y,dtype=np.float32)


seq_train=np.sin(np.linspace(start=0,stop=100,num=TRAIN_EXAMPLES,dtype=np.float32))
seq_test=np.sin(np.linspace(start=100,stop=110,num=TEST_EXAMPLES,dtype=np.float32))


X_train,y_train=generate(seq_train)
#print(X_train.shape,y_train.shape)
X_test,y_test=generate(seq_test)#X_test是前TIME_STEPS個數據,y_test是後一個數據

#reshape to (batch,time_steps,input_size)
X_train=np.reshape(X_train,newshape=(-1,TIME_STEPS,1))#這裏的作用是增加最後一個維度
X_test=np.reshape(X_test,newshape=(-1,TIME_STEPS,1))

#draw y_test
plt.plot(range(1000),y_test[:1000,0],"r*")

#-----------------------------------------------------------------------------------------------------#


#--------------------------------------Define Graph---------------------------------------------------#
graph=tf.Graph()
with graph.as_default():

    #------------------------------------construct LSTM------------------------------------------#
    #place hoder
    X_p=tf.placeholder(dtype=tf.float32,shape=(None,TIME_STEPS,1),name="input_placeholder")
    y_p=tf.placeholder(dtype=tf.float32,shape=(None,1),name="pred_placeholder")

    #lstm instance
    lstm_cell1=rnn.BasicLSTMCell(num_units=HIDDEN_UNITS1)#30
    lstm_cell=rnn.BasicLSTMCell(num_units=HIDDEN_UNITS)#1

    multi_lstm=rnn.MultiRNNCell(cells=[lstm_cell1,lstm_cell])
    ## 初始狀態,可以理解爲初始記憶

    init_state = multi_lstm.zero_state(batch_size=BATCH_SIZE, dtype=tf.float32)

    # 使用dynamic rnn通過指定的RNN Cell來展開計算神經網絡
    outputs, states = tf.nn.dynamic_rnn(cell=multi_lstm, inputs=X_p, initial_state=init_state, dtype=tf.float32)
    # print(outputs.shape)#(128,10,1)
    h = outputs[:, -1, :]


    # #自己展開RNN計算
    # outputs = list()                                    #用來接收存儲每步的結果
    # state = init_state
    # with tf.variable_scope('RNN'):
    #     for timestep in range(TIME_STEPS):#TIME_STEPS爲一個batch訓練數據數量,這裏的序列是一個個輸入的
    #         if timestep > 0:
    #             tf.get_variable_scope().reuse_variables()#timestep=0首次輸入,>0爲後續輸入
    #         # 這裏的state保存了每一層 LSTM 的狀態
    #         (cell_output, state) = multi_lstm(X_p[:, timestep, :], state)######網絡輸入輸出
    #         outputs.append(cell_output)
    # h = outputs[-1]#取了最後的輸出作爲輸出


    #---------------------------------define loss and optimizer----------------------------------#
    mse=tf.losses.mean_squared_error(labels=y_p,predictions=h)#均方誤差
    #print(loss.shape)
    optimizer=tf.train.AdamOptimizer(LEARNING_RATE).minimize(loss=mse)

    init=tf.global_variables_initializer()


#-------------------------------------------Define Session---------------------------------------#
with tf.Session(graph=graph) as sess:
    sess.run(init)
    for epoch in range(1,EPOCH+1):#迭代次數
        results = np.zeros(shape=(TEST_EXAMPLES, 1))
        train_losses=[]
        test_losses=[]
        print("epoch:",epoch)
        for j in range(TRAIN_EXAMPLES//BATCH_SIZE):#訓練數據是根據batch_size劃分成了幾塊
            _,train_loss=sess.run(
                    fetches=(optimizer,mse),#這裏通過運行optimizer進行train,測試時不進行優化就是測試了
                    feed_dict={
                            X_p:X_train[j*BATCH_SIZE:(j+1)*BATCH_SIZE],
                            y_p:y_train[j*BATCH_SIZE:(j+1)*BATCH_SIZE]
                        }
            )
            train_losses.append(train_loss)#train_losses記錄了單次迭代中,每次batch的損失
        print("average training loss:", sum(train_losses) / len(train_losses))


        for j in range(TEST_EXAMPLES//BATCH_SIZE):#測試是在單次迭代後進行的,可以比較多次迭代後的效果
            result,test_loss=sess.run(
                    fetches=(h,mse),#有別於訓練時運行fetches=(optimizer,mse)
                    feed_dict={
                            X_p:X_test[j*BATCH_SIZE:(j+1)*BATCH_SIZE],
                            y_p:y_test[j*BATCH_SIZE:(j+1)*BATCH_SIZE]
                        }
            )
            results[j*BATCH_SIZE:(j+1)*BATCH_SIZE]=result
            test_losses.append(test_loss)
        print("average test loss:", sum(test_losses) / len(test_losses))
    plt.plot(range(1000),results[:1000,0])#利用前1k個點作圖 ,這句放到for循環裏就可以看出優化過程了
    plt.show()

、RNN實例說明

    本部分基於第三部分的代碼實現了基於RNN預測sin曲線,只需要將lstm核換成rnn核,即替換成以下的代碼。肉眼未見測試結果圖有何區別。

    #place hoder
    X_p=tf.placeholder(dtype=tf.float32,shape=(None,TIME_STEPS,1),name="input_placeholder")
    y_p=tf.placeholder(dtype=tf.float32,shape=(None,1),name="pred_placeholder")

    # #lstm instance
    # lstm_cell1=rnn.BasicLSTMCell(num_units=HIDDEN_UNITS1)#30
    # lstm_cell=rnn.BasicLSTMCell(num_units=HIDDEN_UNITS)#1
    # multi_lstm=rnn.MultiRNNCell(cells=[lstm_cell1,lstm_cell])
    # #rnn instance
    cell1 = tf.nn.rnn_cell.BasicRNNCell(num_units=HIDDEN_UNITS1)
    cell2=tf.nn.rnn_cell.BasicRNNCell(num_units=HIDDEN_UNITS)
    multi_RNN = rnn.MultiRNNCell(cells=[cell1, cell2])
    
    init_state = multi_RNN.zero_state(batch_size=BATCH_SIZE, dtype=tf.float32)

    # 使用dynamic rnn通過指定的RNN Cell來展開計算神經網絡
    outputs, states = tf.nn.dynamic_rnn(cell=multi_RNN, inputs=X_p, initial_state=init_state, dtype=tf.float32)
    # print(outputs.shape)#(128,10,1)
    h = outputs[:, -1, :]


五、機器翻譯

    端到端建立源語言到目標語言的對應關係,使用序列到序列的模型,聯合了兩個循環神經網絡:一個網絡接收要源句子,一個輸出成翻譯的語句。即編解碼過程,編碼過程利用RNN的記憶功能,保留最後一個隱藏狀態;解碼器接收一個標識符作爲一句話的開始,輸入網絡得到的輸出作爲第一個詞,輸入第一個詞得到第二個詞。。。編碼器獲得最後一個隱藏狀態作爲內容向量供解碼器使用。

使用循環神經網絡的原因:語句存在序列前後關係

使用序列到序列結構的原因:輸入長度與輸出長度可以不同;詞與詞見的前後關係可以顛倒;

參考網址:

https://blog.csdn.net/xierhacker/article/details/73384760

https://blog.csdn.net/xierhacker/article/details/78772560

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章