当前位置: 首页 > news >正文

网站后台管理规定美食网站开发与设计文献综述

网站后台管理规定,美食网站开发与设计文献综述,做导航网站电脑设备,百度一下你就知道官网新闻PyTorch 训练显存越跑越涨:隐式保留计算图导致 OOM,四步定位与修复(Cursor Codex CodeBuddy 协作 Debug) 一次“跑几百步必炸显存”的翻车记录:开启训练后,GPU 占用缓慢递增直至 CUDA out of memory&…

PyTorch 训练显存越跑越涨:隐式保留计算图导致 OOM,四步定位与修复(Cursor × Codex × CodeBuddy 协作 Debug)

一次“跑几百步必炸显存”的翻车记录:开启训练后,GPU 占用缓慢递增直至 CUDA out of memory;每个 step 显存都不大,却越跑越高。最终定位是 把带梯度的张量(logits、loss)存进 Python 列表做 epoch 级指标/可视化,无 detach() / .item(),导致 计算图被跨 step 持有。本文按你的“基本要求”完整记录与 Cursor / Codex / CodeBuddy / ChatGPT 协作排查的真实过程。

技术环境

OS:Ubuntu 22.04 / Windows 11

Python:3.10.13

PyTorch:2.2.2 + CUDA 12.1

GPU:RTX 3090(24GB)

任务:多标签分类(BCE),bs=64,img=224×224

AI 工具与协作场景:

Cursor(结对编程):在训练循环上下文中提示“列表持有梯度张量”风险,生成 patch。

Codex(代码生成):产出最小可复现与显存探针脚本。

CodeBuddy(PR 评审):建议统一 .detach().cpu()、.item()、移除无意义的 retain_graph=True。

ChatGPT(GPT-5 Thinking):解释 Autograd 图跨 step 被引用的机理,给出二分排查策略。

Bug 现象

显存随 step 缓慢上涨(如每 20–50MB 一阶梯),几百到上千 step 后 OOM。

关闭日志/指标计算后不再上涨;验证阶段忘记 no_grad() 时上涨更快。

通过 torch.cuda.memory_summary() 看到活跃块在增长,但无明显大对象分配。

最小可复现(错误版)

leak_wrong.py —— 演示“列表持有计算图”导致显存泄漏(请勿在生产中照抄)

import torch, torch.nn as nn, torch.nn.functional as F
from torch.utils.data import DataLoader, TensorDataset

x = torch.randn(2000, 3, 224, 224)
y = (torch.rand(2000, 10) > 0.5).float()
loader = DataLoader(TensorDataset(x, y), batch_size=32, shuffle=True)

net = nn.Sequential(nn.Conv2d(3, 16, 3, padding=1), nn.ReLU(),
nn.AdaptiveAvgPool2d(1), nn.Flatten(), nn.Linear(16, 10)).cuda()
opt = torch.optim.AdamW(net.parameters(), lr=1e-3)

logits_buf, labels_buf, loss_hist = [], [], [] # ❌ 跨 step 的“粘性”列表

for step, (bx, by) in enumerate(loader, 1):
bx, by = bx.cuda(), by.cuda()
opt.zero_grad(set_to_none=True)
logits = net(bx) # [B, 10], requires_grad=True
loss = F.binary_cross_entropy_with_logits(logits, by)

loss.backward()
opt.step()# ❌ 直接把带梯度的张量放进列表,持有整条计算图
logits_buf.append(logits)                # ← 泄漏点 1
labels_buf.append(by)                    # ← 泄漏点 2
loss_hist.append(loss)                   # ← 泄漏点 3:loss 张量也持图if step % 50 == 0:alloc = torch.cuda.memory_allocated() / 1024**2print(f"step {step}, mem={alloc:.1f} MB")

若后面还想做 epoch F1/PR 曲线,这些列表会继续增长并持有图,直至 OOM

触发机理:

logits、by、loss 都在计算图链条上(requires_grad=True);放入 Python 容器会让 Autograd 图无法释放,跨 step 积累。

错误更隐蔽的是 loss_hist.append(loss)——很多人以为“只存个标量”,但张量不是标量,必须 .item()。

排查步骤(AI 协作过程)
Step 1:量化现象(Codex 生成显存探针)
def gpu_mb():
return torch.cuda.memory_allocated() / 1024**2

在训练 loop 打点:

print(f"[dbg] before step={step}, mem={gpu_mb():.1f}MB")

print(f"[dbg] after step={step}, mem={gpu_mb():.1f}MB")

现象:每步后都有几 MB 的净增长,说明是跨步累积而非单步峰值。

Step 2:二分法剥离(ChatGPT 提示)

注释日志/指标聚合代码 → 增长消失;

逐一恢复 loss_hist / logits_buf / labels_buf,锁定任一恢复即复现。

结论:容器中持有带梯度张量。

Step 3:Cursor 语义 Review(上下文提示)

提示“requires_grad=True 的张量被加入跨 step 复用的列表”,建议统一 .detach().cpu() 或 .item()。

同时发现验证代码忘记 torch.no_grad(),加剧增长。

Step 4:CodeBuddy PR 建议

训练循环只把需要长期保存的值转为CPU/无梯度;

移除无意义的 retain_graph=True(历史遗留);

指标计算放在epoch 尾,中途清空缓存。

终版修复(稳定模板)

leak_fixed.py —— 推荐写法

import torch, torch.nn as nn, torch.nn.functional as F

logits_buf, labels_buf, loss_hist = [], [], []

for step, (bx, by) in enumerate(loader, 1):
bx, by = bx.cuda(non_blocking=True), by.cuda(non_blocking=True)
opt.zero_grad(set_to_none=True)

with torch.cuda.amp.autocast(False):   # 可选:若用 AMP,保持默认策略即可logits = net(bx)loss = F.binary_cross_entropy_with_logits(logits, by)loss.backward()
# 不要随意 retain_graph=True;若确需多次 backward,请定位到子图而非整图
torch.nn.utils.clip_grad_norm_(net.parameters(), 1.0)
opt.step()# ✅ 仅保存“与训练解耦”的副本
logits_buf.append(logits.detach().cpu())    # 切断计算图,移到 CPU
labels_buf.append(by.detach().cpu())
loss_hist.append(loss.item())               # 标量化if step % 50 == 0:print(f"step {step}, mem={torch.cuda.memory_allocated()/1024**2:.1f} MB")

✅ 指标计算放到 epoch 尾,并尽快释放 GPU 中间态

import torchmetrics
pred = torch.sigmoid(torch.cat(logits_buf)) > 0.5
tgt = torch.cat(labels_buf).bool()

… 计算 F1/PR 等 …

logits_buf.clear(); labels_buf.clear() # 释放 CPU 内存引用
torch.cuda.empty_cache() # 可选:释放可缓存块(碎片化时有用)

✅ 验证阶段务必 no_grad

net.eval()
with torch.inference_mode():
for bx, by in val_loader:
# 验证不会增长显存
_ = net(bx.cuda())
net.train()

备注:torch.cuda.empty_cache() 只把缓存还给 CUDA 驱动,不是“强制释放”,真正的泄漏关键还是引用断开。

验证与效果

修复后,memory_allocated 在训练中稳定震荡(随前向/反向分配与释放),无单调上涨;

10k steps 稳定运行,无 OOM;

训练吞吐不受影响,指标计算迁移到 CPU 后仅增加 ❤️% 的时间。

经验总结(评奖友好表达)

根因:跨 step 的 Python 容器(list/dict/队列)持有参与 Autograd 的张量,导致计算图跨步保留。

三条军规:

训练环里凡进列表者,必 .detach().cpu();

凡入日志者,必 .item();

验证与推理必须 torch.no_grad() / inference_mode()。

工程化:把“显存探针 + 列表守卫”做成单测/钩子,CI 上跑 200 steps 检查 memory_allocated() 不应单调递增。

AI 协作价值:

Cursor 的上下文语义提醒让我们快速聚焦“列表引用”;

Codex 几秒钟生成最小复现 & 探针,大幅缩短二分时间;

CodeBuddy 在 PR 层面把“规范”固化为模板;

ChatGPT 给出原理解释,避免“头痛医头”式修补。

避坑清单(Checklist)

训练中不缓存带梯度张量;如需缓存,.detach().cpu()。

记录 loss 时用 .item();记录指标输入用numpy/CPU 张量。

验证/推理:model.eval() + torch.inference_mode()。

不随意 retain_graph=True;若要二次 backward,请只对必要子图构建。

定期 memory_allocated() 打点;疑难时 memory_summary() 辅助分析。

DataLoader 的 pin_memory=True 与 non_blocking=True 可提速,但与泄漏无关,不要误判。

指标计算与可视化尽量在 epoch 尾进行,流程上与训练解耦。

以上就是这次“显存越跑越涨直到 OOM”的完整排查与修复。把这篇作为“AI 协作 debug 日志”投稿,既能展示真实问题和可复用修复策略,也能量化 AI 带来的效率提升:定位时间从数小时降到 20 分钟内。需要的话,我可以把“显存探针 + 守卫单测”整理成一个可直接放进你仓库的 utils/memory_guard.py。

http://www.dtcms.com/a/568024.html

相关文章:

  • 陕西网站建设哪家专业广西住房和建设厅官网
  • 投资做网站网络服务器的配置与应用心得
  • 重庆有哪些科技骗子公司wordpress4.7优化
  • 如何高效建设品牌网站如何下载wordpress
  • 卡片形式的网站wordpress 批量标签
  • wordpress纯代码下载seo搜索引擎优化薪资
  • 销售网站开发步骤网站以什么名字备案
  • 大宗贸易采购平台福州网站怎么做seo
  • 淘宝的网站怎么做内容营销策略
  • 成都网站定制wordpress ip_hash失效
  • 门户网站还能建设么cida室内设计师资格证
  • 企业网站建设具体步骤网站建设中 怎么办
  • 承接网站建设服务一个公司可以做几个网站吗
  • windows 网站模板热点新闻素材
  • 积分兑换商城网站建设随州企业网络推广怎么做
  • 建设营销网站多少钱wordpress启用主题404
  • 玩具 东莞网站建设 技术支持建设现金分期网站
  • 网站推广打包爱网站关键词挖掘工具
  • 做网站费是多少政务网站设计鉴赏
  • 单位网站备案交友免费网站建设
  • 建设网站的费用怎么做账最打动人心的广告语
  • 福州网站开发公司wordpress5文章外链
  • 做pc端网站公司亚马逊网站网址是多少
  • 深圳企业网站建设公司安徽省房地产开发项目管理系统
  • 专业开发网站公司网站开发制作的流程
  • 手机上的网站是怎么做的烟台制作网站的公司简介
  • php网站开发 多少钱WordPress文件删除漏洞
  • 网站微信分享怎么做网站服务器租赁
  • 网站建设挂什么费用兰州网站建设优化
  • 做健身类小程序的网站区域文化网站建设方案