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

fix: add setup_context for torch.func compatibility#7916
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 Outdated
Comment thread deepspeed/runtime/zero/linear.py Outdated
Signed-off-by: Sung Hyun Cho <hope5487@gmail.com>
… unpack error

Signed-off-by: Sung Hyun Cho <hope5487@gmail.com>
@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 <jianmusings@gmail.com>
Signed-off-by: Sung Hyun Cho <hope5487@gmail.com>
@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 <jianmusings@gmail.com>
PyTorch versions that expose autograd.Function.setup_context need the
modern forward + setup_context shape for torch.func / functorch.

Signed-off-by: Zhang <jianmusings@gmail.com>
@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 and others added 9 commits March 24, 2026 22:21
Signed-off-by: Zhang <jianmusings@gmail.com>
Signed-off-by: Zhang <jianmusings@gmail.com>
Signed-off-by: Zhang <jianmusings@gmail.com>
Signed-off-by: Zhang <jianmusings@gmail.com>
Signed-off-by: Zhang <jianmusings@gmail.com>
Signed-off-by: Zhang <jianmusings@gmail.com>
Signed-off-by: Zhang <jianmusings@gmail.com>
@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 Outdated
zhangj1an and others added 5 commits March 30, 2026 02:29
Signed-off-by: Zhang Jian <jianmusings@gmail.com>
Signed-off-by: Zhang Jian <jianmusings@gmail.com>
Signed-off-by: Zhang Jian <jianmusings@gmail.com>
@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 <hope5487@gmail.com>
Co-authored-by: Masahiro Tanaka <81312776+tohtana@users.noreply.github.com>
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 <hope5487@gmail.com>
Co-authored-by: Masahiro Tanaka <81312776+tohtana@users.noreply.github.com>
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 <hope5487@gmail.com>
Signed-off-by: Zhang <jianmusings@gmail.com>
Signed-off-by: Masahiro Tanaka <mtanaka@anyscale.com>
Signed-off-by: Zhang Jian <jianmusings@gmail.com>
Co-authored-by: zhangj1an <jianmusings@gmail.com>
Co-authored-by: Zhang Jian <zhang.jian@u.nus.edu>
Co-authored-by: Masahiro Tanaka <mtanaka@anyscale.com>
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 <hope5487@gmail.com>
Co-authored-by: Masahiro Tanaka <81312776+tohtana@users.noreply.github.com>
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 <hope5487@gmail.com>
Co-authored-by: Masahiro Tanaka <81312776+tohtana@users.noreply.github.com>
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 <hope5487@gmail.com>
Signed-off-by: Zhang <jianmusings@gmail.com>
Signed-off-by: Masahiro Tanaka <mtanaka@anyscale.com>
Signed-off-by: Zhang Jian <jianmusings@gmail.com>
Co-authored-by: zhangj1an <jianmusings@gmail.com>
Co-authored-by: Zhang Jian <zhang.jian@u.nus.edu>
Co-authored-by: Masahiro Tanaka <mtanaka@anyscale.com>
Signed-off-by: nathon-lee <leejianwoo@gmail.com>
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 <hope5487@gmail.com>
Co-authored-by: Masahiro Tanaka <81312776+tohtana@users.noreply.github.com>
Signed-off-by: nathon-lee <leejianwoo@gmail.com>
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 <hope5487@gmail.com>
Co-authored-by: Masahiro Tanaka <81312776+tohtana@users.noreply.github.com>
Signed-off-by: nathon-lee <leejianwoo@gmail.com>
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 <hope5487@gmail.com>
Signed-off-by: Zhang <jianmusings@gmail.com>
Signed-off-by: Masahiro Tanaka <mtanaka@anyscale.com>
Signed-off-by: Zhang Jian <jianmusings@gmail.com>
Co-authored-by: zhangj1an <jianmusings@gmail.com>
Co-authored-by: Zhang Jian <zhang.jian@u.nus.edu>
Co-authored-by: Masahiro Tanaka <mtanaka@anyscale.com>
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 <hope5487@gmail.com>
Co-authored-by: Masahiro Tanaka <81312776+tohtana@users.noreply.github.com>
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 <hope5487@gmail.com>
Co-authored-by: Masahiro Tanaka <81312776+tohtana@users.noreply.github.com>
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