DEBUG.WIKI
V.PS:让项目靠近用户,亚太、欧洲、北美 KVM VPS
IPPeak:从目标地区访问网页,住宅代理、SEO 监测、广告验证
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国

DDP 第二轮 forward 报上一轮 reduction 还没结束

排查未参与 loss 的可训练参数,再决定启用未使用参数检测或修正训练图。

多卡训练完成一轮后,下一次 forward 报 Expected to have finished reduction in the prior iteration。这类错误常伴随“参数没有用于产生 loss”的提示。

例如 unet 返回 noise_pred 和 align_loss,却只对后者反向传播,就需要检查返回图与 loss 的关系。把另一输出纳入计算图可以解决特定训练图中的未使用参数问题,但给输出一律加上零值 dummy loss 不是所有 DDP 错误的通用修复。应先确认哪些分支需要参与真实训练目标。

以下参数说明以 PyTorch 2.5.1 为基线,2.14.1 仍保留未使用参数检测和 static_graph 的使用条件。这些参数要求训练图满足各自条件;漏算的 loss 或意外切断的梯度,需要在训练代码里修正。其他通信错误,或另一个 mark a variable ready only once 异常,应分别定位。

DDP 等待各参数的梯度同步。如果某个可训练分支没有参与这一轮 loss,默认路径可能等不到它的梯度。多任务模型只训练一个头、条件路由跳过某层,或计算 loss 前把输出 detach,都值得沿计算图检查。

找到缺梯度的参数

在可控复现环境打开诊断后启动原脚本:

TORCH_DISTRIBUTED_DEBUG=DETAIL torchrun --standalone --nproc_per_node=2 train.py

诊断信息可能增加日志和开销,不宜长期留在生产训练任务。需要进一步定位时,可以在单进程的代表性 batch 上执行同样的 forward、loss 和 backward,然后打印:

for name, parameter in model.named_parameters():
    if parameter.requires_grad and parameter.grad is None:
        print(name)

检查应在 backward 后、zero_grad 前。单个 batch 没有梯度只能定位候选,不能证明该层整个训练都不用;动态路由要覆盖各条路径。也应检查 forward 返回结构,DDP 的未使用参数检测从返回的张量追踪图,返回但不参与 loss 的输出需要特别核对。

如果跳过参数是预期行为,可以在构造 DDP 时启用:

model = torch.nn.parallel.DistributedDataParallel(
    model, device_ids=[local_rank], find_unused_parameters=True,
)

这让 DDP 检测未使用参数,代价是额外的图遍历。它不会训练一个被意外切断梯度的分类头;若缺梯度来自错误的 detach 或漏掉一项 loss,应修正计算图。永久不用的头可以在封装 DDP 之前设为 requires_grad=False,并调整 optimizer;这会改变训练目标,不能只为了消除错误冻结本该训练的层。

static_graph=True 也不是通用替代。只有使用/未使用参数集合和训练图在整个循环保持稳定时才考虑它。修正后至少运行两轮,并覆盖条件分支,检查应训练参数的梯度、参数更新和各 rank 的完成状态。仅仅“第一轮没有报错”不足以验收这个故障。