Skip to content

Commit 4699840

Browse files
author
intern_nem_dev_1
committed
Fix packed compat gpt step arity
1 parent f65dafd commit 4699840

6 files changed

Lines changed: 201 additions & 20 deletions

File tree

src/nemotron/recipes/super3/stage1_sft/packed_compat_step.py

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,19 @@ def __getattr__(self, name: str) -> Any:
128128
return getattr(self._model, name)
129129

130130

131-
def forward_step(data_iterator: Any, model: Any): # pragma: no cover - cluster path
132-
"""GPT forward step with Mamba packed-sequence keyword compatibility."""
131+
def forward_step(
132+
state_or_data_iterator: Any,
133+
data_iterator_or_model: Any,
134+
model: Any | None = None,
135+
return_schedule_plan: bool = False,
136+
): # pragma: no cover - cluster path
137+
"""GPT forward step with Mamba packed-sequence keyword compatibility.
138+
139+
Megatron-Bridge has shipped both ``forward_step(data_iterator, model)`` and
140+
``forward_step(state, data_iterator, model, return_schedule_plan=False)``.
141+
Keep both call shapes so local static tests and runtime Bridge training use
142+
the same compatibility adapter.
143+
"""
133144
try:
134145
from megatron.bridge.training.gpt_step import forward_step as upstream_forward_step
135146
except ImportError as exc:
@@ -139,8 +150,21 @@ def forward_step(data_iterator: Any, model: Any): # pragma: no cover - cluster
139150
"SFT `step_function`."
140151
) from exc
141152

153+
if model is None:
154+
data_iterator = state_or_data_iterator
155+
model = data_iterator_or_model
156+
with _drop_unsupported_packed_seq_params(model) as compat_model:
157+
return upstream_forward_step(data_iterator, compat_model)
158+
159+
state = state_or_data_iterator
160+
data_iterator = data_iterator_or_model
142161
with _drop_unsupported_packed_seq_params(model) as compat_model:
143-
return upstream_forward_step(data_iterator, compat_model)
162+
return upstream_forward_step(
163+
state,
164+
data_iterator,
165+
compat_model,
166+
return_schedule_plan=return_schedule_plan,
167+
)
144168

145169

146170
__all__ = [

tests/recipes/super3/test_sft_packed_compat_step.py

Lines changed: 90 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
from __future__ import annotations
22

3+
import inspect
34
import sys
45
import types
6+
from collections.abc import Callable
57
from typing import Any
68

79
from nemotron.recipes.super3.stage1_sft import packed_compat_step
@@ -47,17 +49,11 @@ def forward(
4749
return tokens, packed_seq_params
4850

4951

50-
def _install_stub_gpt_step() -> None:
52+
def _install_stub_gpt_step(forward_step: Callable[..., Any]) -> None:
5153
for parent in ("megatron", "megatron.bridge", "megatron.bridge.training"):
5254
sys.modules.setdefault(parent, types.ModuleType(parent))
5355

5456
gpt_step = types.ModuleType("megatron.bridge.training.gpt_step")
55-
56-
def forward_step(data_iterator: Any, model: Any) -> tuple[Any, Any]:
57-
del data_iterator
58-
output = model(tokens="batch", packed_seq_params={"packed": True})
59-
return output, lambda output_tensor: output_tensor
60-
6157
gpt_step.forward_step = forward_step
6258
sys.modules["megatron.bridge.training.gpt_step"] = gpt_step
6359

@@ -72,12 +68,31 @@ def _remove_stub_gpt_step() -> None:
7268
sys.modules.pop(module_name, None)
7369

7470

75-
def test_packed_compat_step_drops_packed_seq_params_for_mamba_like_leaf() -> None:
71+
def _two_arg_upstream(data_iterator: Any, model: Any) -> tuple[Any, Any]:
72+
del data_iterator
73+
output = model(tokens="batch", packed_seq_params={"packed": True})
74+
return output, lambda output_tensor: output_tensor
75+
76+
77+
def test_packed_compat_step_signature_supports_state_aware_bridge_arity() -> None:
78+
signature = inspect.signature(packed_compat_step.forward_step)
79+
80+
assert list(signature.parameters) == [
81+
"state_or_data_iterator",
82+
"data_iterator_or_model",
83+
"model",
84+
"return_schedule_plan",
85+
]
86+
assert signature.parameters["model"].default is None
87+
assert signature.parameters["return_schedule_plan"].default is False
88+
89+
90+
def test_packed_compat_step_keeps_existing_two_arg_stub_behavior() -> None:
7691
leaf = _MambaLikeLeaf()
7792
model = _ForwardingWrapper(_ForwardingWrapper(leaf))
7893
assert not packed_compat_step._model_forward_accepts_kwarg(model)
7994

80-
_install_stub_gpt_step()
95+
_install_stub_gpt_step(_two_arg_upstream)
8196
try:
8297
output, _loss = packed_compat_step.forward_step(iter(()), model)
8398
finally:
@@ -87,16 +102,79 @@ def test_packed_compat_step_drops_packed_seq_params_for_mamba_like_leaf() -> Non
87102
assert leaf.calls == [{"tokens": "batch", "position_ids": None}]
88103

89104

90-
def test_packed_compat_step_preserves_packed_seq_params_for_supported_leaf() -> None:
105+
def test_packed_compat_step_drops_packed_seq_params_for_state_aware_mamba_like_leaf() -> None:
106+
upstream_calls: list[dict[str, Any]] = []
107+
108+
def state_aware_upstream(
109+
state: Any,
110+
data_iterator: Any,
111+
model: Any,
112+
return_schedule_plan: bool = False,
113+
) -> tuple[Any, Any]:
114+
upstream_calls.append(
115+
{
116+
"state": state,
117+
"data_iterator": data_iterator,
118+
"return_schedule_plan": return_schedule_plan,
119+
}
120+
)
121+
output = model(tokens="batch", packed_seq_params={"packed": True})
122+
return output, lambda output_tensor: output_tensor
123+
124+
leaf = _MambaLikeLeaf()
125+
model = _ForwardingWrapper(_ForwardingWrapper(leaf))
126+
data_iterator = iter(())
127+
128+
_install_stub_gpt_step(state_aware_upstream)
129+
try:
130+
output, _loss = packed_compat_step.forward_step("state", data_iterator, model)
131+
finally:
132+
_remove_stub_gpt_step()
133+
134+
assert output == ("batch", None)
135+
assert leaf.calls == [{"tokens": "batch", "position_ids": None}]
136+
assert upstream_calls == [
137+
{"state": "state", "data_iterator": data_iterator, "return_schedule_plan": False}
138+
]
139+
140+
141+
def test_packed_compat_step_preserves_packed_seq_params_for_state_aware_supported_leaf() -> None:
142+
upstream_calls: list[dict[str, Any]] = []
143+
144+
def state_aware_upstream(
145+
state: Any,
146+
data_iterator: Any,
147+
model: Any,
148+
return_schedule_plan: bool = False,
149+
) -> tuple[Any, Any]:
150+
upstream_calls.append(
151+
{
152+
"state": state,
153+
"data_iterator": data_iterator,
154+
"return_schedule_plan": return_schedule_plan,
155+
}
156+
)
157+
output = model(tokens="batch", packed_seq_params={"packed": True})
158+
return output, lambda output_tensor: output_tensor
159+
91160
leaf = _PackedAwareLeaf()
92161
model = _ForwardingWrapper(_ForwardingWrapper(leaf))
93162
assert packed_compat_step._model_forward_accepts_kwarg(model)
163+
data_iterator = iter(())
94164

95-
_install_stub_gpt_step()
165+
_install_stub_gpt_step(state_aware_upstream)
96166
try:
97-
output, _loss = packed_compat_step.forward_step(iter(()), model)
167+
output, _loss = packed_compat_step.forward_step(
168+
"state",
169+
data_iterator,
170+
model,
171+
return_schedule_plan=True,
172+
)
98173
finally:
99174
_remove_stub_gpt_step()
100175

101176
assert output == ("batch", {"packed": True})
102177
assert leaf.calls == [{"tokens": "batch", "packed_seq_params": {"packed": True}}]
178+
assert upstream_calls == [
179+
{"state": "state", "data_iterator": data_iterator, "return_schedule_plan": True}
180+
]
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
# intern_nem_dev_1 - Status
22

3-
<!-- METADATA:STATUS=Working,TASK=task211_qwen_sft_mamba_packed_seq_params_compat_s1,ROLE=dev,SESSION=2 -->
3+
<!-- METADATA:STATUS=Working,TASK=task213_qwen_sft_packed_compat_gpt_step_arity_s1,ROLE=dev,SESSION=1 -->
44

55
| Field | Value |
66
|------|-----|
77
| Name | intern_nem_dev_1 |
88
| Status | Working |
9-
| Current Task | task211_qwen_sft_mamba_packed_seq_params_compat_s1 |
10-
| PR | https://github.com/songCNMS/Nemotron/pull/309 |
11-
| Session | 2 |
12-
| Recent Progress | PR #309 open and mergeable; final checks passed; pushing Session 2 status/report closeout |
9+
| Current Task | task213_qwen_sft_packed_compat_gpt_step_arity_s1 |
10+
| PR | Pending |
11+
| Session | 1 |
12+
| Recent Progress | Accepted task213; fixed packed compat adapter state-aware gpt_step arity and started validation |
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# task213_qwen_sft_packed_compat_gpt_step_arity_s1
2+
3+
<!-- METADATA:STATUS=InProgress,ASSIGNEE=intern_nem_dev_1,SESSION=1 -->
4+
5+
## Scope
6+
7+
- Fix the task212 evidence failure in
8+
`src/nemotron/recipes/super3/stage1_sft/packed_compat_step.py`.
9+
- Preserve Megatron-Bridge state-aware `gpt_step` arity:
10+
`(state, data_iterator, model, return_schedule_plan=False)`.
11+
- Keep compatibility with existing local two-argument test stubs where
12+
reasonable.
13+
- Continue filtering `packed_seq_params` only around the model argument, and
14+
only for model forward chains that do not support that keyword.
15+
16+
## Boundaries
17+
18+
- Product code/tests/docs only.
19+
- No live train, package install, endpoint, benchmark, W&B, cluster/deploy,
20+
artifact upload, direct `main`/`master` push, or self-merge.
21+
22+
## Status
23+
24+
- Base: `f65dafdb15b28342c1fbd4a5ead807052bcdd264`.
25+
- Branch: `intern_nem_dev_1/task213_qwen_sft_packed_compat_gpt_step_arity_s1`.
26+
- PR: pending.
27+
- Current implementation:
28+
- `packed_compat_step.forward_step` now accepts the runtime
29+
state-aware Bridge call shape and passes `state`, `data_iterator`, `model`,
30+
and `return_schedule_plan` through to upstream `gpt_step`.
31+
- Existing two-argument stub behavior is retained for local static tests.
32+
- Focused tests now cover state-aware Mamba-like drop, packed-aware preserve,
33+
`return_schedule_plan` propagation, legacy two-arg behavior, and dispatch
34+
wiring.
35+
- Checks completed so far:
36+
- `PYTHONPATH=src /work-agents/.venv/bin/python -m pytest -q tests/recipes/super3/test_sft_packed_compat_step.py tests/recipes/super3/test_sft_forward_step_dispatch.py`
37+
-> `10 passed, 1 skipped`.
38+
- `PYTHONPATH=src /work-agents/.venv/bin/python -m pytest -q tests/recipes/super3/test_m1_agentic_sft.py -k 'qwen_local_train or qwen30b_a3b_local_train'`
39+
-> `10 passed, 86 deselected`.
40+
- `PYTHONPATH=src /work-agents/.venv/bin/python -m pytest -q tests/recipes/super3/test_qwen_chat_contract.py tests/recipes/super3/test_stage1_sft_default_config.py tests/recipes/super3/test_m1_agentic_sft.py -k 'qwen or sft or packed or data_prep or target_family'`
41+
-> `136 passed, 1 skipped`.
42+
- `/work-agents/.venv/bin/ruff check src/nemotron/recipes/super3/stage1_sft/packed_compat_step.py tests/recipes/super3/test_sft_packed_compat_step.py tests/recipes/super3/test_sft_forward_step_dispatch.py`
43+
-> passed.
44+
- Blockers: none currently.
45+
- Residual risk: no live SFT training rerun per PM boundary.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# History Log
2+
3+
<!-- METADATA:SESSION=1 -->
4+
5+
## Session 1 - 2026-05-30
6+
7+
- Accepted PM task213 on branch
8+
`intern_nem_dev_1/task213_qwen_sft_packed_compat_gpt_step_arity_s1`
9+
from base `f65dafdb15b28342c1fbd4a5ead807052bcdd264`.
10+
- Root cause from task212 evidence: task211 compatibility adapter called
11+
upstream `gpt_step.forward_step(data_iterator, compat_model)`, but runtime
12+
Megatron-Bridge uses state-aware signature
13+
`(state, data_iterator, model, return_schedule_plan=False)`.
14+
- Updated `packed_compat_step.forward_step` to support the state-aware call
15+
shape while retaining two-argument local stub compatibility.
16+
- Added focused tests for state-aware Mamba-like filtering, packed-aware
17+
preservation, `return_schedule_plan` propagation, legacy two-arg behavior,
18+
and adapter signature/dispatch wiring.
19+
- Began focused and broader SFT/Qwen validation; no live training or forbidden
20+
operations were run.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Task Knowledge
2+
3+
<!-- METADATA:SESSION=1 -->
4+
5+
- Runtime Megatron-Bridge `gpt_step.forward_step` in the task212 environment
6+
has signature `(state, data_iterator, model, return_schedule_plan=False)`.
7+
- The task211 adapter failed because it only called upstream
8+
`forward_step(data_iterator, compat_model)`, producing
9+
`TypeError: forward_step() missing 1 required positional argument: 'model'`.
10+
- `packed_compat_step.forward_step` must wrap only the model argument with
11+
`_drop_unsupported_packed_seq_params`; `state`, `data_iterator`, and
12+
`return_schedule_plan` must pass through unchanged.
13+
- The local two-argument test stub path is still useful because it keeps
14+
sandbox tests independent of an installed Megatron-Bridge runtime.

0 commit comments

Comments
 (0)