Skip to content

fix: add setup_context for torch.func compatibility - #7916

Merged
tohtana merged 28 commits into
deepspeedai:masterfrom
roycho96:fix/support-func-torch
May 21, 2026
Merged

tohtana merged 28 commits into
deepspeedai:masterfrom
roycho96:fix/support-func-torch

Conversation

@roycho96

Copy link
Copy Markdown
Contributor

LinearFunctionForZeroStage3 uses the legacy forward(ctx, ...) pattern which is incompatible with torch.func transforms (torch.func.grad, torch.func.grad_and_value, vmap, etc.):

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 on a ZeRO-3 model.

Fix

Fixes #7913

Note

As pointed out by @zhangj1an in #7913, PostBackwardFunctionModule and PreBackwardFunctionForModule in parameter_offload.py have the same issue. Those will be addressed in a follow-up commit within this PR.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: eed37042bc

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread deepspeed/runtime/zero/linear.py Resolved
Comment thread deepspeed/runtime/zero/linear.py Resolved
@roycho96
roycho96 force-pushed the fix/support-func-torch branch from 252aea1 to 39b1755 Compare March 21, 2026 10:28
zhangj1an

This comment was marked as resolved.

@zhangj1an

This comment was marked as resolved.

@roycho96

Copy link
Copy Markdown
Contributor Author

Thanks for the work! I implemented the same fix, so it looks good to me. To reduce reviewer's effort, I had 2 minor comments. This should lead to linear.py to only have 17 insertions (+) and 7 deletions (-).

Hi @zhangj1an, I've sent you a collaborator invite to my fork. Feel free to push your fix directly to the branch. Thanks for the suggestion!

… setup_context

Co-authored-by: zhangj1an <[email protected]>
Signed-off-by: Sung Hyun Cho <[email protected]>
@zhangj1an
zhangj1an force-pushed the fix/support-func-torch branch from 444122c to 6df37af Compare March 22, 2026 08:45
…afe linear

Avoid asymmetric custom_bwd without custom_fwd on the setup_context forward path;
mirror forward AMP in backward via torch.amp.autocast.

Signed-off-by: Zhang <[email protected]>
PyTorch versions that expose autograd.Function.setup_context need the
modern forward + setup_context shape for torch.func / functorch.

Signed-off-by: Zhang <[email protected]>
@zhangj1an
zhangj1an force-pushed the fix/support-func-torch branch from 0a66444 to 5e83d05 Compare March 22, 2026 09:34
@zhangj1an

This comment was marked as resolved.

@zhangj1an

This comment was marked as resolved.

@roycho96
roycho96 marked this pull request as ready for review March 25, 2026 14:35
@roycho96
roycho96 requested a review from loadams as a code owner March 25, 2026 14:35

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 60d20da79f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread deepspeed/runtime/zero/linear.py Resolved
@roycho96

roycho96 commented Apr 4, 2026

Copy link
Copy Markdown
Contributor Author

@tohtana
Thank you for the review! Your PR #7920 is merged!
Seems like all the conflicts are solved.

@roycho96

Copy link
Copy Markdown
Contributor Author

@tohtana
Gentle ping, happy to address anything if needed, thanks!

@tohtana

tohtana commented May 20, 2026

Copy link
Copy Markdown
Collaborator

Hi @roycho96,
Sorry I have missed the update for a long time, and thank you for pinging me.
I'm happy to merge this PR now, but it seems the current update doesn't cover vmap. Do you want to update this PR before we merge or merge it now leaving it as follow-up work.

@roycho96

Copy link
Copy Markdown
Contributor Author

Hi @roycho96, Sorry I have missed the update for a long time, and thank you for pinging me. I'm happy to merge this PR now, but it seems the current update doesn't cover vmap. Do you want to update this PR before we merge or merge it now leaving it as follow-up work.

Thanks @tohtana! Sounds good to merge this one and I'll send a follow-up for vmap. It'll need generate_vmap_rule on LinearFunctionForZeroStage3 and the offload PreBackwardFunctionForModule / PostBackwardFunctionModule.

@tohtana tohtana left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay let's leave it for now and merge this PR now.

@tohtana
tohtana merged commit 67b9e21 into deepspeedai:master May 21, 2026
10 of 11 checks passed
@roycho96
roycho96 deleted the fix/support-func-torch branch May 21, 2026 05:27
tohtana added a commit that referenced this pull request May 24, 2026
Follow-up to #7916.

Adds `generate_vmap_rule = True` to `LinearFunctionForZeroStage3` so
`torch.func.vmap` works on the Function directly. The previous PR
covered `grad` / `jacrev` via `setup_context` but not `vmap`.

Test:
`pytest
tests/unit/v1/zero/test_zero_functorch_linear.py::TestLinearFunctionVmap`

Signed-off-by: Sung Hyun Cho <[email protected]>
Co-authored-by: Masahiro Tanaka <[email protected]>
tohtana added a commit that referenced this pull request May 28, 2026
)

Follow-up to #7916 and #8023.

Makes `torch.func.grad / grad_and_value / jacrev` and `vmap(grad)` work
when called directly on a DeepSpeed engine for ZeRO 0/1/2.

| API | ZeRO-0 | ZeRO-1 | ZeRO-2 | ZeRO-3 |
|---|---|---|---|---|
| `torch.func.grad(lambda x: engine(x))(x)` | ✓ | ✓ | ✓ | not yet |
| `torch.func.grad_and_value(lambda x: engine(x))(x)` | ✓ | ✓ | ✓ | not
yet |
| `torch.func.jacrev(lambda x: engine(x))(x)` | ✓ | ✓ | ✓ | not yet |
| `torch.func.vmap(torch.func.grad(...))(x_batch)` | ✓ | ✓ | ✓ | not yet
|
| `torch.func.vmap(lambda x: engine(x))(x_batch)` | already ✓ | already
✓ | already ✓ | not yet |
| `engine.backward(loss)` (regression) | ✓ | ✓ | ✓ | ✓ |

`vmap` alone runs only the forward graph so it never hit the broken
backward hooks and already worked before this PR; included in the table
for completeness.

Usage:
```python
engine, _, _, _ = deepspeed.initialize(model=model, ...)

# input gradient
g = torch.func.grad(lambda xi: engine(xi))(x)

# gradient and value in one pass
g, v = torch.func.grad_and_value(lambda xi: engine(xi))(x)

# Jacobian of output w.r.t. input
J = torch.func.jacrev(lambda xi: engine(xi))(x)

# per-sample input gradients (batched)
per_sample_g = torch.func.vmap(torch.func.grad(lambda xi: engine(xi)))(x_batch)
```

ZeRO-3 hits a separate SIGSEGV from the same APIs and is tracked
separately.

Test:
`pytest tests/unit/v1/zero/test_zero_torch_func.py`

---------

Signed-off-by: Sung Hyun Cho <[email protected]>
Co-authored-by: Masahiro Tanaka <[email protected]>
frozenleaves pushed a commit to frozenleaves/DeepSpeed that referenced this pull request Jun 8, 2026
`LinearFunctionForZeroStage3` uses the legacy `forward(ctx, ...)`
pattern which is incompatible with `torch.func` transforms
(`torch.func.grad`, `torch.func.grad_and_value`, `vmap`, etc.):
```
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 on a ZeRO-3
model.

## Fix

Fixes deepspeedai#7913 

## Note

As pointed out by @zhangj1an in deepspeedai#7913, `PostBackwardFunctionModule` and
`PreBackwardFunctionForModule` in `parameter_offload.py` have the same
issue. Those will be addressed in a follow-up commit within this PR.

---------

Signed-off-by: Sung Hyun Cho <[email protected]>
Signed-off-by: Zhang <[email protected]>
Signed-off-by: Masahiro Tanaka <[email protected]>
Signed-off-by: Zhang Jian <[email protected]>
Co-authored-by: zhangj1an <[email protected]>
Co-authored-by: Zhang Jian <[email protected]>
Co-authored-by: Masahiro Tanaka <[email protected]>
frozenleaves pushed a commit to frozenleaves/DeepSpeed that referenced this pull request Jun 8, 2026
Follow-up to deepspeedai#7916.

Adds `generate_vmap_rule = True` to `LinearFunctionForZeroStage3` so
`torch.func.vmap` works on the Function directly. The previous PR
covered `grad` / `jacrev` via `setup_context` but not `vmap`.

Test:
`pytest
tests/unit/v1/zero/test_zero_functorch_linear.py::TestLinearFunctionVmap`

Signed-off-by: Sung Hyun Cho <[email protected]>
Co-authored-by: Masahiro Tanaka <[email protected]>
frozenleaves pushed a commit to frozenleaves/DeepSpeed that referenced this pull request Jun 8, 2026
…epspeedai#8026)

Follow-up to deepspeedai#7916 and deepspeedai#8023.

Makes `torch.func.grad / grad_and_value / jacrev` and `vmap(grad)` work
when called directly on a DeepSpeed engine for ZeRO 0/1/2.

| API | ZeRO-0 | ZeRO-1 | ZeRO-2 | ZeRO-3 |
|---|---|---|---|---|
| `torch.func.grad(lambda x: engine(x))(x)` | ✓ | ✓ | ✓ | not yet |
| `torch.func.grad_and_value(lambda x: engine(x))(x)` | ✓ | ✓ | ✓ | not
yet |
| `torch.func.jacrev(lambda x: engine(x))(x)` | ✓ | ✓ | ✓ | not yet |
| `torch.func.vmap(torch.func.grad(...))(x_batch)` | ✓ | ✓ | ✓ | not yet
|
| `torch.func.vmap(lambda x: engine(x))(x_batch)` | already ✓ | already
✓ | already ✓ | not yet |
| `engine.backward(loss)` (regression) | ✓ | ✓ | ✓ | ✓ |

`vmap` alone runs only the forward graph so it never hit the broken
backward hooks and already worked before this PR; included in the table
for completeness.

Usage:
```python
engine, _, _, _ = deepspeed.initialize(model=model, ...)

# input gradient
g = torch.func.grad(lambda xi: engine(xi))(x)

# gradient and value in one pass
g, v = torch.func.grad_and_value(lambda xi: engine(xi))(x)

# Jacobian of output w.r.t. input
J = torch.func.jacrev(lambda xi: engine(xi))(x)

# per-sample input gradients (batched)
per_sample_g = torch.func.vmap(torch.func.grad(lambda xi: engine(xi)))(x_batch)
```

ZeRO-3 hits a separate SIGSEGV from the same APIs and is tracked
separately.

Test:
`pytest tests/unit/v1/zero/test_zero_torch_func.py`

---------

Signed-off-by: Sung Hyun Cho <[email protected]>
Co-authored-by: Masahiro Tanaka <[email protected]>
nathon-lee pushed a commit to nathon-lee/DeepSpeed_woo that referenced this pull request Jul 1, 2026
`LinearFunctionForZeroStage3` uses the legacy `forward(ctx, ...)`
pattern which is incompatible with `torch.func` transforms
(`torch.func.grad`, `torch.func.grad_and_value`, `vmap`, etc.):
```
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 on a ZeRO-3
model.

## Fix

Fixes deepspeedai#7913

## Note

As pointed out by @zhangj1an in deepspeedai#7913, `PostBackwardFunctionModule` and
`PreBackwardFunctionForModule` in `parameter_offload.py` have the same
issue. Those will be addressed in a follow-up commit within this PR.

---------

Signed-off-by: Sung Hyun Cho <[email protected]>
Signed-off-by: Zhang <[email protected]>
Signed-off-by: Masahiro Tanaka <[email protected]>
Signed-off-by: Zhang Jian <[email protected]>
Co-authored-by: zhangj1an <[email protected]>
Co-authored-by: Zhang Jian <[email protected]>
Co-authored-by: Masahiro Tanaka <[email protected]>
Signed-off-by: nathon-lee <[email protected]>
nathon-lee pushed a commit to nathon-lee/DeepSpeed_woo that referenced this pull request Jul 1, 2026
Follow-up to deepspeedai#7916.

Adds `generate_vmap_rule = True` to `LinearFunctionForZeroStage3` so
`torch.func.vmap` works on the Function directly. The previous PR
covered `grad` / `jacrev` via `setup_context` but not `vmap`.

Test:
`pytest
tests/unit/v1/zero/test_zero_functorch_linear.py::TestLinearFunctionVmap`

Signed-off-by: Sung Hyun Cho <[email protected]>
Co-authored-by: Masahiro Tanaka <[email protected]>
Signed-off-by: nathon-lee <[email protected]>
nathon-lee pushed a commit to nathon-lee/DeepSpeed_woo that referenced this pull request Jul 1, 2026
…epspeedai#8026)

Follow-up to deepspeedai#7916 and deepspeedai#8023.

Makes `torch.func.grad / grad_and_value / jacrev` and `vmap(grad)` work
when called directly on a DeepSpeed engine for ZeRO 0/1/2.

| API | ZeRO-0 | ZeRO-1 | ZeRO-2 | ZeRO-3 |
|---|---|---|---|---|
| `torch.func.grad(lambda x: engine(x))(x)` | ✓ | ✓ | ✓ | not yet |
| `torch.func.grad_and_value(lambda x: engine(x))(x)` | ✓ | ✓ | ✓ | not
yet |
| `torch.func.jacrev(lambda x: engine(x))(x)` | ✓ | ✓ | ✓ | not yet |
| `torch.func.vmap(torch.func.grad(...))(x_batch)` | ✓ | ✓ | ✓ | not yet
|
| `torch.func.vmap(lambda x: engine(x))(x_batch)` | already ✓ | already
✓ | already ✓ | not yet |
| `engine.backward(loss)` (regression) | ✓ | ✓ | ✓ | ✓ |

`vmap` alone runs only the forward graph so it never hit the broken
backward hooks and already worked before this PR; included in the table
for completeness.

Usage:
```python
engine, _, _, _ = deepspeed.initialize(model=model, ...)

# input gradient
g = torch.func.grad(lambda xi: engine(xi))(x)

# gradient and value in one pass
g, v = torch.func.grad_and_value(lambda xi: engine(xi))(x)

# Jacobian of output w.r.t. input
J = torch.func.jacrev(lambda xi: engine(xi))(x)

# per-sample input gradients (batched)
per_sample_g = torch.func.vmap(torch.func.grad(lambda xi: engine(xi)))(x_batch)
```

ZeRO-3 hits a separate SIGSEGV from the same APIs and is tracked
separately.

Test:
`pytest tests/unit/v1/zero/test_zero_torch_func.py`

---------

Signed-off-by: Sung Hyun Cho <[email protected]>
Co-authored-by: Masahiro Tanaka <[email protected]>
Signed-off-by: nathon-lee <[email protected]>
nathon-lee pushed a commit to nathon-lee/DeepSpeed_woo that referenced this pull request Jul 1, 2026
`LinearFunctionForZeroStage3` uses the legacy `forward(ctx, ...)`
pattern which is incompatible with `torch.func` transforms
(`torch.func.grad`, `torch.func.grad_and_value`, `vmap`, etc.):
```
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 on a ZeRO-3
model.

## Fix

Fixes deepspeedai#7913 

## Note

As pointed out by @zhangj1an in deepspeedai#7913, `PostBackwardFunctionModule` and
`PreBackwardFunctionForModule` in `parameter_offload.py` have the same
issue. Those will be addressed in a follow-up commit within this PR.

---------

Signed-off-by: Sung Hyun Cho <[email protected]>
Signed-off-by: Zhang <[email protected]>
Signed-off-by: Masahiro Tanaka <[email protected]>
Signed-off-by: Zhang Jian <[email protected]>
Co-authored-by: zhangj1an <[email protected]>
Co-authored-by: Zhang Jian <[email protected]>
Co-authored-by: Masahiro Tanaka <[email protected]>
nathon-lee pushed a commit to nathon-lee/DeepSpeed_woo that referenced this pull request Jul 1, 2026
Follow-up to deepspeedai#7916.

Adds `generate_vmap_rule = True` to `LinearFunctionForZeroStage3` so
`torch.func.vmap` works on the Function directly. The previous PR
covered `grad` / `jacrev` via `setup_context` but not `vmap`.

Test:
`pytest
tests/unit/v1/zero/test_zero_functorch_linear.py::TestLinearFunctionVmap`

Signed-off-by: Sung Hyun Cho <[email protected]>
Co-authored-by: Masahiro Tanaka <[email protected]>
nathon-lee pushed a commit to nathon-lee/DeepSpeed_woo that referenced this pull request Jul 1, 2026
…epspeedai#8026)

Follow-up to deepspeedai#7916 and deepspeedai#8023.

Makes `torch.func.grad / grad_and_value / jacrev` and `vmap(grad)` work
when called directly on a DeepSpeed engine for ZeRO 0/1/2.

| API | ZeRO-0 | ZeRO-1 | ZeRO-2 | ZeRO-3 |
|---|---|---|---|---|
| `torch.func.grad(lambda x: engine(x))(x)` | ✓ | ✓ | ✓ | not yet |
| `torch.func.grad_and_value(lambda x: engine(x))(x)` | ✓ | ✓ | ✓ | not
yet |
| `torch.func.jacrev(lambda x: engine(x))(x)` | ✓ | ✓ | ✓ | not yet |
| `torch.func.vmap(torch.func.grad(...))(x_batch)` | ✓ | ✓ | ✓ | not yet
|
| `torch.func.vmap(lambda x: engine(x))(x_batch)` | already ✓ | already
✓ | already ✓ | not yet |
| `engine.backward(loss)` (regression) | ✓ | ✓ | ✓ | ✓ |

`vmap` alone runs only the forward graph so it never hit the broken
backward hooks and already worked before this PR; included in the table
for completeness.

Usage:
```python
engine, _, _, _ = deepspeed.initialize(model=model, ...)

# input gradient
g = torch.func.grad(lambda xi: engine(xi))(x)

# gradient and value in one pass
g, v = torch.func.grad_and_value(lambda xi: engine(xi))(x)

# Jacobian of output w.r.t. input
J = torch.func.jacrev(lambda xi: engine(xi))(x)

# per-sample input gradients (batched)
per_sample_g = torch.func.vmap(torch.func.grad(lambda xi: engine(xi)))(x_batch)
```

ZeRO-3 hits a separate SIGSEGV from the same APIs and is tracked
separately.

Test:
`pytest tests/unit/v1/zero/test_zero_torch_func.py`

---------

Signed-off-by: Sung Hyun Cho <[email protected]>
Co-authored-by: Masahiro Tanaka <[email protected]>
weiji14 added a commit to regro-cf-autotick-bot/deepspeed-feedstock that referenced this pull request Aug 13, 2026
weiji14 added a commit to conda-forge/deepspeed-feedstock that referenced this pull request Aug 13, 2026
* updated v0.19.5

* MNT: Re-rendered with conda-smithy 2026.8.9 and conda-forge-pinning 2026.08.13.08.26.4

* Bump minimum version of pytorch to 2.0.0

Xref deepspeedai/DeepSpeed#7916

---------

Co-authored-by: Wei Ji <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

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

5 participants