PyTorch显存“越用越少”是因为memory_allocated表示当前实际使用的显存,而memory_reserved是PyTorch从GPU预占的总量,即使张量删除也不会自动释放,需调用torch.cuda.empty_cache()才能回收未被引用的缓存块。

显存为什么“越用越少”?先看懂 memory_reserved 和 memory_allocated
PyTorch 不是用完就还,而是“借了不急着退”。torch.cuda.memory_allocated() 是你当前正在用的显存(比如模型参数、激活值),而 torch.cuda.memory_reserved() 是 PyTorch 从 GPU 系统里预占下来的总量——哪怕中间张量全删了,这部分也不会自动归还。这就是为什么 nvidia-smi 显示还有 4GB 空闲,却报 CUDA out of memory:空闲的是系统层,PyTorch 的缓存池已经锁死了大部分。
典型表现:训练几轮后 memory_reserved 持续上涨,但 memory_allocated 波动不大;重启 Python 才恢复。这不是泄漏,是设计使然。
- 每次调用
torch.randn(...).to('cuda')或前向传播,都会向缓存池申请块,不是直接向驱动要 -
del x或变量超出作用域,只释放allocated,不触碰reserved -
torch.cuda.empty_cache()是唯一能强制清掉未被引用的reserved块的操作,但它不保证立刻腾出空间给其他进程
训练循环里必须加的三行“保命代码”
很多 OOM 就发生在验证或多次 forward 后没清理,尤其在 torch.no_grad() 块里容易忽略。以下三行应嵌入每个 epoch 的末尾或验证逻辑之后:
torch.cuda.empty_cache() torch.cuda.synchronize() gc.collect()
注意顺序不能颠倒:empty_cache() 需要先等 CUDA 操作完成(synchronize()),否则可能清不到刚算完还没写回的内存;gc.collect() 补上 Python 层的循环引用回收(比如自定义 Dataset 中闭包持有张量)。
立即学习“Python免费学习笔记(深入)”;
- 不要只在报错后加——它得成为习惯性操作,尤其在
val_step或inference后 - 避免在训练主循环内高频调用(比如每 batch 一次),会拖慢速度;集中在阶段切换点更合理
- 如果用了
torch.compile()(PyTorch 2.0+),empty_cache()可能失效,需配合torch._dynamo.reset()
数据加载阶段最容易被忽视的显存黑洞
你以为 DataLoader 是“按需加载”,但默认 pin_memory=True + num_workers>0 会在 GPU 上预分配 pinned memory 缓冲区,且这些缓冲区长期驻留。更隐蔽的是:如果你的 Dataset.__getitem__ 返回了未 .to('cuda') 的 float64 张量,PyTorch 会在首次 .to() 时悄悄升为 float32 并多占一倍显存。
- 显式指定
dtype:用torch.tensor(..., dtype=torch.float16)替代默认 float32,图像类任务常可无损压缩 - 关闭不必要的 pinned memory:
DataLoader(..., pin_memory=False),除非你确认 CPU→GPU 传输是瓶颈 - 避免在 Dataset 里做 heavy transform(如 full-size 图像 resize),改用
torchvision.transforms.InterpolationMode.BILINEAR的低开销模式,或提前存为.npy内存映射文件 - 检查
collate_fn:别在里面构造新张量并 .to('cuda'),让 DataLoader 在 transfer 阶段统一处理
Miniconda-Python3.11 环境下必须做的三件事
Python 3.11 本身内存效率高,但若环境没“瘦”下来,所有优化都白搭。用 Miniconda 创建的环境,很容易因历史安装残留多个 CUDA 工具链或冲突的 cuDNN 版本,导致 PyTorch 初始化时加载冗余模块并隐式占用显存。
- 创建干净环境:
conda create -n pt311 python=3.11,**绝不复用 base 或老环境** - 只装官方 CUDA 版 PyTorch:
conda install pytorch torchvision torchaudio pytorch-cuda=12.1 -c pytorch -c nvidia(版本严格匹配驱动,查nvidia-smi右上角 CUDA Version) - 删掉非必要依赖:
conda list | grep -E "(cudnn|cuda-toolkit|nccl)"确认只有一套;运行pip list | grep -v "torch\|numpy\|Pillow"找出无关包(如 jupyter、matplotlib)并pip uninstall
环境臃肿不会直接报错,但会让 import torch 阶段就多占 200–500MB 显存——这点常被忽略,直到模型加载失败才排查。


















