Skip to content

Build TransformerConfig once in get_batch - #8525

Merged
deepakn94 merged 2 commits into
NVIDIA:mainfrom
deepakn94:dnarayanan/get_batch_config_once
Oct 28, 2026
Merged

deepakn94 merged 2 commits into
NVIDIA:mainfrom
deepakn94:dnarayanan/get_batch_config_once

Conversation

@deepakn94

Copy link
Copy Markdown
Contributor

Summary

get_batch in pretrain_gpt.py and pretrain_hybrid.py rebuilt the transformer config from args on every microbatch via core_transformer_config_from_args. That re-runs TransformerConfig.__post_init__ each time, so its validation warnings repeat in the log every step. For example, with --fp32-residual-connection the rank-0 log gets fp32_residual_connection is enabled, overriding pipeline_dtype from torch.bfloat16 to torch.float ... once per microbatch.

This caches the config per args object (_get_transformer_config(args)), so it is built once per training run and rebuilt only when the global args object is replaced. The fields get_batch reads (pipeline layout, MTP layer count, virtual pipeline size, tensor-parallel size and sequence parallelism, CP layouts) are fixed for the run.

The cache is keyed on the args object rather than being a bare lru_cache, so tests/unit_tests/data/test_get_batch.py, which builds fresh args per test and patches core_transformer_config_from_args, still gets a config built from each test's own args.

Testing

Not yet run; tests/unit_tests/data/test_get_batch.py is the relevant suite. Both changed files pass python -m py_compile.

🤖 Generated with Claude Code

get_batch in pretrain_gpt.py and pretrain_hybrid.py rebuilt the transformer config from args on every microbatch, which re-runs TransformerConfig.__post_init__ and repeats its validation warnings in the log every step. Cache the config per args object so it is built once and rebuilt only when the global args object is replaced.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Deepak Narayanan <dnarayanan@nvidia.com>
@copy-pr-bot

copy-pr-bot Bot commented Oct 26, 2026

Copy link
Copy Markdown

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

@deepakn94
deepakn94 marked this pull request as ready for review October 26, 2026 23:28
@deepakn94
deepakn94 requested a review from a team as a code owner October 26, 2026 23:29
@deepakn94 deepakn94 changed the title Build the transformer config once in get_batch Build the transformer config once in get_batch Oct 26, 2026
@deepakn94 deepakn94 changed the title Build the transformer config once in get_batch Build the TransformerConfig once in get_batch Oct 26, 2026
@deepakn94 deepakn94 changed the title Build the TransformerConfig once in get_batch Build TransformerConfig once in get_batch Oct 26, 2026

@svcnvidia-nemo-ci svcnvidia-nemo-ci left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Add regression coverage for cache reuse and invalidation

The caches added in pretrain_gpt.py and pretrain_hybrid.py have no accompanying regression test. The existing mocked packing case and pretraining case fetch only one batch per args object and do not assert constructor counts. Restoring construction on every microbatch would leave those assertions unchanged, allowing the repeated-warning bug to return undetected. This is a coverage gap, not an observed runtime failure in the proposed implementation.

Add a parameterized regression to test_get_batch.py. Exercise get_batch so the test protects both the helper and its call-site wiring. Repeated calls with the same args must reuse the config, while replacement with an equal-valued but distinct args object must rebuild it.

Suggested addition using the file’s existing imports; source-reasoned and not executed, so verify before adopting:

@pytest.mark.parametrize("script", [pretrain_gpt, pretrain_hybrid], ids=["gpt", "hybrid"])
def test_get_batch_caches_config_until_args_replaced(script, monkeypatch):
    args = SimpleNamespace(
        sequence_packing_scheduler="dp_balanced", dynamic_context_parallel=False
    )
    configs = [
        SimpleNamespace(
            virtual_pipeline_model_parallel_size=None,
            pipeline_model_parallel_layout=None,
            mtp_num_layers=None,
        )
        for _ in range(2)
    ]
    build_config = MagicMock(side_effect=configs)
    result = object()
    fetch_batch = MagicMock(return_value=result)
    monkeypatch.setattr(script, "_transformer_config_cache", None)
    monkeypatch.setattr(script, "get_args", lambda: args)
    monkeypatch.setattr(script, "core_transformer_config_from_args", build_config)
    monkeypatch.setattr(script, "mtp_on_this_rank_func", lambda **kwargs: False)
    monkeypatch.setattr(script, "get_batch_on_this_rank_for_sequence_packing", fetch_batch)
    pgs = ProcessGroupCollection(pp=object())

    for _ in range(2):
        assert script.get_batch(None, pg_collection=pgs) is result
        assert fetch_batch.call_args.kwargs["config"] is configs[0]
    build_config.assert_called_once_with(args)

    previous_args = args
    args = SimpleNamespace(**vars(previous_args))
    assert args == previous_args and args is not previous_args
    for _ in range(2):
        assert script.get_batch(None, pg_collection=pgs) is result
        assert fetch_batch.call_args.kwargs["config"] is configs[1]
    assert build_config.call_count == 2
    assert build_config.call_args.args[0] is args

Acceptance and preservation: for each entrypoint, two batches with the original args construct once; two further batches with replacement args bring the total to exactly two and receive the replacement config. Both phases must return the downstream result unchanged. Retain the existing packed-entrypoint assertions that explicit process groups and config are forwarded by identity, MTP selection respects vp_stage, and only Hybrid requests ContextParallelBatch.

Completed the light review of both changed files and their directly affected args-lifecycle, MTP, packing, and CP paths. No production correctness regression identified. Tests were not executed.

Review generated by codex. This was a full review. Request a full review with /review reset=true.

Add a regression test for pretrain_gpt.py and pretrain_hybrid.py that calls get_batch repeatedly and checks the config is built once per args object, and rebuilt when args is replaced by an equal but distinct object.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Deepak Narayanan <dnarayanan@nvidia.com>
@Phlip79

Phlip79 commented Oct 28, 2026

Copy link
Copy Markdown
Member

/review

@svcnvidia-nemo-ci svcnvidia-nemo-ci left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM. The prior coverage finding is resolved by the new parameterized regression. For both entrypoints, it checks one config construction across repeated calls, rebuilding when args is replaced by an equal-valued but distinct object, config forwarding by identity, and unchanged downstream return identity.

Completed the light follow-up against the previous reviewed head, including the new test’s integration and isolation. The existing process-group, virtual-stage MTP, and Hybrid return-interface assertions remain intact. No unresolved prior finding or qualifying introduced regression identified.

Source inspection only; tests were not executed.

Note: formal approval is not available for this request, so this review is posted as a comment only.

Review generated by codex. This was a findings-only review. Request a full review with /review reset=true.

@deepakn94
deepakn94 added this pull request to the merge queue Oct 28, 2026
@nemo-automation-bot

Copy link
Copy Markdown

🔄 Merge queue validation started!

You can track the progress here: https://github.com/NVIDIA/Megatron-LM/actions/runs/40701164380

@nemo-automation-bot

Copy link
Copy Markdown

🔄 Merge queue validation started!

You can track the progress here: https://github.com/NVIDIA/Megatron-LM/actions/runs/40716203359

Merged via the queue into NVIDIA:main with commit 51039e5 Oct 28, 2026
101 of 105 checks passed
@deepakn94
deepakn94 deleted the dnarayanan/get_batch_config_once branch October 28, 2026 17:27
nemo-autobot-origin Bot pushed a commit to svcnemo-autobot/Megatron-LM that referenced this pull request Nov 2, 2026
Single repair commit for the main slice 5812485 -> dev merge.

- ssm/kda: restore dev's `False` distribute_saved_activations argument
  in both KDA recompute checkpoints. The kda.py conflict resolution had
  taken main NVIDIA#7054's config read; dev's recompute contract (NVIDIA#8203,
  test_gdn_quantized_recompute) passes False, as dev's GDN does.
- tests/models/test_hybrid_mhc: main NVIDIA#7555 replaced mtp_layer_pattern
  with mtp_layer_config_list; assert the new attributes instead.
- tests/transformer/moe/test_route_metadata_cpu: the dispatcher test
  double accepts packed_seq_params, which main NVIDIA#8458 now passes.
- tests/transformer/test_attention_output_gate: the KDA test double sets
  two_stage_gates=False, read by main NVIDIA#7054's _apply_gated_norm.
- tests/data/test_get_batch: stub dev's prepare_packed_seq_params hook
  in main NVIDIA#8525's config-cache test; all main assertions are kept.
- ssm/kda: keep dev's direct-gate op order in _apply_gated_norm (norm,
  then gate reshape). main NVIDIA#7054 reshaped the gate first, which changed the
  compiled rounding that dev NVIDIA#8006's test_kda_gated_norm_preserves_upstream_
  rounding pins; main's two-stage branch is unchanged.
- tests/data/test_pretrain_gpt_dataset_config: main NVIDIA#8391 replaced
  pretrain_gpt's build_tokenizer(args) with get_tokenizer(); the dev test
  now patches get_tokenizer. Its assertion is unchanged.
- ssm/kda_layer_config: run validate_kda() before TransformerConfig's
  __post_init__ as well as after it. Dev NVIDIA#6556's shared GDN-family
  assertions ran first and preempted the KDA ValueErrors that main
  NVIDIA#7054's test_kda config tests expect. Dev's plain TransformerConfig
  checks are unchanged.
- tests/transformer/test_thd_cuda_graph: the dev HybridModel test double
  sets hybrid_layer_config_list=None, which main NVIDIA#7555 reads in
  HybridModel.forward. Main NVIDIA#7555 made the same change to its own hybrid
  test doubles. The test assertions are unchanged.
- functional goldens: refresh dev_dgx_h100 golden values for the four
  gpt3_mcore_te_tp2_pp2 mHC cases after main NVIDIA#7521 changed their
  numerics (local H100 runs on merge 44a8771).
- tests/unit_tests/ssm/test_kda.py: keep dev NVIDIA#6556 kda_safe_gate/kda_lower_bound on
  TransformerConfig (CLI flags); main NVIDIA#7054 placement check now excludes only those two
  fields and asserts they stay on the stack config.
- tests/unit_tests/ssm/test_kda.py: main NVIDIA#7054's recompute-acceptance test
  builds a non-hybrid experimental_attention_variant="kda" config. Dev NVIDIA#6556
  registers kda as a GDN-family variant, and dev requires
  linear_attention_freq for every standalone GDN-family model, so the kda
  case now passes linear_attention_freq=[1]. Dev's validation and the
  test assertion are unchanged.
- docker: pin the ARM64 MoK build to main NVIDIA#8210's 7a8cfb7f. The merged
  MoK backend passes shared_output_gate_weight to mok.functional.forward,
  and main's test_mok_numerics runs that path on GB200. Dev's a2ad2d0c
  pin does not accept the argument (GB200 CI TypeError in
  test_real_mok_ddp_numerics). 7a8cfb7f is a fast-forward of a2ad2d0c
  (2 commits) that already contains both hunks of dev's
  docker/patches/mok.patch, so the patch, its bind mount and the
  install_mok.sh patch argument are removed as on main, and the MoE
  README names the new snapshot. The AMD64 (H100) image still skips MoK;
  the rest of dev's Dockerfile.ci.dev is unchanged.

- .github/workflows/cicd-main.yml: NVIDIA-NeMo/RL 4aaa48fa (NVIDIA#4253) renamed
  tests/functional/L1_Functional_Tests_Megatron_4.sh to
  L1_Functional_Tests_Megatron_Generation.sh, so the NeMo RL dispatch
  pattern matched no script and the downstream pre-flight failed with
  "No test scripts match the requested selection". Point the pattern
  at the renamed script. Dev and main carry the same stale pattern.

Signed-off-by: svcnemo-autobot <svcnemo-autobot@nvidia.com>

This branch was previously deployed

2 inactive deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants