Xenova HF Staff commited on
Commit
b245084
·
verified ·
1 Parent(s): 02f8aff

sync 6fdf6301e2bb

Browse files
README.md CHANGED
@@ -42,12 +42,19 @@ Default values (overridable per request):
42
  | --- | --- |
43
  | `T` | `float32`, `float16` |
44
 
 
 
 
 
 
 
45
  ## Files
46
 
47
  - [`metadata.json`](build/webgpu/metadata.json) — kernel metadata (id, digests, per-variant templates, provenance)
48
  - [`manifest.json`](build/webgpu/manifest.json) — the op contract (source of truth)
49
  - [`test.json`](build/webgpu/test.json) — correctness cases
50
- - [`bench.json`](build/webgpu/bench.json) — benchmark + tuning cases
 
51
  - [`mean-variance-normalization-serial-rows.wgsl.jinja`](build/webgpu/mean-variance-normalization-serial-rows.wgsl.jinja)
52
  - [`mean-variance-normalization-subgroup.wgsl.jinja`](build/webgpu/mean-variance-normalization-subgroup.wgsl.jinja)
53
  - [`noop.wgsl.jinja`](build/webgpu/noop.wgsl.jinja)
@@ -58,7 +65,7 @@ Default values (overridable per request):
58
  ## Use with `@huggingface/kernels`
59
 
60
  ```sh
61
- npm install --save-exact @huggingface/kernels@0.0.1-preview.2
62
  ```
63
 
64
  Required output shapes and logical data types are inferred from the supplied inputs and attributes; result tensors are allocated automatically.
@@ -72,5 +79,5 @@ Replace each `*Data` placeholder with a typed array containing the corresponding
72
  import { getKernel } from "@huggingface/kernels";
73
 
74
  const kernel = await getKernel("webgpu-kernels/ai.onnx.MeanVarianceNormalization", { version: 1 });
75
- const { y } = await kernel({ x: { data: xData, shape: [2, 2, 1, 2] } });
76
  ```
 
42
  | --- | --- |
43
  | `T` | `float32`, `float16` |
44
 
45
+ ## Implementation variants
46
+
47
+ One implementation is selected per call from the device capabilities, the request shapes and the dtypes; these notes say what each one covers.
48
+
49
+ - `packed_short_groups` — Caches contiguous short groups in vector words, uses scaled shifted moments, and guards scalar access for partial words.
50
+
51
  ## Files
52
 
53
  - [`metadata.json`](build/webgpu/metadata.json) — kernel metadata (id, digests, per-variant templates, provenance)
54
  - [`manifest.json`](build/webgpu/manifest.json) — the op contract (source of truth)
55
  - [`test.json`](build/webgpu/test.json) — correctness cases
56
+ - [`bench.json`](build/webgpu/bench.json) — benchmark cases
57
+ - [`mean-variance-normalization-packed-rows.wgsl.jinja`](build/webgpu/mean-variance-normalization-packed-rows.wgsl.jinja)
58
  - [`mean-variance-normalization-serial-rows.wgsl.jinja`](build/webgpu/mean-variance-normalization-serial-rows.wgsl.jinja)
59
  - [`mean-variance-normalization-subgroup.wgsl.jinja`](build/webgpu/mean-variance-normalization-subgroup.wgsl.jinja)
60
  - [`noop.wgsl.jinja`](build/webgpu/noop.wgsl.jinja)
 
65
  ## Use with `@huggingface/kernels`
66
 
67
  ```sh
68
+ npm install --save-exact @huggingface/kernels@0.0.1-preview.3
69
  ```
70
 
71
  Required output shapes and logical data types are inferred from the supplied inputs and attributes; result tensors are allocated automatically.
 
79
  import { getKernel } from "@huggingface/kernels";
80
 
81
  const kernel = await getKernel("webgpu-kernels/ai.onnx.MeanVarianceNormalization", { version: 1 });
82
+ const { y } = await kernel({ x: { data: xData, shape: [1, 1, 2, 2] } });
83
  ```
build/webgpu/bench.json CHANGED
@@ -99,7 +99,282 @@
99
  "attrs": { "axes": [2] },
100
  "inputs": { "x": { "dtype": "float32", "shape": [4194304, 1, 2], "dist": "normal", "seed": 951, "scale": 0.5 } },
101
  "outputs": { "y": { "dtype": "float32", "shape": [4194304, 1, 2] } },
102
- "bench": { "metrics": [{ "type": "bandwidth", "value": "3 * 4 * numel(shapes.x)" }] }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
  }
104
  ]
105
  }
 
99
  "attrs": { "axes": [2] },
100
  "inputs": { "x": { "dtype": "float32", "shape": [4194304, 1, 2], "dist": "normal", "seed": 951, "scale": 0.5 } },
101
  "outputs": { "y": { "dtype": "float32", "shape": [4194304, 1, 2] } },
102
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "2 * 4 * numel(shapes.x)" }] },
103
+ "provenance": { "notes": "The bandwidth metric counts each input and output element once." }
104
+ },
105
+ {
106
+ "name": "packed_float32_rows1048576_r2",
107
+ "preset": "stress",
108
+ "attrs": { "axes": [2] },
109
+ "inputs": { "x": { "dtype": "float32", "shape": [1048576, 1, 2], "dist": "normal", "seed": 951, "scale": 0.5 } },
110
+ "outputs": { "y": { "dtype": "float32", "shape": [1048576, 1, 2] } },
111
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "2 * 4 * numel(shapes.x)" }] },
112
+ "tunableSpace": { "PACKED_WORKGROUP_SIZE": [64, 512] }
113
+ },
114
+ {
115
+ "name": "packed_float32_rows4194239_r2",
116
+ "preset": "stress",
117
+ "attrs": { "axes": [2] },
118
+ "inputs": { "x": { "dtype": "float32", "shape": [4194239, 1, 2], "dist": "normal", "seed": 951, "scale": 0.5 } },
119
+ "outputs": { "y": { "dtype": "float32", "shape": [4194239, 1, 2] } },
120
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "2 * 4 * numel(shapes.x)" }] }
121
+ },
122
+ {
123
+ "name": "packed_float32_rows4194240_r2",
124
+ "preset": "stress",
125
+ "attrs": { "axes": [2] },
126
+ "inputs": { "x": { "dtype": "float32", "shape": [4194240, 1, 2], "dist": "normal", "seed": 951, "scale": 0.5 } },
127
+ "outputs": { "y": { "dtype": "float32", "shape": [4194240, 1, 2] } },
128
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "2 * 4 * numel(shapes.x)" }] }
129
+ },
130
+ {
131
+ "name": "packed_float32_rows4194241_r2",
132
+ "preset": "stress",
133
+ "attrs": { "axes": [2] },
134
+ "inputs": { "x": { "dtype": "float32", "shape": [4194241, 1, 2], "dist": "normal", "seed": 951, "scale": 0.5 } },
135
+ "outputs": { "y": { "dtype": "float32", "shape": [4194241, 1, 2] } },
136
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "2 * 4 * numel(shapes.x)" }] }
137
+ },
138
+ {
139
+ "name": "packed_float32_rows4194304_r3",
140
+ "preset": "stress",
141
+ "attrs": { "axes": [2] },
142
+ "inputs": { "x": { "dtype": "float32", "shape": [4194304, 1, 3], "dist": "normal", "seed": 951, "scale": 0.5 } },
143
+ "outputs": { "y": { "dtype": "float32", "shape": [4194304, 1, 3] } },
144
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "2 * 4 * numel(shapes.x)" }] }
145
+ },
146
+ {
147
+ "name": "packed_float32_rows2097152_r4",
148
+ "preset": "stress",
149
+ "attrs": { "axes": [2] },
150
+ "inputs": { "x": { "dtype": "float32", "shape": [2097152, 1, 4], "dist": "normal", "seed": 951, "scale": 0.5 } },
151
+ "outputs": { "y": { "dtype": "float32", "shape": [2097152, 1, 4] } },
152
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "2 * 4 * numel(shapes.x)" }] }
153
+ },
154
+ {
155
+ "name": "packed_float32_rows255_r3",
156
+ "preset": "stress",
157
+ "attrs": { "axes": [2] },
158
+ "inputs": { "x": { "dtype": "float32", "shape": [255, 1, 3], "dist": "normal", "seed": 951, "scale": 0.5 } },
159
+ "outputs": { "y": { "dtype": "float32", "shape": [255, 1, 3] } },
160
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "2 * 4 * numel(shapes.x)" }] }
161
+ },
162
+ {
163
+ "name": "packed_float32_rows256_r3",
164
+ "preset": "stress",
165
+ "attrs": { "axes": [2] },
166
+ "inputs": { "x": { "dtype": "float32", "shape": [256, 1, 3], "dist": "normal", "seed": 951, "scale": 0.5 } },
167
+ "outputs": { "y": { "dtype": "float32", "shape": [256, 1, 3] } },
168
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "2 * 4 * numel(shapes.x)" }] }
169
+ },
170
+ {
171
+ "name": "packed_float32_rows257_r3",
172
+ "preset": "stress",
173
+ "attrs": { "axes": [2] },
174
+ "inputs": { "x": { "dtype": "float32", "shape": [257, 1, 3], "dist": "normal", "seed": 951, "scale": 0.5 } },
175
+ "outputs": { "y": { "dtype": "float32", "shape": [257, 1, 3] } },
176
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "2 * 4 * numel(shapes.x)" }] }
177
+ },
178
+ {
179
+ "name": "packed_float32_rows513_r4",
180
+ "preset": "stress",
181
+ "attrs": { "axes": [2] },
182
+ "inputs": { "x": { "dtype": "float32", "shape": [513, 1, 4], "dist": "normal", "seed": 951, "scale": 0.5 } },
183
+ "outputs": { "y": { "dtype": "float32", "shape": [513, 1, 4] } },
184
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "2 * 4 * numel(shapes.x)" }] }
185
+ },
186
+ {
187
+ "name": "packed_float32_rows65537_r3",
188
+ "preset": "stress",
189
+ "attrs": { "axes": [2] },
190
+ "inputs": { "x": { "dtype": "float32", "shape": [65537, 1, 3], "dist": "normal", "seed": 951, "scale": 0.5 } },
191
+ "outputs": { "y": { "dtype": "float32", "shape": [65537, 1, 3] } },
192
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "2 * 4 * numel(shapes.x)" }] }
193
+ },
194
+ {
195
+ "name": "packed_float16_rows1048576_r2",
196
+ "preset": "stress",
197
+ "attrs": { "axes": [2] },
198
+ "inputs": { "x": { "dtype": "float16", "shape": [1048576, 1, 2], "dist": "normal", "seed": 951, "scale": 0.5 } },
199
+ "outputs": { "y": { "dtype": "float16", "shape": [1048576, 1, 2] } },
200
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "2 * 2 * numel(shapes.x)" }] },
201
+ "tunableSpace": { "PACKED_WORKGROUP_SIZE": [64, 512] }
202
+ },
203
+ {
204
+ "name": "packed_float16_rows4194239_r2",
205
+ "preset": "stress",
206
+ "attrs": { "axes": [2] },
207
+ "inputs": { "x": { "dtype": "float16", "shape": [4194239, 1, 2], "dist": "normal", "seed": 951, "scale": 0.5 } },
208
+ "outputs": { "y": { "dtype": "float16", "shape": [4194239, 1, 2] } },
209
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "2 * 2 * numel(shapes.x)" }] }
210
+ },
211
+ {
212
+ "name": "packed_float16_rows4194240_r2",
213
+ "preset": "stress",
214
+ "attrs": { "axes": [2] },
215
+ "inputs": { "x": { "dtype": "float16", "shape": [4194240, 1, 2], "dist": "normal", "seed": 951, "scale": 0.5 } },
216
+ "outputs": { "y": { "dtype": "float16", "shape": [4194240, 1, 2] } },
217
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "2 * 2 * numel(shapes.x)" }] }
218
+ },
219
+ {
220
+ "name": "packed_float16_rows4194241_r2",
221
+ "preset": "stress",
222
+ "attrs": { "axes": [2] },
223
+ "inputs": { "x": { "dtype": "float16", "shape": [4194241, 1, 2], "dist": "normal", "seed": 951, "scale": 0.5 } },
224
+ "outputs": { "y": { "dtype": "float16", "shape": [4194241, 1, 2] } },
225
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "2 * 2 * numel(shapes.x)" }] }
226
+ },
227
+ {
228
+ "name": "packed_float16_rows4194304_r3",
229
+ "preset": "stress",
230
+ "attrs": { "axes": [2] },
231
+ "inputs": { "x": { "dtype": "float16", "shape": [4194304, 1, 3], "dist": "normal", "seed": 951, "scale": 0.5 } },
232
+ "outputs": { "y": { "dtype": "float16", "shape": [4194304, 1, 3] } },
233
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "2 * 2 * numel(shapes.x)" }] }
234
+ },
235
+ {
236
+ "name": "packed_float16_rows2097152_r4",
237
+ "preset": "stress",
238
+ "attrs": { "axes": [2] },
239
+ "inputs": { "x": { "dtype": "float16", "shape": [2097152, 1, 4], "dist": "normal", "seed": 951, "scale": 0.5 } },
240
+ "outputs": { "y": { "dtype": "float16", "shape": [2097152, 1, 4] } },
241
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "2 * 2 * numel(shapes.x)" }] }
242
+ },
243
+ {
244
+ "name": "packed_float16_rows255_r3",
245
+ "preset": "stress",
246
+ "attrs": { "axes": [2] },
247
+ "inputs": { "x": { "dtype": "float16", "shape": [255, 1, 3], "dist": "normal", "seed": 951, "scale": 0.5 } },
248
+ "outputs": { "y": { "dtype": "float16", "shape": [255, 1, 3] } },
249
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "2 * 2 * numel(shapes.x)" }] }
250
+ },
251
+ {
252
+ "name": "packed_float16_rows256_r3",
253
+ "preset": "stress",
254
+ "attrs": { "axes": [2] },
255
+ "inputs": { "x": { "dtype": "float16", "shape": [256, 1, 3], "dist": "normal", "seed": 951, "scale": 0.5 } },
256
+ "outputs": { "y": { "dtype": "float16", "shape": [256, 1, 3] } },
257
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "2 * 2 * numel(shapes.x)" }] }
258
+ },
259
+ {
260
+ "name": "packed_float16_rows257_r3",
261
+ "preset": "stress",
262
+ "attrs": { "axes": [2] },
263
+ "inputs": { "x": { "dtype": "float16", "shape": [257, 1, 3], "dist": "normal", "seed": 951, "scale": 0.5 } },
264
+ "outputs": { "y": { "dtype": "float16", "shape": [257, 1, 3] } },
265
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "2 * 2 * numel(shapes.x)" }] }
266
+ },
267
+ {
268
+ "name": "packed_float16_rows513_r4",
269
+ "preset": "stress",
270
+ "attrs": { "axes": [2] },
271
+ "inputs": { "x": { "dtype": "float16", "shape": [513, 1, 4], "dist": "normal", "seed": 951, "scale": 0.5 } },
272
+ "outputs": { "y": { "dtype": "float16", "shape": [513, 1, 4] } },
273
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "2 * 2 * numel(shapes.x)" }] }
274
+ },
275
+ {
276
+ "name": "packed_float16_rows65537_r3",
277
+ "preset": "stress",
278
+ "attrs": { "axes": [2] },
279
+ "inputs": { "x": { "dtype": "float16", "shape": [65537, 1, 3], "dist": "normal", "seed": 951, "scale": 0.5 } },
280
+ "outputs": { "y": { "dtype": "float16", "shape": [65537, 1, 3] } },
281
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "2 * 2 * numel(shapes.x)" }] }
282
+ },
283
+ {
284
+ "name": "cached_small_float32_r2",
285
+ "preset": "stress",
286
+ "attrs": { "axes": [2] },
287
+ "inputs": { "x": { "dtype": "float32", "shape": [2, 1, 2], "dist": "normal", "seed": 951, "scale": 0.5 } },
288
+ "outputs": { "y": { "dtype": "float32", "shape": [2, 1, 2] } },
289
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "2 * 4 * numel(shapes.x)" }] }
290
+ },
291
+ {
292
+ "name": "cached_strided_float32_r2",
293
+ "preset": "stress",
294
+ "attrs": { "axes": [1] },
295
+ "inputs": { "x": { "dtype": "float32", "shape": [262144, 2, 4], "dist": "normal", "seed": 951, "scale": 0.5 } },
296
+ "outputs": { "y": { "dtype": "float32", "shape": [262144, 2, 4] } },
297
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "2 * 4 * numel(shapes.x)" }] }
298
+ },
299
+ {
300
+ "name": "cached_small_float32_r3",
301
+ "preset": "stress",
302
+ "attrs": { "axes": [2] },
303
+ "inputs": { "x": { "dtype": "float32", "shape": [2, 1, 3], "dist": "normal", "seed": 951, "scale": 0.5 } },
304
+ "outputs": { "y": { "dtype": "float32", "shape": [2, 1, 3] } },
305
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "2 * 4 * numel(shapes.x)" }] }
306
+ },
307
+ {
308
+ "name": "cached_strided_float32_r3",
309
+ "preset": "stress",
310
+ "attrs": { "axes": [1] },
311
+ "inputs": { "x": { "dtype": "float32", "shape": [262144, 3, 4], "dist": "normal", "seed": 951, "scale": 0.5 } },
312
+ "outputs": { "y": { "dtype": "float32", "shape": [262144, 3, 4] } },
313
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "2 * 4 * numel(shapes.x)" }] }
314
+ },
315
+ {
316
+ "name": "cached_small_float32_r4",
317
+ "preset": "stress",
318
+ "attrs": { "axes": [2] },
319
+ "inputs": { "x": { "dtype": "float32", "shape": [2, 1, 4], "dist": "normal", "seed": 951, "scale": 0.5 } },
320
+ "outputs": { "y": { "dtype": "float32", "shape": [2, 1, 4] } },
321
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "2 * 4 * numel(shapes.x)" }] }
322
+ },
323
+ {
324
+ "name": "cached_strided_float32_r4",
325
+ "preset": "stress",
326
+ "attrs": { "axes": [1] },
327
+ "inputs": { "x": { "dtype": "float32", "shape": [262144, 4, 4], "dist": "normal", "seed": 951, "scale": 0.5 } },
328
+ "outputs": { "y": { "dtype": "float32", "shape": [262144, 4, 4] } },
329
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "2 * 4 * numel(shapes.x)" }] }
330
+ },
331
+ {
332
+ "name": "cached_small_float16_r2",
333
+ "preset": "stress",
334
+ "attrs": { "axes": [2] },
335
+ "inputs": { "x": { "dtype": "float16", "shape": [2, 1, 2], "dist": "normal", "seed": 951, "scale": 0.5 } },
336
+ "outputs": { "y": { "dtype": "float16", "shape": [2, 1, 2] } },
337
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "2 * 2 * numel(shapes.x)" }] }
338
+ },
339
+ {
340
+ "name": "cached_strided_float16_r2",
341
+ "preset": "stress",
342
+ "attrs": { "axes": [1] },
343
+ "inputs": { "x": { "dtype": "float16", "shape": [262144, 2, 4], "dist": "normal", "seed": 951, "scale": 0.5 } },
344
+ "outputs": { "y": { "dtype": "float16", "shape": [262144, 2, 4] } },
345
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "2 * 2 * numel(shapes.x)" }] }
346
+ },
347
+ {
348
+ "name": "cached_small_float16_r3",
349
+ "preset": "stress",
350
+ "attrs": { "axes": [2] },
351
+ "inputs": { "x": { "dtype": "float16", "shape": [2, 1, 3], "dist": "normal", "seed": 951, "scale": 0.5 } },
352
+ "outputs": { "y": { "dtype": "float16", "shape": [2, 1, 3] } },
353
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "2 * 2 * numel(shapes.x)" }] }
354
+ },
355
+ {
356
+ "name": "cached_strided_float16_r3",
357
+ "preset": "stress",
358
+ "attrs": { "axes": [1] },
359
+ "inputs": { "x": { "dtype": "float16", "shape": [262144, 3, 4], "dist": "normal", "seed": 951, "scale": 0.5 } },
360
+ "outputs": { "y": { "dtype": "float16", "shape": [262144, 3, 4] } },
361
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "2 * 2 * numel(shapes.x)" }] }
362
+ },
363
+ {
364
+ "name": "cached_small_float16_r4",
365
+ "preset": "stress",
366
+ "attrs": { "axes": [2] },
367
+ "inputs": { "x": { "dtype": "float16", "shape": [2, 1, 4], "dist": "normal", "seed": 951, "scale": 0.5 } },
368
+ "outputs": { "y": { "dtype": "float16", "shape": [2, 1, 4] } },
369
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "2 * 2 * numel(shapes.x)" }] }
370
+ },
371
+ {
372
+ "name": "cached_strided_float16_r4",
373
+ "preset": "stress",
374
+ "attrs": { "axes": [1] },
375
+ "inputs": { "x": { "dtype": "float16", "shape": [262144, 4, 4], "dist": "normal", "seed": 951, "scale": 0.5 } },
376
+ "outputs": { "y": { "dtype": "float16", "shape": [262144, 4, 4] } },
377
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "2 * 2 * numel(shapes.x)" }] }
378
  }
379
  ]
380
  }
build/webgpu/manifest.json CHANGED
@@ -16,13 +16,15 @@
16
  "VEC4_MIN_REDUCTION": { "default": 8 },
17
  "FLAT_SPLIT_MIN_ELEMENTS": { "default": 65536 },
18
  "FLAT_SPLIT_TARGET_ELEMENTS": { "default": 4096 },
19
- "MAX_FLAT_SPLITS": { "default": 256 }
 
20
  },
21
  "derive": {
22
  "deviceWorkgroupCap": "min(device.limits.maxComputeInvocationsPerWorkgroup, device.limits.maxComputeWorkgroupSizeX)",
23
  "foldedDispatchCapacity": "min(device.limits.maxComputeWorkgroupsPerDimension, 65535) * min(device.limits.maxComputeWorkgroupsPerDimension, 65535)",
24
  "shapeContract": "ranks.x >= 3 and ranks.x <= 8 and ranks.y == ranks.x and sameShape(shapes.y, shapes.x) and f16Ok(dtypes.T)",
25
  "reduceCount": "(dim(shapes.x, 0) if hasAxis(attrs.axes, 0, ranks.x) else 1) * (dim(shapes.x, 1) if hasAxis(attrs.axes, 1, ranks.x) else 1) * (dim(shapes.x, 2) if hasAxis(attrs.axes, 2, ranks.x) else 1) * (dim(shapes.x, 3) if ranks.x >= 4 and hasAxis(attrs.axes, 3, ranks.x) else 1) * (dim(shapes.x, 4) if ranks.x >= 5 and hasAxis(attrs.axes, 4, ranks.x) else 1) * (dim(shapes.x, 5) if ranks.x >= 6 and hasAxis(attrs.axes, 5, ranks.x) else 1) * (dim(shapes.x, 6) if ranks.x >= 7 and hasAxis(attrs.axes, 6, ranks.x) else 1) * (dim(shapes.x, 7) if ranks.x >= 8 and hasAxis(attrs.axes, 7, ranks.x) else 1)",
 
26
  "rowCount": "numel(shapes.x) / max(1, reduceCount)",
27
  "allAxesReduced": "hasAxis(attrs.axes, 0, ranks.x) and hasAxis(attrs.axes, 1, ranks.x) and hasAxis(attrs.axes, 2, ranks.x) and (ranks.x < 4 or hasAxis(attrs.axes, 3, ranks.x)) and (ranks.x < 5 or hasAxis(attrs.axes, 4, ranks.x)) and (ranks.x < 6 or hasAxis(attrs.axes, 5, ranks.x)) and (ranks.x < 7 or hasAxis(attrs.axes, 6, ranks.x)) and (ranks.x < 8 or hasAxis(attrs.axes, 7, ranks.x))",
28
  "vec4Eligible": "((ranks.x == 3 and hasAxis(attrs.axes, 2, 3) and (dim(shapes.x, 2) % 4 == 0 or (hasAxis(attrs.axes, 1, 3) and dim(shapes.x, 1) * dim(shapes.x, 2) % 4 == 0) or (hasAxis(attrs.axes, 0, 3) and hasAxis(attrs.axes, 1, 3) and numel(shapes.x) % 4 == 0))) or (ranks.x == 4 and hasAxis(attrs.axes, 3, 4) and (dim(shapes.x, 3) % 4 == 0 or (hasAxis(attrs.axes, 2, 4) and dim(shapes.x, 2) * dim(shapes.x, 3) % 4 == 0) or (hasAxis(attrs.axes, 1, 4) and hasAxis(attrs.axes, 2, 4) and dim(shapes.x, 1) * dim(shapes.x, 2) * dim(shapes.x, 3) % 4 == 0) or (hasAxis(attrs.axes, 0, 4) and hasAxis(attrs.axes, 1, 4) and hasAxis(attrs.axes, 2, 4) and numel(shapes.x) % 4 == 0))) or (ranks.x == 5 and hasAxis(attrs.axes, 4, 5) and (dim(shapes.x, 4) % 4 == 0 or (hasAxis(attrs.axes, 3, 5) and dim(shapes.x, 3) * dim(shapes.x, 4) % 4 == 0) or (hasAxis(attrs.axes, 2, 5) and hasAxis(attrs.axes, 3, 5) and dim(shapes.x, 2) * dim(shapes.x, 3) * dim(shapes.x, 4) % 4 == 0) or (hasAxis(attrs.axes, 1, 5) and hasAxis(attrs.axes, 2, 5) and hasAxis(attrs.axes, 3, 5) and dim(shapes.x, 1) * dim(shapes.x, 2) * dim(shapes.x, 3) * dim(shapes.x, 4) % 4 == 0) or (allAxesReduced and numel(shapes.x) % 4 == 0))) or (ranks.x == 6 and hasAxis(attrs.axes, 5, 6) and (dim(shapes.x, 5) % 4 == 0 or (hasAxis(attrs.axes, 4, 6) and dim(shapes.x, 4) * dim(shapes.x, 5) % 4 == 0) or (hasAxis(attrs.axes, 3, 6) and hasAxis(attrs.axes, 4, 6) and dim(shapes.x, 3) * dim(shapes.x, 4) * dim(shapes.x, 5) % 4 == 0) or (hasAxis(attrs.axes, 2, 6) and hasAxis(attrs.axes, 3, 6) and hasAxis(attrs.axes, 4, 6) and dim(shapes.x, 2) * dim(shapes.x, 3) * dim(shapes.x, 4) * dim(shapes.x, 5) % 4 == 0) or (hasAxis(attrs.axes, 1, 6) and hasAxis(attrs.axes, 2, 6) and hasAxis(attrs.axes, 3, 6) and hasAxis(attrs.axes, 4, 6) and dim(shapes.x, 1) * dim(shapes.x, 2) * dim(shapes.x, 3) * dim(shapes.x, 4) * dim(shapes.x, 5) % 4 == 0) or (allAxesReduced and numel(shapes.x) % 4 == 0))))",
@@ -39,19 +41,19 @@
39
  "vectorStorageFits": "vectorWorkgroupSize * 8 <= device.limits.maxComputeWorkgroupStorageSize",
40
  "flatSplit": "min(tunables.MAX_FLAT_SPLITS, pow2ceil(ceilDiv(numel(shapes.x), tunables.FLAT_SPLIT_TARGET_ELEMENTS)))",
41
  "flatScratchBytes": "flatSplit * 8",
42
- "flatPathFits": "flatSplit <= min(device.limits.maxComputeWorkgroupsPerDimension, 65535) and flatScratchBytes <= device.limits.maxStorageBufferBindingSize and flatScratchBytes <= device.limits.maxBufferSize and maxWorkgroupSize * 8 <= device.limits.maxComputeWorkgroupStorageSize and applyDispatchFits"
 
 
 
 
43
  },
44
  "when": ["shapeContract"],
45
  "bindings": {
46
- "x": { "buffer": "read-only-storage", "elementType": "$scalar" },
47
- "params": { "buffer": "uniform", "struct": [{ "name": "count", "type": "u32", "value": "numel(shapes.x)" }] },
48
- "x_2": { "name": "x", "buffer": "read-only-storage", "elementType": "$ioElement" },
49
- "y_2": { "name": "y", "buffer": "storage", "elementType": "$ioElement" },
50
- "params_4": {
51
- "name": "params",
52
- "buffer": "uniform",
53
- "struct": [{ "name": "rows", "type": "u32", "value": "rowCount" }]
54
- }
55
  },
56
  "variants": [
57
  {
@@ -87,18 +89,17 @@
87
  "splitSpec": "flatSplit",
88
  "usesF16Spec": "dtypes.T == \"f16\""
89
  },
90
- "bindings": ["x", { "name": "partials", "buffer": "storage", "elementType": "vec2<f32>" }, "params"],
91
- "dispatch": { "x": "min(flatSplit, 65535)", "y": "ceilDiv(flatSplit, 65535)", "z": 1 }
92
  },
93
  {
94
  "id": "combine",
95
  "name": "MeanVarianceNormalization.FlatCombine",
96
  "shader": "norm-flat-splitk-combine.wgsl.jinja",
97
- "derive": { "splitSpec": "flatSplit", "usesF16Spec": "dtypes.T == \"f16\"" },
98
  "bindings": [
99
- "x",
100
  { "name": "partials", "buffer": "read-only-storage", "elementType": "vec2<f32>" },
101
- { "name": "stats", "buffer": "storage", "elementType": "f32", "length": 2 },
102
  "params"
103
  ],
104
  "dispatch": { "x": "min(1, 65535)", "y": "ceilDiv(1, 65535)", "z": 1 }
@@ -107,11 +108,7 @@
107
  "id": "apply",
108
  "name": "MeanVarianceNormalization.FlatApply",
109
  "shader": "norm-flat-apply.wgsl.jinja",
110
- "derive": {
111
- "workgroupSizeSpec": "maxWorkgroupSize",
112
- "scalar": "dtypes.T",
113
- "usesF16Spec": "dtypes.T == \"f16\""
114
- },
115
  "bindings": [
116
  "x",
117
  { "name": "stats", "buffer": "read-only-storage", "elementType": "f32", "length": 2 },
@@ -126,6 +123,29 @@
126
  }
127
  ]
128
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
129
  {
130
  "id": "serial_rows",
131
  "priority": 115,
@@ -140,10 +160,9 @@
140
  "xShape": "shapes.x",
141
  "reduce": ["hasAxis(attrs.axes, 0, ranks.x)", "hasAxis(attrs.axes, 1, ranks.x)", "hasAxis(attrs.axes, 2, ranks.x)", "hasAxis(attrs.axes, 3, ranks.x)", "hasAxis(attrs.axes, 4, ranks.x)", "hasAxis(attrs.axes, 5, ranks.x)", "hasAxis(attrs.axes, 6, ranks.x)", "hasAxis(attrs.axes, 7, ranks.x)"],
142
  "workgroupSizeSpec": "serialWorkgroupSize",
143
- "scalar": "dtypes.T",
144
  "usesF16Spec": "dtypes.T == \"f16\""
145
  },
146
- "bindings": ["x_2", "y_2", "params_4"],
147
  "dispatch": {
148
  "x": "min(ceilDiv((rowCount), (serialWorkgroupSize)), 65535)",
149
  "y": "ceilDiv(ceilDiv((rowCount), (serialWorkgroupSize)), 65535)",
@@ -162,7 +181,6 @@
162
  "id": "main",
163
  "name": "MeanVarianceNormalization.CooperativeVec4",
164
  "shader": "mean-variance-normalization-subgroup.wgsl.jinja",
165
- "subgroupCollectivesWidth": "portable",
166
  "derive": {
167
  "xShape": "shapes.x",
168
  "reduce": ["hasAxis(attrs.axes, 0, ranks.x)", "hasAxis(attrs.axes, 1, ranks.x)", "hasAxis(attrs.axes, 2, ranks.x)", "hasAxis(attrs.axes, 3, ranks.x)", "hasAxis(attrs.axes, 4, ranks.x)", "hasAxis(attrs.axes, 5, ranks.x)", "hasAxis(attrs.axes, 6, ranks.x)", "hasAxis(attrs.axes, 7, ranks.x)"],
@@ -172,7 +190,7 @@
172
  "usesF16Spec": "dtypes.T == \"f16\"",
173
  "vectorizedSpec": true
174
  },
175
- "bindings": ["x_2", "y_2", "params_4"],
176
  "dispatch": { "x": "min(rowCount, 65535)", "y": "ceilDiv(rowCount, 65535)", "z": 1 }
177
  }
178
  ]
@@ -187,7 +205,6 @@
187
  "id": "main",
188
  "name": "MeanVarianceNormalization.CooperativeScalar",
189
  "shader": "mean-variance-normalization-subgroup.wgsl.jinja",
190
- "subgroupCollectivesWidth": "portable",
191
  "derive": {
192
  "xShape": "shapes.x",
193
  "reduce": ["hasAxis(attrs.axes, 0, ranks.x)", "hasAxis(attrs.axes, 1, ranks.x)", "hasAxis(attrs.axes, 2, ranks.x)", "hasAxis(attrs.axes, 3, ranks.x)", "hasAxis(attrs.axes, 4, ranks.x)", "hasAxis(attrs.axes, 5, ranks.x)", "hasAxis(attrs.axes, 6, ranks.x)", "hasAxis(attrs.axes, 7, ranks.x)"],
@@ -196,7 +213,7 @@
196
  "usesF16Spec": "dtypes.T == \"f16\"",
197
  "vectorizedSpec": false
198
  },
199
- "bindings": ["x_2", "y_2", "params_4"],
200
  "dispatch": { "x": "min(rowCount, 65535)", "y": "ceilDiv(rowCount, 65535)", "z": 1 }
201
  }
202
  ]
 
16
  "VEC4_MIN_REDUCTION": { "default": 8 },
17
  "FLAT_SPLIT_MIN_ELEMENTS": { "default": 65536 },
18
  "FLAT_SPLIT_TARGET_ELEMENTS": { "default": 4096 },
19
+ "MAX_FLAT_SPLITS": { "default": 256 },
20
+ "PACKED_WORKGROUP_SIZE": { "default": 512 }
21
  },
22
  "derive": {
23
  "deviceWorkgroupCap": "min(device.limits.maxComputeInvocationsPerWorkgroup, device.limits.maxComputeWorkgroupSizeX)",
24
  "foldedDispatchCapacity": "min(device.limits.maxComputeWorkgroupsPerDimension, 65535) * min(device.limits.maxComputeWorkgroupsPerDimension, 65535)",
25
  "shapeContract": "ranks.x >= 3 and ranks.x <= 8 and ranks.y == ranks.x and sameShape(shapes.y, shapes.x) and f16Ok(dtypes.T)",
26
  "reduceCount": "(dim(shapes.x, 0) if hasAxis(attrs.axes, 0, ranks.x) else 1) * (dim(shapes.x, 1) if hasAxis(attrs.axes, 1, ranks.x) else 1) * (dim(shapes.x, 2) if hasAxis(attrs.axes, 2, ranks.x) else 1) * (dim(shapes.x, 3) if ranks.x >= 4 and hasAxis(attrs.axes, 3, ranks.x) else 1) * (dim(shapes.x, 4) if ranks.x >= 5 and hasAxis(attrs.axes, 4, ranks.x) else 1) * (dim(shapes.x, 5) if ranks.x >= 6 and hasAxis(attrs.axes, 5, ranks.x) else 1) * (dim(shapes.x, 6) if ranks.x >= 7 and hasAxis(attrs.axes, 6, ranks.x) else 1) * (dim(shapes.x, 7) if ranks.x >= 8 and hasAxis(attrs.axes, 7, ranks.x) else 1)",
27
+ "shortGroup": "reduceCount >= 2 and reduceCount <= 4",
28
  "rowCount": "numel(shapes.x) / max(1, reduceCount)",
29
  "allAxesReduced": "hasAxis(attrs.axes, 0, ranks.x) and hasAxis(attrs.axes, 1, ranks.x) and hasAxis(attrs.axes, 2, ranks.x) and (ranks.x < 4 or hasAxis(attrs.axes, 3, ranks.x)) and (ranks.x < 5 or hasAxis(attrs.axes, 4, ranks.x)) and (ranks.x < 6 or hasAxis(attrs.axes, 5, ranks.x)) and (ranks.x < 7 or hasAxis(attrs.axes, 6, ranks.x)) and (ranks.x < 8 or hasAxis(attrs.axes, 7, ranks.x))",
30
  "vec4Eligible": "((ranks.x == 3 and hasAxis(attrs.axes, 2, 3) and (dim(shapes.x, 2) % 4 == 0 or (hasAxis(attrs.axes, 1, 3) and dim(shapes.x, 1) * dim(shapes.x, 2) % 4 == 0) or (hasAxis(attrs.axes, 0, 3) and hasAxis(attrs.axes, 1, 3) and numel(shapes.x) % 4 == 0))) or (ranks.x == 4 and hasAxis(attrs.axes, 3, 4) and (dim(shapes.x, 3) % 4 == 0 or (hasAxis(attrs.axes, 2, 4) and dim(shapes.x, 2) * dim(shapes.x, 3) % 4 == 0) or (hasAxis(attrs.axes, 1, 4) and hasAxis(attrs.axes, 2, 4) and dim(shapes.x, 1) * dim(shapes.x, 2) * dim(shapes.x, 3) % 4 == 0) or (hasAxis(attrs.axes, 0, 4) and hasAxis(attrs.axes, 1, 4) and hasAxis(attrs.axes, 2, 4) and numel(shapes.x) % 4 == 0))) or (ranks.x == 5 and hasAxis(attrs.axes, 4, 5) and (dim(shapes.x, 4) % 4 == 0 or (hasAxis(attrs.axes, 3, 5) and dim(shapes.x, 3) * dim(shapes.x, 4) % 4 == 0) or (hasAxis(attrs.axes, 2, 5) and hasAxis(attrs.axes, 3, 5) and dim(shapes.x, 2) * dim(shapes.x, 3) * dim(shapes.x, 4) % 4 == 0) or (hasAxis(attrs.axes, 1, 5) and hasAxis(attrs.axes, 2, 5) and hasAxis(attrs.axes, 3, 5) and dim(shapes.x, 1) * dim(shapes.x, 2) * dim(shapes.x, 3) * dim(shapes.x, 4) % 4 == 0) or (allAxesReduced and numel(shapes.x) % 4 == 0))) or (ranks.x == 6 and hasAxis(attrs.axes, 5, 6) and (dim(shapes.x, 5) % 4 == 0 or (hasAxis(attrs.axes, 4, 6) and dim(shapes.x, 4) * dim(shapes.x, 5) % 4 == 0) or (hasAxis(attrs.axes, 3, 6) and hasAxis(attrs.axes, 4, 6) and dim(shapes.x, 3) * dim(shapes.x, 4) * dim(shapes.x, 5) % 4 == 0) or (hasAxis(attrs.axes, 2, 6) and hasAxis(attrs.axes, 3, 6) and hasAxis(attrs.axes, 4, 6) and dim(shapes.x, 2) * dim(shapes.x, 3) * dim(shapes.x, 4) * dim(shapes.x, 5) % 4 == 0) or (hasAxis(attrs.axes, 1, 6) and hasAxis(attrs.axes, 2, 6) and hasAxis(attrs.axes, 3, 6) and hasAxis(attrs.axes, 4, 6) and dim(shapes.x, 1) * dim(shapes.x, 2) * dim(shapes.x, 3) * dim(shapes.x, 4) * dim(shapes.x, 5) % 4 == 0) or (allAxesReduced and numel(shapes.x) % 4 == 0))))",
 
41
  "vectorStorageFits": "vectorWorkgroupSize * 8 <= device.limits.maxComputeWorkgroupStorageSize",
42
  "flatSplit": "min(tunables.MAX_FLAT_SPLITS, pow2ceil(ceilDiv(numel(shapes.x), tunables.FLAT_SPLIT_TARGET_ELEMENTS)))",
43
  "flatScratchBytes": "flatSplit * 8",
44
+ "flatPathFits": "flatSplit <= min(device.limits.maxComputeWorkgroupsPerDimension, 65535) and flatScratchBytes <= device.limits.maxStorageBufferBindingSize and flatScratchBytes <= device.limits.maxBufferSize and maxWorkgroupSize * 8 <= device.limits.maxComputeWorkgroupStorageSize and applyDispatchFits",
45
+ "reducedSpan": "1 + ((dim(shapes.x, 0) - 1) * inner(shapes.x, 0) if ranks.x > 0 and hasAxis(attrs.axes, 0, ranks.x) else 0) + ((dim(shapes.x, 1) - 1) * inner(shapes.x, 1) if ranks.x > 1 and hasAxis(attrs.axes, 1, ranks.x) else 0) + ((dim(shapes.x, 2) - 1) * inner(shapes.x, 2) if ranks.x > 2 and hasAxis(attrs.axes, 2, ranks.x) else 0) + ((dim(shapes.x, 3) - 1) * inner(shapes.x, 3) if ranks.x > 3 and hasAxis(attrs.axes, 3, ranks.x) else 0) + ((dim(shapes.x, 4) - 1) * inner(shapes.x, 4) if ranks.x > 4 and hasAxis(attrs.axes, 4, ranks.x) else 0) + ((dim(shapes.x, 5) - 1) * inner(shapes.x, 5) if ranks.x > 5 and hasAxis(attrs.axes, 5, ranks.x) else 0) + ((dim(shapes.x, 6) - 1) * inner(shapes.x, 6) if ranks.x > 6 and hasAxis(attrs.axes, 6, ranks.x) else 0) + ((dim(shapes.x, 7) - 1) * inner(shapes.x, 7) if ranks.x > 7 and hasAxis(attrs.axes, 7, ranks.x) else 0)",
46
+ "packedRows": "4 if reduceCount % 2 != 0 else (2 if reduceCount % 4 != 0 else 1)",
47
+ "packedVectors": "reduceCount * packedRows / 4",
48
+ "packedWorkgroupSize": "tunables.PACKED_WORKGROUP_SIZE if tunables.PACKED_WORKGROUP_SIZE <= deviceWorkgroupCap else min(tunables.SERIAL_TINY_WORKGROUP_SIZE, deviceWorkgroupCap)"
49
  },
50
  "when": ["shapeContract"],
51
  "bindings": {
52
+ "x": { "elementType": "$scalar" },
53
+ "params": { "struct": [{ "name": "count", "type": "u32", "value": "numel(shapes.x)" }] },
54
+ "x_main": { "name": "x", "elementType": "$ioElement" },
55
+ "y_main": { "name": "y", "elementType": "$ioElement" },
56
+ "params_rows": { "name": "params", "struct": [{ "name": "rows", "type": "u32", "value": "rowCount" }] }
 
 
 
 
57
  },
58
  "variants": [
59
  {
 
89
  "splitSpec": "flatSplit",
90
  "usesF16Spec": "dtypes.T == \"f16\""
91
  },
92
+ "bindings": ["x", { "name": "partials", "elementType": "vec2<f32>" }, "params"],
93
+ "dispatch": { "x": "flatSplit" }
94
  },
95
  {
96
  "id": "combine",
97
  "name": "MeanVarianceNormalization.FlatCombine",
98
  "shader": "norm-flat-splitk-combine.wgsl.jinja",
99
+ "derive": { "splitSpec": "flatSplit" },
100
  "bindings": [
 
101
  { "name": "partials", "buffer": "read-only-storage", "elementType": "vec2<f32>" },
102
+ { "name": "stats", "elementType": "f32", "length": 2 },
103
  "params"
104
  ],
105
  "dispatch": { "x": "min(1, 65535)", "y": "ceilDiv(1, 65535)", "z": 1 }
 
108
  "id": "apply",
109
  "name": "MeanVarianceNormalization.FlatApply",
110
  "shader": "norm-flat-apply.wgsl.jinja",
111
+ "derive": { "workgroupSizeSpec": "maxWorkgroupSize", "usesF16Spec": "dtypes.T == \"f16\"" },
 
 
 
 
112
  "bindings": [
113
  "x",
114
  { "name": "stats", "buffer": "read-only-storage", "elementType": "f32", "length": 2 },
 
123
  }
124
  ]
125
  },
126
+ {
127
+ "id": "packed_short_groups",
128
+ "priority": 116,
129
+ "when": ["numel(shapes.x) > 0", "shortGroup", "rowCount >= tunables.SERIAL_MIN_ROWS", "reducedSpan == reduceCount", "ceilDiv(rowCount / packedRows, packedWorkgroupSize) <= foldedDispatchCapacity"],
130
+ "derive": {
131
+ "packedTail": "rowCount % packedRows != 0",
132
+ "ioElement": "dtypes.T if packedTail else \"vec4<\" ~ dtypes.T ~ \">\"",
133
+ "usesF16Spec": "dtypes.T == \"f16\""
134
+ },
135
+ "passes": [
136
+ {
137
+ "id": "main",
138
+ "name": "MeanVarianceNormalization.PackedShortGroups",
139
+ "shader": "mean-variance-normalization-packed-rows.wgsl.jinja",
140
+ "bindings": ["x_main", "y_main", "params_rows"],
141
+ "dispatch": {
142
+ "x": "min(ceilDiv((ceilDiv(rowCount, packedRows)), (packedWorkgroupSize)), 65535)",
143
+ "y": "ceilDiv(ceilDiv((ceilDiv(rowCount, packedRows)), (packedWorkgroupSize)), 65535)",
144
+ "z": 1
145
+ }
146
+ }
147
+ ]
148
+ },
149
  {
150
  "id": "serial_rows",
151
  "priority": 115,
 
160
  "xShape": "shapes.x",
161
  "reduce": ["hasAxis(attrs.axes, 0, ranks.x)", "hasAxis(attrs.axes, 1, ranks.x)", "hasAxis(attrs.axes, 2, ranks.x)", "hasAxis(attrs.axes, 3, ranks.x)", "hasAxis(attrs.axes, 4, ranks.x)", "hasAxis(attrs.axes, 5, ranks.x)", "hasAxis(attrs.axes, 6, ranks.x)", "hasAxis(attrs.axes, 7, ranks.x)"],
162
  "workgroupSizeSpec": "serialWorkgroupSize",
 
163
  "usesF16Spec": "dtypes.T == \"f16\""
164
  },
165
+ "bindings": ["x_main", "y_main", "params_rows"],
166
  "dispatch": {
167
  "x": "min(ceilDiv((rowCount), (serialWorkgroupSize)), 65535)",
168
  "y": "ceilDiv(ceilDiv((rowCount), (serialWorkgroupSize)), 65535)",
 
181
  "id": "main",
182
  "name": "MeanVarianceNormalization.CooperativeVec4",
183
  "shader": "mean-variance-normalization-subgroup.wgsl.jinja",
 
184
  "derive": {
185
  "xShape": "shapes.x",
186
  "reduce": ["hasAxis(attrs.axes, 0, ranks.x)", "hasAxis(attrs.axes, 1, ranks.x)", "hasAxis(attrs.axes, 2, ranks.x)", "hasAxis(attrs.axes, 3, ranks.x)", "hasAxis(attrs.axes, 4, ranks.x)", "hasAxis(attrs.axes, 5, ranks.x)", "hasAxis(attrs.axes, 6, ranks.x)", "hasAxis(attrs.axes, 7, ranks.x)"],
 
190
  "usesF16Spec": "dtypes.T == \"f16\"",
191
  "vectorizedSpec": true
192
  },
193
+ "bindings": ["x_main", "y_main", "params_rows"],
194
  "dispatch": { "x": "min(rowCount, 65535)", "y": "ceilDiv(rowCount, 65535)", "z": 1 }
195
  }
196
  ]
 
205
  "id": "main",
206
  "name": "MeanVarianceNormalization.CooperativeScalar",
207
  "shader": "mean-variance-normalization-subgroup.wgsl.jinja",
 
208
  "derive": {
209
  "xShape": "shapes.x",
210
  "reduce": ["hasAxis(attrs.axes, 0, ranks.x)", "hasAxis(attrs.axes, 1, ranks.x)", "hasAxis(attrs.axes, 2, ranks.x)", "hasAxis(attrs.axes, 3, ranks.x)", "hasAxis(attrs.axes, 4, ranks.x)", "hasAxis(attrs.axes, 5, ranks.x)", "hasAxis(attrs.axes, 6, ranks.x)", "hasAxis(attrs.axes, 7, ranks.x)"],
 
213
  "usesF16Spec": "dtypes.T == \"f16\"",
214
  "vectorizedSpec": false
215
  },
216
+ "bindings": ["x_main", "y_main", "params_rows"],
217
  "dispatch": { "x": "min(rowCount, 65535)", "y": "ceilDiv(rowCount, 65535)", "z": 1 }
218
  }
219
  ]
build/webgpu/mean-variance-normalization-packed-rows.wgsl.jinja ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% macro normalize_small_group(tag) %}
2
+ {% set count = reduceCount | int %}
3
+ {% if not usesF16Spec %}
4
+ var magnitude{{ tag }} = abs(value{{ tag }}_0);
5
+ {% for c in range(1, count) %}
6
+ magnitude{{ tag }} = max(magnitude{{ tag }}, abs(value{{ tag }}_{{ c }}));
7
+ {% endfor %}
8
+ let exponent{{ tag }} = (bitcast<u32>(magnitude{{ tag }}) >> 23u) & 255u;
9
+ let scale{{ tag }} = bitcast<f32>((254u - clamp(exponent{{ tag }}, 1u, 253u)) << 23u);
10
+ {% for c in range(count) %}
11
+ let scaled{{ tag }}_{{ c }} = value{{ tag }}_{{ c }} * scale{{ tag }};
12
+ {% endfor %}
13
+ {% endif %}
14
+ {% set prefix = "value" if usesF16Spec else "scaled" %}
15
+ var sum{{ tag }} = 0.0;
16
+ {% for c in range(count) %}
17
+ let d{{ tag }}_{{ c }} = {{ subtract(prefix ~ tag ~ "_" ~ c, prefix ~ tag ~ "_0") }};
18
+ sum{{ tag }} = sum{{ tag }} + d{{ tag }}_{{ c }};
19
+ {% endfor %}
20
+ let mean{{ tag }} = sum{{ tag }} / {{ count }}.0;
21
+ var square{{ tag }} = 0.0;
22
+ {% for c in range(count) %}
23
+ let centered{{ tag }}_{{ c }} = {{ subtract("d" ~ tag ~ "_" ~ c, "mean" ~ tag) }};
24
+ square{{ tag }} = square{{ tag }} + centered{{ tag }}_{{ c }} * centered{{ tag }}_{{ c }};
25
+ {% endfor %}
26
+ let denom{{ tag }} = sqrt(square{{ tag }} / {{ count }}.0);
27
+ {% for c in range(count) %}
28
+ let n{{ tag }}_{{ c }} = centered{{ tag }}_{{ c }} / denom{{ tag }};
29
+ {% endfor %}
30
+ {% endmacro %}
31
+ {% macro subtract(value, shift, vector=false) %}
32
+ fma(-1.0, {{ shift }}, {{ value }}){% endmacro %}
33
+ {{ env.wgsl.resourceDeclarations }}
34
+ {% set tail = packedTail %}
35
+ {% set R = reduceCount | int %}
36
+ {% set rows = packedRows | int %}
37
+ {% set vectors = packedVectors | int %}
38
+ {% macro element(index) %}v{{ (index / 4) | int }}.{{ "xyzw"[index % 4] }}{% endmacro %}
39
+
40
+ {% if tail %}
41
+ fn load_element(index: u32) -> f32 {
42
+ if (index < params.rows * {{ R }}u) {
43
+ return f32(x[index]);
44
+ }
45
+ return 0.0;
46
+ }
47
+ {% endif %}
48
+ // An invocation retains a whole number of short groups in complete vec4 words.
49
+ // Keeping differences in shifted coordinates avoids rounding the mean back
50
+ // onto the input's larger offset. Explicit fma preserves these intermediate
51
+ // differences through compiler arithmetic reassociation.
52
+ @compute @workgroup_size({{ packedWorkgroupSize }}, 1, 1)
53
+ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
54
+ let block = gid.x + gid.y * {{ DISPATCH_FOLD_WIDTH }}u * {{ packedWorkgroupSize }}u;
55
+ if (block >= {% if tail %}(params.rows + {{ rows - 1 }}u){% else %}params.rows{% endif %}{% if rows != 1 %} / {{ rows }}u{% endif %}) {
56
+ return;
57
+ }
58
+ let base = block{% if vectors != 1 %} * {{ vectors }}u{% endif %};
59
+ {% for v in range(vectors) %}
60
+ {% if tail %}
61
+ let v{{ v }} = vec4<f32>(
62
+ {% for c in range(4) %}
63
+ load_element(base * 4u + {{ v * 4 + c }}u){% if not loop.last %},{% endif %}
64
+ {% endfor %}
65
+ );
66
+ {% else %}
67
+ let v{{ v }} = vec4<f32>(x[base{% if v != 0 %} + {{ v }}u{% endif %}]);
68
+ {% endif %}
69
+ {% endfor %}
70
+ {% for row in range(rows) %}
71
+ {% for c in range(R) %}
72
+ let value{{ row }}_{{ c }} = {{ element(row * R + c) }};
73
+ {% endfor %}
74
+ {{ normalize_small_group(row) }}
75
+ {% endfor %}
76
+ {% for v in range(vectors) %}
77
+ {% if tail %}let out{{ v }}{% else %}y[base{% if v != 0 %} + {{ v }}u{% endif %}]{% endif %} = {% if usesF16Spec %}vec4<f16>({% endif %}vec4<f32>(
78
+ {% for c in range(4) %}
79
+ n{{ ((v * 4 + c) / R) | int }}_{{ (v * 4 + c) % R }}{% if not loop.last %},{% endif %}
80
+ {% endfor %}
81
+ ){% if usesF16Spec %}){% endif %};
82
+ {% if tail %}
83
+ {% for c in range(4) %}
84
+ if (base * 4u + {{ v * 4 + c }}u < params.rows * {{ R }}u) {
85
+ y[base * 4u + {{ v * 4 + c }}u] = out{{ v }}.{{ "xyzw"[c] }};
86
+ }
87
+ {% endfor %}
88
+ {% endif %}
89
+ {% endfor %}
90
+ }
build/webgpu/mean-variance-normalization-serial-rows.wgsl.jinja CHANGED
@@ -1,6 +1,54 @@
1
- {% if usesF16Spec %}
2
- enable f16;
 
 
 
 
 
 
 
 
 
 
3
  {% endif %}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  {{ env.wgsl.resourceDeclarations }}
5
 
6
  // One invocation owns one normalization group. For many short groups, adjacent
@@ -25,20 +73,21 @@ enable f16;
25
  {% endfor %}
26
  {% endmacro %}
27
  const WG: u32 = {{ workgroupSizeSpec }}u;
 
28
  const R: u32 = {{ reduceCount }}u;
 
29
 
30
  @compute @workgroup_size(WG, 1, 1)
31
  fn main(
32
  @builtin(global_invocation_id) gid: vec3<u32>
33
  ) {
34
- // `threads` dispatches fold past the WebGPU x-dimension limit into y.
35
- let row = gid.x + gid.y * {{ DISPATCH_FOLD_WIDTH }}u * WG;
36
- if (row >= params.rows) {
37
- return;
38
- }
39
 
40
  var base_off = 0u;
41
  {{ nd_offset("base_off", "row", 0) | indent(2, true) }}
 
 
 
42
  let shift = f32(x[base_off]);
43
  var sum_d = 0.0;
44
  var sum_d2 = 0.0;
@@ -51,11 +100,11 @@ fn main(
51
 
52
  let mean_d = sum_d / f32(R);
53
  let variance = max(sum_d2 / f32(R) - mean_d * mean_d, 0.0);
54
- let mean = shift + mean_d;
55
  let denom = sqrt(variance);
56
 
57
  for (var r = 0u; r < R; r = r + 1u) {
58
  var off = base_off;
59
- {{ nd_offset("off", "r", 1) | indent(4, true) }} y[off] = {{ scalar }}((f32(x[off]) - mean) / denom);
60
  }
 
61
  }
 
1
+ {% macro normalize_small_group(tag) %}
2
+ {% set count = reduceCount | int %}
3
+ {% if not usesF16Spec %}
4
+ var magnitude{{ tag }} = abs(value{{ tag }}_0);
5
+ {% for c in range(1, count) %}
6
+ magnitude{{ tag }} = max(magnitude{{ tag }}, abs(value{{ tag }}_{{ c }}));
7
+ {% endfor %}
8
+ let exponent{{ tag }} = (bitcast<u32>(magnitude{{ tag }}) >> 23u) & 255u;
9
+ let scale{{ tag }} = bitcast<f32>((254u - clamp(exponent{{ tag }}, 1u, 253u)) << 23u);
10
+ {% for c in range(count) %}
11
+ let scaled{{ tag }}_{{ c }} = value{{ tag }}_{{ c }} * scale{{ tag }};
12
+ {% endfor %}
13
  {% endif %}
14
+ {% set prefix = "value" if usesF16Spec else "scaled" %}
15
+ var sum{{ tag }} = 0.0;
16
+ {% for c in range(count) %}
17
+ let d{{ tag }}_{{ c }} = {{ subtract(prefix ~ tag ~ "_" ~ c, prefix ~ tag ~ "_0") }};
18
+ sum{{ tag }} = sum{{ tag }} + d{{ tag }}_{{ c }};
19
+ {% endfor %}
20
+ let mean{{ tag }} = sum{{ tag }} / {{ count }}.0;
21
+ var square{{ tag }} = 0.0;
22
+ {% for c in range(count) %}
23
+ let centered{{ tag }}_{{ c }} = {{ subtract("d" ~ tag ~ "_" ~ c, "mean" ~ tag) }};
24
+ square{{ tag }} = square{{ tag }} + centered{{ tag }}_{{ c }} * centered{{ tag }}_{{ c }};
25
+ {% endfor %}
26
+ let denom{{ tag }} = sqrt(square{{ tag }} / {{ count }}.0);
27
+ {% for c in range(count) %}
28
+ let n{{ tag }}_{{ c }} = centered{{ tag }}_{{ c }} / denom{{ tag }};
29
+ {% endfor %}
30
+ {% endmacro %}
31
+ {% macro indexed_small_group(index_offset, vectorized=false) %}
32
+ {% for c in range(reduceCount | int) %}
33
+ var off{{ c }} = base_off;
34
+ {{ index_offset("off" ~ c, c ~ "u", 1) | indent(2, true) }}
35
+ let valueg_{{ c }} = f32(x[off{{ c }}]);
36
+ {% endfor %}
37
+ {{ normalize_small_group("g") }}
38
+ {% for c in range(reduceCount | int) %}
39
+ y[off{{ c }}] = {{ scalar }}(ng_{{ c }});
40
+ {% endfor %}
41
+ {% endmacro %}
42
+ {% macro subtract(value, shift, vector=false) %}
43
+ fma(-1.0, {{ shift }}, {{ value }}){% endmacro %}
44
+ {% macro flat_index_2d(workgroupSize, name="i", bound="params.count", guardInline=false) %}
45
+ {% set wgTerm = workgroupSize ~ "u" if workgroupSize is number else workgroupSize %}
46
+ // 2D-folded flat index: gid.y carries the high bits past the dispatch's
47
+ // per-axis workgroup fold width.
48
+ let {{ name }} = gid.x + gid.y * {{ DISPATCH_FOLD_WIDTH }}u * {{ wgTerm }};
49
+ if ({{ name }} >= {{ bound }}) {
50
+ return;
51
+ }{% endmacro %}
52
  {{ env.wgsl.resourceDeclarations }}
53
 
54
  // One invocation owns one normalization group. For many short groups, adjacent
 
73
  {% endfor %}
74
  {% endmacro %}
75
  const WG: u32 = {{ workgroupSizeSpec }}u;
76
+ {% if not shortGroup %}
77
  const R: u32 = {{ reduceCount }}u;
78
+ {% endif %}
79
 
80
  @compute @workgroup_size(WG, 1, 1)
81
  fn main(
82
  @builtin(global_invocation_id) gid: vec3<u32>
83
  ) {
84
+ {{ flat_index_2d("WG", "row", "params.rows") }}
 
 
 
 
85
 
86
  var base_off = 0u;
87
  {{ nd_offset("base_off", "row", 0) | indent(2, true) }}
88
+ {% if shortGroup %}
89
+ {{ indexed_small_group(nd_offset) }}
90
+ {% else %}
91
  let shift = f32(x[base_off]);
92
  var sum_d = 0.0;
93
  var sum_d2 = 0.0;
 
100
 
101
  let mean_d = sum_d / f32(R);
102
  let variance = max(sum_d2 / f32(R) - mean_d * mean_d, 0.0);
 
103
  let denom = sqrt(variance);
104
 
105
  for (var r = 0u; r < R; r = r + 1u) {
106
  var off = base_off;
107
+ {{ nd_offset("off", "r", 1) | indent(4, true) }} y[off] = {{ scalar }}({{ subtract(subtract("f32(x[off])", "shift"), "mean_d") }} / denom);
108
  }
109
+ {% endif %}
110
  }
build/webgpu/mean-variance-normalization-subgroup.wgsl.jinja CHANGED
@@ -1,7 +1,47 @@
1
- {% if usesF16Spec %}
2
- enable f16;
 
 
 
 
 
 
 
 
 
 
3
  {% endif %}
4
- {% if useSubgroups %}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  enable subgroups;
6
  {% endif %}
7
  {{ env.wgsl.resourceDeclarations }}
@@ -21,6 +61,7 @@ enable subgroups;
21
  {% endfor %}
22
  {% endmacro %}
23
  const WG: u32 = {{ wg }}u;
 
24
  const R: u32 = {{ reduceCount }}u;
25
  {% if vectorizedSpec %}
26
  const RV: u32 = R / 4u;
@@ -35,7 +76,7 @@ var<workgroup> sg_partials: array<vec2<f32>, WG>;
35
  var<workgroup> wg_red: array<vec2<f32>, WG>;
36
  {% endif %}
37
 
38
- fn reduce_pair(value: vec2<f32>, tid: u32{% if useSubgroups %}, sg_size: u32{% endif %}) -> vec2<f32> {
39
  {% if useSubgroups %}
40
  let s = vec2<f32>(subgroupAdd(value.x), subgroupAdd(value.y));
41
  // The whole workgroup is one subgroup: the collective above already covers it
@@ -46,15 +87,20 @@ fn reduce_pair(value: vec2<f32>, tid: u32{% if useSubgroups %}, sg_size: u32{% e
46
  return s;
47
  }
48
  // Cross-subgroup fold that assumes nothing about which invocations share a
49
- // subgroup, how many subgroups there are, or which of a subgroup's lanes are
50
- // active: every invocation owns the slot at its own index, the elected lane
 
51
  // publishes its subgroup pair there and every other lane publishes the sum
52
- // identity. Each subgroup then folds all WG slots — lane `rank`, its dense
53
- // position among the active lanes, walks slots rank, rank + count, ... — and
54
- // one more collective merges the lane partials, so every slot is added
55
- // exactly once at any legal width and partition.
56
- let rank = subgroupExclusiveAdd(1u);
57
- let count = subgroupAdd(1u);
 
 
 
 
58
  sg_partials[tid] = select(vec2<f32>(0.0, 0.0), s, rank == 0u);
59
  workgroupBarrier();
60
  var total = vec2<f32>(0.0, 0.0);
@@ -75,23 +121,30 @@ fn reduce_pair(value: vec2<f32>, tid: u32{% if useSubgroups %}, sg_size: u32{% e
75
  {% endif %}
76
  }
77
 
 
78
  @compute @workgroup_size(WG, 1, 1)
79
  fn main(
80
  @builtin(workgroup_id) wg_id: vec3<u32>,
81
- @builtin(local_invocation_id) lid: vec3<u32>
82
- {%- if useSubgroups %},
83
- @builtin(subgroup_size) sg_size: u32
84
- {%- endif %}
85
  ) {
86
  let row = wg_id.x + wg_id.y * {{ DISPATCH_FOLD_WIDTH }}u;
87
  if (row >= params.rows) {
88
  return;
89
  }
 
 
 
90
  let tid = lid.x;
 
91
 
92
  // Base offset from the kept-axis coordinates.
93
  var base_off = 0u;
94
  {{ nd_offset("base_off", "row", 0) | indent(2, true) }}
 
 
 
95
  {% if vectorizedSpec %}
96
  let shift = f32(x[base_off / 4u].x);
97
  {% else %}
@@ -116,10 +169,9 @@ fn main(
116
  {% endif %}
117
  }
118
 
119
- let totals = reduce_pair(acc, tid{% if useSubgroups %}, sg_size{% endif %});
120
  let mean_d = totals.x / f32(R);
121
  let variance = max(totals.y / f32(R) - mean_d * mean_d, 0.0);
122
- let mean = shift + mean_d;
123
  let denom = sqrt(variance);
124
 
125
  {% if vectorizedSpec %}
@@ -131,9 +183,10 @@ fn main(
131
  var off = base_off;
132
  {{ nd_offset("off", "r", 1) | indent(4, true) }}{% if vectorizedSpec %}
133
  let v = vec4<f32>(x[off / 4u]);
134
- y[off / 4u] = {{ vecType }}((v - vec4<f32>(mean)) / vec4<f32>(denom));
135
  {% else %}
136
- y[off] = {{ scalar }}((f32(x[off]) - mean) / denom);
137
  {% endif %}
138
  }
 
139
  }
 
1
+ {% macro normalize_small_group(tag) %}
2
+ {% set count = reduceCount | int %}
3
+ {% if not usesF16Spec %}
4
+ var magnitude{{ tag }} = abs(value{{ tag }}_0);
5
+ {% for c in range(1, count) %}
6
+ magnitude{{ tag }} = max(magnitude{{ tag }}, abs(value{{ tag }}_{{ c }}));
7
+ {% endfor %}
8
+ let exponent{{ tag }} = (bitcast<u32>(magnitude{{ tag }}) >> 23u) & 255u;
9
+ let scale{{ tag }} = bitcast<f32>((254u - clamp(exponent{{ tag }}, 1u, 253u)) << 23u);
10
+ {% for c in range(count) %}
11
+ let scaled{{ tag }}_{{ c }} = value{{ tag }}_{{ c }} * scale{{ tag }};
12
+ {% endfor %}
13
  {% endif %}
14
+ {% set prefix = "value" if usesF16Spec else "scaled" %}
15
+ var sum{{ tag }} = 0.0;
16
+ {% for c in range(count) %}
17
+ let d{{ tag }}_{{ c }} = {{ subtract(prefix ~ tag ~ "_" ~ c, prefix ~ tag ~ "_0") }};
18
+ sum{{ tag }} = sum{{ tag }} + d{{ tag }}_{{ c }};
19
+ {% endfor %}
20
+ let mean{{ tag }} = sum{{ tag }} / {{ count }}.0;
21
+ var square{{ tag }} = 0.0;
22
+ {% for c in range(count) %}
23
+ let centered{{ tag }}_{{ c }} = {{ subtract("d" ~ tag ~ "_" ~ c, "mean" ~ tag) }};
24
+ square{{ tag }} = square{{ tag }} + centered{{ tag }}_{{ c }} * centered{{ tag }}_{{ c }};
25
+ {% endfor %}
26
+ let denom{{ tag }} = sqrt(square{{ tag }} / {{ count }}.0);
27
+ {% for c in range(count) %}
28
+ let n{{ tag }}_{{ c }} = centered{{ tag }}_{{ c }} / denom{{ tag }};
29
+ {% endfor %}
30
+ {% endmacro %}
31
+ {% macro indexed_small_group(index_offset, vectorized=false) %}
32
+ {% for c in range(reduceCount | int) %}
33
+ var off{{ c }} = base_off;
34
+ {{ index_offset("off" ~ c, c ~ "u", 1) | indent(2, true) }}
35
+ let valueg_{{ c }} = f32(x[off{{ c }}{% if vectorized %} / 4u][off{{ c }} % 4u{% endif %}]);
36
+ {% endfor %}
37
+ {{ normalize_small_group("g") }}
38
+ {% for c in range(reduceCount | int) %}
39
+ y[off{{ c }}{% if vectorized %} / 4u][off{{ c }} % 4u{% endif %}] = {{ scalar }}(ng_{{ c }});
40
+ {% endfor %}
41
+ {% endmacro %}
42
+ {% macro subtract(value, shift, vector=false) %}
43
+ fma({% if vector %}vec4<f32>(-1.0), vec4<f32>({{ shift }}){% else %}-1.0, {{ shift }}{% endif %}, {{ value }}){% endmacro %}
44
+ {% if useSubgroups and not shortGroup %}
45
  enable subgroups;
46
  {% endif %}
47
  {{ env.wgsl.resourceDeclarations }}
 
61
  {% endfor %}
62
  {% endmacro %}
63
  const WG: u32 = {{ wg }}u;
64
+ {% if not shortGroup %}
65
  const R: u32 = {{ reduceCount }}u;
66
  {% if vectorizedSpec %}
67
  const RV: u32 = R / 4u;
 
76
  var<workgroup> wg_red: array<vec2<f32>, WG>;
77
  {% endif %}
78
 
79
+ fn reduce_pair(value: vec2<f32>, tid: u32{% if useSubgroups %}, sg_lane: u32, sg_size: u32{% endif %}) -> vec2<f32> {
80
  {% if useSubgroups %}
81
  let s = vec2<f32>(subgroupAdd(value.x), subgroupAdd(value.y));
82
  // The whole workgroup is one subgroup: the collective above already covers it
 
87
  return s;
88
  }
89
  // Cross-subgroup fold that assumes nothing about which invocations share a
90
+ // subgroup or how many subgroups there are (it does require the uniform
91
+ // control flow this entry point already has): every invocation owns the slot
92
+ // at its own index, the elected lane
93
  // publishes its subgroup pair there and every other lane publishes the sum
94
+ // identity. Each subgroup then folds all WG slots — lane `sg_lane` walks slots
95
+ // sg_lane, sg_lane + sg_size, ... — and one more collective merges the lane
96
+ // partials, so every slot is added exactly once at any legal width.
97
+ // The coordinates are the BUILTINS, never `subgroupExclusiveAdd(1u)` /
98
+ // `subgroupAdd(1u)`: those agree with them under this contract, but a driver
99
+ // in the wild answers a claim derived from them with zero and leaves most of
100
+ // the workgroup's slots unclaimed. Every lane of this entry point is active
101
+ // here, so the full subgroup width is the right stride.
102
+ let rank = sg_lane;
103
+ let count = sg_size;
104
  sg_partials[tid] = select(vec2<f32>(0.0, 0.0), s, rank == 0u);
105
  workgroupBarrier();
106
  var total = vec2<f32>(0.0, 0.0);
 
121
  {% endif %}
122
  }
123
 
124
+ {% endif %}
125
  @compute @workgroup_size(WG, 1, 1)
126
  fn main(
127
  @builtin(workgroup_id) wg_id: vec3<u32>,
128
+ @builtin(local_invocation_id) lid: vec3<u32>{% if useSubgroups and not shortGroup %},
129
+ @builtin(subgroup_invocation_id) sg_lane: u32,
130
+ @builtin(subgroup_size) sg_size: u32{% endif %}
 
131
  ) {
132
  let row = wg_id.x + wg_id.y * {{ DISPATCH_FOLD_WIDTH }}u;
133
  if (row >= params.rows) {
134
  return;
135
  }
136
+ {% if shortGroup %}
137
+ if (lid.x != 0u) { return; }
138
+ {% else %}
139
  let tid = lid.x;
140
+ {% endif %}
141
 
142
  // Base offset from the kept-axis coordinates.
143
  var base_off = 0u;
144
  {{ nd_offset("base_off", "row", 0) | indent(2, true) }}
145
+ {% if shortGroup %}
146
+ {{ indexed_small_group(nd_offset, vectorizedSpec) }}
147
+ {% else %}
148
  {% if vectorizedSpec %}
149
  let shift = f32(x[base_off / 4u].x);
150
  {% else %}
 
169
  {% endif %}
170
  }
171
 
172
+ let totals = reduce_pair(acc, tid{% if useSubgroups %}, sg_lane, sg_size{% endif %});
173
  let mean_d = totals.x / f32(R);
174
  let variance = max(totals.y / f32(R) - mean_d * mean_d, 0.0);
 
175
  let denom = sqrt(variance);
176
 
177
  {% if vectorizedSpec %}
 
183
  var off = base_off;
184
  {{ nd_offset("off", "r", 1) | indent(4, true) }}{% if vectorizedSpec %}
185
  let v = vec4<f32>(x[off / 4u]);
186
+ y[off / 4u] = {{ vecType }}({{ subtract(subtract("v", "shift", true), "mean_d", true) }} / vec4<f32>(denom));
187
  {% else %}
188
+ y[off] = {{ scalar }}({{ subtract(subtract("f32(x[off])", "shift"), "mean_d") }} / denom);
189
  {% endif %}
190
  }
191
+ {% endif %}
192
  }
build/webgpu/metadata.json CHANGED
@@ -1,29 +1,31 @@
1
  {
2
  "name": "ai.onnx.MeanVarianceNormalization",
3
- "id": "_ai_onnx_meanvariancenormalization_webgpu_b716a78",
4
  "version": 1,
5
  "license": "Apache-2.0",
6
  "backend": { "type": "webgpu" },
7
  "digest": {
8
  "algorithm": "sha256",
9
  "files": {
10
- "bench.json": "zH0PcLLzlKTcTGM2WzPi8keFUjvDcCnttgcQLxJ9WuU=",
11
- "manifest.json": "Snfz0B5Kkd7enbnP+ETHCh/vyME+C3vu4puxVB1xF3c=",
12
- "mean-variance-normalization-serial-rows.wgsl.jinja": "qcoGxwmc0jShVeozos6da6awjOJbbIIKLfoMCTyzNuk=",
13
- "mean-variance-normalization-subgroup.wgsl.jinja": "GTbYa5JP9Z186OoP6/BZ6w9CyZD2iihXHHl2Cil91pE=",
 
14
  "noop.wgsl.jinja": "k/5BMD6UO81N7XlF+t4iSKyt3dbtcqNMCru5aUKNBKE=",
15
- "norm-flat-apply.wgsl.jinja": "fJkwUp+SOc5+EV2M+skzaoOyf4cCAj6RE/l9EFpRzlw=",
16
- "norm-flat-splitk-combine.wgsl.jinja": "qrWEZGCTfaNnkDSBX7p6j+pnJHKCaAwFmHIXe0DJQC0=",
17
- "norm-flat-splitk-partials.wgsl.jinja": "mQFvRpYjvQsoFwdFiShP0nMYFrWbaGmWxYIMXrSi4Sc=",
18
- "test.json": "bGHJmclwK4mv21Rm4JYKnWsrwe5GeHdDnBXy+q8fIj8="
19
  }
20
  },
21
- "provenance": { "kernel": { "sha": "91d990483a174128daf7673f3f37a7c890493ae1", "dirty": false } },
22
  "webgpu": {
23
- "manifestSpec": "2.0",
24
  "variants": {
25
  "empty_noop": ["noop.wgsl.jinja"],
26
  "all_axes_flat_split": ["norm-flat-apply.wgsl.jinja", "norm-flat-splitk-combine.wgsl.jinja", "norm-flat-splitk-partials.wgsl.jinja"],
 
27
  "serial_rows": ["mean-variance-normalization-serial-rows.wgsl.jinja"],
28
  "cooperative_vec4": ["mean-variance-normalization-subgroup.wgsl.jinja"],
29
  "cooperative_scalar": ["mean-variance-normalization-subgroup.wgsl.jinja"]
 
1
  {
2
  "name": "ai.onnx.MeanVarianceNormalization",
3
+ "id": "_ai_onnx_meanvariancenormalization_webgpu_85e599c",
4
  "version": 1,
5
  "license": "Apache-2.0",
6
  "backend": { "type": "webgpu" },
7
  "digest": {
8
  "algorithm": "sha256",
9
  "files": {
10
+ "bench.json": "evedCasBZFZVduU8ildFMV2Akf76pploR2KtoAy9EIw=",
11
+ "manifest.json": "iBS4rpeWaBACd7GbnoAYLUB96cJVBEV90PYewcY97vc=",
12
+ "mean-variance-normalization-packed-rows.wgsl.jinja": "oD40PGfvnT00FNOwz1Kt3uLBo//T6s8ItMXu6AG2Daw=",
13
+ "mean-variance-normalization-serial-rows.wgsl.jinja": "FzHqHCKU5zFvX4wSxRU+taXe5o4rjkfLckYYx92LztI=",
14
+ "mean-variance-normalization-subgroup.wgsl.jinja": "Odpm4LwlNRrB7HrK4UI3tRvervrlOfWHcW06frw/s1Y=",
15
  "noop.wgsl.jinja": "k/5BMD6UO81N7XlF+t4iSKyt3dbtcqNMCru5aUKNBKE=",
16
+ "norm-flat-apply.wgsl.jinja": "F+5aySjp34jig9aiKiCFcg9fEpGNRNlcenEqMbpzZBY=",
17
+ "norm-flat-splitk-combine.wgsl.jinja": "hwWrqyz1DrwsOhxMR6OySSAFGWG8aiYb0MsiLdpp1kk=",
18
+ "norm-flat-splitk-partials.wgsl.jinja": "JYD6TeaKsOyk0ZL+yHUhqh65kHSqL4h2NlC261PqtKY=",
19
+ "test.json": "PI5ZucTE7woRMpLWN33z6rsoTAnlIsm+udDXiaOzDm4="
20
  }
21
  },
22
+ "provenance": { "kernel": { "sha": "6fdf6301e2bbcc2f03bf1eaf493b7ad55ef33afc", "dirty": false } },
23
  "webgpu": {
24
+ "manifestSpec": "2.1",
25
  "variants": {
26
  "empty_noop": ["noop.wgsl.jinja"],
27
  "all_axes_flat_split": ["norm-flat-apply.wgsl.jinja", "norm-flat-splitk-combine.wgsl.jinja", "norm-flat-splitk-partials.wgsl.jinja"],
28
+ "packed_short_groups": ["mean-variance-normalization-packed-rows.wgsl.jinja"],
29
  "serial_rows": ["mean-variance-normalization-serial-rows.wgsl.jinja"],
30
  "cooperative_vec4": ["mean-variance-normalization-subgroup.wgsl.jinja"],
31
  "cooperative_scalar": ["mean-variance-normalization-subgroup.wgsl.jinja"]
build/webgpu/norm-flat-apply.wgsl.jinja CHANGED
@@ -1,13 +1,26 @@
1
- {% if usesF16Spec %}
2
- enable f16;
3
- {% endif %}
 
 
 
 
 
 
 
4
  {{ env.wgsl.resourceDeclarations }}
5
 
6
  @compute @workgroup_size({{ workgroupSizeSpec }}, 1, 1)
7
  fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
8
- let i = gid.x + gid.y * {{ DISPATCH_FOLD_WIDTH }}u * {{ workgroupSizeSpec }}u;
9
- if (i >= params.count) {
10
- return;
11
- }
12
- y[i] = {{ scalar }}((f32(x[i]) - stats[0]) / stats[1]);
 
 
 
 
 
 
13
  }
 
1
+ {% macro subtract(value, shift, vector=false) %}
2
+ fma(-1.0, {{ shift }}, {{ value }}){% endmacro %}
3
+ {% macro flat_index_2d(workgroupSize, name="i", bound="params.count", guardInline=false) %}
4
+ {% set wgTerm = workgroupSize ~ "u" if workgroupSize is number else workgroupSize %}
5
+ // 2D-folded flat index: gid.y carries the high bits past the dispatch's
6
+ // per-axis workgroup fold width.
7
+ let {{ name }} = gid.x + gid.y * {{ DISPATCH_FOLD_WIDTH }}u * {{ wgTerm }};
8
+ if ({{ name }} >= {{ bound }}) {
9
+ return;
10
+ }{% endmacro %}
11
  {{ env.wgsl.resourceDeclarations }}
12
 
13
  @compute @workgroup_size({{ workgroupSizeSpec }}, 1, 1)
14
  fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
15
+ {{ flat_index_2d(workgroupSizeSpec) }}
16
+ // Divide the shifted difference BEFORE the mean is subtracted, so no sum ever
17
+ // mixes a value of order 1 with one of order 1e-8. Subtracting both shifts
18
+ // first and dividing once is exact as written, but a driver that reassociates
19
+ // it into x - (x[0] + mean) loses the mean entirely: for inputs one ULP apart
20
+ // the mean is far below an ULP of x[0], so the result would be {0, 2.12} where
21
+ // {-0.71, 1.41} is owed. After the division both terms are order 1, so no
22
+ // reassociation of them can drop one, at the cost of one extra division per
23
+ // element.
24
+ let d = {{ subtract("f32(x[i])", "f32(x[0])") }};
25
+ y[i] = {{ scalar }}(d / stats[1] - stats[0] / stats[1]);
26
  }
build/webgpu/norm-flat-splitk-combine.wgsl.jinja CHANGED
@@ -1,6 +1,3 @@
1
- {% if usesF16Spec %}
2
- enable f16;
3
- {% endif %}
4
  {{ env.wgsl.resourceDeclarations }}
5
 
6
  const SPLIT: u32 = {{ splitSpec }}u;
@@ -11,10 +8,9 @@ fn main() {
11
  for (var part = 0u; part < SPLIT; part = part + 1u) {
12
  pair = pair + partials[part];
13
  }
14
- let shift = f32(x[0]);
15
  let n = f32(params.count);
16
  let mean_d = pair.x / n;
17
  let variance = max(pair.y / n - mean_d * mean_d, 0.0);
18
- stats[0] = shift + mean_d;
19
  stats[1] = sqrt(variance);
20
  }
 
 
 
 
1
  {{ env.wgsl.resourceDeclarations }}
2
 
3
  const SPLIT: u32 = {{ splitSpec }}u;
 
8
  for (var part = 0u; part < SPLIT; part = part + 1u) {
9
  pair = pair + partials[part];
10
  }
 
11
  let n = f32(params.count);
12
  let mean_d = pair.x / n;
13
  let variance = max(pair.y / n - mean_d * mean_d, 0.0);
14
+ stats[0] = mean_d;
15
  stats[1] = sqrt(variance);
16
  }
build/webgpu/norm-flat-splitk-partials.wgsl.jinja CHANGED
@@ -1,6 +1,3 @@
1
- {% if usesF16Spec %}
2
- enable f16;
3
- {% endif %}
4
  {{ env.wgsl.resourceDeclarations }}
5
 
6
  const WG: u32 = {{ workgroupSizeSpec }}u;
 
 
 
 
1
  {{ env.wgsl.resourceDeclarations }}
2
 
3
  const WG: u32 = {{ workgroupSizeSpec }}u;
build/webgpu/test.json CHANGED
@@ -114,15 +114,11 @@
114
  }
115
  },
116
  {
117
- "name": "f32_tiny_variance_axis2_gpu_gap",
118
- "skipGpu": {
119
- "category": "permanent",
120
- "reason": "Portable WGSL floating-point semantics do not guarantee preservation of the subnormal values required by this fixture. Backend evidence: WebGPU/Metal flushes subnormals to zero in f32; the subnormal reduced-axis variance collapses to zero so normalization yields Infinity."
121
- },
122
  "provenance": {
123
  "source": "onnxruntime/test/providers/cpu/tensor/mean_variance_normalization_test.cc",
124
  "test": "MeanVarianceNormalizationTest.DefaultAxes",
125
- "notes": "Valid finite inputs with a positive subnormal variance along the reduced axis; output should be finite instead of +/-Infinity."
126
  },
127
  "attrs": { "axes": [2] },
128
  "inputs": {
@@ -135,15 +131,11 @@
135
  "outputs": { "y": { "dtype": "float32", "shape": [2, 1, 2], "tolerance": 0.00001 } }
136
  },
137
  {
138
- "name": "f32_tiny_variance_default_axes_rank4_gpu_gap",
139
- "skipGpu": {
140
- "category": "permanent",
141
- "reason": "Portable WGSL floating-point semantics do not guarantee preservation of the subnormal values required by this fixture. Backend evidence: WebGPU/Metal flushes subnormals to zero in f32; the subnormal reduced variance collapses to zero so normalization is non-finite (rank-4)."
142
- },
143
  "provenance": {
144
  "source": "onnxruntime/test/providers/cpu/tensor/mean_variance_normalization_test.cc",
145
  "test": "MeanVarianceNormalizationTest.DefaultAxes",
146
- "notes": "With rank-4 default spatial axes, a positive subnormal variance must produce a finite normalized output."
147
  },
148
  "attrs": { "axes": [0, 2, 3] },
149
  "inputs": {
@@ -156,15 +148,11 @@
156
  "outputs": { "y": { "dtype": "float32", "shape": [1, 1, 2, 2], "tolerance": 0.00001 } }
157
  },
158
  {
159
- "name": "f32_tiny_variance_default_axes_rank5_gpu_gap",
160
- "skipGpu": {
161
- "category": "permanent",
162
- "reason": "Portable WGSL floating-point semantics do not guarantee preservation of the subnormal values required by this fixture. Backend evidence: WebGPU/Metal flushes subnormals to zero in f32; the subnormal reduced variance collapses to zero so normalization is non-finite (rank-5)."
163
- },
164
  "provenance": {
165
  "source": "onnxruntime/test/providers/cpu/tensor/mean_variance_normalization_test.cc",
166
  "test": "MeanVarianceNormalizationTest.DefaultAxes",
167
- "notes": "With a rank-5 input, a positive subnormal reduced variance must produce finite normalized values."
168
  },
169
  "attrs": { "axes": [0, 2, 3, 4] },
170
  "inputs": {
@@ -230,9 +218,7 @@
230
  },
231
  {
232
  "name": "channel_axis_no_subgroup_wg64_tail65_f32",
233
- "provenance": {
234
- "notes": "Locks the 65-value channel reduction where the portable reduction uses 64 fully occupied lanes plus one tail value instead of a half-empty 128-lane tree."
235
- },
236
  "attrs": { "axes": [1] },
237
  "inputs": {
238
  "x": {
@@ -524,7 +510,7 @@
524
  {
525
  "name": "all_axes_flat_split_f16_65536",
526
  "provenance": {
527
- "notes": "Locks the widened-f32 split-reduction path for large f16 tensors; scratch stays f32 while input/output storage remains f16."
528
  },
529
  "attrs": { "axes": [0, 1, 2, 3] },
530
  "inputs": {
@@ -565,7 +551,7 @@
565
  {
566
  "name": "rank5_serial_rows_channel_axis_f16",
567
  "provenance": {
568
- "notes": "Float16 data exercises the coalesced serial-row path with at least SERIAL_MIN_ROWS independent rows and a reduction within SERIAL_MAX_REDUCTION."
569
  },
570
  "attrs": { "axes": [1] },
571
  "inputs": {
@@ -593,6 +579,1782 @@
593
  "outputs": {
594
  "y": { "dtype": "float32", "shape": [1, 4, 2, 2, 2, 2, 64], "tolerance": 0.00002, "relTolerance": 0.00002 }
595
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
596
  }
597
  ]
598
  }
 
114
  }
115
  },
116
  {
117
+ "name": "f32_tiny_variance_axis2",
 
 
 
 
118
  "provenance": {
119
  "source": "onnxruntime/test/providers/cpu/tensor/mean_variance_normalization_test.cc",
120
  "test": "MeanVarianceNormalizationTest.DefaultAxes",
121
+ "notes": "The input values are normal f32 values, but their unscaled variance is subnormal. Normalization must remain finite."
122
  },
123
  "attrs": { "axes": [2] },
124
  "inputs": {
 
131
  "outputs": { "y": { "dtype": "float32", "shape": [2, 1, 2], "tolerance": 0.00001 } }
132
  },
133
  {
134
+ "name": "f32_tiny_variance_default_axes_rank4",
 
 
 
 
135
  "provenance": {
136
  "source": "onnxruntime/test/providers/cpu/tensor/mean_variance_normalization_test.cc",
137
  "test": "MeanVarianceNormalizationTest.DefaultAxes",
138
+ "notes": "The input values are normal f32 values, but their unscaled variance is subnormal. Normalization must remain finite."
139
  },
140
  "attrs": { "axes": [0, 2, 3] },
141
  "inputs": {
 
148
  "outputs": { "y": { "dtype": "float32", "shape": [1, 1, 2, 2], "tolerance": 0.00001 } }
149
  },
150
  {
151
+ "name": "f32_tiny_variance_default_axes_rank5",
 
 
 
 
152
  "provenance": {
153
  "source": "onnxruntime/test/providers/cpu/tensor/mean_variance_normalization_test.cc",
154
  "test": "MeanVarianceNormalizationTest.DefaultAxes",
155
+ "notes": "The input values are normal f32 values, but their unscaled variance is subnormal. Normalization must remain finite."
156
  },
157
  "attrs": { "axes": [0, 2, 3, 4] },
158
  "inputs": {
 
218
  },
219
  {
220
  "name": "channel_axis_no_subgroup_wg64_tail65_f32",
221
+ "provenance": { "notes": "A 65-value channel reduction checks the final value beyond a 64-element boundary." },
 
 
222
  "attrs": { "axes": [1] },
223
  "inputs": {
224
  "x": {
 
510
  {
511
  "name": "all_axes_flat_split_f16_65536",
512
  "provenance": {
513
+ "notes": "A large float16 tensor reduced across all axes checks accurate accumulation and float16 output conversion."
514
  },
515
  "attrs": { "axes": [0, 1, 2, 3] },
516
  "inputs": {
 
551
  {
552
  "name": "rank5_serial_rows_channel_axis_f16",
553
  "provenance": {
554
+ "notes": "A float16, rank-5 input reduces over axis 1 (32 channels) across 512 independent groups; verifies normalization accuracy at this row count and reduction size in float16."
555
  },
556
  "attrs": { "axes": [1] },
557
  "inputs": {
 
579
  "outputs": {
580
  "y": { "dtype": "float32", "shape": [1, 4, 2, 2, 2, 2, 64], "tolerance": 0.00002, "relTolerance": 0.00002 }
581
  }
582
+ },
583
+ {
584
+ "name": "packed_boundary_float32_rows255_r2",
585
+ "provenance": {
586
+ "notes": "255 independent 2-element groups (axis 2) sit one row below a 256-row count; verifies the float32 output, including the last row, matches the reference."
587
+ },
588
+ "attrs": { "axes": [2] },
589
+ "inputs": {
590
+ "x": {
591
+ "dtype": "float32",
592
+ "shape": [255, 1, 2],
593
+ "data": { "kind": "cycle", "values": [0.125, -0.75, 0.5, 1.25, -0.25, 0.875] }
594
+ }
595
+ },
596
+ "outputs": { "y": { "dtype": "float32", "shape": [255, 1, 2], "tolerance": 0.00001, "relTolerance": 0.00001 } }
597
+ },
598
+ {
599
+ "name": "packed_boundary_float32_rows256_r2",
600
+ "provenance": {
601
+ "notes": "256 independent 2-element groups (axis 2) exactly reach a 256-row count; verifies every float32 row, with none left over, matches the reference."
602
+ },
603
+ "attrs": { "axes": [2] },
604
+ "inputs": {
605
+ "x": {
606
+ "dtype": "float32",
607
+ "shape": [256, 1, 2],
608
+ "data": { "kind": "cycle", "values": [0.125, -0.75, 0.5, 1.25, -0.25, 0.875] }
609
+ }
610
+ },
611
+ "outputs": { "y": { "dtype": "float32", "shape": [256, 1, 2], "tolerance": 0.00001, "relTolerance": 0.00001 } }
612
+ },
613
+ {
614
+ "name": "packed_boundary_float32_rows257_r2",
615
+ "provenance": {
616
+ "notes": "257 independent 2-element groups (axis 2) sit one row above a 256-row count; verifies the extra float32 row, beyond the 256, matches the reference."
617
+ },
618
+ "attrs": { "axes": [2] },
619
+ "inputs": {
620
+ "x": {
621
+ "dtype": "float32",
622
+ "shape": [257, 1, 2],
623
+ "data": { "kind": "cycle", "values": [0.125, -0.75, 0.5, 1.25, -0.25, 0.875] }
624
+ }
625
+ },
626
+ "outputs": { "y": { "dtype": "float32", "shape": [257, 1, 2], "tolerance": 0.00001, "relTolerance": 0.00001 } }
627
+ },
628
+ {
629
+ "name": "packed_boundary_float32_rows513_r2",
630
+ "provenance": {
631
+ "notes": "513 independent 2-element groups (axis 2) sit one row above twice a 256-row count; verifies the extra float32 row at this larger scale matches the reference."
632
+ },
633
+ "attrs": { "axes": [2] },
634
+ "inputs": {
635
+ "x": {
636
+ "dtype": "float32",
637
+ "shape": [513, 1, 2],
638
+ "data": { "kind": "cycle", "values": [0.125, -0.75, 0.5, 1.25, -0.25, 0.875] }
639
+ }
640
+ },
641
+ "outputs": { "y": { "dtype": "float32", "shape": [513, 1, 2], "tolerance": 0.00001, "relTolerance": 0.00001 } }
642
+ },
643
+ {
644
+ "name": "packed_boundary_float32_rows255_r3",
645
+ "provenance": {
646
+ "notes": "255 independent 3-element groups (axis 2) sit one row below a 256-row count; verifies the float32 output, including the last row, matches the reference."
647
+ },
648
+ "attrs": { "axes": [2] },
649
+ "inputs": {
650
+ "x": {
651
+ "dtype": "float32",
652
+ "shape": [255, 1, 3],
653
+ "data": { "kind": "cycle", "values": [0.125, -0.75, 0.5, 1.25, -0.25, 0.875] }
654
+ }
655
+ },
656
+ "outputs": { "y": { "dtype": "float32", "shape": [255, 1, 3], "tolerance": 0.00001, "relTolerance": 0.00001 } }
657
+ },
658
+ {
659
+ "name": "packed_boundary_float32_rows256_r3",
660
+ "provenance": {
661
+ "notes": "256 independent 3-element groups (axis 2) exactly reach a 256-row count; verifies every float32 row, with none left over, matches the reference."
662
+ },
663
+ "attrs": { "axes": [2] },
664
+ "inputs": {
665
+ "x": {
666
+ "dtype": "float32",
667
+ "shape": [256, 1, 3],
668
+ "data": { "kind": "cycle", "values": [0.125, -0.75, 0.5, 1.25, -0.25, 0.875] }
669
+ }
670
+ },
671
+ "outputs": { "y": { "dtype": "float32", "shape": [256, 1, 3], "tolerance": 0.00001, "relTolerance": 0.00001 } }
672
+ },
673
+ {
674
+ "name": "packed_boundary_float32_rows257_r3",
675
+ "provenance": {
676
+ "notes": "257 independent 3-element groups (axis 2) sit one row above a 256-row count; verifies the extra float32 row, beyond the 256, matches the reference."
677
+ },
678
+ "attrs": { "axes": [2] },
679
+ "inputs": {
680
+ "x": {
681
+ "dtype": "float32",
682
+ "shape": [257, 1, 3],
683
+ "data": { "kind": "cycle", "values": [0.125, -0.75, 0.5, 1.25, -0.25, 0.875] }
684
+ }
685
+ },
686
+ "outputs": { "y": { "dtype": "float32", "shape": [257, 1, 3], "tolerance": 0.00001, "relTolerance": 0.00001 } }
687
+ },
688
+ {
689
+ "name": "packed_boundary_float32_rows513_r3",
690
+ "provenance": {
691
+ "notes": "513 independent 3-element groups (axis 2) sit one row above twice a 256-row count; verifies the extra float32 row at this larger scale matches the reference."
692
+ },
693
+ "attrs": { "axes": [2] },
694
+ "inputs": {
695
+ "x": {
696
+ "dtype": "float32",
697
+ "shape": [513, 1, 3],
698
+ "data": { "kind": "cycle", "values": [0.125, -0.75, 0.5, 1.25, -0.25, 0.875] }
699
+ }
700
+ },
701
+ "outputs": { "y": { "dtype": "float32", "shape": [513, 1, 3], "tolerance": 0.00001, "relTolerance": 0.00001 } }
702
+ },
703
+ {
704
+ "name": "packed_boundary_float32_rows255_r4",
705
+ "provenance": {
706
+ "notes": "255 independent 4-element groups (axis 2) sit one row below a 256-row count; verifies the float32 output, including the last row, matches the reference."
707
+ },
708
+ "attrs": { "axes": [2] },
709
+ "inputs": {
710
+ "x": {
711
+ "dtype": "float32",
712
+ "shape": [255, 1, 4],
713
+ "data": { "kind": "cycle", "values": [0.125, -0.75, 0.5, 1.25, -0.25, 0.875] }
714
+ }
715
+ },
716
+ "outputs": { "y": { "dtype": "float32", "shape": [255, 1, 4], "tolerance": 0.00001, "relTolerance": 0.00001 } }
717
+ },
718
+ {
719
+ "name": "packed_boundary_float32_rows256_r4",
720
+ "provenance": {
721
+ "notes": "256 independent 4-element groups (axis 2) exactly reach a 256-row count; verifies every float32 row, with none left over, matches the reference."
722
+ },
723
+ "attrs": { "axes": [2] },
724
+ "inputs": {
725
+ "x": {
726
+ "dtype": "float32",
727
+ "shape": [256, 1, 4],
728
+ "data": { "kind": "cycle", "values": [0.125, -0.75, 0.5, 1.25, -0.25, 0.875] }
729
+ }
730
+ },
731
+ "outputs": { "y": { "dtype": "float32", "shape": [256, 1, 4], "tolerance": 0.00001, "relTolerance": 0.00001 } }
732
+ },
733
+ {
734
+ "name": "packed_boundary_float32_rows257_r4",
735
+ "provenance": {
736
+ "notes": "257 independent 4-element groups (axis 2) sit one row above a 256-row count; verifies the extra float32 row, beyond the 256, matches the reference."
737
+ },
738
+ "attrs": { "axes": [2] },
739
+ "inputs": {
740
+ "x": {
741
+ "dtype": "float32",
742
+ "shape": [257, 1, 4],
743
+ "data": { "kind": "cycle", "values": [0.125, -0.75, 0.5, 1.25, -0.25, 0.875] }
744
+ }
745
+ },
746
+ "outputs": { "y": { "dtype": "float32", "shape": [257, 1, 4], "tolerance": 0.00001, "relTolerance": 0.00001 } }
747
+ },
748
+ {
749
+ "name": "packed_boundary_float32_rows513_r4",
750
+ "provenance": {
751
+ "notes": "513 independent 4-element groups (axis 2) sit one row above twice a 256-row count; verifies the extra float32 row at this larger scale matches the reference."
752
+ },
753
+ "attrs": { "axes": [2] },
754
+ "inputs": {
755
+ "x": {
756
+ "dtype": "float32",
757
+ "shape": [513, 1, 4],
758
+ "data": { "kind": "cycle", "values": [0.125, -0.75, 0.5, 1.25, -0.25, 0.875] }
759
+ }
760
+ },
761
+ "outputs": { "y": { "dtype": "float32", "shape": [513, 1, 4], "tolerance": 0.00001, "relTolerance": 0.00001 } }
762
+ },
763
+ {
764
+ "name": "shifted_mean_float32_unit_rows2_r2",
765
+ "provenance": {
766
+ "notes": "Adjacent representable inputs retain their centered differences without rounding an absolute mean."
767
+ },
768
+ "attrs": { "axes": [2] },
769
+ "inputs": {
770
+ "x": {
771
+ "dtype": "float32",
772
+ "shape": [2, 1, 2],
773
+ "data": { "kind": "cycle", "values": [1.0, 1.0000001192092896] }
774
+ }
775
+ },
776
+ "outputs": { "y": { "dtype": "float32", "shape": [2, 1, 2], "tolerance": 0.00001, "relTolerance": 0.00001 } }
777
+ },
778
+ {
779
+ "name": "shifted_mean_float32_unit_rows2_r3",
780
+ "provenance": {
781
+ "notes": "Adjacent representable inputs retain their centered differences without rounding an absolute mean."
782
+ },
783
+ "attrs": { "axes": [2] },
784
+ "inputs": {
785
+ "x": {
786
+ "dtype": "float32",
787
+ "shape": [2, 1, 3],
788
+ "data": { "kind": "cycle", "values": [1.0, 1.0000001192092896, 1.0] }
789
+ }
790
+ },
791
+ "outputs": { "y": { "dtype": "float32", "shape": [2, 1, 3], "tolerance": 0.00001, "relTolerance": 0.00001 } }
792
+ },
793
+ {
794
+ "name": "shifted_mean_float32_unit_rows2_r8",
795
+ "provenance": {
796
+ "notes": "Adjacent representable inputs retain their centered differences without rounding an absolute mean."
797
+ },
798
+ "attrs": { "axes": [2] },
799
+ "inputs": {
800
+ "x": {
801
+ "dtype": "float32",
802
+ "shape": [2, 1, 8],
803
+ "data": {
804
+ "kind": "cycle",
805
+ "values": [1.0, 1.0000001192092896, 1.0, 1.0, 1.0000001192092896, 1.0, 1.0, 1.0000001192092896]
806
+ }
807
+ }
808
+ },
809
+ "outputs": { "y": { "dtype": "float32", "shape": [2, 1, 8], "tolerance": 0.00001, "relTolerance": 0.00001 } }
810
+ },
811
+ {
812
+ "name": "shifted_mean_float32_unit_rows256_r2",
813
+ "provenance": {
814
+ "notes": "Adjacent representable inputs retain their centered differences without rounding an absolute mean."
815
+ },
816
+ "attrs": { "axes": [2] },
817
+ "inputs": {
818
+ "x": {
819
+ "dtype": "float32",
820
+ "shape": [256, 1, 2],
821
+ "data": { "kind": "cycle", "values": [1.0, 1.0000001192092896] }
822
+ }
823
+ },
824
+ "outputs": { "y": { "dtype": "float32", "shape": [256, 1, 2], "tolerance": 0.00001, "relTolerance": 0.00001 } }
825
+ },
826
+ {
827
+ "name": "shifted_mean_float32_unit_rows257_r3",
828
+ "provenance": {
829
+ "notes": "Adjacent representable inputs retain their centered differences without rounding an absolute mean."
830
+ },
831
+ "attrs": { "axes": [2] },
832
+ "inputs": {
833
+ "x": {
834
+ "dtype": "float32",
835
+ "shape": [257, 1, 3],
836
+ "data": { "kind": "cycle", "values": [1.0, 1.0000001192092896, 1.0] }
837
+ }
838
+ },
839
+ "outputs": { "y": { "dtype": "float32", "shape": [257, 1, 3], "tolerance": 0.00001, "relTolerance": 0.00001 } }
840
+ },
841
+ {
842
+ "name": "shifted_mean_float32_unit_rows256_r4",
843
+ "provenance": {
844
+ "notes": "Adjacent representable inputs retain their centered differences without rounding an absolute mean."
845
+ },
846
+ "attrs": { "axes": [2] },
847
+ "inputs": {
848
+ "x": {
849
+ "dtype": "float32",
850
+ "shape": [256, 1, 4],
851
+ "data": { "kind": "cycle", "values": [1.0, 1.0000001192092896, 1.0, 1.0] }
852
+ }
853
+ },
854
+ "outputs": { "y": { "dtype": "float32", "shape": [256, 1, 4], "tolerance": 0.00001, "relTolerance": 0.00001 } }
855
+ },
856
+ {
857
+ "name": "shifted_mean_float32_unit_rows256_r8",
858
+ "provenance": {
859
+ "notes": "Adjacent representable inputs retain their centered differences without rounding an absolute mean."
860
+ },
861
+ "attrs": { "axes": [2] },
862
+ "inputs": {
863
+ "x": {
864
+ "dtype": "float32",
865
+ "shape": [256, 1, 8],
866
+ "data": {
867
+ "kind": "cycle",
868
+ "values": [1.0, 1.0000001192092896, 1.0, 1.0, 1.0000001192092896, 1.0, 1.0, 1.0000001192092896]
869
+ }
870
+ }
871
+ },
872
+ "outputs": { "y": { "dtype": "float32", "shape": [256, 1, 8], "tolerance": 0.00001, "relTolerance": 0.00001 } }
873
+ },
874
+ {
875
+ "name": "shifted_mean_float32_large_rows2_r2",
876
+ "provenance": {
877
+ "notes": "Adjacent representable inputs retain their centered differences without rounding an absolute mean."
878
+ },
879
+ "attrs": { "axes": [2] },
880
+ "inputs": {
881
+ "x": {
882
+ "dtype": "float32",
883
+ "shape": [2, 1, 2],
884
+ "data": { "kind": "cycle", "values": [100000000.0, 100000008.0] }
885
+ }
886
+ },
887
+ "outputs": { "y": { "dtype": "float32", "shape": [2, 1, 2], "tolerance": 0.00001, "relTolerance": 0.00001 } }
888
+ },
889
+ {
890
+ "name": "shifted_mean_float32_large_rows2_r3",
891
+ "provenance": {
892
+ "notes": "Adjacent representable inputs retain their centered differences without rounding an absolute mean."
893
+ },
894
+ "attrs": { "axes": [2] },
895
+ "inputs": {
896
+ "x": {
897
+ "dtype": "float32",
898
+ "shape": [2, 1, 3],
899
+ "data": { "kind": "cycle", "values": [100000000.0, 100000008.0, 100000000.0] }
900
+ }
901
+ },
902
+ "outputs": { "y": { "dtype": "float32", "shape": [2, 1, 3], "tolerance": 0.00001, "relTolerance": 0.00001 } }
903
+ },
904
+ {
905
+ "name": "shifted_mean_float32_large_rows2_r8",
906
+ "provenance": {
907
+ "notes": "Adjacent representable inputs retain their centered differences without rounding an absolute mean."
908
+ },
909
+ "attrs": { "axes": [2] },
910
+ "inputs": {
911
+ "x": {
912
+ "dtype": "float32",
913
+ "shape": [2, 1, 8],
914
+ "data": {
915
+ "kind": "cycle",
916
+ "values": [100000000.0, 100000008.0, 100000000.0, 100000000.0, 100000008.0, 100000000.0, 100000000.0, 100000008.0]
917
+ }
918
+ }
919
+ },
920
+ "outputs": { "y": { "dtype": "float32", "shape": [2, 1, 8], "tolerance": 0.00001, "relTolerance": 0.00001 } }
921
+ },
922
+ {
923
+ "name": "shifted_mean_float32_large_rows256_r2",
924
+ "provenance": {
925
+ "notes": "Adjacent representable inputs retain their centered differences without rounding an absolute mean."
926
+ },
927
+ "attrs": { "axes": [2] },
928
+ "inputs": {
929
+ "x": {
930
+ "dtype": "float32",
931
+ "shape": [256, 1, 2],
932
+ "data": { "kind": "cycle", "values": [100000000.0, 100000008.0] }
933
+ }
934
+ },
935
+ "outputs": { "y": { "dtype": "float32", "shape": [256, 1, 2], "tolerance": 0.00001, "relTolerance": 0.00001 } }
936
+ },
937
+ {
938
+ "name": "shifted_mean_float32_large_rows257_r3",
939
+ "provenance": {
940
+ "notes": "Adjacent representable inputs retain their centered differences without rounding an absolute mean."
941
+ },
942
+ "attrs": { "axes": [2] },
943
+ "inputs": {
944
+ "x": {
945
+ "dtype": "float32",
946
+ "shape": [257, 1, 3],
947
+ "data": { "kind": "cycle", "values": [100000000.0, 100000008.0, 100000000.0] }
948
+ }
949
+ },
950
+ "outputs": { "y": { "dtype": "float32", "shape": [257, 1, 3], "tolerance": 0.00001, "relTolerance": 0.00001 } }
951
+ },
952
+ {
953
+ "name": "shifted_mean_float32_large_rows256_r4",
954
+ "provenance": {
955
+ "notes": "Adjacent representable inputs retain their centered differences without rounding an absolute mean."
956
+ },
957
+ "attrs": { "axes": [2] },
958
+ "inputs": {
959
+ "x": {
960
+ "dtype": "float32",
961
+ "shape": [256, 1, 4],
962
+ "data": { "kind": "cycle", "values": [100000000.0, 100000008.0, 100000000.0, 100000000.0] }
963
+ }
964
+ },
965
+ "outputs": { "y": { "dtype": "float32", "shape": [256, 1, 4], "tolerance": 0.00001, "relTolerance": 0.00001 } }
966
+ },
967
+ {
968
+ "name": "shifted_mean_float32_large_rows256_r8",
969
+ "provenance": {
970
+ "notes": "Adjacent representable inputs retain their centered differences without rounding an absolute mean."
971
+ },
972
+ "attrs": { "axes": [2] },
973
+ "inputs": {
974
+ "x": {
975
+ "dtype": "float32",
976
+ "shape": [256, 1, 8],
977
+ "data": {
978
+ "kind": "cycle",
979
+ "values": [100000000.0, 100000008.0, 100000000.0, 100000000.0, 100000008.0, 100000000.0, 100000000.0, 100000008.0]
980
+ }
981
+ }
982
+ },
983
+ "outputs": { "y": { "dtype": "float32", "shape": [256, 1, 8], "tolerance": 0.00001, "relTolerance": 0.00001 } }
984
+ },
985
+ {
986
+ "name": "shifted_mean_flat_float32",
987
+ "provenance": {
988
+ "notes": "The split combine stores a shifted mean and the apply pass preserves both subtractions."
989
+ },
990
+ "attrs": { "axes": [0, 1, 2] },
991
+ "inputs": {
992
+ "x": {
993
+ "dtype": "float32",
994
+ "shape": [1, 1, 65536],
995
+ "data": { "kind": "cycle", "values": [1.0, 1.0000001192092896, 1.0] }
996
+ }
997
+ },
998
+ "outputs": { "y": { "dtype": "float32", "shape": [1, 1, 65536], "tolerance": 0.00001, "relTolerance": 0.00001 } }
999
+ },
1000
+ {
1001
+ "name": "packed_layout_float32_contiguous_axes",
1002
+ "provenance": {
1003
+ "notes": "Checks reduced-span contiguity and rank-general indexing, including a strided fallback."
1004
+ },
1005
+ "attrs": { "axes": [1, 2] },
1006
+ "inputs": {
1007
+ "x": {
1008
+ "dtype": "float32",
1009
+ "shape": [257, 2, 2],
1010
+ "data": { "kind": "cycle", "values": [0.125, -0.75, 0.5, 1.25, -0.25, 0.875] }
1011
+ }
1012
+ },
1013
+ "outputs": { "y": { "dtype": "float32", "shape": [257, 2, 2], "tolerance": 0.00001, "relTolerance": 0.00001 } }
1014
+ },
1015
+ {
1016
+ "name": "packed_layout_float32_singleton_axes",
1017
+ "provenance": {
1018
+ "notes": "Checks reduced-span contiguity and rank-general indexing, including a strided fallback."
1019
+ },
1020
+ "attrs": { "axes": [0, 2, 3] },
1021
+ "inputs": {
1022
+ "x": {
1023
+ "dtype": "float32",
1024
+ "shape": [1, 257, 3, 1],
1025
+ "data": { "kind": "cycle", "values": [0.125, -0.75, 0.5, 1.25, -0.25, 0.875] }
1026
+ }
1027
+ },
1028
+ "outputs": { "y": { "dtype": "float32", "shape": [1, 257, 3, 1], "tolerance": 0.00001, "relTolerance": 0.00001 } }
1029
+ },
1030
+ {
1031
+ "name": "packed_layout_float32_strided_axis",
1032
+ "provenance": {
1033
+ "notes": "Checks reduced-span contiguity and rank-general indexing, including a strided fallback."
1034
+ },
1035
+ "attrs": { "axes": [1] },
1036
+ "inputs": {
1037
+ "x": {
1038
+ "dtype": "float32",
1039
+ "shape": [257, 2, 4],
1040
+ "data": { "kind": "cycle", "values": [0.125, -0.75, 0.5, 1.25, -0.25, 0.875] }
1041
+ }
1042
+ },
1043
+ "outputs": { "y": { "dtype": "float32", "shape": [257, 2, 4], "tolerance": 0.00001, "relTolerance": 0.00001 } }
1044
+ },
1045
+ {
1046
+ "name": "packed_layout_float32_rank8",
1047
+ "provenance": {
1048
+ "notes": "Checks reduced-span contiguity and rank-general indexing, including a strided fallback."
1049
+ },
1050
+ "attrs": { "axes": [-1] },
1051
+ "inputs": {
1052
+ "x": {
1053
+ "dtype": "float32",
1054
+ "shape": [257, 1, 1, 1, 1, 1, 1, 3],
1055
+ "data": { "kind": "cycle", "values": [0.125, -0.75, 0.5, 1.25, -0.25, 0.875] }
1056
+ }
1057
+ },
1058
+ "outputs": {
1059
+ "y": { "dtype": "float32", "shape": [257, 1, 1, 1, 1, 1, 1, 3], "tolerance": 0.00001, "relTolerance": 0.00001 }
1060
+ }
1061
+ },
1062
+ {
1063
+ "name": "packed_zero_variance_float32",
1064
+ "provenance": { "notes": "Zero variance preserves the normalization contract, including the final partial word." },
1065
+ "attrs": { "axes": [2] },
1066
+ "inputs": { "x": { "dtype": "float32", "shape": [257, 1, 3], "data": { "kind": "constant", "value": 7.0 } } },
1067
+ "outputs": {
1068
+ "y": {
1069
+ "dtype": "float32",
1070
+ "shape": [257, 1, 3],
1071
+ "tolerance": 0.00001,
1072
+ "relTolerance": 0.00001,
1073
+ "allowNaN": true
1074
+ }
1075
+ }
1076
+ },
1077
+ {
1078
+ "name": "packed_limited_workgroup_float32",
1079
+ "provenance": {
1080
+ "notes": "An oversized requested workgroup must still produce correct normalization within the device workgroup limit."
1081
+ },
1082
+ "attrs": { "axes": [2] },
1083
+ "inputs": {
1084
+ "x": { "dtype": "float32", "shape": [257, 1, 3], "data": { "kind": "cycle", "values": [0.125, -0.75, 0.5] } }
1085
+ },
1086
+ "outputs": { "y": { "dtype": "float32", "shape": [257, 1, 3], "tolerance": 0.00001, "relTolerance": 0.00001 } },
1087
+ "tunables": { "PACKED_WORKGROUP_SIZE": 2048 }
1088
+ },
1089
+ {
1090
+ "name": "packed_boundary_float16_rows255_r2",
1091
+ "provenance": {
1092
+ "notes": "255 independent 2-element groups (axis 2) sit one row below a 256-row count; verifies the float16 output, including the last row, matches the reference."
1093
+ },
1094
+ "attrs": { "axes": [2] },
1095
+ "inputs": {
1096
+ "x": {
1097
+ "dtype": "float16",
1098
+ "shape": [255, 1, 2],
1099
+ "data": { "kind": "cycle", "values": [0.125, -0.75, 0.5, 1.25, -0.25, 0.875] }
1100
+ }
1101
+ },
1102
+ "outputs": { "y": { "dtype": "float16", "shape": [255, 1, 2], "tolerance": 0.002, "relTolerance": 0.001 } }
1103
+ },
1104
+ {
1105
+ "name": "packed_boundary_float16_rows256_r2",
1106
+ "provenance": {
1107
+ "notes": "256 independent 2-element groups (axis 2) exactly reach a 256-row count; verifies every float16 row, with none left over, matches the reference."
1108
+ },
1109
+ "attrs": { "axes": [2] },
1110
+ "inputs": {
1111
+ "x": {
1112
+ "dtype": "float16",
1113
+ "shape": [256, 1, 2],
1114
+ "data": { "kind": "cycle", "values": [0.125, -0.75, 0.5, 1.25, -0.25, 0.875] }
1115
+ }
1116
+ },
1117
+ "outputs": { "y": { "dtype": "float16", "shape": [256, 1, 2], "tolerance": 0.002, "relTolerance": 0.001 } }
1118
+ },
1119
+ {
1120
+ "name": "packed_boundary_float16_rows257_r2",
1121
+ "provenance": {
1122
+ "notes": "257 independent 2-element groups (axis 2) sit one row above a 256-row count; verifies the extra float16 row, beyond the 256, matches the reference."
1123
+ },
1124
+ "attrs": { "axes": [2] },
1125
+ "inputs": {
1126
+ "x": {
1127
+ "dtype": "float16",
1128
+ "shape": [257, 1, 2],
1129
+ "data": { "kind": "cycle", "values": [0.125, -0.75, 0.5, 1.25, -0.25, 0.875] }
1130
+ }
1131
+ },
1132
+ "outputs": { "y": { "dtype": "float16", "shape": [257, 1, 2], "tolerance": 0.002, "relTolerance": 0.001 } }
1133
+ },
1134
+ {
1135
+ "name": "packed_boundary_float16_rows513_r2",
1136
+ "provenance": {
1137
+ "notes": "513 independent 2-element groups (axis 2) sit one row above twice a 256-row count; verifies the extra float16 row at this larger scale matches the reference."
1138
+ },
1139
+ "attrs": { "axes": [2] },
1140
+ "inputs": {
1141
+ "x": {
1142
+ "dtype": "float16",
1143
+ "shape": [513, 1, 2],
1144
+ "data": { "kind": "cycle", "values": [0.125, -0.75, 0.5, 1.25, -0.25, 0.875] }
1145
+ }
1146
+ },
1147
+ "outputs": { "y": { "dtype": "float16", "shape": [513, 1, 2], "tolerance": 0.002, "relTolerance": 0.001 } }
1148
+ },
1149
+ {
1150
+ "name": "packed_boundary_float16_rows255_r3",
1151
+ "provenance": {
1152
+ "notes": "255 independent 3-element groups (axis 2) sit one row below a 256-row count; verifies the float16 output, including the last row, matches the reference."
1153
+ },
1154
+ "attrs": { "axes": [2] },
1155
+ "inputs": {
1156
+ "x": {
1157
+ "dtype": "float16",
1158
+ "shape": [255, 1, 3],
1159
+ "data": { "kind": "cycle", "values": [0.125, -0.75, 0.5, 1.25, -0.25, 0.875] }
1160
+ }
1161
+ },
1162
+ "outputs": { "y": { "dtype": "float16", "shape": [255, 1, 3], "tolerance": 0.002, "relTolerance": 0.001 } }
1163
+ },
1164
+ {
1165
+ "name": "packed_boundary_float16_rows256_r3",
1166
+ "provenance": {
1167
+ "notes": "256 independent 3-element groups (axis 2) exactly reach a 256-row count; verifies every float16 row, with none left over, matches the reference."
1168
+ },
1169
+ "attrs": { "axes": [2] },
1170
+ "inputs": {
1171
+ "x": {
1172
+ "dtype": "float16",
1173
+ "shape": [256, 1, 3],
1174
+ "data": { "kind": "cycle", "values": [0.125, -0.75, 0.5, 1.25, -0.25, 0.875] }
1175
+ }
1176
+ },
1177
+ "outputs": { "y": { "dtype": "float16", "shape": [256, 1, 3], "tolerance": 0.002, "relTolerance": 0.001 } }
1178
+ },
1179
+ {
1180
+ "name": "packed_boundary_float16_rows257_r3",
1181
+ "provenance": {
1182
+ "notes": "257 independent 3-element groups (axis 2) sit one row above a 256-row count; verifies the extra float16 row, beyond the 256, matches the reference."
1183
+ },
1184
+ "attrs": { "axes": [2] },
1185
+ "inputs": {
1186
+ "x": {
1187
+ "dtype": "float16",
1188
+ "shape": [257, 1, 3],
1189
+ "data": { "kind": "cycle", "values": [0.125, -0.75, 0.5, 1.25, -0.25, 0.875] }
1190
+ }
1191
+ },
1192
+ "outputs": { "y": { "dtype": "float16", "shape": [257, 1, 3], "tolerance": 0.002, "relTolerance": 0.001 } }
1193
+ },
1194
+ {
1195
+ "name": "packed_boundary_float16_rows513_r3",
1196
+ "provenance": {
1197
+ "notes": "513 independent 3-element groups (axis 2) sit one row above twice a 256-row count; verifies the extra float16 row at this larger scale matches the reference."
1198
+ },
1199
+ "attrs": { "axes": [2] },
1200
+ "inputs": {
1201
+ "x": {
1202
+ "dtype": "float16",
1203
+ "shape": [513, 1, 3],
1204
+ "data": { "kind": "cycle", "values": [0.125, -0.75, 0.5, 1.25, -0.25, 0.875] }
1205
+ }
1206
+ },
1207
+ "outputs": { "y": { "dtype": "float16", "shape": [513, 1, 3], "tolerance": 0.002, "relTolerance": 0.001 } }
1208
+ },
1209
+ {
1210
+ "name": "packed_boundary_float16_rows255_r4",
1211
+ "provenance": {
1212
+ "notes": "255 independent 4-element groups (axis 2) sit one row below a 256-row count; verifies the float16 output, including the last row, matches the reference."
1213
+ },
1214
+ "attrs": { "axes": [2] },
1215
+ "inputs": {
1216
+ "x": {
1217
+ "dtype": "float16",
1218
+ "shape": [255, 1, 4],
1219
+ "data": { "kind": "cycle", "values": [0.125, -0.75, 0.5, 1.25, -0.25, 0.875] }
1220
+ }
1221
+ },
1222
+ "outputs": { "y": { "dtype": "float16", "shape": [255, 1, 4], "tolerance": 0.002, "relTolerance": 0.001 } }
1223
+ },
1224
+ {
1225
+ "name": "packed_boundary_float16_rows256_r4",
1226
+ "provenance": {
1227
+ "notes": "256 independent 4-element groups (axis 2) exactly reach a 256-row count; verifies every float16 row, with none left over, matches the reference."
1228
+ },
1229
+ "attrs": { "axes": [2] },
1230
+ "inputs": {
1231
+ "x": {
1232
+ "dtype": "float16",
1233
+ "shape": [256, 1, 4],
1234
+ "data": { "kind": "cycle", "values": [0.125, -0.75, 0.5, 1.25, -0.25, 0.875] }
1235
+ }
1236
+ },
1237
+ "outputs": { "y": { "dtype": "float16", "shape": [256, 1, 4], "tolerance": 0.002, "relTolerance": 0.001 } }
1238
+ },
1239
+ {
1240
+ "name": "packed_boundary_float16_rows257_r4",
1241
+ "provenance": {
1242
+ "notes": "257 independent 4-element groups (axis 2) sit one row above a 256-row count; verifies the extra float16 row, beyond the 256, matches the reference."
1243
+ },
1244
+ "attrs": { "axes": [2] },
1245
+ "inputs": {
1246
+ "x": {
1247
+ "dtype": "float16",
1248
+ "shape": [257, 1, 4],
1249
+ "data": { "kind": "cycle", "values": [0.125, -0.75, 0.5, 1.25, -0.25, 0.875] }
1250
+ }
1251
+ },
1252
+ "outputs": { "y": { "dtype": "float16", "shape": [257, 1, 4], "tolerance": 0.002, "relTolerance": 0.001 } }
1253
+ },
1254
+ {
1255
+ "name": "packed_boundary_float16_rows513_r4",
1256
+ "provenance": {
1257
+ "notes": "513 independent 4-element groups (axis 2) sit one row above twice a 256-row count; verifies the extra float16 row at this larger scale matches the reference."
1258
+ },
1259
+ "attrs": { "axes": [2] },
1260
+ "inputs": {
1261
+ "x": {
1262
+ "dtype": "float16",
1263
+ "shape": [513, 1, 4],
1264
+ "data": { "kind": "cycle", "values": [0.125, -0.75, 0.5, 1.25, -0.25, 0.875] }
1265
+ }
1266
+ },
1267
+ "outputs": { "y": { "dtype": "float16", "shape": [513, 1, 4], "tolerance": 0.002, "relTolerance": 0.001 } }
1268
+ },
1269
+ {
1270
+ "name": "shifted_mean_float16_unit_rows2_r2",
1271
+ "provenance": {
1272
+ "notes": "Adjacent representable inputs retain their centered differences without rounding an absolute mean."
1273
+ },
1274
+ "attrs": { "axes": [2] },
1275
+ "inputs": {
1276
+ "x": { "dtype": "float16", "shape": [2, 1, 2], "data": { "kind": "cycle", "values": [1.0, 1.0009765625] } }
1277
+ },
1278
+ "outputs": { "y": { "dtype": "float16", "shape": [2, 1, 2], "tolerance": 0.002, "relTolerance": 0.001 } }
1279
+ },
1280
+ {
1281
+ "name": "shifted_mean_float16_unit_rows2_r3",
1282
+ "provenance": {
1283
+ "notes": "Adjacent representable inputs retain their centered differences without rounding an absolute mean."
1284
+ },
1285
+ "attrs": { "axes": [2] },
1286
+ "inputs": {
1287
+ "x": { "dtype": "float16", "shape": [2, 1, 3], "data": { "kind": "cycle", "values": [1.0, 1.0009765625, 1.0] } }
1288
+ },
1289
+ "outputs": { "y": { "dtype": "float16", "shape": [2, 1, 3], "tolerance": 0.002, "relTolerance": 0.001 } }
1290
+ },
1291
+ {
1292
+ "name": "shifted_mean_float16_unit_rows2_r8",
1293
+ "provenance": {
1294
+ "notes": "Adjacent representable inputs retain their centered differences without rounding an absolute mean."
1295
+ },
1296
+ "attrs": { "axes": [2] },
1297
+ "inputs": {
1298
+ "x": {
1299
+ "dtype": "float16",
1300
+ "shape": [2, 1, 8],
1301
+ "data": { "kind": "cycle", "values": [1.0, 1.0009765625, 1.0, 1.0, 1.0009765625, 1.0, 1.0, 1.0009765625] }
1302
+ }
1303
+ },
1304
+ "outputs": { "y": { "dtype": "float16", "shape": [2, 1, 8], "tolerance": 0.002, "relTolerance": 0.001 } }
1305
+ },
1306
+ {
1307
+ "name": "shifted_mean_float16_unit_rows256_r2",
1308
+ "provenance": {
1309
+ "notes": "Adjacent representable inputs retain their centered differences without rounding an absolute mean."
1310
+ },
1311
+ "attrs": { "axes": [2] },
1312
+ "inputs": {
1313
+ "x": { "dtype": "float16", "shape": [256, 1, 2], "data": { "kind": "cycle", "values": [1.0, 1.0009765625] } }
1314
+ },
1315
+ "outputs": { "y": { "dtype": "float16", "shape": [256, 1, 2], "tolerance": 0.002, "relTolerance": 0.001 } }
1316
+ },
1317
+ {
1318
+ "name": "shifted_mean_float16_unit_rows257_r3",
1319
+ "provenance": {
1320
+ "notes": "Adjacent representable inputs retain their centered differences without rounding an absolute mean."
1321
+ },
1322
+ "attrs": { "axes": [2] },
1323
+ "inputs": {
1324
+ "x": {
1325
+ "dtype": "float16",
1326
+ "shape": [257, 1, 3],
1327
+ "data": { "kind": "cycle", "values": [1.0, 1.0009765625, 1.0] }
1328
+ }
1329
+ },
1330
+ "outputs": { "y": { "dtype": "float16", "shape": [257, 1, 3], "tolerance": 0.002, "relTolerance": 0.001 } }
1331
+ },
1332
+ {
1333
+ "name": "shifted_mean_float16_unit_rows256_r4",
1334
+ "provenance": {
1335
+ "notes": "Adjacent representable inputs retain their centered differences without rounding an absolute mean."
1336
+ },
1337
+ "attrs": { "axes": [2] },
1338
+ "inputs": {
1339
+ "x": {
1340
+ "dtype": "float16",
1341
+ "shape": [256, 1, 4],
1342
+ "data": { "kind": "cycle", "values": [1.0, 1.0009765625, 1.0, 1.0] }
1343
+ }
1344
+ },
1345
+ "outputs": { "y": { "dtype": "float16", "shape": [256, 1, 4], "tolerance": 0.002, "relTolerance": 0.001 } }
1346
+ },
1347
+ {
1348
+ "name": "shifted_mean_float16_unit_rows256_r8",
1349
+ "provenance": {
1350
+ "notes": "Adjacent representable inputs retain their centered differences without rounding an absolute mean."
1351
+ },
1352
+ "attrs": { "axes": [2] },
1353
+ "inputs": {
1354
+ "x": {
1355
+ "dtype": "float16",
1356
+ "shape": [256, 1, 8],
1357
+ "data": { "kind": "cycle", "values": [1.0, 1.0009765625, 1.0, 1.0, 1.0009765625, 1.0, 1.0, 1.0009765625] }
1358
+ }
1359
+ },
1360
+ "outputs": { "y": { "dtype": "float16", "shape": [256, 1, 8], "tolerance": 0.002, "relTolerance": 0.001 } }
1361
+ },
1362
+ {
1363
+ "name": "shifted_mean_float16_large_rows2_r2",
1364
+ "provenance": {
1365
+ "notes": "Adjacent representable inputs retain their centered differences without rounding an absolute mean."
1366
+ },
1367
+ "attrs": { "axes": [2] },
1368
+ "inputs": {
1369
+ "x": { "dtype": "float16", "shape": [2, 1, 2], "data": { "kind": "cycle", "values": [1024.0, 1025.0] } }
1370
+ },
1371
+ "outputs": { "y": { "dtype": "float16", "shape": [2, 1, 2], "tolerance": 0.002, "relTolerance": 0.001 } }
1372
+ },
1373
+ {
1374
+ "name": "shifted_mean_float16_large_rows2_r3",
1375
+ "provenance": {
1376
+ "notes": "Adjacent representable inputs retain their centered differences without rounding an absolute mean."
1377
+ },
1378
+ "attrs": { "axes": [2] },
1379
+ "inputs": {
1380
+ "x": { "dtype": "float16", "shape": [2, 1, 3], "data": { "kind": "cycle", "values": [1024.0, 1025.0, 1024.0] } }
1381
+ },
1382
+ "outputs": { "y": { "dtype": "float16", "shape": [2, 1, 3], "tolerance": 0.002, "relTolerance": 0.001 } }
1383
+ },
1384
+ {
1385
+ "name": "shifted_mean_float16_large_rows2_r8",
1386
+ "provenance": {
1387
+ "notes": "Adjacent representable inputs retain their centered differences without rounding an absolute mean."
1388
+ },
1389
+ "attrs": { "axes": [2] },
1390
+ "inputs": {
1391
+ "x": {
1392
+ "dtype": "float16",
1393
+ "shape": [2, 1, 8],
1394
+ "data": { "kind": "cycle", "values": [1024.0, 1025.0, 1024.0, 1024.0, 1025.0, 1024.0, 1024.0, 1025.0] }
1395
+ }
1396
+ },
1397
+ "outputs": { "y": { "dtype": "float16", "shape": [2, 1, 8], "tolerance": 0.002, "relTolerance": 0.001 } }
1398
+ },
1399
+ {
1400
+ "name": "shifted_mean_float16_large_rows256_r2",
1401
+ "provenance": {
1402
+ "notes": "Adjacent representable inputs retain their centered differences without rounding an absolute mean."
1403
+ },
1404
+ "attrs": { "axes": [2] },
1405
+ "inputs": {
1406
+ "x": { "dtype": "float16", "shape": [256, 1, 2], "data": { "kind": "cycle", "values": [1024.0, 1025.0] } }
1407
+ },
1408
+ "outputs": { "y": { "dtype": "float16", "shape": [256, 1, 2], "tolerance": 0.002, "relTolerance": 0.001 } }
1409
+ },
1410
+ {
1411
+ "name": "shifted_mean_float16_large_rows257_r3",
1412
+ "provenance": {
1413
+ "notes": "Adjacent representable inputs retain their centered differences without rounding an absolute mean."
1414
+ },
1415
+ "attrs": { "axes": [2] },
1416
+ "inputs": {
1417
+ "x": {
1418
+ "dtype": "float16",
1419
+ "shape": [257, 1, 3],
1420
+ "data": { "kind": "cycle", "values": [1024.0, 1025.0, 1024.0] }
1421
+ }
1422
+ },
1423
+ "outputs": { "y": { "dtype": "float16", "shape": [257, 1, 3], "tolerance": 0.002, "relTolerance": 0.001 } }
1424
+ },
1425
+ {
1426
+ "name": "shifted_mean_float16_large_rows256_r4",
1427
+ "provenance": {
1428
+ "notes": "Adjacent representable inputs retain their centered differences without rounding an absolute mean."
1429
+ },
1430
+ "attrs": { "axes": [2] },
1431
+ "inputs": {
1432
+ "x": {
1433
+ "dtype": "float16",
1434
+ "shape": [256, 1, 4],
1435
+ "data": { "kind": "cycle", "values": [1024.0, 1025.0, 1024.0, 1024.0] }
1436
+ }
1437
+ },
1438
+ "outputs": { "y": { "dtype": "float16", "shape": [256, 1, 4], "tolerance": 0.002, "relTolerance": 0.001 } }
1439
+ },
1440
+ {
1441
+ "name": "shifted_mean_float16_large_rows256_r8",
1442
+ "provenance": {
1443
+ "notes": "Adjacent representable inputs retain their centered differences without rounding an absolute mean."
1444
+ },
1445
+ "attrs": { "axes": [2] },
1446
+ "inputs": {
1447
+ "x": {
1448
+ "dtype": "float16",
1449
+ "shape": [256, 1, 8],
1450
+ "data": { "kind": "cycle", "values": [1024.0, 1025.0, 1024.0, 1024.0, 1025.0, 1024.0, 1024.0, 1025.0] }
1451
+ }
1452
+ },
1453
+ "outputs": { "y": { "dtype": "float16", "shape": [256, 1, 8], "tolerance": 0.002, "relTolerance": 0.001 } }
1454
+ },
1455
+ {
1456
+ "name": "shifted_mean_flat_float16",
1457
+ "provenance": {
1458
+ "notes": "The split combine stores a shifted mean and the apply pass preserves both subtractions."
1459
+ },
1460
+ "attrs": { "axes": [0, 1, 2] },
1461
+ "inputs": {
1462
+ "x": {
1463
+ "dtype": "float16",
1464
+ "shape": [1, 1, 65536],
1465
+ "data": { "kind": "cycle", "values": [1.0, 1.0009765625, 1.0] }
1466
+ }
1467
+ },
1468
+ "outputs": { "y": { "dtype": "float16", "shape": [1, 1, 65536], "tolerance": 0.002, "relTolerance": 0.001 } }
1469
+ },
1470
+ {
1471
+ "name": "packed_layout_float16_contiguous_axes",
1472
+ "provenance": {
1473
+ "notes": "Checks reduced-span contiguity and rank-general indexing, including a strided fallback."
1474
+ },
1475
+ "attrs": { "axes": [1, 2] },
1476
+ "inputs": {
1477
+ "x": {
1478
+ "dtype": "float16",
1479
+ "shape": [257, 2, 2],
1480
+ "data": { "kind": "cycle", "values": [0.125, -0.75, 0.5, 1.25, -0.25, 0.875] }
1481
+ }
1482
+ },
1483
+ "outputs": { "y": { "dtype": "float16", "shape": [257, 2, 2], "tolerance": 0.002, "relTolerance": 0.001 } }
1484
+ },
1485
+ {
1486
+ "name": "packed_layout_float16_singleton_axes",
1487
+ "provenance": {
1488
+ "notes": "Checks reduced-span contiguity and rank-general indexing, including a strided fallback."
1489
+ },
1490
+ "attrs": { "axes": [0, 2, 3] },
1491
+ "inputs": {
1492
+ "x": {
1493
+ "dtype": "float16",
1494
+ "shape": [1, 257, 3, 1],
1495
+ "data": { "kind": "cycle", "values": [0.125, -0.75, 0.5, 1.25, -0.25, 0.875] }
1496
+ }
1497
+ },
1498
+ "outputs": { "y": { "dtype": "float16", "shape": [1, 257, 3, 1], "tolerance": 0.002, "relTolerance": 0.001 } }
1499
+ },
1500
+ {
1501
+ "name": "packed_layout_float16_strided_axis",
1502
+ "provenance": {
1503
+ "notes": "Checks reduced-span contiguity and rank-general indexing, including a strided fallback."
1504
+ },
1505
+ "attrs": { "axes": [1] },
1506
+ "inputs": {
1507
+ "x": {
1508
+ "dtype": "float16",
1509
+ "shape": [257, 2, 4],
1510
+ "data": { "kind": "cycle", "values": [0.125, -0.75, 0.5, 1.25, -0.25, 0.875] }
1511
+ }
1512
+ },
1513
+ "outputs": { "y": { "dtype": "float16", "shape": [257, 2, 4], "tolerance": 0.002, "relTolerance": 0.001 } }
1514
+ },
1515
+ {
1516
+ "name": "packed_layout_float16_rank8",
1517
+ "provenance": {
1518
+ "notes": "Checks reduced-span contiguity and rank-general indexing, including a strided fallback."
1519
+ },
1520
+ "attrs": { "axes": [-1] },
1521
+ "inputs": {
1522
+ "x": {
1523
+ "dtype": "float16",
1524
+ "shape": [257, 1, 1, 1, 1, 1, 1, 3],
1525
+ "data": { "kind": "cycle", "values": [0.125, -0.75, 0.5, 1.25, -0.25, 0.875] }
1526
+ }
1527
+ },
1528
+ "outputs": {
1529
+ "y": { "dtype": "float16", "shape": [257, 1, 1, 1, 1, 1, 1, 3], "tolerance": 0.002, "relTolerance": 0.001 }
1530
+ }
1531
+ },
1532
+ {
1533
+ "name": "packed_zero_variance_float16",
1534
+ "provenance": { "notes": "Zero variance preserves the normalization contract, including the final partial word." },
1535
+ "attrs": { "axes": [2] },
1536
+ "inputs": { "x": { "dtype": "float16", "shape": [257, 1, 3], "data": { "kind": "constant", "value": 7.0 } } },
1537
+ "outputs": {
1538
+ "y": { "dtype": "float16", "shape": [257, 1, 3], "tolerance": 0.002, "relTolerance": 0.001, "allowNaN": true }
1539
+ }
1540
+ },
1541
+ {
1542
+ "name": "packed_limited_workgroup_float16",
1543
+ "provenance": {
1544
+ "notes": "An oversized requested workgroup must still produce correct normalization within the device workgroup limit."
1545
+ },
1546
+ "attrs": { "axes": [2] },
1547
+ "inputs": {
1548
+ "x": { "dtype": "float16", "shape": [257, 1, 3], "data": { "kind": "cycle", "values": [0.125, -0.75, 0.5] } }
1549
+ },
1550
+ "outputs": { "y": { "dtype": "float16", "shape": [257, 1, 3], "tolerance": 0.002, "relTolerance": 0.001 } },
1551
+ "tunables": { "PACKED_WORKGROUP_SIZE": 2048 }
1552
+ },
1553
+ {
1554
+ "name": "shifted_mean_original_close_pair",
1555
+ "provenance": {
1556
+ "notes": "Two nearly identical values within a row isolate centered-output precision at very small variance."
1557
+ },
1558
+ "attrs": { "axes": [2] },
1559
+ "inputs": {
1560
+ "x": {
1561
+ "dtype": "float32",
1562
+ "shape": [2, 1, 2],
1563
+ "data": { "kind": "cycle", "values": [-0.35695281624794006, -0.35694074630737305] }
1564
+ }
1565
+ },
1566
+ "outputs": { "y": { "dtype": "float32", "shape": [2, 1, 2], "tolerance": 0.00001, "relTolerance": 0.00001 } }
1567
+ },
1568
+ {
1569
+ "name": "exponent_f32_rows2_r2_e-100",
1570
+ "provenance": {
1571
+ "notes": "Finite normal inputs cover squared-deviation underflow/overflow and neighboring safe exponent controls."
1572
+ },
1573
+ "attrs": { "axes": [2] },
1574
+ "inputs": {
1575
+ "x": {
1576
+ "dtype": "float32",
1577
+ "shape": [2, 1, 2],
1578
+ "data": { "kind": "cycle", "values": [-7.888609052210118e-31, 0.0] }
1579
+ }
1580
+ },
1581
+ "outputs": { "y": { "dtype": "float32", "shape": [2, 1, 2], "tolerance": 0.00001, "relTolerance": 0.00001 } }
1582
+ },
1583
+ {
1584
+ "name": "exponent_f32_rows2_r2_e-60",
1585
+ "provenance": {
1586
+ "notes": "Finite normal inputs cover squared-deviation underflow/overflow and neighboring safe exponent controls."
1587
+ },
1588
+ "attrs": { "axes": [2] },
1589
+ "inputs": {
1590
+ "x": {
1591
+ "dtype": "float32",
1592
+ "shape": [2, 1, 2],
1593
+ "data": { "kind": "cycle", "values": [-8.673617379884035e-19, 0.0] }
1594
+ }
1595
+ },
1596
+ "outputs": { "y": { "dtype": "float32", "shape": [2, 1, 2], "tolerance": 0.00001, "relTolerance": 0.00001 } }
1597
+ },
1598
+ {
1599
+ "name": "exponent_f32_rows2_r2_e60",
1600
+ "provenance": {
1601
+ "notes": "Finite normal inputs cover squared-deviation underflow/overflow and neighboring safe exponent controls."
1602
+ },
1603
+ "attrs": { "axes": [2] },
1604
+ "inputs": {
1605
+ "x": {
1606
+ "dtype": "float32",
1607
+ "shape": [2, 1, 2],
1608
+ "data": { "kind": "cycle", "values": [-1152921504606847000.0, 0.0] }
1609
+ }
1610
+ },
1611
+ "outputs": { "y": { "dtype": "float32", "shape": [2, 1, 2], "tolerance": 0.00001, "relTolerance": 0.00001 } }
1612
+ },
1613
+ {
1614
+ "name": "exponent_f32_rows2_r2_e100",
1615
+ "provenance": {
1616
+ "notes": "Finite normal inputs cover squared-deviation underflow/overflow and neighboring safe exponent controls."
1617
+ },
1618
+ "attrs": { "axes": [2] },
1619
+ "inputs": {
1620
+ "x": {
1621
+ "dtype": "float32",
1622
+ "shape": [2, 1, 2],
1623
+ "data": { "kind": "cycle", "values": [-1.2676506002282294e+30, 0.0] }
1624
+ }
1625
+ },
1626
+ "outputs": { "y": { "dtype": "float32", "shape": [2, 1, 2], "tolerance": 0.00001, "relTolerance": 0.00001 } }
1627
+ },
1628
+ {
1629
+ "name": "adjacent_minimum_normal_rows2_r2",
1630
+ "provenance": {
1631
+ "notes": "Adjacent finite f32 values at an exponent endpoint retain their normalized differences."
1632
+ },
1633
+ "attrs": { "axes": [2] },
1634
+ "inputs": {
1635
+ "x": {
1636
+ "dtype": "float32",
1637
+ "shape": [2, 1, 2],
1638
+ "data": { "kind": "cycle", "values": [1.1754943508222875e-38, 1.175494490952134e-38] }
1639
+ }
1640
+ },
1641
+ "outputs": { "y": { "dtype": "float32", "shape": [2, 1, 2], "tolerance": 0.00001, "relTolerance": 0.00001 } }
1642
+ },
1643
+ {
1644
+ "name": "adjacent_maximum_finite_rows2_r2",
1645
+ "provenance": {
1646
+ "notes": "Adjacent finite f32 values at an exponent endpoint retain their normalized differences."
1647
+ },
1648
+ "attrs": { "axes": [2] },
1649
+ "inputs": {
1650
+ "x": {
1651
+ "dtype": "float32",
1652
+ "shape": [2, 1, 2],
1653
+ "data": { "kind": "cycle", "values": [3.4028234663852886e+38, 3.4028232635611926e+38] }
1654
+ }
1655
+ },
1656
+ "outputs": { "y": { "dtype": "float32", "shape": [2, 1, 2], "tolerance": 0.00001, "relTolerance": 0.00001 } }
1657
+ },
1658
+ {
1659
+ "name": "exponent_f32_rows257_r2_e-100",
1660
+ "provenance": {
1661
+ "notes": "Finite normal inputs cover squared-deviation underflow/overflow and neighboring safe exponent controls."
1662
+ },
1663
+ "attrs": { "axes": [2] },
1664
+ "inputs": {
1665
+ "x": {
1666
+ "dtype": "float32",
1667
+ "shape": [257, 1, 2],
1668
+ "data": { "kind": "cycle", "values": [-7.888609052210118e-31, 0.0] }
1669
+ }
1670
+ },
1671
+ "outputs": { "y": { "dtype": "float32", "shape": [257, 1, 2], "tolerance": 0.00001, "relTolerance": 0.00001 } }
1672
+ },
1673
+ {
1674
+ "name": "exponent_f32_rows257_r2_e-60",
1675
+ "provenance": {
1676
+ "notes": "Finite normal inputs cover squared-deviation underflow/overflow and neighboring safe exponent controls."
1677
+ },
1678
+ "attrs": { "axes": [2] },
1679
+ "inputs": {
1680
+ "x": {
1681
+ "dtype": "float32",
1682
+ "shape": [257, 1, 2],
1683
+ "data": { "kind": "cycle", "values": [-8.673617379884035e-19, 0.0] }
1684
+ }
1685
+ },
1686
+ "outputs": { "y": { "dtype": "float32", "shape": [257, 1, 2], "tolerance": 0.00001, "relTolerance": 0.00001 } }
1687
+ },
1688
+ {
1689
+ "name": "exponent_f32_rows257_r2_e60",
1690
+ "provenance": {
1691
+ "notes": "Finite normal inputs cover squared-deviation underflow/overflow and neighboring safe exponent controls."
1692
+ },
1693
+ "attrs": { "axes": [2] },
1694
+ "inputs": {
1695
+ "x": {
1696
+ "dtype": "float32",
1697
+ "shape": [257, 1, 2],
1698
+ "data": { "kind": "cycle", "values": [-1152921504606847000.0, 0.0] }
1699
+ }
1700
+ },
1701
+ "outputs": { "y": { "dtype": "float32", "shape": [257, 1, 2], "tolerance": 0.00001, "relTolerance": 0.00001 } }
1702
+ },
1703
+ {
1704
+ "name": "exponent_f32_rows257_r2_e100",
1705
+ "provenance": {
1706
+ "notes": "Finite normal inputs cover squared-deviation underflow/overflow and neighboring safe exponent controls."
1707
+ },
1708
+ "attrs": { "axes": [2] },
1709
+ "inputs": {
1710
+ "x": {
1711
+ "dtype": "float32",
1712
+ "shape": [257, 1, 2],
1713
+ "data": { "kind": "cycle", "values": [-1.2676506002282294e+30, 0.0] }
1714
+ }
1715
+ },
1716
+ "outputs": { "y": { "dtype": "float32", "shape": [257, 1, 2], "tolerance": 0.00001, "relTolerance": 0.00001 } }
1717
+ },
1718
+ {
1719
+ "name": "adjacent_minimum_normal_rows257_r2",
1720
+ "provenance": {
1721
+ "notes": "Adjacent finite f32 values at an exponent endpoint retain their normalized differences."
1722
+ },
1723
+ "attrs": { "axes": [2] },
1724
+ "inputs": {
1725
+ "x": {
1726
+ "dtype": "float32",
1727
+ "shape": [257, 1, 2],
1728
+ "data": { "kind": "cycle", "values": [1.1754943508222875e-38, 1.175494490952134e-38] }
1729
+ }
1730
+ },
1731
+ "outputs": { "y": { "dtype": "float32", "shape": [257, 1, 2], "tolerance": 0.00001, "relTolerance": 0.00001 } }
1732
+ },
1733
+ {
1734
+ "name": "adjacent_maximum_finite_rows257_r2",
1735
+ "provenance": {
1736
+ "notes": "Adjacent finite f32 values at an exponent endpoint retain their normalized differences."
1737
+ },
1738
+ "attrs": { "axes": [2] },
1739
+ "inputs": {
1740
+ "x": {
1741
+ "dtype": "float32",
1742
+ "shape": [257, 1, 2],
1743
+ "data": { "kind": "cycle", "values": [3.4028234663852886e+38, 3.4028232635611926e+38] }
1744
+ }
1745
+ },
1746
+ "outputs": { "y": { "dtype": "float32", "shape": [257, 1, 2], "tolerance": 0.00001, "relTolerance": 0.00001 } }
1747
+ },
1748
+ {
1749
+ "name": "exponent_strided_f32_r2_e-100",
1750
+ "provenance": { "notes": "Strided groups use the same cached exponent-safe moments as contiguous groups." },
1751
+ "attrs": { "axes": [1] },
1752
+ "inputs": {
1753
+ "x": {
1754
+ "dtype": "float32",
1755
+ "shape": [257, 2, 4],
1756
+ "data": {
1757
+ "kind": "cycle",
1758
+ "values": [-7.888609052210118e-31, -7.888609052210118e-31, -7.888609052210118e-31, -7.888609052210118e-31, 0.0, 0.0, 0.0, 0.0]
1759
+ }
1760
+ }
1761
+ },
1762
+ "outputs": { "y": { "dtype": "float32", "shape": [257, 2, 4], "tolerance": 0.00001, "relTolerance": 0.00001 } }
1763
+ },
1764
+ {
1765
+ "name": "exponent_strided_f32_r2_e100",
1766
+ "provenance": { "notes": "Strided groups use the same cached exponent-safe moments as contiguous groups." },
1767
+ "attrs": { "axes": [1] },
1768
+ "inputs": {
1769
+ "x": {
1770
+ "dtype": "float32",
1771
+ "shape": [257, 2, 4],
1772
+ "data": {
1773
+ "kind": "cycle",
1774
+ "values": [-1.2676506002282294e+30, -1.2676506002282294e+30, -1.2676506002282294e+30, -1.2676506002282294e+30, 0.0, 0.0, 0.0, 0.0]
1775
+ }
1776
+ }
1777
+ },
1778
+ "outputs": { "y": { "dtype": "float32", "shape": [257, 2, 4], "tolerance": 0.00001, "relTolerance": 0.00001 } }
1779
+ },
1780
+ {
1781
+ "name": "exponent_f32_rows2_r3_e-100",
1782
+ "provenance": {
1783
+ "notes": "Finite normal inputs cover squared-deviation underflow/overflow and neighboring safe exponent controls."
1784
+ },
1785
+ "attrs": { "axes": [2] },
1786
+ "inputs": {
1787
+ "x": {
1788
+ "dtype": "float32",
1789
+ "shape": [2, 1, 3],
1790
+ "data": { "kind": "cycle", "values": [-7.888609052210118e-31, 0.0, 7.888609052210118e-31] }
1791
+ }
1792
+ },
1793
+ "outputs": { "y": { "dtype": "float32", "shape": [2, 1, 3], "tolerance": 0.00001, "relTolerance": 0.00001 } }
1794
+ },
1795
+ {
1796
+ "name": "exponent_f32_rows2_r3_e-60",
1797
+ "provenance": {
1798
+ "notes": "Finite normal inputs cover squared-deviation underflow/overflow and neighboring safe exponent controls."
1799
+ },
1800
+ "attrs": { "axes": [2] },
1801
+ "inputs": {
1802
+ "x": {
1803
+ "dtype": "float32",
1804
+ "shape": [2, 1, 3],
1805
+ "data": { "kind": "cycle", "values": [-8.673617379884035e-19, 0.0, 8.673617379884035e-19] }
1806
+ }
1807
+ },
1808
+ "outputs": { "y": { "dtype": "float32", "shape": [2, 1, 3], "tolerance": 0.00001, "relTolerance": 0.00001 } }
1809
+ },
1810
+ {
1811
+ "name": "exponent_f32_rows2_r3_e60",
1812
+ "provenance": {
1813
+ "notes": "Finite normal inputs cover squared-deviation underflow/overflow and neighboring safe exponent controls."
1814
+ },
1815
+ "attrs": { "axes": [2] },
1816
+ "inputs": {
1817
+ "x": {
1818
+ "dtype": "float32",
1819
+ "shape": [2, 1, 3],
1820
+ "data": { "kind": "cycle", "values": [-1152921504606847000.0, 0.0, 1152921504606847000.0] }
1821
+ }
1822
+ },
1823
+ "outputs": { "y": { "dtype": "float32", "shape": [2, 1, 3], "tolerance": 0.00001, "relTolerance": 0.00001 } }
1824
+ },
1825
+ {
1826
+ "name": "exponent_f32_rows2_r3_e100",
1827
+ "provenance": {
1828
+ "notes": "Finite normal inputs cover squared-deviation underflow/overflow and neighboring safe exponent controls."
1829
+ },
1830
+ "attrs": { "axes": [2] },
1831
+ "inputs": {
1832
+ "x": {
1833
+ "dtype": "float32",
1834
+ "shape": [2, 1, 3],
1835
+ "data": { "kind": "cycle", "values": [-1.2676506002282294e+30, 0.0, 1.2676506002282294e+30] }
1836
+ }
1837
+ },
1838
+ "outputs": { "y": { "dtype": "float32", "shape": [2, 1, 3], "tolerance": 0.00001, "relTolerance": 0.00001 } }
1839
+ },
1840
+ {
1841
+ "name": "adjacent_minimum_normal_rows2_r3",
1842
+ "provenance": {
1843
+ "notes": "Adjacent finite f32 values at an exponent endpoint retain their normalized differences."
1844
+ },
1845
+ "attrs": { "axes": [2] },
1846
+ "inputs": {
1847
+ "x": {
1848
+ "dtype": "float32",
1849
+ "shape": [2, 1, 3],
1850
+ "data": { "kind": "cycle", "values": [1.1754943508222875e-38, 1.175494490952134e-38, 1.1754946310819804e-38] }
1851
+ }
1852
+ },
1853
+ "outputs": { "y": { "dtype": "float32", "shape": [2, 1, 3], "tolerance": 0.00001, "relTolerance": 0.00001 } }
1854
+ },
1855
+ {
1856
+ "name": "adjacent_maximum_finite_rows2_r3",
1857
+ "provenance": {
1858
+ "notes": "Adjacent finite f32 values at an exponent endpoint retain their normalized differences."
1859
+ },
1860
+ "attrs": { "axes": [2] },
1861
+ "inputs": {
1862
+ "x": {
1863
+ "dtype": "float32",
1864
+ "shape": [2, 1, 3],
1865
+ "data": {
1866
+ "kind": "cycle",
1867
+ "values": [3.4028234663852886e+38, 3.4028232635611926e+38, 3.4028230607370965e+38]
1868
+ }
1869
+ }
1870
+ },
1871
+ "outputs": { "y": { "dtype": "float32", "shape": [2, 1, 3], "tolerance": 0.00001, "relTolerance": 0.00001 } }
1872
+ },
1873
+ {
1874
+ "name": "exponent_f32_rows257_r3_e-100",
1875
+ "provenance": {
1876
+ "notes": "Finite normal inputs cover squared-deviation underflow/overflow and neighboring safe exponent controls."
1877
+ },
1878
+ "attrs": { "axes": [2] },
1879
+ "inputs": {
1880
+ "x": {
1881
+ "dtype": "float32",
1882
+ "shape": [257, 1, 3],
1883
+ "data": { "kind": "cycle", "values": [-7.888609052210118e-31, 0.0, 7.888609052210118e-31] }
1884
+ }
1885
+ },
1886
+ "outputs": { "y": { "dtype": "float32", "shape": [257, 1, 3], "tolerance": 0.00001, "relTolerance": 0.00001 } }
1887
+ },
1888
+ {
1889
+ "name": "exponent_f32_rows257_r3_e-60",
1890
+ "provenance": {
1891
+ "notes": "Finite normal inputs cover squared-deviation underflow/overflow and neighboring safe exponent controls."
1892
+ },
1893
+ "attrs": { "axes": [2] },
1894
+ "inputs": {
1895
+ "x": {
1896
+ "dtype": "float32",
1897
+ "shape": [257, 1, 3],
1898
+ "data": { "kind": "cycle", "values": [-8.673617379884035e-19, 0.0, 8.673617379884035e-19] }
1899
+ }
1900
+ },
1901
+ "outputs": { "y": { "dtype": "float32", "shape": [257, 1, 3], "tolerance": 0.00001, "relTolerance": 0.00001 } }
1902
+ },
1903
+ {
1904
+ "name": "exponent_f32_rows257_r3_e60",
1905
+ "provenance": {
1906
+ "notes": "Finite normal inputs cover squared-deviation underflow/overflow and neighboring safe exponent controls."
1907
+ },
1908
+ "attrs": { "axes": [2] },
1909
+ "inputs": {
1910
+ "x": {
1911
+ "dtype": "float32",
1912
+ "shape": [257, 1, 3],
1913
+ "data": { "kind": "cycle", "values": [-1152921504606847000.0, 0.0, 1152921504606847000.0] }
1914
+ }
1915
+ },
1916
+ "outputs": { "y": { "dtype": "float32", "shape": [257, 1, 3], "tolerance": 0.00001, "relTolerance": 0.00001 } }
1917
+ },
1918
+ {
1919
+ "name": "exponent_f32_rows257_r3_e100",
1920
+ "provenance": {
1921
+ "notes": "Finite normal inputs cover squared-deviation underflow/overflow and neighboring safe exponent controls."
1922
+ },
1923
+ "attrs": { "axes": [2] },
1924
+ "inputs": {
1925
+ "x": {
1926
+ "dtype": "float32",
1927
+ "shape": [257, 1, 3],
1928
+ "data": { "kind": "cycle", "values": [-1.2676506002282294e+30, 0.0, 1.2676506002282294e+30] }
1929
+ }
1930
+ },
1931
+ "outputs": { "y": { "dtype": "float32", "shape": [257, 1, 3], "tolerance": 0.00001, "relTolerance": 0.00001 } }
1932
+ },
1933
+ {
1934
+ "name": "adjacent_minimum_normal_rows257_r3",
1935
+ "provenance": {
1936
+ "notes": "Adjacent finite f32 values at an exponent endpoint retain their normalized differences."
1937
+ },
1938
+ "attrs": { "axes": [2] },
1939
+ "inputs": {
1940
+ "x": {
1941
+ "dtype": "float32",
1942
+ "shape": [257, 1, 3],
1943
+ "data": { "kind": "cycle", "values": [1.1754943508222875e-38, 1.175494490952134e-38, 1.1754946310819804e-38] }
1944
+ }
1945
+ },
1946
+ "outputs": { "y": { "dtype": "float32", "shape": [257, 1, 3], "tolerance": 0.00001, "relTolerance": 0.00001 } }
1947
+ },
1948
+ {
1949
+ "name": "adjacent_maximum_finite_rows257_r3",
1950
+ "provenance": {
1951
+ "notes": "Adjacent finite f32 values at an exponent endpoint retain their normalized differences."
1952
+ },
1953
+ "attrs": { "axes": [2] },
1954
+ "inputs": {
1955
+ "x": {
1956
+ "dtype": "float32",
1957
+ "shape": [257, 1, 3],
1958
+ "data": {
1959
+ "kind": "cycle",
1960
+ "values": [3.4028234663852886e+38, 3.4028232635611926e+38, 3.4028230607370965e+38]
1961
+ }
1962
+ }
1963
+ },
1964
+ "outputs": { "y": { "dtype": "float32", "shape": [257, 1, 3], "tolerance": 0.00001, "relTolerance": 0.00001 } }
1965
+ },
1966
+ {
1967
+ "name": "exponent_strided_f32_r3_e-100",
1968
+ "provenance": { "notes": "Strided groups use the same cached exponent-safe moments as contiguous groups." },
1969
+ "attrs": { "axes": [1] },
1970
+ "inputs": {
1971
+ "x": {
1972
+ "dtype": "float32",
1973
+ "shape": [257, 3, 4],
1974
+ "data": {
1975
+ "kind": "cycle",
1976
+ "values": [-7.888609052210118e-31, -7.888609052210118e-31, -7.888609052210118e-31, -7.888609052210118e-31, 0.0, 0.0, 0.0, 0.0, 7.888609052210118e-31, 7.888609052210118e-31, 7.888609052210118e-31, 7.888609052210118e-31]
1977
+ }
1978
+ }
1979
+ },
1980
+ "outputs": { "y": { "dtype": "float32", "shape": [257, 3, 4], "tolerance": 0.00001, "relTolerance": 0.00001 } }
1981
+ },
1982
+ {
1983
+ "name": "exponent_strided_f32_r3_e100",
1984
+ "provenance": { "notes": "Strided groups use the same cached exponent-safe moments as contiguous groups." },
1985
+ "attrs": { "axes": [1] },
1986
+ "inputs": {
1987
+ "x": {
1988
+ "dtype": "float32",
1989
+ "shape": [257, 3, 4],
1990
+ "data": {
1991
+ "kind": "cycle",
1992
+ "values": [-1.2676506002282294e+30, -1.2676506002282294e+30, -1.2676506002282294e+30, -1.2676506002282294e+30, 0.0, 0.0, 0.0, 0.0, 1.2676506002282294e+30, 1.2676506002282294e+30, 1.2676506002282294e+30, 1.2676506002282294e+30]
1993
+ }
1994
+ }
1995
+ },
1996
+ "outputs": { "y": { "dtype": "float32", "shape": [257, 3, 4], "tolerance": 0.00001, "relTolerance": 0.00001 } }
1997
+ },
1998
+ {
1999
+ "name": "exponent_f32_rows2_r4_e-100",
2000
+ "provenance": {
2001
+ "notes": "Finite normal inputs cover squared-deviation underflow/overflow and neighboring safe exponent controls."
2002
+ },
2003
+ "attrs": { "axes": [2] },
2004
+ "inputs": {
2005
+ "x": {
2006
+ "dtype": "float32",
2007
+ "shape": [2, 1, 4],
2008
+ "data": {
2009
+ "kind": "cycle",
2010
+ "values": [-7.888609052210118e-31, 0.0, 7.888609052210118e-31, 1.5777218104420236e-30]
2011
+ }
2012
+ }
2013
+ },
2014
+ "outputs": { "y": { "dtype": "float32", "shape": [2, 1, 4], "tolerance": 0.00001, "relTolerance": 0.00001 } }
2015
+ },
2016
+ {
2017
+ "name": "exponent_f32_rows2_r4_e-60",
2018
+ "provenance": {
2019
+ "notes": "Finite normal inputs cover squared-deviation underflow/overflow and neighboring safe exponent controls."
2020
+ },
2021
+ "attrs": { "axes": [2] },
2022
+ "inputs": {
2023
+ "x": {
2024
+ "dtype": "float32",
2025
+ "shape": [2, 1, 4],
2026
+ "data": {
2027
+ "kind": "cycle",
2028
+ "values": [-8.673617379884035e-19, 0.0, 8.673617379884035e-19, 1.734723475976807e-18]
2029
+ }
2030
+ }
2031
+ },
2032
+ "outputs": { "y": { "dtype": "float32", "shape": [2, 1, 4], "tolerance": 0.00001, "relTolerance": 0.00001 } }
2033
+ },
2034
+ {
2035
+ "name": "exponent_f32_rows2_r4_e60",
2036
+ "provenance": {
2037
+ "notes": "Finite normal inputs cover squared-deviation underflow/overflow and neighboring safe exponent controls."
2038
+ },
2039
+ "attrs": { "axes": [2] },
2040
+ "inputs": {
2041
+ "x": {
2042
+ "dtype": "float32",
2043
+ "shape": [2, 1, 4],
2044
+ "data": {
2045
+ "kind": "cycle",
2046
+ "values": [-1152921504606847000.0, 0.0, 1152921504606847000.0, 2305843009213694000.0]
2047
+ }
2048
+ }
2049
+ },
2050
+ "outputs": { "y": { "dtype": "float32", "shape": [2, 1, 4], "tolerance": 0.00001, "relTolerance": 0.00001 } }
2051
+ },
2052
+ {
2053
+ "name": "exponent_f32_rows2_r4_e100",
2054
+ "provenance": {
2055
+ "notes": "Finite normal inputs cover squared-deviation underflow/overflow and neighboring safe exponent controls."
2056
+ },
2057
+ "attrs": { "axes": [2] },
2058
+ "inputs": {
2059
+ "x": {
2060
+ "dtype": "float32",
2061
+ "shape": [2, 1, 4],
2062
+ "data": {
2063
+ "kind": "cycle",
2064
+ "values": [-1.2676506002282294e+30, 0.0, 1.2676506002282294e+30, 2.535301200456459e+30]
2065
+ }
2066
+ }
2067
+ },
2068
+ "outputs": { "y": { "dtype": "float32", "shape": [2, 1, 4], "tolerance": 0.00001, "relTolerance": 0.00001 } }
2069
+ },
2070
+ {
2071
+ "name": "adjacent_minimum_normal_rows2_r4",
2072
+ "provenance": {
2073
+ "notes": "Adjacent finite f32 values at an exponent endpoint retain their normalized differences."
2074
+ },
2075
+ "attrs": { "axes": [2] },
2076
+ "inputs": {
2077
+ "x": {
2078
+ "dtype": "float32",
2079
+ "shape": [2, 1, 4],
2080
+ "data": {
2081
+ "kind": "cycle",
2082
+ "values": [1.1754943508222875e-38, 1.175494490952134e-38, 1.1754946310819804e-38, 1.1754947712118268e-38]
2083
+ }
2084
+ }
2085
+ },
2086
+ "outputs": { "y": { "dtype": "float32", "shape": [2, 1, 4], "tolerance": 0.00001, "relTolerance": 0.00001 } }
2087
+ },
2088
+ {
2089
+ "name": "adjacent_maximum_finite_rows2_r4",
2090
+ "provenance": {
2091
+ "notes": "Adjacent finite f32 values at an exponent endpoint retain their normalized differences."
2092
+ },
2093
+ "attrs": { "axes": [2] },
2094
+ "inputs": {
2095
+ "x": {
2096
+ "dtype": "float32",
2097
+ "shape": [2, 1, 4],
2098
+ "data": {
2099
+ "kind": "cycle",
2100
+ "values": [3.4028234663852886e+38, 3.4028232635611926e+38, 3.4028230607370965e+38, 3.4028228579130005e+38]
2101
+ }
2102
+ }
2103
+ },
2104
+ "outputs": { "y": { "dtype": "float32", "shape": [2, 1, 4], "tolerance": 0.00001, "relTolerance": 0.00001 } }
2105
+ },
2106
+ {
2107
+ "name": "exponent_f32_rows257_r4_e-100",
2108
+ "provenance": {
2109
+ "notes": "Finite normal inputs cover squared-deviation underflow/overflow and neighboring safe exponent controls."
2110
+ },
2111
+ "attrs": { "axes": [2] },
2112
+ "inputs": {
2113
+ "x": {
2114
+ "dtype": "float32",
2115
+ "shape": [257, 1, 4],
2116
+ "data": {
2117
+ "kind": "cycle",
2118
+ "values": [-7.888609052210118e-31, 0.0, 7.888609052210118e-31, 1.5777218104420236e-30]
2119
+ }
2120
+ }
2121
+ },
2122
+ "outputs": { "y": { "dtype": "float32", "shape": [257, 1, 4], "tolerance": 0.00001, "relTolerance": 0.00001 } }
2123
+ },
2124
+ {
2125
+ "name": "exponent_f32_rows257_r4_e-60",
2126
+ "provenance": {
2127
+ "notes": "Finite normal inputs cover squared-deviation underflow/overflow and neighboring safe exponent controls."
2128
+ },
2129
+ "attrs": { "axes": [2] },
2130
+ "inputs": {
2131
+ "x": {
2132
+ "dtype": "float32",
2133
+ "shape": [257, 1, 4],
2134
+ "data": {
2135
+ "kind": "cycle",
2136
+ "values": [-8.673617379884035e-19, 0.0, 8.673617379884035e-19, 1.734723475976807e-18]
2137
+ }
2138
+ }
2139
+ },
2140
+ "outputs": { "y": { "dtype": "float32", "shape": [257, 1, 4], "tolerance": 0.00001, "relTolerance": 0.00001 } }
2141
+ },
2142
+ {
2143
+ "name": "exponent_f32_rows257_r4_e60",
2144
+ "provenance": {
2145
+ "notes": "Finite normal inputs cover squared-deviation underflow/overflow and neighboring safe exponent controls."
2146
+ },
2147
+ "attrs": { "axes": [2] },
2148
+ "inputs": {
2149
+ "x": {
2150
+ "dtype": "float32",
2151
+ "shape": [257, 1, 4],
2152
+ "data": {
2153
+ "kind": "cycle",
2154
+ "values": [-1152921504606847000.0, 0.0, 1152921504606847000.0, 2305843009213694000.0]
2155
+ }
2156
+ }
2157
+ },
2158
+ "outputs": { "y": { "dtype": "float32", "shape": [257, 1, 4], "tolerance": 0.00001, "relTolerance": 0.00001 } }
2159
+ },
2160
+ {
2161
+ "name": "exponent_f32_rows257_r4_e100",
2162
+ "provenance": {
2163
+ "notes": "Finite normal inputs cover squared-deviation underflow/overflow and neighboring safe exponent controls."
2164
+ },
2165
+ "attrs": { "axes": [2] },
2166
+ "inputs": {
2167
+ "x": {
2168
+ "dtype": "float32",
2169
+ "shape": [257, 1, 4],
2170
+ "data": {
2171
+ "kind": "cycle",
2172
+ "values": [-1.2676506002282294e+30, 0.0, 1.2676506002282294e+30, 2.535301200456459e+30]
2173
+ }
2174
+ }
2175
+ },
2176
+ "outputs": { "y": { "dtype": "float32", "shape": [257, 1, 4], "tolerance": 0.00001, "relTolerance": 0.00001 } }
2177
+ },
2178
+ {
2179
+ "name": "adjacent_minimum_normal_rows257_r4",
2180
+ "provenance": {
2181
+ "notes": "Adjacent finite f32 values at an exponent endpoint retain their normalized differences."
2182
+ },
2183
+ "attrs": { "axes": [2] },
2184
+ "inputs": {
2185
+ "x": {
2186
+ "dtype": "float32",
2187
+ "shape": [257, 1, 4],
2188
+ "data": {
2189
+ "kind": "cycle",
2190
+ "values": [1.1754943508222875e-38, 1.175494490952134e-38, 1.1754946310819804e-38, 1.1754947712118268e-38]
2191
+ }
2192
+ }
2193
+ },
2194
+ "outputs": { "y": { "dtype": "float32", "shape": [257, 1, 4], "tolerance": 0.00001, "relTolerance": 0.00001 } }
2195
+ },
2196
+ {
2197
+ "name": "adjacent_maximum_finite_rows257_r4",
2198
+ "provenance": {
2199
+ "notes": "Adjacent finite f32 values at an exponent endpoint retain their normalized differences."
2200
+ },
2201
+ "attrs": { "axes": [2] },
2202
+ "inputs": {
2203
+ "x": {
2204
+ "dtype": "float32",
2205
+ "shape": [257, 1, 4],
2206
+ "data": {
2207
+ "kind": "cycle",
2208
+ "values": [3.4028234663852886e+38, 3.4028232635611926e+38, 3.4028230607370965e+38, 3.4028228579130005e+38]
2209
+ }
2210
+ }
2211
+ },
2212
+ "outputs": { "y": { "dtype": "float32", "shape": [257, 1, 4], "tolerance": 0.00001, "relTolerance": 0.00001 } }
2213
+ },
2214
+ {
2215
+ "name": "exponent_strided_f32_r4_e-100",
2216
+ "provenance": { "notes": "Strided groups use the same cached exponent-safe moments as contiguous groups." },
2217
+ "attrs": { "axes": [1] },
2218
+ "inputs": {
2219
+ "x": {
2220
+ "dtype": "float32",
2221
+ "shape": [257, 4, 4],
2222
+ "data": {
2223
+ "kind": "cycle",
2224
+ "values": [-7.888609052210118e-31, -7.888609052210118e-31, -7.888609052210118e-31, -7.888609052210118e-31, 0.0, 0.0, 0.0, 0.0, 7.888609052210118e-31, 7.888609052210118e-31, 7.888609052210118e-31, 7.888609052210118e-31, 1.5777218104420236e-30, 1.5777218104420236e-30, 1.5777218104420236e-30, 1.5777218104420236e-30]
2225
+ }
2226
+ }
2227
+ },
2228
+ "outputs": { "y": { "dtype": "float32", "shape": [257, 4, 4], "tolerance": 0.00001, "relTolerance": 0.00001 } }
2229
+ },
2230
+ {
2231
+ "name": "exponent_strided_f32_r4_e100",
2232
+ "provenance": { "notes": "Strided groups use the same cached exponent-safe moments as contiguous groups." },
2233
+ "attrs": { "axes": [1] },
2234
+ "inputs": {
2235
+ "x": {
2236
+ "dtype": "float32",
2237
+ "shape": [257, 4, 4],
2238
+ "data": {
2239
+ "kind": "cycle",
2240
+ "values": [-1.2676506002282294e+30, -1.2676506002282294e+30, -1.2676506002282294e+30, -1.2676506002282294e+30, 0.0, 0.0, 0.0, 0.0, 1.2676506002282294e+30, 1.2676506002282294e+30, 1.2676506002282294e+30, 1.2676506002282294e+30, 2.535301200456459e+30, 2.535301200456459e+30, 2.535301200456459e+30, 2.535301200456459e+30]
2241
+ }
2242
+ }
2243
+ },
2244
+ "outputs": { "y": { "dtype": "float32", "shape": [257, 4, 4], "tolerance": 0.00001, "relTolerance": 0.00001 } }
2245
+ },
2246
+ {
2247
+ "name": "mixed_normal_exponents_r2",
2248
+ "provenance": {
2249
+ "notes": "Widely separated finite exponents normalize without overflowing a centered difference."
2250
+ },
2251
+ "attrs": { "axes": [2] },
2252
+ "inputs": {
2253
+ "x": {
2254
+ "dtype": "float32",
2255
+ "shape": [257, 1, 2],
2256
+ "data": { "kind": "cycle", "values": [1.1754943508222875e-38, 3.4028234663852886e+38] }
2257
+ }
2258
+ },
2259
+ "outputs": { "y": { "dtype": "float32", "shape": [257, 1, 2], "tolerance": 0.00001, "relTolerance": 0.00001 } }
2260
+ },
2261
+ {
2262
+ "name": "mixed_normal_exponents_r3",
2263
+ "provenance": {
2264
+ "notes": "Widely separated finite exponents normalize without overflowing a centered difference."
2265
+ },
2266
+ "attrs": { "axes": [2] },
2267
+ "inputs": {
2268
+ "x": {
2269
+ "dtype": "float32",
2270
+ "shape": [257, 1, 3],
2271
+ "data": {
2272
+ "kind": "cycle",
2273
+ "values": [1.1754943508222875e-38, 3.4028234663852886e+38, -3.4028234663852886e+38]
2274
+ }
2275
+ }
2276
+ },
2277
+ "outputs": { "y": { "dtype": "float32", "shape": [257, 1, 3], "tolerance": 0.00001, "relTolerance": 0.00001 } }
2278
+ },
2279
+ {
2280
+ "name": "mixed_normal_exponents_r4",
2281
+ "provenance": {
2282
+ "notes": "Widely separated finite exponents normalize without overflowing a centered difference."
2283
+ },
2284
+ "attrs": { "axes": [2] },
2285
+ "inputs": {
2286
+ "x": {
2287
+ "dtype": "float32",
2288
+ "shape": [257, 1, 4],
2289
+ "data": {
2290
+ "kind": "cycle",
2291
+ "values": [1.1754943508222875e-38, 3.4028234663852886e+38, -3.4028234663852886e+38, 2.350988701644575e-38]
2292
+ }
2293
+ }
2294
+ },
2295
+ "outputs": { "y": { "dtype": "float32", "shape": [257, 1, 4], "tolerance": 0.00001, "relTolerance": 0.00001 } }
2296
+ },
2297
+ {
2298
+ "name": "exponent_forced_vec4_float32_e-100",
2299
+ "provenance": { "notes": "A four-value vector group exercises cached moments with vector storage bindings." },
2300
+ "attrs": { "axes": [2] },
2301
+ "inputs": {
2302
+ "x": {
2303
+ "dtype": "float32",
2304
+ "shape": [2, 1, 4],
2305
+ "data": {
2306
+ "kind": "cycle",
2307
+ "values": [-7.888609052210118e-31, 0.0, 7.888609052210118e-31, 1.5777218104420236e-30]
2308
+ }
2309
+ }
2310
+ },
2311
+ "outputs": { "y": { "dtype": "float32", "shape": [2, 1, 4], "tolerance": 0.00001, "relTolerance": 0.00001 } },
2312
+ "tunables": { "VEC4_MIN_REDUCTION": 4 }
2313
+ },
2314
+ {
2315
+ "name": "exponent_forced_vec4_float32_e100",
2316
+ "provenance": { "notes": "A four-value vector group exercises cached moments with vector storage bindings." },
2317
+ "attrs": { "axes": [2] },
2318
+ "inputs": {
2319
+ "x": {
2320
+ "dtype": "float32",
2321
+ "shape": [2, 1, 4],
2322
+ "data": {
2323
+ "kind": "cycle",
2324
+ "values": [-1.2676506002282294e+30, 0.0, 1.2676506002282294e+30, 2.535301200456459e+30]
2325
+ }
2326
+ }
2327
+ },
2328
+ "outputs": { "y": { "dtype": "float32", "shape": [2, 1, 4], "tolerance": 0.00001, "relTolerance": 0.00001 } },
2329
+ "tunables": { "VEC4_MIN_REDUCTION": 4 }
2330
+ },
2331
+ {
2332
+ "name": "exponent_forced_vec4_float16_e-14",
2333
+ "provenance": { "notes": "A four-value vector group exercises cached moments with vector storage bindings." },
2334
+ "attrs": { "axes": [2] },
2335
+ "inputs": {
2336
+ "x": {
2337
+ "dtype": "float16",
2338
+ "shape": [2, 1, 4],
2339
+ "data": { "kind": "cycle", "values": [-0.00006103515625, 0.0, 0.00006103515625, 0.0001220703125] }
2340
+ }
2341
+ },
2342
+ "outputs": { "y": { "dtype": "float16", "shape": [2, 1, 4], "tolerance": 0.002, "relTolerance": 0.001 } },
2343
+ "tunables": { "VEC4_MIN_REDUCTION": 4 }
2344
+ },
2345
+ {
2346
+ "name": "exponent_forced_vec4_float16_e14",
2347
+ "provenance": { "notes": "A four-value vector group exercises cached moments with vector storage bindings." },
2348
+ "attrs": { "axes": [2] },
2349
+ "inputs": {
2350
+ "x": {
2351
+ "dtype": "float16",
2352
+ "shape": [2, 1, 4],
2353
+ "data": { "kind": "cycle", "values": [-16384.0, 0.0, 16384.0, 32768.0] }
2354
+ }
2355
+ },
2356
+ "outputs": { "y": { "dtype": "float16", "shape": [2, 1, 4], "tolerance": 0.002, "relTolerance": 0.001 } },
2357
+ "tunables": { "VEC4_MIN_REDUCTION": 4 }
2358
  }
2359
  ]
2360
  }