Skip to content

Commit 2c2e2cd

Browse files
gramalingamCopilot
andauthored
Use LinearAttention to implement Mamba2 and other cleanup (#163)
Update the NemotronH/Mamba2 implementations to use LinearAttention. --------- Signed-off-by: G Ramalingam <grama@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 7c1972d commit 2c2e2cd

18 files changed

Lines changed: 421 additions & 1094 deletions

examples/nemotron_3_nano_text_generation.py

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -242,9 +242,9 @@ def init_hybrid_states(config, dtype: np.dtype = np.float32) -> dict[str, np.nda
242242
states[f"past_key_values.{i}.conv_state"] = np.zeros(
243243
(batch_size, conv_dim, d_conv - 1), dtype=dtype
244244
)
245-
# ssm_state: (batch, n_heads, d_head, d_state)
245+
# ssm_state: (batch, n_heads, d_state, d_head) — LinearAttention convention
246246
states[f"past_key_values.{i}.ssm_state"] = np.zeros(
247-
(batch_size, n_heads, d_head, d_state),
247+
(batch_size, n_heads, d_state, d_head),
248248
dtype=dtype,
249249
)
250250
elif ltype in ("attention", "full_attention"):
@@ -593,24 +593,39 @@ def main():
593593
"--device",
594594
choices=["cpu", "cuda"],
595595
default="cpu",
596-
help="Device for ONNX Runtime and PyTorch inference (default: %(default)s).",
596+
help=(
597+
"Device for inference (used for ONNX Runtime and for "
598+
"HuggingFace comparison when --compare-hf is set) "
599+
"(default: %(default)s)."
600+
),
601+
)
602+
parser.add_argument(
603+
"--ep",
604+
choices=["cpu", "cuda", "onnx-standard"],
605+
default=None,
606+
help=(
607+
"Execution provider for ONNX model build. "
608+
"'onnx-standard' inlines custom ops (LinearAttention, etc.) "
609+
"into standard ONNX ops, runnable on any ORT version. "
610+
"Defaults to matching --device."
611+
),
597612
)
598613
parser.add_argument(
599614
"--no-chat",
600615
action="store_true",
601616
help="Disable chat template (send raw text).",
602617
)
618+
parser.add_argument(
619+
"--ci",
620+
action="store_true",
621+
help="Exit with non-zero code on failure (for CI pipelines).",
622+
)
603623
parser.add_argument(
604624
"--repetition-penalty",
605625
type=float,
606626
default=REPETITION_PENALTY,
607627
help="Repetition penalty (1.0 = none, default: %(default)s).",
608628
)
609-
parser.add_argument(
610-
"--ci",
611-
action="store_true",
612-
help="Exit with non-zero code on failure (for CI pipelines).",
613-
)
614629
args = parser.parse_args()
615630

616631
use_chat = not args.no_chat
@@ -632,7 +647,7 @@ def main():
632647
build_flags = {}
633648
if args.device == "cuda":
634649
build_flags["ort_cuda_grouped_rmsnorm_workaround"] = True
635-
ep = "cuda" if args.device == "cuda" else "cpu"
650+
ep = args.ep or ("cuda" if args.device == "cuda" else "cpu")
636651
print(f"Building model for {args.model!r} (dtype={args.dtype}, ep={ep}) ...")
637652
with override_flags(**build_flags):
638653
pkg = build(

pyproject.toml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,8 +135,6 @@ ignore = [
135135
]
136136

137137
[tool.ruff.lint.per-file-ignores]
138-
# SSM math notation uses uppercase variable names (A, B, C, D, H, N, etc.)
139-
"src/mobius/components/_mamba_block_chunked.py" = ["N803", "N806"]
140138

141139
[tool.ruff.lint.flake8-tidy-imports]
142140
ban-relative-imports = "all"

src/mobius/_flags.py

Lines changed: 0 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -55,28 +55,6 @@ def _env_bool(name: str, default: bool) -> bool:
5555
return default
5656

5757

58-
def _env_str(name: str, default: str, choices: tuple[str, ...]) -> str:
59-
"""Read a string from an environment variable.
60-
61-
Returns *default* if the variable is unset or has an unrecognised value.
62-
For backwards compatibility, ``"1"``/``"true"``/``"yes"`` map to the
63-
first choice, and ``"0"``/``"false"``/``"no"`` map to the last choice.
64-
"""
65-
val = os.environ.get(name, "").strip().lower()
66-
if not val:
67-
return default
68-
# Direct match against choices
69-
for c in choices:
70-
if val == c.lower():
71-
return c
72-
# Boolean-style aliases: truthy → first choice, falsy → last choice
73-
if val in ("1", "true", "yes"):
74-
return choices[0]
75-
if val in ("0", "false", "no"):
76-
return choices[-1]
77-
return default
78-
79-
8058
@dataclasses.dataclass
8159
class _Flags:
8260
"""Runtime feature flags singleton.
@@ -120,28 +98,6 @@ class _Flags:
12098
Set ``MOBIUS_ORT_CUDA_GROUPED_RMSNORM_WORKAROUND=1`` when targeting CUDA.
12199
"""
122100

123-
mamba_scan: str = dataclasses.field(
124-
default_factory=lambda: _env_str(
125-
"MOBIUS_MAMBA_SCAN",
126-
"single",
127-
("chunked_ssd", "scan", "single"),
128-
)
129-
)
130-
"""Multi-token Mamba2 forward strategy.
131-
132-
- ``"single"`` (default): single-token-only path (seq_len must
133-
be 1). The simplest and most debuggable mode.
134-
- ``"chunked_ssd"``: chunked SSD algorithm — processes the full
135-
sequence in parallel within chunks, with cross-chunk state
136-
propagation. Matches HF ``torch_forward``.
137-
- ``"scan"``: ONNX Scan op that iterates token-by-token. Supports
138-
arbitrary seq_len but is sequential.
139-
140-
Set via ``MOBIUS_MAMBA_SCAN=chunked_ssd|scan|single``.
141-
For backwards compatibility, ``1``/``true`` → ``chunked_ssd``,
142-
``0``/``false`` → ``single``.
143-
"""
144-
145101

146102
# Global singleton — import and use this directly.
147103
flags = _Flags()

src/mobius/components/__init__.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@
5252
"Mistral3MultiModalProjector",
5353
"MLPMultiModalProjector",
5454
"Mamba2Block",
55-
"Mamba2Scan",
5655
"MambaBlock",
5756
"MoELayer",
5857
"OffsetRMSNorm",
@@ -233,7 +232,6 @@
233232
from mobius.components._rotary_embedding import initialize_rope
234233
from mobius.components._ssm import (
235234
JambaSelectiveScan,
236-
Mamba2Scan,
237235
SelectiveScan,
238236
)
239237
from mobius.components._vision import (

0 commit comments

Comments
 (0)