[WebGPU EP] fixes fp16 accumulation bug in gemm kernel (#33057)
# ๐ WebGPU FP16 MatMul Accuracy Fix
## ๐ Bug
The Qwen 2.5 0.5B GenAI WebGPU test produced logits that disagreed with
the CPU reference. The issue was isolated to the generic packed FP16
MatMul kernel with shape `M=3, K=896, N=4864`.
The shader stored its accumulator as `vec4<f16>`. Each addition was
therefore rounded to FP16, causing significant error over the long
`K=896` reduction. The worst single-node WebGPU-to-FP32 error was
`0.7760754`.
## ๐ง Fix
Packed MatMul now supports FP32 accumulation. FP16 inputs and workgroup
storage remain unchanged, cached operands are widened to FP32 for
multiplication and accumulation, and the result is converted back to the
output type when written.
## ๐ฏ Scope
This PR fixes FP16 accumulation in the generic packed ONNX `MatMul`
implementation, covering both vec4 and scalar paths. FP16 atomic Split-K
is disabled for this implementation to avoid rounding or overflowing
partial sums before the final reduction.
ONNX `Gemm` is outside this PR's scope. Its packed caller retains the
default `use_f32_accumulation = false`, so FP16 `Gemm` accumulation is
unchanged. The shared helpers remain opt-in; this PR does not enable
FP32 accumulation for every caller or change vendor-specific MatMul
kernels.
## โ
Validation
1. **๐งช ONNX Runtime unit test**
Added `MathOpTest.MatMulPackedFp16LongReductionUsesFloat32Accumulator`.
Before the fix, it failed with expected `8.953125`, actual `9.140625`,
and error `0.1875`. It passes after the fix.
2. **๐ค GenAI regression test**
Ran `test_webgpu_paged_export_runs_prefill_and_decode`, the Qwen WebGPU
test that exposed the issue. It passed with the rebuilt plugin package.
The standalone full-model repro also passed with matching argmax (`4`)
and a maximum logit difference of `0.101529`.
---------
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Prathik Rao <prathikrao@microsoft.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>