Skip to content

Feature Request: opt-in FP8 KV-cache support for long-context MoE inference #280

Open

Description

@mbetrifork

Summary

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:

The proof of concept:

  • Adds an opt-in --kv-cache-dtype fp8_e4m3 option.
  • 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.

Activity

  1. gdevenyi commented on Sep 5, 2026

    @gdevenyi
    Contributor

    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 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.

    Feedback with the Ada numbers is on #354 itself.

    🤖 Generated with Claude Code

    https://claude.ai/code/session_0173pf9k9fSVtwbm3f898HDt

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions