CERIN AMROTH · ML systems

grouped-nf4-gemm

Triton kernels for 4-bit MoE inference: grouped NF4/MXFP4 GEMM, INT4 GEMV, FP8 paged attention, and CPU/NVMe expert streaming.

Canonical PyPI package
grouped-nf4-gemm
Canonical repository
github.com/pjordanandrsn/grouped-nf4-gemm
Import
nf4_grouped, mxfp4_grouped, int4_b32, fp8_paged_attn, fp8_kv, nvme_arena, nvme_reader, nvme_residency, nvme_bake_nf4, mxfp4_loader, gptq_pack, nf4_pack_ref, mxfp4_pack_ref, verify_provenance
License
MIT
Repository version
0.30.2 (at the pinned commit)
Latest PyPI version
0.30.2 — published
Source commit
e2af4cfb91b2 (2026-09-05) · files at this commit
Claim register
claims tiered in the public register: 11 confirmed · 9 measured · 3 measured-private · 1 projected · 3 open · 1 superseded · 2 retired — docs/claims.json (pinned)
Current status
v0.30.2 · current status → · capability table · docs/STATUS.md (pinned)
System manifest
kernels package of one system with experts4bit-qlorasystem-manifest.json (verbatim, identical in both repositories; provenance)

Also discoverable as nf4gemm, gnf4, grouped-mxfp4-gemm. These are lookup-only aliases from the system manifest; grouped-nf4-gemm is the canonical project.

Direct answer

Use this package when dequantising each active expert into a high-precision weight before its matmul is the bottleneck. It computes the grouped expert GEMM directly over the packed NF4 (bitsandbytes gemm_4bit layout) or native MXFP4 (e2m1 + e8m0) representations, and ships the int4 decode GEMV, the fp8 paged attention, the decode glue and the host/NVMe primitives a 4-bit MoE serving path needs around it. It is a kernel package: experts4bit-qlora drives it.

Use this when

Do not use this when

Install

Routes from docs/capabilities.json at the pinned commit; the first entry of the register is the primary route.

pip install grouped-nf4-gemm

Primary route: kernel package.

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 for the serving tiers and for the default NF4 quantise bake (nvme_bake_nf4.bake_nf4 with quantize_fn=None); the relocation bake and verify (nvme_arena.bake / bake_expert_tensors / verify) need no GPU; NVIDIA CUDA GPU, sm_80 or newer (sm_120 is the primary serving target); NVIDIA CUDA GPU, sm_80 or newer (the composition was measured on the RTX 5090, sm_120); NVIDIA CUDA GPU, sm_80 or newer; this is the path sm_80-sm_88 take by default. Its reference tests were run on an RTX 5090 (sm_120) with the mode forced; no registered cell exists on sm_80-sm_88; NVIDIA CUDA GPU, sm_89 or newer (the fp8 tensor-core dot); measured on the RTX 5090 (sm_120) only -- sm_89 and sm_90 meet the requirement but no registered cell was run there; none: pure torch (a CUDA GPU is optional) · Requires: a local NVMe or fast block device for the arena; O_DIRECT reads; bitsandbytes and CUDA for the NF4 quantise bake (nvme_bake_nf4.bake_nf4 with the default quantiser); the geometry/manifest path is pure torch when a quantize_fn is injected; macOS/Windows: the pure-torch surface (pack references, dequant, provenance, arena bake/verify) imports and runs without triton via _triton_shim; the Triton kernels need a CUDA GPU; macOS and Windows are not exercised by CI; pinned host RAM sized from measured free memory (capacity_for_bytes); shape constraints, all from fp8_paged_attn.fp8_compute_unsupported (the single predicate the default selector and the path's own asserts share): v_groups == 1; k_groups in (1, 2, 4, 8, 16); head_dim // k_groups >= 32; q in bf16 or fp16; split branch: ktile >= 32 when the caller supplies it; packed branch (pack_heads=True): block_tokens * n_kv_heads >= 32. A call that fails any of these with GNF4_ATTN_COMPUTE unset takes the f32 path (its own entry); the open item is on torch 2.8.0+cu128 / triton 3.4.0 -- the package floor -- so no torch/Triton pair inside the supported range is registered as passing this path's reference tests; torch>=2.8; torch>=2.8 (pre-releases accepted); triton>=3.4 (Linux-only distribution)

Which path?

NeedEntry pointInstallStatus
A per-expert 4-bit MoE loop pays a launch per active expert per projection, and wherever that loop dequantises (bitsandbytes releases before 0.50.0, cells outside its packed gemm_4bit inference forward, the conventional 4-bit backward) it also writes and re-reads a bf16 copy of each expert; compute the grouped expert GEMM directly on the NF4-packed weights in one launch instead.nf4_grouped:gemm_4bit_grouped · nf4_grouped:gemm_4bit_grouped_captured · nf4_grouped:build_group_tiles_devicepip install grouped-nf4-gemmsupported
Serve or train a MoE whose experts are released as MXFP4 (gpt-oss, DeepSeek-V4, Kimi lineage) directly from the checkpoint's own bytes, without re-quantising them.mxfp4_grouped:gemm_mxfp4_grouped · mxfp4_grouped:gemv_mxfp4_b32 · mxfp4_pack_ref:dequant_mxfp4pip install grouped-nf4-gemmsupported
Single-token (decode) expert and attention projections on 4-bit weights are bandwidth-bound; an int4 GEMV with 32-wide scales and a calibrated packer serves them near the memory ceiling.int4_b32:quant_x_rows · int4_b32:gemv_int4_b32 · int4_b32:gemm_int4_b32_grouped_capturedpip install grouped-nf4-gemmmeasured-private
A 4-bit MoE serving path needs a paged decode attention over an fp8 KV cache -- sliding windows, attention sinks, a custom scale, per-layer KV geometry -- computed with fp8 tensor-core dots on the cards that have them.fp8_kv:quantize_kv_fp8 · fp8_kv:fp8_kv_append_t1 · fp8_paged_attn:fp8_paged_decode_attentionpip install grouped-nf4-gemmsupported
The same paged decode attention over the fp8 KV cache computed with f32 dots: the default on sm_80-sm_88 (no fp8 tensor-core dot), the fallback wherever the fp8 constraints fail with GNF4_ATTN_COMPUTE unset, and every explicit f32 request.fp8_paged_attn:fp8_paged_decode_attention · fp8_paged_attn:paged_attn_ref · fp8_paged_attn:compute_countspip install grouped-nf4-gemmunsupported
The non-GEMM part of a batch-1 decode step is a tail of small launches (RMSNorm, residual add, rotary, router softmax and top-k, activation, top-k combine, split-K reduce); fold each into one launch.int4_b32:rmsnorm_rows · int4_b32:rmsnorm_resid_rows · int4_b32:scaled_resid_add_rowspip install grouped-nf4-gemmmeasured-private
The expert weights do not fit in VRAM, or not even in host RAM: stream them from pinned host memory or from an on-disk expert arena on NVMe.nvme_arena:bake · nvme_arena:bake_expert_tensors · nvme_arena:verifypip install grouped-nf4-gemmsupported
Prove that the quantised bytes a kernel serves are the checkpoint's released bytes, unchanged, before quoting any result.mxfp4_loader:file_tensor_sha256 · mxfp4_loader:provenance_table · mxfp4_loader:verify_arena_matchespip install grouped-nf4-gemmsupported

Smallest verified example

CPU-only, no Triton: the pure-torch pack reference and the oracle every kernel is asserted against. Executed on a triton-less host by the page authors; the GPU form (gemm_4bit_grouped against the same oracle) is in the solution page.

import torch
from nf4_pack_ref import quantize_pack_nf4
from nf4_grouped import dequant_ref

w = torch.randn(64, 128)
packed, absmax = quantize_pack_nf4(w)                 # [64, 64] uint8, [64, 2] fp32
back = dequant_ref(packed, absmax, 64, 128)           # the checkable oracle
assert (back - w).abs().max() < 0.25 * w.abs().max()  # NF4 round-trip inside the codebook's spacing

What it supports

Modes
benchmark, calibration, inference, offload, packing, serving, streaming, training, verification
Formats
bf16, fp8, int4, mxfp4, nf4
Model families
DeepSeek-V4 lineage; Kimi K3 lineage (reference decode); Qwen3-235B-A22B (host-RAM flagship); any checkpoint whose experts the bake can enumerate; any expert or projection weight packed with pack_int4_b32 / gptq_pack_int4_b32 (driven by experts4bit-qlora's serve lanes); any fused-expert MoE whose experts are packed in the bitsandbytes NF4 gemm_4bit layout (Qwen3-MoE, OLMoE, Mixtral, GraniteMoe, Gemma-4 text tower via experts4bit-qlora); any safetensors checkpoint; MXFP4 expert tensors for gpt-oss / DeepSeek-V4 / Kimi lineage; driven by experts4bit-qlora's paged engine for Qwen3-MoE, OLMoE, GraniteMoe, gpt-oss, Gemma-4, Mixtral; gpt-oss (20b, 120b); gpt-oss / DeepSeek-V4 / Kimi lineage MXFP4 arenas
Operating system
Linux
Python
>=3.11 tested in CI (pyproject says >=3.9; 3.9/3.10 are not tested)
Accelerator
NVIDIA CUDA GPU for the serving tiers and for the default NF4 quantise bake (nvme_bake_nf4.bake_nf4 with quantize_fn=None); the relocation bake and verify (nvme_arena.bake / bake_expert_tensors / verify) need no GPU; NVIDIA CUDA GPU, sm_80 or newer (sm_120 is the primary serving target); NVIDIA CUDA GPU, sm_80 or newer (the composition was measured on the RTX 5090, sm_120); NVIDIA CUDA GPU, sm_80 or newer; this is the path sm_80-sm_88 take by default. Its reference tests were run on an RTX 5090 (sm_120) with the mode forced; no registered cell exists on sm_80-sm_88; NVIDIA CUDA GPU, sm_89 or newer (the fp8 tensor-core dot); measured on the RTX 5090 (sm_120) only -- sm_89 and sm_90 meet the requirement but no registered cell was run there; none: pure torch (a CUDA GPU is optional)
Public entry points
arena_experts:ArenaExpertSource, cli:python -m nvme_arena, cli:python -m nvme_bake_nf4, cli:python -m verify_provenance, flag:GNF4_ATTN_COMPUTE, fp8_kv:fp8_kv_append_t1, fp8_kv:quantize_kv_fp8, fp8_paged_attn:compute_counts, fp8_paged_attn:fp8_compute_unsupported, fp8_paged_attn:fp8_paged_decode_attention, fp8_paged_attn:paged_attn_available, fp8_paged_attn:paged_attn_ref, gptq_pack:HessianAccumulator, gptq_pack:gptq_pack_int4_b32, int4_b32:combine_rows, int4_b32:gemm_int4_b32_grouped_captured, int4_b32:gemv_int4_b32, int4_b32:quant_x_rows, int4_b32:reduce_partials, int4_b32:rmsnorm_resid_rows, int4_b32:rmsnorm_rows, int4_b32:rope_heads, int4_b32:rope_norm_heads, int4_b32:router_epilogue, int4_b32:scaled_resid_add_rows, int4_b32:swiglu_rows, int4_pack_ref:dequant_int4_ref, int4_pack_ref:pack_int4_b32, mxfp4_grouped:gemm_mxfp4_grouped, mxfp4_grouped:gemv_mxfp4_b32, mxfp4_loader:file_tensor_sha256, mxfp4_loader:provenance_table, mxfp4_loader:to_kernel_shapes, mxfp4_loader:verify_arena_matches, mxfp4_native_load:build_native_qlora_model, mxfp4_pack_ref:dequant_mxfp4, mxfp4_pack_ref:quantize_pack_mxfp4, mxfp4_qlora, mxfp4_residency:Mxfp4NvmeResidency, nf4_grouped:build_group_tiles_device, nf4_grouped:dequant_ref, nf4_grouped:dgrad_4bit_grouped, nf4_grouped:gemm_4bit_grouped, nf4_grouped:gemm_4bit_grouped_captured, nf4_grouped:repack_from_bnb, nf4_pack_ref:quantize_pack_nf4, nf4_qlora:fused_grouped_lora, nf4_qlora:gemm_4bit_grouped_train, nvme_arena:bake, nvme_arena:bake_expert_tensors, nvme_arena:verify, nvme_bake_nf4:bake_nf4, nvme_reader:ArenaReader, nvme_reader:alloc_landing, nvme_residency:ColdTier, nvme_residency:capacity_for_bytes, row_pool:RowPool, verify_provenance:main
Owns (system manifest)
  • grouped packed GEMM (NF4 and native MXFP4) and its dgrad
  • decode GEMV (int4-b32, MXFP4) and split-K reduce
  • FP8 paged attention and the fp8 KV appends
  • decode glue kernels (rope, norm and residual folds, swiglu, combine)
  • pack and pure-torch reference operations, GPTQ packing, provenance verification
  • host/NVMe primitives (arena, reader, row tier, bake, residency primitives)
  • kernel-level measurement and the claims register for kernel-level numbers
Related package
experts4bit-qlora — one system, two independently released packages: the runtime package depends on the kernel package through its optional `fast` extra; the kernel package never depends on the runtime package Dependency direction: experts4bit-qlora -> grouped-nf4-gemm.

Limitations — what it does not promise

Current measured position

Representative active claims, selected from docs/claims.json at the source commit; retired and superseded claims never appear here, and the register's tiers are counted above (claims tiered in the public register: 11 confirmed · 9 measured · 3 measured-private · 1 projected · 3 open · 1 superseded · 2 retired). Each card links its receipt at the pinned commit.

The fused NF4 grouped GEMM (fp32 accumulate, bf16 epilogue) has never measured less accurate than the dequantize-to-bf16-then-GEMM baseline, in every confirmatory cell.confirmed
gnf4.kernel.fused-more-accurate-than-dequant-bf16 · sm_86 (A2000, 3090), sm_89, sm_90 · measured 2026-07-14 · receipt (pinned)
At batch-1 decode on sm_86, census MoE shapes (OLMoE, Qwen3-30B, Gemma-4, gpt-oss-120b) run 1.16-2.73x the dequant baseline at median; top_k=1 and tiny (<~5M weight elements) shapes are known losers.confirmed
gnf4.kernel.decode-speed-census · sm_86 · measured 2026-07-14 · receipt (pinned)
Against a CUDA-graphed per-expert baseline at the decode band (T=32) the fused path LOSES on both 4090 and H100 (0.949x, 0.858x); the memory-traffic win survives only at training shape on bandwidth-limited cards (1.489x on the 4090, parity 1.059x on the H100).confirmed
gnf4.kernel.graphed-baseline-decode-loses · RTX 4090 (sm_89), H100 (sm_90) · measured 2026-08-13 · receipt (pinned)
Serving gpt-oss-120b on its exact released MXFP4 bytes scores exact-chunk ppl 26.72 against the shipped-precision reference 26.75, deleting the +9.4% ppl / KL 0.066 NF4-requantisation tax; per-shard provenance sha256(loaded) == sha256(file range) on a 4-tensor spot sample (a spot check, not shard-level coverage).confirmed
gnf4.mxfp4.serve-tax-deleted · DO H200 pod · measured 2026-07-19 · receipt (pinned)
Qwen3-235B-A22B with all NF4 experts in ~128 GB pinned host RAM streams at 5.57 tok/s = 102-103% of the measured 44.3 GB/s link's waterfall ceiling on a 13.6 GB working set (synthetic weights, real attention + router); the dequant path on the identical pipeline: 1.81 tok/s.confirmed
gnf4.flagship.235b-phaseA · datacenter PCIe link 44.3 GB/s · measured 2026-07-14 · receipt (pinned)
The NVMe tier is a batch tier: at the measured per-box S ~= 3.45 GB/s a fully cold 235B streams ~2.3 s/token and a K3-class model ~7.5 s/token. What it buys is reachability and provenance, not latency.measured
gnf4.nvme.tier-batch-only · QNAP Xeon W-1250, FireCuda 530 on PCIe Gen3 x4 · measured 2026-07-27 · receipt (pinned)

Current status and compatibility

v0.30.2 · current status → — the position page is docs/STATUS.md at the pinned commit (latest on main, unpinned; not the source of any fact rendered here); the site's status and compatibility pages are generated from the same commit, and the evidence words are defined once in the system manifest's vocabulary.

Problems this solves

CURRENT · source: pjordanandrsn/grouped-nf4-gemm@e2af4cfb91b2 · rendered package: 0.30.2 · latest published package: 0.30.2