[ExecuTorch][WebGPU] Add q8ta_conv2d_dw op (int8 depthwise conv)#21201
[ExecuTorch][WebGPU] Add q8ta_conv2d_dw op (int8 depthwise conv)#21201JCNTH wants to merge 1 commit into
Conversation
🔗 Helpful Links🧪 See artifacts and rendered test results at hud.pytorch.org/pr/pytorch/executorch/21201
Note: Links to docs will display an error until the docs builds have been completed. ❗ 1 Active SEVsThere are 1 currently active SEVs. If your PR is affected, please view them below: ❌ 44 New Failures, 3 Unrelated FailuresAs of commit c6ed46b with merge base 266e0dc ( NEW FAILURES - The following jobs have failed:
FLAKY - The following jobs failed but were likely due to flakiness present on trunk:
BROKEN TRUNK - The following job failed but were present on the merge base:👉 Rebase onto the `viable/strict` branch to avoid these failures
This comment was automatically generated by Dr. CI and updates every 15 minutes. |
This PR needs a
|
psiddh
left a comment
There was a problem hiding this comment.
Approving full WebGPU stack
Stack from ghstack (oldest at bottom):
Problem: The WebGPU delegate has no quantized depthwise convolution. A depthwise
nn.Conv2d(groups == channels) through XNNPACK static PT2E lowers to a delegatedquantize_per_tensor -> q8ta_conv2d_dw -> dequantize_per_tensorsubgraph; the quantize/dequantize are the landed C0 ops, soq8ta_conv2d_dwis the one missing piece to run a quantized depthwise conv end-to-end.Solution: Port
et_vk.q8ta_conv2d_dw(int8 activation x int8 per-channel weight -> int8). Depthwise means groups == C == OC: each output channel c convolves only input channel c with its own Kh x Kw filter. Per output element:acc = Σ_{kh,kw} (x_int8[n,c,ih,iw] - input_zero_point) * weight_int8[kh,kw,c]withih = oh*stride_h - pad_h + kh*dil_h,iw = ow*stride_w - pad_w + kw*dil_w(out-of-bounds taps skipped = zero padding); dequantizeacc * input_scale * weight_scales[c] + bias, requantizeclamp(round(v * inv_output_scale) + output_zero_point, -128, 127), packed 4 int8 per word. Mirrors Vulkanq8ta_conv2d_dw(Q8taConv2dDW.cpp+q8ta_conv2d_dw.glsl) and the landedconv1d_dwwindowing.Implementation:
Q8taConv2dDw.cppregistersq8ta_conv2d_dw.default,out = args.back(), one thread per output word = 4 consecutiveW_outpositions of a fixed(n, c, oh)(W_out % 4 == 0for output word alignment), 2D dispatch fold to lift the 65535 cap. Reads full conv geometry (stride/padding/dilationint-lists,groups) and guardsgroups == C == OC,[N,C,H_in,W_in]/[Kh,Kw,OC]/[N,C,H_out,W_out]ranks, int8 dtypes, andactivation == "none"(all fail-loud).Q8taConvDwParamsis an 80-byte (16-aligned) uniform.Constraints / divergences from the Vulkan reference (numerically equivalent, golden-verified): (1) the
weight_sumsarg is unused — the input zero-point correction is folded per-element (Σ(x-zp)·w == Σx·w - zp·Σw), so it matches Vulkan'sweight_sumscompensation exactly, including at zero-padded taps. (2) weight arrives raw[Kh,Kw,OC]int8 (the AOT pattern's depthwise reshapepermute(2,3,1,0); the WebGPU prepack is a passthrough), not Vulkan's int8x4-block 4W4C texture layout.activationscoped to"none"(the XNNPACK-static default; relu-fused is fail-loud, a follow-up).Differential Revision: D112257645