參考博客: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表示。
