Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
ae3babc
Add global load balancing and EMO routing
AkshitaB Jul 30, 2026
e1e89ab
Track global MoE load imbalance
AkshitaB Jul 30, 2026
05d8be9
Export distributed profiler event summaries
AkshitaB Jul 30, 2026
3c84fac
lint, style, mypy
AkshitaB Jul 30, 2026
9805d3b
address review comments
AkshitaB Jul 31, 2026
0a0ff35
preserve rng state for emo router
AkshitaB Jul 31, 2026
cc57c80
fix tests
AkshitaB Jul 31, 2026
b849a68
fix CP for global lb
AkshitaB Jul 31, 2026
ccbb7b1
Add KDA sequence mixer (#803)
AkshitaB Aug 2, 2026
d50a769
isort, black
AkshitaB Aug 2, 2026
113dc44
Reject restricted EMO pools in plain HF export
AkshitaB Aug 2, 2026
3dd3c91
Implement KDA inference cache
AkshitaB Aug 2, 2026
e708f6f
Fix KDA inference cache state handling
AkshitaB Aug 2, 2026
153a73c
Fix KDA export validation and cache compatibility
AkshitaB Aug 2, 2026
7631e84
Guard plain HF export for non-EMO routers
AkshitaB Aug 2, 2026
33c8748
Fix initial KDA cache state detection
AkshitaB Aug 2, 2026
4237c3c
Support DDP optimizer checkpoints in HF conversion
AkshitaB Aug 3, 2026
0b8ab09
Export KDA models with optional LatentMoE and EMo
AkshitaB Aug 3, 2026
eded327
Handle standard routers in optional EMo export
AkshitaB Aug 3, 2026
cce7c8b
Tolerate incompatible optional FA4 imports
AkshitaB Aug 4, 2026
3553172
Support explicit Beaker minimum runtime
jacob-morrison Aug 1, 2026
8bfb725
Allow deterministic HF MoE reference routing
jacob-morrison Aug 5, 2026
b339efc
Use eager attention for HF conversion validation
jacob-morrison Aug 5, 2026
855c277
Use reference SwiGLU during HF validation
jacob-morrison Aug 5, 2026
7e4d793
Use math SDPA for HF conversion validation
jacob-morrison Aug 5, 2026
6f0de5e
Keep HF validation on portable attention backend
jacob-morrison Aug 5, 2026
8cef5cb
Match HF router precision to OLMo core
jacob-morrison Aug 5, 2026
2d47e49
Align strict HF verifier with core execution
jacob-morrison Aug 5, 2026
23a2050
Propagate custom GitHub token secret to Gantry
jacob-morrison Aug 5, 2026
baf121d
Support legacy d_attn checkpoint configs
jacob-morrison Aug 6, 2026
fd4012b
Support legacy split norm checkpoint configs
jacob-morrison Aug 6, 2026
7fb467d
Export legacy peri-norm DDP models to HF
jacob-morrison Aug 6, 2026
2a4ddb1
Keep exported Olmo3Moe remote code standalone
jacob-morrison Aug 6, 2026
fd6f94d
Load optimizer-backed DDP checkpoints for generation
jacob-morrison Aug 11, 2026
93dc460
Match shared expert path in strict HF validation
jacob-morrison Aug 11, 2026
b525a8f
add partial ScaledSoftmax support
YashasSamaga Aug 3, 2026
b405483
add Dolma3p5_14t DataMix
yadavta Aug 14, 2026
5596dd7
style fix
yadavta Aug 14, 2026
4433011
Add provisional final-family throughput harness
jacob-morrison Aug 20, 2026
04a16d3
Use workspace Google credential in throughput launcher
jacob-morrison Aug 20, 2026
19944b2
Infer throughput model size from run name
jacob-morrison Aug 20, 2026
7c0a484
Pass Beaker credentials to throughput workers
jacob-morrison Aug 20, 2026
d7b2a7d
Lower final 0.5B throughput microbatch
jacob-morrison Aug 20, 2026
70fbc93
Run final-family microbatch tests on one node
jacob-morrison Aug 20, 2026
2f52487
Use block recomputation for 3.8B single-node test
jacob-morrison Aug 20, 2026
b600e5e
Record final-family throughput qualification
jacob-morrison Aug 20, 2026
7f2b5ae
Parameterize throughput test EP capacity
jacob-morrison Aug 20, 2026
d9c3eeb
Propagate throughput diagnostic overrides
jacob-morrison Aug 20, 2026
2dc7417
Add expert granularity throughput variant
jacob-morrison Aug 20, 2026
b59aa85
Record expert granularity throughput results
jacob-morrison Aug 20, 2026
0a00c1d
Support Scalable-Softmax in OLMoE3 HF export
jacob-morrison Aug 21, 2026
af9bd11
Match Scalable-Softmax BF16 operation order
jacob-morrison Aug 21, 2026
fce4e77
Use reference KDA kernel for conversion validation
jacob-morrison Aug 21, 2026
4974c9d
Test deterministic KDA conversion validation
jacob-morrison Aug 21, 2026
8b8f644
Add per-layer allowed-expert mask to HF OLMoE3 router
AkshitaB Aug 10, 2026
bcf38f3
Support EMO document routing under pipeline parallelism (#814)
AkshitaB Aug 24, 2026
6dd851e
Fix integration branch style and type checks
AkshitaB Aug 25, 2026
159f477
Fix scalable softmax attention config dispatch
AkshitaB Aug 25, 2026
63167b2
Address integration review feedback
AkshitaB Aug 25, 2026
4755efd
Constrain OLMoDDP pipeline schedules
AkshitaB Aug 25, 2026
a5142f6
Fix eval loading and parallel attention sinks
AkshitaB Aug 25, 2026
44bfd59
Restore optimizer state after failed saves
AkshitaB Aug 25, 2026
82fb4a7
Align integration callers with upstream KDA kernel flag
AkshitaB Sep 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ jobs:
# NVSHMEM + CUDA toolkit) before pytest, so the rowwise-EP tests that import the built
# module at collection time can run. One `bash -c` so both run inside the gantry container.
run: |
bash -c 'export PYTHONPATH="$PWD/src${PYTHONPATH:+:$PYTHONPATH}"; python -m olmo_core.kernels.build_symm_mem_vdev2d_ext --inplace && python -c "from olmo_core.kernels import _symm_mem_vdev2d_ext_gpu" && pytest -v --color=yes --durations=3 -m gpu src/test/kernels/ src/test/nn/ddp/ src/test/nn/moe/v2/ src/test/nn/moe/moe_test.py src/test/nn/moe/routed_experts_v2_test.py src/test/train/train_module/transformer/ddp_train_module_test.py'
bash -c 'unset TRITON_PTXAS_PATH TRITON_PTXAS_BLACKWELL_PATH; export PYTHONPATH="$PWD/src${PYTHONPATH:+:$PYTHONPATH}"; python -m olmo_core.kernels.build_symm_mem_vdev2d_ext --inplace && python -c "from olmo_core.kernels import _symm_mem_vdev2d_ext_gpu" && pytest -v --color=yes --durations=3 -m gpu src/test/kernels/ src/test/nn/ddp/ src/test/nn/moe/v2/ src/test/nn/moe/moe_test.py src/test/nn/moe/routed_experts_v2_test.py src/test/train/train_module/transformer/ddp_train_module_test.py'
steps:
- uses: actions/checkout@v5
with:
Expand Down
4 changes: 3 additions & 1 deletion src/examples/huggingface/convert_checkpoint_from_hf.py
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,9 @@ def validate_conversion(
revision=hf_revision,
torch_dtype="auto",
config=hf_config,
attn_implementation="sdpa",
# Validation is a deterministic correctness check. Eager attention also avoids
# cuDNN SDPA plan-selection failures on newer GPU architectures such as B300.
attn_implementation="eager",
)
.to(device)
.eval()
Expand Down
316 changes: 316 additions & 0 deletions src/examples/olmo_ddp/olmoe3_final_family.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,316 @@
"""Provisional GPU-first OLMoE3 final-training model family.

This module is deliberately separate from the production scaling ladder. It
defines the four candidate shapes used for systems qualifications without
changing any production model factory.
"""

from __future__ import annotations

import math
from copy import deepcopy
from dataclasses import dataclass

from olmo_core.config import DType
from olmo_core.nn.attention import (
AttentionBackendName,
AttentionConfig,
AttentionType,
GateConfig,
GateGranularity,
KimiDeltaAttentionConfig,
)
from olmo_core.nn.ddp import OLMoDDPTransformerBlockConfig
from olmo_core.nn.layer_norm import LayerNormConfig, LayerNormType
from olmo_core.nn.lm_head import LMHeadConfig
from olmo_core.nn.moe import (
LatentMoEConfig,
MoELoadBalancingLossGranularity,
MoERouterGatingFunction,
)
from olmo_core.nn.moe.v2.ep_config import ExpertParallelConfig, ExpertParallelPath
from olmo_core.nn.moe.v2.fp8 import MoERowwiseFP8Config
from olmo_core.nn.moe.v2.routed_experts import RoutedExpertsConfig
from olmo_core.nn.moe.v2.router import MoERouterConfigV2
from olmo_core.nn.moe.v2.shared_experts import SharedExpertsConfig
from olmo_core.nn.transformer import (
InitMethod,
OLMoDDPModelConfig,
TransformerBlockType,
TransformerType,
)

VOCAB_SIZE = 100_352
HEAD_DIM = 128
TOP_K = 16
NUM_EXPERTS = 512
LATENT_COMPRESSION = 2
MODEL_SIZES = ("0p5b", "0p9b", "2p0b", "3p8b")


@dataclass(frozen=True)
class Geometry:
"""Geometry and guarded parameter counts for one candidate rung."""

d_model: int
n_layers: int
n_heads: int
n_kv_heads: int
expected_active_params: int
expected_active_non_embedding_params: int
expected_total_params: int

@property
def latent_dim(self) -> int:
return self.d_model // LATENT_COMPRESSION

@property
def expert_hidden_size(self) -> int:
return self.d_model

@property
def full_attention_layers(self) -> tuple[int, ...]:
# Dense layer 0 stays KDA; thereafter use a simple 3:1 KDA:FA cadence.
return tuple(range(3, self.n_layers, 4))


GEOMETRIES: dict[str, Geometry] = {
"0p5b": Geometry(
d_model=1024,
n_layers=8,
n_heads=8,
n_kv_heads=4,
expected_active_params=494_082_112,
expected_active_non_embedding_params=391_321_664,
expected_total_params=5_955_065_920,
),
"0p9b": Geometry(
d_model=1024,
n_layers=20,
n_heads=8,
n_kv_heads=4,
expected_active_params=933_998_752,
expected_active_non_embedding_params=831_238_304,
expected_total_params=15_756_669_088,
),
"2p0b": Geometry(
d_model=1536,
n_layers=20,
n_heads=16,
n_kv_heads=8,
expected_active_params=2_017_495_360,
expected_active_non_embedding_params=1_863_354_688,
expected_total_params=35_368_503_616,
),
"3p8b": Geometry(
d_model=2048,
n_layers=24,
n_heads=16,
n_kv_heads=8,
expected_active_params=3_839_285_632,
expected_active_non_embedding_params=3_633_764_736,
expected_total_params=75_612_215_680,
),
}


def geometry(model_size: str) -> Geometry:
"""Return the geometry for ``model_size``."""

try:
return GEOMETRIES[model_size.lower()]
except KeyError as exc:
raise ValueError(f"Unknown model size {model_size!r}; choose from {MODEL_SIZES}") from exc


def _norm() -> LayerNormConfig:
return LayerNormConfig(
name=LayerNormType.rms,
eps=1e-6,
bias=False,
dtype=DType.float32,
)


def _kda(g: Geometry) -> KimiDeltaAttentionConfig:
return KimiDeltaAttentionConfig(
n_heads=g.n_heads,
n_v_heads=g.n_heads,
head_dim=HEAD_DIM,
expand_v=2.0,
allow_neg_eigval=True,
conv_size=4,
conv_bias=False,
norm_eps=1e-5,
use_experimental_kernels=True,
dtype=DType.float32,
)


def _attention(g: Geometry, norm: LayerNormConfig) -> AttentionConfig:
return AttentionConfig(
name=AttentionType.default,
n_heads=g.n_heads,
n_kv_heads=g.n_kv_heads,
head_dim=HEAD_DIM,
bias=False,
gate=GateConfig(granularity=GateGranularity.elementwise, full_precision=True),
rope=None,
qk_norm=deepcopy(norm),
backend=AttentionBackendName.flash_4,
scalable_softmax=True,
dtype=DType.float32,
use_head_qk_norm=True,
)


def _shared(g: Geometry, *, hidden_size: int | None = None) -> SharedExpertsConfig:
return SharedExpertsConfig(
d_model=g.d_model,
hidden_size=hidden_size or g.expert_hidden_size,
num_experts=1,
bias=False,
dtype=DType.float32,
)


def _moe_block(
g: Geometry,
norm: LayerNormConfig,
sequence_mixer: KimiDeltaAttentionConfig | AttentionConfig,
*,
num_experts: int = NUM_EXPERTS,
top_k: int = TOP_K,
expert_hidden_multiplier: int = 1,
) -> OLMoDDPTransformerBlockConfig:
disabled_fp8 = MoERowwiseFP8Config(enabled=False)
return OLMoDDPTransformerBlockConfig(
name=TransformerBlockType.moe_fused_v2,
sequence_mixer=sequence_mixer,
layer_norm=deepcopy(norm),
shared_experts=_shared(g),
routed_experts=RoutedExpertsConfig(
d_model=g.latent_dim,
hidden_size=g.expert_hidden_size * expert_hidden_multiplier,
num_experts=num_experts,
bias=False,
dtype=DType.float32,
rowwise_fp8=disabled_fp8,
),
routed_experts_router=MoERouterConfigV2(
d_model=g.d_model,
num_experts=num_experts,
top_k=top_k,
bias=False,
normalize_expert_weights=1.0,
gating_function=MoERouterGatingFunction.softmax,
dtype=DType.float32,
lb_loss_weight=0.01,
lb_loss_granularity=MoELoadBalancingLossGranularity.instance,
z_loss_weight=1e-5,
restore_weight_scale=True,
use_recompute_fp32_cast=False,
),
latent_moe=LatentMoEConfig(
latent_dim=g.latent_dim,
up_proj_input_norm_enabled=False,
),
use_peri_norm=True,
use_pre_norm=False,
checkpoint_attn=False,
checkpoint_permute_moe_unpermute=False,
checkpoint_second_unpermute=False,
ep=ExpertParallelConfig(path=ExpertParallelPath.rowwise_nvshmem),
rowwise_fp8=disabled_fp8,
)


def _dense_first(g: Geometry, norm: LayerNormConfig) -> OLMoDDPTransformerBlockConfig:
return OLMoDDPTransformerBlockConfig(
name=TransformerBlockType.moe_fused_v2,
sequence_mixer=_kda(g),
layer_norm=deepcopy(norm),
shared_experts=_shared(g, hidden_size=8 * g.d_model),
use_peri_norm=True,
use_pre_norm=False,
checkpoint_attn=False,
checkpoint_permute_moe_unpermute=False,
checkpoint_second_unpermute=False,
)


def build_model_config(
model_size: str,
*,
vocab_size: int = VOCAB_SIZE,
num_experts: int = NUM_EXPERTS,
top_k: int = TOP_K,
expert_hidden_multiplier: int = 1,
) -> OLMoDDPModelConfig:
"""Build and strictly validate one provisional final-family model."""

g = geometry(model_size)
norm = _norm()
default_block = _moe_block(
g,
norm,
_kda(g),
num_experts=num_experts,
top_k=top_k,
expert_hidden_multiplier=expert_hidden_multiplier,
)
attention_block = _moe_block(
g,
norm,
_attention(g, norm),
num_experts=num_experts,
top_k=top_k,
expert_hidden_multiplier=expert_hidden_multiplier,
)
model = OLMoDDPModelConfig(
name=TransformerType.moe_fused_v2,
d_model=g.d_model,
vocab_size=vocab_size,
n_layers=g.n_layers,
block=default_block,
block_overrides={
0: _dense_first(g, norm),
**{index: deepcopy(attention_block) for index in g.full_attention_layers},
},
lm_head=LMHeadConfig(
layer_norm=deepcopy(norm),
bias=False,
dtype=DType.float32,
),
embedding_norm=deepcopy(norm),
dtype=DType.float32,
init_method=InitMethod.normal,
init_seed=0,
init_std=0.02,
embed_scale=math.sqrt(g.d_model),
tie_word_embeddings=False,
two_batch_overlap=False,
recompute_all_blocks_by_chunk=False,
recompute_each_block=False,
)
model.validate()

if (
vocab_size == VOCAB_SIZE
and num_experts == NUM_EXPERTS
and top_k == TOP_K
and expert_hidden_multiplier == 1
):
actual = (
model.num_active_params,
model.num_active_non_embedding_params,
model.num_params,
)
expected = (
g.expected_active_params,
g.expected_active_non_embedding_params,
g.expected_total_params,
)
if actual != expected:
raise ValueError(f"{model_size} parameter-count drift: {actual=} != {expected=}")
return model
Loading
Loading