深度学习训练模型时确认GPU饱和

训练模型时一个重点的点是确保GPU饱和,没有”偷懒“。

确认GPU饱和的一般做法

一旦训练开始,我们要确保我们正按预期使用手头的计算资源。一个简单的方法来判断瓶颈是在数据加载还是计算上,是等待脚本开始训练(寻找类似 E1 Training 16/7750, done at... 的输出)几秒钟后,然后同时检查 top 和 nvidia-smi:

  • 如果 8 个 Python 工作进程(对应 num_workers 参数)消耗 >80% 的 CPU,那么缓存可能需要准备(我们知道这里是因为我们确保了这个项目的实现中没有 CPU 瓶颈;这通常并不成立)。
  • 如果 nvidia-smi 报告 GPU-Util > 80%,说明你正在饱和你的 GPU。

我们的意图是让 GPU 饱和;我们希望尽可能多地利用它的计算能力来快速完成 epoch。单个 NVIDIA GTX 1080 Ti 应该在 15 分钟内完成一个 epoch。由于我们的模型相对简单,CPU 预处理不需要太多,CPU 不太可能成为瓶颈。当处理具有更大深度(或更多所需计算)的模型时,处理每个批次所需的时间会更长,这会增加我们在 GPU 工作用完之前可以进行的 CPU 处理量,从而让 GPU 持续有活干。

这段话其实揭示了深度学习训练中一个非常经典的流水线(Pipeline)瓶颈问题:

1. 什么是“GPU 饱和 (GPU Saturated)”?

在理想状态下,GPU 应该 100% 都在做矩阵乘法等计算。但在实际训练中,GPU 经常需要“等” CPU:

  • CPU 的工作:从硬盘读取图片、解码、做数据增强(裁剪、翻转等)、转成 Tensor。
  • GPU 的工作:接收 Tensor,进行前向传播和反向传播。 如果 CPU 处理数据的速度 慢于 GPU 消耗数据的速度,GPU 就会停下来等 CPU,这时候 GPU 的利用率就会掉到 50% 甚至更低,这就是没有饱和。

2. 为什么“简单模型”容易遇到 CPU 瓶颈?

文中提到 “Since our model is relatively simple…” 如果模型很小(比如只有几层全连接),GPU 可能 1 毫秒就算完一个 batch。如果此时 CPU 预处理需要 2 毫秒,GPU 就有 1 毫秒在发呆。模型越简单,GPU 算得越快,对 CPU 的预处理速度要求就越高。

3. 为什么“复杂模型”反而不容易遇到 CPU 瓶颈?

这是这段话最精彩的反直觉部分:“When working with models with greater depth…” 如果你换了一个超大模型(比如 ResNet-152 或 Transformer),GPU 算一个 batch 需要 100 毫秒。 这时候,哪怕 CPU 预处理还是需要 2 毫秒,在这 100 毫秒的漫长等待期里,CPU 早就把接下来几十个 batch 的数据都准备好了。GPU 越慢,给 CPU 留出的“准备时间”就越长,CPU 反而不容易成为瓶颈了。

国产显卡怎么查看GPU使用率

国产卡/异构 AI 加速卡没有统一的 nvidia-smi,每家驱动栈自带一套 SMI 工具。

这里我用的是海光的DCU,因此主要关注它的。

华为昇腾 Ascend NPU → npu-smi

1
2
3
4
5
npu-smi info                       # 总览:型号/健康/温度/功耗/HBM/AI Core 利用率
watch -n 1 npu-smi info # 刷利用率
npu-smi info -t usages -i 0 # 单卡细分:HBM 用量、AICore/AIVector/AICPU 利用率、带宽
npu-smi info -t proc -i 0 # 谁在占卡
npu-smi info -t common -i 0 # 温度/ freq/ 健康

注意昇腾把“显存”叫 HBM Usage、“算力”拆成 AICore/AIVector/AICPU Usage、还有 HBM Bandwidth Usage,不是单个 GPU-Util 。深一点用 msprof 做 kernel 级 profiler 。

寒武纪 MLU → cnmon

1
2
3
4
5
cnmon                              # 总览,输出几乎照搬 nvidia-smi 的列
cnmon -c 0 # 指定卡
cnmon -r -t 1000 # 每 1s 刷一次
cnmon info -m # 显存
cnmon proc # 进程级显存

Utilization(%) 就是 MLU 算力利用率、Memory Usage 是显存,训练时常驻看这俩 。

海光 DCU / AMD 系 → hy-smi / rocm-smi

海光 DCU 是 ROCm 分支,工具名可能叫 hy-smi(路径常是 /opt/hyhal/bin/hy-smi)或 dcu-smi :

1
2
3
4
hy-smi                # 类 nvidia-smi 总览
hy-smi -u --showhcuutil --showmemuse -P -t # 利用率/显存/功耗/温度
hy-smi --showpids # 进程
watch -n 1 hy-smi # 每隔1秒刷新一次
纯 AMD/ROCm 卡用 rocm-smi -u --showmemuse --showpids 。

海光 DCU 里“GPU”被叫成 HCU(Hygon Compute Unit),所以 hy-smi 概览里 HCU% 就是你要的“显卡利用率”,不是 VRAM%。判断训练饱不饱和,盯 HCU% / CU 占用 + 功耗 + 显存 这三组,别被显存占满骗了。

概览里先认列(默认 hy-smi 输出)

1
2
HCU  Temp  AvgPwr  Perf  PwrCap  VRAM%  HCU%  Mode
0 61C 108W auto 400W 87% 92% Normal
  • HCU%:计算单元活跃率,等价于 N 卡 GPU-Util,训练饱和看它
  • VRAM%:显存占用率,占满只代表仓库大、不代表在算
  • AvgPwr / PwrCap:实时功耗 / 功耗上限;饱和时功耗会顶到比较高、不会一直躺平在百瓦级
  • Temp / Perf:温度、自动调频档,长期低温低功耗 + 低 HCU% = 没吃饱

训练时怎么盯饱和度(可抄命令)

1
2
3
4
5
6
watch -n1 hy-smi                 # 概览,看 HCU% 是不是贴 80–95%
hy-smi -u --showhcuutil --showcuutil # HCU 活跃时间占比 + CU(波前)占用率
hy-smi --showmemuse --showmemavailable # 显存用了多少、还剩多少
hy-smi --showpids # 哪些进程在吃这张卡
# 滚动采样单卡 利用率+功耗,写日志
hy-smi -idmon 0 -sdmon pu -ddmon 1 -fdmon hcu_train.log
  • --showhcuutil:HCU 在采样窗内干活的时间占比,最像 N 卡 util
  • --showcuutil:CU 占用 / 波前占用率,更深一层看 SIMD 宽利用够不够

怎么判“饱不饱和”

  • HCU% 稳定 80%+ 且 AvgPwr 接近该卡 TDP 的 70–90%、VRAM 稳住不抖 → 卡在算,饱和
  • HCU% 忽高忽低、AvgPwr 起不来、但 VRAM 占着 → 在等数据,瓶颈在 CPU 预处理 / DataLoader / 缓存没接好,不是 DCU 算不动——正好接你前面 LunaDataset 那个语境
  • VRAM% 90%+ 但 HCU% 接近 0、且显存曲线来回抖 → 显存碎碎念 / 频繁申请释放,不是计算饱和
  • 小模型大 batch 还喂不饱 HCU% → 提高 batch / 叠 AUG / 把 num_workers 拉起来,让 CPU 别拖后腿

经验线:迁移/训练文里把 DCU(HCU) Util >80% 当计算饱和参考,但别死磕 95%;HCU% 能稳在 80 上下、功耗温度随负载走,就算吃满了。真要算子级看哪段 kernel 空转,用 DTK 自带的 rocprof --stats 扒 CSV。

如果你跑的是多卡 DDP,每张卡的 HCU% 要分开看,hy-smi -idmon 0,1,2,3 -sdmon u 把多卡 util 同屏滚出来,某张卡掉到 30% 其余 90% 就是通信/切分不均。

摩尔线程 / 壁仞 / 昆仑芯 / 其他

  • 摩尔线程 MUSA → mthreads-gmi
  • 壁仞 → birensmi
  • 百度昆仑 XPU → xpu-smi
  • 这类卡参数各走各的,但一般都有 info / -i 0 / watch 式用法,没文档就 -h 看子命令。
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2019-2026 Vincere Zhou
  • 访问人数: | 浏览次数:

请我喝杯茶吧~

支付宝
微信