DEBUG.WIKI
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
雨云;给项目一台云服务器
RackNerd;$21.99/年 · 1GB KVM

Trainer 组批报 expected sequence of length,padding 为什么没生效

Trainer 组批时报张量长度不同,检查实际 collator 与输入、标签列。区分分类、token classification、seq2seq 和语言模型的补齐及损失掩码。

单条样本能取出,Trainer.train() 刚进入 DataLoader 就报错,堆栈停在 collator 或张量转换处:

ValueError: expected sequence of length 9 at dim 1 (got 33)
ValueError: Unable to create tensor

有时输入明明设置了 padding=True,报错却指向 labels。需要分清是哪一列没有对齐,以及当前 collator 会处理哪些列。下面以 Transformers 4.57.1、PyTorch 文本任务为范围,不覆盖图像 processor、TRL 的 SFTTrainer 或自定义 packing。

padding=True 只对当次编码的批次负责

预处理时使用 padding=True,通常补到那次 tokenizer 调用中最长的序列。若逐条编码,或者 Dataset.map() 分多批调用,不同批次仍可能有不同宽度。Trainer 后来重新组合这些样本,长度就又不同了。

固定长度补齐可使用 padding="max_length" 并设定合理的 max_length,但必须同时按模型容量限制输入。不要为了解决组批错误,把整份数据一律扩展到非常大的长度。动态补齐的做法是在组批时决定宽度。

对每条文本只有一个分类标签的任务,可以使用 DataCollatorWithPadding。下面假设 model、匹配加载的 tokenizer、training_args 和编码后的 train_dataset 已准备好;样本的 input_ids 是整数序列,labels 是合法的分类标签整数:

from transformers import DataCollatorWithPadding, Trainer

# 复用给当前模型编码数据的 tokenizer。
collator = DataCollatorWithPadding(tokenizer=tokenizer)

trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=train_dataset,
    processing_class=tokenizer,
    data_collator=collator,
)

4.57.1 的 Trainer 使用 processing_class;旧教程常使用 tokenizer 参数,不要混用两个名字。若既没有传 tokenizer 类型的处理对象,也没有显式设置 collator,默认 collator 只堆叠数据,不会替变长序列做补齐。

输入补齐了,序列标签仍可能变长

DataCollatorWithPadding 不是所有任务的标签补齐器。它能处理模型输入,却不会自动把任意长度的 labels 列补成一致宽度。先看报错提示的字段:

  • 文本分类标签通常每条一个整数;字符串标签需要先转换,配置 label2id 不能代替修改数据。
  • Token classification 的标签与输入 token 对齐,使用 DataCollatorForTokenClassification,并核对分词后的标签映射。
  • Encoder-decoder 的目标标签有自己的长度,使用 DataCollatorForSeq2Seq,同时做好输入和目标的 tokenization。
  • 普通 causal language modeling 可使用 DataCollatorForLanguageModeling(tokenizer, mlm=False);它从输入复制标签,适用于需要这类损失目标的任务。

最后一种用法应让数据只保留所需的模型输入,不携带手工制作、长度不齐的 labels,由 collator 创建标签。若只希望计算回答部分的损失,不能直接用“整段输入都参与损失”的设置替代原目标。4.57.1 的这个 collator 会将等于 PAD ID 的标签设为 -100;PAD 与 EOS 共用 ID 时,真实 EOS 也会被屏蔽,需要另行审查训练目标。

不要因为某个 collator 能消除异常,就认定它适合当前模型。更换 collator 可以改变标签和损失计算,训练能启动并不是充分验收。

用两条样本把输入和标签分开检查

排查时可先在模型训练前检查实际送入 collator 的少量样本。下面的 features 应来自与训练相同的编码与删列流程,避免拿一份已经固定补齐的数据代替出错的那份:

for index, sample in enumerate(features):
    print(index, {
        key: len(value) if isinstance(value, list) else type(value).__name__
        for key, value in sample.items()
    })

batch = collator(features)
for key, value in batch.items():
    print(key, getattr(value, "shape", None))

取两条不同 token 长度的样本,检查 input_ids 和 attention_mask 的形状是否相同;再按任务核对标签是每样本一个值,还是每 token 一个值。序列标签的补齐位置通常需要损失函数忽略,不能误当成实际监督 token。

如果最内层报错是 too many dimensions 'str',先检查残留的原始文本列和字符串标签;如果是嵌套层数过多,核对是否把单样本保存成了额外带一层 batch 的列表。Unable to create tensor 是外层提示,不能把它全部解释成缺少 padding。若报错明确是 tokenizer does not have a padding token,则先处理 tokenizer 的 PAD 定义,再回到组批检查。