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 定义,再回到组批检查。


