You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Feature Request: opt-in FP8 KV-cache support for long-context MoE inference #280
Please consider adding an opt-in FP8 key/value (KV) cache for long-context inference.
Quantizing the KV cache can substantially increase the usable context capacity on
consumer GPUs, especially when serving large MoE models whose weights already use
NVFP4/FP8 formats. This would complement the broader quantized-cache request in #262 with a specific FP8
design point that should preserve more quality than lower-bit cache formats.
Proof of concept
I built and tested an experimental implementation in a public fork:
Stores K/V values as E4M3 FP8 with independent FP32 dynamic scales.
Dequantizes inside the Triton attention kernels.
Includes KV-pool sizing/accounting and configuration validation.
Includes CPU/configuration tests and optional CUDA kernel tests.
On an 8 GB RTX 2000 Ada laptop GPU, it was used to serve Qwen3.6-35B-A3B-NVFP4 with a 131K-token KV pool and a coding-agent client.
The regular attention KV data is approximately half the BF16 storage, with a
small scale-table overhead.
Current proof-of-concept limitations
The fork intentionally keeps the first implementation narrow:
Qwen3.5/Qwen3.6 MoE checkpoints only.
BF16 compute only.
Triton attention only.
Ordinary paged MHA KV storage only.
Tensor parallel size 1 only.
NVIDIA compute capability 8.9 (Ada) or newer.
Qwen's recurrent Gated DeltaNet state remains unquantized.
Dynamic per-token/per-KV-head scales are used; checkpoint calibration scales
are not yet supported.
Unsupported combinations fail during configuration validation, and the feature
is disabled by default. The fork is intended as a reproducible demonstration of
the design space; maintainers may prefer a different abstraction or kernel
implementation.
Possible next steps
Benchmark BF16 versus FP8 KV memory, prefill/decode throughput, and quality.
Validate FP16 compute and tensor-parallel configurations.
Extend support to other MHA/GQA model families and attention backends.
Decide on scale granularity and optional checkpoint calibration data.
Add a maintained CUDA test/benchmark path for supported GPUs.
This exists now — PR #354 (--kv-cache-dtype fp8, e4m3 codes + row scales). We have been running it in production since 2026-09-04 on exactly the workload this issue describes (long-context MoE), so here are the numbers it buys.
Per-token KV cost, per rank (from /v1/cache/status, which reports unit_bytes):
bytes / token / rank
bf16
13,056
fp8 e4m3
7,009
What that converts into. The interesting part is not the KV saving itself but what the freed VRAM buys on a MoE model, because KV and the expert cache compete for the same budget. At a 2,097,152-token pool (8 users x the model's full 262k context):
KV dtype
expert slots
residency
single-stream
8 concurrent
bf16
8,290
33.7%
-15%
-42%
fp8
17,423
70.9%
baseline
baseline
So on this model fp8 KV is what makes eight full-length contexts affordable at all: in bf16 the same pool starves the expert cache and costs 42% of aggregate throughput. Decode is flat from 100% residency down to ~70% here, so 70.9% is free; 33.7% is not.
Quality. GSM8K-300 greedy 97.0%, unchanged from bf16 KV. Recall probes at 105k and 215k tokens intact, image prefix-cache hits unchanged, eight concurrent 177k-token prompts all recalled with full prefix hits on the second turn. Greedy text does diverge from bf16 after ~30-40 words, as you would expect from any KV quantization — worth knowing if you diff outputs, harmless if you measure task accuracy.
One measurement caveat that cost me an hour: the first process to use the new Triton kernels compiles them during your benchmark. My first run showed 80 tok/s client-side while the server's own gen throughput lines said 94-101. Check ~/.triton/cache mtimes, or just bench twice.
Activity
gdevenyi commentedon Sep 5, 2026
This exists now — PR #354 (
--kv-cache-dtype fp8, e4m3 codes + row scales). We have been running it in production since 2026-09-04 on exactly the workload this issue describes (long-context MoE), so here are the numbers it buys.Setup: 2 x RTX 6000 Ada 48 GB, TP=2, Qwen3.8-Flash-Next NVFP4 (512 experts, top-10, 48 MoE layers, 262,144-token context), offload MoE backend.
Per-token KV cost, per rank (from
/v1/cache/status, which reportsunit_bytes):What that converts into. The interesting part is not the KV saving itself but what the freed VRAM buys on a MoE model, because KV and the expert cache compete for the same budget. At a 2,097,152-token pool (8 users x the model's full 262k context):
So on this model fp8 KV is what makes eight full-length contexts affordable at all: in bf16 the same pool starves the expert cache and costs 42% of aggregate throughput. Decode is flat from 100% residency down to ~70% here, so 70.9% is free; 33.7% is not.
Quality. GSM8K-300 greedy 97.0%, unchanged from bf16 KV. Recall probes at 105k and 215k tokens intact, image prefix-cache hits unchanged, eight concurrent 177k-token prompts all recalled with full prefix hits on the second turn. Greedy text does diverge from bf16 after ~30-40 words, as you would expect from any KV quantization — worth knowing if you diff outputs, harmless if you measure task accuracy.
One measurement caveat that cost me an hour: the first process to use the new Triton kernels compiles them during your benchmark. My first run showed 80 tok/s client-side while the server's own
gen throughputlines said 94-101. Check~/.triton/cachemtimes, or just bench twice.Feedback with the Ada numbers is on #354 itself.
🤖 Generated with Claude Code
https://claude.ai/code/session_0173pf9k9fSVtwbm3f898HDt