来源:Github
作者:huggingface
编译:VK
理念
该库的设计有两个强烈的目标:
from_pretrained()
实例化方法从预训练实例以简单统一的方式初始化,该方法将负责从库中下载,缓存和加载相关类提供的预训练模型或你自己保存的模型。其他几个目标:
主要概念
该库是建立在三个类型的类为每个模型:
所有这些类都可以从预训练模型来实例化,并使用两种方法在本地保存:
from_pretraining()
允许您从一个预训练版本实例化一个模型/配置/tokenizer,这个预训练版本可以由库本身提供(目前这里列出了27个模型),也可以由用户在本地(或服务器上)存储,save_pretraining()
允许您在本地保存模型/配置/tokenizer,以便可以使用from_pretraining()
重新加载它。我们将通过一些简单的快速启动示例来完成这个快速启动之旅,看看如何实例化和使用这些类。其余的文件分为两部分:
快速入门:使用
这里有两个例子展示了一些Bert和GPT2类以及预训练模型。
有关每个模型类的示例,请参阅完整的API参考。
让我们首先使用BertTokenizer
从文本字符串准备一个标记化的输入(要输入给BERT的标记嵌入索引列表)
import torch
from transformers import BertTokenizer, BertModel, BertForMaskedLM
# 可选:如果您想了解发生的信息,请按以下步骤logger
import logging
logging.basicConfig(level=logging.INFO)
# 加载预训练的模型标记器(词汇表)
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
# 标记输入
text = "[CLS] Who was Jim Henson ? [SEP] Jim Henson was a puppeteer [SEP]"
tokenized_text = tokenizer.tokenize(text)
# 用“BertForMaskedLM”掩盖我们试图预测的标记`
masked_index = 8
tokenized_text[masked_index] = '[MASK]'
assert tokenized_text == ['[CLS]', 'who', 'was', 'jim', 'henson', '?', '[SEP]', 'jim', '[MASK]', 'was', 'a', 'puppet', '##eer', '[SEP]']
# 将标记转换为词汇索引
indexed_tokens = tokenizer.convert_tokens_to_ids(tokenized_text)
# 定义与第一句和第二句相关的句子A和B索引(见论文)
segments_ids = [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1]
# 将输入转换为PyTorch张量
tokens_tensor = torch.tensor([indexed_tokens])
segments_tensors = torch.tensor([segments_ids])
让我们看看如何使用BertModel
在隐藏状态下对输入进行编码:
# 加载预训练模型(权重)
model = BertModel.from_pretrained('bert-base-uncased')
# 将模型设置为评估模式
# 在评估期间有可再现的结果这是很重要的!
model.eval()
# 如果你有GPU,把所有东西都放在cuda上
tokens_tensor = tokens_tensor.to('cuda')
segments_tensors = segments_tensors.to('cuda')
model.to('cuda')
#预测每个层的隐藏状态特征
with torch.no_grad():
# 有关输入的详细信息,请参见models文档字符串
outputs = model(tokens_tensor, token_type_ids=segments_tensors)
# Transformer模型总是输出元组。
# 有关所有输出的详细信息,请参见模型文档字符串。在我们的例子中,第一个元素是Bert模型最后一层的隐藏状态
encoded_layers = outputs[0]
# 我们已将输入序列编码为形状(批量大小、序列长度、模型隐藏维度)的FloatTensor
assert tuple(encoded_layers.shape) == (1, len(indexed_tokens), model.config.hidden_size)
以及如何使用BertForMaskedLM
预测屏蔽的标记:
# 加载预训练模型(权重)
model = BertForMaskedLM.from_pretrained('bert-base-uncased')
model.eval()
# 如果你有GPU,把所有东西都放在cuda上
tokens_tensor = tokens_tensor.to('cuda')
segments_tensors = segments_tensors.to('cuda')
model.to('cuda')
# 预测所有标记
with torch.no_grad():
outputs = model(tokens_tensor, token_type_ids=segments_tensors)
predictions = outputs[0]
# 确认我们能预测“henson”
predicted_index = torch.argmax(predictions[0, masked_index]).item()
predicted_token = tokenizer.convert_ids_to_tokens([predicted_index])[0]
assert predicted_token == 'henson'
下面是一个快速开始的例子,使用GPT2Tokenizer和GPT2LMHeadModel类以及OpenAI的预训练模型来预测文本提示中的下一个标记。
首先,让我们使用GPT2Tokenizer
import torch
from transformers import GPT2Tokenizer, GPT2LMHeadModel
# 可选:如果您想了解发生的信息,请按以下步骤logger
import logging
logging.basicConfig(level=logging.INFO)
# 加载预训练模型(权重)
tokenizer = GPT2Tokenizer.from_pretrained('gpt2')
# 编码输入
text = "Who was Jim Henson ? Jim Henson was a"
indexed_tokens = tokenizer.encode(text)
# 转换为PyTorch tensor
tokens_tensor = torch.tensor([indexed_tokens])
让我们看看如何使用GPT2LMHeadModel
生成下一个跟在我们的文本后面的token:
# 加载预训练模型(权重)
model = GPT2LMHeadModel.from_pretrained('gpt2')
# 将模型设置为评估模式
# 在评估期间有可再现的结果这是很重要的!
model.eval()
# 如果你有GPU,把所有东西都放在cuda上
tokens_tensor = tokens_tensor.to('cuda')
model.to('cuda')
# 预测所有标记
with torch.no_grad():
outputs = model(tokens_tensor)
predictions = outputs[0]
# 得到预测的下一个子词(在我们的例子中,是“man”这个词)
predicted_index = torch.argmax(predictions[0, -1, :]).item()
predicted_text = tokenizer.decode(indexed_tokens + [predicted_index])
assert predicted_text == 'Who was Jim Henson? Jim Henson was a man'
每个模型架构(Bert、GPT、GPT-2、Transformer XL、XLNet和XLM)的每个模型类的示例,可以在文档中找到。
以及其他一些模型(GPT、XLNet、Transfo XL、CTRL),使用past
或mems
属性,这些属性可用于防止在使用顺序解码时重新计算键/值对。它在生成序列时很有用,因为注意力机制的很大一部分得益于以前的计算。
下面是一个使用带past
的GPT2LMHeadModel
和argmax解码的完整工作示例(只能作为示例,因为argmax decoding引入了大量重复):
from transformers import GPT2LMHeadModel, GPT2Tokenizer
import torch
tokenizer = GPT2Tokenizer.from_pretrained("gpt2")
model = GPT2LMHeadModel.from_pretrained('gpt2')
generated = tokenizer.encode("The Manhattan bridge")
context = torch.tensor([generated])
past = None
for i in range(100):
print(i)
output, past = model(context, past=past)
token = torch.argmax(output[..., -1, :])
generated += [token.tolist()]
context = token.unsqueeze(0)
sequence = tokenizer.decode(generated)
print(sequence)
由于以前所有标记的键/值对都包含在past
,因此模型只需要一个标记作为输入。
编码器-解码器架构需要两个标记化输入:一个用于编码器,另一个用于解码器。假设我们想使用Model2Model
进行生成性问答,从标记将输入模型的问答开始。
import torch
from transformers import BertTokenizer, Model2Model
# 可选:如果您想了解发生的信息,请按以下步骤logger
import logging
logging.basicConfig(level=logging.INFO)
# 加载预训练模型(权重)
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
# 编码输入(问题)
question = "Who was Jim Henson?"
encoded_question = tokenizer.encode(question)
# 编码输入(答案)
answer = "Jim Henson was a puppeteer"
encoded_answer = tokenizer.encode(answer)
# 将输入转换为PyTorch张量
question_tensor = torch.tensor([encoded_question])
answer_tensor = torch.tensor([encoded_answer])
让我们看看如何使用Model2Model
获取与此(问题,答案)对相关联的loss值:
#为了计算损失,我们需要向解码器提供语言模型标签(模型生成的标记id)。
lm_labels = encoded_answer
labels_tensor = torch.tensor([lm_labels])
# 加载预训练模型(权重)
model = Model2Model.from_pretrained('bert-base-uncased')
# 将模型设置为评估模式
# 在评估期间有可再现的结果这是很重要的!
model.eval()
# 如果你有GPU,把所有东西都放在cuda上
question_tensor = question_tensor.to('cuda')
answer_tensor = answer_tensor.to('cuda')
labels_tensor = labels_tensor.to('cuda')
model.to('cuda')
# 预测每个层的隐藏状态特征
with torch.no_grad():
# 有关输入的详细信息,请参见models文档字符串
outputs = model(question_tensor, answer_tensor, decoder_lm_labels=labels_tensor)
# Transformers模型总是输出元组。
# 有关所有输出的详细信息,请参见models文档字符串
# 在我们的例子中,第一个元素是LM损失的值
lm_loss = outputs[0]
此损失可用于对Model2Model的问答任务进行微调。假设我们对模型进行了微调,现在让我们看看如何生成答案:
# 让我们重复前面的问题
question = "Who was Jim Henson?"
encoded_question = tokenizer.encode(question)
question_tensor = torch.tensor([encoded_question])
# 这次我们试图生成答案,所以我们从一个空序列开始
answer = "[CLS]"
encoded_answer = tokenizer.encode(answer, add_special_tokens=False)
answer_tensor = torch.tensor([encoded_answer])
# 加载预训练模型(权重)
model = Model2Model.from_pretrained('fine-tuned-weights')
model.eval()
# 如果你有GPU,把所有东西都放在cuda上
question_tensor = question_tensor.to('cuda')
answer_tensor = answer_tensor.to('cuda')
model.to('cuda')
# 预测所有标记
with torch.no_grad():
outputs = model(question_tensor, answer_tensor)
predictions = outputs[0]
# 确认我们能预测“jim”
predicted_index = torch.argmax(predictions[0, -1]).item()
predicted_token = tokenizer.convert_ids_to_tokens([predicted_index])[0]
assert predicted_token == 'jim'