您的位置首页 >要闻 > 人工智能 >

报错 batch must contain tensors,优先检查 PyTorch Dataset 的返回对象

在 PyTorch 使用 DataLoader 加载数据时报错 batch must contain tensors, numbers, dicts or lists; found object,最常见根源就是你的自定义 Dataset 的 __getitem__ 返回了自定义类实例,而不是 tensor、数字、字典、列表这几类 DataLoader 能自动 collate 的类型,DataLoader 的默认 default_collate 没办法识别普通 Python object,打包 batch 的时候直接抛出异常。很多同学写数据集时习惯封装样本到自己写的 Sample / ImageItem 类里,直接 return 这个实例,或者在读取图片、标注后返回 PIL Image、ndarray 之外的自定义对象,自己以为只是包装一下,却忽略了 collate 函数的限制;还有一种情况是数据读取出错,返回了 None,None 同样会被判定为非法 object。整套排查思路是先定位 Dataset 的返回值,打印 __getitem__ 返回的类型,把自定义对象拆解成基础类型,如果需要保留结构化信息,可以改成 tuple、dict,或者自己实现 collate_fn,再交给 DataLoader。下面把报错原理、复现代码、修复方案、排查步骤分开说明。

一、报错核心拆解

  • 报错本质:torch.utils.data.default_collate 遍历每一条样本,要求每个样本只能是 tensor、数字、dict、list、tuple;自定义 class、None、特殊包装对象都不行。
  • 高频触发场景:
  • Dataset __getitem__ return 自定义类实例。
  • 读取失败返回 None。
  • 返回的是第三方封装对象,不是原生类型。
  • 混入了无法序列化、无法堆叠的对象。
  • 区分:PIL Image、numpy array 本身不会触发这条报错,collate 会尝试转 tensor;但如果你把它们包进自己写的类再返回,就会触发。

二、错误写法与修复写法对照表

写法示例代码问题 / 方案
错误:返回自定义对象```python

class MySample:

def init(self, img, label):

self.img = img

self.label = label

def getitem(self, idx):

img, label = self.get_data(idx)

return MySample(img, label)

|方案 A:返回 tuple(最简单)|`return img_tensor, label_tensor`|适合只有图像+标签,顺序固定|

|方案 B:返回 dict(推荐)|`return {"image": img_tensor, "label": label_tensor}`|可读性强,后续加字段很方便|

|方案 C:自定义 collate_fn|在 DataLoader 传入 `collate_fn=my_collate`|必须保留自定义类时使用,自己实现打包逻辑|

三、完整排查与修复实操步骤

1. 单独调用 Dataset 的 `__getitem__`,打印返回值以及 `type()`,确认是不是自定义对象或者 None。

python

ds = MyDataset()

sample = ds[0]

print(type(sample))

  1. 如果是自定义类:优先重构,拆成 dict /tuple,把里面的属性拿出来作为字段,不要直接返回实例。
  2. 如果偶尔返回 None:增加判断,读取失败时跳过这条样本,或者抛出异常,不要让 None 流进 DataLoader。
  3. 如果业务上必须保留自定义对象:编写自己的 collate 函数,手动接收样本列表、批量堆叠 tensor,再封装成批量对象。
  4. 修改完成后,先用 DataLoader 拿一个 batch 测试:
  5. 如果还有问题,检查样本内部嵌套,不要在 dict /list 里面再塞自定义对象,嵌套元素依然要遵守 collate 规则。

loader = DataLoader(ds, batch_size=2) next(iter(loader))

四、简易自定义 collate_fn 模板

适合不想改 Dataset、一定要返回自定义类的场景:

def collate_fn(batch):

imgs = torch.stack([item.img for item in batch])

labels = torch.tensor([item.label for item in batch])

return {"image": imgs, "label": labels}

loader = DataLoader(dataset, batch_size=4, collate_fn=collate_fn)

五、高频踩坑清单

  • 只在训练循环里调试,不去单独测 Dataset,以为问题出在 DataLoader,实际源头在 __getitem__。
  • 偶尔有一张图片损坏,读取后得到 None,随机复现报错,很难稳定复现。
  • 嵌套结构里藏自定义对象:返回 {"data": MyObj()},外层是 dict,但内部字段非法,依然报错。
  • 使用第三方数据集封装库,直接返回库内部的样本对象,没有转成 tensor/dict。
  • 混用多进程 num_workers>0,多进程下报错栈更乱,优先设置 num_workers=0 定位问题。

【相关 FAQ】

问题 1:出现这个 batch must contain tensors 报错,是不是优先检查 Dataset 的返回内容?

回答 1:是的,绝大多数场景根源就是 Dataset 的 __getitem__ 返回了自定义对象,default_collate 无法处理;优先单独取出一条样本打印类型,而不是先去改 DataLoader 参数。

问题 2:Dataset 返回 PIL.Image 或者 numpy 数组,会不会触发这个 batch object 报错?

回答 2:正常不会,默认 collate 可以把 PIL Image、numpy array 转为 tensor;但如果你把 PIL Image 包进自己定义的类再返回,就会触发这条报错。

问题 3:如果业务必须返回自定义对象,除了修改 Dataset,还有别的办法吗?

回答 3:可以给 DataLoader 传入自定义 collate_fn,手动遍历 batch、提取属性、堆叠张量,避开 default_collate 的限制,这是保留自定义对象的备选方案。

问题 4:我只在开启 num_workers>0 的时候才出现这个报错,是不是 Dataset 返回对象的问题?

回答 4:大概率还是 Dataset 返回非法对象,多进程只是让报错更容易暴露;排查时建议先把 num_workers 设为 0,简化环境确认是不是样本返回值问题。

【参考资料】

[2026-11-08](PyTorch DataLoader default_collate 报错 found object 排查思路)PyTorch 论坛

[2026-10-21](自定义 Dataset 返回自定义类触发 collate 失败)掘金

[2026-09-12](torch.utils.data.default_collate 支持类型说明)PyTorch 官方文档

[2026-08-03](collate_fn 自定义实现,处理非常规样本结构)towardsdatascience

[2026-07-14](数据集读取异常返回 None,随机触发 DataLoader 报错)CSDN

【免责声明】

本文针对 PyTorch DataLoader collate 报错提供排查方案;不同 PyTorch 版本对 default_collate 的支持细节略有差异;自定义 collate_fn 需要自行处理梯度、设备、padding、异常样本,本文方案仅解决该报错,不保证训练流程、数据堆叠逻辑符合你的任务需求。