Skip to content

Port OLMoDDP transformer block + model#764

Merged
AkshitaB merged 9 commits into
akshitab/moe-v2-corefrom
akshitab/olmo-ddp-block-model
Jul 14, 2026
Merged

Port OLMoDDP transformer block + model#764
AkshitaB merged 9 commits into
akshitab/moe-v2-corefrom
akshitab/olmo-ddp-block-model

Conversation

@AkshitaB

Copy link
Copy Markdown
Contributor

Ports the fused OLMoDDP transformer block and model, bringing the MoE-v2 block/model up to their full feature set.

What's here

  • nn/ddp/block.py + model.py: the OLMoDDPTransformerBlock / OLMoDDPModel compute, EP dispatch, rowwise-FP8, TBO, and symmetric-memory buffer management.
  • nn/moe/v2/te/cpu_offload.py: Transformer-Engine CPU-offload helpers (currently unwired — offload is disabled by default; wiring lands with the TE work).
  • nn/moe/v2/block.py: convenience re-exports of the router/expert configs.
  • Transformer.prepare_cp_sequence_inputs: context-parallel sequence-sharding helper on the base model (shards input_ids/labels via the existing CP load balancer and returns the original sequence length for RoPE rebuild).

Notes

  • The experimental rowwise_wave / deepep_v2 backends are imported lazily at their dispatch sites and remain rejected by ExpertParallelConfig.
  • Block config keeps a single layer_norm field (split into attention/feed-forward norms in the constructor); CUDA events are allocated only when CUDA is available; num_flops_per_token is implemented on the block.
  • GPU-only paths are exercised by the src/test/nn/ddp suite; the CP + train-module integration test lands with the DDP train module.

🤖 Generated with Claude Code

@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: db85cdacdf

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

rope.warmup_cache(max_seq_len, device)

if self.lm_head is not None and not self.tie_word_embeddings:
if self.lm_head is not None:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Preserve tied embedding storage during initialization

When tie_word_embeddings=True, self.to_empty() has already allocated fresh storage for the embedding and LM-head parameters, so the model must call _tie_weights() again before returning. This branch now runs for tied models and there is no subsequent re-tie, leaving the LM head as an independent output matrix despite the config and silently training/saving the wrong architecture.

Useful? React with 👍 / 👎.

Comment thread src/olmo_core/nn/ddp/block.py Outdated
Comment on lines +1097 to +1098
rowwise_fp8_cfg = self.rowwise_fp8
use_rowwise_fp8 = (
rowwise_fp8_cfg is not None
and rowwise_fp8_cfg.enabled
and mlp_inp.device.type == "cuda"
)
use_rowwise_fp8 = rowwise_fp8_cfg is not None and rowwise_fp8_cfg.enabled

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep the CPU fallback for shared FP8 blocks

For shared-only blocks with rowwise_fp8.enabled=True on CPU, this now sets use_rowwise_fp8 solely from the config and immediately calls assert_runtime_supported(), which raises because rowwise FP8 requires CUDA. The previous device guard fell back to the normal shared expert path on CPU, so CPU smoke tests or CPU materialized/eval runs with an FP8 config now fail before reaching the dense fallback.

Useful? React with 👍 / 👎.

Base automatically changed from akshitab/olmo-ddp-experts-variants to akshitab/moe-v2-core July 14, 2026 03:09
AkshitaB and others added 2 commits July 13, 2026 20:10
Take olmo-ddp's nn/ddp/block.py and model.py wholesale, then reconcile with core:
pull te/cpu_offload forward, lazy-import the deferred rowwise_wave/deepep_v2
backends, make nvtx optional, and drop olmo-ddp cruft (dead selective-checkpoint
machinery, a shadowed apply_ep stub, scattered imports, unused locals).

Re-apply core cleanups the wholesale checkout dropped: keep the single-layer_norm
block config (split only in the constructor), guard CUDA-event allocation behind
torch.cuda.is_available() with the _tbo1 names the merged EP modules expect, and
restore the block-level num_flops_per_token (routing attention through
num_flops_per_token instead of a config-level flops_per_seq core lacks).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Tianhua Tao <taotianhua@outlook.com>
Pull forward olmo-ddp's context-parallel sequence-sharding helper onto the base
Transformer. It shards input_ids/labels via the existing _cp_load_balancer.batch_shard
and returns the original sequence length so pipeline stages can rebuild RoPE buffers
consistently. Self-contained (core already has the CP load balancer); full CP train
wiring lands with the DDP train module.

The rest of olmo-ddp's shared transformer/block.py + model.py diff is intentionally
not taken: the shared-block norm split (#687) is rejected in favor of core's single
layer_norm, weight-tying is kept, and the v1 MoEHybrid overlap isn't on the OLMoDDP path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Tianhua Tao <taotianhua@outlook.com>
@AkshitaB
AkshitaB force-pushed the akshitab/olmo-ddp-block-model branch from db85cda to 23af3c2 Compare July 14, 2026 03:13

@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: 23af3c26d0

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

"When TBO and EP no-sync are enabled, EP shared_slots must be >= 2 "
f"(block={moe_block.block_idx}, got {moe_block.ep.shared_slots})."
)
if moe_block.ep.path != ExpertParallelPath.rowwise_nvshmem:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Restore non-rowwise TBO dispatch

With two_batch_overlap=True, this rejects every routed block whose EP path is sync_1d or no_sync_1d. Those paths are still built by the checked-in TBO tests (src/test/nn/moe/v2/tbo_test.py and src/test/nn/moe/v2/ep_no_sync_tbo_1d_test.py) and were supported by the old combined_forward_ep_tbo/ep_no_sync_tbo_1d dispatch, so applying EP to those configs now fails before forward instead of exercising the existing TBO implementation.

Useful? React with 👍 / 👎.

Comment thread src/olmo_core/nn/ddp/block.py Outdated
block_inp = x
del x

attn_res_out = self._res_norm_attn(block_inp, **kwargs)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Honor shared-only attention checkpointing

For shared-only DDP blocks, checkpoint_attn=True no longer does anything because this path now calls _res_norm_attn directly instead of _checkpointed_res_norm_attn. Configs using shared-only blocks as dense layers with attention checkpointing will retain the full attention activations and can OOM compared with the previous behavior.

Useful? React with 👍 / 👎.

AkshitaB and others added 2 commits July 13, 2026 21:20
Re-apply moe-v2-core behaviors dropped by the wholesale port:
- re-tie word embeddings after to_empty() in init_weights (a tied model was
  silently left with an independent LM head after materialization);
- fall back to the dense shared-expert path on CPU when rowwise_fp8 is enabled
  (the CUDA-only assert broke CPU smoke/eval/materialize runs);
- honor checkpoint_attn for shared-only blocks by routing through
  _checkpointed_res_norm_attn instead of _res_norm_attn.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Tianhua Tao <taotianhua@outlook.com>
olmo-ddp's OLMoDDP forward_tbo is rowwise_nvshmem-only, superseding moe-v2-core's
1d two-batch-overlap (ep_sync_tbo / ep_no_sync_tbo_1d). Remove the now-orphaned 1d
TBO modules and their tests; the model's TBO requirement check already restricts to
the rowwise_nvshmem path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Tianhua Tao <taotianhua@outlook.com>

@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: d5a59437b6

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/olmo_core/nn/ddp/model.py Outdated
max_local_microbatch_size: Optional[int] = None,
device: Optional[torch.device] = None,
world_mesh: Optional[Dict[str, Optional[DeviceMesh]]] = None,
world_mesh: Dict[str, Optional[DeviceMesh]],

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Restore optional world_mesh for weight init

When OLMoDDPModel.init_weights() is called through the public config/model API without pipeline or expert-parallel meshes, this new required keyword raises TypeError before the body can run; for example the existing DDP smoke path builds the model and calls model.init_weights(device=...). world_mesh is only used under self.pp_enabled/self.ep_enabled, so standalone/non-parallel initialization should keep the base Transformer.init_weights() behavior by making this argument optional.

Useful? React with 👍 / 👎.

world_mesh was a required keyword, so the non-parallel init path
(model.init_weights(device=...)) raised TypeError before running. It's only used
under pipeline/expert parallelism, so default it to None and assert presence in
those branches. Also move the misplaced docstring above the local import so it's a
real docstring.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Tianhua Tao <taotianhua@outlook.com>

@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: 78d0960d3d

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +363 to +367
cpu_offload_handler = CpuOffloadHandler(
num_offload_group=num_layers,
num_model_group=model_layers,
tensor_need_offloading_checker=tensor_need_offloading_checker_activations,
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Defer CUDA handler creation until offload is enabled

When callers request the documented disabled path (enabled=False) or run CPU-only smoke/materialization code, this still constructs CpuOffloadHandler, whose initializer immediately allocates torch.cuda.Stream() objects. That makes the supposed no-op helper raise on CPU-only processes before it can return (nullcontext(), None); construct the handler only inside the if enabled: branch.

Useful? React with 👍 / 👎.

get_cpu_offload_context(enabled=False) constructed CpuOffloadHandler, whose
__init__ allocates torch.cuda.Stream(), so the documented no-op/disabled path
raised on CPU-only processes. Build the handler only when enabled; return
(nullcontext(), None) otherwise.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Tianhua Tao <taotianhua@outlook.com>

@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: d1e830f6ef

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

"When TBO and EP no-sync are enabled, EP shared_slots must be >= 2 "
f"(block={moe_block.block_idx}, got {moe_block.ep.shared_slots})."
)
if moe_block.ep.path != ExpertParallelPath.rowwise_nvshmem:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Don’t leave sync_1d TBO rejected while its test remains

Fresh evidence after the prior TBO comment: src/test/nn/moe/v2/ep_sync_tbo_test.py:67-69 still builds the checked-in TBO comparison with ExpertParallelPath.sync_1d, and test_sync_ep_tbo_matches_standard_forward runs that model with two_batch_overlap=True. This guard raises in forward_tbo() before the test can execute, so either the synced TBO path needs to remain accepted here or the remaining sync_1d TBO test/config needs to be removed or updated; otherwise the current multi-GPU test suite fails for the existing sync_1d TBO coverage.

Useful? React with 👍 / 👎.

AkshitaB and others added 3 commits July 13, 2026 21:52
…ad, restore config docstrings

- Thread per-block context-parallel RoPE shards into the routed
  rowwise-nvshmem TBO loop, matching the dense/non-TBO paths so
  TBO + CP blocks receive their pos_sin/pos_cos/freqs_cis shards.
- Remove the unused, untested TE cpu-offload module (te/cpu_offload.py,
  te/__init__.py) and the dead commented offload hooks in OLMoDDPModel;
  the feature was never wired up.
- Restore the class docstring and per-attribute docstrings on
  OLMoDDPTransformerBlockConfig lost in the wholesale replacement.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Tianhua Tao <tianhuatao@gmail.com>
ep_sync_tbo_test.py built the TBO model with ExpertParallelPath.sync_1d,
but _check_tbo_requirements() now rejects every EP path except
rowwise_nvshmem, so the test would fail at the path guard on a GPU
runner. The supported rowwise-NVSHMEM TBO surface is already covered by
ep_no_sync_tbo_rowwise_test.py, and the other legacy TBO tests were
already removed with the 1d-TBO retirement.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Tianhua Tao <tianhuatao@gmail.com>
tbo_state.py held only SyncedTboPendingContext, which nothing constructs
or consumes now that _tbo_last_step() is narrowed to the no-sync rowwise
pending context. Its only reference was a smoke assertion that existed
solely to keep the dead type alive. Drop the module and the assertion so
the retired synchronous-TBO surface is removed consistently.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Tianhua Tao <tianhuatao@gmail.com>
@AkshitaB
AkshitaB merged commit 15d062f into akshitab/moe-v2-core Jul 14, 2026
66 of 70 checks passed
@AkshitaB
AkshitaB deleted the akshitab/olmo-ddp-block-model branch July 14, 2026 07:42
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.

1 participant