news 2026/10/1 2:41:48

对象检测数据集解析:以 D2L 香蕉检测数据集为例的数据加载与标注格式实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
对象检测数据集解析:以 D2L 香蕉检测数据集为例的数据加载与标注格式实战指南
  • 文档
  • 教程
  • 人工智能
  • 深度学习
  • NLP
  • 计算机视觉
  • 强化学习

【免费下载链接】d2l-en

Interactive deep learning book with multi-framework code, math, and discussions. Adopted at 500 universities from 70 countries including Stanford, MIT, Harvard, and Cambridge.

项目地址:https://gitcode.com/gh_mirrors/d2/d2l-en
点击查看免费下载

导读

目标检测任务需要"图像 + 物体类别 + 真实边界框(ground-truth bounding box)"三类信息的配套数据集,其数据组织方式与图像分类有着本质差异。本文以《动手学深度学习》(D2L)仓库中自带的香蕉检测数据集为核心,完整讲解该数据集的构建思路、下载方式、CSV 标注格式、read_data_bananas/BananasDataset/load_data_bananas三层数据加载管线,以及 mini-batch 中标签的填充(padding)机制,并结合 d2l/torch.py 与 d2l/mxnet.py 中的源码实现进行底层验证。读完本文,你将掌握目标检测数据集从标注文件到可训练DataLoader的完整组织范式,为后续阅读 SSD、R-CNN 等检测模型(如 chapter_computer-vision/ssd.md)打下数据基础。

为什么目标检测需要一个专门的小数据集

在图像分类领域,研究者习惯使用 MNIST、Fashion-MNIST 这类"小而标准"的数据集来快速验证模型。但在目标检测领域,并没有同等规模的标准小数据集——公开的检测数据集(如 VOC、COCO)体积大、标注复杂,不适合在教材和快速原型中反复加载。

为此,原文档作者采取了一个非常工程化的做法:人工构造一个 1000 张图片的香蕉检测数据集。具体流程是:

  1. 拍摄办公室里的免费香蕉照片;
  2. 通过对照片进行不同旋转、缩放,生成 1000 张香蕉图像;
  3. 将每张香蕉图像随机放置到某些背景图上;
  4. 为每张图像标注香蕉的边界框。

这种"合成 + 人工标注"的方式,让研究者可以在几乎零成本的前提下,获得一个包含完整目标(类别)与位置(边界框)监督信号的数据集,用于快速演示目标检测模型。需要强调的是,它只是一个简单的合成数据集,真实世界的数据集通常复杂得多。

数据集的下载:DATA_HUB 注册与 SHA-1 校验

在 D2L 中,所有可下载数据集都统一注册在d2l.DATA_HUB字典中,香蕉检测数据集也不例外:

#@save d2l.DATA_HUB['banana-detection'] = ( d2l.DATA_URL + 'banana-detection.zip', '5de26c8fce5ccdea9f91267273464dc968d20d72')

注册条目是一个二元组:第一项是完整下载地址(由d2l.DATA_URL拼接文件名得到),第二项是该压缩包的SHA-1 校验值。在 d2l/torch.py 中可以看到DATA_URL = 'http://d2l-data.s3-accelerate.amazonaws.com/',即文件最终指向banana-detection.zip的公开镜像。

SHA-1 校验值的作用体现在底层下载函数download中(见 d2l/torch.py):

  • 先检查本地缓存:若目标文件已存在于默认目录../data,则逐块(每次 1 MB)计算其 SHA-1 并与注册值比对,一致则直接复用,避免重复下载;
  • 不一致或文件不存在时,才通过requests.get重新下载。

随后的download_extract(见 d2l/torch.py)负责解压:根据扩展名区分.zip与.tar/.gz,解压到数据目录并返回解压后的文件夹路径。整个下载、校验、解压流程对用户完全透明,调用方只需一句d2l.download_extract('banana-detection')。

数据集目录结构与 CSV 标注格式

解压后的香蕉检测数据集采用训练集 / 验证集分离的目录结构:

banana-detection/ ├── bananas_train/ │ ├── label.csv # 训练集标注 │ └── images/ # 训练图像 └── bananas_val/ ├── label.csv # 验证集标注 └── images/ # 验证图像

每个子集的标注统一存放在label.csv中,以图像文件名为索引。每行记录包含 5 个数值,含义为:

字段含义
第 1 项目标类别索引(香蕉数据集全部图像只有香蕉一个类别,索引为 0)
第 2、3 项边界框左上角顶点的 $(x, y)$ 坐标
第 4、5 项边界框右下角顶点的 $(x, y)$ 坐标

需要特别说明的是,CSV 中的坐标以像素为单位,取值范围大致在 0 到 256 之间(对应 256×256 的图像边长)。而模型训练通常偏好归一化坐标,因此读取代码会在末尾统一除以 256(详见下文),将坐标缩放到 $[0, 1]$ 区间。

读取数据:read_data_bananas 的实现剖析

read_data_bananas(is_train)是数据管线的第一层,负责把 CSV 标注与图像文件读入内存。以 PyTorch 版本为例(见 d2l/torch.py):

#@save def read_data_bananas(is_train=True): """Read the banana detection dataset images and labels.""" data_dir = d2l.download_extract('banana-detection') csv_fname = os.path.join(data_dir, 'bananas_train' if is_train else 'bananas_val', 'label.csv') csv_data = pd.read_csv(csv_fname) csv_data = csv_data.set_index('img_name') images, targets = [], [] for img_name, target in csv_data.iterrows(): images.append(torchvision.io.read_image( os.path.join(data_dir, 'bananas_train' if is_train else 'bananas_val', 'images', f'{img_name}'))) # Here `target` contains (class, upper-left x, upper-left y, # lower-right x, lower-right y), where all the images have the same # banana class (index 0) targets.append(list(target)) return images, torch.tensor(targets).unsqueeze(1) / 256

代码的关键处理步骤:

  1. 延迟下载解压:通过d2l.download_extract('banana-detection')首次调用时自动下载并解压,之后命中本地缓存;
  2. 按is_train选择子集:True读取bananas_train/label.csv,False读取bananas_val/label.csv;
  3. 以img_name为索引:set_index('img_name')后逐行迭代,用图像文件名拼接出实际图片路径并读入;
  4. 坐标归一化:torch.tensor(targets).unsqueeze(1) / 256是关键一步——unsqueeze(1)在类别维后插入一个长度为 1 的维度(详见下一节"标签形状"),除以 256 则把像素坐标归一化到 $[0, 1]$。

在 MXNet 版本(见 d2l/mxnet.py)中,差异仅在于读图 API 换成image.imread,以及通过np.expand_dims(np.array(targets), 1) / 256完成同样的升维与归一化,整体逻辑完全一致。

标签形状 (batch, m, 5) 与非法框填充机制

为什么读取时要unsqueeze(1)升维?这与目标检测 mini-batch 的标签组织方式密切相关。在演示代码中:

#@tab all batch_size, edge_size = 32, 256 train_iter, _ = load_data_bananas(batch_size) batch = next(iter(train_iter)) batch[0].shape, batch[1].shape

运行后会得到两个形状:

  • 图像 mini-batch:(32, 3, 256, 256),即(batch size, 通道数, 高, 宽),与图像分类任务完全一致;
  • 标签 mini-batch:(32, m, 5),其中m是数据集中任意单张图像所能包含的最大边界框数量。

这里存在一个普遍性问题:mini-batch 计算要求 batch 内所有样本可通过拼接(concatenation)形成张量,但真实场景中不同图像的边界框数量往往不同。解决方案是填充(padding):图像边界框数量少于 $m$ 时,用"非法边界框"补齐到 $m$ 个。

每个边界框的标签是一个长度为 5 的数组:

  • 第 1 个元素是框内目标的类别,-1表示填充产生的非法边界框(区别于真实类别的非负索引);
  • 后 4 个元素是左上角、右下角两顶点的 $(x, y)$ 坐标,取值范围 $[0, 1]$(已归一化)。

对香蕉数据集而言,每张图像恰好只有一个边界框,因此 $m = 1$,unsqueeze(1)后标签形状即为(batch, 1, 5)。以非法框-1作为类别占位符的设计,在后续基于锚框的目标检测实现(如 chapter_computer-vision/anchor.md 中assign_anchor_to_bbox的-1哨兵值)中一脉相承,是贯穿 D2L 检测章节的统一约定。

自定义 Dataset 与 DataLoader 封装

BananasDataset:把读取逻辑封装为标准 Dataset

第二层封装是继承框架标准 Dataset 基类的BananasDataset,其职责是让香蕉数据接入框架原生的数据加载体系:

#@tab pytorch #@save class BananasDataset(torch.utils.data.Dataset): """A customized dataset to load the banana detection dataset.""" def __init__(self, is_train): self.features, self.labels = read_data_bananas(is_train) print('read ' + str(len(self.features)) + (f' training examples' if is_train else f' validation examples')) def __getitem__(self, idx): return (self.features[idx].float(), self.labels[idx]) def __len__(self): return len(self.features)

要点:

  • __init__一次性调用read_data_bananas把全部图像与标签载入内存,并打印样本数量,方便确认训练集 / 验证集规模;
  • __getitem__返回(图像, 标签)对,PyTorch 版本把图像转为float32(MXNet 版本则先astype('float32')再transpose(2, 0, 1)把 HWC 转为 CHW),保证与模型输入约定一致;
  • __len__返回样本总数,供DataLoader计算迭代轮数。

load_data_bananas:一键返回训练 / 验证迭代器

第三层封装load_data_bananas(batch_size)组装出两个可直接用于训练循环的迭代器:

#@tab pytorch #@save def load_data_bananas(batch_size): """Load the banana detection dataset.""" train_iter = torch.utils.data.DataLoader(BananasDataset(is_train=True), batch_size, shuffle=True) val_iter = torch.utils.data.DataLoader(BananasDataset(is_train=False), batch_size) return train_iter, val_iter

细节值得注意:训练集迭代器开启shuffle=True以打乱样本顺序(随机梯度下降需要);验证集则保持顺序读取,shuffle取默认的False,便于结果复现与逐样本评估。该函数在 d2l/torch.py 与 d2l/mxnet.py 中均有完整实现,可直接from d2l import torch as d2l后调用。

可视化演示:展示图像与边界框

数据加载完成后,原文档用一个演示片段可视化 10 张图像及其真实边界框:

#@tab pytorch imgs = (batch[0][:10].permute(0, 2, 3, 1)) / 255 axes = d2l.show_images(imgs, 2, 5, scale=2) for ax, label in zip(axes, batch[1][:10]): d2l.show_bboxes(ax, [label[0][1:5] * edge_size], colors=['w'])

这里的处理链条是:

  1. permute(0, 2, 3, 1)(MXNet 用transpose(0, 2, 3, 1))把 CHW 换回 HWC 以便绘制,并除以 255 把像素值归一化到 $[0, 1]$;
  2. d2l.show_images(imgs, 2, 5, scale=2)将 10 张图排成 2 行 5 列展示;
  3. 对每张图的标签label[0][1:5]取出归一化的边界框坐标,乘以edge_size = 256还原为像素坐标,再调用d2l.show_bboxes绘制白色边界框(底层实现见 d2l/torch.py,核心是bbox_to_rect生成 matplotlib Rectangle 并axes.add_patch)。

从可视化结果可以看到,10 张图片中香蕉的旋转角度、尺寸和摆放位置各不相同——这正体现了数据集构造时引入的多样性,也说明它是一个便于调试检测流程的合成数据集。仓库中的 img/banana.jpg 即属于该类香蕉素材,在 chapter_computer-vision/ssd.md 中还被用作训练完成后推理演示的输入图片。

总结

回顾本文核心结论:

  • 香蕉检测数据集由 D2L 团队人工构造(1000 张、单一类别、每图一个边界框),用于快速演示目标检测模型,可从互联网直接下载,并通过注册在d2l.DATA_HUB中的 SHA-1 校验值保证数据完整性;
  • 数据加载流程与图像分类相似:同样经过"读图 → 封装 Dataset → 构造 DataLoader"的管线;但目标检测的标签额外携带真实边界框坐标,这是图像分类标签所不具备的;
  • 标签统一组织为(batch, m, 5)张量:坐标归一化到 $[0, 1]$,第 1 维类别中-1用作填充非法边界框的哨兵值,保证变长标注可以拼成定长 mini-batch;
  • 坐标系约定:CSV 原始坐标以像素为单位,读取时除以edge_size(256)完成归一化,可视化时再反向乘以边长还原。

动手练习

  1. 展示更多样本:修改演示代码,随机选取香蕉数据集中其他图像并绘制真实边界框,观察不同图像的边界框与物体外观差异(如旋转角度、遮挡、背景干扰)。
  2. 思考数据增强的差异:若要对目标检测应用随机裁剪等数据增强,它与图像分类中的数据增强有何不同?提示:裁剪后的图像如果只包含物体的一小部分,边界框标注应当如何处理(例如保留、调整还是丢弃)?这一问题的工程答案会在 SSD 等检测模型的数据加载实现(见 chapter_computer-vision/ssd.md)中体现。
  • 文档
  • 教程
  • 人工智能
  • 深度学习
  • NLP
  • 计算机视觉
  • 强化学习

【免费下载链接】d2l-en

Interactive deep learning book with multi-framework code, math, and discussions. Adopted at 500 universities from 70 countries including Stanford, MIT, Harvard, and Cambridge.

项目地址:https://gitcode.com/gh_mirrors/d2/d2l-en
点击查看免费下载

相关推荐

上一篇:华硕ROG屏幕突然发白、色彩配置文件丢失?G-Helper 2分钟修复显示颜色教程
下一篇:3000枚免费生物科学矢量图标:Bioicons 让科研插图不再从零手绘

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/1 2:40:21

anacoda虚拟环境管理

一、概述Anaconda 是一款专为数据科学、机器学习和人工智能领域设计的开源 Python/R 语言发行版。集成了 Python 解释器、Conda 包管理器、数百个预装的数据科学库(如 NumPy、Pandas、Jupyter Notebook 等)以及可视化管理工具。二、核心优势环境隔离&…

作者头像 李华
网站建设 2026/10/1 2:40:18

多用户商城架构实战:微服务拆分与高并发一致性设计

多用户商城这个场景,大概是Java技术栈里最能体现“全家桶”价值的项目了。用户、商品、订单、库存、支付、营销、物流、售后,每一个模块拆出来都能单独写一本书,合在一起又是一张复杂的依赖网。我用Spring Boot Spring Cloud MyBatis Redi…

作者头像 李华
网站建设 2026/10/1 2:38:25

小波阈值降噪实战:SNR与MSE指标解析及Python实现

简介:这份资源面向信号处理、图像去噪方向的学习者与工程人员,围绕小波阈值降噪展开,重点解决如何通过小波分解与阈值处理抑制噪声,并用信噪比(SNR)与均方误差(MSE)量化评估降噪效果…

作者头像 李华