ITADN

[BUG] LinearFunctionForZeroStage3 crashes with torch.func transforms (missing setup_context)

#7913Openroycho96 创建于 2026-03-19
bugtraining
R
roycho96commented
**Describe the bug** `LinearFunctionForZeroStage3` in `deepspeed/runtime/zero/linear.py` uses the legacy `autograd.Function` pattern where `forward(ctx, ...)` directly calls `ctx.save_for_backward()`. This crashes when any code path uses `torch.func` transforms (`torch.func.grad`, `torch.func.grad_and_value`, `vmap`, etc.) on a model running with ZeRO Stage 3. ``` RuntimeError: In order to use an autograd.Function with functorch transforms (vmap, grad, jvp, jacrev, ...), it must override the setup_context staticmethod. ``` This affects any library that uses `torch.func` internally, including Liger-Kernel (fused cross-entropy) and Axolotl's KD (Knowledge Distillation) kernel. **To Reproduce** 1. Enable ZeRO Stage 3 2. Use any operation that internally calls `torch.func.grad_and_value` during forward/loss computation (e.g. Axolotl offline KD with Liger kernel, or any custom loss using functorch) 3. Training crashes at the first forward pass Minimal example: ```python import torch import deepspeed model = ... # any model model, _, _, _ = deepspeed.initialize(model=model, config={"zero_optimization": {"stage": 3}, ...}) # Any torch.func usage on a ZeRO-3 wrapped model triggers the crash # because F.linear is replaced by LinearFunctionForZeroStage3 # which lacks setup_context torch.func.grad_and_value(some_loss_fn)(params, inputs) ``` **Expected behavior** `LinearFunctionForZeroStage3` should be compatible with `torch.func` transforms. The `ctx` usage in `forward` is minimal (only `save_for_backward`), so splitting into the `setup_context` pattern is straightforward: ```python # Current (crashes with torch.func) class LinearFunctionForZeroStage3(torch.autograd.Function): @staticmethod def forward(ctx, input, weight, bias=None): ctx.save_for_backward(input, weight, bias) ... # Fix: separate setup_context (compatible with torch.func) class LinearFunctionForZeroStage3(torch.autograd.Function): @staticmethod def forward(input, weight, bias=None): ... return ret @staticmethod def setup_context(ctx, inputs, output): input, weight, bias = inputs ctx.save_for_backward(input, weight, bias) ``` `backward` needs no changes. Note: `setup_context` requires PyTorch >= 2.0, so a version-conditional definition may be needed if PyTorch < 2.0 support is still required. **ds_report output** ``` DeepSpeed C++/CUDA extension op report NOTE: Alarm op not installed NOTE: AsyncIO op not installed ... torch install path: /usr/local/lib/python3.11/dist-packages/torch torch version: 2.8.0+cu128 deepspeed install path: /usr/local/lib/python3.11/dist-packages/deepspeed deepspeed info: 0.16.4, unknown, unknown torch cuda version: 12.8 torch hip version: None nvcc version: Not Available deepspeed wheel compiled w.: torch 2.8, cuda 12.8 ``` **System info:** - OS: Ubuntu 22.04 - GPU: H100 80GB PCIe - Python: 3.11 - PyTorch: 2.8.0+cu128 **Launcher context** deepspeed CLI launcher **Additional context** The root cause is that PyTorch's `torch.func` transforms require `autograd.Function` subclasses to use the separate `forward()` + `setup_context()` pattern instead of the combined `forward(ctx, ...)` pattern. This is documented in [Extending torch.func with autograd.Function](https://docs.pytorch.org/docs/stable/notes/extending.func.html). The current `forward` only uses `ctx` for a single `save_for_backward` call, making the migration minimal. The `backward` method uses `ctx.saved_tensors` and `ctx.needs_input_grad`, both of which work identically with the new pattern. One consideration: `setup_context` was introduced in PyTorch 2.0. DeepSpeed's documented minimum is PyTorch 1.9+. if PyTorch < 2.0 is no longer actively supported, the migration can be done unconditionally. Happy to submit a PR if this direction is acceptable.
2 条评论