案例二:對文字進行分類,類別有財經、房產、股票、教育、科技、社會、時政、體育、遊戲、娛樂
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
:返回模型的輸出。
思考:
和案例一中程式碼相比,試分析不同點。
- 在案例二程式碼中,模型的初始化是透過傳入一個配置引數
config
來完成的,其中包含了模型所需的各種引數,如詞表大小、詞向量維度、隱藏層大小等。模型的詞嵌入層和LSTM層都會根據配置引數進行初始化。
在案例一程式碼中,模型的初始化是直接在__init__
方法中進行的,並沒有接受額外的引數。詞嵌入層和LSTM層的大小是根據預先定義的全域性變數n_class
和n_hidden
來確定的。 - 針對
forward
,在案例二程式碼中,前向傳播方法forward
接受一個輸入x,該輸入包含了文字資料和對應的標籤。模型首先透過詞嵌入層將文字序列轉換為詞向量表示,然後透過LSTM層對詞向量進行編碼,最後取句子最後時刻的隱藏狀態並透過全連線層進行分類。
在案例一程式碼中,前向傳播方法forward
接受一個輸入X,該輸入是一個形狀為[batch_size, max_len, n_class]
的序列資料。模型首先將輸入轉置為形狀為[max_len, batch_size, n_class]
,然後透過LSTM層進行序列編碼,最後取序列的最後一個時間步的隱藏狀態,並透過全連線層進行預測。 - 在案例二程式碼中,最佳化器和損失函式的定義並未包含在Model類中,可能是在其他地方進行了定義。
在案例一程式碼中,定義了一個名為optimizer
的最佳化器和一個交叉熵損失函式nn.CrossEntropyLoss()
。
和案例一中程式碼相比,試分析相同點。
- 模型的輸出層都是全連線層:無論是文字分類模型還是序列預測模型,它們都在最後一層使用了全連線層(nn.Linear)來將LSTM的輸出對映到最終的預測結果。這樣的設計是為了將LSTM輸出的特徵向量轉換為最終的分類或預測結果。
- 使用了相似的引數初始化方式:儘管引數的具體值可能不同,但兩個模型都在初始化階段使用了類似的方法來確定詞嵌入層和LSTM層的引數。這包括詞彙表大小、詞向量維度、隱藏層大小等引數的設定,使得兩個模型在結構上具有一定的相似性。
- 使用了相似的前向傳播方法:儘管模型任務不同,但它們的前向傳播方法都遵循了相似的流程:首先對輸入資料進行一些預處理(如詞嵌入或轉置),然後將資料輸入到LSTM模型中進行編碼,最後將編碼後的結果透過全連線層得到最終的輸出。
- 都繼承自
nn.Module
:兩個模型都是基於PyTorch的nn.Module
類進行構建的,這是PyTorch中定義模型的標準做法。因此,它們具有相似的模型結構和方法。
對於BiLSTM的實現,兩段程式碼有異曲同工之妙:
- BiLSTM是由兩個LSTM組成的,一個按照正序處理輸入序列,另一個按照逆序處理輸入序列。兩者的輸出經過連線或者拼接,形成了最終的BiLSTM輸出。
- 兩段程式碼中,都可以透過設定引數來定義BiLSTM的輸入維度、隱藏層維度、層數、是否雙向、是否批次優先以及dropout率等引數。
- 無論哪個案例,都需要經過詞嵌入層(如果有)以及適當的預處理後再輸入到BiLSTM模型中進行處理。
- 在前向傳播過程中,兩段程式碼都會將輸入資料傳遞給BiLSTM模型進行處理,然後取得BiLSTM輸出的結果。
這些輸出結果通常是每個時間步的隱藏狀態,可以根據任務的不同選擇不同的輸出方式,如取最後一個時間步的隱藏狀態或者進行序列的平均池化等。
最終,透過全連線層對BiLSTM的輸出進行對映,得到最終的分類或預測結果。