快速结论:这个报错通常出现在对多模态(含图片)提示词做左填充(left padding)后调用 generate 的场景,且当填充后的总长度满足 total_padded_length % 32 == 1 时触发。优先排查填充后总长度是否命中该条件,并对比同一序列在无填充与有填充下的 prefill logits。
适用环境:Issue 中确认环境为 transformers 5.13.1 / 5.14.1(两者结果相同),Python 3.12.13,PyTorch 2.12.0+cu130,单张 NVIDIA RTX PRO 6000 Blackwell Workstation Edition,bf16,SDPA 注意力,模型为 google/gemma-4-12B-it,device_map=”auto”,未使用分布式或并行设置。
最快修复方案:暂无确认的一步修复方案。Issue 中只给出了定位结果(触发条件为填充后总长度满足 % 32 == 1)以及一套待执行的隔离诊断计划,没有已验证通过并合并的代码修复。
注意事项:不要直接把“对 sequence_length % 32 做永久特判”当作正式修复;维护者明确表示在定位到首个错误发生的环节(多模态准备、mask 构造或 PyTorch SDPA 后端)之前,不应急于加这种特殊情况处理。该问题只在含图片输入时复现,纯文本提示在已测试的各个填充长度下未受影响。
问题场景
使用 Gemma4UnifiedForConditionalGeneration(google/gemma-4-12B-it,bf16,SDPA)对多模态提示词(282 个 token,含一张图片)做左填充后进行生成。当填充长度为 7(即填充后总长度为 289)时,prefill logits 出现异常;后续定位表明真正的触发条件不是“填充长度为 7”,而是填充后总长度满足 total_padded_length % 32 == 1。该现象在 batch=1 与 batch=2 左填充批次中一致复现,未填充的那一行保持正常。用户侧表现为:greedy 生成在填充行上静默输出退化的描述式文本,而不是正常的指令跟随回复,容易误认为是采样波动。
报错原文
Major Bug in parallel generation / left padding.
B. padded, batch=1, pad=6 max|dLogit|= 0.5000 mean=0.13692 argmax_flipped=False
B. padded, batch=1, pad=7 max|dLogit|= 40.1875 mean=11.57746 argmax_flipped=True
solo top5: 'I':27.25 'The':27.25 'You':22.62 'There':21.12 'In':21.00
this top5: '
原因分析
可能原因:填充后的总长度落在 % 32 == 1 这一对齐边界上时,模型内部某个环节(多模态特征插入、mask 构造、multimodal block/group ID 生成或所选 PyTorch SDPA 后端)对有效 token 的处理出现偏差,导致 prefill 阶段的 logits 被破坏。Issue 中已排除的项包括:
- 不是批次大小问题:batch=1 的 pad=7 与 batch=2 中较短行填充 7 的表现一致。
- 不是 collation 问题:input_ids、attention_mask、token type ids 都是同步填充,填充行后缀与单独编码逐字节一致,position_ids 跟随 attention mask。
- 不是渐进数值噪声:其他填充长度(1–6、8、9、15、16、63、64)都保持在 bf16 抖动范围内,只有命中
% 32 == 1时出现离散式跳变。 - 纯文本提示在所有已测填充长度下不受影响,图片输入是复现的必要条件。
截至 Issue 关闭时,首个错误值究竟源自 Gemma 4 的多模态准备、mask 构造还是 PyTorch SDPA 后端,尚未最终确定。
环境排查
- transformers 版本:确认是否为 5.13.1 或 5.14.1(两者在本脚本上逐位相同)。
- Python 版本:3.12.13。
- PyTorch 版本:2.12.0+cu130(CUDA),确认实际使用的注意力后端。
- 注意力实现:是否使用 SDPA;建议同时对比 eager 与 SDPA。
- 显卡:RTX PRO 6000 Blackwell;如有条件,在非 Blackwell 架构上交叉验证。
- 精度:bf16;建议同时用 float32 对比,以区分数值与结构性问题。
- 模型与处理器:
google/gemma-4-12B-it及其配套 processor。 - 输入类型:确认提示词是否包含图片;纯文本在已测长度下不复现。
- 填充后总长度:计算
total_padded_length % 32,确认是否等于 1。
解决步骤
- 先复现并确认触发条件:用相同提示词与图片,在 batch=1 下扫描填充长度,记录每个长度下的
max|dLogit|是否跳到 ~40 且 argmax 翻转;同时记录填充后总长度,确认触发点是否都满足total_padded_length % 32 == 1。 - 独立变化提示词长度与填充长度(例如分别覆盖 31、32、33;63、64、65;95、96、97;287、288、289、290),确认触发因素是“填充后总长度”而非“某个固定填充量”。
- 在 processor 输出层逐项对比填充与未填充:
input_ids、attention_mask、mm_token_type_ids、图片位置输入,确认有效 token 的一一对应关系是否被破坏。 - 在多模态准备阶段对比:投影后的图片特征、图片占位符 mask、插入图片特征后的 embedding、以及(如可开启)每层输入,定位是否在进入语言模型前就已经出现差异。
- 在位置与 mask 准备阶段对比:有效 token 的
position_ids、生成的多模态 block 序列 ID、全局 attention mask、滑动窗口 attention mask。 - 若 embedding 与 mask 在有效 token 坐标上等价,则固定同一组 Q、K、V 与完全物化的 attention mask,分别用 eager、SDPA 以及支持的各个 SDPA 后端、bf16 与 float32 对比,判断问题是否可缩减为独立的 PyTorch SDPA 复现。
- 根据以上结果确定修复层级:若差异出现在语言模型之前,修多模态特征插入或序列对齐元数据;若等价有效 token 坐标上的 mask 不一致,修 padding-aware 的 mask 或 block ID 构造;若 eager 正确而 SDPA 错误,向 PyTorch 上游提交最小复现;若两者都失败,则将修复限制在 Gemma 4 模型路径内。
- 在定位完成前,如需临时缓解,应严格限定在已确认受影响的后端/设备/dtype/路径上,仅作用于受影响的多模态 prefill,通过一次性警告显式提示,并在合入上游修复后可移除;不要在模型配置上做全局改动,以免影响并发请求的线程安全。
验证方法
对同一非填充 token 序列与多模态输入,加上被 mask 的左填充后,应满足:多模态特征位置、有效 token 的 position IDs、多模态 block/group IDs、有效 token 间的注意力可见性、最终 token logits(除 dtype 级数值抖动外)以及确定性 greedy 输出均不发生实质变化。具体可检查填充与未填充下 max|dLogit| 回到 bf16 抖动水平(约 0.5–0.66),argmax 不再翻转,填充行的 greedy 输出与单独运行时一致。建议补充 fast deterministic unit test(基于 tiny Gemma 4 配置)以覆盖 % 32 == 1 附近的对齐边界,防止回归。
参考来源
huggingface/transformers #47651
AI 工具推荐
想把多个 AI 模型放在一个入口?
GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。
推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。
这个方案解决了吗?
可以继续搜索完整报错,或查看同一工具的其他排查指南。


