前言
最近在为一个YOLO可视化标注训练工具添加训练功能时,遇到了一个极其顽固的错误:PytorchStreamReader failed reading zip archive: failed finding central directory。前后折腾了数小时,尝试了无数种方法------重装PyTorch、降级版本、修改路径、换用绝对路径、在多线程/子进程/子线程间反复横跳------都无济于事。直到最后才发现,问题根本不在于我的模型文件,而在于Ultralytics内部一个"好心办坏事"的自动检测机制。
本文将完整记录这一调试过程、最终发现的根本原因,以及为什么一个简单的 amp=False 就能解决所有问题。
一、错误现象
在使用Ultralytics YOLO进行训练时,代码在模型加载阶段一切正常:
python
from ultralytics import YOLO
model = YOLO('yolov8n.pt') # 成功
但一旦调用 model.train(),就会抛出如下异常:
RuntimeError: PytorchStreamReader failed reading zip archive: failed finding central directory
错误堆栈指向 torch.load 在读取一个zip文件时失败。令人困惑的是,模型文件明明存在且完整(通过 torch.load 单独测试也能成功加载),为什么训练时会失败?
二、第一波排查:模型文件损坏?
起初怀疑是下载的模型文件不完整。反复从官方GitHub、镜像站、甚至用curl重新下载,文件大小约6MB,torch.load 也能正常读取。排除模型文件本身问题。
三、第二波排查:路径与文件锁
怀疑Windows下的文件句柄冲突。尝试:
- 将模型文件复制到项目根目录,使用绝对路径加载;
- 只在主线程加载一次,然后将模型实例传递给子线程;
- 只在子线程中加载,不预先加载;
- 清除Ultralytics缓存目录
~/.cache/ultralytics。
所有尝试均无效,错误依旧。
四、第三波排查:PyTorch版本与多进程
怀疑PyTorch 2.7.1与Ultralytics 8.4.33不兼容。降级到2.0.1、2.1.0,依然报错。设置 workers=0 禁用多进程数据加载,也没用。
五、转机:仔细阅读错误堆栈
在一次完整的错误堆栈中,我发现了一个关键信息:
python
File "ultralytics/utils/checks.py", line 894, in check_amp
assert amp_allclose(YOLO("yolo26n.pt"), im)
原来,在训练初始化阶段,Ultralytics 会调用一个名为 check_amp 的函数,该函数内部会尝试加载一个叫 yolo26n.pt 的模型文件!这个文件并不是用户指定的模型,而是Ultralytics内部用于检测AMP(自动混合精度)是否可用的一个小型测试模型。它会自动从网络下载(如果本地没有)。
而我的环境中,由于网络限制或其他原因,这个 yolo26n.pt 下载失败或下载不完整,导致 torch.load 读取时抛出 PytorchStreamReader 错误。
六、根本原因
Ultralytics 在训练开始时,默认会执行AMP可用性检查。该检查会尝试下载一个内部测试模型 yolo26n.pt(约几MB),然后通过它来验证AMP是否能正常工作。如果下载失败或文件损坏,整个训练就会因为无法读取这个临时模型而崩溃。
这个设计初衷是为了自动判断是否可以使用混合精度训练,以提高训练速度。但在网络不稳定、无互联网环境、或文件服务器响应异常的情况下,就会造成用户完全无法训练,且错误信息完全误导用户去怀疑自己的模型文件。
七、解决方案:禁用AMP检查
既然问题是AMP检查引起的,最直接的解决方案就是跳过这个检查 。Ultralytics 提供了 amp 参数,默认值为 True,将其设为 False 即可禁用AMP检查,从而避免下载 yolo26n.pt。
修改后的训练调用:
python
model.train(
data='data.yaml',
epochs=100,
amp=False, # 关键!
# ... 其他参数
)
添加 amp=False 后,训练立即正常启动,GPU满载运行,所有错误消失。
八、为什么会有 amp=False 这个参数?
amp是 Automatic Mixed Precision 的缩写。启用AMP可以显著减少显存占用并加速训练(尤其在高分辨率大模型上)。- Ultralytics 默认开启AMP,并自动测试当前环境是否支持(通过下载
yolo26n.pt进行快速验证)。 - 用户可以手动设置
amp=False来完全禁用AMP,同时也禁用了该检测过程。
因此,amp=False 并非为了解决下载问题而设计,但它恰好成为了绕过这个bug的钥匙。
九、经验教训
- 遇到奇怪的
PytorchStreamReader错误时,首先检查是否在训练初始化阶段有内部模型下载行为。 仔细阅读完整堆栈,不要只盯着自己的模型文件路径。 - 不要盲目重装环境或修改路径,先理解错误的真正来源。
- Ultralytics 的"智能"检测有时会成为负担,在离线或受限环境中,务必主动关闭不必要的自动行为。
- 官方文档中其实提到了
amp参数,但很少有人会想到它与这个错误有关。社区中也有类似的问题报告,但多数被误导到模型文件损坏上。
十、总结
这次调试过程让我深刻体会到:一个看似复杂的错误,其根源往往藏在最不起眼的角落。从怀疑模型文件、怀疑路径、怀疑多线程,到最后发现是Ultralytics内部下载 yolo26n.pt 失败,每一步都充满了挫败感。但最终,一个简单的 amp=False 解决了所有问题。
希望这篇博客能帮助遇到同样问题的朋友节省时间。如果您的YOLO训练莫名其妙地报 PytorchStreamReader 错误,请先尝试在 train 参数中加入 amp=False,很可能您根本不需要修改任何模型或环境。