4. 故障分类与诊断方法
DeepSpeed 训练故障往往不是单一原因造成的,而是配置、硬件、通信、显存、数据与代码逻辑多因素叠加的结果。若没有统一的分类框架和诊断路径,工程师容易陷入“看到什么改什么”的试错循环。本节建立一套可复用的故障分类与诊断方法:先按故障域归类,再用日志与监控指标缩小范围,最后借助调试工具完成根因定位。
一、故障分类:先归类,再定位
DeepSpeed 的故障可以按“发生层次”和“表现形态”两个维度划分。按层次可分为配置层、显存层、通信层、计算层、数据层和硬件层;按表现形态可分为启动失败、训练中断、性能退化、结果异常和静默错误。分类的价值在于:不同类别的首选诊断手段不同,例如通信层优先看 NCCL 日志,显存层优先看 OOM 堆栈与显存快照。
| 故障域 | 典型表现 | 首选诊断入口 |
|---|---|---|
| 配置层 | 启动即报错、参数不生效 | ds_config.json 校验、启动命令回显 |
| 显存层 | CUDA OOM、碎片化、峰值突增 | OOM 堆栈、显存快照、ZeRO stage 配置 |
| 通信层 | NCCL timeout、hang、allreduce 卡住 | NCCL_DEBUG=INFO、torch.distributed 日志 |
| 计算层 | loss NaN、梯度爆炸、精度异常 | 梯度范数、loss scale 日志、算子检查 |
| 数据层 | dataloader 卡死、样本损坏 | 数据管道日志、单卡复现 |
| 硬件层 | ECC 错误、GPU 掉卡、NVLink 降速 | nvidia-smi、dmesg、DCGM 指标 |
二、日志分析:从海量输出中抓关键信号
DeepSpeed 日志分为三类:启动日志、训练步日志和异常堆栈。启动日志关注参数解析与引擎初始化;训练步日志关注 loss、grad norm、lr、step time;异常堆栈关注 Python traceback 与 CUDA/NCCL 错误码。建议在启动时开启分级日志:
export NCCL_DEBUG=INFO
export NCCL_DEBUG_SUBSYS=INIT,COLL
export TORCH_DISTRIBUTED_DEBUG=DETAIL
deepspeed --num_gpus=8 train.py \
--deepspeed ds_config.json \
2>&1 | tee train_$(date +%m%d_%H%M).log
分析时遵循“三看”原则:一看首个报错,而非最后一行;二看 rank 编号,定位是全局问题还是单卡问题;三看时间戳,判断是启动阶段、前向阶段还是反向阶段出错。若日志中出现 NCCL timeout,应优先检查网络与 rank 间通信;若出现 CUDA out of memory,则结合 ZeRO stage 与 batch size 分析。
三、监控指标:用数据判断故障边界
日志是离散事件,监控指标是连续信号。DeepSpeed 训练应重点监控以下指标:GPU 利用率、显存占用、显存碎片率、SM 活跃度、NVLink/PCIe 带宽、NCCL 通信耗时、step time、loss 与 grad norm。当 step time 突然上升而 GPU 利用率下降时,通常指向通信瓶颈或数据加载瓶颈;当显存占用持续爬升不释放时,需排查激活值缓存或未释放的中间张量。
四、调试工具:从观察到干预
当日志和指标不足以定位时,需要主动干预。常用工具包括:py-spy dump 抓取 Python 进程堆栈,判断是否卡在通信或数据加载;torch.distributed.breakpoint() 在指定 rank 进入交互式调试;cuda-gdb 定位 CUDA 核函数异常;nsys 与 ncu 分析算子级性能与显存行为。对于通信 hang,可在疑似卡住的 rank 上执行:
py-spy dump --pid $(pgrep -f train.py | head -1)
# 观察是否阻塞在 torch.distributed.all_reduce
# 或阻塞在 DataLoader 的 next() 调用
五、根因分析流程与常见误区
推荐的根因分析流程为:现象采集 → 故障归类 → 范围缩小 → 根因验证 → 修复 → 回归验证。范围缩小是关键步骤,常用“二分法”:先判断是单卡还是全局,再判断是单节点还是多节点,最后判断是配置问题还是代码问题。例如,8 卡训练中仅 rank 3 报 OOM,优先检查该卡是否有其他进程占用或数据分片不均。
常见误区有三:一是只看最后一行报错,忽略首个异常;二是直接调大 batch size 或关闭 ZeRO 来“绕过”问题,掩盖真实根因;三是缺少对照实验,无法确认修复是否有效。复盘时应记录:故障现象、影响范围、根因、修复动作、回归结果和预防措施,形成可检索的故障知识库。