fp8 KV cache: pre-dispatch quantize_kv in forward_serve_vllm - #4646
Open
lokic233 wants to merge 2 commits into
Open
fp8 KV cache: pre-dispatch quantize_kv in forward_serve_vllm#4646lokic233 wants to merge 2 commits into
lokic233 wants to merge 2 commits into
Conversation
forward_serve_vllm passes bf16 k/v straight into the RPA v3 kernel with q_scale=k_scale=v_scale=None. When the KV cache is allocated in fp8 (kv_cache_dtype=fp8), the kernel raises 'Expected kv_cache.dtype=float8_e4m3fn to be equal to k.dtype=bfloat16' -- its static_validate_inputs requires kv_cache.dtype == k.dtype == v.dtype and its own comment states it expects the kv quantization to happen outside the RPA kernel. The native vLLM backend (layers/vllm/backends/flash_attn.py) already does this: it calls quantize_kv before dispatch. This mirrors that on the MaxText serving path -- when the cache is a 1-byte float (fp8 e4m3/e5m2), quantize k/v to the cache dtype via the shared quantize_kv helper and thread the scales through. Non-fp8 caches are a no-op (scales stay None), so existing bf16 behavior is unchanged. Validated on TPU v7x (gemma-4-2B DAPO RL, 64 chips): with this fix and an fp8 KV cache, capture_model/kv-init clears (no dtype assert), real decode runs on the same RPA kernel that previously asserted, and reward is unchanged (rewards/mean 0.1405, matching the bf16-cache baseline).
lokic233
requested review from
NuojCheng,
RissyRan,
aireenmei,
bvandermoon,
gagika,
gobbleturk,
huytransformer,
igorts-git,
jiangjy1982,
parambole,
richjames0,
shralex,
shuningjin,
suexu1025 and
xibinliu
as code owners
July 28, 2026 16:53
|
Caution The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased. |
4 tasks
Mirrors the existing test_forward_serve_vllm (same mock/fixtures): with an fp8 KV cache, asserts the k/v handed to the RPA kernel are cast to the fp8 cache dtype, guarding the dtype-mismatch crash. Skipped like its sibling (needs the vllm-tpu package, not yet a MaxText dependency).
lokic233
requested review from
A9isha,
SurbhiJainUSC,
abhinavclemson,
darisoy,
dipannita08,
hengtaoguo,
khatwanimohit and
vipannalla
as code owners
July 28, 2026 18:05
Author
|
Added a minimal regression test ( |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Attention.forward_serve_vllmpasses bf16k/vstraight into the ragged-paged-attention (RPA) v3 kernel withq_scale = k_scale = v_scale = None. When the vLLM rollout allocates the KV cache in fp8 (kv_cache_dtype=fp8), the kernel raises:The RPA v3 kernel's
static_validate_inputsrequireskv_cache.dtype == k.dtype == v.dtype, and its own comment states it "expects the kv quantization happens outside of the RPA kernel." The MaxText serving path never quantizes, so it trips the assert duringcapture_model/KV-init and again on any real decode step.Why the native path doesn't hit this
The native vLLM backend (
layers/vllm/backends/flash_attn.py) already quantizes before dispatch — it callsquantize_kv(...)onk/vahead of the attention call.forward_serve_vllmis simply missing the equivalent step.Fix
Mirror
flash_attn.pyon the MaxText serving path: when the KV cache is a 1-byte float (fp8 e4m3/e5m2), quantizek/vto the cache dtype via the sharedquantize_kvhelper and thread the scales through to the kernel. Non-fp8 caches are a no-op (scales stayNone), so bf16 behavior is unchanged. Single code path, reusing the existing helper — no duplicated quantization logic and no in-kernel cast.Validation
Validated on TPU v7x (gemma-4-2B DAPO/GRPO RL, 64 chips, 4x4x4) with
kv_cache_dtype=fp8:capture_model/KV-init — no dtype assert; real decode runs on the same RPA kernel that previously asserted (peak ~500 tok/s).rewards/mean = 0.1405, matching the bf16-cache baseline (~0.13); advantages centered at ~0, no NaN/collapse. Properly-scaled fp8 preserves the reward signal.