Skip to content

Commit 390852b

Browse files
justinchubyCopilot
andcommitted
feat(models): add NVIDIA Cosmos 3 Edge text reasoner backbone
Add support for the text reasoner (language tower) of the cosmos3_edge vision-language checkpoint (nvidia/Cosmos3-Edge, Cosmos3EdgeForConditionalGeneration). The language tower is a standard grouped-query-attention decoder with two Cosmos-specific traits handled here: - Non-gated squared-ReLU FFN (hidden_act="relu2", down_proj(relu2(up_proj(x)))), mapped onto the existing FCMLP component (Nemotron precedent) instead of the GLU-style gated MLP. - 3D multimodal RoPE (mrope_section=[24, 20, 20]); for text-only inference the three sections are identical, reducing to standard 1D RoPE. preprocess_weights renames the self_attn.to_{q,k,v,out} projections to the q/k/v/o_proj component names, nests the top-level text tower (layers.*, embed_tokens, norm) under model., keeps lm_head at the top level, and drops the vision encoder (model.visual.*), the multimodal projector (model.projector.*), and the per-layer k_norm_und_for_gen key-norm — the latter being a two-tower (Mixture-of-Transformers) artifact that normalizes the understanding tower's keys for the generator (diffusion) tower and is not applied in the reasoner's own causal self-attention. Registered as cosmos3_edge / cosmos3_edge_text and exported from models/__init__.py. L1 graph-build verified via the parametrized CAUSAL_LM_CONFIGS matrix; end-to-end build from the real config.json produces a 28-layer GQA decoder with the expected non-gated relu2 FFN. L4/L5 numerical parity is deferred (NVIDIA's custom edge modeling code is not in transformers), recorded in _COVERAGE_SKIP. The cosmos3_omni diffusion world-model variants (Cosmos3-Nano/-Super) are out of scope for this decoder-only path. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: justinchuby <justinchuby@users.noreply.github.com>
1 parent 13491cd commit 390852b

6 files changed

Lines changed: 130 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### NVIDIA Cosmos 3 Edge text reasoner (`cosmos3_edge`)
11+
12+
#### Added
13+
14+
- Support for the **text reasoner backbone** of the `cosmos3_edge`
15+
vision-language checkpoint (`nvidia/Cosmos3-Edge`). The language tower is a
16+
grouped-query-attention decoder with a **non-gated squared-ReLU FFN**
17+
(`hidden_act="relu2"`, `up_proj → relu2 → down_proj`) and 3D multimodal RoPE
18+
(`mrope_section=[24, 20, 20]`, equivalent to 1D RoPE for text-only). Mapped
19+
onto the standard `CausalLMModel` backbone + `FCMLP`; `preprocess_weights`
20+
renames the `self_attn.to_{q,k,v,out}` projections, nests the top-level text
21+
tower under `model.`, and drops the vision encoder, projector, and the
22+
generator-tower `k_norm_und_for_gen` key-norm. Registered as `cosmos3_edge`
23+
/ `cosmos3_edge_text`; L1 graph-build tested. The `cosmos3_omni` variants
24+
(`Cosmos3-Nano`/`-Super`) are two-tower diffusion world models and remain out
25+
of scope for this decoder-only path.
26+
1027
### Text-only export for multimodal Gemma 4 (`--text-only`)
1128

1229
#### Added

src/mobius/_registry.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
ArceeCausalLMModel,
3636
CausalLMModel,
3737
ChatGLMCausalLMModel,
38+
Cosmos3EdgeTextModel,
3839
DeepSeekOCR2CausalLMModel,
3940
DeepSeekV3CausalLMModel,
4041
DeepSeekV4CausalLMModel,
@@ -397,6 +398,8 @@ def _detect_fallback_registration(hf_config) -> ModelRegistration | None:
397398
"codegen": ModelRegistration(CodeGenCausalLMModel),
398399
"cohere": ModelRegistration(CohereCausalLMModel),
399400
"cohere2": ModelRegistration(CohereCausalLMModel),
401+
"cosmos3_edge": ModelRegistration(Cosmos3EdgeTextModel),
402+
"cosmos3_edge_text": ModelRegistration(Cosmos3EdgeTextModel),
400403
"diffllama": ModelRegistration(DiffLlamaCausalLMModel),
401404
"doge": ModelRegistration(DogeCausalLMModel),
402405
"ernie4_5": ModelRegistration(ErnieCausalLMModel),
@@ -805,6 +808,8 @@ def _create_default_registry() -> ModelRegistry:
805808
"qwen2": "Qwen/Qwen2.5-0.5B",
806809
"cohere": "CohereForAI/c4ai-command-r7b-12-2024",
807810
"cohere2": "CohereForAI/c4ai-command-r7b-12-2024",
811+
"cosmos3_edge": "nvidia/Cosmos3-Edge",
812+
"cosmos3_edge_text": "nvidia/Cosmos3-Edge",
808813
"exaone": "LGAI-EXAONE/EXAONE-3.0-7.8B-Instruct",
809814
"glm": "THUDM/glm-4-9b-chat-hf",
810815
"glm4": "THUDM/glm-4-9b-chat-hf",

src/mobius/models/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
"CogVideoXTransformer3DModel",
2424
"CohereCausalLMModel",
2525
"ControlNetModel",
26+
"Cosmos3EdgeTextModel",
2627
"DeepSeekOCR2CausalLMModel",
2728
"DeepSeekV3CausalLMModel",
2829
"DeepSeekV4CausalLMModel",
@@ -164,6 +165,7 @@
164165
from mobius.models.cogvideox import CogVideoXTransformer3DModel
165166
from mobius.models.cohere import CohereCausalLMModel
166167
from mobius.models.controlnet import ControlNetModel
168+
from mobius.models.cosmos import Cosmos3EdgeTextModel
167169
from mobius.models.ctrl import CTRLCausalLMModel
168170
from mobius.models.deepseek import DeepSeekV3CausalLMModel
169171
from mobius.models.deepseek_ocr2 import DeepSeekOCR2CausalLMModel

src/mobius/models/cosmos.py

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# Copyright (c) Microsoft Corporation.
2+
# Licensed under the MIT License.
3+
4+
"""NVIDIA Cosmos 3 model support.
5+
6+
Currently supports the **text reasoner backbone** of the ``cosmos3_edge``
7+
checkpoint (``nvidia/Cosmos3-Edge``, ``Cosmos3EdgeForConditionalGeneration``).
8+
9+
Cosmos3-Edge is a vision-language model whose language tower is a standard
10+
grouped-query-attention decoder with two Cosmos-specific traits:
11+
12+
- **Non-gated feed-forward network** — ``down_proj(relu2(up_proj(x)))`` using
13+
a squared-ReLU activation (``hidden_act="relu2"``), rather than the
14+
GLU-style gated MLP used by Llama/Qwen. This maps onto :class:`FCMLP`.
15+
- **3D multimodal RoPE** (``mrope_section=[24, 20, 20]``). For text-only
16+
inference the three sections are identical, so it reduces to standard 1D
17+
RoPE (same simplification used by the Qwen-VL text decoders).
18+
19+
The HuggingFace weights use ``self_attn.to_{q,k,v,out}`` projection names and
20+
place the text tower at the top level (``layers.*``, ``embed_tokens``,
21+
``norm``, ``lm_head``) with the vision encoder and projector under
22+
``model.visual.*`` / ``model.projector.*``. :meth:`preprocess_weights` renames
23+
the projections, prefixes the text tower with ``model.`` and drops the
24+
vision/projector weights.
25+
26+
The ``k_norm_und_for_gen`` per-layer key-norm weight is an artifact of the
27+
two-tower (Mixture-of-Transformers) design: it normalizes the *understanding*
28+
tower's keys for consumption by the *generator* (diffusion) tower, and is not
29+
applied in the reasoner's own causal self-attention. It is therefore dropped
30+
for the standalone text decoder.
31+
32+
The ``cosmos3_omni`` variants (``nvidia/Cosmos3-Nano`` / ``-Super``) are
33+
two-tower diffusion world models exported as diffusers pipelines and are out
34+
of scope for this decoder-only path.
35+
"""
36+
37+
from __future__ import annotations
38+
39+
from typing import TYPE_CHECKING
40+
41+
from mobius._configs import ArchitectureConfig
42+
from mobius.components import FCMLP
43+
from mobius.models.base import CausalLMModel
44+
45+
if TYPE_CHECKING:
46+
import torch
47+
48+
49+
class Cosmos3EdgeTextModel(CausalLMModel):
50+
"""Cosmos3-Edge text reasoner backbone (decoder-only).
51+
52+
Extracts the language tower from the ``cosmos3_edge`` vision-language
53+
checkpoint. Replaces the gated MLP with a non-gated squared-ReLU
54+
:class:`FCMLP` and renames/strips weights so the standard
55+
:class:`CausalLMModel` backbone can consume them.
56+
"""
57+
58+
def __init__(self, config: ArchitectureConfig):
59+
super().__init__(config)
60+
# Cosmos3-Edge uses a non-gated FFN (up_proj -> relu2 -> down_proj),
61+
# unlike the GLU-style gated MLP of the base CausalLMModel.
62+
for layer in self.model.layers:
63+
layer.mlp = FCMLP(
64+
config.hidden_size,
65+
config.intermediate_size,
66+
activation=config.hidden_act or "relu2",
67+
bias=config.mlp_bias,
68+
)
69+
70+
def preprocess_weights(
71+
self, state_dict: dict[str, torch.Tensor]
72+
) -> dict[str, torch.Tensor]:
73+
renamed: dict[str, torch.Tensor] = {}
74+
for key, value in state_dict.items():
75+
# Drop the vision encoder and multimodal projector — this is the
76+
# standalone text decoder.
77+
if key.startswith(("model.visual.", "model.projector.")):
78+
continue
79+
# Drop the generator-tower key-norm (see module docstring).
80+
if "k_norm_und_for_gen" in key:
81+
continue
82+
83+
new_key = (
84+
key.replace("self_attn.to_q.", "self_attn.q_proj.")
85+
.replace("self_attn.to_k.", "self_attn.k_proj.")
86+
.replace("self_attn.to_v.", "self_attn.v_proj.")
87+
.replace("self_attn.to_out.", "self_attn.o_proj.")
88+
)
89+
# The text tower is stored at the top level; the mobius backbone
90+
# nests it under ``model.``. ``lm_head`` stays at the top level.
91+
if new_key == "lm_head.weight":
92+
pass
93+
elif new_key.startswith(("layers.", "embed_tokens.")) or new_key == "norm.weight":
94+
new_key = f"model.{new_key}"
95+
96+
renamed[new_key] = value
97+
return super().preprocess_weights(renamed)

tests/_test_configs.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,11 @@ def _base_config(config_cls=None, **overrides) -> ArchitectureConfig:
111111
("qwen2", {}, True),
112112
("cohere", {"tie_word_embeddings": True, "logit_scale": 0.0625}, True),
113113
("cohere2", {"tie_word_embeddings": True, "logit_scale": 0.0625}, False),
114+
(
115+
"cosmos3_edge",
116+
{"hidden_act": "relu2", "mlp_bias": False, "mrope_section": [24, 20, 20]},
117+
True,
118+
),
114119
("diffllama", {}, False),
115120
("doge", {}, False),
116121
(

tests/model_coverage_test.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,10 @@ def _all_registered_with_test_id() -> dict[str, str]:
158158
"shieldgemma2": "Alias for gemma2 — covered by gemma2",
159159
"yi": "Alias for llama — covered by llama",
160160
# --- VL text-decoder submodels (tested via their parent VL model) ---
161+
"cosmos3_edge": "Cosmos3-Edge text reasoner backbone — L1 graph-build only; "
162+
"L4/L5 parity needs NVIDIA's custom edge modeling code (not in transformers)",
163+
"cosmos3_edge_text": "Alias for cosmos3_edge text reasoner — L1 graph-build only; "
164+
"L4/L5 parity needs NVIDIA's custom edge modeling code (not in transformers)",
161165
"glm4v_moe_text": "VL text decoder — tested via glm4v_moe",
162166
"glm4v_text": "VL text decoder — tested via glm4v",
163167
"qwen2_5_vl_text": "VL text decoder — tested via qwen2_5_vl",

0 commit comments

Comments
 (0)