LSTM實現詳解

2021-01-09 CSDN技術社區
前言

在很長一段時間裡,我一直忙於尋找一個實現LSTM網絡的好教程。它們似乎很複雜,而且在此之前我從來沒有使用它們做過任何東西。在網際網路上快速搜索並沒有什麼幫助,因為我找到的都是一些幻燈片。

幸運地是,我參加了Kaggle EEG 競賽,而且我認為使用LSTM很有意思,最後還理解了它的工作原理。這篇文章基於我的解決方案,使用的是AndrejKarpathy的char-rnn代碼,這也是我強烈推薦給大家的。

RNN誤區

我感覺有一件很重要的事情一直未被大家充分強調過(而且這也是我為什麼不能使用RNN做我想做的事情的主要原因)。RNN和前饋神經網絡並沒有很大不同。最容易實現RNN的一種方法就是像前饋神經網絡使用部分輸入到隱含層,以及一些來自隱含層的輸出。在網絡中沒有任何神奇的內部狀態。它作為輸入的一部分。


RNN的整體結構與前饋網絡的結構非常相似

LSTM回顧

本節內容將僅覆蓋LSTM的正式定義。有很多其它的好博文,都詳細地描述了你該如何設想並思考這些等式。

LSTM有多種變換形式,但我們只講解一個簡單的。一個Cell由三個Gate(input、forget、output)和一個cell單元組成。Gate使用一個sigmoid激活函數,而input和cell state通常會使用tanh來轉換。LSTM 的cell可以使用下列的等式來定義:

Gates:


輸入變換:


狀態更新:


使用圖片描述類似下圖:


由於門控機制,Cell可以在工作時保持一段時間的信息,並在訓練時保持內部梯度不受不利變化的幹擾。Vanilla LSTM 沒有forget gate,並在更新期間添加無變化的cell狀態(它可以看作是一個恆定的權值為1的遞歸連結),通常被稱為一個Constant Error Carousel(CEC)。這樣命名是因為它解決了在RNN訓練時一個嚴重的梯度消失和梯度爆炸問題,從而使得學習長期關係成為可能。

建立你自己的LSTM層

這篇教程的代碼使用的是Torch7。如果你不了解它也不必擔心。我會詳細解釋的,所以你可以使用你喜歡的框架來實現相同的算法。

該網絡將作為nngraph.gModule模塊來實現,基本上表示我們定義的一個由標準nn模塊組成的神經網絡計算圖。我們需要以下幾層:

nn.Identity() - 傳遞輸入(用來存放輸入數據)nn.Dropout(p) - 標準的dropout模塊(以1-p的概率丟棄一部分隱層單元)nn.Linear(in, out) - 從in維到out維的一個仿射變換nn.Narrow(dim, start, len) - 在第dim方向上選擇一個子向量,下標從start開始,長度為lennn.Sigmoid() - 應用sigmoid智能元素nn.Tanh() - 應用tanh智能元素nn.CMulTable() - 輸出張量(tensor)的乘積nn.CAddTable() - 輸出張量的總和

輸入

首先,讓我們來定義輸入形式。在lua中類似數組的對象稱為表,這個網絡將接受一個類似下面的這個張量表。


local inputs = {}
table.insert(inputs, nn.Identity()())  -- network input
table.insert(inputs, nn.Identity()())  -- c at time t-1
table.insert(inputs, nn.Identity()())  -- h at time t-1
local input = inputs[1]
local prev_c = inputs[2]
local prev_h = inputs[3]

Identity模塊只將我們提供給網絡的輸入複製到圖中。

計算gate值

為了加快我們的實現,我們會同時運用整個LSTM層轉換。

locali2h=nn.Linear(input_size,4*rnn_size)(input)-- input to hiddenlocalh2h=nn.Linear(rnn_size,4*rnn_size)(prev_h)-- hidden to hiddenlocalpreactivations=nn.CAddTable()({i2h,h2h})-- i2h + h2h

如果你不熟悉nngraph,你也許會覺得奇怪,在上一小節我們建立的inputs屬於nn.Module,這裡怎麼已經用圖節點調用一次了。事實上發生的是,第二次調用把nn.Module轉換為nngraph.gModule,並且參數指定了該節點在圖中的父節點。

preactivations輸出一個向量,該向量由輸入和前隱藏狀態的一個線性變換生成。這些都是原始值,用來計算gate 激活函數和cell輸出。這個向量被分為四個部分,每一部分的大小為rnn_size。第一部分將用於in gates,第二部分用於forget gate,第三部分用於out gate,而最後一個作為cell input(因此各個gate的下標和cell數量i的輸入為{i, rnn_size+i, 2⋅rnn_size+i, 3⋅rnn_size+i})。


接下來,我們必須運用非線性,但是儘管所有的gate使用的都是sigmoid,我們仍使用tanh對輸入進行預激活處理。正因為這個,我們將會使用兩個nn.Narrow模塊,這會選擇預激活向量中合適的部分。

-- gates
localpre_sigmoid_chunk=nn.Narrow(2,1,3*rnn_size)(preactivations)
localall_gates=nn.Sigmoid()(pre_sigmoid_chunk)
-- input
localin_chunk=nn.Narrow(2,3*rnn_size+1,rnn_size)(preactivations)
localin_transform=nn.Tanh()(in_chunk)

在非線性操作之後,我們需要增加更多的nn.Narrow,然後我們就完成了gates。

localin_gate=nn.Narrow(2,1,rnn_size)(all_gates)
localforget_gate=nn.Narrow(2,rnn_size+1,rnn_size)(all_gates)
localout_gate=nn.Narrow(2,2*rnn_size+1,rnn_size)(all_gates)

Cell和hidden state

有了計算好的gate值,接下來我們可以計算當前的Cell狀態了。所有的這些需要的是兩個nn.CMulTable模塊(一個用於,一個用於),並且nn.CAddTable用於把它們加到當前的cell狀態上。

-- previous cell state contribution
localc_forget=nn.CMulTable()({forget_gate,prev_c})
-- input contribution
localc_input=nn.CMulTable()({in_gate,in_transform})
-- next cell state
localnext_c=nn.CAddTable()({
 c_forget,
 c_input
})

最後,是時候來實現hidden 狀態計算了。這是最簡單的部分,因為它僅僅是把tanh應用到當前的cell 狀態(nn.Tanh)並乘上output gate(nn.CMulTable)。

localc_transform=nn.Tanh()(next_c)
localnext_h=nn.CMulTable()({out_gate,c_transform})

定義模塊

現在,如果你想要導出整張圖作為一個獨立的模塊,你可以使用下列代碼把它封裝起來:

-- module outputs
outputs={}
table.insert(outputs,next_c)
table.insert(outputs,next_h)

-- packs the graph into a convenient module with standard API (:forward(), :backward())
returnnn.gModule(inputs,outputs)

實例

LSTM layer實現可以在這裡獲得。你也可以這樣使用它:

th> LSTM= require 'LSTM.lua' 
                                                                                                 [0.0224s]
th> layer= LSTM.create(3, 2)
                                                                                                 [0.0019s]
th> layer:forward({torch.randn(1,3), torch.randn(1,2), torch.randn(1,2)})
{  
1 : DoubleTensor - size: 1x2 
 2 : DoubleTensor - size: 1x2} 
}
                                                                                                 [0.0005s]

為了製作一個多層LSTM網絡,你可以在for循環中請求後續層,用上一層的next_h作為下一層的輸入。你可以查看這個例子。

訓練

最後,如果你感興趣,請留個評論吧,我會試著擴展這篇文章!

結束語

確實是這樣!當你理解怎樣處理隱藏層的時候,實現任何RNN都會很容易。僅僅把一個常規MLP層放到頂部,然後連接多個層並且把它和最後一層的隱藏層相連,你就完成了。

如果你有興趣的話,下面還有幾篇關於RNN的好論文:

原文連結:LSTM implementation explained

(編譯/劉帝偉 審校/趙屹華、朱正貴、李子健 責編/周建丁)

譯者簡介: 劉帝偉,中南大學軟體學院在讀研究生,關注機器學習、數據挖掘及生物信息領域。

連結:深入淺出LSTM神經網絡

1. 加入CSDN人工智慧用戶微信群,交流人工智慧相關技術,加微信號「jianding_zhou」或掃下方二維碼,由工作人員加入。請註明個人信息和入群需求,並在入群後按此格式改群名片:機構名-技術方向-姓名/暱稱

2. 加入CSDN 人工智慧技術交流QQ群,請搜索群號加入:465538150。同上註明信息。

3. CSDN高端專家微信群,採取受邀加入方式,不懼高門檻的請加微信號「jianding_zhou」或掃描下方二維碼,PS:請務必帶上你的BIO

本文為CSDN編譯整理,未經允許不得轉載,如需轉載請聯繫market#csdn.net(#換成@)

相關焦點

  • PyTorch:Bi-LSTM的文本生成
    —歐內斯特·海明威本博客的目的是解釋如何通過實現基於LSTMs的強大體系結構來構建文本生成的端到端模型。到目前為止,我們已經解釋了文本生成模型的體系結構以及實現的方法。現在我們需要知道如何使用PyTorch框架來實現所有這些,但是首先,我想簡單地解釋一下bilstm和LSTM是如何協同工作的,以便稍後了解如何在代碼中實現這一點,那麼讓我們看看bilstm網絡是如何工作的。
  • 如何使用LSTM在Keras中快速實現情感分析任務
    本文對 LSTM 進行了簡單介紹,並講述了如何使用 LSTM 在 Keras 中快速實現情感分析任務。長短期記憶網絡通常被稱為 LSTM,它是由 Hochreiter 和 Schmiduber 提出的,被廣泛地應用在語音識別、語言建模、情感分析和文本預測中。
  • 時間序列的LSTM模型預測——基於Keras
    今天介紹的就是如何基於Keras和Python,實現時間序列的LSTM模型預測。二、LSTM模型介紹    長短時記憶網絡(Long Short Term Memory,簡稱LSTM)模型,本質上是一種特定形式的循環神經網絡(Recurrent Neural Network,簡稱RNN)。
  • 用純NumPy碼一個RNN、LSTM:這是最好的入門方式了
    大多數開發者對底層運行機制,尤其是如何使用純 NumPy 實現神經網絡變得比較陌生。以前機器之心曾介紹過如何使用 NumPy 實現簡單的卷積神經網絡,但今天會介紹如何使用 NumPy 實現 LSTM 等循環神經網絡。一般使用純 NumPy 實現深度網絡會面臨兩大問題,首先對於前向傳播,卷積和循環網絡並不如全連接網絡那樣可以直觀地實現。
  • 在 TensorFlow 上使用 LSTM 進行情感分析
    batchSize = 24lstmUnits = 64numClasses = 2iterations = 100000與大多數 TensorFlow 圖一樣,現在我們需要指定兩個佔位符,一個用於數據輸入,另一個用於標籤數據。對於佔位符,最重要的一點就是確定好維度。
  • 使用LSTM深度學習模型進行溫度的時間序列單步和多步預測
    對於序列建模,我們將選擇具有LSTM層的遞歸神經網絡的Tensorflow實現。LSTM網絡的輸入是3D張量:(樣本,時間步長,功能)樣本—用於訓練的序列總數。timesteps-樣本的長度。 Xval=None, Yval=None, mask_value=-999.0, min_delta=0.001, patience=5 ): lstm_input
  • Pytorch貝葉斯庫BLiTZ實現使用LSTM預測時序數據和繪製置信區間
    __init__() self.lstm_1 = BayesianLSTM(1, 10) self.linear = nn.Linear(10, 1) def forward(self, x): x_, _ = self.lstm_1(x) #gathering only the latent end-of-sequence for the
  • BiLSTM+CRF 的實現詳解
    class BiLSTM_CRF(nn.Module):def __init__(self, vocab_size, tag2idx, embedding_dim, hidden_dim):self.word_embeds = nn.Embedding(vocab_size, embedding_dim)self.lstm = nn.LSTM(
  • 探索LSTM:基本概念到內部結構
    RNN的數學原理如圖所示:通過LSTM實現長期記憶模型如何更新對世界的認知?到目前為止,還沒有任何規則限制,所以模型的認知可能非常混亂。這一幀模型認為人物身處美國,下一幀如果出現了壽司,模型可能認為人物身處日本……這種混亂的背後,是信息的快速變換和消失,模型難以保持長期記憶。所以我們需要讓網絡學習如何更新信息。
  • MXNet 宣布支持 Keras 2,可更加方便快捷地實現 CNN 及 RNN 分布式...
    雷鋒網(公眾號:雷鋒網) AI 研習社按,近期,AWS 表示 MXNet 支持 Keras 2,開發者可以使用 Keras-MXNet 更加方便快捷地實現使用 imdb_lstm 示例腳本。 在嵌入層中傳遞輸入長度,並按如下所示設置 unroll = True。首先,在 DLAMI 的終端會話中,從 Keras-MXNet repo 文件夾下載示例腳本。
  • 手推公式:LSTM單元梯度的詳細的數學推導
    LSTM單元的基本單元結構已經介紹完成,繼續推導在實現中使用的方程。推導先決條件推導方程的核心概念是基於反向傳播、成本函數和損失。除此以外還假設您對高中微積分(計算導數和規則)有基本的了解。反向傳播推導lstm的輸出有兩個值需要計算。Softmax:對於交叉熵損失的導數,我們將直接使用最終的方程。隱藏狀態是ht。ht是w.r的微分。根據鏈式法則,推導過程如下圖所示。
  • 用金庸、古龍群俠名稱訓練LSTM,會生成多麼奇葩的名字?
    http://magicly.me/2017/04/07/rnn-lstm-generate-name/?utm_source=tuicool&utm_medium=referralMagicly:之前翻譯了一篇介紹RNN的文章,一直沒看到作者寫新的介紹LSTM的blog,於是我又找了其他資料學習。
  • 一步一步教會你,詳解用Python實現一個簡易的溫度換算GUI小工具
    詳解Python文件對話框filedialog和顏色選擇colorchooser的使用詳解GUI詞雲自動生成工具中詞雲屬性設置界面的實現(連載六)Python自動生成詞雲工具(GUI)之數據清洗功能實現(連載五)
  • 乾貨: 五種常見數據複製技術詳解
    獨立於底層的作業系統、資料庫、存儲,應用可以根據需求實現雙寫或者多寫,從而實現主本和多個數據副本之間的數據複製功能。這種由應用實現的技術,可以在中間件或者應用平臺層面進行封裝和實現,對上面的應用透明,也可以在應用層面實現。
  • 教你用PyTorch實現「看圖說話」(附代碼、學習資源)
    具體實現案例讓我們看一個Pytorch中imagecaptioning的簡單實現。__init__()       self.embed= nn.Embedding(vocab_size, embed_size)       self.lstm= nn.LSTM(embed_size, hidden_size, num_layers, batch_first=True)       self.linear= nn.Linear(hidden_size
  • 使用Tensorflow實現RNN-LSTM的菜鳥指南
    Tensorflow和其他各種庫(Theano,Torch,PyBrain)為用戶提供了設計模型的工具,而沒有深入了解實現神經網絡,優化或反向傳播算法的細節。Danijar概述了組織Tensorflow模型的好方法,您可能希望稍後使用它來整理代碼。出於本教程的目的,我們將跳過這一點,並專注於編寫正常工作的代碼。首先導入所需的包。