本文主要讲如何调用pytorch_transformers这个包来提取一个句子的特征。
pytorch_transformers Quickstart
pytorch_transformers包含BERT, GPT, GPT-2, Transfo-XL, XLNet, XLM 等多个模型,并提供了27 个预训练模型。
对于每个模型,pytorch_transformers库里都对应有三个类:
torch.nn.Modules
) of the 6 models architectures currently provided in the library, e.g. BertModel
BertConfig
. You don’t always need to instantiate these your-self, in particular if you are using a pretrained model without any modification, creating the model will automatically take care of instantiating the configuration (which is part of the model)BertTokenizer
简单来说,model classes是模型的网络结构,configuration classes是模型的相关参数,tokenizer classes是分词工具,一般建议直接使用from_pretrained()方法加载已经预训练好的模型或者参数。
from_pretrained()
let you instantiate a model/configuration/tokenizer from a pretrained version either provided by the library itself (currently 27 models are provided as listed here) or stored locally (or on a server) by the user,pytorch_transformers中的Bert说明文档
接下来讲解如何使用pytorch_transformers中的Bert模型。
先安装pytorch_transformers库
pip install pytorch_transformers
然后从pytorch_transformers库中导入Bert的上面所说到的3个类
from pytorch_transformers import BertModel, BertConfig,BertTokenizer
先是用BertTokenizer对输入文本进行处理,从预训练模型中加载tokenizer
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
如果无法访问外网,可以先把bert-base-uncased-vocab.txt 下载下来加载进去。本文最后提供下载链接。
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased-vocab.txt')
需要在文本开头加上’[CLS]’,在每个句子后面加上’[SEP]’,这样输入到BertModel中才能被正确识别。
text = "[CLS] Who was Jim Henson ? [SEP] Jim Henson was a puppeteer [SEP]"
tokenized_text = tokenizer.tokenize(text) #用tokenizer对句子分词
indexed_tokens = tokenizer.convert_tokens_to_ids(tokenized_text)#词在预训练词表中的索引列表
segments_ids = [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1]
#用来指定哪个是第一个句子,哪个是第二个句子,0的部分代表句子一, 1的部分代表句子二
#转换成PyTorch tensors
tokens_tensor = torch.tensor([indexed_tokens])
segments_tensors = torch.tensor([segments_ids])
tokens_tensor,segments_tensors将作为BertModel的输入。
很多时候输入文本是只有一个句子的,上面两个句子的情况只是简单提一下,下面主要是以一个句子为主。同样,先在句子前面加上’[CLS]’,后面加上’[SEP]’。一般神经网络提取文本特征是以batch为单位的,因此还需要用到一个输入input_masks,假设text是一个batch的数据。
texts = ["[CLS] Who was Jim Henson ? [SEP]",
"[CLS] Jim Henson was a puppeteer [SEP]"]
tokens, segments, input_masks = [], [], []
for text in texts:
tokenized_text = tokenizer.tokenize(text) #用tokenizer对句子分词
indexed_tokens = tokenizer.convert_tokens_to_ids(tokenized_text)#索引列表
tokens.append(indexed_tokens)
segments.append([0] * len(indexed_tokens))
input_masks.append([1] * len(indexed_tokens))
max_len = max([len(single) for single in tokens]) #最大的句子长度
for j in range(len(tokens)):
padding = [0] * (max_len - len(tokens[j]))
tokens[j] += padding
segments[j] += padding
input_masks[j] += padding
#segments列表全0,因为只有一个句子1,没有句子2
#input_masks列表1的部分代表句子单词,而后面0的部分代表paddig,只是用于保持输入整齐,没有实际意义。
#相当于告诉BertModel不要利用后面0的部分
#转换成PyTorch tensors
tokens_tensor = torch.tensor(tokens)
segments_tensors = torch.tensor(segments)
input_masks_tensors = torch.tensor(input_masks)
tokens_tensor,segments_tensors,input_masks_tensors 将作为BertModel的输入。
在BertModel后面加上一个全连接层,能够调整输出feature的维度。
class TextNet(nn.Module):
def __init__(self, code_length): #code_length为fc映射到的维度大小
super(TextNet, self).__init__()
modelConfig = BertConfig.from_pretrained('bert-base-uncased-config.json')
self.textExtractor = BertModel.from_pretrained(
'bert-base-uncased-pytorch_model.bin', config=modelConfig)
embedding_dim = self.textExtractor.config.hidden_size
self.fc = nn.Linear(embedding_dim, code_length)
self.tanh = torch.nn.Tanh()
def forward(self, tokens, segments, input_masks):
output=self.textExtractor(tokens, token_type_ids=segments,
attention_mask=input_masks)
text_embeddings = output[0][:, 0, :]
#output[0](batch size, sequence length, model hidden dimension)
features = self.fc(text_embeddings)
features=self.tanh(features)
return features
使用pytorch_transformers本身提供的预训练BertConfig,以及加载预训练模型。如果能访问外网,直接用
config = BertConfig.from_pretrained('bert-base-uncased')
self.textExtractor = BertModel.from_pretrained('bert-base-uncased', config=modelConfig)
否则还是像上面模型那样加载本地下载的预训练模型,下载链接在文末。
把输入到BertModel后得到的输出output,一般是使用它的第0维信息
outputs[0] # The last hidden-state is the first element of the output tuple
其中output[0][:,0,:]
代表下图中的C的输出向量,参考论文Bert
from pytorch_transformers import BertModel, BertConfig,BertTokenizer
#——————构造模型——————
class TextNet(nn.Module):
def __init__(self, code_length): #code_length为fc映射到的维度大小
super(TextNet, self).__init__()
modelConfig = BertConfig.from_pretrained('bert-base-uncased-config.json')
self.textExtractor = BertModel.from_pretrained(
'bert-base-uncased-pytorch_model.bin', config=modelConfig)
embedding_dim = self.textExtractor.config.hidden_size
self.fc = nn.Linear(embedding_dim, code_length)
self.tanh = torch.nn.Tanh()
def forward(self, tokens, segments, input_masks):
output=self.textExtractor(tokens, token_type_ids=segments,
attention_mask=input_masks)
text_embeddings = output[0][:, 0, :]
#output[0](batch size, sequence length, model hidden dimension)
features = self.fc(text_embeddings)
features=self.tanh(features)
return features
textNet = TextNet(code_length=32)
#——————输入处理——————
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased-vocab.txt')
texts = ["[CLS] Who was Jim Henson ? [SEP]",
"[CLS] Jim Henson was a puppeteer [SEP]"]
tokens, segments, input_masks = [], [], []
for text in texts:
tokenized_text = tokenizer.tokenize(text) #用tokenizer对句子分词
indexed_tokens = tokenizer.convert_tokens_to_ids(tokenized_text)#索引列表
tokens.append(indexed_tokens)
segments.append([0] * len(indexed_tokens))
input_masks.append([1] * len(indexed_tokens))
max_len = max([len(single) for single in tokens]) #最大的句子长度
for j in range(len(tokens)):
padding = [0] * (max_len - len(tokens[j]))
tokens[j] += padding
segments[j] += padding
input_masks[j] += padding
#segments列表全0,因为只有一个句子1,没有句子2
#input_masks列表1的部分代表句子单词,而后面0的部分代表paddig,只是用于保持输入整齐,没有实际意义。
#相当于告诉BertModel不要利用后面0的部分
#转换成PyTorch tensors
tokens_tensor = torch.tensor(tokens)
segments_tensors = torch.tensor(segments)
input_masks_tensors = torch.tensor(input_masks)
#——————提取文本特征——————
text_hashCodes = textNet(tokens, segments, input_masks) #text_hashCodes是一个32-dim文本特征
百度网盘链接:https://pan.baidu.com/s/1bpGS0HbmOoO-GH4cFWsVdw
我在做跨模态检索(根据文本句子检索图片)时用到Bert来提取句子特征,参考github代码
https://github.com/zhongzhh8/Cross-Modal-Retrieval