4、推理时显存溢出(OOM):batch size过大、分辨率过高、内存泄漏排查

显存溢出,圈里人常说的 OOM(Out of Memory),是 YOLO 实时流推理里最让人头疼的问题之一。你想想看,摄像头画面正推着,突然程序崩了,终端里跳出个红色报错——那种感觉,我经历过太多次了。

其实 OOM 的原因并不复杂,无非就是显存装不下当前的计算量。但排查起来,往往需要一点耐心。我个人习惯把 OOM 分成三类:配置不当型、输入过载型、内存泄漏型。咱们一个一个说。

4.1 配置不当:batch size 的陷阱

很多人以为 batch size 越大推理越快,这个想法在训练阶段没错,但在实时流推理里,它是个大坑。

YOLO 推理时,batch size 决定了一次送入 GPU 的图片数量。如果你设了 batch=8,每张图 640×640,那显存占用就是单张的 8 倍。我见过一个项目,同事把训练脚本的 batch=32 直接搬到了推理脚本里,结果 8GB 显存的卡瞬间爆掉。

我的经验:实时流推理用 batch=1 就够了。视频流是一帧一帧来的,没必要攒一批再推。除非你用的是多路视频流合并推理,那可以适当调大,但建议从 batch=2 开始试。

这里有个简单的估算公式:

显存占用 ≈ batch_size × (输入分辨率宽 × 输入分辨率高 × 3 × 4) × 模型系数

模型系数取决于 YOLO 版本和模型大小。YOLOv8s 大约 1.2,YOLOv8x 能到 2.5 以上。你可以先跑一次小 batch 看看占用,再往上加。

4.2 分辨率过高:不是越大越好

YOLO 默认输入分辨率是 640×640。很多人觉得分辨率越高检测越准,于是改成 1280×1280,甚至 1920×1920。结果呢?显存直接翻 4 倍甚至 9 倍。

为什么会这样?因为分辨率是平方级影响显存的。从 640 提到 1280,像素数变成 4 倍,显存占用也差不多 4 倍。再加上特征图也跟着膨胀,实际占用可能更高。

输入分辨率 像素数(相对 640) 显存占用估算(batch=1) 适用场景
320×320 0.25x 约 0.3 GB 低功耗设备、快速检测
640×640 1x 约 1.0 GB 通用场景
1280×1280 4x 约 3.5-4.5 GB 小目标检测、高精度需求
1920×1920 9x 约 8-10 GB 慎用,仅高端显卡
注意:分辨率翻倍并不代表精度翻倍。我做过对比测试,640→1280 在 COCO 上 mAP 提升不到 3%,但显存占用涨了 300%。性价比很低。

4.3 内存泄漏:最隐蔽的杀手

配置和分辨率的问题,改一下参数就能解决。但内存泄漏不一样——它不会一开始就爆,而是跑着跑着,显存一点点涨上去,直到撑不住。

我曾经维护过一个实时监控系统,摄像头 24 小时运行。前 2 小时一切正常,第 3 小时开始卡顿,第 5 小时直接 OOM 崩溃。查了两天才发现,是推理循环里有个 tensor 没释放。

常见的泄漏原因有:

  • 每次推理都创建新的 tensor,但没有 detach()——计算图越积越大
  • 视频帧队列无限增长——处理速度跟不上推流速度
  • 日志或可视化代码里保留了历史帧引用——垃圾回收不了
  • 多线程中显存上下文没正确切换——每个线程都在吃显存

排查泄漏,我一般用这招:

import torch

# 在推理循环里打印显存变化
print(f"allocated: {torch.cuda.memory_allocated() / 1024**3:.2f} GB")
print(f"cached:    {torch.cuda.memory_reserved() / 1024**3:.2f} GB")

如果 allocated 持续增长,说明有泄漏。如果 allocated 稳定但 cached 在涨,那是 PyTorch 的缓存机制,不用太担心。

排查步骤:
  1. 在推理循环前后各打一次显存占用
  2. 如果每次循环后 allocated 都增加,检查 tensor 是否 detach
  3. 检查是否有全局列表或字典在累积推理结果
  4. 用 torch.cuda.empty_cache() 手动清理缓存(治标不治本)
  5. 最终方案:用 with torch.no_grad() 包裹推理代码,切断计算图

4.4 知识结构图:OOM 排查全景

下面这张图总结了 OOM 的三大原因和对应的排查路径,你可以把它当作调试时的快速参考。

YOLO 推理显存溢出排查全景图 YOLO 推理显存溢出(OOM)排查全景 显存溢出 OOM batch size 过大 输入分辨率过高 内存泄漏 实时流建议 batch=1 640×640 性价比最高 tensor 未 detach 逐步增大 batch 测试 从 320 开始向上调 打印显存变化曲线 最终建议:先降分辨率,再调 batch 配合 torch.no_grad() 和显存监控 💡 排查口诀 先看 batch 和分辨率,再查 tensor 有没有 detach;显存监控打日志,泄漏排查不费事

4.5 实战排查清单

最后,我整理了一份排查清单。下次遇到 OOM,按这个顺序走一遍,基本能定位问题。

  1. 检查当前显存占用:nvidia-smi 看一眼,确认是不是真的爆了
  2. 降低 batch size:直接改成 1,看还爆不爆
  3. 降低输入分辨率:从 640 降到 320,看显存占用变化
  4. 检查推理代码:有没有 with torch.no_grad()?有没有 detach?
  5. 检查视频帧队列:队列长度是不是在无限增长?
  6. 加显存监控日志:每 100 帧打印一次,观察趋势
  7. 尝试半精度推理:model.half() 能省一半显存
避坑提醒:我曾经在排查泄漏时,花了一整天检查代码,最后发现是另一个进程在同时跑训练,把显存吃光了。所以,第一步先看看是不是有其他程序在占显存——别像我一样走弯路。