Xenova HF Staff commited on
Commit
07e768f
·
verified ·
1 Parent(s): 77b755a

sync 2e7068faf55e

Browse files
README.md CHANGED
@@ -1,3 +1,82 @@
1
  ---
 
2
  license: apache-2.0
 
 
 
 
3
  ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ library_name: kernels
3
  license: apache-2.0
4
+ tags:
5
+ - kernel
6
+ - webgpu
7
+ - wgsl
8
  ---
9
+ # ai.onnx.ConvInteger
10
+
11
+ `ai.onnx` · standard ONNX operator · ONNX opset ≥ 10
12
+
13
+ ## Description
14
+
15
+ Performs integer convolution on quantized inputs `x` and filter `w`, each with an optional zero point, producing an `int32` output. Zero-point subtraction is applied before accumulation; the result must not overflow 32 bits during accumulation.
16
+
17
+ See the [ONNX `ConvInteger` spec](https://onnx.ai/onnx/operators/onnx__ConvInteger.html) for the reference semantics.
18
+
19
+ ## Inputs
20
+
21
+ | Name | Bind key | Logical dtype | Rank | Shape | Description | Presence |
22
+ | --- | --- | --- | --- | --- | --- | --- |
23
+ | `x` | `x` | `TX` | — | — | Input data tensor of shape `(N x C x D1 x ... x Dn)`. | required |
24
+ | `w` | `w` | `TW` | — | — | Convolution weight tensor of shape `(M x C/group x k1 x ... x kn)`. | required |
25
+ | `x_zero_point` | `x_zero_point` | `TX` | — | — | Optional scalar zero point for `x`; defaults to 0. | optional |
26
+ | `w_zero_point` | `w_zero_point` | `TW` | — | — | Optional scalar or per-output-channel zero point for `w`; defaults to 0. | optional |
27
+
28
+ ## Outputs
29
+
30
+ | Name | Bind key | Logical dtype | Rank | Shape | Description | Presence |
31
+ | --- | --- | --- | --- | --- | --- | --- |
32
+ | `y` | `y` | `TY` | same as `x` | derived; see description | Output tensor containing `int32` convolution results. | required |
33
+
34
+ ## Attributes
35
+
36
+ Attributes and default values (overridable per request):
37
+
38
+ | Attribute | Default | Description |
39
+ | --- | --- | --- |
40
+ | `auto_pad` | `"NOTSET"` | Automatic padding mode. `NOTSET` uses `pads`; `SAME_UPPER` and `SAME_LOWER` choose padding so each output spatial size is `ceil(input / stride)`; `VALID` uses no padding. |
41
+ | `group` | `1` | Number of groups that input and output channels are split into; defaults to 1. |
42
+ | `dilations` | — | Optional dilation factors, one positive integer per spatial axis. Omission means all ones. |
43
+ | `kernel_shape` | — | Optional kernel shape, one positive integer per spatial axis. When present, it must match the spatial dimensions of the weight tensor; omission infers the shape from the weights. |
44
+ | `pads` | — | Optional explicit padding in ONNX order `[begin_axis_0, ..., begin_axis_n, end_axis_0, ..., end_axis_n]`. Omission means all zeros; it cannot be combined with an automatic padding mode. |
45
+ | `strides` | — | Optional stride factors, one positive integer per spatial axis. Omission means all ones. |
46
+
47
+ ## Type constraints
48
+
49
+ | Variable | Allowed dtypes |
50
+ | --- | --- |
51
+ | `TX` | `uint8`, `int8` |
52
+ | `TW` | `uint8`, `int8` |
53
+ | `TY` | `int32` |
54
+
55
+ ## Files
56
+
57
+ - [`metadata.json`](build/webgpu/metadata.json) — kernel metadata (id, digests, provenance)
58
+ - [`manifest.json`](build/webgpu/manifest.json) — the op contract (source of truth)
59
+ - [`test.json`](build/webgpu/test.json) — correctness cases
60
+ - [`bench.json`](build/webgpu/bench.json) — benchmark + tuning cases
61
+ - [`conv-int-accumulate-spatial.wgsl.jinja`](build/webgpu/conv-int-accumulate-spatial.wgsl.jinja)
62
+ - [`conv-int-im2col-spatial.wgsl.jinja`](build/webgpu/conv-int-im2col-spatial.wgsl.jinja)
63
+ - [`quant-dp4a-matmul.wgsl.jinja`](build/webgpu/quant-dp4a-matmul.wgsl.jinja)
64
+
65
+ ## Use with `@huggingface/kernels`
66
+
67
+ The loader derives every required output's shape and logical dtype from the manifest contract and this call.
68
+ It then allocates the result tensors automatically.
69
+
70
+ The `version: 1` option selects the published kernel contract; it is independent of any operator opset, contrib `since_version`, or model version.
71
+
72
+ Replace each `*Data` placeholder with a typed array containing the corresponding input data.
73
+
74
+ ```js
75
+ import { getKernel } from "@huggingface/kernels";
76
+
77
+ const kernel = await getKernel("webgpu-kernels/ai.onnx.ConvInteger", { version: 1 });
78
+ const { y } = await kernel({
79
+ x: { data: xData, shape: [1, 1, 2, 1, 1] },
80
+ w: { data: wData, shape: [1, 1, 1, 1, 1] },
81
+ });
82
+ ```
build/webgpu/bench.json ADDED
@@ -0,0 +1,172 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "op": "ai.onnx.ConvInteger",
3
+ "cases": [
4
+ {
5
+ "name": "u8_nchw_1x16x32x32",
6
+ "inputs": {
7
+ "x": { "dtype": "uint8", "shape": [1, 16, 32, 32], "data": { "kind": "constant", "value": 127 } },
8
+ "w": { "dtype": "uint8", "shape": [16, 16, 3, 3], "data": { "kind": "constant", "value": 129 } },
9
+ "x_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [128] } },
10
+ "w_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [128] } }
11
+ },
12
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 16, 30, 30] } },
13
+ "bench": {
14
+ "metrics": [
15
+ { "type": "gflops", "value": "2 * numel(shapes.y) * dim(shapes.w, 1) * dim(shapes.w, 2) * dim(shapes.w, 3)" }
16
+ ]
17
+ },
18
+ "attrs": {}
19
+ },
20
+ {
21
+ "name": "u8s8_pointwise_1x64x56x56_oc128",
22
+ "inputs": {
23
+ "x": { "dtype": "uint8", "shape": [1, 64, 56, 56], "data": { "kind": "constant", "value": 127 } },
24
+ "w": { "dtype": "int8", "shape": [128, 64, 1, 1], "data": { "kind": "constant", "value": -3 } },
25
+ "x_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [128] } },
26
+ "w_zero_point": { "dtype": "int8", "shape": [1], "data": { "kind": "values", "values": [0] } }
27
+ },
28
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 128, 56, 56] } },
29
+ "bench": {
30
+ "primary": true,
31
+ "metrics": [
32
+ { "type": "gflops", "value": "2 * numel(shapes.y) * dim(shapes.w, 1) * dim(shapes.w, 2) * dim(shapes.w, 3)" }
33
+ ]
34
+ },
35
+ "attrs": {}
36
+ },
37
+ {
38
+ "name": "u8s8_pointwise_unalignedC_c66_oc128_56x56_scalar",
39
+ "preset": "smoke",
40
+ "inputs": {
41
+ "x": { "dtype": "uint8", "shape": [1, 66, 56, 56], "data": { "kind": "constant", "value": 127 } },
42
+ "w": { "dtype": "int8", "shape": [128, 66, 1, 1], "data": { "kind": "constant", "value": -3 } },
43
+ "x_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [128] } },
44
+ "w_zero_point": { "dtype": "int8", "shape": [1], "data": { "kind": "values", "values": [0] } }
45
+ },
46
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 128, 56, 56] } },
47
+ "bench": {
48
+ "metrics": [
49
+ { "type": "gflops", "value": "2 * numel(shapes.y) * dim(shapes.w, 1) * dim(shapes.w, 2) * dim(shapes.w, 3)" }
50
+ ]
51
+ },
52
+ "attrs": {}
53
+ },
54
+ {
55
+ "name": "u8s8_pointwise_rgb_stem_c3_oc32_112x112_scalar",
56
+ "preset": "smoke",
57
+ "inputs": {
58
+ "x": { "dtype": "uint8", "shape": [1, 3, 112, 112], "data": { "kind": "constant", "value": 127 } },
59
+ "w": { "dtype": "int8", "shape": [32, 3, 1, 1], "data": { "kind": "constant", "value": -3 } },
60
+ "x_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [128] } },
61
+ "w_zero_point": { "dtype": "int8", "shape": [1], "data": { "kind": "values", "values": [0] } }
62
+ },
63
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 32, 112, 112] } },
64
+ "bench": {
65
+ "metrics": [
66
+ { "type": "gflops", "value": "2 * numel(shapes.y) * dim(shapes.w, 1) * dim(shapes.w, 2) * dim(shapes.w, 3)" }
67
+ ]
68
+ },
69
+ "attrs": {}
70
+ },
71
+ {
72
+ "name": "u8u8_depthwise_c128_3x3_group128_56x56_scalar",
73
+ "preset": "smoke",
74
+ "attrs": { "group": 128 },
75
+ "inputs": {
76
+ "x": { "dtype": "uint8", "shape": [1, 128, 56, 56], "data": { "kind": "constant", "value": 127 } },
77
+ "w": { "dtype": "uint8", "shape": [128, 1, 3, 3], "data": { "kind": "constant", "value": 129 } },
78
+ "x_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [128] } },
79
+ "w_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [128] } }
80
+ },
81
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 128, 54, 54] } },
82
+ "bench": {
83
+ "metrics": [
84
+ { "type": "gflops", "value": "2 * numel(shapes.y) * dim(shapes.w, 1) * dim(shapes.w, 2) * dim(shapes.w, 3)" }
85
+ ]
86
+ }
87
+ },
88
+ {
89
+ "name": "u8s8_pointwise_gemv_alignedN_n2048_c256_dp4a",
90
+ "preset": "smoke",
91
+ "inputs": {
92
+ "x": { "dtype": "uint8", "shape": [1, 256, 1, 1], "data": { "kind": "constant", "value": 127 } },
93
+ "w": { "dtype": "int8", "shape": [2048, 256, 1, 1], "data": { "kind": "constant", "value": -3 } },
94
+ "x_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [128] } },
95
+ "w_zero_point": { "dtype": "int8", "shape": [1], "data": { "kind": "values", "values": [0] } }
96
+ },
97
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 2048, 1, 1] } },
98
+ "bench": {
99
+ "metrics": [
100
+ { "type": "gflops", "value": "2 * numel(shapes.y) * dim(shapes.w, 1) * dim(shapes.w, 2) * dim(shapes.w, 3)" }
101
+ ]
102
+ },
103
+ "attrs": {}
104
+ },
105
+ {
106
+ "name": "u8s8_pointwise_gemv_unalignedN_n2050_c256_dp4a",
107
+ "preset": "smoke",
108
+ "inputs": {
109
+ "x": { "dtype": "uint8", "shape": [1, 256, 1, 1], "data": { "kind": "constant", "value": 127 } },
110
+ "w": { "dtype": "int8", "shape": [2050, 256, 1, 1], "data": { "kind": "constant", "value": -3 } },
111
+ "x_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [128] } },
112
+ "w_zero_point": { "dtype": "int8", "shape": [1], "data": { "kind": "values", "values": [0] } }
113
+ },
114
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 2050, 1, 1] } },
115
+ "bench": {
116
+ "metrics": [
117
+ { "type": "gflops", "value": "2 * numel(shapes.y) * dim(shapes.w, 1) * dim(shapes.w, 2) * dim(shapes.w, 3)" }
118
+ ]
119
+ },
120
+ "attrs": {}
121
+ },
122
+ {
123
+ "name": "u8s8_nchw_oc128_c64_3x3_32x32",
124
+ "inputs": {
125
+ "x": { "dtype": "uint8", "shape": [1, 64, 32, 32], "dist": "randint", "seed": 21, "min": 0, "max": 255 },
126
+ "w": { "dtype": "int8", "shape": [128, 64, 3, 3], "dist": "randint", "seed": 22, "min": -127, "max": 127 },
127
+ "x_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [128] } },
128
+ "w_zero_point": { "dtype": "int8", "shape": [1], "data": { "kind": "values", "values": [0] } }
129
+ },
130
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 128, 30, 30] } },
131
+ "bench": { "metrics": [{ "type": "gflops", "value": "2 * 128 * 30 * 30 * 64 * 3 * 3" }] },
132
+ "attrs": {}
133
+ },
134
+ {
135
+ "name": "s8s8_im2col_small_output_numel_scalar_fallback",
136
+ "preset": "stress",
137
+ "inputs": {
138
+ "x": { "dtype": "int8", "shape": [4, 64, 8, 8], "dist": "randint", "seed": 42, "min": -100, "max": 100 },
139
+ "w": { "dtype": "int8", "shape": [64, 64, 3, 3], "dist": "randint", "seed": 43, "min": -64, "max": 64 },
140
+ "x_zero_point": { "dtype": "int8", "shape": [1], "data": { "kind": "values", "values": [0] } },
141
+ "w_zero_point": { "dtype": "int8", "shape": [1], "data": { "kind": "values", "values": [0] } }
142
+ },
143
+ "outputs": { "y": { "dtype": "int32", "shape": [4, 64, 6, 6], "dist": "empty" } },
144
+ "bench": {
145
+ "metrics": [
146
+ { "type": "gflops", "value": "2 * numel(shapes.y) * dim(shapes.w, 1) * dim(shapes.w, 2) * dim(shapes.w, 3)" }
147
+ ]
148
+ },
149
+ "attrs": {}
150
+ },
151
+ {
152
+ "name": "u8s8_conv3d_dilated_depth_b1c16m32_16x32x32_k3",
153
+ "preset": "stress",
154
+ "attrs": { "strides": [1, 1, 1], "dilations": [2, 1, 1], "pads": [2, 1, 1, 2, 1, 1] },
155
+ "inputs": {
156
+ "x": { "dtype": "uint8", "shape": [1, 16, 16, 32, 32], "dist": "randint", "seed": 7601, "min": 0, "max": 255 },
157
+ "w": { "dtype": "int8", "shape": [32, 16, 3, 3, 3], "dist": "randint", "seed": 7602, "min": -127, "max": 127 },
158
+ "x_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [128] } },
159
+ "w_zero_point": { "dtype": "int8", "shape": [1], "data": { "kind": "values", "values": [0] } }
160
+ },
161
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 32, 16, 32, 32], "dist": "empty" } },
162
+ "bench": {
163
+ "metrics": [
164
+ {
165
+ "type": "gflops",
166
+ "value": "2 * numel(shapes.y) * dim(shapes.w, 1) * dim(shapes.w, 2) * dim(shapes.w, 3) * dim(shapes.w, 4)"
167
+ }
168
+ ]
169
+ }
170
+ }
171
+ ]
172
+ }
build/webgpu/conv-int-accumulate-spatial.wgsl.jinja ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% macro flat_index_2d(name="i", bound="params.count", guardInline=false, note="dispatch-limit") %}
2
+ {% if note == "dispatch-limit" %}
3
+ // 2D-folded flat index: gid.y carries the high bits past the
4
+ // maxComputeWorkgroupsPerDimension dispatch limit (outputs > 16.7M elements).
5
+ {% elif note == "limit" %}
6
+ // 2D-folded flat index: gid.y carries the high bits past the
7
+ // maxComputeWorkgroupsPerDimension limit.
8
+ {% elif note == "device-axis" %}
9
+ // The flat dispatch is folded across x/y at the device's per-axis workgroup
10
+ // limit; gid.y carries the high portion of the output index.
11
+ {% elif note == "vec4-limit" %}
12
+ // 2D-folded flat vec4 index: gid.y carries the high bits past the
13
+ // maxComputeWorkgroupsPerDimension limit (the dispatch caps x and spills into y).
14
+ {% elif note == "element-limit" %}
15
+ // 2D-folded flat element index: gid.y carries the high bits past the
16
+ // maxComputeWorkgroupsPerDimension limit.
17
+ {% elif note == "dispatch" %}
18
+ // 2D-folded flat index: gid.y carries the high bits past the
19
+ // maxComputeWorkgroupsPerDimension dispatch limit.
20
+ {% endif %}
21
+ {% if bound == "" %}
22
+ let {{ name }} = gid.x + gid.y * nwg.x * {{ tunables.WORKGROUP_SIZE }}u;
23
+ {%- elif guardInline %}
24
+ let {{ name }} = gid.x + gid.y * nwg.x * {{ tunables.WORKGROUP_SIZE }}u;
25
+ if ({{ name }} >= {{ bound }}) { return; }
26
+ {%- else %}
27
+ let {{ name }} = gid.x + gid.y * nwg.x * {{ tunables.WORKGROUP_SIZE }}u;
28
+ if ({{ name }} >= {{ bound }}) {
29
+ return;
30
+ }
31
+ {%- endif %}
32
+ {% endmacro %}
33
+
34
+ {% set depthIndent = " " if source.spatialRank == 3 else "" %}
35
+ {{ env.wgsl.resourceDeclarations }}
36
+
37
+ fn read_x(index: u32) -> i32 {
38
+ {% if xUnsigned %}
39
+ return i32(x[index]);
40
+ {% else %}
41
+ return x[index];
42
+ {% endif %}
43
+ }
44
+
45
+ fn read_w(index: u32) -> i32 {
46
+ {% if wUnsigned %}
47
+ return i32(w[index]);
48
+ {% else %}
49
+ return w[index];
50
+ {% endif %}
51
+ }
52
+
53
+ fn read_x_zero() -> i32 {
54
+ {% if source.xZeroOmitted is defined and source.xZeroOmitted %}
55
+ return 0;
56
+ {% elif xUnsigned %}
57
+ return i32(x_zero_point[0]);
58
+ {% else %}
59
+ return x_zero_point[0];
60
+ {% endif %}
61
+ }
62
+
63
+ // A per-output-channel weight zero point applies at every spatial rank.
64
+ fn read_w_zero({% if wZeroPerChannel %}oc: u32{% endif %}) -> i32 {
65
+ {% if source.wZeroOmitted is defined and source.wZeroOmitted %}
66
+ return 0;
67
+ {% elif wZeroPerChannel %}
68
+ {% if wUnsigned %}
69
+ return i32(w_zero_point[oc]);
70
+ {% else %}
71
+ return w_zero_point[oc];
72
+ {% endif %}
73
+ {% else %}
74
+ {% if wUnsigned %}
75
+ return i32(w_zero_point[0]);
76
+ {% else %}
77
+ return w_zero_point[0];
78
+ {% endif %}
79
+ {% endif %}
80
+ }
81
+
82
+ @compute @workgroup_size({{ tunables.WORKGROUP_SIZE }})
83
+ fn main(@builtin(global_invocation_id) gid: vec3<u32>, @builtin(num_workgroups) nwg: vec3<u32>) {
84
+ {{ flat_index_2d("index", guardInline=true) }}
85
+ let ow = index % params.outW;
86
+ var t = index / params.outW;
87
+ let oh = t % params.outH;
88
+ t = t / params.outH;
89
+ {% if source.spatialRank == 3 %}
90
+ let od = t % params.outD;
91
+ t = t / params.outD;
92
+ {% endif %}
93
+ let oc = t % params.outChannels;
94
+ let batch = t / params.outChannels;
95
+ let group = oc / params.outChannelsPerGroup;
96
+ let xzp = read_x_zero();
97
+ let wzp = read_w_zero({% if wZeroPerChannel %}oc{% endif %});
98
+ var acc = 0i;
99
+ for (var ic = 0u; ic < params.weightInChannels; ic = ic + 1u) {
100
+ let input_channel = group * params.inChannelsPerGroup + ic;
101
+ {% if source.spatialRank == 3 %}
102
+ for (var kd = 0u; kd < params.kernelD; kd = kd + 1u) {
103
+ let id = i32(od * params.strideD + kd * params.dilationD) - params.padD;
104
+ if (id < 0 || id >= i32(params.inD)) { continue; }
105
+ {% endif %}
106
+ {{ depthIndent }} for (var kh = 0u; kh < params.kernelH; kh = kh + 1u) {
107
+ {{ depthIndent }} let ih = i32(oh * params.strideH + kh * params.dilationH) - params.padH;
108
+ {{ depthIndent }} if (ih < 0 || ih >= i32(params.inH)) { continue; }
109
+ {{ depthIndent }} for (var kw = 0u; kw < params.kernelW; kw = kw + 1u) {
110
+ {{ depthIndent }} let iw = i32(ow * params.strideW + kw * params.dilationW) - params.padW;
111
+ {{ depthIndent }} if (iw < 0 || iw >= i32(params.inW)) { continue; }
112
+ {% if source.spatialRank == 3 %}
113
+ {{ depthIndent }} let x_index = (((batch * params.inChannels + input_channel) * params.inD + u32(id)) * params.inH + u32(ih)) * params.inW + u32(iw);
114
+ {{ depthIndent }} let w_index = (((oc * params.weightInChannels + ic) * params.kernelD + kd) * params.kernelH + kh) * params.kernelW + kw;
115
+ {% else %}
116
+ {{ depthIndent }} let x_index = ((batch * params.inChannels + input_channel) * params.inH + u32(ih)) * params.inW + u32(iw);
117
+ {{ depthIndent }} let w_index = ((oc * params.weightInChannels + ic) * params.kernelH + kh) * params.kernelW + kw;
118
+ {% endif %}
119
+ {{ depthIndent }} acc = acc + (read_x(x_index) - xzp) * (read_w(w_index) - wzp);
120
+ {{ depthIndent }} }
121
+ {{ depthIndent }} }
122
+ {% if source.spatialRank == 3 %}
123
+ }
124
+ {% endif %}
125
+ }
126
+ y[index] = acc;
127
+ }
build/webgpu/conv-int-im2col-spatial.wgsl.jinja ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Widened-int8 im2col for convolution DP4A paths. The materialized K order is
2
+ * OIHW for 2D input and OIDHW for 3D input. Spatial padding is filled with the
3
+ * input zero point, so padded taps contribute exactly zero after centering.
4
+ * Adjacent x invocations cover adjacent output positions for coalesced writes.
5
+ * Optional extra K rows contain the raw input zero point to align the DP4A
6
+ * reduction. */
7
+ {{ env.wgsl.resourceDeclarations }}
8
+ {% if source.spatialRank == 3 %}
9
+
10
+ const KERNEL_D: u32 = {{ source.kernelD }}u;
11
+ {% endif %}
12
+ const KERNEL_H: u32 = {{ source.kernelH }}u;
13
+ const KERNEL_W: u32 = {{ source.kernelW }}u;
14
+ const KERNEL_HW: u32 = KERNEL_H * KERNEL_W;
15
+ {% if source.spatialRank == 3 %}
16
+ const KSIZE: u32 = KERNEL_D * KERNEL_HW;
17
+ const STRIDE_D: u32 = {{ source.strideD }}u;
18
+ const DILATION_D: u32 = {{ source.dilationD }}u;
19
+ const PAD_FRONT: i32 = {{ source.padFront }};
20
+ {% else %}
21
+ const KSIZE: u32 = KERNEL_HW;
22
+ {% endif %}
23
+ const STRIDE_H: u32 = {{ source.strideH }}u;
24
+ const STRIDE_W: u32 = {{ source.strideW }}u;
25
+ const DILATION_H: u32 = {{ source.dilationH }}u;
26
+ const DILATION_W: u32 = {{ source.dilationW }}u;
27
+ const PAD_TOP: i32 = {{ source.padTop }};
28
+ const PAD_LEFT: i32 = {{ source.padLeft }};
29
+
30
+ @compute @workgroup_size({{ tunables.WORKGROUP_SIZE }})
31
+ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
32
+ let pos = gid.x;
33
+ if (pos >= params.outCount) {
34
+ return;
35
+ }
36
+ let k = gid.y;
37
+ let batch = gid.z;
38
+ let ic = k / KSIZE;
39
+ let kq = k - ic * KSIZE;
40
+ {% if source.spatialRank == 3 %}
41
+ let kd = kq / KERNEL_HW;
42
+ let khw = kq - kd * KERNEL_HW;
43
+ let kh = khw / KERNEL_W;
44
+ let kw = khw - kh * KERNEL_W;
45
+ let outHW = params.outH * params.outW;
46
+ let od = pos / outHW;
47
+ let ohw = pos - od * outHW;
48
+ let oh = ohw / params.outW;
49
+ let ow = ohw - oh * params.outW;
50
+ let id = i32(od * STRIDE_D + kd * DILATION_D) - PAD_FRONT;
51
+ {% else %}
52
+ let kh = kq / KERNEL_W;
53
+ let kw = kq - kh * KERNEL_W;
54
+ let oh = pos / params.outW;
55
+ let ow = pos - oh * params.outW;
56
+ {% endif %}
57
+ let ih = i32(oh * STRIDE_H + kh * DILATION_H) - PAD_TOP;
58
+ let iw = i32(ow * STRIDE_W + kw * DILATION_W) - PAD_LEFT;
59
+ var value: {{ bScalar }} = x_zero_point[0];
60
+ {% if source.spatialRank == 3 %}
61
+ if (
62
+ id >= 0 && id < i32(params.inD)
63
+ && ih >= 0 && ih < i32(params.inH)
64
+ && iw >= 0 && iw < i32(params.inW)
65
+ ) {
66
+ value = x[
67
+ (((batch * params.inChannels + ic) * params.inD + u32(id)) * params.inH + u32(ih))
68
+ * params.inW + u32(iw)
69
+ ];
70
+ }
71
+ {% else %}
72
+ if (ih >= 0 && ih < i32(params.inH) && iw >= 0 && iw < i32(params.inW)) {
73
+ value = x[((batch * params.inChannels + ic) * params.inH + u32(ih)) * params.inW + u32(iw)];
74
+ }
75
+ {% endif %}
76
+ cols[(batch * params.kRows + k) * params.outCount + pos] = value;
77
+ }
build/webgpu/manifest.json ADDED
@@ -0,0 +1,1221 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "domain": "ai.onnx",
3
+ "name": "ConvInteger",
4
+ "sinceVersion": 10,
5
+ "description": "Performs integer convolution on quantized inputs `x` and filter `w`, each with an optional zero point, producing an `int32` output. Zero-point subtraction is applied before accumulation; the result must not overflow 32 bits during accumulation.",
6
+ "inputs": [
7
+ { "role": "x", "dtype": "TX", "description": "Input data tensor of shape `(N x C x D1 x ... x Dn)`." },
8
+ { "role": "w", "dtype": "TW", "description": "Convolution weight tensor of shape `(M x C/group x k1 x ... x kn)`." },
9
+ {
10
+ "role": "x_zero_point",
11
+ "dtype": "TX",
12
+ "description": "Optional scalar zero point for `x`; defaults to 0.",
13
+ "optional": true
14
+ },
15
+ {
16
+ "role": "w_zero_point",
17
+ "dtype": "TW",
18
+ "description": "Optional scalar or per-output-channel zero point for `w`; defaults to 0.",
19
+ "optional": true
20
+ }
21
+ ],
22
+ "outputs": [
23
+ {
24
+ "role": "y",
25
+ "dtype": "TY",
26
+ "description": "Output tensor containing `int32` convolution results.",
27
+ "rank": "ranks.x",
28
+ "shape": "[dim(shapes.x, 0), dim(shapes.w, 0), expectedOutputWidth] if ranks.x == 3 else ([dim(shapes.x, 0), dim(shapes.w, 0), expectedOutputHeight, expectedOutputWidth] if ranks.x == 4 else [dim(shapes.x, 0), dim(shapes.w, 0), expectedOutputDepth, expectedOutputHeight, expectedOutputWidth])"
29
+ }
30
+ ],
31
+ "attributes": { "auto_pad": "NOTSET", "group": 1 },
32
+ "attributeDescriptions": {
33
+ "auto_pad": "Automatic padding mode. `NOTSET` uses `pads`; `SAME_UPPER` and `SAME_LOWER` choose padding so each output spatial size is `ceil(input / stride)`; `VALID` uses no padding.",
34
+ "dilations": "Optional dilation factors, one positive integer per spatial axis. Omission means all ones.",
35
+ "group": "Number of groups that input and output channels are split into; defaults to 1.",
36
+ "kernel_shape": "Optional kernel shape, one positive integer per spatial axis. When present, it must match the spatial dimensions of the weight tensor; omission infers the shape from the weights.",
37
+ "pads": "Optional explicit padding in ONNX order `[begin_axis_0, ..., begin_axis_n, end_axis_0, ..., end_axis_n]`. Omission means all zeros; it cannot be combined with an automatic padding mode.",
38
+ "strides": "Optional stride factors, one positive integer per spatial axis. Omission means all ones."
39
+ },
40
+ "attributeConstraints": { "auto_pad": { "values": ["NOTSET", "SAME_UPPER", "SAME_LOWER", "VALID"] } },
41
+ "typeConstraints": { "TX": ["uint8", "int8"], "TW": ["uint8", "int8"], "TY": ["int32"] },
42
+ "args": {
43
+ "x": { "kind": "tensor", "semantic": "x", "role": "input" },
44
+ "w": { "kind": "tensor", "semantic": "w", "role": "input" },
45
+ "x_zero_point": { "kind": "tensor", "semantic": "x_zero_point", "role": "input", "required": false },
46
+ "w_zero_point": { "kind": "tensor", "semantic": "w_zero_point", "role": "input", "required": false },
47
+ "y": { "kind": "tensor", "semantic": "y", "role": "output" }
48
+ },
49
+ "tunables": { "WORKGROUP_SIZE": 256 },
50
+ "derive": {
51
+ "inputDepth": "dim(shapes.x, 2) if ranks.x == 5 else 1",
52
+ "inputHeight": "dim(shapes.x, 3) if ranks.x == 5 else (dim(shapes.x, 2) if ranks.x == 4 else 1)",
53
+ "inputWidth": "dim(shapes.x, ranks.x - 1) if ranks.x >= 3 else 1",
54
+ "outputDepth": "dim(shapes.y, 2) if ranks.y == 5 else 1",
55
+ "outputHeight": "dim(shapes.y, 3) if ranks.y == 5 else (dim(shapes.y, 2) if ranks.y == 4 else 1)",
56
+ "outputWidth": "dim(shapes.y, ranks.y - 1) if ranks.y >= 3 else 1",
57
+ "kernelDepth": "dim(shapes.w, 2) if ranks.w == 5 else 1",
58
+ "kernelHeight": "dim(shapes.w, 3) if ranks.w == 5 else (dim(shapes.w, 2) if ranks.w == 4 else 1)",
59
+ "kernelWidth": "dim(shapes.w, ranks.w - 1) if ranks.w >= 3 else 1",
60
+ "spatialRank": "ranks.w - 2",
61
+ "kernelShapeLengthOk": "not has(attrs, \"kernel_shape\") or (attrs.kernel_shape | length) == spatialRank",
62
+ "stridesLengthOk": "not has(attrs, \"strides\") or (attrs.strides | length) == spatialRank",
63
+ "dilationsLengthOk": "not has(attrs, \"dilations\") or (attrs.dilations | length) == spatialRank",
64
+ "padsLengthOk": "not has(attrs, \"pads\") or (attrs.pads | length) == 2 * spatialRank",
65
+ "kernelD": "attrs.kernel_shape[0] if kernelShapeLengthOk and has(attrs, \"kernel_shape\") and spatialRank == 3 else 1",
66
+ "kernelH": "attrs.kernel_shape[spatialRank - 2] if kernelShapeLengthOk and has(attrs, \"kernel_shape\") and spatialRank >= 2 else 1",
67
+ "kernelW": "attrs.kernel_shape[spatialRank - 1] if kernelShapeLengthOk and has(attrs, \"kernel_shape\") and spatialRank >= 1 else 1",
68
+ "strideD": "attrs.strides[0] if stridesLengthOk and has(attrs, \"strides\") and spatialRank == 3 else 1",
69
+ "strideH": "attrs.strides[spatialRank - 2] if stridesLengthOk and has(attrs, \"strides\") and spatialRank >= 2 else 1",
70
+ "strideW": "attrs.strides[spatialRank - 1] if stridesLengthOk and has(attrs, \"strides\") and spatialRank >= 1 else 1",
71
+ "dilationD": "attrs.dilations[0] if dilationsLengthOk and has(attrs, \"dilations\") and spatialRank == 3 else 1",
72
+ "dilationH": "attrs.dilations[spatialRank - 2] if dilationsLengthOk and has(attrs, \"dilations\") and spatialRank >= 2 else 1",
73
+ "dilationW": "attrs.dilations[spatialRank - 1] if dilationsLengthOk and has(attrs, \"dilations\") and spatialRank >= 1 else 1",
74
+ "padFront": "attrs.pads[0] if padsLengthOk and has(attrs, \"pads\") and spatialRank == 3 else 0",
75
+ "padTop": "attrs.pads[spatialRank - 2] if padsLengthOk and has(attrs, \"pads\") and spatialRank >= 2 else 0",
76
+ "padLeft": "attrs.pads[spatialRank - 1] if padsLengthOk and has(attrs, \"pads\") and spatialRank >= 1 else 0",
77
+ "padBack": "attrs.pads[spatialRank] if padsLengthOk and has(attrs, \"pads\") and spatialRank == 3 else 0",
78
+ "padBottom": "attrs.pads[2 * spatialRank - 2] if padsLengthOk and has(attrs, \"pads\") and spatialRank >= 2 else 0",
79
+ "padRight": "attrs.pads[2 * spatialRank - 1] if padsLengthOk and has(attrs, \"pads\") and spatialRank >= 1 else 0",
80
+ "autoPadSame": "attrs.auto_pad == \"SAME_UPPER\" or attrs.auto_pad == \"SAME_LOWER\"",
81
+ "autoPadValid": "attrs.auto_pad == \"VALID\"",
82
+ "samePadDepth": "max(0, (outputDepth - 1) * strideD + (kernelDepth - 1) * dilationD + 1 - inputDepth)",
83
+ "samePadHeight": "max(0, (outputHeight - 1) * strideH + (kernelHeight - 1) * dilationH + 1 - inputHeight)",
84
+ "samePadWidth": "max(0, (outputWidth - 1) * strideW + (kernelWidth - 1) * dilationW + 1 - inputWidth)",
85
+ "samePadFront": "floor(samePadDepth / 2) if attrs.auto_pad == \"SAME_UPPER\" else samePadDepth - floor(samePadDepth / 2)",
86
+ "samePadTop": "floor(samePadHeight / 2) if attrs.auto_pad == \"SAME_UPPER\" else samePadHeight - floor(samePadHeight / 2)",
87
+ "samePadLeft": "floor(samePadWidth / 2) if attrs.auto_pad == \"SAME_UPPER\" else samePadWidth - floor(samePadWidth / 2)",
88
+ "effectivePadFront": "samePadFront if autoPadSame else (0 if autoPadValid else padFront)",
89
+ "effectivePadTop": "samePadTop if autoPadSame else (0 if autoPadValid else padTop)",
90
+ "effectivePadLeft": "samePadLeft if autoPadSame else (0 if autoPadValid else padLeft)",
91
+ "expectedOutputDepth": "ceil(inputDepth / strideD) if autoPadSame else floor((inputDepth + (0 if autoPadValid else padFront + padBack) - ((kernelDepth - 1) * dilationD + 1)) / strideD) + 1",
92
+ "expectedOutputHeight": "ceil(inputHeight / strideH) if autoPadSame else floor((inputHeight + (0 if autoPadValid else padTop + padBottom) - ((kernelHeight - 1) * dilationH + 1)) / strideH) + 1",
93
+ "expectedOutputWidth": "ceil(inputWidth / strideW) if autoPadSame else floor((inputWidth + (0 if autoPadValid else padLeft + padRight) - ((kernelWidth - 1) * dilationW + 1)) / strideW) + 1",
94
+ "spatialAttributeLengthsOk": "kernelShapeLengthOk and stridesLengthOk and dilationsLengthOk and padsLengthOk",
95
+ "kernelShapeMatchesWeights": "not has(attrs, \"kernel_shape\") or (kernelW == kernelWidth and (spatialRank < 2 or kernelH == kernelHeight) and (spatialRank < 3 or kernelD == kernelDepth))",
96
+ "kernelExtentsOk": "kernelWidth >= 1 and (spatialRank < 2 or kernelHeight >= 1) and (spatialRank < 3 or kernelDepth >= 1)",
97
+ "stridesValuesOk": "not has(attrs, \"strides\") or (strideD >= 1 and floor(strideD) == strideD and strideH >= 1 and floor(strideH) == strideH and strideW >= 1 and floor(strideW) == strideW)",
98
+ "dilationsValuesOk": "not has(attrs, \"dilations\") or (dilationD >= 1 and floor(dilationD) == dilationD and dilationH >= 1 and floor(dilationH) == dilationH and dilationW >= 1 and floor(dilationW) == dilationW)",
99
+ "padsValuesOk": "padFront >= 0 and floor(padFront) == padFront and padTop >= 0 and floor(padTop) == padTop and padLeft >= 0 and floor(padLeft) == padLeft and padBack >= 0 and floor(padBack) == padBack and padBottom >= 0 and floor(padBottom) == padBottom and padRight >= 0 and floor(padRight) == padRight",
100
+ "explicitPadsOk": "attrs.auto_pad == \"NOTSET\" or not has(attrs, \"pads\")",
101
+ "spatialAttributesOk": "spatialRank >= 1 and spatialRank <= 3 and spatialAttributeLengthsOk and kernelShapeMatchesWeights and kernelExtentsOk and stridesValuesOk and dilationsValuesOk and padsValuesOk and explicitPadsOk",
102
+ "packedFeature": "device.wgslLanguageFeatures.has(\"packed_4x8_integer_dot_product\")",
103
+ "rank4TensorOk": "spatialAttributesOk and (ranks.x == 4 and ranks.w == 4 and ranks.y == 4)",
104
+ "rank5TensorOk": "spatialAttributesOk and (ranks.x == 5 and ranks.w == 5 and ranks.y == 5)",
105
+ "scalarXZeroOk": "ranks.x_zero_point == 0 or (ranks.x_zero_point == 1 and dim(shapes.x_zero_point, 0) == 1)",
106
+ "scalarWZeroOk": "ranks.w_zero_point == 0 or (ranks.w_zero_point == 1 and dim(shapes.w_zero_point, 0) == 1)",
107
+ "scalarXZeroRequiredOk": "present.x_zero_point and scalarXZeroOk",
108
+ "scalarWZeroRequiredOk": "present.w_zero_point and scalarWZeroOk",
109
+ "outputBatchChannelsOk": "dim(shapes.y, 0) == dim(shapes.x, 0) and dim(shapes.y, 1) == dim(shapes.w, 0)",
110
+ "ungroupedChannelsOk": "attrs.group == 1 and dim(shapes.w, 1) == dim(shapes.x, 1)",
111
+ "groupChannelsOk": "attrs.group >= 1 and dim(shapes.w, 1) * attrs.group == dim(shapes.x, 1) and dim(shapes.w, 0) % attrs.group == 0",
112
+ "output2dShapeOk": "dim(shapes.y, 2) == expectedOutputHeight and dim(shapes.y, 3) == expectedOutputWidth",
113
+ "output3dShapeOk": "dim(shapes.y, 2) == expectedOutputDepth and dim(shapes.y, 3) == expectedOutputHeight and dim(shapes.y, 4) == expectedOutputWidth",
114
+ "rank3TensorOk": "spatialAttributesOk and (ranks.x == 3 and ranks.w == 3 and ranks.y == 3)",
115
+ "nchwTensorOk": "rank4TensorOk or rank3TensorOk",
116
+ "output1dShapeOk": "dim(shapes.y, 2) == expectedOutputWidth",
117
+ "outputSpatialShapeOk": "output2dShapeOk if rank4TensorOk else output1dShapeOk",
118
+ "zeroPointsOmitted": "not present.x_zero_point and not present.w_zero_point"
119
+ },
120
+ "bindingSets": {
121
+ "nchw2d_accumulate": [
122
+ { "name": "x", "arg": "x", "semantic": "x", "buffer": { "type": "read-only-storage" }, "elementType": "$xScalar" },
123
+ { "name": "w", "arg": "w", "semantic": "w", "buffer": { "type": "read-only-storage" }, "elementType": "$wScalar" },
124
+ {
125
+ "name": "x_zero_point",
126
+ "arg": "x_zero_point",
127
+ "semantic": "x_zero_point",
128
+ "buffer": { "type": "read-only-storage" },
129
+ "elementType": "$xScalar",
130
+ "length": 1
131
+ },
132
+ {
133
+ "name": "w_zero_point",
134
+ "arg": "w_zero_point",
135
+ "semantic": "w_zero_point",
136
+ "buffer": { "type": "read-only-storage" },
137
+ "elementType": "$wScalar"
138
+ },
139
+ { "name": "y", "arg": "y", "semantic": "y", "buffer": { "type": "storage" }, "elementType": "i32" },
140
+ {
141
+ "name": "params",
142
+ "semantic": "kernel.params",
143
+ "buffer": { "type": "uniform" },
144
+ "struct": {
145
+ "name": "Params",
146
+ "fields": [
147
+ { "name": "inChannels", "type": "u32", "value": "dim(shapes.x, 1)" },
148
+ { "name": "inH", "type": "u32", "value": "inputHeight" },
149
+ { "name": "inW", "type": "u32", "value": "inputWidth" },
150
+ { "name": "outChannels", "type": "u32", "value": "dim(shapes.w, 0)" },
151
+ { "name": "weightInChannels", "type": "u32", "value": "dim(shapes.w, 1)" },
152
+ { "name": "inChannelsPerGroup", "type": "u32", "value": "dim(shapes.x, 1) / attrs.group" },
153
+ { "name": "outChannelsPerGroup", "type": "u32", "value": "dim(shapes.w, 0) / attrs.group" },
154
+ { "name": "kernelH", "type": "u32", "value": "kernelHeight" },
155
+ { "name": "kernelW", "type": "u32", "value": "kernelWidth" },
156
+ { "name": "outH", "type": "u32", "value": "outputHeight" },
157
+ { "name": "outW", "type": "u32", "value": "outputWidth" },
158
+ { "name": "strideH", "type": "u32", "value": "strideH" },
159
+ { "name": "strideW", "type": "u32", "value": "strideW" },
160
+ { "name": "dilationH", "type": "u32", "value": "dilationH" },
161
+ { "name": "dilationW", "type": "u32", "value": "dilationW" },
162
+ { "name": "padH", "type": "i32", "value": "effectivePadTop" },
163
+ { "name": "padW", "type": "i32", "value": "effectivePadLeft" },
164
+ { "name": "count", "type": "u32", "value": "numel(shapes.y)" }
165
+ ]
166
+ }
167
+ }
168
+ ],
169
+ "nchw2dAccumulateScalarWZero": [
170
+ { "name": "x", "arg": "x", "semantic": "x", "buffer": { "type": "read-only-storage" }, "elementType": "$xScalar" },
171
+ { "name": "w", "arg": "w", "semantic": "w", "buffer": { "type": "read-only-storage" }, "elementType": "$wScalar" },
172
+ {
173
+ "name": "x_zero_point",
174
+ "arg": "x_zero_point",
175
+ "semantic": "x_zero_point",
176
+ "buffer": { "type": "read-only-storage" },
177
+ "elementType": "$xScalar",
178
+ "length": 1
179
+ },
180
+ {
181
+ "name": "w_zero_point",
182
+ "arg": "w_zero_point",
183
+ "semantic": "w_zero_point",
184
+ "buffer": { "type": "read-only-storage" },
185
+ "elementType": "$wScalar",
186
+ "length": 1
187
+ },
188
+ { "name": "y", "arg": "y", "semantic": "y", "buffer": { "type": "storage" }, "elementType": "i32" },
189
+ {
190
+ "name": "params",
191
+ "semantic": "kernel.params",
192
+ "buffer": { "type": "uniform" },
193
+ "struct": {
194
+ "name": "Params",
195
+ "fields": [
196
+ { "name": "inChannels", "type": "u32", "value": "dim(shapes.x, 1)" },
197
+ { "name": "inH", "type": "u32", "value": "inputHeight" },
198
+ { "name": "inW", "type": "u32", "value": "inputWidth" },
199
+ { "name": "outChannels", "type": "u32", "value": "dim(shapes.w, 0)" },
200
+ { "name": "weightInChannels", "type": "u32", "value": "dim(shapes.w, 1)" },
201
+ { "name": "inChannelsPerGroup", "type": "u32", "value": "dim(shapes.x, 1) / attrs.group" },
202
+ { "name": "outChannelsPerGroup", "type": "u32", "value": "dim(shapes.w, 0) / attrs.group" },
203
+ { "name": "kernelH", "type": "u32", "value": "kernelHeight" },
204
+ { "name": "kernelW", "type": "u32", "value": "kernelWidth" },
205
+ { "name": "outH", "type": "u32", "value": "outputHeight" },
206
+ { "name": "outW", "type": "u32", "value": "outputWidth" },
207
+ { "name": "strideH", "type": "u32", "value": "strideH" },
208
+ { "name": "strideW", "type": "u32", "value": "strideW" },
209
+ { "name": "dilationH", "type": "u32", "value": "dilationH" },
210
+ { "name": "dilationW", "type": "u32", "value": "dilationW" },
211
+ { "name": "padH", "type": "i32", "value": "effectivePadTop" },
212
+ { "name": "padW", "type": "i32", "value": "effectivePadLeft" },
213
+ { "name": "count", "type": "u32", "value": "numel(shapes.y)" }
214
+ ]
215
+ }
216
+ }
217
+ ],
218
+ "im2colNcdhw": [
219
+ { "name": "x", "arg": "x", "semantic": "x", "buffer": { "type": "read-only-storage" }, "elementType": "$bScalar" },
220
+ {
221
+ "name": "x_zero_point",
222
+ "arg": "x_zero_point",
223
+ "semantic": "x_zero_point",
224
+ "buffer": { "type": "read-only-storage" },
225
+ "elementType": "$bScalar",
226
+ "length": 1
227
+ },
228
+ { "name": "cols", "semantic": "cols3d", "buffer": { "type": "storage" }, "elementType": "$bScalar" },
229
+ {
230
+ "name": "params",
231
+ "semantic": "kernel.params",
232
+ "buffer": { "type": "uniform" },
233
+ "struct": {
234
+ "name": "Params",
235
+ "fields": [
236
+ { "name": "outCount", "type": "u32", "value": "dim(shapes.y, 2) * dim(shapes.y, 3) * dim(shapes.y, 4)" },
237
+ { "name": "inChannels", "type": "u32", "value": "dim(shapes.x, 1)" },
238
+ { "name": "inD", "type": "u32", "value": "dim(shapes.x, 2)" },
239
+ { "name": "inH", "type": "u32", "value": "dim(shapes.x, 3)" },
240
+ { "name": "inW", "type": "u32", "value": "dim(shapes.x, 4)" },
241
+ {
242
+ "name": "kRows",
243
+ "type": "u32",
244
+ "value": "dim(shapes.w, 1) * dim(shapes.w, 2) * dim(shapes.w, 3) * dim(shapes.w, 4)"
245
+ },
246
+ { "name": "outH", "type": "u32", "value": "dim(shapes.y, 3)" },
247
+ { "name": "outW", "type": "u32", "value": "dim(shapes.y, 4)" }
248
+ ]
249
+ }
250
+ }
251
+ ],
252
+ "dp4aMain3d": [
253
+ { "name": "a", "arg": "w", "semantic": "w", "buffer": { "type": "read-only-storage" }, "elementType": "$aVec4" },
254
+ { "name": "b", "semantic": "cols3d", "buffer": { "type": "read-only-storage" }, "elementType": "$bScalar" },
255
+ {
256
+ "name": "a_zero_point",
257
+ "arg": "w_zero_point",
258
+ "semantic": "w_zero_point",
259
+ "buffer": { "type": "read-only-storage" },
260
+ "elementType": "$aScalar",
261
+ "length": 1
262
+ },
263
+ {
264
+ "name": "b_zero_point",
265
+ "arg": "x_zero_point",
266
+ "semantic": "x_zero_point",
267
+ "buffer": { "type": "read-only-storage" },
268
+ "elementType": "$bScalar",
269
+ "length": 1
270
+ },
271
+ { "name": "y", "arg": "y", "semantic": "y", "buffer": { "type": "storage" }, "elementType": "i32" },
272
+ {
273
+ "name": "params",
274
+ "semantic": "kernel.params",
275
+ "buffer": { "type": "uniform" },
276
+ "struct": {
277
+ "name": "Params",
278
+ "fields": [
279
+ { "name": "M", "type": "u32", "value": "dim(shapes.w, 0)" },
280
+ { "name": "N", "type": "u32", "value": "dim(shapes.y, 2) * dim(shapes.y, 3) * dim(shapes.y, 4)" },
281
+ {
282
+ "name": "K",
283
+ "type": "u32",
284
+ "value": "dim(shapes.w, 1) * dim(shapes.w, 2) * dim(shapes.w, 3) * dim(shapes.w, 4)"
285
+ },
286
+ { "name": "aBatchStride4", "type": "u32", "value": 0 },
287
+ {
288
+ "name": "bBatchStride",
289
+ "type": "u32",
290
+ "value": "dim(shapes.w, 1) * dim(shapes.w, 2) * dim(shapes.w, 3) * dim(shapes.w, 4) * dim(shapes.y, 2) * dim(shapes.y, 3) * dim(shapes.y, 4)"
291
+ },
292
+ {
293
+ "name": "yBatchStride",
294
+ "type": "u32",
295
+ "value": "dim(shapes.w, 0) * dim(shapes.y, 2) * dim(shapes.y, 3) * dim(shapes.y, 4)"
296
+ }
297
+ ]
298
+ }
299
+ }
300
+ ],
301
+ "im2colNchw": [
302
+ { "name": "x", "arg": "x", "semantic": "x", "buffer": { "type": "read-only-storage" }, "elementType": "$bScalar" },
303
+ {
304
+ "name": "x_zero_point",
305
+ "arg": "x_zero_point",
306
+ "semantic": "x_zero_point",
307
+ "buffer": { "type": "read-only-storage" },
308
+ "elementType": "$bScalar",
309
+ "length": 1
310
+ },
311
+ { "name": "cols", "semantic": "cols", "buffer": { "type": "storage" }, "elementType": "$bScalar" },
312
+ {
313
+ "name": "params",
314
+ "semantic": "kernel.params",
315
+ "buffer": { "type": "uniform" },
316
+ "struct": {
317
+ "name": "Params",
318
+ "fields": [
319
+ { "name": "outCount", "type": "u32", "value": "dim(shapes.y, 2) * dim(shapes.y, 3)" },
320
+ { "name": "inChannels", "type": "u32", "value": "dim(shapes.x, 1)" },
321
+ { "name": "inH", "type": "u32", "value": "dim(shapes.x, 2)" },
322
+ { "name": "inW", "type": "u32", "value": "dim(shapes.x, 3)" },
323
+ { "name": "kRows", "type": "u32", "value": "dim(shapes.w, 1) * dim(shapes.w, 2) * dim(shapes.w, 3)" },
324
+ { "name": "outW", "type": "u32", "value": "dim(shapes.y, 3)" }
325
+ ]
326
+ }
327
+ }
328
+ ],
329
+ "dp4aMain": [
330
+ { "name": "a", "arg": "w", "semantic": "w", "buffer": { "type": "read-only-storage" }, "elementType": "$aVec4" },
331
+ {
332
+ "name": "b",
333
+ "arg": "cols",
334
+ "semantic": "cols",
335
+ "buffer": { "type": "read-only-storage" },
336
+ "elementType": "$bScalar"
337
+ },
338
+ {
339
+ "name": "a_zero_point",
340
+ "arg": "w_zero_point",
341
+ "semantic": "w_zero_point",
342
+ "buffer": { "type": "read-only-storage" },
343
+ "elementType": "$aScalar",
344
+ "length": 1
345
+ },
346
+ {
347
+ "name": "b_zero_point",
348
+ "arg": "x_zero_point",
349
+ "semantic": "x_zero_point",
350
+ "buffer": { "type": "read-only-storage" },
351
+ "elementType": "$bScalar",
352
+ "length": 1
353
+ },
354
+ { "name": "y", "arg": "y", "semantic": "y", "buffer": { "type": "storage" }, "elementType": "i32" },
355
+ {
356
+ "name": "params",
357
+ "semantic": "kernel.params",
358
+ "buffer": { "type": "uniform" },
359
+ "struct": {
360
+ "name": "Params",
361
+ "fields": [
362
+ { "name": "M", "type": "u32", "value": "dim(shapes.w, 0)" },
363
+ { "name": "N", "type": "u32", "value": "dim(shapes.y, 2) * dim(shapes.y, 3)" },
364
+ { "name": "K", "type": "u32", "value": "dim(shapes.w, 1) * dim(shapes.w, 2) * dim(shapes.w, 3)" },
365
+ { "name": "aBatchStride4", "type": "u32", "value": 0 },
366
+ {
367
+ "name": "bBatchStride",
368
+ "type": "u32",
369
+ "value": "(dim(shapes.w, 1) * dim(shapes.w, 2) * dim(shapes.w, 3)) * (dim(shapes.y, 2) * dim(shapes.y, 3))"
370
+ },
371
+ { "name": "yBatchStride", "type": "u32", "value": "dim(shapes.w, 0) * dim(shapes.y, 2) * dim(shapes.y, 3)" }
372
+ ]
373
+ }
374
+ }
375
+ ],
376
+ "dp4aPointwiseTail": [
377
+ { "name": "a", "arg": "w", "semantic": "w", "buffer": { "type": "read-only-storage" }, "elementType": "$aScalar" },
378
+ { "name": "b", "arg": "x", "semantic": "x", "buffer": { "type": "read-only-storage" }, "elementType": "$bScalar" },
379
+ {
380
+ "name": "a_zero_point",
381
+ "arg": "w_zero_point",
382
+ "semantic": "w_zero_point",
383
+ "buffer": { "type": "read-only-storage" },
384
+ "elementType": "$aScalar",
385
+ "length": 1
386
+ },
387
+ {
388
+ "name": "b_zero_point",
389
+ "arg": "x_zero_point",
390
+ "semantic": "x_zero_point",
391
+ "buffer": { "type": "read-only-storage" },
392
+ "elementType": "$bScalar",
393
+ "length": 1
394
+ },
395
+ { "name": "y", "arg": "y", "semantic": "y", "buffer": { "type": "storage" }, "elementType": "i32" },
396
+ {
397
+ "name": "params",
398
+ "semantic": "kernel.params",
399
+ "buffer": { "type": "uniform" },
400
+ "struct": {
401
+ "name": "Params",
402
+ "fields": [
403
+ { "name": "M", "type": "u32", "value": "dim(shapes.w, 0)" },
404
+ { "name": "N", "type": "u32", "value": "dim(shapes.y, 2) * dim(shapes.y, 3)" },
405
+ { "name": "K", "type": "u32", "value": "dim(shapes.x, 1)" },
406
+ { "name": "aBatchStride4", "type": "u32", "value": 0 },
407
+ { "name": "bBatchStride", "type": "u32", "value": "dim(shapes.x, 1) * dim(shapes.x, 2) * dim(shapes.x, 3)" },
408
+ { "name": "yBatchStride", "type": "u32", "value": "dim(shapes.w, 0) * dim(shapes.y, 2) * dim(shapes.y, 3)" }
409
+ ]
410
+ }
411
+ }
412
+ ],
413
+ "dp4aPointwise": [
414
+ { "name": "a", "arg": "w", "semantic": "w", "buffer": { "type": "read-only-storage" }, "elementType": "$aVec4" },
415
+ { "name": "b", "arg": "x", "semantic": "x", "buffer": { "type": "read-only-storage" }, "elementType": "$bScalar" },
416
+ {
417
+ "name": "a_zero_point",
418
+ "arg": "w_zero_point",
419
+ "semantic": "w_zero_point",
420
+ "buffer": { "type": "read-only-storage" },
421
+ "elementType": "$aScalar",
422
+ "length": 1
423
+ },
424
+ {
425
+ "name": "b_zero_point",
426
+ "arg": "x_zero_point",
427
+ "semantic": "x_zero_point",
428
+ "buffer": { "type": "read-only-storage" },
429
+ "elementType": "$bScalar",
430
+ "length": 1
431
+ },
432
+ { "name": "y", "arg": "y", "semantic": "y", "buffer": { "type": "storage" }, "elementType": "i32" },
433
+ {
434
+ "name": "params",
435
+ "semantic": "kernel.params",
436
+ "buffer": { "type": "uniform" },
437
+ "struct": {
438
+ "name": "Params",
439
+ "fields": [
440
+ { "name": "M", "type": "u32", "value": "dim(shapes.w, 0)" },
441
+ { "name": "N", "type": "u32", "value": "dim(shapes.y, 2) * dim(shapes.y, 3)" },
442
+ { "name": "K", "type": "u32", "value": "dim(shapes.x, 1)" },
443
+ { "name": "aBatchStride4", "type": "u32", "value": 0 },
444
+ { "name": "bBatchStride", "type": "u32", "value": "dim(shapes.x, 1) * dim(shapes.x, 2) * dim(shapes.x, 3)" },
445
+ { "name": "yBatchStride", "type": "u32", "value": "dim(shapes.w, 0) * dim(shapes.y, 2) * dim(shapes.y, 3)" }
446
+ ]
447
+ }
448
+ }
449
+ ],
450
+ "ncdhw3dAccumulate": [
451
+ { "name": "x", "arg": "x", "semantic": "x", "buffer": { "type": "read-only-storage" }, "elementType": "$xScalar" },
452
+ { "name": "w", "arg": "w", "semantic": "w", "buffer": { "type": "read-only-storage" }, "elementType": "$wScalar" },
453
+ {
454
+ "name": "x_zero_point",
455
+ "arg": "x_zero_point",
456
+ "semantic": "x_zero_point",
457
+ "buffer": { "type": "read-only-storage" },
458
+ "elementType": "$xScalar",
459
+ "length": 1
460
+ },
461
+ {
462
+ "name": "w_zero_point",
463
+ "arg": "w_zero_point",
464
+ "semantic": "w_zero_point",
465
+ "buffer": { "type": "read-only-storage" },
466
+ "elementType": "$wScalar",
467
+ "length": 1
468
+ },
469
+ { "name": "y", "arg": "y", "semantic": "y", "buffer": { "type": "storage" }, "elementType": "i32" },
470
+ {
471
+ "name": "params",
472
+ "semantic": "kernel.params",
473
+ "buffer": { "type": "uniform" },
474
+ "struct": {
475
+ "name": "Params",
476
+ "fields": [
477
+ { "name": "inChannels", "type": "u32", "value": "dim(shapes.x, 1)" },
478
+ { "name": "inD", "type": "u32", "value": "dim(shapes.x, 2)" },
479
+ { "name": "inH", "type": "u32", "value": "dim(shapes.x, 3)" },
480
+ { "name": "inW", "type": "u32", "value": "dim(shapes.x, 4)" },
481
+ { "name": "outChannels", "type": "u32", "value": "dim(shapes.w, 0)" },
482
+ { "name": "weightInChannels", "type": "u32", "value": "dim(shapes.w, 1)" },
483
+ { "name": "inChannelsPerGroup", "type": "u32", "value": "dim(shapes.x, 1) / attrs.group" },
484
+ { "name": "outChannelsPerGroup", "type": "u32", "value": "dim(shapes.w, 0) / attrs.group" },
485
+ { "name": "kernelD", "type": "u32", "value": "dim(shapes.w, 2)" },
486
+ { "name": "kernelH", "type": "u32", "value": "dim(shapes.w, 3)" },
487
+ { "name": "kernelW", "type": "u32", "value": "dim(shapes.w, 4)" },
488
+ { "name": "outD", "type": "u32", "value": "dim(shapes.y, 2)" },
489
+ { "name": "outH", "type": "u32", "value": "dim(shapes.y, 3)" },
490
+ { "name": "outW", "type": "u32", "value": "dim(shapes.y, 4)" },
491
+ { "name": "strideD", "type": "u32", "value": "strideD" },
492
+ { "name": "strideH", "type": "u32", "value": "strideH" },
493
+ { "name": "strideW", "type": "u32", "value": "strideW" },
494
+ { "name": "dilationD", "type": "u32", "value": "dilationD" },
495
+ { "name": "dilationH", "type": "u32", "value": "dilationH" },
496
+ { "name": "dilationW", "type": "u32", "value": "dilationW" },
497
+ { "name": "padD", "type": "i32", "value": "effectivePadFront" },
498
+ { "name": "padH", "type": "i32", "value": "effectivePadTop" },
499
+ { "name": "padW", "type": "i32", "value": "effectivePadLeft" },
500
+ { "name": "count", "type": "u32", "value": "numel(shapes.y)" }
501
+ ]
502
+ }
503
+ }
504
+ ],
505
+ "nchwAccumulatePerChannelWZeroOnly": [
506
+ { "name": "x", "arg": "x", "semantic": "x", "buffer": { "type": "read-only-storage" }, "elementType": "$xScalar" },
507
+ { "name": "w", "arg": "w", "semantic": "w", "buffer": { "type": "read-only-storage" }, "elementType": "$wScalar" },
508
+ {
509
+ "name": "w_zero_point",
510
+ "arg": "w_zero_point",
511
+ "semantic": "w_zero_point",
512
+ "buffer": { "type": "read-only-storage" },
513
+ "elementType": "$wScalar"
514
+ },
515
+ { "name": "y", "arg": "y", "semantic": "y", "buffer": { "type": "storage" }, "elementType": "i32" },
516
+ {
517
+ "name": "params",
518
+ "semantic": "kernel.params",
519
+ "buffer": { "type": "uniform" },
520
+ "struct": {
521
+ "name": "Params",
522
+ "fields": [
523
+ { "name": "inChannels", "type": "u32", "value": "dim(shapes.x, 1)" },
524
+ { "name": "inH", "type": "u32", "value": "inputHeight" },
525
+ { "name": "inW", "type": "u32", "value": "inputWidth" },
526
+ { "name": "outChannels", "type": "u32", "value": "dim(shapes.w, 0)" },
527
+ { "name": "weightInChannels", "type": "u32", "value": "dim(shapes.w, 1)" },
528
+ { "name": "inChannelsPerGroup", "type": "u32", "value": "dim(shapes.x, 1) / attrs.group" },
529
+ { "name": "outChannelsPerGroup", "type": "u32", "value": "dim(shapes.w, 0) / attrs.group" },
530
+ { "name": "kernelH", "type": "u32", "value": "kernelHeight" },
531
+ { "name": "kernelW", "type": "u32", "value": "kernelWidth" },
532
+ { "name": "outH", "type": "u32", "value": "outputHeight" },
533
+ { "name": "outW", "type": "u32", "value": "outputWidth" },
534
+ { "name": "strideH", "type": "u32", "value": "strideH" },
535
+ { "name": "strideW", "type": "u32", "value": "strideW" },
536
+ { "name": "dilationH", "type": "u32", "value": "dilationH" },
537
+ { "name": "dilationW", "type": "u32", "value": "dilationW" },
538
+ { "name": "padH", "type": "i32", "value": "effectivePadTop" },
539
+ { "name": "padW", "type": "i32", "value": "effectivePadLeft" },
540
+ { "name": "count", "type": "u32", "value": "numel(shapes.y)" }
541
+ ]
542
+ }
543
+ }
544
+ ],
545
+ "nchwAccumulateXZeroOnly": [
546
+ { "name": "x", "arg": "x", "semantic": "x", "buffer": { "type": "read-only-storage" }, "elementType": "$xScalar" },
547
+ { "name": "w", "arg": "w", "semantic": "w", "buffer": { "type": "read-only-storage" }, "elementType": "$wScalar" },
548
+ {
549
+ "name": "x_zero_point",
550
+ "arg": "x_zero_point",
551
+ "semantic": "x_zero_point",
552
+ "buffer": { "type": "read-only-storage" },
553
+ "elementType": "$xScalar",
554
+ "length": 1
555
+ },
556
+ { "name": "y", "arg": "y", "semantic": "y", "buffer": { "type": "storage" }, "elementType": "i32" },
557
+ {
558
+ "name": "params",
559
+ "semantic": "kernel.params",
560
+ "buffer": { "type": "uniform" },
561
+ "struct": {
562
+ "name": "Params",
563
+ "fields": [
564
+ { "name": "inChannels", "type": "u32", "value": "dim(shapes.x, 1)" },
565
+ { "name": "inH", "type": "u32", "value": "inputHeight" },
566
+ { "name": "inW", "type": "u32", "value": "inputWidth" },
567
+ { "name": "outChannels", "type": "u32", "value": "dim(shapes.w, 0)" },
568
+ { "name": "weightInChannels", "type": "u32", "value": "dim(shapes.w, 1)" },
569
+ { "name": "inChannelsPerGroup", "type": "u32", "value": "dim(shapes.x, 1) / attrs.group" },
570
+ { "name": "outChannelsPerGroup", "type": "u32", "value": "dim(shapes.w, 0) / attrs.group" },
571
+ { "name": "kernelH", "type": "u32", "value": "kernelHeight" },
572
+ { "name": "kernelW", "type": "u32", "value": "kernelWidth" },
573
+ { "name": "outH", "type": "u32", "value": "outputHeight" },
574
+ { "name": "outW", "type": "u32", "value": "outputWidth" },
575
+ { "name": "strideH", "type": "u32", "value": "strideH" },
576
+ { "name": "strideW", "type": "u32", "value": "strideW" },
577
+ { "name": "dilationH", "type": "u32", "value": "dilationH" },
578
+ { "name": "dilationW", "type": "u32", "value": "dilationW" },
579
+ { "name": "padH", "type": "i32", "value": "effectivePadTop" },
580
+ { "name": "padW", "type": "i32", "value": "effectivePadLeft" },
581
+ { "name": "count", "type": "u32", "value": "numel(shapes.y)" }
582
+ ]
583
+ }
584
+ }
585
+ ],
586
+ "nchwAccumulateWZeroOnly": [
587
+ { "name": "x", "arg": "x", "semantic": "x", "buffer": { "type": "read-only-storage" }, "elementType": "$xScalar" },
588
+ { "name": "w", "arg": "w", "semantic": "w", "buffer": { "type": "read-only-storage" }, "elementType": "$wScalar" },
589
+ {
590
+ "name": "w_zero_point",
591
+ "arg": "w_zero_point",
592
+ "semantic": "w_zero_point",
593
+ "buffer": { "type": "read-only-storage" },
594
+ "elementType": "$wScalar",
595
+ "length": 1
596
+ },
597
+ { "name": "y", "arg": "y", "semantic": "y", "buffer": { "type": "storage" }, "elementType": "i32" },
598
+ {
599
+ "name": "params",
600
+ "semantic": "kernel.params",
601
+ "buffer": { "type": "uniform" },
602
+ "struct": {
603
+ "name": "Params",
604
+ "fields": [
605
+ { "name": "inChannels", "type": "u32", "value": "dim(shapes.x, 1)" },
606
+ { "name": "inH", "type": "u32", "value": "inputHeight" },
607
+ { "name": "inW", "type": "u32", "value": "inputWidth" },
608
+ { "name": "outChannels", "type": "u32", "value": "dim(shapes.w, 0)" },
609
+ { "name": "weightInChannels", "type": "u32", "value": "dim(shapes.w, 1)" },
610
+ { "name": "inChannelsPerGroup", "type": "u32", "value": "dim(shapes.x, 1) / attrs.group" },
611
+ { "name": "outChannelsPerGroup", "type": "u32", "value": "dim(shapes.w, 0) / attrs.group" },
612
+ { "name": "kernelH", "type": "u32", "value": "kernelHeight" },
613
+ { "name": "kernelW", "type": "u32", "value": "kernelWidth" },
614
+ { "name": "outH", "type": "u32", "value": "outputHeight" },
615
+ { "name": "outW", "type": "u32", "value": "outputWidth" },
616
+ { "name": "strideH", "type": "u32", "value": "strideH" },
617
+ { "name": "strideW", "type": "u32", "value": "strideW" },
618
+ { "name": "dilationH", "type": "u32", "value": "dilationH" },
619
+ { "name": "dilationW", "type": "u32", "value": "dilationW" },
620
+ { "name": "padH", "type": "i32", "value": "effectivePadTop" },
621
+ { "name": "padW", "type": "i32", "value": "effectivePadLeft" },
622
+ { "name": "count", "type": "u32", "value": "numel(shapes.y)" }
623
+ ]
624
+ }
625
+ }
626
+ ],
627
+ "nchwAccumulateNoZeroPoints": [
628
+ { "name": "x", "arg": "x", "semantic": "x", "buffer": { "type": "read-only-storage" }, "elementType": "$xScalar" },
629
+ { "name": "w", "arg": "w", "semantic": "w", "buffer": { "type": "read-only-storage" }, "elementType": "$wScalar" },
630
+ { "name": "y", "arg": "y", "semantic": "y", "buffer": { "type": "storage" }, "elementType": "i32" },
631
+ {
632
+ "name": "params",
633
+ "semantic": "kernel.params",
634
+ "buffer": { "type": "uniform" },
635
+ "struct": {
636
+ "name": "Params",
637
+ "fields": [
638
+ { "name": "inChannels", "type": "u32", "value": "dim(shapes.x, 1)" },
639
+ { "name": "inH", "type": "u32", "value": "inputHeight" },
640
+ { "name": "inW", "type": "u32", "value": "inputWidth" },
641
+ { "name": "outChannels", "type": "u32", "value": "dim(shapes.w, 0)" },
642
+ { "name": "weightInChannels", "type": "u32", "value": "dim(shapes.w, 1)" },
643
+ { "name": "inChannelsPerGroup", "type": "u32", "value": "dim(shapes.x, 1) / attrs.group" },
644
+ { "name": "outChannelsPerGroup", "type": "u32", "value": "dim(shapes.w, 0) / attrs.group" },
645
+ { "name": "kernelH", "type": "u32", "value": "kernelHeight" },
646
+ { "name": "kernelW", "type": "u32", "value": "kernelWidth" },
647
+ { "name": "outH", "type": "u32", "value": "outputHeight" },
648
+ { "name": "outW", "type": "u32", "value": "outputWidth" },
649
+ { "name": "strideH", "type": "u32", "value": "strideH" },
650
+ { "name": "strideW", "type": "u32", "value": "strideW" },
651
+ { "name": "dilationH", "type": "u32", "value": "dilationH" },
652
+ { "name": "dilationW", "type": "u32", "value": "dilationW" },
653
+ { "name": "padH", "type": "i32", "value": "effectivePadTop" },
654
+ { "name": "padW", "type": "i32", "value": "effectivePadLeft" },
655
+ { "name": "count", "type": "u32", "value": "numel(shapes.y)" }
656
+ ]
657
+ }
658
+ }
659
+ ],
660
+ "ncdhw3dAccumulateXZeroOnly": [
661
+ { "name": "x", "arg": "x", "semantic": "x", "buffer": { "type": "read-only-storage" }, "elementType": "$xScalar" },
662
+ { "name": "w", "arg": "w", "semantic": "w", "buffer": { "type": "read-only-storage" }, "elementType": "$wScalar" },
663
+ {
664
+ "name": "x_zero_point",
665
+ "arg": "x_zero_point",
666
+ "semantic": "x_zero_point",
667
+ "buffer": { "type": "read-only-storage" },
668
+ "elementType": "$xScalar",
669
+ "length": 1
670
+ },
671
+ { "name": "y", "arg": "y", "semantic": "y", "buffer": { "type": "storage" }, "elementType": "i32" },
672
+ {
673
+ "name": "params",
674
+ "semantic": "kernel.params",
675
+ "buffer": { "type": "uniform" },
676
+ "struct": {
677
+ "name": "Params",
678
+ "fields": [
679
+ { "name": "inChannels", "type": "u32", "value": "dim(shapes.x, 1)" },
680
+ { "name": "inD", "type": "u32", "value": "dim(shapes.x, 2)" },
681
+ { "name": "inH", "type": "u32", "value": "dim(shapes.x, 3)" },
682
+ { "name": "inW", "type": "u32", "value": "dim(shapes.x, 4)" },
683
+ { "name": "outChannels", "type": "u32", "value": "dim(shapes.w, 0)" },
684
+ { "name": "weightInChannels", "type": "u32", "value": "dim(shapes.w, 1)" },
685
+ { "name": "inChannelsPerGroup", "type": "u32", "value": "dim(shapes.x, 1) / attrs.group" },
686
+ { "name": "outChannelsPerGroup", "type": "u32", "value": "dim(shapes.w, 0) / attrs.group" },
687
+ { "name": "kernelD", "type": "u32", "value": "dim(shapes.w, 2)" },
688
+ { "name": "kernelH", "type": "u32", "value": "dim(shapes.w, 3)" },
689
+ { "name": "kernelW", "type": "u32", "value": "dim(shapes.w, 4)" },
690
+ { "name": "outD", "type": "u32", "value": "dim(shapes.y, 2)" },
691
+ { "name": "outH", "type": "u32", "value": "dim(shapes.y, 3)" },
692
+ { "name": "outW", "type": "u32", "value": "dim(shapes.y, 4)" },
693
+ { "name": "strideD", "type": "u32", "value": "strideD" },
694
+ { "name": "strideH", "type": "u32", "value": "strideH" },
695
+ { "name": "strideW", "type": "u32", "value": "strideW" },
696
+ { "name": "dilationD", "type": "u32", "value": "dilationD" },
697
+ { "name": "dilationH", "type": "u32", "value": "dilationH" },
698
+ { "name": "dilationW", "type": "u32", "value": "dilationW" },
699
+ { "name": "padD", "type": "i32", "value": "effectivePadFront" },
700
+ { "name": "padH", "type": "i32", "value": "effectivePadTop" },
701
+ { "name": "padW", "type": "i32", "value": "effectivePadLeft" },
702
+ { "name": "count", "type": "u32", "value": "numel(shapes.y)" }
703
+ ]
704
+ }
705
+ }
706
+ ],
707
+ "ncdhw3dAccumulateWZeroOnly": [
708
+ { "name": "x", "arg": "x", "semantic": "x", "buffer": { "type": "read-only-storage" }, "elementType": "$xScalar" },
709
+ { "name": "w", "arg": "w", "semantic": "w", "buffer": { "type": "read-only-storage" }, "elementType": "$wScalar" },
710
+ {
711
+ "name": "w_zero_point",
712
+ "arg": "w_zero_point",
713
+ "semantic": "w_zero_point",
714
+ "buffer": { "type": "read-only-storage" },
715
+ "elementType": "$wScalar",
716
+ "length": 1
717
+ },
718
+ { "name": "y", "arg": "y", "semantic": "y", "buffer": { "type": "storage" }, "elementType": "i32" },
719
+ {
720
+ "name": "params",
721
+ "semantic": "kernel.params",
722
+ "buffer": { "type": "uniform" },
723
+ "struct": {
724
+ "name": "Params",
725
+ "fields": [
726
+ { "name": "inChannels", "type": "u32", "value": "dim(shapes.x, 1)" },
727
+ { "name": "inD", "type": "u32", "value": "dim(shapes.x, 2)" },
728
+ { "name": "inH", "type": "u32", "value": "dim(shapes.x, 3)" },
729
+ { "name": "inW", "type": "u32", "value": "dim(shapes.x, 4)" },
730
+ { "name": "outChannels", "type": "u32", "value": "dim(shapes.w, 0)" },
731
+ { "name": "weightInChannels", "type": "u32", "value": "dim(shapes.w, 1)" },
732
+ { "name": "inChannelsPerGroup", "type": "u32", "value": "dim(shapes.x, 1) / attrs.group" },
733
+ { "name": "outChannelsPerGroup", "type": "u32", "value": "dim(shapes.w, 0) / attrs.group" },
734
+ { "name": "kernelD", "type": "u32", "value": "dim(shapes.w, 2)" },
735
+ { "name": "kernelH", "type": "u32", "value": "dim(shapes.w, 3)" },
736
+ { "name": "kernelW", "type": "u32", "value": "dim(shapes.w, 4)" },
737
+ { "name": "outD", "type": "u32", "value": "dim(shapes.y, 2)" },
738
+ { "name": "outH", "type": "u32", "value": "dim(shapes.y, 3)" },
739
+ { "name": "outW", "type": "u32", "value": "dim(shapes.y, 4)" },
740
+ { "name": "strideD", "type": "u32", "value": "strideD" },
741
+ { "name": "strideH", "type": "u32", "value": "strideH" },
742
+ { "name": "strideW", "type": "u32", "value": "strideW" },
743
+ { "name": "dilationD", "type": "u32", "value": "dilationD" },
744
+ { "name": "dilationH", "type": "u32", "value": "dilationH" },
745
+ { "name": "dilationW", "type": "u32", "value": "dilationW" },
746
+ { "name": "padD", "type": "i32", "value": "effectivePadFront" },
747
+ { "name": "padH", "type": "i32", "value": "effectivePadTop" },
748
+ { "name": "padW", "type": "i32", "value": "effectivePadLeft" },
749
+ { "name": "count", "type": "u32", "value": "numel(shapes.y)" }
750
+ ]
751
+ }
752
+ }
753
+ ],
754
+ "ncdhw3dAccumulateNoZeroPoints": [
755
+ { "name": "x", "arg": "x", "semantic": "x", "buffer": { "type": "read-only-storage" }, "elementType": "$xScalar" },
756
+ { "name": "w", "arg": "w", "semantic": "w", "buffer": { "type": "read-only-storage" }, "elementType": "$wScalar" },
757
+ { "name": "y", "arg": "y", "semantic": "y", "buffer": { "type": "storage" }, "elementType": "i32" },
758
+ {
759
+ "name": "params",
760
+ "semantic": "kernel.params",
761
+ "buffer": { "type": "uniform" },
762
+ "struct": {
763
+ "name": "Params",
764
+ "fields": [
765
+ { "name": "inChannels", "type": "u32", "value": "dim(shapes.x, 1)" },
766
+ { "name": "inD", "type": "u32", "value": "dim(shapes.x, 2)" },
767
+ { "name": "inH", "type": "u32", "value": "dim(shapes.x, 3)" },
768
+ { "name": "inW", "type": "u32", "value": "dim(shapes.x, 4)" },
769
+ { "name": "outChannels", "type": "u32", "value": "dim(shapes.w, 0)" },
770
+ { "name": "weightInChannels", "type": "u32", "value": "dim(shapes.w, 1)" },
771
+ { "name": "inChannelsPerGroup", "type": "u32", "value": "dim(shapes.x, 1) / attrs.group" },
772
+ { "name": "outChannelsPerGroup", "type": "u32", "value": "dim(shapes.w, 0) / attrs.group" },
773
+ { "name": "kernelD", "type": "u32", "value": "dim(shapes.w, 2)" },
774
+ { "name": "kernelH", "type": "u32", "value": "dim(shapes.w, 3)" },
775
+ { "name": "kernelW", "type": "u32", "value": "dim(shapes.w, 4)" },
776
+ { "name": "outD", "type": "u32", "value": "dim(shapes.y, 2)" },
777
+ { "name": "outH", "type": "u32", "value": "dim(shapes.y, 3)" },
778
+ { "name": "outW", "type": "u32", "value": "dim(shapes.y, 4)" },
779
+ { "name": "strideD", "type": "u32", "value": "strideD" },
780
+ { "name": "strideH", "type": "u32", "value": "strideH" },
781
+ { "name": "strideW", "type": "u32", "value": "strideW" },
782
+ { "name": "dilationD", "type": "u32", "value": "dilationD" },
783
+ { "name": "dilationH", "type": "u32", "value": "dilationH" },
784
+ { "name": "dilationW", "type": "u32", "value": "dilationW" },
785
+ { "name": "padD", "type": "i32", "value": "effectivePadFront" },
786
+ { "name": "padH", "type": "i32", "value": "effectivePadTop" },
787
+ { "name": "padW", "type": "i32", "value": "effectivePadLeft" },
788
+ { "name": "count", "type": "u32", "value": "numel(shapes.y)" }
789
+ ]
790
+ }
791
+ }
792
+ ]
793
+ },
794
+ "variants": [
795
+ {
796
+ "id": "dp4a_im2col_ncdhw3d_scalar_zero_points",
797
+ "priority": 20,
798
+ "when": ["packedFeature", "rank5TensorOk", "scalarXZeroRequiredOk", "scalarWZeroRequiredOk", "ungroupedChannelsOk", "dim(shapes.w, 1) * dim(shapes.w, 2) * dim(shapes.w, 3) * dim(shapes.w, 4) % 4 == 0", "dim(shapes.w, 1) * dim(shapes.w, 2) * dim(shapes.w, 3) * dim(shapes.w, 4) >= 32", "dim(shapes.w, 0) >= 8", "dim(shapes.y, 2) * dim(shapes.y, 3) * dim(shapes.y, 4) >= 256", "outputBatchChannelsOk", "output3dShapeOk", "dim(shapes.x, 0) * dim(shapes.w, 1) * dim(shapes.w, 2) * dim(shapes.w, 3) * dim(shapes.w, 4) * dim(shapes.y, 2) * dim(shapes.y, 3) * dim(shapes.y, 4) * 4 <= device.limits.maxStorageBufferBindingSize", "dim(shapes.w, 1) * dim(shapes.w, 2) * dim(shapes.w, 3) * dim(shapes.w, 4) <= device.limits.maxComputeWorkgroupsPerDimension", "ceilDiv(dim(shapes.y, 2) * dim(shapes.y, 3) * dim(shapes.y, 4), tunables.WORKGROUP_SIZE) <= device.limits.maxComputeWorkgroupsPerDimension", "ceilDiv(dim(shapes.y, 2) * dim(shapes.y, 3) * dim(shapes.y, 4), 64) <= device.limits.maxComputeWorkgroupsPerDimension", "ceilDiv(dim(shapes.w, 0), 8) <= device.limits.maxComputeWorkgroupsPerDimension", "dim(shapes.x, 0) <= device.limits.maxComputeWorkgroupsPerDimension"],
799
+ "constants": {
800
+ "aScalar": "\"u32\" if tensorDtypes.w == \"uint8\" else \"i32\"",
801
+ "bScalar": "\"u32\" if tensorDtypes.x == \"uint8\" else \"i32\"",
802
+ "aVec4": "\"vec4<u32>\" if tensorDtypes.w == \"uint8\" else \"vec4<i32>\"",
803
+ "aUnsigned": "tensorDtypes.w == \"uint8\"",
804
+ "bUnsigned": "tensorDtypes.x == \"uint8\"",
805
+ "hasAZero": true,
806
+ "hasBZero": true,
807
+ "aPacked": true,
808
+ "aZeroPerRow": false,
809
+ "bZeroPerColumn": false,
810
+ "requant": "\"none\"",
811
+ "scaleScalar": "\"f32\"",
812
+ "tileM": 8,
813
+ "tileN": 64,
814
+ "ktWords": 32,
815
+ "hasBias": false
816
+ },
817
+ "intermediates": [
818
+ {
819
+ "id": "cols3d",
820
+ "dtype": "int32",
821
+ "shape": "[dim(shapes.x, 0) * dim(shapes.w, 1) * dim(shapes.w, 2) * dim(shapes.w, 3) * dim(shapes.w, 4) * dim(shapes.y, 2) * dim(shapes.y, 3) * dim(shapes.y, 4)]"
822
+ }
823
+ ],
824
+ "passes": [
825
+ {
826
+ "id": "im2col",
827
+ "name": "ConvInteger.Im2Col3d",
828
+ "source": {
829
+ "shader": "conv-int-im2col-spatial.wgsl.jinja",
830
+ "inputs": {
831
+ "spatialRank": 3,
832
+ "kernelD": "dim(shapes.w, 2)",
833
+ "kernelH": "dim(shapes.w, 3)",
834
+ "kernelW": "dim(shapes.w, 4)",
835
+ "strideD": "strideD",
836
+ "strideH": "strideH",
837
+ "strideW": "strideW",
838
+ "dilationD": "dilationD",
839
+ "dilationH": "dilationH",
840
+ "dilationW": "dilationW",
841
+ "padFront": "effectivePadFront",
842
+ "padTop": "effectivePadTop",
843
+ "padLeft": "effectivePadLeft"
844
+ }
845
+ },
846
+ "bindings": "im2colNcdhw",
847
+ "dispatch": {
848
+ "x": "ceil(dim(shapes.y, 2) * dim(shapes.y, 3) * dim(shapes.y, 4) / tunables.WORKGROUP_SIZE)",
849
+ "y": "dim(shapes.w, 1) * dim(shapes.w, 2) * dim(shapes.w, 3) * dim(shapes.w, 4)",
850
+ "z": "dim(shapes.x, 0)"
851
+ }
852
+ },
853
+ {
854
+ "id": "main",
855
+ "name": "ConvInteger.Im2Col3dDp4a",
856
+ "shader": "quant-dp4a-matmul.wgsl.jinja",
857
+ "bindings": "dp4aMain3d",
858
+ "dispatch": {
859
+ "x": "ceil(dim(shapes.y, 2) * dim(shapes.y, 3) * dim(shapes.y, 4) / 64)",
860
+ "y": "ceil(dim(shapes.w, 0) / 8)",
861
+ "z": "dim(shapes.y, 0)"
862
+ }
863
+ }
864
+ ]
865
+ },
866
+ {
867
+ "id": "dp4a_im2col_nchw_scalar_zero_points",
868
+ "priority": 20,
869
+ "when": ["packedFeature", "rank4TensorOk", "scalarXZeroRequiredOk", "scalarWZeroRequiredOk", "ungroupedChannelsOk", "(dim(shapes.w, 2) > 1 or dim(shapes.w, 3) > 1)", "outputBatchChannelsOk", "dim(shapes.w, 1) * dim(shapes.w, 2) * dim(shapes.w, 3) % 4 == 0", "dim(shapes.w, 1) * dim(shapes.w, 2) * dim(shapes.w, 3) >= 64", "numel(shapes.y) >= 8192", "dim(shapes.y, 2) * dim(shapes.y, 3) <= 4194240", "dim(shapes.w, 0) <= 524280", "dim(shapes.y, 0) <= device.limits.maxComputeWorkgroupsPerDimension"],
870
+ "constants": {
871
+ "aScalar": "\"u32\" if tensorDtypes.w == \"uint8\" else \"i32\"",
872
+ "bScalar": "\"u32\" if tensorDtypes.x == \"uint8\" else \"i32\"",
873
+ "aVec4": "\"vec4<u32>\" if tensorDtypes.w == \"uint8\" else \"vec4<i32>\"",
874
+ "aUnsigned": "tensorDtypes.w == \"uint8\"",
875
+ "bUnsigned": "tensorDtypes.x == \"uint8\"",
876
+ "hasAZero": true,
877
+ "hasBZero": true,
878
+ "bZeroPerColumn": false,
879
+ "requant": "\"none\"",
880
+ "scaleScalar": "\"f32\"",
881
+ "tileM": 8,
882
+ "tileN": 64,
883
+ "ktWords": 32
884
+ },
885
+ "intermediates": [
886
+ {
887
+ "id": "cols",
888
+ "dtype": "int32",
889
+ "shape": "[dim(shapes.x, 0) * (dim(shapes.w, 1) * dim(shapes.w, 2) * dim(shapes.w, 3)) * (dim(shapes.y, 2) * dim(shapes.y, 3))]"
890
+ }
891
+ ],
892
+ "passes": [
893
+ {
894
+ "id": "im2col",
895
+ "name": "ConvInteger.Im2Col",
896
+ "source": {
897
+ "shader": "conv-int-im2col-spatial.wgsl.jinja",
898
+ "inputs": {
899
+ "spatialRank": 2,
900
+ "kernelH": "dim(shapes.w, 2)",
901
+ "kernelW": "dim(shapes.w, 3)",
902
+ "strideH": "strideH",
903
+ "strideW": "strideW",
904
+ "dilationH": "dilationH",
905
+ "dilationW": "dilationW",
906
+ "padTop": "effectivePadTop",
907
+ "padLeft": "effectivePadLeft"
908
+ }
909
+ },
910
+ "bindings": "im2colNchw",
911
+ "dispatch": {
912
+ "x": "ceil(dim(shapes.y, 2) * dim(shapes.y, 3) / tunables.WORKGROUP_SIZE)",
913
+ "y": "dim(shapes.w, 1) * dim(shapes.w, 2) * dim(shapes.w, 3)",
914
+ "z": "dim(shapes.x, 0)"
915
+ }
916
+ },
917
+ {
918
+ "id": "main",
919
+ "name": "ConvInteger.Im2ColDp4a",
920
+ "shader": "quant-dp4a-matmul.wgsl.jinja",
921
+ "bindings": "dp4aMain",
922
+ "dispatch": {
923
+ "x": "ceil(dim(shapes.y, 2) * dim(shapes.y, 3) / 64)",
924
+ "y": "ceil(dim(shapes.w, 0) / 8)",
925
+ "z": "dim(shapes.y, 0)"
926
+ }
927
+ }
928
+ ]
929
+ },
930
+ {
931
+ "id": "dp4a_pointwise_1x1_tail",
932
+ "priority": 21,
933
+ "when": ["packedFeature", "rank4TensorOk", "scalarXZeroRequiredOk", "scalarWZeroRequiredOk", "ungroupedChannelsOk", "dim(shapes.w, 2) == 1", "dim(shapes.w, 3) == 1", "strideH == 1", "strideW == 1", "padTop == 0 and padBottom == 0", "padLeft == 0 and padRight == 0", "outputBatchChannelsOk", "dim(shapes.y, 2) == dim(shapes.x, 2)", "dim(shapes.y, 3) == dim(shapes.x, 3)", "dim(shapes.x, 1) >= 32", "dim(shapes.x, 1) % 4 != 0", "dim(shapes.y, 2) * dim(shapes.y, 3) <= 4194240", "dim(shapes.w, 0) <= 524280", "dim(shapes.y, 0) <= device.limits.maxComputeWorkgroupsPerDimension"],
934
+ "constants": {
935
+ "aScalar": "\"u32\" if tensorDtypes.w == \"uint8\" else \"i32\"",
936
+ "bScalar": "\"u32\" if tensorDtypes.x == \"uint8\" else \"i32\"",
937
+ "aPacked": false,
938
+ "aUnsigned": "tensorDtypes.w == \"uint8\"",
939
+ "bUnsigned": "tensorDtypes.x == \"uint8\"",
940
+ "hasAZero": true,
941
+ "hasBZero": true,
942
+ "bZeroPerColumn": false,
943
+ "requant": "\"none\"",
944
+ "scaleScalar": "\"f32\"",
945
+ "tileM": 8,
946
+ "tileN": 64,
947
+ "ktWords": 32
948
+ },
949
+ "passes": [
950
+ {
951
+ "id": "main",
952
+ "name": "ConvInteger.Dp4aPointwiseTail",
953
+ "shader": "quant-dp4a-matmul.wgsl.jinja",
954
+ "bindings": "dp4aPointwiseTail",
955
+ "dispatch": {
956
+ "x": "ceil(dim(shapes.y, 2) * dim(shapes.y, 3) / 64)",
957
+ "y": "ceil(dim(shapes.w, 0) / 8)",
958
+ "z": "dim(shapes.y, 0)"
959
+ }
960
+ }
961
+ ]
962
+ },
963
+ {
964
+ "id": "dp4a_pointwise_1x1",
965
+ "priority": 20,
966
+ "when": ["packedFeature", "rank4TensorOk", "scalarXZeroRequiredOk", "scalarWZeroRequiredOk", "ungroupedChannelsOk", "dim(shapes.w, 2) == 1", "dim(shapes.w, 3) == 1", "strideH == 1", "strideW == 1", "padTop == 0 and padBottom == 0", "padLeft == 0 and padRight == 0", "outputBatchChannelsOk", "dim(shapes.y, 2) == dim(shapes.x, 2)", "dim(shapes.y, 3) == dim(shapes.x, 3)", "dim(shapes.x, 1) % 4 == 0", "dim(shapes.y, 2) * dim(shapes.y, 3) <= 4194240", "dim(shapes.w, 0) <= 524280", "dim(shapes.y, 0) <= device.limits.maxComputeWorkgroupsPerDimension"],
967
+ "constants": {
968
+ "aScalar": "\"u32\" if tensorDtypes.w == \"uint8\" else \"i32\"",
969
+ "bScalar": "\"u32\" if tensorDtypes.x == \"uint8\" else \"i32\"",
970
+ "aVec4": "\"vec4<u32>\" if tensorDtypes.w == \"uint8\" else \"vec4<i32>\"",
971
+ "aUnsigned": "tensorDtypes.w == \"uint8\"",
972
+ "bUnsigned": "tensorDtypes.x == \"uint8\"",
973
+ "hasAZero": true,
974
+ "hasBZero": true,
975
+ "bZeroPerColumn": false,
976
+ "requant": "\"none\"",
977
+ "scaleScalar": "\"f32\"",
978
+ "tileM": 8,
979
+ "tileN": 64,
980
+ "ktWords": 32
981
+ },
982
+ "passes": [
983
+ {
984
+ "id": "main",
985
+ "name": "ConvInteger.Dp4aPointwise",
986
+ "shader": "quant-dp4a-matmul.wgsl.jinja",
987
+ "bindings": "dp4aPointwise",
988
+ "dispatch": {
989
+ "x": "ceil(dim(shapes.y, 2) * dim(shapes.y, 3) / 64)",
990
+ "y": "ceil(dim(shapes.w, 0) / 8)",
991
+ "z": "dim(shapes.y, 0)"
992
+ }
993
+ }
994
+ ]
995
+ },
996
+ {
997
+ "id": "nchw2d_per_channel_zero_point",
998
+ "priority": 5,
999
+ "when": ["nchwTensorOk", "scalarXZeroRequiredOk", "ranks.w_zero_point == 1", "dim(shapes.w_zero_point, 0) == dim(shapes.w, 0)", "groupChannelsOk", "outputBatchChannelsOk", "outputSpatialShapeOk"],
1000
+ "constants": {
1001
+ "xScalar": "\"u32\" if tensorDtypes.x == \"uint8\" else \"i32\"",
1002
+ "wScalar": "\"u32\" if tensorDtypes.w == \"uint8\" else \"i32\"",
1003
+ "xUnsigned": "tensorDtypes.x == \"uint8\"",
1004
+ "wUnsigned": "tensorDtypes.w == \"uint8\"",
1005
+ "wZeroPerChannel": true
1006
+ },
1007
+ "passes": [
1008
+ {
1009
+ "id": "main",
1010
+ "name": "ConvIntegerPerChannel",
1011
+ "source": {
1012
+ "shader": "conv-int-accumulate-spatial.wgsl.jinja",
1013
+ "inputs": { "spatialRank": 2, "xZeroOmitted": "false", "wZeroOmitted": "false" }
1014
+ },
1015
+ "bindings": "nchw2d_accumulate",
1016
+ "dispatch": { "threads": "numel(shapes.y)", "workgroupSize": "tunables.WORKGROUP_SIZE" }
1017
+ }
1018
+ ]
1019
+ },
1020
+ {
1021
+ "id": "nchw2d_per_channel_w_zero_point_only",
1022
+ "priority": 5,
1023
+ "when": ["nchwTensorOk", "not present.x_zero_point", "present.w_zero_point", "ranks.w_zero_point == 1", "dim(shapes.w_zero_point, 0) == dim(shapes.w, 0)", "groupChannelsOk", "outputBatchChannelsOk", "outputSpatialShapeOk"],
1024
+ "constants": {
1025
+ "xScalar": "\"u32\" if tensorDtypes.x == \"uint8\" else \"i32\"",
1026
+ "wScalar": "\"u32\" if tensorDtypes.w == \"uint8\" else \"i32\"",
1027
+ "xUnsigned": "tensorDtypes.x == \"uint8\"",
1028
+ "wUnsigned": "tensorDtypes.w == \"uint8\"",
1029
+ "wZeroPerChannel": true
1030
+ },
1031
+ "passes": [
1032
+ {
1033
+ "id": "main",
1034
+ "name": "ConvIntegerPerChannel",
1035
+ "source": {
1036
+ "shader": "conv-int-accumulate-spatial.wgsl.jinja",
1037
+ "inputs": { "spatialRank": 2, "xZeroOmitted": "true", "wZeroOmitted": "false" }
1038
+ },
1039
+ "bindings": "nchwAccumulatePerChannelWZeroOnly",
1040
+ "dispatch": { "threads": "numel(shapes.y)", "workgroupSize": "tunables.WORKGROUP_SIZE" }
1041
+ }
1042
+ ]
1043
+ },
1044
+ {
1045
+ "id": "nchw2d_scalar_zero_points",
1046
+ "when": ["nchwTensorOk", "scalarXZeroRequiredOk", "scalarWZeroRequiredOk", "groupChannelsOk", "outputBatchChannelsOk", "outputSpatialShapeOk"],
1047
+ "constants": {
1048
+ "xScalar": "\"u32\" if tensorDtypes.x == \"uint8\" else \"i32\"",
1049
+ "wScalar": "\"u32\" if tensorDtypes.w == \"uint8\" else \"i32\"",
1050
+ "xUnsigned": "tensorDtypes.x == \"uint8\"",
1051
+ "wUnsigned": "tensorDtypes.w == \"uint8\""
1052
+ },
1053
+ "passes": [
1054
+ {
1055
+ "id": "main",
1056
+ "name": "ConvInteger",
1057
+ "source": {
1058
+ "shader": "conv-int-accumulate-spatial.wgsl.jinja",
1059
+ "inputs": { "spatialRank": 2, "xZeroOmitted": "false", "wZeroOmitted": "false" }
1060
+ },
1061
+ "bindings": "nchw2dAccumulateScalarWZero",
1062
+ "dispatch": { "threads": "numel(shapes.y)", "workgroupSize": "tunables.WORKGROUP_SIZE" }
1063
+ }
1064
+ ]
1065
+ },
1066
+ {
1067
+ "id": "nchw2d_x_zero_point_only",
1068
+ "when": ["nchwTensorOk", "present.x_zero_point", "not present.w_zero_point", "scalarXZeroRequiredOk", "groupChannelsOk", "outputBatchChannelsOk", "outputSpatialShapeOk"],
1069
+ "constants": {
1070
+ "xScalar": "\"u32\" if tensorDtypes.x == \"uint8\" else \"i32\"",
1071
+ "wScalar": "\"u32\" if tensorDtypes.w == \"uint8\" else \"i32\"",
1072
+ "xUnsigned": "tensorDtypes.x == \"uint8\"",
1073
+ "wUnsigned": "tensorDtypes.w == \"uint8\""
1074
+ },
1075
+ "passes": [
1076
+ {
1077
+ "id": "main",
1078
+ "name": "ConvInteger",
1079
+ "source": {
1080
+ "shader": "conv-int-accumulate-spatial.wgsl.jinja",
1081
+ "inputs": { "spatialRank": 2, "xZeroOmitted": "false", "wZeroOmitted": "true" }
1082
+ },
1083
+ "bindings": "nchwAccumulateXZeroOnly",
1084
+ "dispatch": { "threads": "numel(shapes.y)", "workgroupSize": "tunables.WORKGROUP_SIZE" }
1085
+ }
1086
+ ]
1087
+ },
1088
+ {
1089
+ "id": "nchw2d_w_zero_point_only",
1090
+ "when": ["nchwTensorOk", "not present.x_zero_point", "present.w_zero_point", "scalarWZeroRequiredOk", "groupChannelsOk", "outputBatchChannelsOk", "outputSpatialShapeOk"],
1091
+ "constants": {
1092
+ "xScalar": "\"u32\" if tensorDtypes.x == \"uint8\" else \"i32\"",
1093
+ "wScalar": "\"u32\" if tensorDtypes.w == \"uint8\" else \"i32\"",
1094
+ "xUnsigned": "tensorDtypes.x == \"uint8\"",
1095
+ "wUnsigned": "tensorDtypes.w == \"uint8\""
1096
+ },
1097
+ "passes": [
1098
+ {
1099
+ "id": "main",
1100
+ "name": "ConvInteger",
1101
+ "source": {
1102
+ "shader": "conv-int-accumulate-spatial.wgsl.jinja",
1103
+ "inputs": { "spatialRank": 2, "xZeroOmitted": "true", "wZeroOmitted": "false" }
1104
+ },
1105
+ "bindings": "nchwAccumulateWZeroOnly",
1106
+ "dispatch": { "threads": "numel(shapes.y)", "workgroupSize": "tunables.WORKGROUP_SIZE" }
1107
+ }
1108
+ ]
1109
+ },
1110
+ {
1111
+ "id": "ncdhw3d_scalar_zero_points",
1112
+ "when": ["rank5TensorOk", "present.x_zero_point", "present.w_zero_point", "scalarXZeroOk", "scalarWZeroOk", "groupChannelsOk", "outputBatchChannelsOk", "output3dShapeOk"],
1113
+ "constants": {
1114
+ "xScalar": "\"u32\" if tensorDtypes.x == \"uint8\" else \"i32\"",
1115
+ "wScalar": "\"u32\" if tensorDtypes.w == \"uint8\" else \"i32\"",
1116
+ "xUnsigned": "tensorDtypes.x == \"uint8\"",
1117
+ "wUnsigned": "tensorDtypes.w == \"uint8\""
1118
+ },
1119
+ "passes": [
1120
+ {
1121
+ "id": "main",
1122
+ "name": "ConvInteger3d",
1123
+ "source": {
1124
+ "shader": "conv-int-accumulate-spatial.wgsl.jinja",
1125
+ "inputs": { "spatialRank": 3, "xZeroOmitted": "false", "wZeroOmitted": "false" }
1126
+ },
1127
+ "bindings": "ncdhw3dAccumulate",
1128
+ "dispatch": { "threads": "numel(shapes.y)", "workgroupSize": "tunables.WORKGROUP_SIZE" }
1129
+ }
1130
+ ]
1131
+ },
1132
+ {
1133
+ "id": "ncdhw3d_x_zero_point_only",
1134
+ "when": ["rank5TensorOk", "present.x_zero_point", "not present.w_zero_point", "scalarXZeroOk", "groupChannelsOk", "outputBatchChannelsOk", "output3dShapeOk"],
1135
+ "constants": {
1136
+ "xScalar": "\"u32\" if tensorDtypes.x == \"uint8\" else \"i32\"",
1137
+ "wScalar": "\"u32\" if tensorDtypes.w == \"uint8\" else \"i32\"",
1138
+ "xUnsigned": "tensorDtypes.x == \"uint8\"",
1139
+ "wUnsigned": "tensorDtypes.w == \"uint8\""
1140
+ },
1141
+ "passes": [
1142
+ {
1143
+ "id": "main",
1144
+ "name": "ConvInteger3d",
1145
+ "source": {
1146
+ "shader": "conv-int-accumulate-spatial.wgsl.jinja",
1147
+ "inputs": { "spatialRank": 3, "xZeroOmitted": "false", "wZeroOmitted": "true" }
1148
+ },
1149
+ "bindings": "ncdhw3dAccumulateXZeroOnly",
1150
+ "dispatch": { "threads": "numel(shapes.y)", "workgroupSize": "tunables.WORKGROUP_SIZE" }
1151
+ }
1152
+ ]
1153
+ },
1154
+ {
1155
+ "id": "ncdhw3d_w_zero_point_only",
1156
+ "when": ["rank5TensorOk", "not present.x_zero_point", "present.w_zero_point", "scalarWZeroOk", "groupChannelsOk", "outputBatchChannelsOk", "output3dShapeOk"],
1157
+ "constants": {
1158
+ "xScalar": "\"u32\" if tensorDtypes.x == \"uint8\" else \"i32\"",
1159
+ "wScalar": "\"u32\" if tensorDtypes.w == \"uint8\" else \"i32\"",
1160
+ "xUnsigned": "tensorDtypes.x == \"uint8\"",
1161
+ "wUnsigned": "tensorDtypes.w == \"uint8\""
1162
+ },
1163
+ "passes": [
1164
+ {
1165
+ "id": "main",
1166
+ "name": "ConvInteger3d",
1167
+ "source": {
1168
+ "shader": "conv-int-accumulate-spatial.wgsl.jinja",
1169
+ "inputs": { "spatialRank": 3, "xZeroOmitted": "true", "wZeroOmitted": "false" }
1170
+ },
1171
+ "bindings": "ncdhw3dAccumulateWZeroOnly",
1172
+ "dispatch": { "threads": "numel(shapes.y)", "workgroupSize": "tunables.WORKGROUP_SIZE" }
1173
+ }
1174
+ ]
1175
+ },
1176
+ {
1177
+ "id": "ncdhw3d_implicit_zero_points",
1178
+ "when": ["rank5TensorOk", "not present.x_zero_point", "not present.w_zero_point", "groupChannelsOk", "outputBatchChannelsOk", "output3dShapeOk"],
1179
+ "constants": {
1180
+ "xScalar": "\"u32\" if tensorDtypes.x == \"uint8\" else \"i32\"",
1181
+ "wScalar": "\"u32\" if tensorDtypes.w == \"uint8\" else \"i32\"",
1182
+ "xUnsigned": "tensorDtypes.x == \"uint8\"",
1183
+ "wUnsigned": "tensorDtypes.w == \"uint8\""
1184
+ },
1185
+ "passes": [
1186
+ {
1187
+ "id": "main",
1188
+ "name": "ConvInteger3d",
1189
+ "source": {
1190
+ "shader": "conv-int-accumulate-spatial.wgsl.jinja",
1191
+ "inputs": { "spatialRank": 3, "xZeroOmitted": "true", "wZeroOmitted": "true" }
1192
+ },
1193
+ "bindings": "ncdhw3dAccumulateNoZeroPoints",
1194
+ "dispatch": { "threads": "numel(shapes.y)", "workgroupSize": "tunables.WORKGROUP_SIZE" }
1195
+ }
1196
+ ]
1197
+ },
1198
+ {
1199
+ "id": "nchw_implicit_zero_points",
1200
+ "when": ["nchwTensorOk", "zeroPointsOmitted", "groupChannelsOk", "outputBatchChannelsOk", "outputSpatialShapeOk"],
1201
+ "constants": {
1202
+ "xScalar": "\"u32\" if tensorDtypes.x == \"uint8\" else \"i32\"",
1203
+ "wScalar": "\"u32\" if tensorDtypes.w == \"uint8\" else \"i32\"",
1204
+ "xUnsigned": "tensorDtypes.x == \"uint8\"",
1205
+ "wUnsigned": "tensorDtypes.w == \"uint8\""
1206
+ },
1207
+ "passes": [
1208
+ {
1209
+ "id": "main",
1210
+ "name": "ConvInteger",
1211
+ "source": {
1212
+ "shader": "conv-int-accumulate-spatial.wgsl.jinja",
1213
+ "inputs": { "spatialRank": 2, "xZeroOmitted": "true", "wZeroOmitted": "true" }
1214
+ },
1215
+ "bindings": "nchwAccumulateNoZeroPoints",
1216
+ "dispatch": { "threads": "numel(shapes.y)", "workgroupSize": "tunables.WORKGROUP_SIZE" }
1217
+ }
1218
+ ]
1219
+ }
1220
+ ]
1221
+ }
build/webgpu/metadata.json ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "ai.onnx.ConvInteger",
3
+ "id": "_ai_onnx_convinteger_webgpu_ac7ae27",
4
+ "version": 1,
5
+ "license": "Apache-2.0",
6
+ "backend": { "type": "webgpu" },
7
+ "digest": {
8
+ "algorithm": "sha256",
9
+ "files": {
10
+ "bench.json": "FxmmRX4sXmysOymGqufcK/SEHqonPxx0mjgpdFtthw4=",
11
+ "conv-int-accumulate-spatial.wgsl.jinja": "n0fxsi3cnW+RmTawiPp6t8zgBzS/Sg+eKHARguziK7Q=",
12
+ "conv-int-im2col-spatial.wgsl.jinja": "yeNh5h+P9uP5JNa11SdeEd811/c9e6bJ1w/AqkzC0ck=",
13
+ "manifest.json": "GyuPs+3QC5Ok4y/pJ/R+ASsnICvEpfC6cbpOYA+Ppcs=",
14
+ "quant-dp4a-matmul.wgsl.jinja": "YO5g0dZL7JdLEzF04XK1cEtKp4P3i/IRnRUdFeuVsiw=",
15
+ "test.json": "5CyT/c0HcXkyJOl/Xem2F58Yi86+X6ZTltfq7ZUFBek="
16
+ }
17
+ },
18
+ "provenance": { "kernel": { "sha": "2e7068faf55e7f43df740015f6d1ee49391a41c5", "dirty": false } },
19
+ "webgpu": { "manifestSpec": "1.0", "specialized": true, "opPath": "ops/ai.onnx.ConvInteger" }
20
+ }
build/webgpu/quant-dp4a-matmul.wgsl.jinja ADDED
@@ -0,0 +1,336 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% if requant != "none" and scaleScalar == "f16" %}
2
+ enable f16;
3
+ {% endif %}
4
+ {{ env.wgsl.resourceDeclarations }}
5
+
6
+ const TILE_M: u32 = {{ tileM }}u;
7
+ const TILE_N: u32 = {{ tileN }}u;
8
+ const KT_WORDS: u32 = {{ ktWords }}u;
9
+ const A_TILE_WORDS: u32 = TILE_M * KT_WORDS;
10
+ {% set GEMV_UNROLL = gemvKUnroll if gemvKUnroll is defined else 4 %}
11
+ {% if tileM == 1 %}
12
+ const GEMV_K_UNROLL: u32 = {{ GEMV_UNROLL }}u;
13
+ {% endif %}
14
+
15
+ {% set needsASum = hasBZero or bUnsigned %}
16
+ {% set needsBSum = hasAZero or aUnsigned %}
17
+ var<workgroup> a_tile: array<u32, A_TILE_WORDS>;
18
+ {% if needsASum %}
19
+ var<workgroup> a_row_sum: array<atomic<i32>, TILE_M>;
20
+
21
+ {% endif %}
22
+ // Pack 4 widened A values into one u32 (byte 0 = lowest k).
23
+ fn pack_a(v: vec4<{{ aScalar }}>) -> u32 {
24
+ {% if aUnsigned %}
25
+ // u8 -> biased i8: (u - 128) two's-complement low byte == u ^ 0x80.
26
+ return ((v.x ^ 0x80u) & 0xFFu) | (((v.y ^ 0x80u) & 0xFFu) << 8u) | (((v.z ^ 0x80u) & 0xFFu) << 16u) | (((v.w ^ 0x80u) & 0xFFu) << 24u);
27
+ {% else %}
28
+ return (u32(v.x) & 0xFFu) | ((u32(v.y) & 0xFFu) << 8u) | ((u32(v.z) & 0xFFu) << 16u) | ((u32(v.w) & 0xFFu) << 24u);
29
+ {% endif %}
30
+ }
31
+ {% if needsASum %}
32
+
33
+ // Sum of the 4 bias-shifted A values of one packed word.
34
+ fn sum4_a(v: vec4<{{ aScalar }}>) -> i32 {
35
+ {% if aUnsigned %}
36
+ return i32(v.x + v.y + v.z + v.w) - 512;
37
+ {% else %}
38
+ return v.x + v.y + v.z + v.w;
39
+ {% endif %}
40
+ }
41
+
42
+ {% endif %}
43
+ fn pack_b(b0: {{ bScalar }}, b1: {{ bScalar }}, b2: {{ bScalar }}, b3: {{ bScalar }}) -> u32 {
44
+ {% if bUnsigned %}
45
+ return ((b0 ^ 0x80u) & 0xFFu) | (((b1 ^ 0x80u) & 0xFFu) << 8u) | (((b2 ^ 0x80u) & 0xFFu) << 16u) | (((b3 ^ 0x80u) & 0xFFu) << 24u);
46
+ {% else %}
47
+ return (u32(b0) & 0xFFu) | ((u32(b1) & 0xFFu) << 8u) | ((u32(b2) & 0xFFu) << 16u) | ((u32(b3) & 0xFFu) << 24u);
48
+ {% endif %}
49
+ }
50
+
51
+ // Centralize the signed packed-int8 dot expression so unrolled callers cannot
52
+ // collide in lowering-generated temporaries.
53
+ fn dot4_packed(a_word: u32, b_word: u32) -> i32 {
54
+ return dot4I8Packed(a_word, b_word);
55
+ }
56
+
57
+ {% if needsBSum %}
58
+
59
+ fn sum4_b(b0: {{ bScalar }}, b1: {{ bScalar }}, b2: {{ bScalar }}, b3: {{ bScalar }}) -> i32 {
60
+ {% if bUnsigned %}
61
+ return i32(b0 + b1 + b2 + b3) - 512;
62
+ {% else %}
63
+ return b0 + b1 + b2 + b3;
64
+ {% endif %}
65
+ }
66
+
67
+ {% endif %}
68
+ {% if hasAZero %}
69
+ fn read_a_zero({% if aZeroPerRow %}row: u32{% endif %}) -> i32 {
70
+ {% if aZeroPerRow %}
71
+ {% if aUnsigned %}
72
+ return i32(a_zero_point[row]);
73
+ {% else %}
74
+ return a_zero_point[row];
75
+ {% endif %}
76
+ {% else %}
77
+ {% if aUnsigned %}
78
+ return i32(a_zero_point[0]);
79
+ {% else %}
80
+ return a_zero_point[0];
81
+ {% endif %}
82
+ {% endif %}
83
+ }
84
+
85
+ {% endif %}
86
+ {% if hasBZero %}
87
+ fn read_b_zero({% if bZeroPerColumn %}col: u32{% endif %}) -> i32 {
88
+ {% if bZeroPerColumn %}
89
+ {% if bUnsigned %}
90
+ return i32(b_zero_point[col]);
91
+ {% else %}
92
+ return b_zero_point[col];
93
+ {% endif %}
94
+ {% else %}
95
+ {% if bUnsigned %}
96
+ return i32(b_zero_point[0]);
97
+ {% else %}
98
+ return b_zero_point[0];
99
+ {% endif %}
100
+ {% endif %}
101
+ }
102
+
103
+ {% endif %}
104
+ {% if requant != "none" %}
105
+ fn read_y_zero() -> i32 {
106
+ return y_zero_point[0];
107
+ }
108
+
109
+ {% endif %}
110
+ @compute @workgroup_size(TILE_N, 1, 1)
111
+ fn main(@builtin(workgroup_id) wg: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {
112
+ let batch = wg.z;
113
+ let a_base4 = batch * params.aBatchStride4;
114
+ let b_base = batch * params.bBatchStride;
115
+ let y_base = batch * params.yBatchStride;
116
+ let m_block = wg.y * TILE_M;
117
+ let n_block = wg.x * TILE_N;
118
+ let tid = lid.x;
119
+ let col = n_block + tid;
120
+ let n_valid = col < params.N;
121
+ {% if aPacked == false %}
122
+ // Tail variants keep the hot loop on complete words. Packing the one partial
123
+ // word afterward prevents its bounds checks from infecting every full-word load.
124
+ let k_words_total = params.K / 4u;
125
+ let tail_lanes = params.K - k_words_total * 4u;
126
+ {% else %}
127
+ let k_words_total = params.K / 4u;
128
+ {% endif %}
129
+
130
+ {% if needsASum %}
131
+ if (tid < TILE_M) {
132
+ atomicStore(&a_row_sum[tid], 0);
133
+ }
134
+ workgroupBarrier();
135
+
136
+ {% endif %}
137
+ {% if tileM == 1 %}
138
+ var r0: i32 = 0;
139
+ {% for u in range(1, GEMV_UNROLL) %}
140
+ var r0_{{ u }}: i32 = 0;
141
+ {% endfor %}
142
+ {% else %}
143
+ {% for m in range(tileM) %}
144
+ var r{{ m }}: i32 = 0;
145
+ {% endfor %}
146
+ {% endif %}
147
+ {% if needsBSum %}
148
+ var sum_b: i32 = 0;
149
+ {% if tileM == 1 %}
150
+ {% for u in range(1, GEMV_UNROLL) %}
151
+ var sum_b_{{ u }}: i32 = 0;
152
+ {% endfor %}
153
+ {% endif %}
154
+ {% endif %}
155
+
156
+ for (var kw0 = 0u; kw0 < k_words_total; kw0 = kw0 + KT_WORDS) {
157
+ let words = min(KT_WORDS, k_words_total - kw0);
158
+ // Cooperative vec4 load + pack of the A tile (TILE_M rows x `words` u32).
159
+ for (var i = tid; i < TILE_M * words; i = i + TILE_N) {
160
+ let mi = i / words;
161
+ let ki = i % words;
162
+ let src_m = m_block + mi;
163
+ var packed = 0u;
164
+ if (src_m < params.M) {
165
+ {% if aPacked == false %}
166
+ let k4 = (kw0 + ki) * 4u;
167
+ let a_row = a_base4 + src_m * params.K;
168
+ let v = vec4<{{ aScalar }}>(
169
+ a[a_row + k4],
170
+ a[a_row + k4 + 1u],
171
+ a[a_row + k4 + 2u],
172
+ a[a_row + k4 + 3u],
173
+ );
174
+ {% else %}
175
+ let v = a[a_base4 + src_m * k_words_total + kw0 + ki];
176
+ {% endif %}
177
+ packed = pack_a(v);
178
+ {% if needsASum %}
179
+ atomicAdd(&a_row_sum[mi], sum4_a(v));
180
+ {% endif %}
181
+ }
182
+ a_tile[mi * KT_WORDS + ki] = packed;
183
+ }
184
+ workgroupBarrier();
185
+
186
+ if (n_valid) {
187
+ {% if tileM == 1 %}
188
+ // M=1 has only one output accumulator, so a scalar K loop forms a long
189
+ // dependent DP4A chain. Interleave several words while preserving the
190
+ // coalesced mapping of neighboring threads to neighboring B columns.
191
+ let unrolled_words = words - words % GEMV_K_UNROLL;
192
+ for (var kk = 0u; kk < unrolled_words; kk += GEMV_K_UNROLL) {
193
+ {% for u in range(GEMV_UNROLL) %}
194
+ let k4_{{ u }} = (kw0 + kk + {{ u }}u) * 4u;
195
+ let b_row_{{ u }} = b_base + k4_{{ u }} * params.N + col;
196
+ let b0_{{ u }} = b[b_row_{{ u }}];
197
+ let b1_{{ u }} = b[b_row_{{ u }} + params.N];
198
+ let b2_{{ u }} = b[b_row_{{ u }} + 2u * params.N];
199
+ let b3_{{ u }} = b[b_row_{{ u }} + 3u * params.N];
200
+ {% if needsBSum %}
201
+ sum_b{{ "" if u == 0 else "_" ~ u }} += sum4_b(b0_{{ u }}, b1_{{ u }}, b2_{{ u }}, b3_{{ u }});
202
+ {% endif %}
203
+ let bp_{{ u }} = pack_b(b0_{{ u }}, b1_{{ u }}, b2_{{ u }}, b3_{{ u }});
204
+ r0{{ "" if u == 0 else "_" ~ u }} += dot4_packed(a_tile[kk + {{ u }}u], bp_{{ u }});
205
+ {% endfor %}
206
+ }
207
+ for (var kk = unrolled_words; kk < words; kk++) {
208
+ let k4 = (kw0 + kk) * 4u;
209
+ let b_row = b_base + k4 * params.N + col;
210
+ let b0 = b[b_row];
211
+ let b1 = b[b_row + params.N];
212
+ let b2 = b[b_row + 2u * params.N];
213
+ let b3 = b[b_row + 3u * params.N];
214
+ {% if needsBSum %}
215
+ sum_b += sum4_b(b0, b1, b2, b3);
216
+ {% endif %}
217
+ let bp = pack_b(b0, b1, b2, b3);
218
+ r0 += dot4_packed(a_tile[kk], bp);
219
+ }
220
+ {% else %}
221
+ for (var kk = 0u; kk < words; kk = kk + 1u) {
222
+ let k4 = (kw0 + kk) * 4u;
223
+ let b_row = b_base + k4 * params.N + col;
224
+ let b0 = b[b_row];
225
+ let b1 = b[b_row + params.N];
226
+ let b2 = b[b_row + 2u * params.N];
227
+ let b3 = b[b_row + 3u * params.N];
228
+ {% if needsBSum %}
229
+ sum_b = sum_b + sum4_b(b0, b1, b2, b3);
230
+ {% endif %}
231
+ let bp = pack_b(b0, b1, b2, b3);
232
+ {% for m in range(tileM) %}
233
+ r{{ m }} = r{{ m }} + dot4_packed(a_tile[{{ m }}u * KT_WORDS + kk], bp);
234
+ {% endfor %}
235
+ }
236
+ {% endif %}
237
+ }
238
+ workgroupBarrier();
239
+ }
240
+ {% if aPacked == false %}
241
+
242
+ // Exactly one uniform guarded word handles K % 4. Missing lanes use the raw
243
+ // bias-domain zero (128 for u8, 0 for i8), so their shifted values, sums, and
244
+ // dot-product contributions are all zero while params.K remains unpadded for
245
+ // the zero-point correction below.
246
+ if (tail_lanes != 0u) {
247
+ if (tid < TILE_M) {
248
+ let src_m = m_block + tid;
249
+ var packed = 0u;
250
+ if (src_m < params.M) {
251
+ let k4 = k_words_total * 4u;
252
+ let a_row = a_base4 + src_m * params.K;
253
+ let a0 = a[a_row + k4];
254
+ var a1: {{ aScalar }} = {{ "128u" if aUnsigned else "0" }};
255
+ var a2: {{ aScalar }} = {{ "128u" if aUnsigned else "0" }};
256
+ if (tail_lanes > 1u) { a1 = a[a_row + k4 + 1u]; }
257
+ if (tail_lanes > 2u) { a2 = a[a_row + k4 + 2u]; }
258
+ let a3: {{ aScalar }} = {{ "128u" if aUnsigned else "0" }};
259
+ let v = vec4<{{ aScalar }}>(a0, a1, a2, a3);
260
+ packed = pack_a(v);
261
+ {% if needsASum %}
262
+ atomicAdd(&a_row_sum[tid], sum4_a(v));
263
+ {% endif %}
264
+ }
265
+ a_tile[tid * KT_WORDS] = packed;
266
+ }
267
+ workgroupBarrier();
268
+
269
+ if (n_valid) {
270
+ let k4 = k_words_total * 4u;
271
+ let b_row = b_base + k4 * params.N + col;
272
+ let b0 = b[b_row];
273
+ var b1: {{ bScalar }} = {{ "128u" if bUnsigned else "0" }};
274
+ var b2: {{ bScalar }} = {{ "128u" if bUnsigned else "0" }};
275
+ if (tail_lanes > 1u) { b1 = b[b_row + params.N]; }
276
+ if (tail_lanes > 2u) { b2 = b[b_row + 2u * params.N]; }
277
+ let b3: {{ bScalar }} = {{ "128u" if bUnsigned else "0" }};
278
+ {% if needsBSum %}
279
+ sum_b = sum_b + sum4_b(b0, b1, b2, b3);
280
+ {% endif %}
281
+ let bp = pack_b(b0, b1, b2, b3);
282
+ {% for m in range(tileM) %}
283
+ r{{ m }} = r{{ m }} + dot4_packed(a_tile[{{ m }}u * KT_WORDS], bp);
284
+ {% endfor %}
285
+ }
286
+ workgroupBarrier();
287
+ }
288
+
289
+ {% endif %}
290
+ if (!n_valid) {
291
+ return;
292
+ }
293
+
294
+ // Fold bias + zero-point corrections (exact in modular i32 arithmetic).
295
+ let cb: i32 = {{ "128" if bUnsigned else "0" }}{% if hasBZero %} - read_b_zero({% if bZeroPerColumn %}col{% endif %}){% endif %};
296
+ {% if not aZeroPerRow %}
297
+ let ca: i32 = {{ "128" if aUnsigned else "0" }}{% if hasAZero %} - read_a_zero(){% endif %};
298
+ let kcc: i32 = i32(params.K) * ca * cb;
299
+ {% endif %}
300
+ {% if needsBSum and tileM == 1 %}
301
+ let sum_b_total = sum_b{% for u in range(1, GEMV_UNROLL) %} + sum_b_{{ u }}{% endfor %};
302
+ {% endif %}
303
+
304
+ {% for m in range(tileM) %}
305
+ {
306
+ let mr = m_block + {{ m }}u;
307
+ if (mr < params.M) {
308
+ {% if aZeroPerRow %}
309
+ let ca: i32 = {{ "128" if aUnsigned else "0" }} - read_a_zero(mr);
310
+ let kcc: i32 = i32(params.K) * ca * cb;
311
+ {% endif %}
312
+ var acc = r{{ m }}{% if tileM == 1 %}{% for u in range(1, GEMV_UNROLL) %} + r0_{{ u }}{% endfor %}{% endif %};
313
+ {% if needsASum %}
314
+ acc = acc + cb * atomicLoad(&a_row_sum[{{ m }}u]);
315
+ {% endif %}
316
+ {% if needsBSum %}
317
+ acc = acc + ca * {% if tileM == 1 %}sum_b_total{% else %}sum_b{% endif %};
318
+ {% endif %}
319
+ acc = acc + kcc;
320
+ {% if hasBias %}
321
+ acc = acc + bias[mr];
322
+ {% endif %}
323
+ {% if requant == "none" %}
324
+ y[y_base + mr * params.N + col] = acc;
325
+ {% else %}
326
+ let scaled = f32(acc) * f32(a_scale[0]) * f32(b_scale[{% if requant == "per_column" %}col{% elif requant == "per_row" %}mr{% else %}0u{% endif %}]) / f32(y_scale[0]);
327
+ // Clamp the rounded float into an i32-representable range before the cast
328
+ // so a huge-finite / Inf requantized value saturates (the final clamp pins
329
+ // it to [qMin,qMax]) instead of invoking undefined i32(huge_float).
330
+ let q = clamp(i32(clamp(round(scaled), -2.0e9, 2.0e9)) + read_y_zero(), {{ qMin }}, {{ qMax }});
331
+ y[y_base + mr * params.N + col] = q;
332
+ {% endif %}
333
+ }
334
+ }
335
+ {% endfor %}
336
+ }
build/webgpu/test.json ADDED
@@ -0,0 +1,1282 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "op": "ai.onnx.ConvInteger",
3
+ "fixtureArrays": {
4
+ "ort_stride_padding_input_x": [10, 11, 12, 13, 14, 15, 16, 20, 21, 22, 23, 24, 25, 26, 30, 31, 32, 33, 34, 35, 36, 40, 41, 42, 43, 44, 45, 46, 50, 51, 52, 53, 54, 55, 56, 60, 61, 62, 63, 64, 65, 66, 70, 71, 72, 73, 74, 75, 76],
5
+ "ort_with_group_2d_u8u8_input_x": [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28],
6
+ "ort_padded_3d_u8u8_output_y": [1, 3, 5, 3, 5, 12, 16, 9, 11, 24, 28, 15, 7, 15, 17, 9, 11, 24, 28, 15, 28, 60, 68, 36, 40, 84, 92, 48, 23, 48, 52, 27, 29, 60, 64, 33, 64, 132, 140, 72, 76, 156, 164, 84, 41, 84, 88, 45, 19, 39, 41, 21, 41, 84, 88, 45, 47, 96, 100, 51, 25, 51, 53, 27],
7
+ "dp4a_pointwise_u8s8_c8_batched_input_x": [0, 255, 128, 127, 56, 77, 3, 100, 200, 42, 5, 19, 64, 88, 33, 7, 125, 90, 211, 16],
8
+ "unaligned_kernel_small_numel_scalar_path_input_w": [11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30],
9
+ "same_upper_stride2_autopad_input_x": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
10
+ },
11
+ "cases": [
12
+ {
13
+ "name": "dispatch_cliff_nchw2d_scalar_1x1",
14
+ "attrs": { "kernel_shape": [1, 1], "strides": [1, 1] },
15
+ "inputs": {
16
+ "x": { "dtype": "uint8", "shape": [1, 1, 64, 64], "data": { "kind": "cycle", "values": [1, 2, 3, 4, 5] } },
17
+ "w": { "dtype": "uint8", "shape": [4096, 1, 1, 1], "data": { "kind": "cycle", "values": [2, 1, 3] } },
18
+ "x_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "constant", "value": 0 } },
19
+ "w_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "constant", "value": 0 } }
20
+ },
21
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 4096, 64, 64], "tolerance": 0 } }
22
+ },
23
+ {
24
+ "name": "uint8_padding",
25
+ "attrs": { "strides": [1, 1], "pads": [1, 1, 1, 1] },
26
+ "inputs": {
27
+ "x": {
28
+ "dtype": "uint8",
29
+ "shape": [1, 1, 3, 3],
30
+ "data": { "kind": "values", "values": [128, 129, 130, 131, 132, 133, 134, 135, 136] }
31
+ },
32
+ "w": { "dtype": "uint8", "shape": [1, 1, 2, 2], "data": { "kind": "values", "values": [127, 128, 129, 130] } },
33
+ "x_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [128] } },
34
+ "w_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [128] } }
35
+ },
36
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 1, 4, 4] } }
37
+ },
38
+ {
39
+ "name": "int8_grouped",
40
+ "attrs": { "group": 2 },
41
+ "inputs": {
42
+ "x": {
43
+ "dtype": "int8",
44
+ "shape": [1, 2, 3, 3],
45
+ "data": { "kind": "values", "values": [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15, 16, 17, 18] }
46
+ },
47
+ "w": {
48
+ "dtype": "int8",
49
+ "shape": [2, 1, 2, 2],
50
+ "data": { "kind": "values", "values": [1, 0, 0, 1, -1, 1, 1, -1] }
51
+ },
52
+ "x_zero_point": { "dtype": "int8", "shape": [1], "data": { "kind": "values", "values": [0] } },
53
+ "w_zero_point": { "dtype": "int8", "shape": [1], "data": { "kind": "values", "values": [0] } }
54
+ },
55
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 2, 2, 2] } }
56
+ },
57
+ {
58
+ "name": "ort_without_padding_u8u8",
59
+ "provenance": {
60
+ "source": "onnxruntime/test/providers/cpu/nn/conv_integer_test.cc",
61
+ "test": "ConvIntegerTest.WithoutPadding_2D_u8u8"
62
+ },
63
+ "inputs": {
64
+ "x": {
65
+ "dtype": "uint8",
66
+ "shape": [1, 1, 3, 3],
67
+ "data": { "kind": "values", "values": [2, 3, 4, 5, 6, 7, 8, 9, 10] }
68
+ },
69
+ "w": { "dtype": "uint8", "shape": [1, 1, 2, 2], "data": { "kind": "values", "values": [2, 2, 2, 2] } },
70
+ "x_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [1] } },
71
+ "w_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [1] } }
72
+ },
73
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 1, 2, 2], "tolerance": 0 } },
74
+ "attrs": {}
75
+ },
76
+ {
77
+ "name": "ort_with_padding_u8u8",
78
+ "provenance": {
79
+ "source": "onnxruntime/test/providers/cpu/nn/conv_integer_test.cc",
80
+ "test": "ConvIntegerTest.WithPadding_2D_u8u8"
81
+ },
82
+ "attrs": { "pads": [1, 1, 1, 1] },
83
+ "inputs": {
84
+ "x": {
85
+ "dtype": "uint8",
86
+ "shape": [1, 1, 3, 3],
87
+ "data": { "kind": "values", "values": [2, 3, 4, 5, 6, 7, 8, 9, 10] }
88
+ },
89
+ "w": { "dtype": "uint8", "shape": [1, 1, 2, 2], "data": { "kind": "values", "values": [2, 2, 2, 2] } },
90
+ "x_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [1] } },
91
+ "w_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [1] } }
92
+ },
93
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 1, 4, 4], "tolerance": 0 } }
94
+ },
95
+ {
96
+ "name": "ort_pointwise_u8u8",
97
+ "provenance": {
98
+ "source": "onnxruntime/test/providers/cpu/nn/conv_integer_test.cc",
99
+ "test": "ConvIntegerTest.Pointwise_2D_u8u8"
100
+ },
101
+ "inputs": {
102
+ "x": {
103
+ "dtype": "uint8",
104
+ "shape": [1, 1, 3, 3],
105
+ "data": { "kind": "values", "values": [2, 3, 4, 5, 6, 7, 8, 9, 10] }
106
+ },
107
+ "w": { "dtype": "uint8", "shape": [1, 1, 1, 1], "data": { "kind": "values", "values": [5] } },
108
+ "x_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [1] } },
109
+ "w_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [1] } }
110
+ },
111
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 1, 3, 3], "tolerance": 0 } },
112
+ "attrs": {}
113
+ },
114
+ {
115
+ "name": "ort_without_padding_u8s8",
116
+ "provenance": {
117
+ "source": "onnxruntime/test/providers/cpu/nn/conv_integer_test.cc",
118
+ "test": "ConvIntegerTest.WithoutPadding_2D_u8s8"
119
+ },
120
+ "inputs": {
121
+ "x": {
122
+ "dtype": "uint8",
123
+ "shape": [1, 1, 3, 3],
124
+ "data": { "kind": "values", "values": [2, 3, 4, 5, 6, 7, 8, 9, 10] }
125
+ },
126
+ "w": { "dtype": "int8", "shape": [1, 1, 2, 2], "data": { "kind": "values", "values": [-9, -9, -9, -9] } },
127
+ "x_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [1] } },
128
+ "w_zero_point": { "dtype": "int8", "shape": [1], "data": { "kind": "values", "values": [-10] } }
129
+ },
130
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 1, 2, 2], "tolerance": 0 } },
131
+ "attrs": {}
132
+ },
133
+ {
134
+ "name": "ort_with_padding_u8s8",
135
+ "provenance": {
136
+ "source": "onnxruntime/test/providers/cpu/nn/conv_integer_test.cc",
137
+ "test": "ConvIntegerTest.WithPadding_2D_u8s8"
138
+ },
139
+ "attrs": { "pads": [1, 1, 1, 1] },
140
+ "inputs": {
141
+ "x": {
142
+ "dtype": "uint8",
143
+ "shape": [1, 1, 3, 3],
144
+ "data": { "kind": "values", "values": [2, 3, 4, 5, 6, 7, 8, 9, 10] }
145
+ },
146
+ "w": { "dtype": "int8", "shape": [1, 1, 2, 2], "data": { "kind": "values", "values": [-9, -9, -9, -9] } },
147
+ "x_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [1] } },
148
+ "w_zero_point": { "dtype": "int8", "shape": [1], "data": { "kind": "values", "values": [-10] } }
149
+ },
150
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 1, 4, 4], "tolerance": 0 } }
151
+ },
152
+ {
153
+ "name": "ort_without_padding_s8s8",
154
+ "provenance": {
155
+ "source": "onnxruntime/test/providers/cpu/nn/conv_integer_test.cc",
156
+ "test": "ConvIntegerTest.WithoutPadding_2D_s8s8"
157
+ },
158
+ "inputs": {
159
+ "x": {
160
+ "dtype": "int8",
161
+ "shape": [1, 1, 3, 3],
162
+ "data": { "kind": "values", "values": [-1, 2, -3, 4, -5, 6, -7, 8, -9] }
163
+ },
164
+ "w": { "dtype": "int8", "shape": [1, 1, 2, 2], "data": { "kind": "values", "values": [1, -2, 3, -4] } },
165
+ "x_zero_point": { "dtype": "int8", "shape": [1], "data": { "kind": "values", "values": [0] } },
166
+ "w_zero_point": { "dtype": "int8", "shape": [1], "data": { "kind": "values", "values": [0] } }
167
+ },
168
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 1, 2, 2], "tolerance": 0 } },
169
+ "attrs": {}
170
+ },
171
+ {
172
+ "name": "ort_without_padding_s8u8",
173
+ "provenance": {
174
+ "source": "onnxruntime/test/providers/cpu/nn/conv_integer_test.cc",
175
+ "test": "ConvIntegerTest.WithoutPadding_2D_s8u8"
176
+ },
177
+ "inputs": {
178
+ "x": {
179
+ "dtype": "int8",
180
+ "shape": [1, 1, 3, 3],
181
+ "data": { "kind": "values", "values": [-1, 2, -3, 4, -5, 6, -7, 8, -9] }
182
+ },
183
+ "w": { "dtype": "uint8", "shape": [1, 1, 2, 2], "data": { "kind": "values", "values": [1, 2, 3, 4] } },
184
+ "x_zero_point": { "dtype": "int8", "shape": [1], "data": { "kind": "values", "values": [0] } },
185
+ "w_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [0] } }
186
+ },
187
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 1, 2, 2], "tolerance": 0 } },
188
+ "attrs": {}
189
+ },
190
+ {
191
+ "name": "ort_with_padding_s8u8",
192
+ "provenance": {
193
+ "source": "onnxruntime/test/providers/cpu/nn/conv_integer_test.cc",
194
+ "test": "ConvIntegerTest.WithPadding_2D_s8u8"
195
+ },
196
+ "attrs": { "pads": [1, 1, 1, 1] },
197
+ "inputs": {
198
+ "x": {
199
+ "dtype": "int8",
200
+ "shape": [1, 1, 3, 3],
201
+ "data": { "kind": "values", "values": [-1, 2, -3, 4, -5, 6, -7, 8, -9] }
202
+ },
203
+ "w": { "dtype": "uint8", "shape": [1, 1, 2, 2], "data": { "kind": "values", "values": [1, 2, 3, 4] } },
204
+ "x_zero_point": { "dtype": "int8", "shape": [1], "data": { "kind": "values", "values": [0] } },
205
+ "w_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [0] } }
206
+ },
207
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 1, 4, 4], "tolerance": 0 } }
208
+ },
209
+ {
210
+ "name": "ort_stride2_padding_u8u8",
211
+ "provenance": {
212
+ "source": "onnxruntime/test/providers/cpu/nn/conv_integer_test.cc",
213
+ "test": "ConvIntegerTest.WithStride2_2D_u8u8"
214
+ },
215
+ "attrs": { "strides": [2, 2], "pads": [1, 1, 1, 1] },
216
+ "inputs": {
217
+ "x": {
218
+ "dtype": "uint8",
219
+ "shape": [1, 1, 7, 7],
220
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/ort_stride_padding_input_x" } }
221
+ },
222
+ "w": {
223
+ "dtype": "uint8",
224
+ "shape": [1, 1, 3, 3],
225
+ "data": { "kind": "values", "values": [11, 12, 11, 12, 13, 12, 11, 12, 11] }
226
+ },
227
+ "x_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [10] } },
228
+ "w_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [10] } }
229
+ },
230
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 1, 4, 4], "tolerance": 0 } }
231
+ },
232
+ {
233
+ "name": "ort_with_group_2d_u8u8",
234
+ "provenance": {
235
+ "source": "onnxruntime/test/providers/cpu/nn/conv_integer_test.cc",
236
+ "test": "ConvIntegerTest.WithGroup_2D_u8u8"
237
+ },
238
+ "attrs": { "group": 3, "pads": [1, 1, 1, 1] },
239
+ "inputs": {
240
+ "x": {
241
+ "dtype": "uint8",
242
+ "shape": [1, 3, 3, 3],
243
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/ort_with_group_2d_u8u8_input_x" } }
244
+ },
245
+ "w": {
246
+ "dtype": "uint8",
247
+ "shape": [3, 1, 2, 2],
248
+ "data": { "kind": "values", "values": [11, 12, 12, 11, 13, 14, 14, 13, 15, 16, 16, 15] }
249
+ },
250
+ "x_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [1] } },
251
+ "w_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [10] } }
252
+ },
253
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 3, 4, 4], "tolerance": 0 } }
254
+ },
255
+ {
256
+ "name": "ort_with_group_2d_u8s8",
257
+ "provenance": {
258
+ "source": "onnxruntime/test/providers/cpu/nn/conv_integer_test.cc",
259
+ "test": "ConvIntegerTest.WithGroup_2D_u8s8"
260
+ },
261
+ "attrs": { "group": 3, "pads": [1, 1, 1, 1] },
262
+ "inputs": {
263
+ "x": {
264
+ "dtype": "uint8",
265
+ "shape": [1, 3, 3, 3],
266
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/ort_with_group_2d_u8u8_input_x" } }
267
+ },
268
+ "w": {
269
+ "dtype": "int8",
270
+ "shape": [3, 1, 2, 2],
271
+ "data": { "kind": "values", "values": [-9, -8, -8, -9, -7, -6, -6, -7, -5, -4, -4, -5] }
272
+ },
273
+ "x_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [1] } },
274
+ "w_zero_point": { "dtype": "int8", "shape": [1], "data": { "kind": "values", "values": [-10] } }
275
+ },
276
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 3, 4, 4], "tolerance": 0 } }
277
+ },
278
+ {
279
+ "name": "ort_stride2_padding_u8s8",
280
+ "provenance": {
281
+ "source": "onnxruntime/test/providers/cpu/nn/conv_integer_test.cc",
282
+ "test": "ConvIntegerTest.WithStride2_2D_u8s8"
283
+ },
284
+ "attrs": { "strides": [2, 2], "pads": [1, 1, 1, 1] },
285
+ "inputs": {
286
+ "x": {
287
+ "dtype": "uint8",
288
+ "shape": [1, 1, 7, 7],
289
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/ort_stride_padding_input_x" } }
290
+ },
291
+ "w": {
292
+ "dtype": "int8",
293
+ "shape": [1, 1, 3, 3],
294
+ "data": { "kind": "values", "values": [-9, -8, -9, -8, -7, -8, -9, -8, -9] }
295
+ },
296
+ "x_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [10] } },
297
+ "w_zero_point": { "dtype": "int8", "shape": [1], "data": { "kind": "values", "values": [-10] } }
298
+ },
299
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 1, 4, 4], "tolerance": 0 } }
300
+ },
301
+ {
302
+ "name": "ort_with_padding_2d_s8s8",
303
+ "provenance": {
304
+ "source": "onnxruntime/test/providers/cpu/nn/conv_integer_test.cc",
305
+ "test": "ConvIntegerTest.WithPadding_2D_s8s8"
306
+ },
307
+ "attrs": { "pads": [1, 1, 1, 1] },
308
+ "inputs": {
309
+ "x": {
310
+ "dtype": "int8",
311
+ "shape": [1, 1, 3, 3],
312
+ "data": { "kind": "values", "values": [-1, 2, -3, 4, -5, 6, -7, 8, -9] }
313
+ },
314
+ "w": { "dtype": "int8", "shape": [1, 1, 2, 2], "data": { "kind": "values", "values": [1, -2, 3, -4] } },
315
+ "x_zero_point": { "dtype": "int8", "shape": [1], "data": { "kind": "values", "values": [0] } },
316
+ "w_zero_point": { "dtype": "int8", "shape": [1], "data": { "kind": "values", "values": [0] } }
317
+ },
318
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 1, 4, 4], "tolerance": 0 } }
319
+ },
320
+ {
321
+ "name": "ort_with_group_2d_s8s8",
322
+ "provenance": {
323
+ "source": "onnxruntime/test/providers/cpu/nn/conv_integer_test.cc",
324
+ "test": "ConvIntegerTest.WithGroup_2D_s8s8"
325
+ },
326
+ "attrs": { "group": 3, "pads": [1, 1, 1, 1] },
327
+ "inputs": {
328
+ "x": {
329
+ "dtype": "int8",
330
+ "shape": [1, 3, 3, 3],
331
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/ort_with_group_2d_u8u8_input_x" } }
332
+ },
333
+ "w": {
334
+ "dtype": "int8",
335
+ "shape": [3, 1, 2, 2],
336
+ "data": { "kind": "values", "values": [-9, -8, -8, -9, -7, -6, -6, -7, -5, -4, -4, -5] }
337
+ },
338
+ "x_zero_point": { "dtype": "int8", "shape": [1], "data": { "kind": "values", "values": [1] } },
339
+ "w_zero_point": { "dtype": "int8", "shape": [1], "data": { "kind": "values", "values": [-10] } }
340
+ },
341
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 3, 4, 4], "tolerance": 0 } }
342
+ },
343
+ {
344
+ "name": "ort_with_group_2d_s8u8",
345
+ "provenance": {
346
+ "source": "onnxruntime/test/providers/cpu/nn/conv_integer_test.cc",
347
+ "test": "ConvIntegerTest.WithGroup_2D_s8u8"
348
+ },
349
+ "attrs": { "group": 3, "pads": [1, 1, 1, 1] },
350
+ "inputs": {
351
+ "x": {
352
+ "dtype": "int8",
353
+ "shape": [1, 3, 3, 3],
354
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/ort_with_group_2d_u8u8_input_x" } }
355
+ },
356
+ "w": {
357
+ "dtype": "uint8",
358
+ "shape": [3, 1, 2, 2],
359
+ "data": { "kind": "values", "values": [11, 12, 12, 11, 13, 14, 14, 13, 15, 16, 16, 15] }
360
+ },
361
+ "x_zero_point": { "dtype": "int8", "shape": [1], "data": { "kind": "values", "values": [1] } },
362
+ "w_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [10] } }
363
+ },
364
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 3, 4, 4], "tolerance": 0 } }
365
+ },
366
+ {
367
+ "name": "ort_stride2_padding_s8s8",
368
+ "provenance": {
369
+ "source": "onnxruntime/test/providers/cpu/nn/conv_integer_test.cc",
370
+ "test": "ConvIntegerTest.WithStride2_2D_s8s8"
371
+ },
372
+ "attrs": { "strides": [2, 2], "pads": [1, 1, 1, 1] },
373
+ "inputs": {
374
+ "x": {
375
+ "dtype": "int8",
376
+ "shape": [1, 1, 7, 7],
377
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/ort_stride_padding_input_x" } }
378
+ },
379
+ "w": {
380
+ "dtype": "int8",
381
+ "shape": [1, 1, 3, 3],
382
+ "data": { "kind": "values", "values": [-9, -8, -9, -8, -7, -8, -9, -8, -9] }
383
+ },
384
+ "x_zero_point": { "dtype": "int8", "shape": [1], "data": { "kind": "values", "values": [10] } },
385
+ "w_zero_point": { "dtype": "int8", "shape": [1], "data": { "kind": "values", "values": [-10] } }
386
+ },
387
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 1, 4, 4], "tolerance": 0 } }
388
+ },
389
+ {
390
+ "name": "ort_stride2_padding_s8u8",
391
+ "provenance": {
392
+ "source": "onnxruntime/test/providers/cpu/nn/conv_integer_test.cc",
393
+ "test": "ConvIntegerTest.WithStride2_2D_s8u8"
394
+ },
395
+ "attrs": { "strides": [2, 2], "pads": [1, 1, 1, 1] },
396
+ "inputs": {
397
+ "x": {
398
+ "dtype": "int8",
399
+ "shape": [1, 1, 7, 7],
400
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/ort_stride_padding_input_x" } }
401
+ },
402
+ "w": {
403
+ "dtype": "uint8",
404
+ "shape": [1, 1, 3, 3],
405
+ "data": { "kind": "values", "values": [11, 12, 11, 12, 13, 12, 11, 12, 11] }
406
+ },
407
+ "x_zero_point": { "dtype": "int8", "shape": [1], "data": { "kind": "values", "values": [10] } },
408
+ "w_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [10] } }
409
+ },
410
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 1, 4, 4], "tolerance": 0 } }
411
+ },
412
+ {
413
+ "name": "ort_no_x_zero_point",
414
+ "provenance": {
415
+ "source": "onnxruntime/test/providers/cpu/nn/conv_integer_test.cc",
416
+ "test": "ConvIntegerTest.NoXZeroPoint",
417
+ "notes": "Exercises the independent optional x_zero_point input; its omitted value defaults to zero while w_zero_point remains nonzero."
418
+ },
419
+ "inputs": {
420
+ "x": {
421
+ "dtype": "uint8",
422
+ "shape": [1, 1, 3, 3],
423
+ "data": { "kind": "values", "values": [2, 3, 4, 5, 6, 7, 8, 9, 10] }
424
+ },
425
+ "w": { "dtype": "uint8", "shape": [1, 1, 2, 2], "data": { "kind": "values", "values": [2, 2, 2, 2] } },
426
+ "w_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [1] } }
427
+ },
428
+ "outputs": {
429
+ "y": {
430
+ "dtype": "int32",
431
+ "shape": [1, 1, 2, 2],
432
+ "tolerance": 0,
433
+ "data": { "kind": "values", "values": [16, 20, 28, 32] }
434
+ }
435
+ },
436
+ "attrs": {}
437
+ },
438
+ {
439
+ "name": "ort_no_w_zero_point",
440
+ "provenance": {
441
+ "source": "onnxruntime/test/providers/cpu/nn/conv_integer_test.cc",
442
+ "test": "ConvIntegerTest.NoWZeroPoint",
443
+ "notes": "Exercises the independent optional w_zero_point input; its omitted value defaults to zero while x_zero_point remains nonzero."
444
+ },
445
+ "inputs": {
446
+ "x": {
447
+ "dtype": "uint8",
448
+ "shape": [1, 1, 3, 3],
449
+ "data": { "kind": "values", "values": [2, 3, 4, 5, 6, 7, 8, 9, 10] }
450
+ },
451
+ "w": { "dtype": "uint8", "shape": [1, 1, 2, 2], "data": { "kind": "values", "values": [2, 2, 2, 2] } },
452
+ "x_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [1] } }
453
+ },
454
+ "outputs": {
455
+ "y": {
456
+ "dtype": "int32",
457
+ "shape": [1, 1, 2, 2],
458
+ "tolerance": 0,
459
+ "data": { "kind": "values", "values": [24, 32, 48, 56] }
460
+ }
461
+ },
462
+ "attrs": {}
463
+ },
464
+ {
465
+ "name": "ort_stride3_asymmetric_padding_u8u8",
466
+ "provenance": {
467
+ "source": "onnxruntime/test/providers/cpu/nn/conv_integer_test.cc",
468
+ "test": "ConvIntegerTest.WithStride3_2D_u8u8"
469
+ },
470
+ "attrs": { "strides": [3, 3], "pads": [2, 2, 1, 1] },
471
+ "inputs": {
472
+ "x": {
473
+ "dtype": "uint8",
474
+ "shape": [1, 1, 7, 7],
475
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/ort_stride_padding_input_x" } }
476
+ },
477
+ "w": {
478
+ "dtype": "uint8",
479
+ "shape": [1, 1, 3, 3],
480
+ "data": { "kind": "values", "values": [11, 12, 11, 12, 13, 12, 11, 12, 11] }
481
+ },
482
+ "x_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [10] } },
483
+ "w_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [10] } }
484
+ },
485
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 1, 3, 3] } }
486
+ },
487
+ {
488
+ "name": "ort_stride3_asymmetric_padding_u8s8",
489
+ "provenance": {
490
+ "source": "onnxruntime/test/providers/cpu/nn/conv_integer_test.cc",
491
+ "test": "ConvIntegerTest.WithStride3_2D_u8s8"
492
+ },
493
+ "attrs": { "strides": [3, 3], "pads": [2, 2, 1, 1] },
494
+ "inputs": {
495
+ "x": {
496
+ "dtype": "uint8",
497
+ "shape": [1, 1, 7, 7],
498
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/ort_stride_padding_input_x" } }
499
+ },
500
+ "w": {
501
+ "dtype": "int8",
502
+ "shape": [1, 1, 3, 3],
503
+ "data": { "kind": "values", "values": [-9, -8, -9, -8, -7, -8, -9, -8, -9] }
504
+ },
505
+ "x_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [10] } },
506
+ "w_zero_point": { "dtype": "int8", "shape": [1], "data": { "kind": "values", "values": [-10] } }
507
+ },
508
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 1, 3, 3] } }
509
+ },
510
+ {
511
+ "name": "ort_stride3_asymmetric_padding_s8s8",
512
+ "provenance": {
513
+ "source": "onnxruntime/test/providers/cpu/nn/conv_integer_test.cc",
514
+ "test": "ConvIntegerTest.WithStride3_2D_s8s8"
515
+ },
516
+ "attrs": { "strides": [3, 3], "pads": [2, 2, 1, 1] },
517
+ "inputs": {
518
+ "x": {
519
+ "dtype": "int8",
520
+ "shape": [1, 1, 7, 7],
521
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/ort_stride_padding_input_x" } }
522
+ },
523
+ "w": {
524
+ "dtype": "int8",
525
+ "shape": [1, 1, 3, 3],
526
+ "data": { "kind": "values", "values": [-9, -8, -9, -8, -7, -8, -9, -8, -9] }
527
+ },
528
+ "x_zero_point": { "dtype": "int8", "shape": [1], "data": { "kind": "values", "values": [10] } },
529
+ "w_zero_point": { "dtype": "int8", "shape": [1], "data": { "kind": "values", "values": [-10] } }
530
+ },
531
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 1, 3, 3] } }
532
+ },
533
+ {
534
+ "name": "ort_stride3_asymmetric_padding_s8u8",
535
+ "provenance": {
536
+ "source": "onnxruntime/test/providers/cpu/nn/conv_integer_test.cc",
537
+ "test": "ConvIntegerTest.WithStride3_2D_s8u8"
538
+ },
539
+ "attrs": { "strides": [3, 3], "pads": [2, 2, 1, 1] },
540
+ "inputs": {
541
+ "x": {
542
+ "dtype": "int8",
543
+ "shape": [1, 1, 7, 7],
544
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/ort_stride_padding_input_x" } }
545
+ },
546
+ "w": {
547
+ "dtype": "uint8",
548
+ "shape": [1, 1, 3, 3],
549
+ "data": { "kind": "values", "values": [11, 12, 11, 12, 13, 12, 11, 12, 11] }
550
+ },
551
+ "x_zero_point": { "dtype": "int8", "shape": [1], "data": { "kind": "values", "values": [10] } },
552
+ "w_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [10] } }
553
+ },
554
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 1, 3, 3] } }
555
+ },
556
+ {
557
+ "name": "ort_padded_3d_u8u8",
558
+ "attrs": { "pads": [1, 1, 1, 1, 1, 1] },
559
+ "provenance": {
560
+ "source": "onnxruntime/test/providers/cpu/nn/conv_integer_test.cc",
561
+ "test": "ConvIntegerTest.WithPadding_3D_u8u8"
562
+ },
563
+ "inputs": {
564
+ "x": {
565
+ "dtype": "uint8",
566
+ "shape": [1, 1, 3, 3, 3],
567
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/ort_with_group_2d_u8u8_input_x" } }
568
+ },
569
+ "w": {
570
+ "dtype": "uint8",
571
+ "shape": [1, 1, 2, 2, 2],
572
+ "data": { "kind": "values", "values": [11, 11, 11, 11, 11, 11, 11, 11] }
573
+ },
574
+ "x_zero_point": { "dtype": "uint8", "shape": [], "data": { "kind": "values", "values": [1] } },
575
+ "w_zero_point": { "dtype": "uint8", "shape": [], "data": { "kind": "values", "values": [10] } }
576
+ },
577
+ "outputs": {
578
+ "y": {
579
+ "dtype": "int32",
580
+ "shape": [1, 1, 4, 4, 4],
581
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/ort_padded_3d_u8u8_output_y" } },
582
+ "tolerance": 0
583
+ }
584
+ }
585
+ },
586
+ {
587
+ "name": "ort_padded_3d_u8s8",
588
+ "attrs": { "pads": [1, 1, 1, 1, 1, 1] },
589
+ "provenance": {
590
+ "source": "onnxruntime/test/providers/cpu/nn/conv_integer_test.cc",
591
+ "test": "ConvIntegerTest.WithPadding_3D_u8s8",
592
+ "notes": "ORT's mixed uint8/int8 3D padding case."
593
+ },
594
+ "inputs": {
595
+ "x": {
596
+ "dtype": "uint8",
597
+ "shape": [1, 1, 3, 3, 3],
598
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/ort_with_group_2d_u8u8_input_x" } }
599
+ },
600
+ "w": {
601
+ "dtype": "int8",
602
+ "shape": [1, 1, 2, 2, 2],
603
+ "data": { "kind": "values", "values": [-9, -9, -9, -9, -9, -9, -9, -9] }
604
+ },
605
+ "x_zero_point": { "dtype": "uint8", "shape": [], "data": { "kind": "values", "values": [1] } },
606
+ "w_zero_point": { "dtype": "int8", "shape": [], "data": { "kind": "values", "values": [-10] } }
607
+ },
608
+ "outputs": {
609
+ "y": {
610
+ "dtype": "int32",
611
+ "shape": [1, 1, 4, 4, 4],
612
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/ort_padded_3d_u8u8_output_y" } },
613
+ "tolerance": 0
614
+ }
615
+ }
616
+ },
617
+ {
618
+ "name": "ort_padded_3d_s8s8",
619
+ "attrs": { "pads": [1, 1, 1, 1, 1, 1] },
620
+ "provenance": {
621
+ "source": "onnxruntime/test/providers/cpu/nn/conv_integer_test.cc",
622
+ "test": "ConvIntegerTest.WithPadding_3D_s8s8",
623
+ "notes": "ORT's signed 3D padding case."
624
+ },
625
+ "inputs": {
626
+ "x": {
627
+ "dtype": "int8",
628
+ "shape": [1, 1, 3, 3, 3],
629
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/ort_with_group_2d_u8u8_input_x" } }
630
+ },
631
+ "w": {
632
+ "dtype": "int8",
633
+ "shape": [1, 1, 2, 2, 2],
634
+ "data": { "kind": "values", "values": [-9, -9, -9, -9, -9, -9, -9, -9] }
635
+ },
636
+ "x_zero_point": { "dtype": "int8", "shape": [], "data": { "kind": "values", "values": [1] } },
637
+ "w_zero_point": { "dtype": "int8", "shape": [], "data": { "kind": "values", "values": [-10] } }
638
+ },
639
+ "outputs": {
640
+ "y": {
641
+ "dtype": "int32",
642
+ "shape": [1, 1, 4, 4, 4],
643
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/ort_padded_3d_u8u8_output_y" } },
644
+ "tolerance": 0
645
+ }
646
+ }
647
+ },
648
+ {
649
+ "name": "ort_pointwise_3d_u8u8",
650
+ "provenance": {
651
+ "source": "onnxruntime/test/providers/cpu/nn/conv_integer_test.cc",
652
+ "test": "ConvIntegerTest.Pointwise_3D_u8u8"
653
+ },
654
+ "inputs": {
655
+ "x": {
656
+ "dtype": "uint8",
657
+ "shape": [1, 1, 3, 3, 3],
658
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/ort_with_group_2d_u8u8_input_x" } }
659
+ },
660
+ "w": { "dtype": "uint8", "shape": [1, 1, 1, 1, 1], "data": { "kind": "values", "values": [5] } },
661
+ "x_zero_point": { "dtype": "uint8", "shape": [], "data": { "kind": "values", "values": [1] } },
662
+ "w_zero_point": { "dtype": "uint8", "shape": [], "data": { "kind": "values", "values": [1] } }
663
+ },
664
+ "outputs": {
665
+ "y": {
666
+ "dtype": "int32",
667
+ "shape": [1, 1, 3, 3, 3],
668
+ "data": {
669
+ "kind": "values",
670
+ "values": [4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92, 96, 100, 104, 108]
671
+ },
672
+ "tolerance": 0
673
+ }
674
+ },
675
+ "attrs": {}
676
+ },
677
+ {
678
+ "name": "onnx_backend_convinteger_with_padding",
679
+ "attrs": { "pads": [1, 1, 1, 1] },
680
+ "inputs": {
681
+ "x": {
682
+ "dtype": "uint8",
683
+ "shape": [1, 1, 3, 3],
684
+ "data": { "kind": "values", "values": [2, 3, 4, 5, 6, 7, 8, 9, 10] }
685
+ },
686
+ "w": {
687
+ "dtype": "uint8",
688
+ "shape": [2, 1, 2, 2],
689
+ "data": { "kind": "values", "values": [1, 1, 1, 1, 1, 1, 1, 1] }
690
+ },
691
+ "x_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [1] } },
692
+ "w_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [0] } }
693
+ },
694
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 2, 4, 4] } },
695
+ "provenance": { "source": "cmake/external/onnx/onnx/backend/test/data/node/test_convinteger_with_padding" }
696
+ },
697
+ {
698
+ "name": "onnx_backend_convinteger_without_padding",
699
+ "inputs": {
700
+ "x": {
701
+ "dtype": "uint8",
702
+ "shape": [1, 1, 3, 3],
703
+ "data": { "kind": "values", "values": [2, 3, 4, 5, 6, 7, 8, 9, 10] }
704
+ },
705
+ "w": { "dtype": "uint8", "shape": [1, 1, 2, 2], "data": { "kind": "values", "values": [1, 1, 1, 1] } },
706
+ "x_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [1] } },
707
+ "w_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [0] } }
708
+ },
709
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 1, 2, 2] } },
710
+ "provenance": { "source": "cmake/external/onnx/onnx/backend/test/data/node/test_convinteger_without_padding" },
711
+ "attrs": {}
712
+ },
713
+ {
714
+ "name": "dp4a_pointwise_u8s8_c34_tail",
715
+ "provenance": {
716
+ "notes": "Pins the widened-storage DP4A tail route for a realistic pointwise projection whose channel count is not divisible by four."
717
+ },
718
+ "inputs": {
719
+ "x": {
720
+ "dtype": "uint8",
721
+ "shape": [1, 34, 2, 3],
722
+ "data": { "kind": "cycle", "values": [0, 255, 128, 127, 56, 77, 3, 100, 200, 42, 5, 19, 64] }
723
+ },
724
+ "w": {
725
+ "dtype": "int8",
726
+ "shape": [5, 34, 1, 1],
727
+ "data": { "kind": "cycle", "values": [-77, 3, 100, -100, 42, -5, 19, -64, 88, -33, 7, 125, -90, -128, 127] }
728
+ },
729
+ "x_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [113] } },
730
+ "w_zero_point": { "dtype": "int8", "shape": [1], "data": { "kind": "values", "values": [-7] } }
731
+ },
732
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 5, 2, 3], "tolerance": 0 } },
733
+ "attrs": {}
734
+ },
735
+ {
736
+ "name": "dp4a_pointwise_u8s8_c8_batched",
737
+ "inputs": {
738
+ "x": {
739
+ "dtype": "uint8",
740
+ "shape": [2, 8, 3, 5],
741
+ "data": { "kind": "cycle", "values": { "$ref": "#/fixtureArrays/dp4a_pointwise_u8s8_c8_batched_input_x" } }
742
+ },
743
+ "w": {
744
+ "dtype": "int8",
745
+ "shape": [6, 8, 1, 1],
746
+ "data": {
747
+ "kind": "cycle",
748
+ "values": [-77, 3, 100, -100, 42, -5, 19, -64, 88, -33, 7, 125, -90, -128, 127, 0, -1, 56]
749
+ }
750
+ },
751
+ "x_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [113] } },
752
+ "w_zero_point": { "dtype": "int8", "shape": [1], "data": { "kind": "values", "values": [-7] } }
753
+ },
754
+ "outputs": { "y": { "dtype": "int32", "shape": [2, 6, 3, 5], "tolerance": 0 } },
755
+ "attrs": {}
756
+ },
757
+ {
758
+ "name": "dp4a_pointwise_s8u8_c12_tails",
759
+ "inputs": {
760
+ "x": {
761
+ "dtype": "int8",
762
+ "shape": [1, 12, 7, 11],
763
+ "data": {
764
+ "kind": "cycle",
765
+ "values": [-128, 127, 0, -1, 56, -77, 3, 100, -100, 42, -5, 19, -64, 88, -33, 7, 125, -90]
766
+ }
767
+ },
768
+ "w": {
769
+ "dtype": "uint8",
770
+ "shape": [9, 12, 1, 1],
771
+ "data": {
772
+ "kind": "cycle",
773
+ "values": [19, 64, 88, 33, 7, 125, 90, 128, 127, 0, 1, 56, 77, 3, 100, 255, 42, 5]
774
+ }
775
+ },
776
+ "x_zero_point": { "dtype": "int8", "shape": [1], "data": { "kind": "values", "values": [5] } },
777
+ "w_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [120] } }
778
+ },
779
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 9, 7, 11], "tolerance": 0 } },
780
+ "attrs": {}
781
+ },
782
+ {
783
+ "name": "empty_zero_dim",
784
+ "attrs": { "strides": [1, 1], "pads": [1, 1, 1, 1] },
785
+ "inputs": {
786
+ "x": { "dtype": "uint8", "shape": [0, 1, 3, 3], "data": { "kind": "values", "values": [] } },
787
+ "w": { "dtype": "uint8", "shape": [1, 1, 2, 2], "data": { "kind": "constant", "value": 1 } },
788
+ "x_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "constant", "value": 0 } },
789
+ "w_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "constant", "value": 0 } }
790
+ },
791
+ "outputs": { "y": { "dtype": "int32", "shape": [0, 1, 4, 4], "tolerance": 0 } }
792
+ },
793
+ {
794
+ "name": "ort_caseB_empty",
795
+ "attrs": { "strides": [1, 1], "pads": [1, 1, 1, 1] },
796
+ "inputs": {
797
+ "x": { "dtype": "uint8", "shape": [1, 1, 0, 3], "data": { "kind": "values", "values": [] } },
798
+ "w": { "dtype": "uint8", "shape": [1, 1, 2, 2], "data": { "kind": "values", "values": [127, 128, 129, 130] } },
799
+ "x_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [128] } },
800
+ "w_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [128] } }
801
+ },
802
+ "outputs": {
803
+ "y": {
804
+ "dtype": "int32",
805
+ "shape": [1, 1, 1, 4],
806
+ "data": { "kind": "values", "values": [0, 0, 0, 0] },
807
+ "tolerance": 0.001
808
+ }
809
+ }
810
+ },
811
+ {
812
+ "name": "dilation2_2d_u8u8",
813
+ "attrs": { "dilations": [2, 2] },
814
+ "inputs": {
815
+ "x": {
816
+ "dtype": "uint8",
817
+ "shape": [1, 1, 5, 5],
818
+ "data": {
819
+ "kind": "values",
820
+ "values": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]
821
+ }
822
+ },
823
+ "w": {
824
+ "dtype": "uint8",
825
+ "shape": [1, 1, 3, 3],
826
+ "data": { "kind": "values", "values": [1, 1, 1, 1, 1, 1, 1, 1, 1] }
827
+ },
828
+ "x_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [2] } },
829
+ "w_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [0] } }
830
+ },
831
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 1, 1, 1], "tolerance": 0 } }
832
+ },
833
+ {
834
+ "name": "dilation2_2d_u8s8_multichannel",
835
+ "attrs": { "dilations": [2, 2] },
836
+ "inputs": {
837
+ "x": {
838
+ "dtype": "uint8",
839
+ "shape": [1, 8, 9, 9],
840
+ "data": { "kind": "cycle", "values": { "$ref": "#/fixtureArrays/dp4a_pointwise_u8s8_c8_batched_input_x" } }
841
+ },
842
+ "w": {
843
+ "dtype": "int8",
844
+ "shape": [16, 8, 3, 3],
845
+ "data": { "kind": "cycle", "values": [-4, -3, -2, -1, 0, 1, 2, 3, 4, -2, 1, -1, 2, 0, 3, -3] }
846
+ },
847
+ "x_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [100] } },
848
+ "w_zero_point": { "dtype": "int8", "shape": [1], "data": { "kind": "values", "values": [0] } }
849
+ },
850
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 16, 5, 5], "tolerance": 0 } }
851
+ },
852
+ {
853
+ "name": "group2_in_channels_per_group2_u8s8",
854
+ "attrs": { "group": 2 },
855
+ "inputs": {
856
+ "x": {
857
+ "dtype": "uint8",
858
+ "shape": [1, 4, 5, 5],
859
+ "data": {
860
+ "kind": "cycle",
861
+ "values": [3, 7, 12, 19, 25, 31, 44, 50, 8, 16, 22, 37, 41, 5, 18, 29, 33, 47, 11, 24]
862
+ }
863
+ },
864
+ "w": {
865
+ "dtype": "int8",
866
+ "shape": [4, 2, 3, 3],
867
+ "data": { "kind": "cycle", "values": [-3, -2, -1, 0, 1, 2, 3, -1, 2, -2, 1, -3, 0, 3, -1, 1] }
868
+ },
869
+ "x_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [10] } },
870
+ "w_zero_point": { "dtype": "int8", "shape": [1], "data": { "kind": "values", "values": [-1] } }
871
+ },
872
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 4, 3, 3], "tolerance": 0 } }
873
+ },
874
+ {
875
+ "name": "dp4a_pointwise_c4_aligned_u8s8",
876
+ "inputs": {
877
+ "x": {
878
+ "dtype": "uint8",
879
+ "shape": [1, 4, 8, 8],
880
+ "data": { "kind": "cycle", "values": { "$ref": "#/fixtureArrays/dp4a_pointwise_u8s8_c8_batched_input_x" } }
881
+ },
882
+ "w": {
883
+ "dtype": "int8",
884
+ "shape": [8, 4, 1, 1],
885
+ "data": {
886
+ "kind": "cycle",
887
+ "values": [-77, 3, 100, -100, 42, -5, 19, -64, 88, -33, 7, 125, -90, -128, 127, 0]
888
+ }
889
+ },
890
+ "x_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [120] } },
891
+ "w_zero_point": { "dtype": "int8", "shape": [1], "data": { "kind": "values", "values": [-3] } }
892
+ },
893
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 8, 8, 8], "tolerance": 0 } },
894
+ "attrs": {}
895
+ },
896
+ {
897
+ "name": "dp4a_im2col_u8s8_oc64_c16_3x3_24x24",
898
+ "inputs": {
899
+ "x": {
900
+ "dtype": "uint8",
901
+ "shape": [1, 16, 24, 24],
902
+ "data": { "kind": "cycle", "values": [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 8] }
903
+ },
904
+ "w": {
905
+ "dtype": "int8",
906
+ "shape": [64, 16, 3, 3],
907
+ "data": { "kind": "cycle", "values": [2, -1, 3, -2, 1, 4, -3, 2, 0] }
908
+ },
909
+ "x_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "cycle", "values": [2] } },
910
+ "w_zero_point": { "dtype": "int8", "shape": [1], "data": { "kind": "cycle", "values": [1] } }
911
+ },
912
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 64, 22, 22] } },
913
+ "attrs": {}
914
+ },
915
+ {
916
+ "name": "per_channel_w_zero_point_u8s8_3x3",
917
+ "inputs": {
918
+ "x": {
919
+ "dtype": "uint8",
920
+ "shape": [1, 4, 5, 5],
921
+ "data": { "kind": "cycle", "values": [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160] }
922
+ },
923
+ "w": {
924
+ "dtype": "int8",
925
+ "shape": [4, 4, 3, 3],
926
+ "data": {
927
+ "kind": "cycle",
928
+ "values": [-4, 3, -2, 1, 0, -1, 2, -3, 4, -1, 2, -2, 3, 0, -3, 1, 2, -4, 3, -1, 0, 1, -2, 4, -3, 2, 1, -1, 3, -4, 2, 0, -2, 4, -1, 3]
929
+ }
930
+ },
931
+ "x_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [128] } },
932
+ "w_zero_point": { "dtype": "int8", "shape": [4], "data": { "kind": "values", "values": [0, 2, -3, 5] } }
933
+ },
934
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 4, 3, 3], "tolerance": 0 } },
935
+ "attrs": {}
936
+ },
937
+ {
938
+ "name": "per_channel_w_zero_point_int8_pointwise",
939
+ "inputs": {
940
+ "x": {
941
+ "dtype": "int8",
942
+ "shape": [1, 8, 4, 4],
943
+ "data": { "kind": "cycle", "values": [-50, 25, -10, 40, -30, 15, 50, -20, 35, -45, 5, -15, 20, -35, 45, -5] }
944
+ },
945
+ "w": {
946
+ "dtype": "int8",
947
+ "shape": [6, 8, 1, 1],
948
+ "data": {
949
+ "kind": "cycle",
950
+ "values": [3, -2, 5, -4, 1, -3, 6, -1, 4, -5, 2, -6, 7, -7, -2, 3, -4, 5, 1, -1, 3, -3, 2, -2]
951
+ }
952
+ },
953
+ "x_zero_point": { "dtype": "int8", "shape": [1], "data": { "kind": "values", "values": [0] } },
954
+ "w_zero_point": { "dtype": "int8", "shape": [6], "data": { "kind": "values", "values": [0, 1, -2, 3, -1, 2] } }
955
+ },
956
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 6, 4, 4], "tolerance": 0 } },
957
+ "attrs": {}
958
+ },
959
+ {
960
+ "name": "unaligned_kernel_small_numel_scalar_path",
961
+ "attrs": { "strides": [2, 2], "pads": [1, 1, 1, 1] },
962
+ "inputs": {
963
+ "x": {
964
+ "dtype": "uint8",
965
+ "shape": [2, 6, 9, 9],
966
+ "data": {
967
+ "kind": "cycle",
968
+ "values": [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160, 170, 180]
969
+ }
970
+ },
971
+ "w": {
972
+ "dtype": "uint8",
973
+ "shape": [8, 6, 3, 3],
974
+ "data": {
975
+ "kind": "cycle",
976
+ "values": { "$ref": "#/fixtureArrays/unaligned_kernel_small_numel_scalar_path_input_w" }
977
+ }
978
+ },
979
+ "x_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [128] } },
980
+ "w_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [16] } }
981
+ },
982
+ "outputs": { "y": { "dtype": "int32", "shape": [2, 8, 5, 5], "tolerance": 0 } }
983
+ },
984
+ {
985
+ "name": "group_conv_unequal_per_channel_zero_point_u8u8",
986
+ "attrs": { "group": 2 },
987
+ "inputs": {
988
+ "x": {
989
+ "dtype": "uint8",
990
+ "shape": [1, 4, 5, 5],
991
+ "data": { "kind": "cycle", "values": [5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80] }
992
+ },
993
+ "w": {
994
+ "dtype": "uint8",
995
+ "shape": [4, 2, 3, 3],
996
+ "data": {
997
+ "kind": "cycle",
998
+ "values": { "$ref": "#/fixtureArrays/unaligned_kernel_small_numel_scalar_path_input_w" }
999
+ }
1000
+ },
1001
+ "x_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [10] } },
1002
+ "w_zero_point": { "dtype": "uint8", "shape": [4], "data": { "kind": "values", "values": [10, 15, 12, 20] } }
1003
+ },
1004
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 4, 3, 3], "tolerance": 0 } }
1005
+ },
1006
+ {
1007
+ "name": "same_upper_stride2_autopad",
1008
+ "provenance": {
1009
+ "source": "ONNX Runtime ConvInteger-10 CPUExecutionProvider",
1010
+ "notes": "ConvInteger inherits Conv auto_pad semantics. This fixture exercises the exact SAME_UPPER spelling and the derived asymmetric bottom/right padding for a stride-2 output."
1011
+ },
1012
+ "attrs": { "auto_pad": "SAME_UPPER", "strides": [2, 2] },
1013
+ "inputs": {
1014
+ "x": {
1015
+ "dtype": "uint8",
1016
+ "shape": [1, 1, 4, 4],
1017
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/same_upper_stride2_autopad_input_x" } }
1018
+ },
1019
+ "w": { "dtype": "uint8", "shape": [1, 1, 3, 3], "data": { "kind": "constant", "value": 1 } },
1020
+ "x_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [0] } },
1021
+ "w_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [0] } }
1022
+ },
1023
+ "outputs": {
1024
+ "y": {
1025
+ "dtype": "int32",
1026
+ "shape": [1, 1, 2, 2],
1027
+ "data": { "kind": "values", "values": [54, 45, 72, 54] },
1028
+ "tolerance": 0
1029
+ }
1030
+ }
1031
+ },
1032
+ {
1033
+ "name": "optional_zero_points_omitted",
1034
+ "provenance": {
1035
+ "source": "ONNX Runtime ConvInteger-10 CPUExecutionProvider",
1036
+ "notes": "Both ConvInteger zero-point inputs are optional and independently default to zero."
1037
+ },
1038
+ "inputs": {
1039
+ "x": { "dtype": "uint8", "shape": [1, 1, 2, 2], "data": { "kind": "values", "values": [1, 2, 3, 4] } },
1040
+ "w": { "dtype": "uint8", "shape": [1, 1, 1, 1], "data": { "kind": "values", "values": [2] } }
1041
+ },
1042
+ "outputs": {
1043
+ "y": {
1044
+ "dtype": "int32",
1045
+ "shape": [1, 1, 2, 2],
1046
+ "data": { "kind": "values", "values": [2, 4, 6, 8] },
1047
+ "tolerance": 0
1048
+ }
1049
+ },
1050
+ "attrs": {}
1051
+ },
1052
+ {
1053
+ "name": "conv1d_u8u8_scalar_zero_points",
1054
+ "provenance": {
1055
+ "source": "ONNX Runtime ConvInteger-10 CPUExecutionProvider",
1056
+ "notes": "ConvInteger is defined for N-dimensional convolution and rank-3 NCW is a realistic quantized audio shape."
1057
+ },
1058
+ "inputs": {
1059
+ "x": { "dtype": "uint8", "shape": [1, 1, 6], "data": { "kind": "values", "values": [10, 12, 13, 8, 15, 16] } },
1060
+ "w": { "dtype": "uint8", "shape": [1, 1, 3], "data": { "kind": "values", "values": [3, 1, 4] } },
1061
+ "x_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [10] } },
1062
+ "w_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [2] } }
1063
+ },
1064
+ "outputs": {
1065
+ "y": {
1066
+ "dtype": "int32",
1067
+ "shape": [1, 1, 4],
1068
+ "data": { "kind": "values", "values": [4, -5, 15, 5] },
1069
+ "tolerance": 0
1070
+ }
1071
+ },
1072
+ "attrs": {}
1073
+ },
1074
+ {
1075
+ "name": "conv1d_x_zero_point_only",
1076
+ "provenance": {
1077
+ "source": "ONNX ConvInteger-10 optional-input contract",
1078
+ "notes": "Exercises rank-3 NCW convolution with x_zero_point present and w_zero_point independently omitted."
1079
+ },
1080
+ "inputs": {
1081
+ "x": { "dtype": "uint8", "shape": [1, 1, 4], "data": { "kind": "values", "values": [10, 12, 13, 8] } },
1082
+ "w": { "dtype": "uint8", "shape": [1, 1, 2], "data": { "kind": "values", "values": [3, 1] } },
1083
+ "x_zero_point": { "dtype": "uint8", "shape": [], "data": { "kind": "values", "values": [10] } }
1084
+ },
1085
+ "outputs": {
1086
+ "y": { "dtype": "int32", "shape": [1, 1, 3], "data": { "kind": "values", "values": [2, 9, 7] }, "tolerance": 0 }
1087
+ },
1088
+ "attrs": {}
1089
+ },
1090
+ {
1091
+ "name": "conv1d_w_zero_point_only",
1092
+ "provenance": {
1093
+ "source": "ONNX ConvInteger-10 optional-input contract",
1094
+ "notes": "Exercises rank-3 NCW convolution with w_zero_point present and x_zero_point independently omitted."
1095
+ },
1096
+ "inputs": {
1097
+ "x": { "dtype": "uint8", "shape": [1, 1, 4], "data": { "kind": "values", "values": [10, 12, 13, 8] } },
1098
+ "w": { "dtype": "uint8", "shape": [1, 1, 2], "data": { "kind": "values", "values": [3, 1] } },
1099
+ "w_zero_point": { "dtype": "uint8", "shape": [], "data": { "kind": "values", "values": [2] } }
1100
+ },
1101
+ "outputs": {
1102
+ "y": {
1103
+ "dtype": "int32",
1104
+ "shape": [1, 1, 3],
1105
+ "data": { "kind": "values", "values": [-2, -1, 5] },
1106
+ "tolerance": 0
1107
+ }
1108
+ },
1109
+ "attrs": {}
1110
+ },
1111
+ {
1112
+ "name": "conv1d_zero_points_omitted",
1113
+ "provenance": {
1114
+ "source": "ONNX ConvInteger-10 optional-input contract",
1115
+ "notes": "Completes the rank-3 NCW optional-presence matrix with both zero points omitted and defaulting to zero."
1116
+ },
1117
+ "inputs": {
1118
+ "x": { "dtype": "uint8", "shape": [1, 1, 4], "data": { "kind": "values", "values": [10, 12, 13, 8] } },
1119
+ "w": { "dtype": "uint8", "shape": [1, 1, 2], "data": { "kind": "values", "values": [3, 1] } }
1120
+ },
1121
+ "outputs": {
1122
+ "y": {
1123
+ "dtype": "int32",
1124
+ "shape": [1, 1, 3],
1125
+ "data": { "kind": "values", "values": [42, 49, 47] },
1126
+ "tolerance": 0
1127
+ }
1128
+ },
1129
+ "attrs": {}
1130
+ },
1131
+ {
1132
+ "name": "per_channel_w_zero_point_without_x_zero_point",
1133
+ "provenance": {
1134
+ "source": "ONNX ConvInteger-10 optional-input contract",
1135
+ "notes": "Exercises a per-output-channel w_zero_point while x_zero_point independently defaults to zero."
1136
+ },
1137
+ "inputs": {
1138
+ "x": { "dtype": "uint8", "shape": [1, 1, 2, 2], "data": { "kind": "values", "values": [1, 2, 3, 4] } },
1139
+ "w": { "dtype": "uint8", "shape": [2, 1, 1, 1], "data": { "kind": "values", "values": [3, 4] } },
1140
+ "w_zero_point": { "dtype": "uint8", "shape": [2], "data": { "kind": "values", "values": [1, 2] } }
1141
+ },
1142
+ "outputs": {
1143
+ "y": {
1144
+ "dtype": "int32",
1145
+ "shape": [1, 2, 2, 2],
1146
+ "data": { "kind": "values", "values": [2, 4, 6, 8, 2, 4, 6, 8] },
1147
+ "tolerance": 0
1148
+ }
1149
+ },
1150
+ "attrs": {}
1151
+ },
1152
+ {
1153
+ "name": "conv3d_zero_points_omitted",
1154
+ "provenance": {
1155
+ "source": "ONNX ConvInteger-10 optional-input contract",
1156
+ "notes": "Exercises rank-5 NCDHW convolution with both independent zero-point inputs omitted."
1157
+ },
1158
+ "inputs": {
1159
+ "x": { "dtype": "uint8", "shape": [1, 1, 2, 1, 1], "data": { "kind": "values", "values": [2, 5] } },
1160
+ "w": { "dtype": "uint8", "shape": [1, 1, 1, 1, 1], "data": { "kind": "values", "values": [3] } }
1161
+ },
1162
+ "outputs": {
1163
+ "y": {
1164
+ "dtype": "int32",
1165
+ "shape": [1, 1, 2, 1, 1],
1166
+ "data": { "kind": "values", "values": [6, 15] },
1167
+ "tolerance": 0
1168
+ }
1169
+ },
1170
+ "attrs": {}
1171
+ },
1172
+ {
1173
+ "name": "conv3d_x_zero_point_only",
1174
+ "provenance": {
1175
+ "source": "ONNX ConvInteger-10 optional-input contract",
1176
+ "notes": "Exercises rank-5 NCDHW convolution with x_zero_point present and w_zero_point omitted."
1177
+ },
1178
+ "inputs": {
1179
+ "x": { "dtype": "uint8", "shape": [1, 1, 2, 1, 1], "data": { "kind": "values", "values": [2, 5] } },
1180
+ "w": { "dtype": "uint8", "shape": [1, 1, 1, 1, 1], "data": { "kind": "values", "values": [3] } },
1181
+ "x_zero_point": { "dtype": "uint8", "shape": [], "data": { "kind": "values", "values": [1] } }
1182
+ },
1183
+ "outputs": {
1184
+ "y": {
1185
+ "dtype": "int32",
1186
+ "shape": [1, 1, 2, 1, 1],
1187
+ "data": { "kind": "values", "values": [3, 12] },
1188
+ "tolerance": 0
1189
+ }
1190
+ },
1191
+ "attrs": {}
1192
+ },
1193
+ {
1194
+ "name": "conv3d_w_zero_point_only",
1195
+ "provenance": {
1196
+ "source": "ONNX ConvInteger-10 optional-input contract",
1197
+ "notes": "Exercises rank-5 NCDHW convolution with w_zero_point present and x_zero_point omitted."
1198
+ },
1199
+ "inputs": {
1200
+ "x": { "dtype": "uint8", "shape": [1, 1, 2, 1, 1], "data": { "kind": "values", "values": [2, 5] } },
1201
+ "w": { "dtype": "uint8", "shape": [1, 1, 1, 1, 1], "data": { "kind": "values", "values": [3] } },
1202
+ "w_zero_point": { "dtype": "uint8", "shape": [], "data": { "kind": "values", "values": [2] } }
1203
+ },
1204
+ "outputs": {
1205
+ "y": {
1206
+ "dtype": "int32",
1207
+ "shape": [1, 1, 2, 1, 1],
1208
+ "data": { "kind": "values", "values": [2, 5] },
1209
+ "tolerance": 0
1210
+ }
1211
+ },
1212
+ "attrs": {}
1213
+ },
1214
+ {
1215
+ "name": "conv3d_depth_dilation2_compact",
1216
+ "provenance": {
1217
+ "source": "ONNX ConvInteger-10 volumetric dilation semantics",
1218
+ "notes": "Covers a non-default depth dilation. Existing 3D fixtures varied data types and padding but kept dilationD=1."
1219
+ },
1220
+ "attrs": { "strides": [1, 1, 1], "dilations": [2, 1, 1] },
1221
+ "inputs": {
1222
+ "x": {
1223
+ "dtype": "uint8",
1224
+ "shape": [1, 1, 4, 2, 2],
1225
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/same_upper_stride2_autopad_input_x" } }
1226
+ },
1227
+ "w": { "dtype": "uint8", "shape": [1, 1, 2, 1, 1], "data": { "kind": "values", "values": [1, 2] } },
1228
+ "x_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [0] } },
1229
+ "w_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [0] } }
1230
+ },
1231
+ "outputs": {
1232
+ "y": {
1233
+ "dtype": "int32",
1234
+ "shape": [1, 1, 2, 2, 2],
1235
+ "data": { "kind": "values", "values": [19, 22, 25, 28, 31, 34, 37, 40] }
1236
+ }
1237
+ }
1238
+ },
1239
+ {
1240
+ "name": "dp4a_im2col_3d_u8s8_b1c4m8_4x8x8_k3",
1241
+ "provenance": {
1242
+ "source": "ONNX ConvInteger-10 volumetric convolution",
1243
+ "notes": "Locks the shared 3-D im2col-to-DP4A route with zero-point-filled spatial padding."
1244
+ },
1245
+ "attrs": { "pads": [1, 1, 1, 1, 1, 1] },
1246
+ "inputs": {
1247
+ "x": {
1248
+ "dtype": "uint8",
1249
+ "shape": [1, 4, 4, 8, 8],
1250
+ "data": { "kind": "cycle", "values": [0, 17, 63, 127, 128, 191, 255] }
1251
+ },
1252
+ "w": {
1253
+ "dtype": "int8",
1254
+ "shape": [8, 4, 3, 3, 3],
1255
+ "data": { "kind": "cycle", "values": [-127, -31, -1, 0, 7, 63, 126] }
1256
+ },
1257
+ "x_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [127] } },
1258
+ "w_zero_point": { "dtype": "int8", "shape": [1], "data": { "kind": "values", "values": [-3] } }
1259
+ },
1260
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 8, 4, 8, 8], "tolerance": 0 } }
1261
+ },
1262
+ {
1263
+ "name": "same_lower_stride2_autopad",
1264
+ "provenance": {
1265
+ "source": "ONNX Runtime ConvInteger-10 CPUExecutionProvider",
1266
+ "notes": "ONNX auto_pad SAME_LOWER puts the odd padding element at the START of the axis, so unlike its SAME_UPPER twin this case has a non-zero leading pad and fails if the kernel is handed the explicit pad attributes instead of the derived ones."
1267
+ },
1268
+ "attrs": { "auto_pad": "SAME_LOWER", "strides": [2, 2] },
1269
+ "inputs": {
1270
+ "x": {
1271
+ "dtype": "uint8",
1272
+ "shape": [1, 1, 4, 4],
1273
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/same_upper_stride2_autopad_input_x" } }
1274
+ },
1275
+ "w": { "dtype": "uint8", "shape": [1, 1, 3, 3], "data": { "kind": "constant", "value": 1 } },
1276
+ "x_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [0] } },
1277
+ "w_zero_point": { "dtype": "uint8", "shape": [1], "data": { "kind": "values", "values": [0] } }
1278
+ },
1279
+ "outputs": { "y": { "dtype": "int32", "shape": [1, 1, 2, 2], "tolerance": 0 } }
1280
+ }
1281
+ ]
1282
+ }