<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    Python人工智能 | 十二.循環神經網絡RNN和LSTM原理詳解及TensorFlow分類案例

    VSole2022-01-17 14:57:48

    一.循環神經網絡

    在編寫代碼之前,我們需要介紹什么是RNN,RNN是怎樣運行的以及RNN的結構。

    1.RNN原理

    循環神經網絡英文是Recurrent Neural Networks,簡稱RNN。假設有一組數據data0、data1、data2、data3,使用同一個神經網絡預測它們,得到對應的結果。如果數據之間是有關系的,比如做菜下料的前后步驟,英文單詞的順序,如何讓數據之間的關聯也被神經網絡學習呢?這就要用到——RNN。

    假設存在ABCD數字,需要預測下一個數字E,會根據前面ABCD順序進行預測,這就稱為記憶。預測之前,需要回顧以前的記憶有哪些,再加上這一步新的記憶點,最終輸出output,循環神經網絡(RNN)就利用了這樣的原理。

    首先,讓我們想想人類是怎么分析事物之間的關聯或順序的。人類通常記住之前發生的事情,從而幫助我們后續的行為判斷,那么是否能讓計算機也記住之前發生的事情呢?

    在分析data0時,我們把分析結果存入記憶Memory中,然后當分析data1時,神經網絡(NN)會產生新的記憶,但此時新的記憶和老的記憶沒有關聯,如上圖所示。在RNN中,我們會簡單的把老記憶調用過來分析新記憶,如果繼續分析更多的數據時,NN就會把之前的記憶全部累積起來。

    RNN結構如下圖所示,按照時間點t-1、t、t+1,每個時刻有不同的x,每次計算會考慮上一步的state和這一步的x(t),再輸出y值。在該數學形式中,每次RNN運行完之后都會產生s(t),當RNN要分析x(t+1)時,此刻的y(t+1)是由s(t)和s(t+1)共同創造的,s(t)可看作上一步的記憶。多個神經網絡NN的累積就轉換成了循環神經網絡,其簡化圖如下圖的左邊所示。

    總之,只要你的數據是有順序的,就可以使用RNN,比如人類說話的順序,電話號碼的順序,圖像像素排列的順序,ABC字母的順序等。在前面講解CNN原理時,它可以看做是一個濾波器滑動掃描整幅圖像,通過卷積加深神經網絡對圖像的理解。

    而RNN也有同樣的掃描效果,只不過是增加了時間順序和記憶功能。RNN通過隱藏層周期性的連接,從而捕獲序列化數據中的動態信息,提升預測結果。


    2.RNN應用

    RNN常用于自然語言處理、機器翻譯、語音識別、圖像識別等領域,下面簡單分享RNN相關應用所對應的結構。

    RNN情感分析: 當分析一個人說話情感是積極的還是消極的,就用如下圖所示的RNN結構,它有N個輸入,1個輸出,最后時間點的Y值代表最終的輸出結果。

    RNN圖像識別: 此時有一張圖片輸入X,N張對應的輸出。

    RNN機器翻譯: 輸入和輸出分別兩個,對應的是中文和英文,如下圖所示。

    二.LSTM RNN原理詳解

    接下來我們看一個更強大的結構,稱為LSTM。

    1.為什么引入LSTM

    RNN是在有序的數據上進行學習的,RNN會像人一樣對先前的數據發生記憶,但有時候也會像老爺爺一樣忘記先前所說。為了解決RNN的這個弊端,提出了LTSM技術,它的英文全稱是Long short-term memory,長短期記憶,也是當下最流行的RNN之一。

    假設現在有一句話,如下圖所示,RNN判斷這句話是紅燒排骨,這時需要學習,而“紅燒排骨“在句子開頭。

    "紅燒排骨"這個詞需要經過長途跋涉才能抵達,要經過一系列得到誤差,然后經過反向傳遞,它在每一步都會乘以一個權重w參數。如果乘以的權重是小于1的數,比如0.9,0.9會不斷地乘以誤差,最終這個值傳遞到初始值時,誤差就消失了,這稱為梯度消失或梯度離散。

    反之,如果誤差是一個很大的數,比如1.1,則這個RNN得到的值會很大,這稱為梯度爆炸。

    梯度消失或梯度爆炸:
    在RNN中,如果你的State是一個很長的序列,假設反向傳遞的誤差值是一個小于1的數,每次反向傳遞都會乘以這個數,0.9的n次方趨向于0,1.1的n次方趨向于無窮大,這就會造成梯度消失或梯度爆炸。

    這也是RNN沒有恢復記憶的原因,為了解決RNN梯度下降時遇到的梯度消失或梯度爆炸問題,引入了LSTM。


    2.LSTM

    LSTM是在普通的RNN上面做了一些改進,LSTM RNN多了三個控制器,即輸入、輸出、忘記控制器。左邊多了個條主線,例如電影的主線劇情,而原本的RNN體系變成了分線劇情,并且三個控制器都在分線上。

    • 輸入控制器(write gate): 在輸入input時設置一個gate,gate的作用是判斷要不要寫入這個input到我們的內存Memory中,它相當于一個參數,也是可以被訓練的,這個參數就是用來控制要不要記住當下這個點。
    • 輸出控制器(read gate): 在輸出位置的gate,判斷要不要讀取現在的Memory。
    • 忘記控制器(forget gate): 處理位置的忘記控制器,判斷要不要忘記之前的Memory。


    LSTM工作原理為:如果分線劇情對于最終結果十分重要,輸入控制器會將這個分線劇情按重要程度寫入主線劇情,再進行分析;如果分線劇情改變了我們之前的想法,那么忘記控制器會將某些主線劇情忘記,然后按比例替換新劇情,所以主線劇情的更新就取決于輸入和忘記控制;最后的輸出會基于主線劇情和分線劇情。

    通過這三個gate能夠很好地控制我們的RNN,基于這些控制機制,LSTM是延緩記憶的良藥,從而帶來更好的結果。

    三.Tensorflow編寫RNN代碼

    接下來我們通過手寫數字圖片集數據編寫RNN代碼。RNN是基于順序的數據,想象下圖片的順序,它是一行一行像素組成的,最終判定圖片的數字屬于哪類。

    第一步,打開Anaconda,然后選擇已經搭建好的“tensorflow”環境,運行Spyder。

    第二步,導入擴展包。

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

    第三步,下載數據集。

    由于MNIST數據集是TensorFlow的示例數據,所以我們只需要下面一行代碼,即可實現數據集的讀取工作。如果數據集不存在它會在線下載,如果數據集已經被下載,它會被直接調用。

    # 下載手寫數字圖像數據集
    mnist = input_data.read_data_sets('MNIST_data', one_hot=True)
    

    第四步,定義參數。

    # 設置參數
    learning_rate = 0.001     # 學習效率
    train_iters = 100000      # 訓練次數
    batch_size = 128          # 自定義
    n_inputs = 28             # MNIST 輸入圖像形狀 28*28 黑白圖片高度為1
    n_steps = 28              # time steps 輸入圖像的28行數據
    n_hidden_units = 128      # 神經網絡隱藏層數量
    n_classes = 10            # 分類結果 數字0-0
    

    第五步,定義placeholder,用于傳入值xs和ys至神經網絡。

    # 設置傳入的值xs和ys
    x = tf.placeholder(tf.float32, [None, n_steps, n_inputs])  #每張圖片28*28=784個點
    y = tf.placeholder(tf.float32, [None, n_classes])          #每個樣本有10個輸出
    

    第六步,定義權重和誤差變量。

    權重和偏置包括輸入和輸出值,需要注意其設置的形狀。

    # 定義權重 進入RNN前的隱藏層 輸入&輸出
    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])),
    }
    # 定義偏置 進入RNN前的隱藏層 輸入&輸出
    biases = {
        # (128, )
        'in': tf.Variable(tf.constant(0.1, shape=[n_hidden_units, ])),
        # (10, )
        'out': tf.Variable(tf.constant(0.1, shape=[n_classes, ])),
    }
    

    第七步,定義RNN神經網絡。

    RNN定義分別對應三層,X輸入、Cell為中心計算、H為最終輸出,需要注意數據形狀的變化。在RNN運算過程中,每一步的輸出都存儲在outputs序列中,LSTM包括c_state(主線)和m_state(分線)。最終輸出結果為Cell的輸出和權重輸出的乘積,再加上輸出偏置。(詳見注釋)

    #---------------------------------定義RNN-------------------------------
    def RNN(X, weights, biases):
        # hidden layer for input to cell
        #######################################################
        # X (128 batch, 28 steps, 28 inputs) 28行*28列 
        # X ==> (128*28, 28 inputs)
        X = tf.reshape(X, [-1, n_inputs])
        # 隱藏層 輸入
        # X_in ==> (128batch*28steps, 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]) # 128個隱藏層
        
        # cell
        #######################################################
        # Cell結構 隱藏層數 forget初始偏置為1.0(初始時不希望forget)
        lstm_cell = tf.nn.rnn_cell.BasicLSTMCell(n_hidden_units, forget_bias=1.0, state_is_tuple=True)
        # RNN會保留每一步計算的結果state
        # lstm cell is divided into two parts (c_state, m_state) 主線c_state 分線m_state
        _init_state = lstm_cell.zero_state(batch_size, dtype=tf.float32)
        # RNN運算過程 每一步的輸出都存儲在outputs序列中
        # 常規RNN只有m_state LSTM包括c_state和m_state
        outputs, states = tf.nn.dynamic_rnn(lstm_cell, X_in, initial_state=_init_state, time_major=False)
        
        # hidden layer for output as final results
        #######################################################
        # 第三層加工最終的輸出
        # 最終輸出=Cell的輸出*權重輸出+偏置數據
        # states包含了主線劇情和分線劇情 states[1]表示分線劇情的結果 即為outputs[-1]最后一個輸出結果
        results = tf.matmul(states[1], weights['out']) + biases['out']
        
        # 第二種方法
        # 解包 unpack to list [(batch, outputs)..] * steps
        #outputs = tf.unstack(tf.transpose(outputs, [1,0,2])) # states is the last outputs
        #results = tf.matmul(outputs[-1], weights['out']) + biases['out']
        return results
    

    第八步,定義誤差和準確度。

    #---------------------------------定義誤差和訓練-------------------------------
    pre = RNN(x, weights, biases)
    # 預測值與真實值誤差
    cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=pre, labels=y))
    # 訓練學習 學習效率設置為0.001
    train_step = tf.train.AdamOptimizer(learning_rate).minimize(cost) #梯度下降減小誤差
    # 預測正確個數
    correct_pred = tf.equal(tf.argmax(pre, 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
        # 循環每次提取128個樣本
        while step * batch_size < train_iters:
            # 從下載好的數據集提取128個樣本
            batch_xs, batch_ys = mnist.train.next_batch(batch_size)
            # 形狀修改 [128, 28, 28]
            batch_xs = batch_xs.reshape([batch_size, n_steps, n_inputs])
            # 訓練
            sess.run([train_step], feed_dict={
                x: batch_xs,
                y: batch_ys,
            })
            # 每隔20步輸出結果
            if step % 20 == 0: # 20*128
                print(sess.run(accuracy, feed_dict={
                    x: batch_xs,
                    y: batch_ys,
                }))
            step += 1
    

    最終輸出結果如下所示,可以看到,最早預測的準確度結果非常低為2.187%,最后提升到了96.87%,其結果高于之前的一般神經網絡的結果87.79%(第六篇博客),由此可見TensorFlow RNN的分類學習效果還不錯,并且在不斷學習中。

    Extracting MNIST_data\train-images-idx3-ubyte.gz
    Extracting MNIST_data\train-labels-idx1-ubyte.gz
    Extracting MNIST_data\t10k-images-idx3-ubyte.gz
    Extracting MNIST_data\t10k-labels-idx1-ubyte.gz
    0.2187500
    0.6796875
    0.8281250
    0.8203125
    0.8359375
    0.8984375
    0.8828125
    0.8359375
    0.9062500
    ....
    0.9843750
    0.9609375
    0.9453125
    0.9609375
    0.9765625
    0.9375000
    0.9921875
    0.9609375
    0.9921875
    0.9687500
    

    完整代碼如下:

    # -*- coding: utf-8 -*-
    """
    Created on Fri Jan  3 11:50:33 2020
    @author: xiuzhang Eastmount CSDN
    """
    import tensorflow as tf
    from tensorflow.examples.tutorials.mnist import input_data
    # 下載手寫數字圖像數據集
    mnist = input_data.read_data_sets('MNIST_data', one_hot=True)
    # 設置參數
    learning_rate = 0.001     # 學習效率
    train_iters = 100000      # 訓練次數
    batch_size = 128          # 自定義
    n_inputs = 28             # MNIST 輸入圖像形狀 28*28 黑白圖片高度為1
    n_steps = 28              # time steps 輸入圖像的28行數據
    n_hidden_units = 128      # 神經網絡隱藏層數量
    n_classes = 10            # 分類結果 數字0-0
    #-----------------------------定義placeholder輸入-------------------------
    # 設置傳入的值xs和ys
    x = tf.placeholder(tf.float32, [None, n_steps, n_inputs])  #每張圖片28*28=784個點
    y = tf.placeholder(tf.float32, [None, n_classes])          #每個樣本有10個輸出
    # 定義權重 進入RNN前的隱藏層 輸入&輸出
    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])),
    }
    # 定義偏置 進入RNN前的隱藏層 輸入&輸出
    biases = {
        # (128, )
        'in': tf.Variable(tf.constant(0.1, shape=[n_hidden_units, ])),
        # (10, )
        'out': tf.Variable(tf.constant(0.1, shape=[n_classes, ])),
    }
    #---------------------------------定義RNN-------------------------------
    def RNN(X, weights, biases):
        # hidden layer for input to cell
        #######################################################
        # X (128 batch, 28 steps, 28 inputs) 28行*28列 
        # X ==> (128*28, 28 inputs)
        X = tf.reshape(X, [-1, n_inputs])
        # 隱藏層 輸入
        # X_in ==> (128batch*28steps, 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]) # 128個隱藏層
        
        # cell
        #######################################################
        # Cell結構 隱藏層數 forget初始偏置為1.0(初始時不希望forget)
        lstm_cell = tf.nn.rnn_cell.BasicLSTMCell(n_hidden_units, forget_bias=1.0, state_is_tuple=True)
        # RNN會保留每一步計算的結果state
        # lstm cell is divided into two parts (c_state, m_state) 主線c_state 分線m_state
        _init_state = lstm_cell.zero_state(batch_size, dtype=tf.float32)
        # RNN運算過程 每一步的輸出都存儲在outputs序列中
        # 常規RNN只有m_state LSTM包括c_state和m_state
        outputs, states = tf.nn.dynamic_rnn(lstm_cell, X_in, initial_state=_init_state, time_major=False)
        
        # hidden layer for output as final results
        #######################################################
        # 第三層加工最終的輸出
        # 最終輸出=Cell的輸出*權重輸出+偏置數據
        # states包含了主線劇情和分線劇情 states[1]表示分線劇情的結果 即為outputs[-1]最后一個輸出結果
        results = tf.matmul(states[1], weights['out']) + biases['out']
        
        # 第二種方法
        # 解包 unpack to list [(batch, outputs)..] * steps
        #outputs = tf.unstack(tf.transpose(outputs, [1,0,2])) # states is the last outputs
        #results = tf.matmul(outputs[-1], weights['out']) + biases['out']
        return results
    #---------------------------------定義誤差和訓練-------------------------------
    pre = RNN(x, weights, biases)
    # 預測值與真實值誤差
    cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=pre, labels=y))
    # 訓練學習 學習效率設置為0.001
    train_step = tf.train.AdamOptimizer(learning_rate).minimize(cost) #梯度下降減小誤差
    # 預測正確個數
    correct_pred = tf.equal(tf.argmax(pre, 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
        # 循環每次提取128個樣本
        while step * batch_size < train_iters:
            # 從下載好的數據集提取128個樣本
            batch_xs, batch_ys = mnist.train.next_batch(batch_size)
            # 形狀修改 [128, 28, 28]
            batch_xs = batch_xs.reshape([batch_size, n_steps, n_inputs])
            # 訓練
            sess.run([train_step], feed_dict={
                x: batch_xs,
                y: batch_ys,
            })
            # 每隔20步輸出結果
            if step % 20 == 0: # 20*128
                print(sess.run(accuracy, feed_dict={
                    x: batch_xs,
                    y: batch_ys,
                }))
            step += 1
    

    注意,在運行代碼過程中可能會報錯“ValueError: Variable rnn/basic_lstm_cell/kernel already exists, disallowed. Did you mean to set reuse=True or reuse=tf.AUTO_REUSE in VarScope?”

    在Spyder中有kernel選項,點擊選擇 “ Restart & RunAll ” 重新運行代碼即可解決問題。


    四.總結

    寫到這里,這篇文章就講解完畢,更多TensorFlow深度學習文章會繼續分享,接下來我們會分享RNN回歸、文本識別、圖像識別、語音識別等內容。如果讀者有什么想學習的,也可以私聊我,我去學習并應用到你的領域。

    最后,希望這篇基礎性文章對您有所幫助,如果文章中存在錯誤或不足之處,還請海涵~作為人工智能的菜鳥,我希望自己能不斷進步并深入,后續將它應用于圖像識別、網絡安全、對抗樣本等領域,指導大家撰寫簡單的學術論文,一起加油!

    tensorflowrnn
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    Python人工智能第12篇文章介紹RNN和LSTM
    Python人工智能第11篇文章介紹如何保存神經網絡參數
    評價神經網絡的方法和評價機器學習的方法大同小異,常見的包括誤差、準確率、R2 score、F值等。
    Python人工智能第10篇介紹TF實現CNN圖像分類任務
    從本專欄開始,作者正式研究Python深度學習、神經網絡及人工智能相關知識。一.RNN文本分類1.RNN循環神經網絡英文是Recurrent Neural Networks,簡稱RNN。假設有一組數據data0、data1、data2、data3,使用同一個神經網絡預測它們,得到對應的結果。RNN常用于自然語言處理、機器翻譯、語音識別、圖像識別等領域。本文將采用詞向量、TFIDF兩種方式進行實驗。
    搭建過程詳見這篇文章:二.TensorFlow環境搭建、學習路線及入門案例安裝如下圖所示:安裝成功之后,我們嘗試一個簡單的代碼。打開Anaconda,然后選擇已經搭建好的“tensorflow”環境,運行Spyder。
    實體對齊尋求在不同的知識圖譜(KG)中找到引用同一真實世界對象的實體。KG嵌入的最新進展推動了基于嵌入的實體對齊的出現,它在一個連續的嵌入空間中對實體進行編碼,并基于學習到的嵌入來測量實體的相似性。本文對這一新興領域進行了全面的實驗研究。團隊調查了最近23種基于嵌入的實體對齊方法,并根據它們的技術和特點對它們進行了分類。此外團隊還提出了一種新的KG抽樣算法,通過該算法生成了一組具有各種異質性和分布
    網絡攻防對抗不斷演化升級,人工智能因其具備自學習和自適應能力,可為自動化網絡攻防提供助力,已成為網絡攻防的核心關鍵技術之一。
    近日,谷歌發布了Google TensorFlow存在任意代碼執行漏洞的風險通告。目前廠商已修復該漏洞,建議受影響用戶及時升級至安全版本進行防護,做好資產自查以及預防工作,以免遭受黑客攻擊。
    360漏洞云監測到TensorFlow存在任意代碼執行漏洞(CVE-2021-37678)。
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类