[WebGPU] Optimize MatMulNBits wide-tile shader#29611
Conversation
|
@qjia7 @hariharans29 PTAL |
Please check #29599, I think using f32 accumulators is the right direction. Could you split the refactoring changes into a separate PR? That would make it much easier to review and focus on the optimization work. |
- Store the A workgroup tile as [kTileM][KAVecSizeForBlock32/2][2] pairs of vecs so the two vecs consumed per dequantized weight column are read in one access. - Accumulate directly in output_element_t (e.g., f16 for f16 models) instead of hardcoding to f32.
|
Let's leave this refactoring for a follow-up PR. |
I agree - isn't it safer to accumulate in fp32 ? Accumulating in fp16 universally across all workloads (if the op is fp16) seems risky ? |
|
Since #29599 was referenced here — a data point on the accumulator part of this change (the tile-layout optimization itself looks like a clear win and is orthogonal): The f32 accumulator in the wide-tile kernel isn't just precision hygiene — it's load-bearing for correctness. With f16 accumulation, partial dot-product sums overflow 65504 and saturate to +Inf once K approaches ~2048 (deterministically, not as a gradual accuracy loss), which then propagates NaN through LayerNorm/Softmax. That's the failure class of #26732. Notably, both benchmark models here are in that range (gpt-oss-20b K≈2880, Phi-4-mini K=3072) — the table reports prefill TPS, but was output correctness checked against the f32-accumulator baseline on those runs? Also, since the PR changes tile layout and accumulator precision together, it would be useful to benchmark them separately — the memory-access refactoring may account for most of the gain, in which case you could keep the speedup without reintroducing the overflow. If f32 accumulation does turn out to be a measurable cost on Intel in isolation, gating the promotion on K above a threshold (overflow risk scales with reduction length) was floated in #29599 as a compromise that keeps small-K workloads untouched — happy to coordinate there. |
I think it would be helpful to reproduce the overflow issue in the LLM first, before we decide on our next steps. Alternatively, we could use the |
Done — details in #29599 (comment) (the non-repro had a concrete cause: the Hub's fp16 Gemma weights were re-exported on 2025-12-02 with Clip nodes inserted as a model-side workaround for this exact overflow). Summary: pinning On
|
|
Data point relevant to the f16-accumulator question here: following up on the repro request, I ran raw-WGSL f16 accumulation probes across adapters and backends — full write-up in #29599 (comment). Short version: on Intel (D3D12) the shader compiler evaluates straight-line/unrolled f16 The implication for this PR: correctness results obtained with f16 accumulators on Intel don't transfer to other vendors (or even to Intel on a different backend, or to looped codegen). Demoting the wide-tile accumulator to |
Since the NVIDIA-specific logic requires fp32 accumulators and will be gated by a vendor string check. |
|
Flagging one interaction for whoever reviews this PR, since the accumulator part is being deferred to #29599 (full reasoning in #29599 (comment)): The proposal on #29599 is to gate the f32 accumulator behind an NVIDIA vendor-string check. If that lands and this PR demotes the wide-tile accumulator to The tile-layout half of this PR looks like a clean, orthogonal win. The only ask is to keep the accumulator in f32 (or make the demotion opt-in via |
Description
Intel Panther Lake
[1] https://huggingface.co/onnx-community/gpt-oss-20b-ONNX
[2] https://huggingface.co/onnx-community/Phi-4-mini-instruct-ONNX
Motivation and Context
See above.