mamba-rs
Mamba SSM and Mamba-3 SISO in Rust with optional CUDA GPU acceleration. Inference and training for both, with custom CUDA kernels.
Pure Rust + CUDA — no PyTorch, no Triton, no Burn, no Candle. Kernels compile at runtime via NVRTC.
Features
- Two architectures — Mamba SSM (Gu & Dao, 2023) and Mamba-3 SISO (Lahoti et al., ICLR 2026).
- CPU + GPU — both paths exposed, with a cross-path parity test on shared weights.
- Inference + training — full backward pass with BPTT through the recurrent SSM state; AdamW optimizer; CUDA Graph capture for both.
- f32 / bf16 / f16 — a single
WeightDtypeselector at construction. Compute stays f32 (upcast-in-kernel, f32 accumulators) regardless of storage dtype. - Batch-invariant bf16 inference (0.3.0) — own CUDA matvec kernel
(
kernels/gemm_batch_invariant.cu) gives the same logits per row regardless of batch size. KL ≈ 1e-11 cross-batch (vs cuBLAS's ~1e-3 algorithm-selection drift). 86 % of cuBLAS gemv throughput; ~6 percentage points ahead of vLLM / Thinking Machines Lab's opt-in Triton kernel, and the default path here, not opt-in. - HuggingFace loader — safetensors, synthetic + real Mamba SSM checkpoints (130m / 370m / 1.4b / 2.8b validated).
- Standalone — no framework dependency.
Use cases and API choice
The crate targets two workloads. Pick the entry point that matches yours.
Reinforcement learning / small custom models
Latency-critical, typically d_model ≤ 256, often batch = 1 for actor
rollouts. Both CPU and GPU paths are supported; CPU is competitive at
these sizes (~85 µs/step on Ada Xeon vs 79 µs/step on RTX 6000 Ada).
- Inference —
mamba_step(CPU) orGpuMambaBackbone::step(GPU) - Training —
parallel_mamba_forward/parallel_mamba_backward(CPU, Rayon-parallel batch) orMambaTrainer::step(GPU, CUDA-Graph- captured forward + backward + AdamW + sync)
CPU training works for model sizes where GPU overhead dominates
(d_model ≤ 128, batch ≤ 8); GPU training scales well to batch ≥ 32.
Large language models
Throughput-critical, d_model ≥ 768, sequence-level decoding with a
HuggingFace checkpoint. GPU-only in practice — a 2.8b model on CPU is
single-digit tokens/sec regardless of implementation.
- Inference —
GpuMambaLM::from_hf_with_dtype+generate - Fine-tuning —
MambaTrainer::new_fullaccepting the HF backbone weights (Mamba SSM only; no public Mamba-3 SISO checkpoint exists yet)
The CPU MambaLM path compiles and runs end-to-end, but exists for
CPU↔GPU parity testing (tests/hf_batch_parity.rs), not for production
LLM serving.
Sharing weights across paths
All paths consume the same MambaWeights / Mamba3Weights struct.
A training run's MambaTrainer::snapshot_master() output loads directly
into GpuMambaBackbone, GpuMambaLM, or the CPU MambaBackbone without
conversion.
Quick start (CPU)
Mamba SSM
use ;
let cfg = default;
let weights = init;
let mut state = zeros;
let mut scratch = new;
let mut output = vec!;
mamba_step;
Mamba-3
use Mamba3Config;
use ;
use Mamba3State;
use Mamba3Weights;
let cfg = default;
let weights = init;
let mut state = zeros;
let mut scratch = new;
let mut output = vec!;
mamba3_step;
Quick start (GPU inference)
[]
= { = "0.3", = ["cuda"] }
GpuMambaBackbone::new_with_dtype and the symmetric Mamba-3 constructor take
WeightDtype::{F32, Bf16, F16} — the rest of the API is unchanged.
use GpuMambaBackbone;
use WeightDtype;
let mut gpu = new_with_dtype?;
gpu.capture_graph?; // optional; ~2× decode speedup
gpu.step?;
gpu.reset?;
HuggingFace LM inference
use GpuMambaLM;
use SampleParams;
use WeightDtype;
use Path;
let mut lm = from_hf_with_dtype?;
lm.capture_graph?;
let tokens = lm.generate?;
bf16 vs f32 on all four cached state-spaces/mamba-*-hf checkpoints:
15/15 greedy match, KL ≤ 1.6e-3. Batch=1 vs batch=32 on the same prompt:
KL ≈ 2e-11 (bit-identical up to f32 roundoff of the fixed reduction tree).
Quick start (GPU training)
MambaTrainer / Mamba3Trainer wrap the full forward + backward + AdamW +
sync pipeline behind a single .step() call. One dispatch struct per
architecture; an internal enum selects the f32 or mixed (bf16/f16) inner
engine based on the WeightDtype constructor argument.
use MambaTrainer;
use WeightDtype;
let mut trainer = new_full?;
trainer.capture_graph?; // optional; one cuGraphLaunch per step after this
let metrics = trainer.step?;
// metrics.step, metrics.graph_replayed, metrics.loss_scale (f16), metrics.overflow_skipped (f16)
let master = trainer.snapshot_master?; // CPU-side MambaWeights for checkpointing
Mamba3Trainer mirrors the same API. f16 training activates the dynamic
loss scaler automatically; metrics.loss_scale / metrics.overflow_skipped
report its state each step.
Serialization
use serialize;
save?;
let = load?;
// Mamba-3
use ;
save_mamba3?;
let = load_mamba3?;
Performance (RTX 6000 Ada)
LLM throughput — state-spaces/mamba-*-hf, greedy decode, CUDA Graph
| Model | f32 tok/s | bf16 tok/s | f16 tok/s | bf16 vs f32 |
|---|---|---|---|---|
| mamba-130m-hf | 725 | 898 | 899 | +24 % |
| mamba-370m-hf | 305 | 396 | 395 | +30 % |
| mamba-1.4b-hf | 116 | 189 | 190 | +63 % |
| mamba-2.8b-hf | 61 | 104 | 104 | +70 % |
All produced by the batch-invariant matvec kernel — pure Rust + NVRTC,
no Python / Triton dependency. Strict cross-batch bit-identity at
KL ≈ 1e-11 (b=1 vs b=N produce the same logits per slot). Reaches
~86 % of cuBLAS gemv throughput; ~6 percentage points faster than
vLLM / Thinking Machines Lab batch_invariant Triton (~80 % of cuBLAS,
opt-in).
Per-step latency (default config: d_model=128, 3 layers)
| Mamba SSM | Mamba-3 SISO | |
|---|---|---|
| GPU inference B=1 (CUDA Graph) | 79 µs | 86 µs |
| GPU training fwd+bwd (T=32) | 1 629 µs | 2 169 µs |
| CPU inference B=1 | 88 µs | 70 µs |
| CPU training fwd+bwd (T=32) | 15 874 µs | 3 609 µs |
Detailed tables: Mamba SSM benchmarks, Mamba-3 SISO benchmarks.
Testing
49 test files, 280+ individual tests:
- Correctness: bit-parity across CPU ↔ GPU, eager ↔ CUDA Graph, f32 ↔ bf16/f16
- Gradient checks: finite-difference vs analytical on every weight tensor
- Real checkpoints: 30-step training convergence + inference on
state-spaces/mamba-130m-hffor all three dtypes - Batch invariance: KL < 1e-4 across batch sizes 1 / 4 / 16 / 32 at bf16
- Long-sequence stability: 1024-token generation + T=1024 M3 training
- CUDA Graph: replay determinism, pointer-stability assertions
Run the fast suite:
Full suite including HuggingFace-backed tests (needs the HF cache):
Documentation
Citation
License
Dual-licensed under MIT or Apache-2.0.