以下代码没有批处理:
from transformers import GPT2LMHeadModel, GPT2Tokenizer
import torch
tokenizer = GPT2Tokenizer.from_pretrained("gpt2")
model = GPT2LMHeadModel.from_pretrained('gpt2')
model.eval()
context=torch.tensor([tokenizer.encode("This is")])
output, past = model(context)
token = torch.argmax(output[..., -1, :])
print(tokenizer.decode(token.item()))
output: ' a'
这工作正常。现在,我将其扩展到批处理设置:
from transformers import GPT2LMHeadModel, GPT2Tokenizer
import torch
tokenizer = GPT2Tokenizer.from_pretrained("gpt2")
model = GPT2LMHeadModel.from_pretrained('gpt2')
model.eval()
context=[torch.tensor(tokenizer.encode("This is ")),torch.tensor(tokenizer.encode("Hello How are "))]
context=pad_sequence(context,batch_first=True)
mask=torch.tensor([[1,1,0],[1,1,1]])
output, past = model(context,attention_mask=mask)
token = torch.argmax(output[..., -1, :],dim=1)
tokenizer.decode(token)
output: '\n you'
这\n
是第一个上下文you
的下一个标记,是批次的第二个上下文的下一个标记。但是第一个上下文的预期下一个标记是a
,因为所有设置都是相同的。此外,如果您将第二个上下文减少到 2 个令牌,您将获得a
此批处理设置。很明显,模型无法理解填充。此外,注意面具不起作用。因为,在填充序列的下一个标记之后this is
是 0(零)。并且根据注意[1,1,0]
掩码(这种注意力屏蔽不起作用的证据是:this
is
使用注意掩码 [1,1,1],这意味着即使在填充零上也参加,您会得到相同的输出,即
\n
.使用字符串
this is!
。这里!
有词汇矩阵中的零索引。你再次得到相同的输出,即\n
.
只有时间,才有可能在没有批处理设置和注意掩码的情况下获得理想的输出(现在看来,这并不重要,因为它无论如何都没有效果)
然后我发现了这个,它建议使用pad_token。所以我使用如下:
from transformers import GPT2LMHeadModel, GPT2Tokenizer
import torch
from torch.nn.utils.rnn import pad_sequence
tokenizer = GPT2Tokenizer.from_pretrained("gpt2",pad_token="<PAD>")
model = GPT2LMHeadModel.from_pretrained('gpt2')
model.eval()
context=[torch.tensor(tokenizer.encode("This is <PAD> ")),torch.tensor(tokenizer.encode("Hello How are"))]
context=torch.stack(context)
print(context)
mask=torch.tensor([[1,1,0],[1,1,1]])
output, past = model(context,attention_mask=mask)
token = torch.argmax(output[..., -1, :],dim=1)
tokenizer.decode(token)
output: 'The you'
这The
是第一个上下文you
的下一个标记,是批次的第二个上下文的下一个标记。这也行不通。因为The
不是第一个上下文的预期。
如何在 gpt/gpt2 模型的批量设置中使用可变长度序列?