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表示。