mudler / mudler/vllm.cpp

fix(QUANT-FP8-GENERIC): the per-tensor fp8 QKV projection emits f32 where upstream emits the model dtype

Open
#2,659 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
C++
Stars
423
Forks
53
Avg merge
20h 26m
Merged PRs (30d)
310

Description

Row: QUANT-FP8-GENERIC

Found by wave PORTQ-2 re-deriving PORT-NOW entry 61 of 5559679229..e126687a9a
(#2646). Upstream:
0b37d8389f vllm#48861, "NVFP4 quantization out_dtype should match model dtype,
not torch default".

The invariant, and where this tree breaks it

Upstream's commit replaces self.out_dtype = torch.get_default_dtype() with
get_current_vllm_config().model_config.dtype on three ModelOpt FP8 linear
methods. The VALUE is usually the same; what changes is that the model dtype
becomes the stated authority for an FP8 linear's output.

This tree's per-tensor FP8 QKV projection emits f32, which is wider than
either. src/vllm/model_executor/models/qwen3_5.cpp:2835-2839, inside
ProjectFullAttnQkv's project:

    if (fp8) {
      return h_fp8 != nullptr
                 ? MatmulFp8CutlassPreQuantD(d, *h_fp8, fp8_weight, DType::kF32)
                 : MatmulFp8CutlassD(d, h, fp8_weight, DType::kF32);
    }

The bf16 arm below it and the fp4 arm (:2815-2816) both emit kBF16, so bf16
q/k/v is already a supported downstream shape at this site.

This is known debt, not a discovery

.agents/specs/model-fp8-block-linear.md:133 already records it: "The per-tensor
fp8 arm's kF32 beside it is that arm's own pre-existing choice, not upstream's,
and this row does not adopt it", and :136 says the same for the split GDN
in_proj_qkv. What this entry adds is upstream authority: at the pin target the
model dtype is the explicit rule, so the deviation now contradicts a stated
upstream contract rather than an inferred one.

AGENTS.md is direct about why this matters: "A token gate cannot detect a dtype
that is too wide."
The tokens still match while the path moves twice the bytes.

Scope

Change the per-tensor fp8 out_dtype at ProjectFullAttnQkv's project and at
the merged-FP8 QKV helper (qwen3_5.cpp:2757 deliberately matches the split
path's f32) from kF32 to the model dtype.

One coupling to respect: the split GDN in_proj_qkv hardcodes
fp8_mixed_dt = DType::kF32 (qwen3_5.cpp:4356) under a VT_CHECK asserting it
equals GdnProjectedMixedQkvDType(...). The packed-decode predictor moves with it
or vt::GdnPackedDecode throws.

Roughly 15-40 lines over 1-2 files, plus a memory-format assertion, since a
token gate cannot see this.

Not settled

The reader did not trace every consumer of out.qgate/key/value to prove bf16 is
accepted on the fp8 arm specifically. The fp4 arm already emits bf16 under
Bf16GemmOutEnabled(), which is strong but not conclusive.
model-fp8-block-linear.md:304-306 names exactly this as a NEEDS_DECISION.

QUANT-FP8-MO-STATIC (.agents/quantization-matrix.md:126) is the exact-scope
row but is DONE; this issue is filed against QUANT-FP8-GENERIC (:127,
PARTIAL) so it lands on an open row rather than reopening a closed one. Move it
if the owner prefers.

Nothing was executed for this finding.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in src/vllm/model_executor/models/qwen3_5.cpp at ProjectFullAttnQkv, the merged-FP8 QKV helper, and split GDN in_proj_qkv; read the linked dtype checks and the NEEDS_DECISION note in .agents/specs/model-fp8-block-linear.md. Trace qgate/key/value consumers before deciding the accepted output dtype, then verify the packed-decode coupling and add the requested memory-format assertion. Done means the generic FP8 paths follow the model dtype without breaking the GDN predictor.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
backend, performance
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.