Bert獲取詞向量的過程
參考部落格:https://blog.csdn.net/u011984148/article/details/99921480
1.把我們要獲取詞向量的句子進行分詞處理,再根據模型中的vocab.txt獲取每個詞的對應的索引。
token初始化
tokenized_text = tokenizer.tokenize(marked_text) print (tokenized_text) ['[CLS]', 'after', 'stealing', 'money', 'from', 'the', 'bank', 'vault', ',', 'the', 'bank', 'robber', 'was', 'seen', 'fishing', 'on', 'the', 'mississippi', 'river', 'bank', '.', '[SEP]']
通過分詞後的token獲取詞表中對應的索引
indexed_tokens = tokenizer.convert_tokens_to_ids(tokenized_text) for tup in zip(tokenized_text, indexed_tokens): print (tup) ('[CLS]', 101) ('after', 2044) ('stealing', 11065) ('money', 2769) ('from', 2013) ('the', 1996) ('bank', 2924) ('vault', 11632) (',', 1010) ('the', 1996) ('bank', 2924) ('robber', 27307) ('was', 2001) ('seen', 2464) ('fishing', 5645) ('on', 2006) ('the', 1996) ('mississippi', 5900) ('river', 2314) ('bank', 2924) ('.', 1012) ('[SEP]', 102)
2.生成句子的位置編碼,bert以一個或者兩個句子作為輸入,要對句子進行處理,獲取他們的位置編碼。
segments_ids = [1] * len(tokenized_text) print (segments_ids) [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
3.
接下來,我們需要將資料轉換為torch張量並呼叫BERT模型。BERT PyTorch介面要求資料使用torch張量而不是Python列表,所以我們在這裡轉換列表——這不會改變形狀或資料。
eval()將我們的模型置於評估模式,而不是訓練模式。在這種情況下,評估模式關閉了訓練中使用的dropout正則化。
呼叫
from_pretrained
將從網上獲取模型。當我們載入 bert-base-uncased
時,我們會在日誌中看到列印的模型定義。該模型是一個12層的深度神經網路!
# Convert inputs to PyTorch tensors tokens_tensor = torch.tensor([indexed_tokens]) segments_tensors = torch.tensor([segments_ids]) # Load pre-trained model (weights) model = BertModel.from_pretrained('bert-base-uncased') # Put the model in "evaluation" mode, meaning feed-forward operation. model.eval()
4.接下來,讓我們獲取網路的隱藏狀態。encode_layers隱藏狀態是一個四維的張量,分別是隱藏層的層數、batch(批處理的大小)、一個輸入的句子(一個樣本),句子中每個token的編碼(768維的向量)
torch.no_grad禁用梯度計算,節省記憶體,並加快計算速度(我們不需要梯度或反向傳播,因為我們只是執行向前傳播)。
# Predict hidden states features for each layer with torch.no_grad(): encoded_layers, _ = model(tokens_tensor, segments_tensors)
print ("Number of layers:", len(encoded_layers)) layer_i = 0 print ("Number of batches:", len(encoded_layers[layer_i])) batch_i = 0 print ("Number of tokens:", len(encoded_layers[layer_i][batch_i])) token_i = 0 print ("Number of hidden units:", len(encoded_layers[layer_i][batch_i][token_i])) Number of layers: 12 Number of batches: 1 Number of tokens: 22 Number of hidden units: 768
5.對獲取的隱藏狀態進行重構,獲取的token_embeddings是一個三維的張量,是一個樣本中每個token在神經網路每一層對應的編碼,對應的維度分別是句子中的token個數,神經網路的層數,每個token對應的編碼。
[# tokens, # layers, # features] # Convert the hidden state embeddings into single token vectors # Holds the list of 12 layer embeddings for each token # Will have the shape: [# tokens, # layers, # features] token_embeddings = [] # For each token in the sentence... for token_i in range(len(tokenized_text)): # Holds 12 layers of hidden states for each token hidden_layers = [] # For each of the 12 layers... for layer_i in range(len(encoded_layers)): # Lookup the vector for `token_i` in `layer_i` vec = encoded_layers[layer_i][batch_i][token_i] hidden_layers.append(vec) token_embeddings.append(hidden_layers) # Sanity check the dimensions: print ("Number of tokens in sequence:", len(token_embeddings)) print ("Number of layers per token:", len(token_embeddings[0])) Number of tokens in sequence: 22 Number of layers per token: 12
6.構建詞向量和句向量,詞向量是根據神經網路的最後四層來進行構建的,因為最後四層的效果最好,可以使用拼接的方式,也可以使用求和取平均的方式來獲取詞向量的編碼。句向量是是對每個token的倒數第二個隱藏層求平均,生成一個768長度的向量。具體程式碼見上面部落格連線。
總結,通過預訓練模型來獲取詞向量,就是先對句子分詞,根據token獲取詞表中對應的索引,之後再獲取位置編碼,將它們輸入到模型之中,(模型可以設定成評估模式,關閉訓練過程中的正則化,同時去掉反向傳播)模型就會返回每個隱藏層中的token的編碼,之後在對其進行處理,比如用最後四層的token編碼來計算最終的token表示。