1 问题描述

我尝试对 Qwen2.5-0.5B-Instruct 进行 SFT,封装了 DataLoader 后模型在运行的时候报错:ValueError: Cannot handle batch sizes > 1 if no padding token is defined.

2 解决方案

问题报错的内容是当 batch sizes > 1pad_token 没有定义,所以采用以下步骤排查问题:

步骤1:先排查是不是 tokenizer 的问题,最简单的思路就是先打印出来 DataLoader 中的 input_idsatt_masksshape

步骤2:如果 input_idsatt_masksshape 不对,那么检查 tokenizerpadding 的代码对不对,很有可能在做 padding 的时候只对单句做了处理,如:

 inputs = self.tokenizer(
     text,
     truncation=True,
     padding=True,
     max_length=self.max_length,
     return_tensors='pt'
 )

而上述代码有个问题,如果 Dataset 是采用 __getitem__ 的方式实现的,那么实际上是一次只抽取一条数据做 padding,这里需要把上述代码改为:

 inputs = self.tokenizer(
     text,
     truncation=True,
     padding='max_length',
     max_length=self.max_length,
     return_tensors='pt'
 )

从而保证 padding 的长度是固定的。

步骤3:如果上述代码是正确的,那么再排查是不是 tokenizer 的问题,采用下述代码排查:

print(tokenizer.pad_token)
print(tokenizer.pad_token_id)

检查这两个是否为 None,如果为 None,说明是 tokenizer 在加载预训练参数时没有加载 pad_token 或者根本没有,那么可以采用下述方法设置:

tokenizer.pad_token = tokenizer.eos_token

如果 tokenizer 也没有 eos_token,那么可以自定义 pad_token

tokenizer.add_special_tokens({'pad_token': '[PAD]'})

步骤4:如果上述排查都没问题,那么继续排查 model 的问题,首先用下述代码排查:

# 注意这里的 model 指的是模型本身, 比如 Qwen2ForSequenceClassification
# 而非自己定义的 model 这个类
# 而且这里的 model 是 from_pretrained 加载后的
print(self.model.config.pad_token_id)

如果步骤1-3都没问题,那么理论上这里 print 出来的结果会为 None。接着只需要在模型 from_pretrained 之后加上如下代码即可:

self.model.config.pad_token_id = tokenizer.pad_token_id

3 问题产生原因

由于我没有在网上找到原因,我个人觉得该问题产生是因为 LLM 默认只处理单句任务,所以当模型加载后不会额外加载 pad_token_id。而 tokenizer 在处理数据的时候会给句子进行 padding,而没有加载 pad_token_id 的模型不认识这些 pad_token,所以导致的报错。

反正就我个人而言我觉得这个问题真的欺诈性太强了,我一直以为是我自己 tokenizer 或者 DataLoader 的问题,排查了好久TAT

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐