关于 spark-training-gotchas
面向 DGX Spark 训练运维的故障排查技能,覆盖启动、内存、性能和精度问题。它将十类常见故障编号为 G1–G10,并提供检查方法及预检脚本。
主要功能
- 01十类编号故障
- 02症状、原因、检查与修复说明
- 03针对部分问题的预检脚本
- 04双 Spark 并行策略建议
适用场景
- 01排查 CUDA 导入错误或段错误
- 02调查仍显示有余量时发生的 OOM
- 03检查长时间运行中的吞吐下降
- 04为双 Spark 训练选择并行策略
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ wshobson/ agents --skill spark-training-gotchas安装后在 Claude Code 中输入/spark-training-gotchas确认已加载。
附带文件assets/preflight.shreferences/gotcha-checks.md
详细介绍
Spark 训练避坑指南
DGX Spark 的 GB10 芯片(Grace Blackwell、SM121、128GB 统一 内存、aarch64)在启动、内存、散热、带宽和精度方面有十种反复 出现的故障模式。每一种都被命名为 G1–G10,以便按编号检查—— 这套编号对运行这些检查的工具至关重要。请在长时间运行之前 阅读本文,而不是在第六个小时之后。
何时使用本技能
- 训练运行无法启动,出现导入错误或段错误,但并未指向 真正的原因。
- 运行发生 OOM,而
nvidia-smi仍显示有余量。 - 一个起初正常的运行在中途吞吐量下降。
- 在 GB10 上执行任何数小时或多轮次的任务之前。
- 将两台 Spark 连接在一起时,在选择并行策略之前。
- 为 Spark 托管的运行在 FP8 和 NVFP4 之间做选择时。
常见问题速查
| # | 症状 | 修复 |
|---|---|---|
| G1 | undefined symbol / 段错误 | cu130 wheel 或容器 |
| G2 | flash-attn 使用了错误的后端 | 跳过 pip 构建;在 NGC 上 monkeypatch |
| G3 | 有余量却 OOM | 丢弃页缓存 |
| G4 | 吞吐量下降 / 重启 | 预期约 100W 持续上限 |
| G5 | 内存受限的步骤缓慢 | 按 180–192 GB/s 预算 |
| G6 | 缓存运行中途被逐出 | 一次只运行一个 GPU 服务 |
| G7 | NVFP4 比 FP8 慢 | 除非 sm_121a,否则保持 FP8 |
| G8 | playbook 直接失败 | 检查上游 issue |
| G9 | 安装后环境损坏 | 使用容器 |
| G10 | 2-Spark TP 挂起 | 仅用 DDP/FSDP,绝不用 TP |
十大坑
G1:CUDA 12/13 ABI 不匹配
- 症状:
ImportError: undefined symbol并指出某个 CUDA 函数,或在第一次.cuda()调用时段错误。 - 原因: 大多数 PyPI wheel 链接
libcudart.so.12;Spark 搭载 CUDA 13。pip 从不检查 CUDA ABI,因此只在导入或首次 内核启动时才会暴露。 - 检查:
references/gotcha-checks.mdG1 —— wheel 的 CUDA 构建标签。 - 修复: 从
download.pytorch.org/whl/cu130重新安装,或 使用匹配的容器。
G2:flash-attn —— 跳过 pip 构建,留意 Unsloth 的自动检测
- 症状:
pip install flash-attn仍然失败/挂起。 Unsloth 还可能在没有明确请求的情况下静默地在 SDPA 上 训练 flash-attn。 - 原因: 裸 pip 没有 aarch64/sm_121 wheel —— 但 NGC
容器附带可用的 SM121 flash-attn,且 Unsloth 会自动优先
使用它,从而丢弃
attn_implementation="sdpa"。 - 检查:
references/gotcha-checks.mdG2 —— flash-attn 是否已存在且可用。 - 修复: 裸 pip —— 跳过 flash-attn,使用 SDPA(保持不变)。
在 NGC 上 —— 唯一可靠的覆盖方式是
references/gotcha-checks.mdG2 中的 monkeypatch。
G3:低于 128GB 的 UMA OOM
- 症状: 在模型加载/训练期间发生 OOM,而
nvidia-smi仍报告低于 128GB 上限的可用内存 —— 或者,在某些设置下,直接显示[N/A]而不是数字。 - 原因: 在 safetensors 加载期间,mmap 和 CUDA 分配器会 重复计算页;QLoRA 可能比 bf16 更早 OOM,因为反量化会 增加临时分配。
- 检查:
references/gotcha-checks.mdG3 —— 读取free -g和/proc/meminfo,而不是nvidia-smi。 - 修复: 用
sync; echo 3 > /proc/sys/vm/drop_caches丢弃页缓存 —— 需要 root,是运行之间的重置,而不是训练中途的步骤。
G4:热节流
- 症状: 吞吐量在数小时的运行中途下降,或机器在持续 负载下自发重启。
- 原因: 持续功耗上限约为 100W,而额定值为 240W;长时间运行会逼近该上限并节流,有时还会重启。
- 检查:
references/gotcha-checks.mdG4 —— 采样nvidia-smi --query-gpu=temperature.gpu,power.draw。 - 修复: 如果功耗在 240W 以下趋于平稳而温度 攀升,则将节流视为原因;改善散热或 限制运行时长。
G5:带宽上限
- 症状: 内存受限型工作负载,尤其是解码密集的 RL 循环,吞吐量远低于预期便进入平台期。
- 原因: 273 GB/s 是规格上限,并非持续带宽;实测带宽在 180–192 GB/s 之间。
- 检查:
references/gotcha-checks.mdG5 — 将观察到的步长时间与实测区间对比,而非规格值。 - 修复: 按 180–192 GB/s 来规划吞吐量;修订基于 273 GB/s 数值制定的方案。
G6:全局 UMA 资源争用
- 症状: 某个进程的 KV cache/权重在运行中途被静默逐出,其自身日志中没有 OOM。
- 原因: 统一内存是一个全局池;一个未设上限或接近容量的进程会与其他任何进程竞争,并可能将其逐出。一个小规模、有上限的工作负载则不会——一个 <4GB 的 LoRA 可与上限设为
gpu-memory-utilization<=0.5的 vLLM 共存无碍。 - 检查:
references/gotcha-checks.mdG6 — 其他驻留 GPU 的进程以及它们是否设了上限。 - 修复: “单一重负载作业”规则适用于未设上限或接近容量的工作负载——先给无关服务设上限或将其停止。一个小规模、有上限的工作负载则无需停止。
G7:在 SM121 上 NVFP4 比 FP8 更慢
- 症状: 在 Spark 上将推理工作负载从 FP8 切换到 NVFP4 后反而更慢,而不是更快。
- 原因: 除非内核以
sm_121a为目标,SM121 缺少cvt.e2m1x2;缺少它时 NVFP4 运行速度约慢 32%。 - 检查:
references/gotcha-checks.mdG7 — 能力报告为(12, 1);构建是否以sm_121a为目标? - 修复: 除非构建以
sm_121a为目标,否则继续使用 FP8。
G8:过时的官方 Playbook
- 症状: 按照官方 DGX Spark playbook 操作仍然失败,且没有本地配置错误可以解释。
- 原因: 官方 playbook 以前就发布过有问题的版本;技术栈的演进快于文档。
- 检查:
references/gotcha-checks.mdG8 — 该 playbook 仓库近期的 issue。 - 修复: 在信任某个配方进行高昂成本的运行之前,先查看
github.com/NVIDIA/dgx-spark-playbooks的 issue。
G9:容器优先,而非裸 pip
- 症状: 昨天还能用的裸 pip 环境在一次无关的
pip install之后坏了,或者两个“完全相同”的环境表现不同。 - 原因: 裸 pip 让 Triton、xformers 和 transformers 各自漂移;没有任何东西将它们固定到 GB10 的 SM121 目标上。
- 检查:
references/gotcha-checks.mdG9 — 容器还是裸 pip? - 修复: 优先使用 NGC 容器(标签指引见
spark-environment-setup)或 Unsloth 的容器。如果无法避免裸 pip,请遵循 NVIDIA 的安装顺序,包括对 Unsloth 使用--no-deps。
G10:双 Spark 仅支持 DDP/FSDP
- 症状: 跨两台 Spark 的张量并行启动会挂起、比单台 Spark 慢得多,或报错。
- 原因: ConnectX-7 的速度足以进行梯度/参数同步(DDP、FSDP),但对于 TP 的细粒度流量来说过于单薄。
- 检查:
references/gotcha-checks.mdG10 — 所配置的并行策略。 - 修复: 在两台 Spark 的配置中,选择 DDP 或 FSDP,绝不要用张量并行——这里 TP 仅限单节点。
快速排查
在其他操作之前最先要运行的最廉价检查:
python3 -c "import torch; print(torch.version.cuda)" # expect 13.x (G1); NGC builds have no +cu130 tag — that's not a failure
import torch; print(torch.cuda.get_device_capability()) # expect (12, 1) (G7)
{ [ -f /.dockerenv -o -f /run/.containerenv ] || grep -qE 'docker|containerd' /proc/1/cgroup; } 2>/dev/null && echo container || echo unknown # G9
assets/preflight.sh 会运行 G1、G3、G4、G7、G9,并以固定格式为每个坑输出一行:先是 G 编号,然后是 PASS/FAIL/WARN(可自动化的部分)、不可用时的 SKIP,或用于原始读数的 INFO:(G3、G4)。完整命令见:references/gotcha-checks.md。假定可用的环境另见 spark-environment-setup。
评论
支持 Markdown