Xenova HF Staff commited on
Commit
6dbed36
·
verified ·
1 Parent(s): 62b03c9

sync 91d990483a17

Browse files
README.md CHANGED
@@ -18,18 +18,18 @@ See the [ONNX Runtime `GatherBlockQuantized` contrib-operator spec](https://gith
18
 
19
  ## Inputs
20
 
21
- | Name | Bind key | Logical dtype | WebGPU storage | Rank | Shape | Description | Presence |
22
  | --- | --- | --- | --- | --- | --- | --- | --- |
23
- | `data` | `dataT` | `T1` | runtime-selected; narrow integers and bool use 32-bit slots | `2` | — | Constant uint8 weight matrix. With `bits = 4`, each byte stores two values low-nibble first; with `bits = 8`, each byte stores one value. | required |
24
- | `indices` | `indicesT` | `Tind` | `uint32` | `1` | — | Non-negative logical int64 indices selecting rows from axis 0 of `data`. Every index must be less than the row count; values use checked uint32 WebGPU storage. | required |
25
- | `scales` | `scalesT` | `T2` | same as logical dtype | `2` | — | Per-block dequantization scale factors of shape `(rows, ceil(output_columns / block_size))`. | required |
26
- | `zero_points` | `zeroPointsT` | `T1` | runtime-selected; narrow integers and bool use 32-bit slots | `2` | — | Optional uint8 zero points. At 4 bits two zero points are packed per byte along the quantized axis, low-nibble first; at 8 bits the shape matches `scales`. If absent, uint8 data uses 2^(bits-1). | optional |
27
 
28
  ## Outputs
29
 
30
- | Name | Bind key | Logical dtype | Rank | Shape | Description | Presence |
31
  | --- | --- | --- | --- | --- | --- | --- |
32
- | `output` | `outputT` | `T2` | `2` | derived; see description | Dequantized floating-point output rows corresponding to the gathered indices. | required |
33
 
34
  ## Attributes
35
 
@@ -52,7 +52,7 @@ Default values (overridable per request):
52
 
53
  ## Files
54
 
55
- - [`metadata.json`](build/webgpu/metadata.json) — kernel metadata (id, digests, provenance)
56
  - [`manifest.json`](build/webgpu/manifest.json) — the op contract (source of truth)
57
  - [`test.json`](build/webgpu/test.json) — correctness cases
58
  - [`bench.json`](build/webgpu/bench.json) — benchmark + tuning cases
@@ -61,10 +61,14 @@ Default values (overridable per request):
61
 
62
  ## Use with `@huggingface/kernels`
63
 
64
- The loader derives every required output's shape and logical dtype from the manifest contract and this call.
65
- It then allocates the result tensors automatically.
 
 
 
66
 
67
  The `version: 1` option selects the published kernel contract; it is independent of any operator opset, contrib `since_version`, or model version.
 
68
 
69
  Replace each `*Data` placeholder with a typed array containing the corresponding input data.
70
 
 
18
 
19
  ## Inputs
20
 
21
+ | Name | Upstream name | Logical dtype | WebGPU storage | Rank | Shape | Description | Presence |
22
  | --- | --- | --- | --- | --- | --- | --- | --- |
23
+ | `dataT` | `data` | `T1` | runtime-selected; narrow integers and bool use 32-bit slots | `2` | — | Constant uint8 weight matrix. With `bits = 4`, each byte stores two values low-nibble first; with `bits = 8`, each byte stores one value. | required |
24
+ | `indicesT` | `indices` | `Tind` | `uint32` | `1` | — | Non-negative logical int64 indices selecting rows from axis 0 of `data`. Every index must be less than the row count; values use checked uint32 WebGPU storage. | required |
25
+ | `scalesT` | `scales` | `T2` | same as logical dtype | `2` | — | Per-block dequantization scale factors of shape `(rows, ceil(output_columns / block_size))`. | required |
26
+ | `zeroPointsT` | `zero_points` | `T1` | runtime-selected; narrow integers and bool use 32-bit slots | `2` | — | Optional uint8 zero points. At 4 bits two zero points are packed per byte along the quantized axis, low-nibble first; at 8 bits the shape matches `scales`. If absent, uint8 data uses 2^(bits-1). | optional |
27
 
28
  ## Outputs
29
 
30
+ | Name | Upstream name | Logical dtype | Rank | Shape | Description | Presence |
31
  | --- | --- | --- | --- | --- | --- | --- |
32
+ | `outputT` | `output` | `T2` | `2` | derived | Dequantized floating-point output rows corresponding to the gathered indices. | required |
33
 
34
  ## Attributes
35
 
 
52
 
53
  ## Files
54
 
55
+ - [`metadata.json`](build/webgpu/metadata.json) — kernel metadata (id, digests, per-variant templates, provenance)
56
  - [`manifest.json`](build/webgpu/manifest.json) — the op contract (source of truth)
57
  - [`test.json`](build/webgpu/test.json) — correctness cases
58
  - [`bench.json`](build/webgpu/bench.json) — benchmark + tuning cases
 
61
 
62
  ## Use with `@huggingface/kernels`
63
 
64
+ ```sh
65
+ npm install --save-exact @huggingface/kernels@0.0.1-preview.2
66
+ ```
67
+
68
+ Required output shapes and logical data types are inferred from the supplied inputs and attributes; result tensors are allocated 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
+ It follows the `v1` branch as fixes land. To pin exact artifact bytes, pass a 40-character commit `revision` instead of `version`.
72
 
73
  Replace each `*Data` placeholder with a typed array containing the corresponding input data.
74
 
build/webgpu/bench.json CHANGED
@@ -1,5 +1,4 @@
1
  {
2
- "op": "com.microsoft.GatherBlockQuantized",
3
  "tunableSpace": { "workgroupSize": [64, 128, 256] },
4
  "cases": [
5
  {
@@ -237,7 +236,7 @@
237
  "name": "gather-block-q8-dispatch-healthy-idx1024-cols4096-1d",
238
  "preset": "stress",
239
  "provenance": {
240
- "notes": "Stress-only capacity sibling: widened uint8 GPU storage brings the declared footprint to 280 MiB."
241
  },
242
  "vars": { "rows": 16384, "cols": 4096, "indexCount": 1024, "bits": 8, "blockSize": 32 },
243
  "attrs": { "bits": 8, "block_size": 32 },
 
1
  {
 
2
  "tunableSpace": { "workgroupSize": [64, 128, 256] },
3
  "cases": [
4
  {
 
236
  "name": "gather-block-q8-dispatch-healthy-idx1024-cols4096-1d",
237
  "preset": "stress",
238
  "provenance": {
239
+ "notes": "Widened uint8 GPU storage gives this capacity stress case a declared footprint of 280 MiB."
240
  },
241
  "vars": { "rows": 16384, "cols": 4096, "indexCount": 1024, "bits": 8, "blockSize": 32 },
242
  "attrs": { "bits": 8, "block_size": 32 },
build/webgpu/gather-block-quantized-q4-pair.wgsl.jinja CHANGED
@@ -3,11 +3,10 @@
3
  const WG: u32 = {{ workgroupSize }}u;
4
 
5
  @compute @workgroup_size(WG, 1, 1)
6
- fn main(@builtin(global_invocation_id) gid: vec3<u32>,
7
- @builtin(num_workgroups) nwg: vec3<u32>) {
8
- // 2D-folded flat index: gid.y carries the high bits past the maxComputeWorkgroupsPerDimension
9
- // workgroup-per-dimension dispatch limit. Reduces to gid.x when nwg.y == 1.
10
- let pair_index = gid.x + gid.y * nwg.x * WG;
11
  let total = params.indexCount * params.packedCols;
12
  if (pair_index >= total) {
13
  return;
 
3
  const WG: u32 = {{ workgroupSize }}u;
4
 
5
  @compute @workgroup_size(WG, 1, 1)
6
+ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
7
+ // 2D-folded flat index: gid.y carries the high bits past the per-axis dispatch fold width.
8
+ // Reduces to gid.x when the dispatch does not fold.
9
+ let pair_index = gid.x + gid.y * {{ DISPATCH_FOLD_WIDTH }}u * WG;
 
10
  let total = params.indexCount * params.packedCols;
11
  if (pair_index >= total) {
12
  return;
build/webgpu/gather-block-quantized-q8-vec4.wgsl.jinja CHANGED
@@ -3,11 +3,10 @@
3
  const WG: u32 = {{ workgroupSize }}u;
4
 
5
  @compute @workgroup_size(WG, 1, 1)
6
- fn main(@builtin(global_invocation_id) gid: vec3<u32>,
7
- @builtin(num_workgroups) nwg: vec3<u32>) {
8
- // 2D-folded flat index: gid.y carries the high bits past the maxComputeWorkgroupsPerDimension
9
- // workgroup-per-dimension dispatch limit. Reduces to gid.x when nwg.y == 1.
10
- let vec_index = gid.x + gid.y * nwg.x * WG;
11
  {% if scalarTail %}
12
  let row_vecs = (params.cols + 3u) / 4u;
13
  {% else %}
 
3
  const WG: u32 = {{ workgroupSize }}u;
4
 
5
  @compute @workgroup_size(WG, 1, 1)
6
+ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
7
+ // 2D-folded flat index: gid.y carries the high bits past the per-axis dispatch fold width.
8
+ // Reduces to gid.x when the dispatch does not fold.
9
+ let vec_index = gid.x + gid.y * {{ DISPATCH_FOLD_WIDTH }}u * WG;
 
10
  {% if scalarTail %}
11
  let row_vecs = (params.cols + 3u) / 4u;
12
  {% else %}
build/webgpu/manifest.json CHANGED
@@ -2,453 +2,111 @@
2
  "domain": "com.microsoft",
3
  "name": "GatherBlockQuantized",
4
  "sinceVersion": 1,
5
- "description": "Gathers rows from a block-wise quantized weight matrix and dequantizes them. This inference implementation supports the standard `gather_axis = 0`, `quantize_axis = 1` matrix subset with uint8 `data`, 4-bit packed or 8-bit values, rank-1 non-negative in-bounds int64 `indices` projected to uint32 WebGPU storage, and float32 scales/output. Higher-rank gathers, negative indices, int32 indices, int4/uint4 data, 2-bit data, float16/bfloat16 output, and non-default axes are not implemented.",
6
- "inputs": [
7
- {
8
- "role": "data",
9
- "dtype": "T1",
10
- "rank": 2,
11
- "description": "Constant uint8 weight matrix. With `bits = 4`, each byte stores two values low-nibble first; with `bits = 8`, each byte stores one value."
12
- },
13
- {
14
- "role": "indices",
15
- "dtype": "Tind",
16
- "rank": 1,
17
- "description": "Non-negative logical int64 indices selecting rows from axis 0 of `data`. Every index must be less than the row count; values use checked uint32 WebGPU storage."
18
- },
19
- {
20
- "role": "scales",
21
- "dtype": "T2",
22
- "rank": 2,
23
- "description": "Per-block dequantization scale factors of shape `(rows, ceil(output_columns / block_size))`."
24
- },
25
- {
26
- "role": "zero_points",
27
- "dtype": "T1",
28
- "rank": 2,
29
- "optional": true,
30
- "description": "Optional uint8 zero points. At 4 bits two zero points are packed per byte along the quantized axis, low-nibble first; at 8 bits the shape matches `scales`. If absent, uint8 data uses 2^(bits-1)."
31
- }
32
- ],
33
- "outputs": [
34
- {
35
- "role": "output",
36
  "dtype": "T2",
37
  "rank": 2,
38
- "shape": "[dim(shapes.indices, 0), dim(shapes.data, 1) * (8 / attrs.bits)]",
39
- "description": "Dequantized floating-point output rows corresponding to the gathered indices."
40
  }
41
- ],
42
- "attributes": { "bits": 4, "block_size": 128, "gather_axis": 0, "quantize_axis": 1 },
 
 
 
 
 
43
  "attributeConstraints": {
44
  "bits": { "values": [4, 8] },
45
  "gather_axis": { "values": [0] },
46
  "quantize_axis": { "values": [1] }
47
  },
48
- "attributeDescriptions": {
49
- "bits": "Bits per quantized value. The schema default is 4; this implementation supports 4 or 8.",
50
- "block_size": "Number of values sharing a scale. Defaults to 128 and must be a power of two at least 16.",
51
- "gather_axis": "Axis from which values are gathered. This matrix implementation supports the standard default, axis 0.",
52
- "quantize_axis": "Axis split into quantization blocks. This matrix implementation supports the standard default, axis 1."
53
- },
54
  "typeConstraints": { "T1": ["uint8"], "T2": ["float32"], "Tind": ["int64"] },
55
- "args": {
56
- "dataT": { "kind": "tensor", "semantic": "data", "role": "input" },
57
- "indicesT": { "kind": "tensor", "semantic": "indices", "role": "input", "dtype": "uint32", "narrowing": "checked" },
58
- "scalesT": { "kind": "tensor", "semantic": "scales", "role": "input" },
59
- "zeroPointsT": { "kind": "tensor", "semantic": "zero_points", "role": "input", "required": false },
60
- "outputT": { "kind": "tensor", "semantic": "output", "role": "output" }
61
- },
62
  "derive": {
63
  "deviceWorkgroupCap": "min(device.limits.maxComputeInvocationsPerWorkgroup, device.limits.maxComputeWorkgroupSizeX)",
64
  "bits": "attrs.bits",
65
  "blockSize": "attrs.block_size",
66
  "blockSizeOk": "blockSize >= 16 and pow2ceil(blockSize) == blockSize",
67
- "outBlocks": "ceilDiv(dim(shapes.output, 1), blockSize)",
68
  "zeroPointCols": "ceilDiv(outBlocks, 2) if bits == 4 else outBlocks",
69
  "workgroupSize": "min(tunables.WORKGROUP_SIZE, deviceWorkgroupCap)",
70
- "commonShapeValid": "blockSizeOk and ranks.data == 2 and ranks.indices == 1 and ranks.scales == 2 and ranks.output == 2 and tensorDtypes.indices == \"uint32\" and tensorDtypes.scales == \"float32\" and tensorDtypes.output == \"float32\" and dim(shapes.output, 0) == dim(shapes.indices, 0) and dim(shapes.scales, 0) == dim(shapes.data, 0) and dim(shapes.scales, 1) == outBlocks",
71
- "q4ShapeValid": "commonShapeValid and tensorDtypes.data == \"uint8\" and dim(shapes.output, 1) == dim(shapes.data, 1) * 2",
72
- "q8ShapeValid": "commonShapeValid and tensorDtypes.data == \"uint8\" and dim(shapes.output, 1) == dim(shapes.data, 1)",
73
- "zeroPointsValid": "present.zeroPointsT and ranks.zero_points == 2 and tensorDtypes.zero_points == \"uint8\" and dim(shapes.zero_points, 0) == dim(shapes.data, 0) and dim(shapes.zero_points, 1) == zeroPointCols",
74
  "noZeroMode": "not present.zeroPointsT",
75
  "zeroMode": "zeroPointsValid",
76
  "workgroupFits": "workgroupSize > 0",
77
- "foldedDispatchFits": "ceil(ceil(numel(shapes.output) / device.limits.maxComputeWorkgroupsPerDimension) / workgroupSize) <= device.limits.maxComputeWorkgroupsPerDimension"
78
  },
79
- "tunables": { "WORKGROUP_SIZE": 64 },
80
- "bindingSets": {
81
- "noZero": [
82
- {
83
- "name": "data",
84
- "arg": "dataT",
85
- "semantic": "data",
86
- "buffer": { "type": "read-only-storage" },
87
- "elementType": "$dataElement"
88
- },
89
- {
90
- "name": "indices",
91
- "arg": "indicesT",
92
- "semantic": "indices",
93
- "buffer": { "type": "read-only-storage" },
94
- "elementType": "$indexScalar"
95
- },
96
- {
97
- "name": "scales",
98
- "arg": "scalesT",
99
- "semantic": "scales",
100
- "buffer": { "type": "read-only-storage" },
101
- "elementType": "$scaleScalar"
102
- },
103
- {
104
- "name": "output",
105
- "arg": "outputT",
106
- "semantic": "output",
107
- "buffer": { "type": "storage" },
108
- "elementType": "$outputElement"
109
- },
110
- {
111
- "name": "params",
112
- "semantic": "kernel.params",
113
- "buffer": { "type": "uniform" },
114
- "struct": {
115
- "name": "Params",
116
- "fields": [
117
- { "name": "indexCount", "type": "u32", "value": "dim(shapes.indices, 0)" },
118
- { "name": "cols", "type": "u32", "value": "dim(shapes.output, 1)" },
119
- { "name": "packedCols", "type": "u32", "value": "dim(shapes.data, 1)" },
120
- { "name": "blocks", "type": "u32", "value": "dim(shapes.scales, 1)" },
121
- { "name": "blockSize", "type": "u32", "value": "blockSize" },
122
- { "name": "rows", "type": "u32", "value": "dim(shapes.data, 0)" }
123
- ]
124
- }
125
- }
126
- ],
127
- "zero": [
128
- {
129
- "name": "data",
130
- "arg": "dataT",
131
- "semantic": "data",
132
- "buffer": { "type": "read-only-storage" },
133
- "elementType": "$dataElement"
134
- },
135
- {
136
- "name": "indices",
137
- "arg": "indicesT",
138
- "semantic": "indices",
139
- "buffer": { "type": "read-only-storage" },
140
- "elementType": "$indexScalar"
141
- },
142
- {
143
- "name": "scales",
144
- "arg": "scalesT",
145
- "semantic": "scales",
146
- "buffer": { "type": "read-only-storage" },
147
- "elementType": "$scaleScalar"
148
- },
149
- {
150
- "name": "zero_points",
151
- "arg": "zeroPointsT",
152
- "semantic": "zero_points",
153
- "buffer": { "type": "read-only-storage" },
154
- "elementType": "$zeroPointElement"
155
- },
156
- {
157
- "name": "output",
158
- "arg": "outputT",
159
- "semantic": "output",
160
- "buffer": { "type": "storage" },
161
- "elementType": "$outputElement"
162
- },
163
- {
164
- "name": "params",
165
- "semantic": "kernel.params",
166
- "buffer": { "type": "uniform" },
167
- "struct": {
168
- "name": "Params",
169
- "fields": [
170
- { "name": "indexCount", "type": "u32", "value": "dim(shapes.indices, 0)" },
171
- { "name": "cols", "type": "u32", "value": "dim(shapes.output, 1)" },
172
- { "name": "packedCols", "type": "u32", "value": "dim(shapes.data, 1)" },
173
- { "name": "blocks", "type": "u32", "value": "dim(shapes.scales, 1)" },
174
- { "name": "blockSize", "type": "u32", "value": "blockSize" },
175
- { "name": "rows", "type": "u32", "value": "dim(shapes.data, 0)" }
176
- ]
177
- }
178
- }
179
- ],
180
- "noZeroIo": [
181
- {
182
- "name": "data",
183
- "arg": "dataT",
184
- "semantic": "data",
185
- "buffer": { "type": "read-only-storage" },
186
- "elementType": "$dataElement"
187
- },
188
- {
189
- "name": "indices",
190
- "arg": "indicesT",
191
- "semantic": "indices",
192
- "buffer": { "type": "read-only-storage" },
193
- "elementType": "$indexScalar"
194
- },
195
- {
196
- "name": "scales",
197
- "arg": "scalesT",
198
- "semantic": "scales",
199
- "buffer": { "type": "read-only-storage" },
200
- "elementType": "$scaleScalar"
201
- },
202
- {
203
- "name": "output",
204
- "arg": "outputT",
205
- "semantic": "output",
206
- "buffer": { "type": "storage" },
207
- "elementType": "$outputElement"
208
- }
209
- ],
210
- "zeroIo": [
211
- {
212
- "name": "data",
213
- "arg": "dataT",
214
- "semantic": "data",
215
- "buffer": { "type": "read-only-storage" },
216
- "elementType": "$dataElement"
217
- },
218
- {
219
- "name": "indices",
220
- "arg": "indicesT",
221
- "semantic": "indices",
222
- "buffer": { "type": "read-only-storage" },
223
- "elementType": "$indexScalar"
224
- },
225
- {
226
- "name": "scales",
227
- "arg": "scalesT",
228
- "semantic": "scales",
229
- "buffer": { "type": "read-only-storage" },
230
- "elementType": "$scaleScalar"
231
- },
232
- {
233
- "name": "zero_points",
234
- "arg": "zeroPointsT",
235
- "semantic": "zero_points",
236
- "buffer": { "type": "read-only-storage" },
237
- "elementType": "$zeroPointElement"
238
- },
239
- {
240
- "name": "output",
241
- "arg": "outputT",
242
- "semantic": "output",
243
- "buffer": { "type": "storage" },
244
- "elementType": "$outputElement"
245
- }
246
- ],
247
- "q4NoZero": [
248
- {
249
- "name": "data",
250
- "arg": "dataT",
251
- "semantic": "data",
252
- "buffer": { "type": "read-only-storage" },
253
- "elementType": "$dataElement"
254
- },
255
- {
256
- "name": "indices",
257
- "arg": "indicesT",
258
- "semantic": "indices",
259
- "buffer": { "type": "read-only-storage" },
260
- "elementType": "$indexScalar"
261
- },
262
- {
263
- "name": "scales",
264
- "arg": "scalesT",
265
- "semantic": "scales",
266
- "buffer": { "type": "read-only-storage" },
267
- "elementType": "$scaleScalar"
268
- },
269
- {
270
- "name": "output",
271
- "arg": "outputT",
272
- "semantic": "output",
273
- "buffer": { "type": "storage" },
274
- "elementType": "$outputElement"
275
- },
276
- {
277
- "name": "params",
278
- "semantic": "kernel.params",
279
- "buffer": { "type": "uniform" },
280
- "struct": {
281
- "name": "Params",
282
- "fields": [
283
- { "name": "indexCount", "type": "u32", "value": "dim(shapes.indices, 0)" },
284
- { "name": "packedCols", "type": "u32", "value": "dim(shapes.data, 1)" },
285
- { "name": "blocks", "type": "u32", "value": "dim(shapes.scales, 1)" },
286
- { "name": "blockSize", "type": "u32", "value": "blockSize" },
287
- { "name": "rows", "type": "u32", "value": "dim(shapes.data, 0)" }
288
- ]
289
- }
290
- }
291
- ],
292
- "q4Zero": [
293
- {
294
- "name": "data",
295
- "arg": "dataT",
296
- "semantic": "data",
297
- "buffer": { "type": "read-only-storage" },
298
- "elementType": "$dataElement"
299
- },
300
- {
301
- "name": "indices",
302
- "arg": "indicesT",
303
- "semantic": "indices",
304
- "buffer": { "type": "read-only-storage" },
305
- "elementType": "$indexScalar"
306
- },
307
- {
308
- "name": "scales",
309
- "arg": "scalesT",
310
- "semantic": "scales",
311
- "buffer": { "type": "read-only-storage" },
312
- "elementType": "$scaleScalar"
313
- },
314
- {
315
- "name": "zero_points",
316
- "arg": "zeroPointsT",
317
- "semantic": "zero_points",
318
- "buffer": { "type": "read-only-storage" },
319
- "elementType": "$zeroPointElement"
320
- },
321
- {
322
- "name": "output",
323
- "arg": "outputT",
324
- "semantic": "output",
325
- "buffer": { "type": "storage" },
326
- "elementType": "$outputElement"
327
- },
328
- {
329
- "name": "params",
330
- "semantic": "kernel.params",
331
- "buffer": { "type": "uniform" },
332
- "struct": {
333
- "name": "Params",
334
- "fields": [
335
- { "name": "indexCount", "type": "u32", "value": "dim(shapes.indices, 0)" },
336
- { "name": "packedCols", "type": "u32", "value": "dim(shapes.data, 1)" },
337
- { "name": "blocks", "type": "u32", "value": "dim(shapes.scales, 1)" },
338
- { "name": "zeroPointCols", "type": "u32", "value": "zeroPointCols" },
339
- { "name": "blockSize", "type": "u32", "value": "blockSize" },
340
- { "name": "rows", "type": "u32", "value": "dim(shapes.data, 0)" }
341
- ]
342
- }
343
- }
344
- ],
345
- "q8Vec4NoZero": [
346
- {
347
- "name": "data",
348
- "arg": "dataT",
349
- "semantic": "data",
350
- "buffer": { "type": "read-only-storage" },
351
- "elementType": "$dataElement"
352
- },
353
- {
354
- "name": "indices",
355
- "arg": "indicesT",
356
- "semantic": "indices",
357
- "buffer": { "type": "read-only-storage" },
358
- "elementType": "$indexScalar"
359
- },
360
- {
361
- "name": "scales",
362
- "arg": "scalesT",
363
- "semantic": "scales",
364
- "buffer": { "type": "read-only-storage" },
365
- "elementType": "$scaleScalar"
366
- },
367
- {
368
- "name": "output",
369
- "arg": "outputT",
370
- "semantic": "output",
371
- "buffer": { "type": "storage" },
372
- "elementType": "$outputElement"
373
- },
374
- {
375
- "name": "params",
376
- "semantic": "kernel.params",
377
- "buffer": { "type": "uniform" },
378
- "struct": {
379
- "name": "Params",
380
- "fields": [
381
- { "name": "indexCount", "type": "u32", "value": "dim(shapes.indices, 0)" },
382
- { "name": "cols", "type": "u32", "value": "dim(shapes.output, 1)" },
383
- { "name": "blocks", "type": "u32", "value": "dim(shapes.scales, 1)" },
384
- { "name": "blockSize", "type": "u32", "value": "blockSize" },
385
- { "name": "rows", "type": "u32", "value": "dim(shapes.data, 0)" }
386
- ]
387
- }
388
- }
389
- ],
390
- "q8Vec4Zero": [
391
- {
392
- "name": "data",
393
- "arg": "dataT",
394
- "semantic": "data",
395
- "buffer": { "type": "read-only-storage" },
396
- "elementType": "$dataElement"
397
- },
398
- {
399
- "name": "indices",
400
- "arg": "indicesT",
401
- "semantic": "indices",
402
- "buffer": { "type": "read-only-storage" },
403
- "elementType": "$indexScalar"
404
- },
405
- {
406
- "name": "scales",
407
- "arg": "scalesT",
408
- "semantic": "scales",
409
- "buffer": { "type": "read-only-storage" },
410
- "elementType": "$scaleScalar"
411
- },
412
- {
413
- "name": "zero_points",
414
- "arg": "zeroPointsT",
415
- "semantic": "zero_points",
416
- "buffer": { "type": "read-only-storage" },
417
- "elementType": "$zeroPointElement"
418
- },
419
- {
420
- "name": "output",
421
- "arg": "outputT",
422
- "semantic": "output",
423
- "buffer": { "type": "storage" },
424
- "elementType": "$outputElement"
425
- },
426
- {
427
- "name": "params",
428
- "semantic": "kernel.params",
429
- "buffer": { "type": "uniform" },
430
- "struct": {
431
- "name": "Params",
432
- "fields": [
433
- { "name": "indexCount", "type": "u32", "value": "dim(shapes.indices, 0)" },
434
- { "name": "cols", "type": "u32", "value": "dim(shapes.output, 1)" },
435
- { "name": "blocks", "type": "u32", "value": "dim(shapes.scales, 1)" },
436
- { "name": "blockSize", "type": "u32", "value": "blockSize" },
437
- { "name": "rows", "type": "u32", "value": "dim(shapes.data, 0)" }
438
- ]
439
- }
440
- }
441
- ]
442
  },
443
  "variants": [
444
  {
445
  "id": "q8_no_zero_vec4",
446
  "priority": 10,
447
- "when": ["q8ShapeValid", "noZeroMode", "bits == 8", "blockSize % 4 == 0", "dim(shapes.output, 1) % 4 == 0", "workgroupFits", "foldedDispatchFits"],
448
- "constants": {
449
  "hasZero": false,
450
  "scalarTail": false,
451
- "workgroupSize": "workgroupSize",
452
  "dataElement": "\"vec4<u32>\"",
453
  "indexScalar": "\"u32\"",
454
  "scaleScalar": "\"f32\"",
@@ -458,10 +116,11 @@
458
  {
459
  "id": "main",
460
  "shader": "gather-block-quantized-q8-vec4.wgsl.jinja",
461
- "bindings": "q8Vec4NoZero",
462
  "dispatch": {
463
- "threads": "dim(shapes.indices, 0) * (dim(shapes.output, 1) / 4)",
464
- "workgroupSize": "constants.workgroupSize"
 
465
  }
466
  }
467
  ]
@@ -469,10 +128,9 @@
469
  {
470
  "id": "q4_no_zero_pair",
471
  "priority": 10,
472
- "when": ["q4ShapeValid", "noZeroMode", "bits == 4", "workgroupFits", "foldedDispatchFits"],
473
- "constants": {
474
  "hasZero": false,
475
- "workgroupSize": "workgroupSize",
476
  "dataElement": "\"u32\"",
477
  "indexScalar": "\"u32\"",
478
  "scaleScalar": "\"f32\"",
@@ -482,10 +140,11 @@
482
  {
483
  "id": "main",
484
  "shader": "gather-block-quantized-q4-pair.wgsl.jinja",
485
- "bindings": "q4NoZero",
486
  "dispatch": {
487
- "threads": "dim(shapes.indices, 0) * dim(shapes.data, 1)",
488
- "workgroupSize": "constants.workgroupSize"
 
489
  }
490
  }
491
  ]
@@ -493,10 +152,9 @@
493
  {
494
  "id": "q4_zero_pair",
495
  "priority": 10,
496
- "when": ["q4ShapeValid", "zeroMode", "bits == 4", "workgroupFits", "foldedDispatchFits"],
497
- "constants": {
498
  "hasZero": true,
499
- "workgroupSize": "workgroupSize",
500
  "dataElement": "\"u32\"",
501
  "indexScalar": "\"u32\"",
502
  "scaleScalar": "\"f32\"",
@@ -507,10 +165,11 @@
507
  {
508
  "id": "main",
509
  "shader": "gather-block-quantized-q4-pair.wgsl.jinja",
510
- "bindings": "q4Zero",
511
  "dispatch": {
512
- "threads": "dim(shapes.indices, 0) * dim(shapes.data, 1)",
513
- "workgroupSize": "constants.workgroupSize"
 
514
  }
515
  }
516
  ]
@@ -518,11 +177,10 @@
518
  {
519
  "id": "q8_zero_vec4",
520
  "priority": 10,
521
- "when": ["q8ShapeValid", "zeroMode", "bits == 8", "blockSize % 4 == 0", "dim(shapes.output, 1) % 4 == 0", "workgroupFits", "foldedDispatchFits"],
522
- "constants": {
523
  "hasZero": true,
524
  "scalarTail": false,
525
- "workgroupSize": "workgroupSize",
526
  "dataElement": "\"vec4<u32>\"",
527
  "zeroPointElement": "\"u32\"",
528
  "indexScalar": "\"u32\"",
@@ -533,10 +191,11 @@
533
  {
534
  "id": "main",
535
  "shader": "gather-block-quantized-q8-vec4.wgsl.jinja",
536
- "bindings": "q8Vec4Zero",
537
  "dispatch": {
538
- "threads": "dim(shapes.indices, 0) * (dim(shapes.output, 1) / 4)",
539
- "workgroupSize": "constants.workgroupSize"
 
540
  }
541
  }
542
  ]
@@ -544,11 +203,10 @@
544
  {
545
  "id": "q8_no_zero_tail4",
546
  "priority": 5,
547
- "when": ["q8ShapeValid", "noZeroMode", "bits == 8", "workgroupFits", "foldedDispatchFits"],
548
- "constants": {
549
  "hasZero": false,
550
  "scalarTail": true,
551
- "workgroupSize": "workgroupSize",
552
  "dataElement": "\"u32\"",
553
  "indexScalar": "\"u32\"",
554
  "scaleScalar": "\"f32\"",
@@ -558,10 +216,11 @@
558
  {
559
  "id": "main",
560
  "shader": "gather-block-quantized-q8-vec4.wgsl.jinja",
561
- "bindings": "noZero",
562
  "dispatch": {
563
- "threads": "dim(shapes.indices, 0) * ceilDiv(dim(shapes.output, 1), 4)",
564
- "workgroupSize": "constants.workgroupSize"
 
565
  }
566
  }
567
  ]
@@ -569,11 +228,10 @@
569
  {
570
  "id": "q8_zero_tail4",
571
  "priority": 5,
572
- "when": ["q8ShapeValid", "zeroMode", "bits == 8", "workgroupFits", "foldedDispatchFits"],
573
- "constants": {
574
  "hasZero": true,
575
  "scalarTail": true,
576
- "workgroupSize": "workgroupSize",
577
  "dataElement": "\"u32\"",
578
  "indexScalar": "\"u32\"",
579
  "scaleScalar": "\"f32\"",
@@ -584,10 +242,11 @@
584
  {
585
  "id": "main",
586
  "shader": "gather-block-quantized-q8-vec4.wgsl.jinja",
587
- "bindings": "zero",
588
  "dispatch": {
589
- "threads": "dim(shapes.indices, 0) * ceilDiv(dim(shapes.output, 1), 4)",
590
- "workgroupSize": "constants.workgroupSize"
 
591
  }
592
  }
593
  ]
 
2
  "domain": "com.microsoft",
3
  "name": "GatherBlockQuantized",
4
  "sinceVersion": 1,
5
+ "inputs": {
6
+ "dataT": { "onnx": "data", "dtype": "T1", "rank": 2 },
7
+ "indicesT": { "onnx": "indices", "dtype": "Tind", "rank": 1, "storage": "uint32", "narrowing": "checked" },
8
+ "scalesT": { "onnx": "scales", "dtype": "T2", "rank": 2 },
9
+ "zeroPointsT": { "onnx": "zero_points", "dtype": "T1", "rank": 2, "optional": true }
10
+ },
11
+ "outputs": {
12
+ "outputT": {
13
+ "onnx": "output",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  "dtype": "T2",
15
  "rank": 2,
16
+ "shape": "[dim(shapes.indicesT, 0), dim(shapes.dataT, 1) * (8 / attrs.bits)]"
 
17
  }
18
+ },
19
+ "attributes": {
20
+ "bits": { "default": 4 },
21
+ "block_size": { "default": 128 },
22
+ "gather_axis": { "default": 0 },
23
+ "quantize_axis": { "default": 1 }
24
+ },
25
  "attributeConstraints": {
26
  "bits": { "values": [4, 8] },
27
  "gather_axis": { "values": [0] },
28
  "quantize_axis": { "values": [1] }
29
  },
 
 
 
 
 
 
30
  "typeConstraints": { "T1": ["uint8"], "T2": ["float32"], "Tind": ["int64"] },
31
+ "tunables": { "WORKGROUP_SIZE": { "default": 64 } },
 
 
 
 
 
 
32
  "derive": {
33
  "deviceWorkgroupCap": "min(device.limits.maxComputeInvocationsPerWorkgroup, device.limits.maxComputeWorkgroupSizeX)",
34
  "bits": "attrs.bits",
35
  "blockSize": "attrs.block_size",
36
  "blockSizeOk": "blockSize >= 16 and pow2ceil(blockSize) == blockSize",
37
+ "outBlocks": "ceilDiv(dim(shapes.outputT, 1), blockSize)",
38
  "zeroPointCols": "ceilDiv(outBlocks, 2) if bits == 4 else outBlocks",
39
  "workgroupSize": "min(tunables.WORKGROUP_SIZE, deviceWorkgroupCap)",
40
+ "commonShapeValid": "blockSizeOk and ranks.dataT == 2 and ranks.indicesT == 1 and ranks.scalesT == 2 and ranks.outputT == 2 and tensorDtypes.indicesT == \"uint32\" and tensorDtypes.scalesT == \"float32\" and tensorDtypes.outputT == \"float32\" and dim(shapes.outputT, 0) == dim(shapes.indicesT, 0) and dim(shapes.scalesT, 0) == dim(shapes.dataT, 0) and dim(shapes.scalesT, 1) == outBlocks",
41
+ "q4ShapeValid": "commonShapeValid and tensorDtypes.dataT == \"uint8\" and dim(shapes.outputT, 1) == dim(shapes.dataT, 1) * 2",
42
+ "q8ShapeValid": "commonShapeValid and tensorDtypes.dataT == \"uint8\" and dim(shapes.outputT, 1) == dim(shapes.dataT, 1)",
43
+ "zeroPointsValid": "present.zeroPointsT and ranks.zeroPointsT == 2 and tensorDtypes.zeroPointsT == \"uint8\" and dim(shapes.zeroPointsT, 0) == dim(shapes.dataT, 0) and dim(shapes.zeroPointsT, 1) == zeroPointCols",
44
  "noZeroMode": "not present.zeroPointsT",
45
  "zeroMode": "zeroPointsValid",
46
  "workgroupFits": "workgroupSize > 0",
47
+ "foldedDispatchFits": "ceil(ceil(numel(shapes.outputT) / min(device.limits.maxComputeWorkgroupsPerDimension, 65535)) / workgroupSize) <= min(device.limits.maxComputeWorkgroupsPerDimension, 65535)"
48
  },
49
+ "when": ["foldedDispatchFits", "workgroupFits"],
50
+ "bindings": {
51
+ "data": { "arg": "dataT", "buffer": "read-only-storage", "elementType": "$dataElement" },
52
+ "indices": { "arg": "indicesT", "buffer": "read-only-storage", "elementType": "$indexScalar" },
53
+ "scales": { "arg": "scalesT", "buffer": "read-only-storage", "elementType": "$scaleScalar" },
54
+ "output": { "arg": "outputT", "buffer": "storage", "elementType": "$outputElement" },
55
+ "params": {
56
+ "buffer": "uniform",
57
+ "struct": [
58
+ { "name": "indexCount", "type": "u32", "value": "dim(shapes.indicesT, 0)" },
59
+ { "name": "cols", "type": "u32", "value": "dim(shapes.outputT, 1)" },
60
+ { "name": "blocks", "type": "u32", "value": "dim(shapes.scalesT, 1)" },
61
+ { "name": "blockSize", "type": "u32", "value": "blockSize" },
62
+ { "name": "rows", "type": "u32", "value": "dim(shapes.dataT, 0)" }
63
+ ]
64
+ },
65
+ "params_2": {
66
+ "name": "params",
67
+ "buffer": "uniform",
68
+ "struct": [
69
+ { "name": "indexCount", "type": "u32", "value": "dim(shapes.indicesT, 0)" },
70
+ { "name": "packedCols", "type": "u32", "value": "dim(shapes.dataT, 1)" },
71
+ { "name": "blocks", "type": "u32", "value": "dim(shapes.scalesT, 1)" },
72
+ { "name": "blockSize", "type": "u32", "value": "blockSize" },
73
+ { "name": "rows", "type": "u32", "value": "dim(shapes.dataT, 0)" }
74
+ ]
75
+ },
76
+ "zero_points": { "arg": "zeroPointsT", "buffer": "read-only-storage", "elementType": "$zeroPointElement" },
77
+ "params_3": {
78
+ "name": "params",
79
+ "buffer": "uniform",
80
+ "struct": [
81
+ { "name": "indexCount", "type": "u32", "value": "dim(shapes.indicesT, 0)" },
82
+ { "name": "packedCols", "type": "u32", "value": "dim(shapes.dataT, 1)" },
83
+ { "name": "blocks", "type": "u32", "value": "dim(shapes.scalesT, 1)" },
84
+ { "name": "zeroPointCols", "type": "u32", "value": "zeroPointCols" },
85
+ { "name": "blockSize", "type": "u32", "value": "blockSize" },
86
+ { "name": "rows", "type": "u32", "value": "dim(shapes.dataT, 0)" }
87
+ ]
88
+ },
89
+ "params_4": {
90
+ "name": "params",
91
+ "buffer": "uniform",
92
+ "struct": [
93
+ { "name": "indexCount", "type": "u32", "value": "dim(shapes.indicesT, 0)" },
94
+ { "name": "cols", "type": "u32", "value": "dim(shapes.outputT, 1)" },
95
+ { "name": "packedCols", "type": "u32", "value": "dim(shapes.dataT, 1)" },
96
+ { "name": "blocks", "type": "u32", "value": "dim(shapes.scalesT, 1)" },
97
+ { "name": "blockSize", "type": "u32", "value": "blockSize" },
98
+ { "name": "rows", "type": "u32", "value": "dim(shapes.dataT, 0)" }
99
+ ]
100
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
  },
102
  "variants": [
103
  {
104
  "id": "q8_no_zero_vec4",
105
  "priority": 10,
106
+ "when": ["q8ShapeValid", "noZeroMode", "bits == 8", "blockSize % 4 == 0", "dim(shapes.outputT, 1) % 4 == 0"],
107
+ "derive": {
108
  "hasZero": false,
109
  "scalarTail": false,
 
110
  "dataElement": "\"vec4<u32>\"",
111
  "indexScalar": "\"u32\"",
112
  "scaleScalar": "\"f32\"",
 
116
  {
117
  "id": "main",
118
  "shader": "gather-block-quantized-q8-vec4.wgsl.jinja",
119
+ "bindings": ["data", "indices", "scales", "output", "params"],
120
  "dispatch": {
121
+ "x": "min(ceilDiv((dim(shapes.indicesT, 0) * (dim(shapes.outputT, 1) / 4)), (workgroupSize)), 65535)",
122
+ "y": "ceilDiv(ceilDiv((dim(shapes.indicesT, 0) * (dim(shapes.outputT, 1) / 4)), (workgroupSize)), 65535)",
123
+ "z": 1
124
  }
125
  }
126
  ]
 
128
  {
129
  "id": "q4_no_zero_pair",
130
  "priority": 10,
131
+ "when": ["q4ShapeValid", "noZeroMode", "bits == 4"],
132
+ "derive": {
133
  "hasZero": false,
 
134
  "dataElement": "\"u32\"",
135
  "indexScalar": "\"u32\"",
136
  "scaleScalar": "\"f32\"",
 
140
  {
141
  "id": "main",
142
  "shader": "gather-block-quantized-q4-pair.wgsl.jinja",
143
+ "bindings": ["data", "indices", "scales", "output", "params_2"],
144
  "dispatch": {
145
+ "x": "min(ceilDiv((dim(shapes.indicesT, 0) * dim(shapes.dataT, 1)), (workgroupSize)), 65535)",
146
+ "y": "ceilDiv(ceilDiv((dim(shapes.indicesT, 0) * dim(shapes.dataT, 1)), (workgroupSize)), 65535)",
147
+ "z": 1
148
  }
149
  }
150
  ]
 
152
  {
153
  "id": "q4_zero_pair",
154
  "priority": 10,
155
+ "when": ["q4ShapeValid", "zeroMode", "bits == 4"],
156
+ "derive": {
157
  "hasZero": true,
 
158
  "dataElement": "\"u32\"",
159
  "indexScalar": "\"u32\"",
160
  "scaleScalar": "\"f32\"",
 
165
  {
166
  "id": "main",
167
  "shader": "gather-block-quantized-q4-pair.wgsl.jinja",
168
+ "bindings": ["data", "indices", "scales", "zero_points", "output", "params_3"],
169
  "dispatch": {
170
+ "x": "min(ceilDiv((dim(shapes.indicesT, 0) * dim(shapes.dataT, 1)), (workgroupSize)), 65535)",
171
+ "y": "ceilDiv(ceilDiv((dim(shapes.indicesT, 0) * dim(shapes.dataT, 1)), (workgroupSize)), 65535)",
172
+ "z": 1
173
  }
174
  }
175
  ]
 
177
  {
178
  "id": "q8_zero_vec4",
179
  "priority": 10,
180
+ "when": ["q8ShapeValid", "zeroMode", "bits == 8", "blockSize % 4 == 0", "dim(shapes.outputT, 1) % 4 == 0"],
181
+ "derive": {
182
  "hasZero": true,
183
  "scalarTail": false,
 
184
  "dataElement": "\"vec4<u32>\"",
185
  "zeroPointElement": "\"u32\"",
186
  "indexScalar": "\"u32\"",
 
191
  {
192
  "id": "main",
193
  "shader": "gather-block-quantized-q8-vec4.wgsl.jinja",
194
+ "bindings": ["data", "indices", "scales", "zero_points", "output", "params"],
195
  "dispatch": {
196
+ "x": "min(ceilDiv((dim(shapes.indicesT, 0) * (dim(shapes.outputT, 1) / 4)), (workgroupSize)), 65535)",
197
+ "y": "ceilDiv(ceilDiv((dim(shapes.indicesT, 0) * (dim(shapes.outputT, 1) / 4)), (workgroupSize)), 65535)",
198
+ "z": 1
199
  }
200
  }
201
  ]
 
203
  {
204
  "id": "q8_no_zero_tail4",
205
  "priority": 5,
206
+ "when": ["q8ShapeValid", "noZeroMode", "bits == 8"],
207
+ "derive": {
208
  "hasZero": false,
209
  "scalarTail": true,
 
210
  "dataElement": "\"u32\"",
211
  "indexScalar": "\"u32\"",
212
  "scaleScalar": "\"f32\"",
 
216
  {
217
  "id": "main",
218
  "shader": "gather-block-quantized-q8-vec4.wgsl.jinja",
219
+ "bindings": ["data", "indices", "scales", "output", "params_4"],
220
  "dispatch": {
221
+ "x": "min(ceilDiv((dim(shapes.indicesT, 0) * ceilDiv(dim(shapes.outputT, 1), 4)), (workgroupSize)), 65535)",
222
+ "y": "ceilDiv(ceilDiv((dim(shapes.indicesT, 0) * ceilDiv(dim(shapes.outputT, 1), 4)), (workgroupSize)), 65535)",
223
+ "z": 1
224
  }
225
  }
226
  ]
 
228
  {
229
  "id": "q8_zero_tail4",
230
  "priority": 5,
231
+ "when": ["q8ShapeValid", "zeroMode", "bits == 8"],
232
+ "derive": {
233
  "hasZero": true,
234
  "scalarTail": true,
 
235
  "dataElement": "\"u32\"",
236
  "indexScalar": "\"u32\"",
237
  "scaleScalar": "\"f32\"",
 
242
  {
243
  "id": "main",
244
  "shader": "gather-block-quantized-q8-vec4.wgsl.jinja",
245
+ "bindings": ["data", "indices", "scales", "zero_points", "output", "params_4"],
246
  "dispatch": {
247
+ "x": "min(ceilDiv((dim(shapes.indicesT, 0) * ceilDiv(dim(shapes.outputT, 1), 4)), (workgroupSize)), 65535)",
248
+ "y": "ceilDiv(ceilDiv((dim(shapes.indicesT, 0) * ceilDiv(dim(shapes.outputT, 1), 4)), (workgroupSize)), 65535)",
249
+ "z": 1
250
  }
251
  }
252
  ]
build/webgpu/metadata.json CHANGED
@@ -1,19 +1,29 @@
1
  {
2
  "name": "com.microsoft.GatherBlockQuantized",
3
- "id": "_com_microsoft_gatherblockquantized_webgpu_88e1761",
4
  "version": 1,
5
  "license": "Apache-2.0",
6
  "backend": { "type": "webgpu" },
7
  "digest": {
8
  "algorithm": "sha256",
9
  "files": {
10
- "bench.json": "Pi6+cheiVelf+nINEm8o7zLFULpK/8jCmL8+6Jlp9I8=",
11
- "gather-block-quantized-q4-pair.wgsl.jinja": "U+OSY+xymDWP4cMqTJneiOhIv+Sfazov3A7s3gplCXI=",
12
- "gather-block-quantized-q8-vec4.wgsl.jinja": "YKplb0sTVxSB/jvuYiQ3HFxNR6sTBp206dp5EEi4TNM=",
13
- "manifest.json": "On/e3F5KW0FA0mt8SUJXckCZKr4EZrxPKZS9JrQdvKU=",
14
- "test.json": "XEZF0vZ5ZbO6reeoRXjDL1hLXosLscWnzfZjtHIr9aU="
15
  }
16
  },
17
- "provenance": { "kernel": { "sha": "2e7068faf55e7f43df740015f6d1ee49391a41c5", "dirty": false } },
18
- "webgpu": { "manifestSpec": "1.0", "specialized": true, "opPath": "ops/com.microsoft.GatherBlockQuantized" }
 
 
 
 
 
 
 
 
 
 
19
  }
 
1
  {
2
  "name": "com.microsoft.GatherBlockQuantized",
3
+ "id": "_com_microsoft_gatherblockquantized_webgpu_dceac49",
4
  "version": 1,
5
  "license": "Apache-2.0",
6
  "backend": { "type": "webgpu" },
7
  "digest": {
8
  "algorithm": "sha256",
9
  "files": {
10
+ "bench.json": "iQN5nfNOefh08J/5z4Vc63omCfclP0JZggomZracQjI=",
11
+ "gather-block-quantized-q4-pair.wgsl.jinja": "9LBelD9NWvia8DuYSL/FCXreyJ6mLtpiiddFdbronSM=",
12
+ "gather-block-quantized-q8-vec4.wgsl.jinja": "3RQDkgbVbh8TiZZzROkXVWxlFTYBgz4IqY27DOvuVyY=",
13
+ "manifest.json": "3+GjaCq6H0K41bzVOxcw9rg9vf0MVERgqWjUqBgopq4=",
14
+ "test.json": "+2tkFsiI9bP4xaQI+hw2wX3CbMkCEqUzgTHYrTAL6bg="
15
  }
16
  },
17
+ "provenance": { "kernel": { "sha": "91d990483a174128daf7673f3f37a7c890493ae1", "dirty": false } },
18
+ "webgpu": {
19
+ "manifestSpec": "2.0",
20
+ "variants": {
21
+ "q8_no_zero_vec4": ["gather-block-quantized-q8-vec4.wgsl.jinja"],
22
+ "q4_no_zero_pair": ["gather-block-quantized-q4-pair.wgsl.jinja"],
23
+ "q4_zero_pair": ["gather-block-quantized-q4-pair.wgsl.jinja"],
24
+ "q8_zero_vec4": ["gather-block-quantized-q8-vec4.wgsl.jinja"],
25
+ "q8_no_zero_tail4": ["gather-block-quantized-q8-vec4.wgsl.jinja"],
26
+ "q8_zero_tail4": ["gather-block-quantized-q8-vec4.wgsl.jinja"]
27
+ }
28
+ }
29
  }
build/webgpu/test.json CHANGED
@@ -1,5 +1,4 @@
1
  {
2
- "op": "com.microsoft.GatherBlockQuantized",
3
  "fixtureArrays": {
4
  "ort_q8_no_zero_input_dataT": [0, 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, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63],
5
  "q8_no_zero_multiblock_vec4_cols32_input_dataT": [0, 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, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127]
@@ -32,7 +31,7 @@
32
  "provenance": {
33
  "source": "onnxruntime/test/python/transformers/test_cuda_plugin_ep.py",
34
  "test": "TestCudaPluginEP.test_op_gather_block_quantized",
35
- "notes": "Pinned. With zero_points omitted the default zero point is 2^(bits-1) = 128 at 8 bits, because `data` is unsigned storage for signed values offset by the midpoint; the cited test states this and ORT's kernel applies it in the uint8 branch of contrib_ops/cpu/quantization/gather_block_quantized.cc. Values are chosen so every expected element is exact in f32 and the two rows use different scales, so a wrong default shifts each row by a different amount rather than by a common offset."
36
  },
37
  "attrs": { "bits": 8, "block_size": 16 },
38
  "inputs": {
@@ -124,7 +123,7 @@
124
  {
125
  "name": "q8_no_zero_wide_vec4_cols256_idx64",
126
  "provenance": {
127
- "notes": "Compact sibling for the q8 wide-column gather benchmark; preserves no-zero-point q8, blockSize=32, vec4-aligned columns, many gathered rows, and multiple scale blocks per source row."
128
  },
129
  "attrs": { "bits": 8, "block_size": 32 },
130
  "inputs": {
 
1
  {
 
2
  "fixtureArrays": {
3
  "ort_q8_no_zero_input_dataT": [0, 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, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63],
4
  "q8_no_zero_multiblock_vec4_cols32_input_dataT": [0, 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, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127]
 
31
  "provenance": {
32
  "source": "onnxruntime/test/python/transformers/test_cuda_plugin_ep.py",
33
  "test": "TestCudaPluginEP.test_op_gather_block_quantized",
34
+ "notes": "With zero_points omitted, the default is 2^(bits-1) = 128 at 8 bits: unsigned storage represents signed values offset by the midpoint. Expected values are exact in float32; different row scales make an incorrect zero point shift the two rows by different amounts."
35
  },
36
  "attrs": { "bits": 8, "block_size": 16 },
37
  "inputs": {
 
123
  {
124
  "name": "q8_no_zero_wide_vec4_cols256_idx64",
125
  "provenance": {
126
+ "notes": "A compact q8 gather uses block size 32, the default zero point, four-wide aligned columns, many gathered rows, and multiple scale blocks per source row."
127
  },
128
  "attrs": { "bits": 8, "block_size": 32 },
129
  "inputs": {