背景
结束符是一个句子(prompt)的结尾标记,再大语言模型中,句子中的每个单词都会被编码成数字才能被模型处理。同样的,结尾标记也会被编码成一个数字。再Meta给的源码中,Llama3的结束符是-1(pad_id=-1,参考llama3/llama/tokenizer.py at main · meta-llama/llama3 (github.com))。transformers中现在是不支持pad_id=-1的,当同时给模型输入了多个句子(batch>1),我们就没法标记单个句子结束的地方。
解决办法
再Llama的源码中,我们看到向分词器(tokenizer模型)中添加了很多special_tokens,并且代码里也有用<|end_of_text|>、<|eot_id|>两个令牌来判断生成的句子是否结束。代码片段如下:
代码语言:txt复制self.tokenizer.stop_tokens = {
self.special_tokens["<|end_of_text|>"],
self.special_tokens["<|eot_id|>"],
}
out_tokens, out_logprobs = [], []
for i, toks in enumerate(tokens.tolist()):
# cut to max gen len
start = 0 if echo else len(prompt_tokens[i])
toks = toks[start : len(prompt_tokens[i]) max_gen_len]
probs = None
if logprobs:
probs = token_logprobs[i][start : len(prompt_tokens[i]) max_gen_len]
# cut to after eos tok if any
for stop_token in self.tokenizer.stop_tokens:
try:
eos_idx = toks.index(stop_token)
toks = toks[:eos_idx]
probs = probs[:eos_idx] if logprobs else None
except ValueError:
pass
out_tokens.append(toks)
out_logprobs.append(probs)
1. 我们可以直接把结束符设置为self.tokenizer.pad_token = "<|eot_id|>"
2. 也可以直接查看stop_tokens的id:
代码语言:txt复制pad_id = self.tokenizer.convert_tokens_to_ids("<|eot_id|>")
self.tokenizer.pad_token_id = pad_id