Skip to content

[PyTorch] LSTM 的原理與輸入輸出格式紀錄

Last Updated on 2021-07-01 by Clay

LSTM (Long Short-Term Memory),中文翻譯做『長短期記憶』,是一種循環神經網路 (RNN)。其論文發表於 1997 年,是在自然語言處理當中非常重要、並且好用的模型層。

由於我經常會使用 LSTM 來處理我的任務,故一直尋思著要整理一篇筆記。這樣一來,以後若是有碰到 LSTM 相關的問題,我都可以回頭來翻閱我的筆記,省去了在網路上四處瀏覽的時間。

為了我自己的查看方便,這篇筆記會分成兩部份。前半是紀錄 LSTM 原理的部份、後半則是專門紀錄在 PyTorch 當中 LSTM 的使用格式。


LSTM 的原理

由於這篇文章是我用來紀錄學習過程的文章,故有些圖片與原理的解說是參考他人文章。以下的內要參考網頁的連結會附在最底下的 References 區塊,示例圖片有侵權,麻煩告知我,我會馬上撤換 —— 我對於這些前輩大神們製作的圖片只有尊敬的意思,非常感謝他們製作了淺顯易懂的圖片幫助我學習。

LSTM 可以視為 RNN 的複雜版本,基本上最重要的是就是在不同時序的神經元間會有參數傳遞。以下是個 RNN 的架構圖,可以看到除了向前傳播的 h 值以外,神經元彼此之間按照時序傳遞資訊。

展開的遞歸神經網絡。
RNN 架構

然而 LSTM 單個神經元的架構明顯複雜多了:

A LSTM neural network.
LSTM 的架構
Understanding LSTM Networks -- colah's blog
單個 LSTM 神經元架構

以下來看看神經元的資料處理過程。基本上慢慢按照公式思考就會比較明白。


PyTorch 中 LSTM 使用方法

LSTM 的參數:

  • input_size: 輸入 x 的特徵數量
  • hidden_size: 隱藏層 h 的特徵數量
  • num_layers: LSTM 的循環層數 (Default=1)
  • bias: 若為 False,則 bias 初始化為 0 (Default=True)
  • batch_first: 若為 True,則輸入維度為 (batch_size, seq_len, feature)
  • dropout: 若不為 0,則在每一層 LSTM 後都會接著 dropout (Default=0)
  • bidirectional: 若為 True,則為雙向 LSTM (Default=False)

再來,我想要紀錄起資料在 LSTM 當中的變化。

首先,我們假設輸入的維度為 (batch_size, seq_len, input_size) —— 當然,這是 batch_first=True 的情況。

PyTorch 中定義的模型如下:

# coding: utf-8
import torch.nn as nn


# LSTM
class LSTM(nn.Module):
    def __init__(self, input_size, hidden_size, num_layers, bidirectional):
        super(LSTM, self).__init__()
        self.lstm = nn.LSTM(
            input_size=input_size,
            hidden_size=hidden_size,
            num_layers=num_layers,
            bidirectional=bidirectional,
        )

        self.fc = nn.Linear(hidden_size, 1)
        self.sigmoid = nn.Sigmoid()

    def forward(self, inputs):
        out, (h_n, c_n) = self.lstm(inputs, None)
        outputs = self.fc(h_n.squeeze(0))

        return self.sigmoid(outputs)



我們可以看到,這是一個 LSTM 的分類器,重要的是我們的三個 Output: “out”、”h_n”、”c_n”。以下我們分別來看看。


out (batch_first=True)

out: (batch_size, seq_len, hudden_size * num_directions)

out 是三維的 Tensor,第一維為 Batch Size,第二維為序列長度,第三維為『隱藏層大小 x num_directions』。隱藏層大小就是 hidden_size 設定的大小、num_directions 就是雙向 LSTM 為 2、單向為 1。


h_n

h_n: (num_layers * num_directions, batch_size, hidden_size)

num_layers 的意思為 LSTM 的隱藏層有幾層,除此之外都與上方 “out” 的解釋相仿。


c_n

c_n: (num_layers * num_directions, batch_size, hidden_size)

c_n 與 h_n 的構造相仿,唯一的差別在於 h_n 是 h 的輸出、c_n 則是 c 的輸出,可以參考上方的結構圖。


Bi-LSTM 的輸出

Bi-LSTM 比較不同,由於最後的輸出為『雙向』的,所以我們會得到一個順時序的輸出以及逆時序的輸出,這時候若是直接將其合併用以進行分類,通常效果會不太好。

我們要做的就是將逆時序的輸出再反過來,再與順時序的輸出合併。

順帶一提,在 PyTorch 當中直接設定 “Bidirectional=True” 是有點小問題的。其中最大的問題是無法以固定的 Seed 去固定其輸出結果。這在實驗模型中是危險的——因為你無法重複自己所做的實驗。


References

Leave a Reply