先看现象。批量推理或训练时报错,提示 pad token id 未定义,或 padding 之后 attention mask 全为 1,输出长度异常。

真正麻烦的地方在于,几个原因的现象几乎一样。tokenizer 没有指定 pad_token。少数情况下是pad_token 与 eos_token 相同,模型分不清结束与填充。

少数情况下是左侧填充与右侧填充选错,生成结果错位。

不容易想到的是,自定义 tokenizer 未保存该字段。

动手时先把 pad_token 指向 eos_token 并保存

tokenizer.pad_token = tokenizer.eos_token; tokenizer.save_pretrained('./tok')

批量编码时显式指定填充方向

tokenizer.pad_token_side = 'left'

再往下确认 attention mask 正确

python -c "print(batch['attention_mask'][0][-10:])"

剩下的就是加载时传回同一份 tokenizer

tok = AutoTokenizer.from_pretrained('./tok')

同样的操作我在测试机上先走了一遍,线上只做验证过的部分。

怎么算真的好了,看的是同一批现象。批量推理不再报错,不同长度的输入生成的回答长度正常,填充位置被正确忽略,显存占用也没有异常上涨。

生成式模型通常要用左侧填充,右侧填充会让模型从填充符之后开始续写,输出看起来像乱码但不会报错。改动前把原配置备份一份,出问题能马上回滚,这比任何技巧都实用。

作者 9823189