RNN原理解析與實現(Keras)

爲何要使用RNN

前饋神經網絡

  • 前饋神經網絡是一種最簡單的神經網絡,是目前應用最普遍、發展最迅速的人工神經網絡之一。
  • 各神經元分層排列,第一層是輸入層;而後是隱藏層,其中隱藏層可能會有多層;最後一層爲輸出層。
    • 層與層之間是全鏈接的,每層的節點之間是無連接的。
    • 每層的神經元只與前一層的神經元相連,只接受前一層的輸出,並傳給下一層,各層間沒有反饋。
    • 每一層的神經元之間都是相互獨立的,如輸入層的神經元是彼此獨立的。
  • 常見的前饋神經網絡有單層前饋神經網絡、多層前饋神經網絡(DNN、多層感知器)、CNN等。

前饋神經網絡的缺陷

前饋神經網絡只能單獨處理一個個的輸入,前一個輸入與後一個輸入之間沒有任何關係,若是碰到須要處理輸入之間關係的數據,它們將沒法正確的預測輸入值,好比下列樣例:算法

  • 球的軌跡(移動過程點的集合)數據庫

    • 現有一個球在平面上移動,咱們想要預測球的移動方向。
    • 若是使用前饋網絡,那麼咱們把點集輸入模型,可是因爲它只能處理單獨一個個的輸入,那麼咱們就沒法根據上一個的信息來預測下一個點的方向(即球的移動方向)。
    • 只能根據被動的根據全部的輸入(點)的來預測方向,不清楚點位於第幾步,就沒法正確的預測方向。以下圖:咱們知道球的軌跡,卻不清楚此時球位於哪一點的位置。
  • 天然語言處理數組

    • 若是咱們輸入一句話我吃蘋果,想要預測它的語義,那麼它會被拆成一個個詞輸入模型
    • 若是咱們不知道它們的順序,隨機處理它們,那麼咱們就沒法正確的預測出這句話的語義
    • 由於:蘋果吃我蘋我吃果我吃蘋果是徹底不一樣的語義

RNN的定義

針對上述須要須要按照順序處理的數據,在原有全鏈接神經網絡的基礎上添加了一個時間軸的概念,即誕生了循環神經網絡(RNN)網絡

循環神經網絡(RNN)是一類用於處理序列數據的神經網絡。RNN擁有記憶模塊,能夠獲取以及計算過的信息,記住執行的順序。即便是一樣的輸入,若是輸入的順序不一樣也會產生不一樣的輸出。架構

RNN的基本結構

神經網絡的結構分爲輸入層、隱藏層、輸出層。輸入與輸出層是處理數據的輸入輸出的;而隱藏層則對數據進行計算、預測處理。前饋網絡與循環網絡(RNN)的主要區別就是在隱藏層。 app

最簡前饋神經網絡

前饋網絡的隱藏層,若是隻有一個神經元,則直接處理;若是有多個神經元,每一個神經元都單獨運行,互不相關,沒有任何順序、引用、傳值的關係。 機器學習

RNN的結構

而RNN的結構則是在前饋網絡隱藏層上添加了時間軸的概念,讓每個單元都按照輸入的順序進行處理,上一個處理的輸出做爲下一個處理的輸入與當前的輸入一塊兒計算,綜合前幾個輸入的計算結果與當前輸入一塊兒進行預測。 函數

RNN的種類(結構的四種形式)

1 to N

這種形式一是隻在序列開始把輸入信息輸入模型計算(左);二是把輸入信息做爲每一個階段的輸入(右),這種結構能夠處理如: 輸入圖像的特徵,輸出y的序列是一段句子或者從別的類別生成語音;輸入一個類別,輸出一段描述文字這類問題。 學習

N to 1

輸入的是一個序列,輸出的是一個單獨的值。這種結構經常使用於處理分類問題,如:輸入一段文字判斷類別、輸入句子判斷感情傾向、輸入圖片判斷類別。 測試

N to N

輸入和輸出序列是等長的。這種能夠做爲簡單的Char RNN能夠用來生成文章,詩歌,甚至是代碼。

N to M

這種結構又稱Encoder-Decoder、Seq2Seq模型,它會將輸入數據編碼成一個上下文向量c,以後經過c輸出預測序列。它普遍應用於機器翻譯、文本摘要、閱讀理解、對話生成等領域。

RNN的實現

準備數據集,提取特徵信息最爲輸入數據

實現RNN的第一步須要準備數據集,下列是對圖像進行分類的數據處理格式

(x_train, y_train) =  dealImage()
# 處理數據格式,將圖片數據x轉化到-1到1之間(除以像素點最大值255),提升精確度
x_train = x_train.reshape(x_train.shape[0], 56, -1).astype('float') / 255.0
# 轉換labels爲one hot格式
y_train = np_utils.to_categorical(y_train, num_classes=num_classes)
# 一樣的方法加載測試數據
(x_test, y_test) =  dealTestImage()
複製代碼
# deal.py 處理圖片分類時的數據預處理,讀取圖片數據和對應類別
def dealImage():
    result = [(src, label)....] # 路徑和類別的對應關係能夠保存到本地文件或者數據庫中,須要使用的時候在讀取
    images = []
    labels = []
    for row in result:
        imsrc = cv2.imread(row[0], 0)
        im = cv2.resize(imsrc, (56, 56), interpolation=cv2.INTER_AREA)  # 轉換數據格式(按本身須要的格式轉換) 
        imgData = np.array(im) # numpy array化
        images.append(imgData)
        labels.append(row[1])
    images = np.array(images)
    labels = np.array(labels)
    return (images, labels)
複製代碼

搭建神經網絡結構(從輸入到輸出)

根據前向傳播算法的理論,搭建RNN神經網絡,選擇恰當的神經網絡的層數、神經元數目

  • 建立模型
    • 建立模型 keras模型分爲順序模型和函數式API模型
    • 順序模型是多個網絡層的線性堆疊,能夠幫助咱們快速建立一些簡單的模型,是咱們最常使用的模型
    • 函數式API模型是用來定義複雜模型(多輸出模型、有向無環圖、具備共享層的模型)的方法
# 建立模型,當前模型比較簡單無複雜的結構,使用順序模型便可
model = Sequential()
cell_size = 300
複製代碼
  • 搭建神經網絡
    • 若是當前層的輸入維度與前一層的輸出維度一致,能夠不寫輸入維度
    • (若是建立多層)每層SimpleRNN之間必須設置return_sequences=True(默認是False)
    • 激活函數也是神經網絡中一個很重的部分。每一層的網絡輸出都要通過激活函數。
      • 經常使用激活函數有:softmaxSoftplusRelutanhsigmodhard_sigmoidlinear
      • 通過調試,當前模型的SimpleRNN適合使用tanh函數,輸出Dense層適合採用softmax進行分類
# 循環神經網絡
model.add(SimpleRNN(
    units=cell_size,  # 輸出數據的維度(當前層神經元的數目)
    activation='tanh',  # 激活函數,默認即tanh
    return_sequences=True,
    input_shape=(56, 56)  # 輸入數據的維度(shape)
))

model.add(SimpleRNN(units=cell_size, return_sequences=True))
model.add(SimpleRNN(units=cell_size, return_sequences=True))
# 每層SimpleRNN之間必須設置return_sequences=True(默認是False)
# return_sequences 是返回輸出序列的最後一個輸出(False),仍是返回所有序列(True)
# return_sequences=True 表示咱們須要完整的編碼序列,而不只僅是最終總結狀態

# return_sequences=True 返回的是個多維數組,若是下一層沒法接收該種多維數組,則層須要設置爲return_sequences=True或者不設置取默認值
model.add(SimpleRNN(units=cell_size))
# 添加全鏈接層做爲輸出層 
model.add(Dense(num_classes, activation='softmax'))
複製代碼

大量特徵數據輸入神經網絡,優化神經網絡參數,訓練模型

使用反向傳播算法迭代訓練模型,根據每次訓練結果優化參數後再次訓練直到獲得能儘量好的預測結果的模型

反向傳播算法tensorflow與keras都有封裝,直接調用方法便可

  • 第一步須要定義模型的優化器、損失函數
    • 機器學習分爲構建模型、訓練模型兩部分。優化器和損失函數是模型訓練時兩個最重要的參數
    • 優化器是用來更新和計算影響模型訓練和輸出的參數,是模型的輸出逼近或達到最優值,從而最小(大)化損失函數的值
      • 優化器有:SGDAdagradRMSpropAdam
      • 本例採用的是經常使用的Adam算法
    • 損失函數是用來評估模型好壞程度的,即預測值與真實值的不一致程度
      • 損失函數有msemaemapemslehingecategorical_crossentropy等等
      • 本例採用適合分類的交叉熵categorical_crossentropy函數
# 初始化優化器
adam = Adam(lr=1e-4)
# 定義優化器,loss function,訓練過程當中計算準確率
model.compile(
    optimizer=adam, # 優化器
    loss='categorical_crossentropy',  # 損失函數 mse 均方差 categorical_crossentropy 交叉熵(多分類)
    metrics=['accuracy'] # 訓練和測試期間的模型評估標準
)
複製代碼
  • 傳入數據,調用keras模型的方法開始訓練
# 開始訓練模型,調用model.fit()方法,方法採用時序後向傳播算法訓練模型
# 以給的數目的輪次訓練模型,到第epochs輪結束訓練,每輪多個批次,每批次大小batch_size
model.fit(x_train, y_train, batch_size=32, epochs=20)
# 預測模型的損失值和準確率
loss, accuracy = model.evaluate(x_test, y_test)
# 保存模型,以便使用時加載
model.save('myfile/rnn.hdf5')
複製代碼

訓練結果

使用模型預測和分類數據

加載已保存的模型,輸入待預測的,輸出最可能的結果

# 加載模型
model = load_model('myfile/rnn.hdf5')
# 使用模型預測結果
pred = model.predict(data) # data 是numpy的array格式
# 取出可能性最大的值做爲預測結果
print([final.argmax() for final in pred])
複製代碼

RNN常見變體

雙向循環網絡(Bi-RNN)

在處理序列信息時,有時咱們不只須要以前的信息,還須要以後的信息,好比:預測我__蘋果這句話所缺失的詞是什麼,咱們就須要根據上下文的詞彙一塊兒去預測。而Bi-RNN能很好的解決這個問題,它是一個由兩個RNN上下疊加在一塊兒組成的相對較簡單的RNN。所以,它的輸出由前向RNN和後向RNN共同決定,它當前時刻輸出(第t步的輸出)不只僅與以前序列有關,還與以後序列有關。

堆疊循環神經網絡(SRNN)

SRNN是在全鏈接的單層循環神經網絡的基礎上堆疊造成的深度算法。該網絡具備更強大的表達與學習能力,可是複雜性也隨之提升,同時須要更多的訓練數據。

長短時間記憶網絡(LSTM)

RNN在處理長期依賴(時間序列上距離較遠的節點)時會遇到巨大的困難,由於計算距離較遠的節點之間的聯繫時會涉及雅可比矩陣的屢次相乘,會形成梯度消失或者梯度膨脹的現象。 LSTM就是一種爲了解決長期依賴問題而提出的特殊RNN,所以,記住長時間的信息是它的基本功能

門控循環單元(GRU)

GRU能夠當作是LSTM的變種,GRU把LSTM中的遺忘門和輸入們用更新門來替代。 把cell state和隱狀態ht進行合併,在計算當前時刻新信息的方法和LSTM有所不一樣。GRU的構造更簡單,在訓練數據大的狀況下能節省更多時間

參考文獻

相關文章
相關標籤/搜索