Repository navigation
[fix][megatron] Call mark_not_offload in the fused LM head path - #2522
dyurk-lila wants to merge 1 commit into
Conversation
With fine_grained_activation_offloading enabled, call_model_with_fused_lm_head marks the output-layer parameters as not offloadable through FineGrainedActivationOffloadingInterface.mark_not_offloadable. Megatron-core does not have that method; its API is the staticmethod mark_not_offload(tensor). Setting both transformer_config_kwargs.fine_grained_activation_offloading=true and trainer.fused_lm_head_logprob=true therefore raises AttributeError in the policy forward. Call mark_not_offload instead. Rename the unit-test stub to the real method (the stub had the same wrong name, which hid the bug), and add a test that checks the installed megatron-core interface exposes mark_not_offload. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Code Review
This pull request updates the activation offloading interface from mark_not_offloadable to mark_not_offload to align with changes in the Megatron API, and updates the corresponding tests. A review comment suggests improving the new guard test by skipping only if the top-level megatron package is missing, rather than the deep submodule path, to prevent the test from being silently skipped if the submodule is renamed or moved.
|
|
||
| def test_megatron_offload_interface_exposes_mark_not_offload(): | ||
| # The stub above must track the real interface; guard against the method name drifting. | ||
| offload = pytest.importorskip("megatron.core.pipeline_parallel.fine_grained_activation_offload") |
There was a problem hiding this comment.
Using pytest.importorskip on the deep submodule path megatron.core.pipeline_parallel.fine_grained_activation_offload will cause the test to be silently skipped if the submodule is renamed, moved, or removed in future Megatron versions. This defeats the purpose of this guard test, which is to detect drift or changes in the Megatron interface. Instead, skip only if the top-level megatron package is missing, and perform a standard import for the submodule so that any internal changes or drift will trigger a test failure.
| offload = pytest.importorskip("megatron.core.pipeline_parallel.fine_grained_activation_offload") | |
| pytest.importorskip("megatron") | |
| import megatron.core.pipeline_parallel.fine_grained_activation_offload as offload |
[Medium impact] The change reaches a bounded Megatron training path. The fix appears safe to merge, with a non-blocking gap in the new test's CI coverage. Findings
Reviews (1) · Last reviewed commit: "[fix][megatron] Call mark_not_offload in..." · Reviewed by Greptile |
| ) | ||
|
|
||
|
|
||
| def test_megatron_offload_interface_exposes_mark_not_offload(): |
There was a problem hiding this comment.
The new test never checks the real Megatron interface in CPU CI. The job that installs Megatron selects only tests marked megatron, but this test has no marker. The other jobs lack Megatron, so pytest.importorskip skips it. Add @pytest.mark.megatron to this test so CI can catch another method-name change instead of letting the stub tests pass while training breaks.
| def test_megatron_offload_interface_exposes_mark_not_offload(): | |
| @pytest.mark.megatron | |
| def test_megatron_offload_interface_exposes_mark_not_offload(): |
What breaks
On the Megatron backend, enabling both
transformer_config_kwargs.fine_grained_activation_offloading: trueandtrainer.fused_lm_head_logprob: truecrashes in the policy forward:Root cause
call_model_with_fused_lm_head(skyrl/backends/skyrl_train/distributed/megatron/fused_lm_head.py) turns off Megatron post-processing and handles the LM head itself. Because of that, it has to mark the output-layer parameters as not offloadable on its own, and it does so withFineGrainedActivationOffloadingInterface.mark_not_offloadable. That method doesn't exist at the pinned megatron-core commit (07147d6942dfd4e6d1566b64bb1730f478a1bc32). The real method is the staticmethodmark_not_offload(tensor)inmegatron/core/pipeline_parallel/fine_grained_activation_offload.py. The unit test's stub of the interface used the same wrong name, so the tests never caught the bug.Fix
off_interface.mark_not_offload(parameter). This is the only call site.tests/backends/skyrl_train/distributed/test_fused_lm_head.pytomark_not_offload, and have it set the same_do_not_offloadflag that Megatron's implementation sets.test_megatron_offload_interface_exposes_mark_not_offload. It checks that the installed megatron-core interface hasmark_not_offload, and skips if megatron-core isn't installed. If the method is renamed again, this test fails, so the stub can't silently drift from the real interface.Tests
hasattr(FineGrainedActivationOffloadingInterface, "mark_not_offload")isTrue, andhasattr(..., "mark_not_offloadable")isFalse.pytest tests/backends/skyrl_train/distributed/test_fused_lm_head.py: 14 passed (CPU).AttributeErrorshown above.ruff(v0.11.9) andblack(24.10.0) are clean on the changed files.🤖 Generated with Claude Code
Note
Low Risk
Single-call-site rename to match megatron-core; fixes a runtime AttributeError with no auth or data-path changes.
Overview
Fixes a crash when fine-grained activation offloading and fused LM head logprob are both enabled on the Megatron HybridModel path:
call_model_with_fused_lm_headnow calls Megatron’sFineGrainedActivationOffloadingInterface.mark_not_offloadinstead of the non-existentmark_not_offloadablewhen marking output-layer parameters before bypassing post-processing.Tests are aligned with the real API (
_do_not_offloadon tensors), and a new integration-style check asserts that installed megatron-core exposesmark_not_offloadso the stub cannot drift again.Reviewed by Cursor Bugbot for commit 00a5f96. Bugbot is set up for automated code reviews on this repo. Configure here.