简介:面向图像分类与计算机视觉研究者,提供一套基于 Python 3 的 ImageNet 子集自助下载方案。核心脚本可指定类别数量和每类图片张数,自动从 ImageNet 图像 URL 中随机筛选并抓取样本,用于快速搭建训练集、验证集或进行小规模实验,尤其适合模型预训练前的数据检查、类别均衡测试以及教学演示。压缩包包含 7 个文件,从类型上看,既有可执行下载脚本,也有记录类别的文本清单、映射类别编号的 JSON 文件,以及 Markdown 格式的详细使用说明,整体仅 1.55MB,轻量且便于携带。附带 CSV 格式的 URL 状态统计表,可辅助判断当前链接可用比例,减少下载失败;README 中还说明了工具的编写思路,并分析 ImageNet 图片链接现状。已有 1000 人学习下载,适合有一定 Python 基础的数据科学学习者和开发者,能够节省手工筛选图片的时间,快速获得可用的自定义数据集。 做深度学习视觉项目的人,几乎都绕不开 ImageNet。但很多人对它是又爱又恨——想用,硬盘空间和下载时长不答应;不用,又总觉得做分类实验少了点什么。ImageNet-Datasets-Downloader 这个开源小工具,解决的就是这个扎心问题:按需从 ImageNet 拉取指定类别的图片,做一个完全自定义规模的数据集。我最初拿到这个工具是在做一个小样本分类实验,只需要 5 个类、每类几百张图,如果去拖全量数据,不但要准备几百 GB 空间,还要忍受漫长的下载和解压时间。而这个工具直接在命令行里就搞定了,适合迁移学习微调、少样本学习、模型快速验证这类场景,也适合刚入门想动手跑通一套训练流程的同学。
1. 为什么还需要一个 ImageNet 下载器
1.1 全量数据集的天坑
ImageNet 全量数据集体积惊人,ILSVRC2012 的压缩包就有 100 多 GB,解压之后训练集加验证集接近 150 GB。就算你的硬盘装得下,下载过程也极其折磨——很多人挂在半夜下载,第二天醒来发现某个分卷校验失败,只能重来。更麻烦的是,官方下载流程要先注册、同意条款,再通过校园邮箱或机构权限申请,个人想直接拿链接并不轻松。
全量数据对大多数场景其实是浪费的。你只是想测试一个新网络结构,或者做一次迁移学习实验,根本用不到一千个类、上百万张图。每张图都要经过解码、缩放、增强,数据加载反而成了训练瓶颈。这时如果能只下载目标类别的图片,整个过程就从“重型工程”变成了“轻量准备”。
1.2 按需抽取的真实场景
我遇到过几种情况,特别适合用这类工具:
- 做二分类或小规模多分类基线实验,比如动物和交通工具的区分;
- 验证一个新提出的数据增强策略,先用少量真实图片观察效果;
- 复现论文时,需要某个类子集的统计分布;
- 教学演示时,不想让学生一上来就面对几百 GB 的数据集。
这类场景的共同点是:类别可控、数据量可控、样本质量和格式尽量贴近 ImageNet。ImageNet-Datasets-Downloader 的思路正好对路——它通过指定 ImageNet 的 WordNet ID(wnid)来决定下载哪些类,再用参数控制每个类下载多少张图。
2. 先搞懂工具背后的数据组织:WordNet ID 与 ImageNet 对齐
2.1 Synset 是什么
ImageNet 的类别不是简单的字符串标签,而是 WordNet 中的 synset(同义词集),比如“狗”这个类对应一个 synset,它包含 dog、domestic dog、Canis familiaris 等多个同义表达。每个 synset 都有一个唯一的 ID 作为标识,这就是我们常说的 wnid,形如 n02084071。ImageNet 的很多类别标签都直接沿用这个 wnid,而不是重新设计一套编码体系。
这个设计带来一个好处:只要你会查 WordNet,就能在 ImageNet 里准确地找到所有下属类别,尤其是父子层级关系。比如狗是一个父类 synset,下面还细分了猎犬、牧羊犬、伴侣犬等子类,每个子类也都有各自的 wnid。下载时想要“全部狗类”还是“某一种狗”,取决于你选择哪一个层级的 synset。
2.2 如何快速定位你要的 wnid
目前最直接的方式是访问 ImageNet 官网的同步词表单页,按其类目浏览或用关键词搜索,页面会列出对应的 wnid。如果你想用程序化方式,可以访问 ImageNet 的 API 接口,比如用 synset 的 ID 获取同义词集信息和图片 URL 列表。另一个比较省事的办法是直接下载 ImageNet 官方提供的类别映射文件,里面包含了从 wnid 到类别描述文本的完整对应关系。
我自己常用的是先看 ILSVRC2012 的类别文件,因为它和目前多数视觉模型的输出类别完全一致。比如文件里第一行是 n01440764 tench,第二行是 n01443537 goldfish。你只需要打开这个文本文件,按关键词搜一下,就能拿到目标类别的 wnid。这里要特别提醒:ImageNet 的类别名和日常自然语言并不完全一致,比如“猫”在 WordNet 里可能对应多个 synset,比如 domestic cat 是 n02121808,而 big cat 是另一个 ID。如果你想找所有猫科图片,建议把父类 wnid 下的子类全部展开,再合并下载。
3. 环境准备与工具安装
3.1 依赖与安装
这个工具本质上是一段 Python 脚本,核心依赖是 requests 和 tqdm,有版本还用到 click 来解析命令行参数。我用的版本是基于 Python 3.7 以上环境跑的,建议直接使用虚拟环境安装,避免污染系统 Python。
git clone https://github.com/madhav-madhusoodanan/ImageNet-Datasets-Downloader.git cd ImageNet-Datasets-Downloader pip install -r requirements.txt如果你不想 clone,也可以直接下载仓库里的核心脚本,再把依赖装上。需要注意,这个项目并非官方维护,不同分支的命令行参数可能略有差异。我最初用的时候,仓库主分支的入口文件是Imagenet_downloader.py,后来看到一些 fork 版本改成了main.py。所以动手前先看一眼 README,确认你本地这个版本的入口文件叫什么。
3.2 命令行参数说明
大多数版本的参数都围绕这几个核心项:
| 参数 | 作用 | 示例 |
|---|---|---|
--classes或--wnids | 指定要下载的 WordNet ID 列表,多个之间用空格分隔 | n02084071 n02121808 |
--images或--num_images | 每个类别需要下载的图片数量 | 200 |
以我本地的版本为例,实际调用格式如下:
python Imagenet_downloader.py \ --classes n02084071 n02121808 \ --images 200执行后,工具会在当前目录生成以 wnid 命名的文件夹,图片依次写入其中。有些 fork 版本还会支持输出目录指定、并发线程数、超时时间等扩展参数,可以根据需要自行查看。
4. 实操:从零下载自定义 ImageNet 子集
4.1 获取类别清单并拼出下载命令
假设我想做一个包含狗和猫的二分类数据集,每类 200 张图片。第一步拿到两个类的 wnid:狗是 n02084071,家猫是 n02121808。然后执行上面的命令。这里建议把命令写成一个 shell 脚本,方便后续调整类别或数量时复用。
mkdir -p my_imagenet_subset && cd my_imagenet_subset python ../Imagenet_downloader.py \ --classes n02084071 n02121808 \ --images 200下载过程会显示进度条和当前正在处理的文件。因为是逐批请求图片 URL,速度不会特别快,200 张图每类通常需要几分钟到十几分钟,取决于网络状况和网站响应速度。
4.2 下载过程与目录结构
这个下载器的工作逻辑并不复杂:先根据 wnid 向 ImageNet 的公开接口请求该 synset 下的图片 URL 列表,然后逐一下载。实际效果是每个 wnid 对应一个文件夹,里面是 JPEG 图片文件,文件名一般带有原始 ID 信息,结构大致如下:
my_imagenet_subset/ ├── n02084071/ │ ├── n02084071_1.JPEG │ ├── n02084071_2.JPEG │ └── ... └── n02121808/ ├── n02121808_1.JPEG └── ...这种按 wnid 命名的目录结构本身已经满足 PyTorch 的ImageFolder格式要求,因为ImageFolder会直接把每个子目录名当作类别标签。不过 wnid 可读性太差,训练时还需要一份映射表,把 n02084071 映射成狗,把 n02121808 映射成猫。
4.3 校验与清洗
下载完成不等于可以直接进训练管线。ImageNet 的数据来自互联网,不少图片链接可能已经失效或内容发生了变化。常见问题包括:
- 下载到一半图片损坏,无法解码;
- 某些图片实际是缩略图或空白图;
- 个别图片被原站点反爬拦截,返回了错误页面。
因此我每次下载完都会跑一遍简单校验,用 OpenCV 或 PIL 打开所有文件,无法解码的直接删掉。
from PIL import Image import os for root, _, files in os.walk("my_imagenet_subset"): for f in files: path = os.path.join(root, f) try: img = Image.open(path) img.verify() except Exception: os.remove(path) print("removed", path)不要小看这一步,我曾有一批数据训练到一半才发现有几十张损坏图片,导致 Batch 训练时随机报错,排查了很久。先清洗,后面能省很多事。
5. 进阶:把下载内容变成可直接训练的数据集
5.1 按 ImageFolder 标准整理文件
很多视觉训练的代码默认使用torchvision.datasets.ImageFolder,它要求目录按类别名/图片文件组织。现在我们的目录是按 wnid 组织的,类别名就是 wnid,这没问题。但如果想让训练代码直接显示可读标签,最好把文件夹重命名成英文标签,比如dog、cat。
mv n02084071 dog mv n02121808 cat这里要注意:重命名会让后续手工核对 wnid 变得麻烦,所以一定要把映射关系记录好。我习惯在数据集根目录放一个labels.txt,每行是“文件夹名 可读描述”,方便随时查。
5.2 标签映射与 WordNet 对齐
讲到这里,就不得不提“WordNet 和 ImageNet 对齐”这个热门问题。很多模型是以 ImageNet 的 1000 类为基准训练的,比如 ResNet、EfficientNet 在torchvision里的预训练权重,输出类别按 ILSVRC2012 的 1 到 1000 索引排列。当你自定义数据集时,如果希望使用这些预训练权重做迁移学习,就需要搞清楚自己选出来的 wnid 对应模型输出索引的哪一位。
查索引的方式很简单:官方的imagenet_class_index.json已经给出索引到 wnid 的映射。你可以直接加载这份 JSON 文件,反查出某个 wnid 对应的输出索引是多少。这样在替换模型最后的全连接层时,就不会搞混类别顺序。
import json with open("imagenet_class_index.json") as f: class_index = json.load(f) wnid_to_idx = {v[0]: int(k) for k, v in class_index.items()} print(wnid_to_idx["n02084071"]) # 输出狗类在预训练模型中的索引这个操作在处理一些“从 ImageNet 子集初始化并微调”的论文复现时尤其重要,标签对齐错一位,整个实验结论都可能反转。
5.3 训练集/验证集划分
下载器本身只负责把图片拉到本地,并不提供 train/val 切分。自己写脚本划分很直接,按比例随机抽样,把文件移动或软链到train和val目录下。我更推荐用软链而不是复制,因为自定义数据集一般不大,复制也能接受,但软链更省空间,适合反复调整划分比例。
mkdir -p dataset/train/dog dataset/val/dog cd dataset find ../dog -type f | sort | head -n 160 | xargs -I {} ln -s {} train/dog/ find ../cat -type f | sort | head -n 160 | xargs -I {} ln -s {} train/cat/简单做的话,用 Python 脚本写个随机切分更灵活,还可以顺便把清洗步骤合并进去。
6. 常见问题与避坑记录
6.1 下载到一半不动了
这个工具在请求图片时如果网络状态不佳,可能会卡在某个文件上。大多数情况下是因为目标站点的响应超时或者连接被断开。我的处理办法是:不要死等,直接中断进程,然后删除对应目录里不完整的文件重跑。很多版本本身没有断点续传功能,所以最稳妥的做法是设置一个合理的线程间隔或加入超时参数。如果你用的版本支持--timeout参数,建议设置成 10 到 20 秒,避免因为一两张图拖死整个任务。
6.2 下载数量和设置不一致
这个基本属于预期内。ImageNet 原始图片 URL 中有一部分已经失效,下载器尽力去请求也可能返回 404,尤其是年份比较久的 synset。这种情况下实际下载的图片数会小于你设定的数量。我一般会直接把期望数量上调 20% 到 30%,下载完成后清洗删掉坏图,最后数量就差不多了。
6.3 图片打不开或内容不对
这个问题主要来自原始站点的反爬或跳转机制,有时候保存下来的文件内容其实是 HTML 而不是 JPEG。用文件头检查可以快速发现:
file n02084071/*.JPEG | grep -v "JPEG image" | head如果发现大量非图片文件,说明下载环境被目标网站识别了,可以考虑更换下载时间段或调整请求间隔,尽量模拟正常访问。数据量要求不高的实验,也可以改为使用官方提供的image-net.org的图片下载接口,按 synset 拉取。
6.4 想下载的类在 ImageNet 里没有
ImageNet 的类别集合是固定的,它覆盖 WordNet 中约 2 万多个名词 synset,但日常概念并不一定都在里面。想确认某个类别是否存在,最直接的方式是去 ImageNet 官网搜索界面输入关键词,如果返回为空,那就只能换用其他数据集,或者自己收集图片并清洗。实在想用 ImageNet 的预训练模型权重,也可以选择离目标概念最近的 synset,比如“无人机”不好找,就用“飞机”相关的 synset 做近似替代。
7. 一些体会
做视觉实验越久,越觉得“数据准备”这件事不应该成为启动项目的阻碍。以前我喜欢一次性下载全套数据,觉得“都拿下来总没错”,结果每次都被存储和预处理拖住手脚。后来改成按需抽取,反而让实验迭代快了不少。ImageNet-Datasets-Downloader 虽然体量不大,代码也不算复杂,但它把一个很长链条中的关键环节切得足够短,让任何普通开发者都能在几分钟内拿到一份可用的自定义 ImageNet 子集。如果你只是跑个实验验证想法,完全不必去啃全量数据。
最后再分享一个小技巧:用这类工具生成的数据集,最好把 wnid 映射和下载日期记录在同一个说明文件里。因为 ImageNet 的图片内容会随时间变化,同一 wnid 在不同时间下载,可能得到不同的图片集合。留一份 meta 信息,实验出问题时你才知道数据到底是不是变化的那个变量。数据集小有小的好处,但前提是每一步都干净、可追溯。
本文还有配套的精品资源,点击获取