CERIN AMROTH · ML systems

How do I train and serve MoE models released in MXFP4 (gpt-oss, DeepSeek-V4)?

Solved by experts4bit-qlora · this page in the repository (pinned 0c2a256dcdc2, the source of this rendering; latest on main, unpinned; not the source of any fact rendered here)

Install routes

From docs/capabilities.json at the pinned commit.

pip install "experts4bit-qlora[train]"

Primary route: minimum/reference training.

Alternatives:

Environment (from the capability register): OS: Linux · Python: >=3.11 tested in CI (pyproject says >=3.9; 3.9/3.10 are not tested) · Accelerator: NVIDIA CUDA GPU, sm_80 or newer (Triton kernels via grouped-nf4-gemm) · Requires: an expert arena baked with grouped-nf4-gemm (nvme_bake_nf4 for NF4, the MXFP4 relocation bake for native MXFP4); grouped-nf4-gemm>=0.30.0 ([fast] extra; the floor is pyproject.toml's, validated by CI); local NVMe or a fast block device; pinned host RAM for the hot tier; triton>=3.4 (Linux-only distribution)

load_moe_4bit_streaming dequantises the released MXFP4 experts bit-identically and, by default, re-quantises them to NF4 for QLoRA. To keep computing on the released bytes, relocate them into an arena with grouped-nf4-gemm and bind it with enable_mxfp4_nvme_residency (serving) or enable_nvme_train_residency (training); the native MXFP4 expert store for the paged engine is a separate opt-in whose quality gate is still open.

Two fidelity paths — choose before loading

Only the second path keeps the checkpoint's original expert bytes.

  1. Convenient QLoRA path — decode, then re-quantise to NF4. The quantising branch of load_moe_4bit_streaming (experts4bit_qlora/loader.py) reads the released blocks and scales through experts4bit_qlora.formats.mxfp4.dequantize_mxfp4 — verified bit-identical to transformers' reference decode in tests/test_mxfp4_dequant.py — and then builds the expert stack in the storage you asked for, NF4 by default: GptOssExperts4bit.from_gptoss(..., quant_type=quant_type) for gpt-oss and DeepseekV4Experts4bit.from_deepseek_v4(..., quant_type=quant_type) for DeepSeek-V4, each of which quantises the decoded stack through Experts4bit.from_float. What trains and serves afterwards is an NF4 re-quantisation of an exact decode of the release: the decode is bit-exact, the NF4 that follows it is the quantiser's output, and that — not the release — is the provenance of the served experts. Needs no arena and no kernel package. verify_moe_4bit(model, strict=True) proves the stack is 4-bit, not that it is the released bytes.
  2. Native-byte path — retain the released MXFP4 blocks and scales. Relocate the checkpoint's own blocks and scales verbatim into an arena with nvme_arena.bake_expert_tensors (hash-preserving; the manifest's bake_mode records it) and bind it with enable_mxfp4_nvme_residency (serving through mxfp4_grouped's native kernels) or enable_nvme_train_residency on an arena=..., arena_train=True load (training against the arena, gradient checkpointing required). The paged engine's native MXFP4 store — enable_serve_experts_int4 on gpt-oss, which never re-quantises onto the int4 grid — is the all-VRAM form of the same idea. Here the checkpoint's expert bytes are what computes, and provenance is preserved end to end.

Symptoms

Why it happens

MXFP4 (OCP microscaling FP4) stores two e2m1 nibbles per byte in blocks of 32 values sharing one e8m0 power-of-two scale. gpt-oss adds per-expert biases, interleaved gate/up rows and a clamped GLU; DeepSeek-V4 keeps SwiGLU with one-sided and two-sided clamps and stores its dense half as block-scaled FP8 (../DEEPSEEK-V4.md). Re-quantising these experts to a uniform int4 grid fails the quality gate because NF4's levels sit on e2m1's and int4's do not (../SERVING-THROUGHPUT.md).

Which project solves it

experts4bit-qlora owns the model side: formats.mxfp4.dequantize_mxfp4 (verified bit-identical to transformers' reference, tests/test_mxfp4_dequant.py), arch/gptoss.py (biases, de-interleave, clamped GLU, GptOssExperts4bit), arch/deepseek_v4.py (key map, FP8 dense side, _apply_gate epilogue), and the binding engines engines/nvme_experts.py, engines/nvme_train.py and engines/int4_experts.py. grouped-nf4-gemm (GitHub, PyPI) owns the native MXFP4 kernels (mxfp4_grouped, including the decode GEMV), the relocation bake nvme_arena.bake_expert_tensors, and mxfp4_residency. Kernel-level questions belong there; [fast] is the seam.

Install

pip install "experts4bit-qlora[train]"   # minimum/reference training: the loader (decode-then-NF4 path)
pip install "experts4bit-qlora[fast]"    # residency/NVMe/fast-kernel route: grouped-nf4-gemm's MXFP4 kernels, arena bake, residency

Smallest correct example

Needs: GPU + network + model download + local NVMe.

python -c "
from nvme_arena import bake_expert_tensors
from mxfp4_residency import V4_RESIDENCY_KINDS
bake_expert_tensors('/path/to/DeepSeek-V4-Flash', '/nvme/v4.mxarena',
                    name_template='layers.{layer}.ffn.experts.{expert}.{kind}',
                    kinds=V4_RESIDENCY_KINDS)"        # relocation: no re-quantisation

Needs: the same GPU, the [train] and [fast] extras, and the arena baked above.

import torch
from experts4bit_qlora import enable_mxfp4_nvme_residency, load_moe_4bit_streaming

model, cfg = load_moe_4bit_streaming("deepseek-ai/DeepSeek-V4-Flash", "cuda", torch.bfloat16,
                                     r=8, alpha=16, quant_type="nf4", arena="/nvme/v4.mxarena")
n = enable_mxfp4_nvme_residency(model, "/nvme/v4.mxarena",
                                k_slots=cfg.num_experts_per_tok, hot_rows=16)
assert n > 0

Training against the same relocated bytes: load with arena=..., arena_train=True, then enable_nvme_train_residency(model, arena, hot_rows=<expert count>) with gradient checkpointing enabled (offload-moe-experts-to-cpu-or-nvme.md). The default NF4 path needs no arena: load_moe_4bit_streaming("openai/gpt-oss-20b", ...) then verify_moe_4bit(model, strict=True).

Expected result

enable_mxfp4_nvme_residency returns the number of MoE modules bound (one per layer); a model loaded with arena= has its experts on meta and cannot run until an engine is bound. enable_nvme_train_residency returns the number of modules moved and refuses an undersized hot_rows. For the NF4 path, verify_moe_4bit(model, strict=True) returns without raising. The CPU spec for the MXFP4 training arena — layout resolution, staging into MXFP4-declared buffers, numerics against an oracle decoded from the source bytes — is tests/test_mxfp4_arena_train.py.

Supported scope

Limitations

Evidence

Register: ../claims.json.

Common wrong approaches

Source and freshness

This page is a rendering of docs/solutions/mxfp4-moe-training-and-residency.md at commit 0c2a256dcdc2 (sha256 7975d3720999027b…). Numbers are never copied here: every measured statement cites a claim ID in docs/claims.json at that commit. Repository-relative links resolve to this site's pages where the document is published and to the pinned commit otherwise.

CURRENT · source: pjordanandrsn/experts4bit-qlora@0c2a256dcdc2 · rendered package: 0.35.3 · latest published package: 0.35.3