BiLSTM演算法(二)

江左子固發表於2024-04-10

案例二:對文字進行分類,類別有財經、房產、股票、教育、科技、社會、時政、體育、遊戲、娛樂


github程式碼連結點選此文字分類
原作者給出了好幾種模型
模型
此次僅針對BiLSTM模型分析。
核心程式碼如下:

class Model(nn.Module):
    def __init__(self, config):
        super(Model, self).__init__()
        if config.embedding_pretrained is not None:
            self.embedding = nn.Embedding.from_pretrained(config.embedding_pretrained, freeze=False)
        else:
            self.embedding = nn.Embedding(config.n_vocab, config.embed, padding_idx=config.n_vocab - 1)
        self.lstm = nn.LSTM(config.embed, config.hidden_size, config.num_layers,
                            bidirectional=True, batch_first=True, dropout=config.dropout)
        self.fc = nn.Linear(config.hidden_size * 2, config.num_classes)

    def forward(self, x):
        x, _ = x
        out = self.embedding(x)  # [batch_size, seq_len, embeding]=[128, 32, 300]
        out, _ = self.lstm(out)
        out = self.fc(out[:, -1, :])  # 句子最後時刻的 hidden state
        return out

class Model(nn.Module)::定義了一個繼承自nn.Module的模型類Model。

針對def __init__(self, config):

def __init__(self, config)::定義了類的初始化方法,接受一個配置引數config,用於初始化模型的各種引數。

super(Model, self).__init__():呼叫父類nn.Module的初始化方法。

if config.embedding_pretrained is not None::判斷是否提供了預訓練的詞向量。

如果提供了預訓練的詞向量,則使用nn.Embedding.from_pretrained()方法初始化詞嵌入層,並將引數freeze設定為False,表示不凍結詞向量引數。

如果沒有提供預訓練的詞向量,則使用nn.Embedding()方法初始化詞嵌入層,引數包括詞彙表大小config.n_vocab、詞向量維度config.embed和填充符索引padding_idx

self.lstm = nn.LSTM(config.embed, config.hidden_size, config.num_layers, bidirectional=True, batch_first=True, dropout=config.dropout):初始化雙向LSTM層。

引數包括輸入維度config.embed、隱藏層維度config.hidden_size、層數config.num_layers、是否雙向、是否批次優先以及dropout率。

self.fc = nn.Linear(config.hidden_size * 2, config.num_classes):初始化全連線層。

輸入大小為雙向LSTM輸出的特徵維度乘以2(因為使用了雙向LSTM),輸出大小為類別數量config.num_classes

針對def forward(self, x):

def forward(self, x)::定義了模型的前向傳播方法。

x, _ = x:由於輸入x是一個元組,包含文字資料和對應的標籤,這裡使用x, _來解包取得文字資料。

out = self.embedding(x):將文字資料x經過詞嵌入層得到詞向量表示out。

out, _ = self.lstm(out):將詞向量表示輸入雙向LSTM層進行編碼,得到LSTM的輸出out。

out = self.fc(out[:, -1, :]):取出LSTM輸出序列的最後一個時間步的隱藏狀態作為整個句子的表示,然後透過全連線層進行分類得到輸出out。

return out:返回模型的輸出。

思考:

和案例一中程式碼相比,試分析不同點。

  1. 在案例二程式碼中,模型的初始化是透過傳入一個配置引數config來完成的,其中包含了模型所需的各種引數,如詞表大小、詞向量維度、隱藏層大小等。模型的詞嵌入層和LSTM層都會根據配置引數進行初始化。
    在案例一程式碼中,模型的初始化是直接在__init__方法中進行的,並沒有接受額外的引數。詞嵌入層和LSTM層的大小是根據預先定義的全域性變數n_classn_hidden來確定的。
  2. 針對forward,在案例二程式碼中,前向傳播方法forward接受一個輸入x,該輸入包含了文字資料和對應的標籤。模型首先透過詞嵌入層將文字序列轉換為詞向量表示,然後透過LSTM層對詞向量進行編碼,最後取句子最後時刻的隱藏狀態並透過全連線層進行分類。
    在案例一程式碼中,前向傳播方法forward接受一個輸入X,該輸入是一個形狀為[batch_size, max_len, n_class]的序列資料。模型首先將輸入轉置為形狀為[max_len, batch_size, n_class],然後透過LSTM層進行序列編碼,最後取序列的最後一個時間步的隱藏狀態,並透過全連線層進行預測。
  3. 在案例二程式碼中,最佳化器和損失函式的定義並未包含在Model類中,可能是在其他地方進行了定義。
    在案例一程式碼中,定義了一個名為optimizer的最佳化器和一個交叉熵損失函式nn.CrossEntropyLoss()

和案例一中程式碼相比,試分析相同點。

  1. 模型的輸出層都是全連線層:無論是文字分類模型還是序列預測模型,它們都在最後一層使用了全連線層(nn.Linear)來將LSTM的輸出對映到最終的預測結果。這樣的設計是為了將LSTM輸出的特徵向量轉換為最終的分類或預測結果。
  2. 使用了相似的引數初始化方式:儘管引數的具體值可能不同,但兩個模型都在初始化階段使用了類似的方法來確定詞嵌入層和LSTM層的引數。這包括詞彙表大小、詞向量維度、隱藏層大小等引數的設定,使得兩個模型在結構上具有一定的相似性。
  3. 使用了相似的前向傳播方法:儘管模型任務不同,但它們的前向傳播方法都遵循了相似的流程:首先對輸入資料進行一些預處理(如詞嵌入或轉置),然後將資料輸入到LSTM模型中進行編碼,最後將編碼後的結果透過全連線層得到最終的輸出。
  4. 都繼承自nn.Module:兩個模型都是基於PyTorch的nn.Module類進行構建的,這是PyTorch中定義模型的標準做法。因此,它們具有相似的模型結構和方法。

對於BiLSTM的實現,兩段程式碼有異曲同工之妙:

  1. BiLSTM是由兩個LSTM組成的,一個按照正序處理輸入序列,另一個按照逆序處理輸入序列。兩者的輸出經過連線或者拼接,形成了最終的BiLSTM輸出。
  2. 兩段程式碼中,都可以透過設定引數來定義BiLSTM的輸入維度、隱藏層維度、層數、是否雙向、是否批次優先以及dropout率等引數。
  3. 無論哪個案例,都需要經過詞嵌入層(如果有)以及適當的預處理後再輸入到BiLSTM模型中進行處理。
  4. 在前向傳播過程中,兩段程式碼都會將輸入資料傳遞給BiLSTM模型進行處理,然後取得BiLSTM輸出的結果。
    這些輸出結果通常是每個時間步的隱藏狀態,可以根據任務的不同選擇不同的輸出方式,如取最後一個時間步的隱藏狀態或者進行序列的平均池化等。
    最終,透過全連線層對BiLSTM的輸出進行對映,得到最終的分類或預測結果。

相關文章