您的示例产生了以下输出,并且在我的环境中完成了 282 名候选人大约需要 48.5 秒(我只进行了 3 次运行):
{'watch': -5.406847953796387
, 'run': -5.533411502838135
, 'think': -4.525279521942139
, 'apple': -6.158637046813965
, 'light': -5.835141658782959}
正如 cmets 中所述,我认为您可以使用 past 参数和快速 tokenizer 进行一些计算,如下面的注释示例所示:
import torch
from transformers import GPT2TokenizerFast, GPT2LMHeadModel
from torch.nn import CrossEntropyLoss
model = GPT2LMHeadModel.from_pretrained("gpt2")
model.eval()
tokenizer = GPT2TokenizerFast.from_pretrained("gpt2")
###We calculate the hidden_states and the past of the common left part of the sentence
past = "I like sitting in my new chair and"
past_tokenize_input = tokenizer.tokenize(past)
past_tensor_input = torch.tensor([tokenizer.convert_tokens_to_ids(past_tokenize_input)])
past_last_hidden_state, past = model.transformer(past_tensor_input)
def score(sentence, past, past_last_hidden_state, past_tensor_input):
tokenize_input = tokenizer.tokenize(sentence, )
tensor_input = torch.tensor([tokenizer.convert_tokens_to_ids(tokenize_input)])
###the following code is slightly modified from https://github.com/huggingface/transformers/blob/09a2f40684f77e62d0fd8485fe9d2d610390453f/src/transformers/modeling_gpt2.py#L604
###now we calculate the right part of the sentence with the already calculated past
transformer_outputs = model.transformer(
tensor_input,
past=past,
attention_mask=None,
token_type_ids=None,
position_ids=None,
head_mask=None,
inputs_embeds=None,
use_cache=None,
output_attentions=None,
output_hidden_states=None,
)
###and concatenate the output of with the hidden_state of the left part of the sentence
hidden_states = torch.cat((past_last_hidden_state, transformer_outputs[0]), dim=1)
###the following part is exactly the same as https://github.com/huggingface/transformers/blob/09a2f40684f77e62d0fd8485fe9d2d610390453f/src/transformers/modeling_gpt2.py#L604
lm_logits = model.lm_head(hidden_states)
labels_input = torch.cat((past_tensor_input, tensor_input), dim=1)
# Shift so that tokens < n predict n
shift_logits = lm_logits[..., :-1, :].contiguous()
shift_labels = labels_input[..., 1:].contiguous()
# Flatten the tokens
loss_fct = CrossEntropyLoss()
loss = loss_fct(shift_logits.view(-1, shift_logits.size(-1)), shift_labels.view(-1))
return -loss.item()
candidates = ["watch", "run", "think", "apple", "light"]
sent_template = " {} about life"
print({candidate: score(sent_template.format(candidate), past, past_last_hidden_state, past_tensor_input) for candidate in candidates})
输出:
{'watch': -5.406846046447754
, 'run': -5.533413887023926
, 'think': -4.525280952453613
, 'apple': -6.158637046813965
, 'light': -5.835141181945801}
这里的运行时间是 40.5 秒,有 282 个候选者(又是 3 个周期)。你也看到我失去了一些精确度。
非常感谢patrickvonplaten,他给了我一个很好的explanation 关于过去的实施。