Repository navigation
WebGPU: Fix DequantizeLinear 1-D block_size handling - #32734
Merged
Merged
Conversation
Corrected WebGPU rank-1 blocked DequantizeLinear classification and added an int8 regression test with zero-point. Local tests: - python tools\ci_build\build.py --build_dir D:\jiajia\PR-Manager\.build-slot-pool\slots\ort-webgpu-1\build --config Release --build_shared_lib --use_webgpu --parallel --build --skip_tests --target onnxruntime_provider_test: passed (Reconfigured pooled slot for this worktree; onnxruntime_provider_test built successfully.) - onnxruntime_provider_test.exe --gtest_filter="DequantizeLinearOp21BlockedTest.*": passed (37 tests ran and passed; SignedInt_UseZeroPoint_OneDimension executed successfully.) - lintrunner -a: passed (No lint issues; all patches applied successfully.) - Initial provider-test build with inherited Git configuration: failed (diagnostic/superseded) (Dawn version generation rejected an empty GIT_CONFIG_VALUE_3; retry with the malformed inherited entry removed succeeded.) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Copilot review overview
π’ Approval recommended
The focused fix matches the operator semantics and includes regression coverage for the reported failure.
Review effort: Balanced
Findings: None
What changed in this PR
Fixes WebGPUβs classification of rank-1 blocked DequantizeLinear inputs.
Changes:
- Treats explicit positive
block_sizeas blocked quantization. - Adds an int8 regression test with zero-point values.
| File | Description |
|---|---|
onnxruntime/βcore/βproviders/βwebgpu/βquantization/βquantize_linear.cc |
Corrects blocked-quantization classification. |
onnxruntime/βtest/βproviders/βcpu/βtensor/βquantize_linear_test.cc |
Tests rank-1 blocked dequantization on WebGPU and CPU. |
π‘ Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Jiajia Qin (qjia7)
marked this pull request as ready for review
September 25, 2026 07:55
Jiajia Qin (qjia7)
requested review from
Edward Chen (edgchen1) and
Prathik Rao (prathikr)
September 26, 2026 01:41
Xiaofei Han (xiaofeihan1)
approved these changes
Oct 14, 2026
Edward Chen (edgchen1)
added a commit
that referenced
this pull request
Oct 27, 2026
### Description <!-- Describe your changes. --> This cherry-picks the following commits for the release: | Commit ID | PR Number | Commit Title | |-----------|-----------|-------------| | 7c1103e | #32734 | WebGPU: Fix DequantizeLinear 1-D block_size handling | | 3b4a0ff | #33571 | Fix OrtMemoryInfo ABI mismatch across the plugin EP boundary | ### Motivation and Context <!-- - Why is this change required? What problem does it solve? - If it fixes an open issue, please link to the issue here. --> WebGPU EP 0.5.0 release. --------- Co-authored-by: Jiajia Qin <jiajiaqin@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: adrastogi <aditya.rastogi@microsoft.com>
adrastogi
added a commit
that referenced
this pull request
Oct 30, 2026
### Description Adds a WebGPU `QuantizeLinear` kernel and int8 support in `Cast`, and fixes byte-lane packing in the segmented (>`maxStorageBufferBindingSize`) output setters. All gaps were found by the W3C WebNN conformance (WPT) suite running on the WebGPU EP with CPU fallback disabled. Commits: 1. **Add WebNN regression test for 1-D blocked uint8 DequantizeLinear.** Adds the WebNN vector "dequantizeLinear uint8 1D tensor with 1D scale, implicit block_size = 2" (#32730) for f32 and f16 scales, with `block_size` both explicit and inferred. #32734 fixed this path but only tested int8 with block_size 4. 2. **Add QuantizeLinear kernel.** - f32/f16 input, int8/uint8 output. Registered for opsets 10-12, 13-18, 19-20, 21-22 and 23-24. From opset 23, x / y_scale is computed in the `precision` type (default: the y_scale type). The kernel divides in f32, so opset 23/24 is registered for f32 `y_scale` only. Both GetCapability paths (in-tree `webgpu_execution_provider.cc` and plugin `ep/ep.cc`) leave nodes with an explicit non-f32 `precision` to another EP. - Each invocation writes one packed u32 word (4 outputs), so output bytes are never shared between invocations. - DequantizeLinear's per-tensor/per-axis/blocked classification and shape validation (including block_size inference and the element-wise axis 0, block_size 1 form) is factored into a helper used by both kernels. - Adds an `Int8x4` case to `ShaderVariableHelper::SetByOffset` that packs the low byte of each lane. - WGSL f32 division is only accurate to 2.5 ULP, which flips results near .5 (e.g. `QuantizeLinearOpTest.Int8`: -5 / 0.039215686 = -127.4999...). The shader recomputes the quotient with integer long division when 0.25 <= |q| < 1024, so round-half-to-even matches the CPU kernel bit-exactly. 3. **Support int8 in Cast.** Adds int8 to T1/T2. Input is unpacked with `unpack4xI8` (sign-extending) on both the generic and to-int64 paths; output uses the new Int8x4 packing, which keeps each lane's low byte like a narrowing conversion. 4. **Pack byte lanes in segmented output setters.** Outputs larger than `maxStorageBufferBindingSize` are written through a generated per-segment setter that stored the packed u32 value unchanged. Uint8x4/Int8x4 writers (Cast, Expand, Gather, QuantizeLinear) pass one value per lane, so those shaders failed to compile. The setter now takes `vec4<u32>`/`vec4<i32>` lanes and packs them like the unsegmented `SetByOffset`. This also fixes a latent uint8 bug on main for Cast/Expand/Gather. Tests (WebGPU-pinned, CPU EP fallback disabled) are in `onnxruntime/test/providers/webgpu/tensor/{quantize_linear_test,cast_op_test}.cc`. They cover the WebNN conformance vectors, ties, saturation, per-axis, blocked (first/last axis, partial block), all opsets, `precision` routing, near-tie quotients against the CPU reference, Q -> DQ round trip, int8 casts to/from f32/f16/int32/int64/uint8/bool, and outputs spanning buffer segments. Validation (Windows ARM64, NVIDIA RTX Spark N1X / D3D12, Release): - `build.py --use_webgpu ... --target onnxruntime_provider_test`, then `onnxruntime_provider_test --gtest_filter="*WebGpu*:CastOpTest.*:*QuantizeLinear*:*DequantizeLinear*:ExpandOpTest.*:GatherOpTest.*"`: 1159 tests, 1147 passed, 0 failed, 12 skipped. The skips existed before this change and are unrelated: `QuantizeLinearOpTest.*_DML*` (DML only) and hardware/build-feature skips in `WebGpuMatMulAlgorithmTest`, `WebGpuMatMulNBitsTest.DP4A*` and `WebGpuContextTest.AdapterIndexRejectsUnsupportedBuild`. - New tests that ran and passed: `WebGpuQuantizeLinearTest.*` (including `OpsetVersions` 10-24, `Opset23PrecisionOtherThanFloat`, `Opset23ExplicitFloatPrecision`, `SegmentedOutput`), `CastOpTest.Int8ToOtherTypes_WebGpu`, `CastOpTest.OtherTypesToInt8_WebGpu`, `CastOpTest.ByteOutputsAcrossBufferSegments_WebGpu` and `WebGpuDequantizeLinearTest.*`. - The existing CPU `QuantizeLinearOpTest.*` suite also runs on WebGPU and passes, including `Int8`, which depends on the exact-quotient rounding. - Plugin EP build: `build.py --use_webgpu shared_lib --cmake_extra_defines onnxruntime_BUILD_UNIT_TESTS=OFF --target onnxruntime_providers_webgpu` succeeds. This compiles the `ep/ep.cc` GetCapability change. - Sensitivity check: without the fixes, `Opset23PrecisionOtherThanFloat` returned 5 and 3 (expected 4 and 2), and `SegmentedOutput` and `CastOpTest.ByteOutputsAcrossBufferSegments_WebGpu` failed. Related work: this overlaps with @edgchen1's branch [`edgchen1/webgpu_quantizelinear`](https://github.com/microsoft/onnxruntime/tree/edgchen1/webgpu_quantizelinear) (last updated 2026-04-10, no PR yet). That branch also adds int4/uint4 QuantizeLinear output, which this PR does not cover; int4/uint4 is planned as a follow-up PR. ### Motivation and Context WebNN's `quantizeLinear`, qdq subgraphs and int8 `cast` lower to ONNX `QuantizeLinear`/`Cast`, which had no WebGPU kernel (or no int8 type), so graph build failed with CPU fallback disabled. WPT results (webgfx/webnn-test full suite, Edge Canary 158 arm64, NVIDIA RTX Spark N1X (D3D12), ORT 1.28.3 runtime, WebGPU plugin EP). Before = plugin built from main at 8120434; after = plugin with this change and four companion WebGPU PRs applied, attributed by op. This PR's ops fix 67 subtests (57 required): | WPT test | Before | After | Notes | |---|---|---|---| | quantizeLinear | 4/29 | 15/29 | remaining 14 are optional int4/uint4/int32 outputs | | qdq_subgraph | 1/43 | 43/43 | | | dequantizeLinear | 25/33 | 27/33 | "quantizeLinear then dequantizeLinear" cases | | cast | 38/51 | 50/51 | all int8 casts; remaining failure is a separate f32->f16 rounding issue | For context, with this PR and its four companions applied, failing WPT subtests drop from 343 to 68 (required failures 275 -> 11). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
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.
Closes #32730
Summary
Corrected WebGPU rank-1 blocked DequantizeLinear classification and added an int8 regression test with zero-point.
Local tests
This pr was prepared by compilot-cli.