最近帮朋友在一台刚装好 Ubuntu 22.04 的开发机上跑图像分类入门实验,结果卡在了第一步:下载 CIFAR-10。这个数据集在 Windows 上点几下浏览器就能解决,换到 Ubuntu 命令行,反而有一堆细节让人抓狂——下载到一半断了怎么办?解压之后目录长什么样?为什么 PyTorch 和 TensorFlow 下载到的文件路径不一样?这篇文章把我踩过的坑和最终跑通的流程整理出来,不管你用官方压缩包还是框架自带下载,看完应该都能一次搞定。
1. 下载CIFAR-10之前,先把这三件事想明白
1.1 CIFAR-10是什么:只有6万张图,却是视觉入门的必修课
CIFAR-10 应该是计算机视觉领域最经典的入门数据集,没有之一。它包含 10 个类别(飞机、汽车、鸟、猫、鹿、狗、青蛙、马、轮船、卡车),每张图是 32×32 的彩色小图,总共 6 万张,其中 5 万张训练、1 万张测试。因为图片分辨率低、总量才一百多兆,CPU 都能轻松跑完一轮训练,所以不管是上课、写博客还是跑开源项目,它都是首选验证集。
我为什么要先讲这个?因为很多人下载时根本没意识到一件事:CIFAR-10 有不止一种官方分发格式。后面你无论用 PyTorch 的 torchvision,还是 TensorFlow 的 Keras,它们下载回来的东西其实都源自同一个官方压缩包,只是缓存路径和解压方式不一样。如果你手动下载时选错版本,或者目录放得不对,后面加载数据就会绕很多弯。
1.2 官方给的不止一个包:Python版、binary版和Matlab版
打开官网 https://www.cs.toronto.edu/~kriz/cifar.html,你会看到三种下载文件:
cifar-10-python.tar.gz:Python 版,解压后是 pickle 序列化的数据块,深度学习最常用。cifar-10-binary.tar.gz:C++/C 版,每个类别单独一个二进制文件,适合自己写 C++ 数据读取器的人。cifar-10-matlab.tar.gz:Matlab 版,.mat格式,适合老实验室在 Matlab 里做实验。
做深度学习的话,直接选 Python 版就够了。这个包解压后是一个叫 cifar-10-batches-py 的文件夹,里面是 data_batch_1 到 data_batch_5、test_batch、batches.meta 这些 pickle 文件,torchvision 的默认下载逻辑最终也是把它落盘到这个名称下。
Keras 的 load_data() 下载的其实是同一个 Python 版数据集,只不过它会把压缩包缓存在 ~/.keras/datasets 目录下,文件名是 cifar-10-batches-py.tar.gz。明白这个对应关系之后,你再遇到"为什么同一个数据集我磁盘上有好几份"的问题,就不会懵了。
1.3 先做目录规划:数据集位置别随手乱放
在 Ubuntu 下我习惯先规划一个固定目录,比如 ~/datasets/cifar-10,而不是随手放在当前项目目录里。原因很实际:手动解压验证、torchvision 的 root 参数、Keras 的缓存路径,全都要明确一个数据位置。如果每个项目都用默认相对路径,很容易出现多个项目重复下载、磁盘空间莫名减少、重装系统后数据全部丢失的情况。
先初始化一下:
bash复制mkdir -p ~/datasets/cifar-10
cd ~/datasets/cifar-10
如果你的 Ubuntu 是 Server 版或者跑在 Docker 容器里,没有图形界面,目录规划就更重要了。下面所有操作我都会默认先切到这个目录。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备:Ubuntu下先把这些工具检查一遍
2.1 Python、pip和下载工具,一个都不能少
Ubuntu 桌面版通常自带 Python 3,但 Server 版不一定。打开终端先确认基础环境:
bash复制python3 --version
pip3 --version
which wget curl
如果提示找不到 wget 或 curl,先安装:
bash复制sudo apt update
sudo apt install -y wget curl tar
这个组合基本覆盖了手动下载的所有需求。wget 好就好在支持断点续传,curl 更擅长调试头部信息,tar 用来解压数据集。没有图形界面的时候,这三件套能解决绝大多数文件传输问题。
2.2 一个特别容易忽略的点:Ubuntu 22.04的pip环境隔离
如果你打算用框架自动下载,或者后面还要装 torchvision、tensorflow,那这一步一定要看。Ubuntu 22.04 和 24.04 的 Python 3 环境默认启用了 externally-managed-environment 策略,直接执行 pip3 install torchvision 大概率会报一个 error: externally-managed-environment,意思是说系统 Python 环境被 dpkg 管理,不建议用 pip 全局装包。
正确做法是建一个虚拟环境:
bash复制python3 -m venv ~/venv/ai
source ~/venv/ai/bin/activate
之后在这个环境里装深度学习库就不会和系统环境打架。这其实不是 CIFAR-10 下载本身的问题,但下载之前没准备好环境,往往才是折腾半天的真正原因。
2.3 网络自检:先确认能不能摸到官方源
下载最怕的是什么?不是解压错误,而是网络连不上,反复超时。所以在正式下载前,我一般会先做一个轻量探测:
bash复制wget --spider https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz
--spider 参数只做 HTTP 探测,不下载文件。如果返回 Remote file exists,说明能连通,可以继续。如果一直卡住或者报连接失败,那就得先解决网络问题,或者考虑换网络环境再试。这一步能帮你区分是命令问题还是网络问题,省掉后面很多无意义的排障。
3. 官方渠道直连:用wget拿到压缩包并完成解压
3.1 正式下载:wget的坑和参数用法
网络确认没问题后,直接下载:
bash复制wget -c https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz
压缩包大概 170MB,视网络情况需要几十秒到几分钟。-c 是断点续传参数,很重要。官方服务器并不是任何时候都稳定,尤其从某些网络环境直连时,下载到一半断开的概率不低。没有 -c 的话,断了只能从头再来;加了 -c,下次执行会从上次断开的位置继续。
如果网络抖动严重,可以再加几个参数:
bash复制wget -c --tries=5 --retry-connrefused https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz
--tries=5 表示最多尝试 5 次,--retry-connrefused 让 wget 在连接被拒绝时主动重试。我实际在校园网环境下载时,这两个参数是救命级别的存在。
3.2 解压并确认目录结构
下载完成后,解压并查看结构:
bash复制tar -xzf cifar-10-python.tar.gz
ls -lh cifar-10-batches-py/
正常情况下你会看到:
batches.meta:包含label_names等元信息data_batch_1~data_batch_5:训练集被分成了 5 个 batch,每个 10000 张test_batch:测试集,10000 张readme.html:官方说明文件
每个 data_batch_* 文件大约 31MB,test_batch 也是 31MB 左右,整个目录加起来约 300MB。看到这些文件,就说明手动版本已经下载成功了。这里插一句:data_batch_* 里其实是 pickle 序列化的字典,包含 b'data' 字段和 b'labels' 字段,不是直接的图片文件,后面加载时要写对应的解析逻辑。
3.3 MD5校验:防止文件损坏的神器
下载完不要急着解压就完事。官方页面给了每个文件的 MD5 值,一定要核验一次:
bash复制md5sum cifar-10-python.tar.gz
正常输出应该是:
text复制c58f30108f718f92721af3b95e74349a cifar-10-python.tar.gz
这个值我在多台机器上下载验证过,是稳定不变的。如果校验值对不上,说明文件下载不完整或者传输过程中出错了,直接删掉重新下载,不要强行解压。不校验的后果是:后面训练时数据解析到一半突然报错,而且错误信息看起来像代码 bug,实际却是数据文件坏了,排查起来特别浪费时间。
4. 框架自动下载:PyTorch和TensorFlow两条主流路线
4.1 torchvision的CIFAR10接口:一行代码自动搞定
手动下载适合想完全掌控文件位置的人,但对大多数跑深度学习项目的人来说,用框架自带接口更省心。PyTorch 生态最常用的是 torchvision.datasets.CIFAR10:
python复制from torchvision import datasets
# 第一次运行会自动下载,第二次直接读取
train_dataset = datasets.CIFAR10(root='./data', train=True, download=True)
test_dataset = datasets.CIFAR10(root='./data', train=False, download=True)
这里 root='./data' 不是解压目录,而是数据集根目录。实际落地位置是 ./data/cifar-10-batches-py。你提前手动下载并解压到这个路径,download=True 也不会重复下载;如果这个目录不存在,它会自动用 wget/urllib 把官方压缩包拉下来再解压。
有一点容易踩坑:train=True 对应 data_batch_1 到 data_batch_5,train=False 对应 test_batch。如果你只是为了做推理验证,可以不下载训练集,只用 test_dataset,能省下大部分下载时间。但那 5 个训练 batch 是绑定的,download=True 会全部拉下来,属于正常的 170MB 开销。
4.2 Keras的load_data():一条命令直接进内存
如果你用的是 TensorFlow/Keras,操作更粗暴:
python复制from tensorflow.keras.datasets import cifar10
(x_train, y_train), (x_test, y_test) = cifar10.load_data()
这一行命令会检查 ~/.keras/datasets/cifar-10-batches-py.tar.gz 是否存在,不存在就下载,存在则直接解压并加载成 NumPy 数组。返回的 x_train 是 shape 为 (50000, 32, 32, 3) 的 uint8 数组,y_train 是 (50000, 1),注意标签是二维的,后面训练时可能需要 y_train.ravel() 或 squeeze() 处理一下。
Keras 这种方式的优点是代码最少,适合快速验证模型。缺点是你对数据文件位置的控制力弱一些,缓存路径固定在 ~/.keras/datasets,如果想做精细的数据集管理,不如 torchvision 方便。
4.3 两条路线怎么选:一张表看清差异
| 对比项 | torchvision | Keras load_data |
|---|---|---|
| 缓存目录 | root 参数可指定 | ~/.keras/datasets |
| 返回类型 | Dataset 对象 | NumPy 数组 |
| 额外依赖 | torch + torchvision | tensorflow |
| 适合场景 | 自定义 DataLoader、数据增强 | 快速调试、现成模型训练 |
| 标签维度 | 1D 标签列表 | 2D 标签数组 |
我的经验是:如果项目后续要做图像增强、自定义采样器,用 torchvision 更顺手;如果只是想快速跑一个分类模型,看准确率曲线,Keras 的 load_data() 是最短路径。两条路下载的数据本质一样,只是组织方式不同。
5. 高频踩坑:从下载中断到权限报错的完整排查链路
5.1 网络不稳定导致下载中断:断点续传的正确姿势
我见过太多人卡在 80% 就放弃了,其实没必要。wget 的 -c 参数我之前提过,再补充一个 curl 版本:
bash复制curl -C - -O https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz
-C - 是 curl 的断点续传,-O 表示把远程文件名保存到本地。如果你一开始用的是 curl,断线后重跑同一条命令,它会自动从断点继续,不会覆盖已下载的部分。
如果你有 aria2,更推荐装一个:
bash复制sudo apt install -y aria2
aria2c -c -x 16 https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz
-x 16 表示开 16 个线程下载同一个文件,速度提升明显,而且支持断点续传。对于 170MB 的文件来说,这可能是从"等十分钟"变成"等一分钟"的差距。
5.2 PermissionError背后是Linux权限链,不是代码问题
用 torchvision 下载时,最常见的报错之一是:
text复制PermissionError: [Errno 13] Permission denied: './data/cifar-10-batches-py'
排查思路不要先看代码,而是先看当前目录的属主。很多人为了省事会用 sudo python train.py 跑脚本,结果 root 用户创建了 ./data 目录,所有者和组都是 root。之后切回普通用户再跑,当然没权限写。
解决办法有两种:
bash复制# 方案一:不要用 sudo 跑 Python 脚本
source ~/venv/ai/bin/activate
python train.py
# 方案二:如果已经创建了 root 归属的目录,改回来
sudo chown -R $USER:$USER ./data
这个坑在手动解压时也会遇到:如果当时用了 sudo tar,解压出来的 cifar-10-batches-py 目录就有 root 权限,后面不管是 PyTorch 还是 Keras 加载都会很别扭。所以养成习惯:数据集这类普通文件,永远用普通用户操作。
5.3 URLError与校验失败:先别怀疑官网站点,按这个顺序排查
有时候 download=True 会报:
text复制URLError: <urlopen error ...>
这里有个非常重要的排查逻辑:PyTorch 的下载逻辑是"先看目标目录是否存在,存在就不下载"。如果你第一次下载中断,留下了半截文件或者不完整的目录,第二次执行时它会以为数据已经存在,不会重新下载,然后加载时要么报 pickle 解析错误,要么报 checksum 不对。
正确的排查顺序是:
- 看
root目录下是否有cifar-10-batches-py文件夹。 - 有的话,看文件夹里的文件是否完整,至少要有 5 个
data_batch_*和test_batch。 - 不完整就直接删掉整个目录,重新用
download=True下载。
还有一种情况是 SSL 证书问题,但概率比较低。如果你用老版本的 Python 或者公司内网有 HTTPS 代理拦截,可能会报证书相关错误。这时优先升级 certifi 库,而不是关掉证书验证。关闭验证的办法虽然能绕过报错,但安全风险太高,不推荐在日常项目里用。
5.4 磁盘空间不足:不是错误,是物理限制
CIFAR-10 看着很小,但解压后需要约 300MB 空间,如果再算上压缩包 170MB,整个过程峰值占用约 500MB。听着不多,可如果你在 Docker 容器里跑,默认容器磁盘可能被限制在 10GB 甚至更小,装完 CUDA、PyTorch、系统依赖后,剩余空间可能真的不够。
遇到 No space left on device 时,先看磁盘占用分布:
bash复制df -h ~
du -sh ~/datasets/cifar-10
如果确实是 / 分区满了,最简单的做法是把数据集放到空间更大的分区,比如单独挂载的 /data 盘,然后创建软链接:
bash复制sudo mkdir -p /data/datasets
sudo chown -R $USER:$USER /data/datasets
mkdir -p /data/datasets/cifar-10
ln -s /data/datasets/cifar-10 ~/datasets/cifar-10
这样项目代码里的路径不用改,实际数据却落在了大分区。这个软链接思路在后续下载 ImageNet、COCO 这类大数据集时尤其好用。
6. 下载完成后如何验证数据可用性
6.1 目录和文件数量核对:下载不是终点,校验才是
先做一次静态体检:
bash复制cd ~/datasets/cifar-10
du -sh cifar-10-batches-py
ls -l cifar-10-batches-py/
正常应该看到 5 个 data_batch_*(训练集分块)、1 个 test_batch(测试集)、1 个 batches.meta(元信息),每个文件大小约 31MB。如果发现某个文件只有几百 KB,那基本可以断定下载不完整,删掉重来。
也可以用一行 Python 快速确认训练和测试图片总数:
bash复制python3 -c "
import pickle
train_n = 0
for i in range(1, 6):
with open(f'cifar-10-batches-py/data_batch_{i}', 'rb') as f:
d = pickle.load(f, encoding='bytes')
train_n += len(d[b'data'])
print('train images:', train_n)
"
输出 train images: 50000 就说明训练集完整。
6.2 用Python抽看几张图片:第一时间发现颜色通道问题
文件完整不代表内容一定对。我习惯把图片可视化出来看看,这一步能发现不少隐蔽问题,最典型的就是通道顺序错误。
写个快速抽取脚本:
python复制import pickle
import matplotlib.pyplot as plt
def unpickle(file):
with open(file, 'rb') as fo:
data = pickle.load(fo, encoding='bytes')
return data
meta = unpickle('cifar-10-batches-py/batches.meta')
label_names = [x.decode() for x in meta[b'label_names']]
batch = unpickle('cifar-10-batches-py/data_batch_1')
images = batch[b'data'].reshape(-1, 3, 32, 32).transpose(0, 2, 3, 1)
labels = batch[b'labels']
plt.figure(figsize=(10, 2))
for i in range(5):
plt.subplot(1, 5, i + 1)
plt.imshow(images[i])
plt.title(label_names[labels[i]])
plt.axis('off')
plt.show()
注意 reshape(-1, 3, 32, 32) 这一步:data 数组是 (10000, 3072),而 3072 = 3×32×32,所以要先还原成 (batch, 3, 32, 32),再 transpose(0, 2, 3, 1) 变成 (batch, 32, 32, 3)。如果不做 transpose,matplotlib 会把通道维度误当成宽高,显示出来的图颜色扭曲、内容拉伸,看起来像损坏了其实没有。这个细节坑过不少刚入门的朋友。
如果环境不支持图形界面显示窗口,把 plt.show() 改成 plt.savefig('sample.png') 就行。
6.3 整理成自己的通用目录结构:一次下载,到处复用
最后分享一个我自己的习惯:下载好的 CIFAR-10 尽量保持原始目录结构,不要在 cifar-10-batches-py 里塞额外文件。我会在它的上一级建一个 processed 目录,专门放归一化后的 .npy 文件或 TFRecord 文件。
比如这样组织:
text复制~/datasets/cifar-10/
├── cifar-10-batches-py/ # 原始数据,只读
├── cifar-10-python.tar.gz # 压缩包,可留作备份
└── processed/ # 预处理结果,可随时删除
这样做的理由是:原始数据只有一份,不会被预处理逻辑污染;万一预处理写错了,删掉 processed 重新生成就行,不需要重新下载。CIFAR-10 只有 170MB 重新下载也快,但等以后换成几十 GB 的数据集,这套结构会帮你省下大把时间。
另外一个很实用的软链接技巧:多个项目共享同一份数据集。每个新项目里建一个 data 软链接指向 ~/datasets/cifar-10,代码里路径永远是 data/cifar-10-batches-py,但实际数据只存一份。这样既保证了路径在项目里可见,又不会因为复制多份把磁盘塞爆。
我在实际使用中最大的体会是:CIFAR-10 的下载本身不难,难的是下载前后那些看起来不起眼的细节——权限、断点续传、通道顺序、缓存路径。把这些搞明白,后续换任何一个数据集,你都会发现套路是相通的。特别是软链接那招,如果你打算长期玩深度学习,建议现在就养成习惯,后面用到 ImageNet 级别的数据时,你会回来感谢这个决定的。
