torch.cuda.outofmemoryerror通常源于pytorch缓存分配器无法找到连续显存块,而非物理显存耗尽;其根本原因是张量引用未清除、缓存未及时释放或隐性开销(如batchnorm统计量、adamw状态)累积所致。

torch.cuda.OutOfMemoryError 出现时,GPU显存并非真的“用光了”,而是 PyTorch 的缓存分配器无法找到连续可用块——多数情况能通过几行代码干预解决,不需要换卡或重写模型。
为什么 torch.cuda.empty_cache() 有时没用?
它只清空 PyTorch 缓存中“已释放但未归还给驱动”的显存块,对仍被张量引用的内存无效。常见失效场景包括:
-
del变量后没调用torch.cuda.empty_cache(),或调用太早(Python 引用计数还没降为 0) - 张量被意外保留在全局列表、日志对象或闭包中,导致引用始终存在
- 在
with torch.no_grad():外部保留了中间输出(如output = model(x)后没及时del output) - 使用
model.train()时,BatchNorm层的 running_mean/running_var 会持续累积显存
训练循环里该在哪删变量、何时清缓存?
不是越勤越好,也不是越晚越稳。关键节点是:梯度更新后、验证前、每个 epoch 结束时。
- 每次
optimizer.step()后立即del所有中间变量(如loss,outputs,logits),再调用torch.cuda.empty_cache() - 验证阶段必须加
with torch.no_grad():,否则反向传播残留会悄悄吃掉显存 - 避免在 dataloader 循环内频繁调用
empty_cache()—— 它有毫秒级延迟,会拖慢吞吐 - 如果用了
torch.compile(),首次运行后缓存更顽固,建议只在 epoch 级别清
batch_size=1 还 OOM?检查这三处隐性开销
显存占用不只是输入张量 × batch_size。真正吃显存的是:
-
optimizer状态:AdamW 比 SGD 多占约 2 倍显存(动量 + 二阶矩估计),可改用torch.optim.Adam或SGD临时诊断 -
model.parameters()的梯度本身不占大头,但model.named_buffers()中的running_mean(尤其 BatchNorm 层数多时)会随 batch 累积 - 混合精度中
scaler本身不耗显存,但若autocast区域外漏了 float32 张量(如手动创建torch.tensor(..., dtype=torch.float32)),会破坏内存节省效果
推理时 torch.cuda.OutOfMemoryError 怎么破?
推理本不该触发反向传播,OOM 通常源于“忘了关梯度”或“缓存没清理”。最简修复:
- 确保所有推理逻辑包裹在
with torch.no_grad():内,包括预处理和后处理中的张量运算 - 避免在循环中反复调用
model(input)而不del输出——尤其当输出是 dict 或 tuple 时,容易漏删某个 key 对应的张量 - 加载模型后立刻执行
model.eval(),否则 Dropout/BatchNorm 会保留训练状态,间接增加显存压力 - 如果用
torch.jit.script或torch.compile,首次运行后缓存更大,建议推理前先 warmup 一次再清缓存
detach() 的中间特征图,或验证集上少写了 no_grad,就足以让显存缓慢爬升到崩溃点。Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











