Xenova HF Staff commited on
Commit
f3f43cb
·
verified ·
1 Parent(s): 19cdc0e

sync 91d990483a17

Browse files
README.md CHANGED
@@ -12,22 +12,22 @@ tags:
12
 
13
  ## Description
14
 
15
- Computes RMS normalization over the suffix dimensions of `X` starting at `axis`: `Y = X / sqrt(mean(X^2) + epsilon) * scale`. The normalization stage supports TensorProto `stash_type` values `1` (float32) and `10` (float16), and is cast back to the dtype of `X` before `scale` is applied. The input type `T` and scale/output type `V` may independently be float16 or float32; ONNX's bfloat16 and double cases are not yet implemented.
16
 
17
  See the [ONNX `RMSNormalization` spec](https://onnx.ai/onnx/operators/onnx__RMSNormalization.html) for the reference semantics.
18
 
19
  ## Inputs
20
 
21
- | Name | Bind key | Logical dtype | Rank | Shape | Description | Presence |
22
  | --- | --- | --- | --- | --- | --- | --- |
23
- | `X` | `x` | `T` | — | — | Input tensor to be normalized; the RMS is taken over the last dimensions starting at `axis`. | required |
24
- | `scale` | `scale` | `V` | — | — | Scale tensor, unidirectionally broadcastable to `X`; its dtype `V` may differ from the input dtype `T`. | required |
25
 
26
  ## Outputs
27
 
28
- | Name | Bind key | Logical dtype | Rank | Shape | Description | Presence |
29
  | --- | --- | --- | --- | --- | --- | --- |
30
- | `Y` | `y` | `V` | same as `X` | same as `X` | Normalized and scaled output tensor; same shape as `X` and same dtype `V` as `scale`. | required |
31
 
32
  ## Attributes
33
 
@@ -48,7 +48,7 @@ Default values (overridable per request):
48
 
49
  ## Files
50
 
51
- - [`metadata.json`](build/webgpu/metadata.json) — kernel metadata (id, digests, provenance)
52
  - [`manifest.json`](build/webgpu/manifest.json) — the op contract (source of truth)
53
  - [`test.json`](build/webgpu/test.json) — correctness cases
54
  - [`bench.json`](build/webgpu/bench.json) — benchmark + tuning cases
@@ -60,10 +60,14 @@ Default values (overridable per request):
60
 
61
  ## Use with `@huggingface/kernels`
62
 
63
- The loader derives every required output's shape and logical dtype from the manifest contract and this call.
64
- It then allocates the result tensors automatically.
 
 
 
65
 
66
  The `version: 1` option selects the published kernel contract; it is independent of any operator opset, contrib `since_version`, or model version.
 
67
 
68
  Replace each `*Data` placeholder with a typed array containing the corresponding input data.
69
 
 
12
 
13
  ## Description
14
 
15
+ Computes RMS normalization over the suffix dimensions of `X` starting at `axis`: `Y = X / sqrt(mean(X^2) + epsilon) * scale`. The normalization stage supports TensorProto `stash_type` values `1` (float32) and `10` (float16), and is cast back to the dtype of `X` before `scale` is applied. The input type `T` and scale/output type `V` may independently be float16 or float32; ONNX bfloat16 and double cases are unsupported.
16
 
17
  See the [ONNX `RMSNormalization` spec](https://onnx.ai/onnx/operators/onnx__RMSNormalization.html) for the reference semantics.
18
 
19
  ## Inputs
20
 
21
+ | Name | Upstream name | Logical dtype | Rank | Shape | Description | Presence |
22
  | --- | --- | --- | --- | --- | --- | --- |
23
+ | `x` | `X` | `T` | — | — | Input tensor to be normalized; the RMS is taken over the last dimensions starting at `axis`. | required |
24
+ | `scale` | | `V` | — | — | Scale tensor, unidirectionally broadcastable to `X`; its dtype `V` may differ from the input dtype `T`. | required |
25
 
26
  ## Outputs
27
 
28
+ | Name | Upstream name | Logical dtype | Rank | Shape | Description | Presence |
29
  | --- | --- | --- | --- | --- | --- | --- |
30
+ | `y` | `Y` | `V` | same as `x` | same as `x` | Normalized and scaled output tensor; same shape as `X` and same dtype `V` as `scale`. | required |
31
 
32
  ## Attributes
33
 
 
48
 
49
  ## Files
50
 
51
+ - [`metadata.json`](build/webgpu/metadata.json) — kernel metadata (id, digests, per-variant templates, provenance)
52
  - [`manifest.json`](build/webgpu/manifest.json) — the op contract (source of truth)
53
  - [`test.json`](build/webgpu/test.json) — correctness cases
54
  - [`bench.json`](build/webgpu/bench.json) — benchmark + tuning cases
 
60
 
61
  ## Use with `@huggingface/kernels`
62
 
63
+ ```sh
64
+ npm install --save-exact @huggingface/kernels@0.0.1-preview.2
65
+ ```
66
+
67
+ Required output shapes and logical data types are inferred from the supplied inputs and attributes; result tensors are allocated automatically.
68
 
69
  The `version: 1` option selects the published kernel contract; it is independent of any operator opset, contrib `since_version`, or model version.
70
+ It follows the `v1` branch as fixes land. To pin exact artifact bytes, pass a 40-character commit `revision` instead of `version`.
71
 
72
  Replace each `*Data` placeholder with a typed array containing the corresponding input data.
73
 
build/webgpu/bench.json CHANGED
@@ -1,5 +1,4 @@
1
  {
2
- "op": "ai.onnx.RMSNormalization",
3
  "cases": [
4
  {
5
  "name": "rmsnorm-f32-256x1024",
@@ -168,6 +167,342 @@
168
  "bench": {
169
  "metrics": [{ "type": "bandwidth", "value": "(args.rows * args.dim * 2 + args.dim) * dtypeBytes(args.dtype)" }]
170
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
171
  }
172
  ]
173
  }
 
1
  {
 
2
  "cases": [
3
  {
4
  "name": "rmsnorm-f32-256x1024",
 
167
  "bench": {
168
  "metrics": [{ "type": "bandwidth", "value": "(args.rows * args.dim * 2 + args.dim) * dtypeBytes(args.dtype)" }]
169
  }
170
+ },
171
+ {
172
+ "name": "split_f32-1x16384",
173
+ "preset": "stress",
174
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
175
+ "tunables": {},
176
+ "inputs": {
177
+ "x": { "shape": [1, 16384], "dtype": "float32", "dist": "normal", "seed": 8123, "scale": 0.5 },
178
+ "scale": { "shape": [], "dtype": "float32", "dist": "uniform", "seed": 8124, "scale": 0.25, "offset": 1 }
179
+ },
180
+ "outputs": { "y": { "shape": [1, 16384], "dtype": "float32" } },
181
+ "bench": { "metrics": [{ "type": "bandwidth", "value": 131076 }] }
182
+ },
183
+ {
184
+ "name": "split_f32-1x16385",
185
+ "preset": "stress",
186
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
187
+ "tunables": {},
188
+ "inputs": {
189
+ "x": { "shape": [1, 16385], "dtype": "float32", "dist": "normal", "seed": 8123, "scale": 0.5 },
190
+ "scale": { "shape": [], "dtype": "float32", "dist": "uniform", "seed": 8124, "scale": 0.25, "offset": 1 }
191
+ },
192
+ "outputs": { "y": { "shape": [1, 16385], "dtype": "float32" } },
193
+ "bench": { "metrics": [{ "type": "bandwidth", "value": 131084 }] }
194
+ },
195
+ {
196
+ "name": "split_f32-1x32769",
197
+ "preset": "stress",
198
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
199
+ "tunables": {},
200
+ "inputs": {
201
+ "x": { "shape": [1, 32769], "dtype": "float32", "dist": "normal", "seed": 8123, "scale": 0.5 },
202
+ "scale": { "shape": [], "dtype": "float32", "dist": "uniform", "seed": 8124, "scale": 0.25, "offset": 1 }
203
+ },
204
+ "outputs": { "y": { "shape": [1, 32769], "dtype": "float32" } },
205
+ "bench": { "metrics": [{ "type": "bandwidth", "value": 262156 }] }
206
+ },
207
+ {
208
+ "name": "split_f32-1x65536",
209
+ "preset": "stress",
210
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
211
+ "tunables": {},
212
+ "inputs": {
213
+ "x": { "shape": [1, 65536], "dtype": "float32", "dist": "normal", "seed": 8123, "scale": 0.5 },
214
+ "scale": { "shape": [], "dtype": "float32", "dist": "uniform", "seed": 8124, "scale": 0.25, "offset": 1 }
215
+ },
216
+ "outputs": { "y": { "shape": [1, 65536], "dtype": "float32" } },
217
+ "bench": { "metrics": [{ "type": "bandwidth", "value": 524292 }] }
218
+ },
219
+ {
220
+ "name": "split_f32-1x131072",
221
+ "preset": "stress",
222
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
223
+ "tunables": {},
224
+ "inputs": {
225
+ "x": { "shape": [1, 131072], "dtype": "float32", "dist": "normal", "seed": 8123, "scale": 0.5 },
226
+ "scale": { "shape": [], "dtype": "float32", "dist": "uniform", "seed": 8124, "scale": 0.25, "offset": 1 }
227
+ },
228
+ "outputs": { "y": { "shape": [1, 131072], "dtype": "float32" } },
229
+ "bench": { "metrics": [{ "type": "bandwidth", "value": 1048580 }] }
230
+ },
231
+ {
232
+ "name": "split_f32-1x262144",
233
+ "preset": "stress",
234
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
235
+ "tunables": {},
236
+ "inputs": {
237
+ "x": { "shape": [1, 262144], "dtype": "float32", "dist": "normal", "seed": 8123, "scale": 0.5 },
238
+ "scale": { "shape": [], "dtype": "float32", "dist": "uniform", "seed": 8124, "scale": 0.25, "offset": 1 }
239
+ },
240
+ "outputs": { "y": { "shape": [1, 262144], "dtype": "float32" } },
241
+ "bench": { "metrics": [{ "type": "bandwidth", "value": 2097156 }] }
242
+ },
243
+ {
244
+ "name": "split_f32-1x524288",
245
+ "preset": "stress",
246
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
247
+ "tunables": {},
248
+ "inputs": {
249
+ "x": { "shape": [1, 524288], "dtype": "float32", "dist": "normal", "seed": 8123, "scale": 0.5 },
250
+ "scale": { "shape": [], "dtype": "float32", "dist": "uniform", "seed": 8124, "scale": 0.25, "offset": 1 }
251
+ },
252
+ "outputs": { "y": { "shape": [1, 524288], "dtype": "float32" } },
253
+ "bench": { "metrics": [{ "type": "bandwidth", "value": 4194308 }] }
254
+ },
255
+ {
256
+ "name": "split_f32-1x1048576",
257
+ "preset": "stress",
258
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
259
+ "tunables": {},
260
+ "inputs": {
261
+ "x": { "shape": [1, 1048576], "dtype": "float32", "dist": "normal", "seed": 8123, "scale": 0.5 },
262
+ "scale": { "shape": [], "dtype": "float32", "dist": "uniform", "seed": 8124, "scale": 0.25, "offset": 1 }
263
+ },
264
+ "outputs": { "y": { "shape": [1, 1048576], "dtype": "float32" } },
265
+ "bench": { "metrics": [{ "type": "bandwidth", "value": 8388612 }] }
266
+ },
267
+ {
268
+ "name": "split_f32-1x2097152",
269
+ "preset": "stress",
270
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
271
+ "tunables": {},
272
+ "inputs": {
273
+ "x": { "shape": [1, 2097152], "dtype": "float32", "dist": "normal", "seed": 8123, "scale": 0.5 },
274
+ "scale": { "shape": [], "dtype": "float32", "dist": "uniform", "seed": 8124, "scale": 0.25, "offset": 1 }
275
+ },
276
+ "outputs": { "y": { "shape": [1, 2097152], "dtype": "float32" } },
277
+ "bench": { "metrics": [{ "type": "bandwidth", "value": 16777220 }] }
278
+ },
279
+ {
280
+ "name": "split_f32-2x131073",
281
+ "preset": "stress",
282
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
283
+ "tunables": {},
284
+ "inputs": {
285
+ "x": { "shape": [2, 131073], "dtype": "float32", "dist": "normal", "seed": 8123, "scale": 0.5 },
286
+ "scale": { "shape": [], "dtype": "float32", "dist": "uniform", "seed": 8124, "scale": 0.25, "offset": 1 }
287
+ },
288
+ "outputs": { "y": { "shape": [2, 131073], "dtype": "float32" } },
289
+ "bench": { "metrics": [{ "type": "bandwidth", "value": 2097172 }] }
290
+ },
291
+ {
292
+ "name": "split_f32-3x524289",
293
+ "preset": "stress",
294
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
295
+ "tunables": {},
296
+ "inputs": {
297
+ "x": { "shape": [3, 524289], "dtype": "float32", "dist": "normal", "seed": 8123, "scale": 0.5 },
298
+ "scale": { "shape": [], "dtype": "float32", "dist": "uniform", "seed": 8124, "scale": 0.25, "offset": 1 }
299
+ },
300
+ "outputs": { "y": { "shape": [3, 524289], "dtype": "float32" } },
301
+ "bench": { "metrics": [{ "type": "bandwidth", "value": 12582940 }] }
302
+ },
303
+ {
304
+ "name": "split_f32-4x1048576",
305
+ "preset": "stress",
306
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
307
+ "tunables": {},
308
+ "inputs": {
309
+ "x": { "shape": [4, 1048576], "dtype": "float32", "dist": "normal", "seed": 8123, "scale": 0.5 },
310
+ "scale": { "shape": [], "dtype": "float32", "dist": "uniform", "seed": 8124, "scale": 0.25, "offset": 1 }
311
+ },
312
+ "outputs": { "y": { "shape": [4, 1048576], "dtype": "float32" } },
313
+ "bench": { "metrics": [{ "type": "bandwidth", "value": 33554436 }] }
314
+ },
315
+ {
316
+ "name": "split_f32-8x16384",
317
+ "preset": "stress",
318
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
319
+ "tunables": {},
320
+ "inputs": {
321
+ "x": { "shape": [8, 16384], "dtype": "float32", "dist": "normal", "seed": 8123, "scale": 0.5 },
322
+ "scale": { "shape": [], "dtype": "float32", "dist": "uniform", "seed": 8124, "scale": 0.25, "offset": 1 }
323
+ },
324
+ "outputs": { "y": { "shape": [8, 16384], "dtype": "float32" } },
325
+ "bench": { "metrics": [{ "type": "bandwidth", "value": 1048580 }] }
326
+ },
327
+ {
328
+ "name": "split_f32-16x65536",
329
+ "preset": "stress",
330
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
331
+ "tunables": {},
332
+ "inputs": {
333
+ "x": { "shape": [16, 65536], "dtype": "float32", "dist": "normal", "seed": 8123, "scale": 0.5 },
334
+ "scale": { "shape": [], "dtype": "float32", "dist": "uniform", "seed": 8124, "scale": 0.25, "offset": 1 }
335
+ },
336
+ "outputs": { "y": { "shape": [16, 65536], "dtype": "float32" } },
337
+ "bench": { "metrics": [{ "type": "bandwidth", "value": 8388612 }] }
338
+ },
339
+ {
340
+ "name": "split_f32-32x32769",
341
+ "preset": "stress",
342
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
343
+ "tunables": {},
344
+ "inputs": {
345
+ "x": { "shape": [32, 32769], "dtype": "float32", "dist": "normal", "seed": 8123, "scale": 0.5 },
346
+ "scale": { "shape": [], "dtype": "float32", "dist": "uniform", "seed": 8124, "scale": 0.25, "offset": 1 }
347
+ },
348
+ "outputs": { "y": { "shape": [32, 32769], "dtype": "float32" } },
349
+ "bench": { "metrics": [{ "type": "bandwidth", "value": 8388868 }] }
350
+ },
351
+ {
352
+ "name": "split_f32-128x16384",
353
+ "preset": "stress",
354
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
355
+ "tunables": {},
356
+ "inputs": {
357
+ "x": { "shape": [128, 16384], "dtype": "float32", "dist": "normal", "seed": 8123, "scale": 0.5 },
358
+ "scale": { "shape": [], "dtype": "float32", "dist": "uniform", "seed": 8124, "scale": 0.25, "offset": 1 }
359
+ },
360
+ "outputs": { "y": { "shape": [128, 16384], "dtype": "float32" } },
361
+ "bench": { "metrics": [{ "type": "bandwidth", "value": 16777220 }] }
362
+ },
363
+ {
364
+ "name": "split_f16-1x16385",
365
+ "preset": "stress",
366
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
367
+ "tunables": {},
368
+ "inputs": {
369
+ "x": { "shape": [1, 16385], "dtype": "float16", "dist": "normal", "seed": 8123, "scale": 0.5 },
370
+ "scale": { "shape": [], "dtype": "float16", "dist": "uniform", "seed": 8124, "scale": 0.25, "offset": 1 }
371
+ },
372
+ "outputs": { "y": { "shape": [1, 16385], "dtype": "float16" } },
373
+ "bench": { "metrics": [{ "type": "bandwidth", "value": 65542 }] }
374
+ },
375
+ {
376
+ "name": "split_f16-1x131072",
377
+ "preset": "stress",
378
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
379
+ "tunables": {},
380
+ "inputs": {
381
+ "x": { "shape": [1, 131072], "dtype": "float16", "dist": "normal", "seed": 8123, "scale": 0.5 },
382
+ "scale": { "shape": [], "dtype": "float16", "dist": "uniform", "seed": 8124, "scale": 0.25, "offset": 1 }
383
+ },
384
+ "outputs": { "y": { "shape": [1, 131072], "dtype": "float16" } },
385
+ "bench": { "metrics": [{ "type": "bandwidth", "value": 524290 }] }
386
+ },
387
+ {
388
+ "name": "split_f16-1x524288",
389
+ "preset": "stress",
390
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
391
+ "tunables": {},
392
+ "inputs": {
393
+ "x": { "shape": [1, 524288], "dtype": "float16", "dist": "normal", "seed": 8123, "scale": 0.5 },
394
+ "scale": { "shape": [], "dtype": "float16", "dist": "uniform", "seed": 8124, "scale": 0.25, "offset": 1 }
395
+ },
396
+ "outputs": { "y": { "shape": [1, 524288], "dtype": "float16" } },
397
+ "bench": { "metrics": [{ "type": "bandwidth", "value": 2097154 }] }
398
+ },
399
+ {
400
+ "name": "split_f16-1x2097152",
401
+ "preset": "stress",
402
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
403
+ "tunables": {},
404
+ "inputs": {
405
+ "x": { "shape": [1, 2097152], "dtype": "float16", "dist": "normal", "seed": 8123, "scale": 0.5 },
406
+ "scale": { "shape": [], "dtype": "float16", "dist": "uniform", "seed": 8124, "scale": 0.25, "offset": 1 }
407
+ },
408
+ "outputs": { "y": { "shape": [1, 2097152], "dtype": "float16" } },
409
+ "bench": { "metrics": [{ "type": "bandwidth", "value": 8388610 }] }
410
+ },
411
+ {
412
+ "name": "split_f16-3x524289",
413
+ "preset": "stress",
414
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
415
+ "tunables": {},
416
+ "inputs": {
417
+ "x": { "shape": [3, 524289], "dtype": "float16", "dist": "normal", "seed": 8123, "scale": 0.5 },
418
+ "scale": { "shape": [], "dtype": "float16", "dist": "uniform", "seed": 8124, "scale": 0.25, "offset": 1 }
419
+ },
420
+ "outputs": { "y": { "shape": [3, 524289], "dtype": "float16" } },
421
+ "bench": { "metrics": [{ "type": "bandwidth", "value": 6291470 }] }
422
+ },
423
+ {
424
+ "name": "split_f16-16x65536",
425
+ "preset": "stress",
426
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
427
+ "tunables": {},
428
+ "inputs": {
429
+ "x": { "shape": [16, 65536], "dtype": "float16", "dist": "normal", "seed": 8123, "scale": 0.5 },
430
+ "scale": { "shape": [], "dtype": "float16", "dist": "uniform", "seed": 8124, "scale": 0.25, "offset": 1 }
431
+ },
432
+ "outputs": { "y": { "shape": [16, 65536], "dtype": "float16" } },
433
+ "bench": { "metrics": [{ "type": "bandwidth", "value": 4194306 }] }
434
+ },
435
+ {
436
+ "name": "split_f32-f16-2x32769",
437
+ "preset": "stress",
438
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
439
+ "tunables": {},
440
+ "inputs": {
441
+ "x": { "shape": [2, 32769], "dtype": "float32", "dist": "normal", "seed": 8123, "scale": 0.5 },
442
+ "scale": { "shape": [], "dtype": "float16", "dist": "uniform", "seed": 8124, "scale": 0.25, "offset": 1 }
443
+ },
444
+ "outputs": { "y": { "shape": [2, 32769], "dtype": "float16" } },
445
+ "bench": { "metrics": [{ "type": "bandwidth", "value": 393230 }] }
446
+ },
447
+ {
448
+ "name": "split_f16-f32-2x32769",
449
+ "preset": "stress",
450
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
451
+ "tunables": {},
452
+ "inputs": {
453
+ "x": { "shape": [2, 32769], "dtype": "float16", "dist": "normal", "seed": 8123, "scale": 0.5 },
454
+ "scale": { "shape": [], "dtype": "float32", "dist": "uniform", "seed": 8124, "scale": 0.25, "offset": 1 }
455
+ },
456
+ "outputs": { "y": { "shape": [2, 32769], "dtype": "float32" } },
457
+ "bench": { "metrics": [{ "type": "bandwidth", "value": 393232 }] }
458
+ },
459
+ {
460
+ "name": "split_f32-1x16384-split1",
461
+ "preset": "stress",
462
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
463
+ "tunables": { "MAX_SPLITS": 1 },
464
+ "inputs": {
465
+ "x": { "shape": [1, 16384], "dtype": "float32", "dist": "normal", "seed": 8123, "scale": 0.5 },
466
+ "scale": { "shape": [], "dtype": "float32", "dist": "uniform", "seed": 8124, "scale": 0.25, "offset": 1 }
467
+ },
468
+ "outputs": { "y": { "shape": [1, 16384], "dtype": "float32" } },
469
+ "bench": { "metrics": [{ "type": "bandwidth", "value": 131076 }] }
470
+ },
471
+ {
472
+ "name": "split_f32-1x16385-split3",
473
+ "preset": "stress",
474
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
475
+ "tunables": { "MAX_SPLITS": 3 },
476
+ "inputs": {
477
+ "x": { "shape": [1, 16385], "dtype": "float32", "dist": "normal", "seed": 8123, "scale": 0.5 },
478
+ "scale": { "shape": [], "dtype": "float32", "dist": "uniform", "seed": 8124, "scale": 0.25, "offset": 1 }
479
+ },
480
+ "outputs": { "y": { "shape": [1, 16385], "dtype": "float32" } },
481
+ "bench": { "metrics": [{ "type": "bandwidth", "value": 131084 }] }
482
+ },
483
+ {
484
+ "name": "split_f32-2x262145-wg64",
485
+ "preset": "stress",
486
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
487
+ "tunables": { "WORKGROUP_SIZE": 64 },
488
+ "inputs": {
489
+ "x": { "shape": [2, 262145], "dtype": "float32", "dist": "normal", "seed": 8123, "scale": 0.5 },
490
+ "scale": { "shape": [], "dtype": "float32", "dist": "uniform", "seed": 8124, "scale": 0.25, "offset": 1 }
491
+ },
492
+ "outputs": { "y": { "shape": [2, 262145], "dtype": "float32" } },
493
+ "bench": { "metrics": [{ "type": "bandwidth", "value": 4194324 }] }
494
+ },
495
+ {
496
+ "name": "split_f32-2x262145-wg128",
497
+ "preset": "stress",
498
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
499
+ "tunables": { "WORKGROUP_SIZE": 128 },
500
+ "inputs": {
501
+ "x": { "shape": [2, 262145], "dtype": "float32", "dist": "normal", "seed": 8123, "scale": 0.5 },
502
+ "scale": { "shape": [], "dtype": "float32", "dist": "uniform", "seed": 8124, "scale": 0.25, "offset": 1 }
503
+ },
504
+ "outputs": { "y": { "shape": [2, 262145], "dtype": "float32" } },
505
+ "bench": { "metrics": [{ "type": "bandwidth", "value": 4194324 }] }
506
  }
507
  ]
508
  }
build/webgpu/manifest.json CHANGED
@@ -2,47 +2,17 @@
2
  "domain": "ai.onnx",
3
  "name": "RMSNormalization",
4
  "sinceVersion": 23,
5
- "description": "Computes RMS normalization over the suffix dimensions of `X` starting at `axis`: `Y = X / sqrt(mean(X^2) + epsilon) * scale`. The normalization stage supports TensorProto `stash_type` values `1` (float32) and `10` (float16), and is cast back to the dtype of `X` before `scale` is applied. The input type `T` and scale/output type `V` may independently be float16 or float32; ONNX's bfloat16 and double cases are not yet implemented.",
6
- "inputs": [
7
- {
8
- "role": "X",
9
- "dtype": "T",
10
- "description": "Input tensor to be normalized; the RMS is taken over the last dimensions starting at `axis`."
11
- },
12
- {
13
- "role": "scale",
14
- "dtype": "V",
15
- "description": "Scale tensor, unidirectionally broadcastable to `X`; its dtype `V` may differ from the input dtype `T`."
16
- }
17
- ],
18
- "outputs": [
19
- {
20
- "role": "Y",
21
- "dtype": "V",
22
- "rank": "ranks.X",
23
- "shape": "shapes.X",
24
- "description": "Normalized and scaled output tensor; same shape as `X` and same dtype `V` as `scale`."
25
- }
26
- ],
27
- "attributes": { "axis": -1, "epsilon": 0.00001, "stash_type": 1 },
28
- "attributeDescriptions": {
29
- "axis": "The first dimension of the normalization suffix; negative values count from the end, so the default `-1` normalizes over only the last dimension.",
30
- "epsilon": "Small constant added to the mean square before taking the square root to avoid division by zero.",
31
- "stash_type": "TensorProto element type used for normalization: `1` computes in float32, while `10` computes in float16."
32
- },
33
  "attributeConstraints": { "stash_type": { "values": [1, 10] } },
34
  "typeConstraints": { "T": ["float32", "float16"], "V": ["float32", "float16"] },
35
- "args": {
36
- "x": { "kind": "tensor", "semantic": "X", "role": "input" },
37
- "scale": { "kind": "tensor", "semantic": "scale", "role": "input" },
38
- "y": { "kind": "tensor", "semantic": "Y", "role": "output" }
39
- },
40
  "tunables": {
41
- "WORKGROUP_SIZE": 256,
42
- "SPLIT_MAX_ROWS": 256,
43
- "SPLIT_MIN_HIDDEN": 16384,
44
- "SPLIT_TARGET_ELEMENTS": 4096,
45
- "MAX_SPLITS": 64
46
  },
47
  "derive": {
48
  "deviceWorkgroupCap": "min(device.limits.maxComputeInvocationsPerWorkgroup, device.limits.maxComputeWorkgroupSizeX)",
@@ -50,118 +20,51 @@
50
  "reportedNonWave32Adapter": "not wave32Adapter and (has(device.adapterInfo, \"subgroupMinSize\") or has(device.adapterInfo, \"subgroupMaxSize\"))",
51
  "normMaxWorkgroup": "min(tunables.WORKGROUP_SIZE, deviceWorkgroupCap)",
52
  "hasSubgroupId": "device.features.has(\"subgroups\") and device.wgslLanguageFeatures.has(\"subgroup_id\")",
53
- "axisNorm": "attrs.axis if attrs.axis >= 0 else attrs.axis + ranks.X",
54
- "normalizedRows": "outer(shapes.X, axisNorm)",
55
- "normalizedHidden": "dim(shapes.X, axisNorm) * inner(shapes.X, axisNorm)",
56
  "normalizedDispatchRows": "0 if normalizedHidden == 0 else normalizedRows",
57
  "normalizedWorkgroupHidden": "max(1, normalizedHidden)",
58
- "normalizationShapeOk": "ranks.X >= 1 and ranks.scale >= 0 and ranks.scale <= ranks.X and sameShape(shapes.Y, shapes.X) and attrs.axis + ranks.X >= 0 and attrs.axis < ranks.X and broadcastable(shapes.scale, shapes.X) and f16Ok(dtypes.T) and f16Ok(dtypes.V)",
59
  "baseOk": "normalizationShapeOk and attrs.stash_type == onnxDtypeCode(\"float32\")",
60
  "stashF16Ok": "normalizationShapeOk and attrs.stash_type == onnxDtypeCode(\"float16\")",
61
- "lastAxisOk": "baseOk and (attrs.axis == -1 or attrs.axis == ranks.X - 1)",
62
- "suffixAxisOk": "baseOk and ranks.X >= 2 and not (attrs.axis == -1 or attrs.axis == ranks.X - 1)"
63
  },
64
- "bindingSets": {
65
- "rows": [
66
- {
67
- "name": "x",
68
- "arg": "x",
69
- "semantic": "X",
70
- "buffer": { "type": "read-only-storage" },
71
- "elementType": "$xElement"
72
- },
73
- {
74
- "name": "scale",
75
- "arg": "scale",
76
- "semantic": "scale",
77
- "buffer": { "type": "read-only-storage" },
78
- "elementType": "$ioElement"
79
- },
80
- { "name": "y", "arg": "y", "semantic": "Y", "buffer": { "type": "storage" }, "elementType": "$ioElement" },
81
- {
82
- "name": "params",
83
- "semantic": "kernel.params",
84
- "buffer": { "type": "uniform" },
85
- "struct": {
86
- "name": "Params",
87
- "fields": [
88
- { "name": "rows", "type": "u32", "value": "normalizedRows" },
89
- {
90
- "name": "rowStride",
91
- "type": "u32",
92
- "value": "max(1, min(normalizedRows, device.limits.maxComputeWorkgroupsPerDimension))"
93
- }
94
- ]
95
- }
96
- }
97
- ],
98
- "splitPartials": [
99
- {
100
- "name": "x",
101
- "arg": "x",
102
- "semantic": "X",
103
- "buffer": { "type": "read-only-storage" },
104
- "elementType": "$xElement"
105
- },
106
- { "name": "partials", "semantic": "partials", "buffer": { "type": "storage" }, "elementType": "f32" },
107
- {
108
- "name": "params",
109
- "semantic": "kernel.params",
110
- "buffer": { "type": "uniform" },
111
- "struct": {
112
- "name": "Params",
113
- "fields": [
114
- { "name": "rows", "type": "u32", "value": "splitRows" },
115
- {
116
- "name": "rowStride",
117
- "type": "u32",
118
- "value": "max(1, min(splitRows, device.limits.maxComputeWorkgroupsPerDimension))"
119
- }
120
- ]
121
  }
122
- }
123
- ],
124
- "splitNormalize": [
125
- {
126
- "name": "x",
127
- "arg": "x",
128
- "semantic": "X",
129
- "buffer": { "type": "read-only-storage" },
130
- "elementType": "$xElement"
131
- },
132
- {
133
- "name": "scale",
134
- "arg": "scale",
135
- "semantic": "scale",
136
- "buffer": { "type": "read-only-storage" },
137
- "elementType": "$ioElement"
138
- },
139
- { "name": "partials", "semantic": "partials", "buffer": { "type": "read-only-storage" }, "elementType": "f32" },
140
- { "name": "y", "arg": "y", "semantic": "Y", "buffer": { "type": "storage" }, "elementType": "$ioElement" },
141
- {
142
- "name": "params",
143
- "semantic": "kernel.params",
144
- "buffer": { "type": "uniform" },
145
- "struct": {
146
- "name": "Params",
147
- "fields": [
148
- { "name": "rows", "type": "u32", "value": "splitRows" },
149
- {
150
- "name": "rowStride",
151
- "type": "u32",
152
- "value": "max(1, min(splitRows, device.limits.maxComputeWorkgroupsPerDimension))"
153
- }
154
- ]
155
  }
156
- }
157
- ]
158
  },
159
  "variants": [
160
  {
161
  "id": "stash_f16_serial",
162
  "priority": 1000,
163
- "when": "stashF16Ok",
164
- "constants": {
165
  "scalar": "dtypes.V",
166
  "xElement": "dtypes.T",
167
  "ioElement": "dtypes.V",
@@ -173,73 +76,87 @@
173
  {
174
  "id": "main",
175
  "name": "RMSNormalization.StashF16Serial",
176
- "source": {
177
- "shader": "rms-normalization-stash-f16-serial.wgsl.jinja",
178
- "inputs": {
179
- "xShape": "shapes.X",
180
- "scaleShape": "shapes.scale",
181
- "xRank": "ranks.X",
182
- "scaleRank": "ranks.scale"
183
- }
184
  },
185
- "bindings": "rows",
186
- "dispatch": { "workgroups": "normalizedDispatchRows" }
 
 
 
 
187
  }
188
  ]
189
  },
190
  {
191
  "id": "suffix_axis_splitk",
192
  "priority": 15,
 
 
193
  "derive": {
194
  "splitRows": "normalizedRows",
195
  "splitHidden": "normalizedHidden",
196
- "split": "min(tunables.MAX_SPLITS, pow2ceil(ceilDiv(splitHidden, tunables.SPLIT_TARGET_ELEMENTS)))"
197
- },
198
- "when": ["baseOk", "ranks.X >= 2", "normalizedRows <= tunables.SPLIT_MAX_ROWS", "normalizedHidden >= tunables.SPLIT_MIN_HIDDEN", "min(tunables.MAX_SPLITS, pow2ceil(ceilDiv(normalizedHidden, tunables.SPLIT_TARGET_ELEMENTS))) <= device.limits.maxComputeWorkgroupsPerDimension", "normalizedRows * min(tunables.MAX_SPLITS, pow2ceil(ceilDiv(normalizedHidden, tunables.SPLIT_TARGET_ELEMENTS))) * 4 <= device.limits.maxStorageBufferBindingSize", "normalizedRows * min(tunables.MAX_SPLITS, pow2ceil(ceilDiv(normalizedHidden, tunables.SPLIT_TARGET_ELEMENTS))) * 4 <= device.limits.maxBufferSize"],
199
- "demoteWhen": ["reportedNonWave32Adapter"],
200
- "constants": {
201
  "scalar": "dtypes.V",
202
  "xElement": "dtypes.T",
203
  "ioElement": "dtypes.V",
204
  "usesF16": "dtypes.T == \"f16\" or dtypes.V == \"f16\"",
205
  "hiddenSize": "splitHidden",
206
  "workgroupSize": "normMaxWorkgroup",
207
- "split": "split",
208
- "epsilon": "attrs.epsilon"
209
  },
210
  "intermediates": [{ "id": "partials", "dtype": "float32", "shape": "[splitRows * split]" }],
211
  "passes": [
212
  {
213
  "id": "partials",
214
  "name": "RMSNormalization.SplitKPartials",
215
- "source": { "shader": "rms-normalization-splitk-partials.wgsl.jinja", "inputs": {} },
216
- "bindings": "splitPartials",
217
- "dispatch": { "workgroups": "splitRows", "z": "split" }
 
 
 
 
218
  },
219
  {
220
  "id": "normalize",
221
  "name": "RMSNormalization.SplitKNormalize",
222
- "source": {
223
- "shader": "rms-normalization-splitk-normalize.wgsl.jinja",
224
- "inputs": {
225
- "xShape": "shapes.X",
226
- "scaleShape": "shapes.scale",
227
- "xRank": "ranks.X",
228
- "scaleRank": "ranks.scale",
229
- "writeStats": false,
230
- "rmsScaleAfterCast": true
231
- }
232
  },
233
- "bindings": "splitNormalize",
234
- "dispatch": { "workgroups": "splitRows", "z": "split" }
 
 
 
 
 
 
 
 
 
 
235
  }
236
  ]
237
  },
238
  {
239
  "id": "last_axis",
240
  "priority": 0,
241
- "when": "lastAxisOk",
242
- "constants": {
243
  "scalar": "dtypes.V",
244
  "xElement": "dtypes.T",
245
  "usesF16": "dtypes.T == \"f16\" or dtypes.V == \"f16\"",
@@ -252,27 +169,29 @@
252
  {
253
  "id": "main",
254
  "name": "RMSNormalization",
255
- "source": {
256
- "shader": "rms-normalization.wgsl.jinja",
257
- "inputs": {
258
- "xShape": "shapes.X",
259
- "scaleShape": "shapes.scale",
260
- "xRank": "ranks.X",
261
- "scaleRank": "ranks.scale",
262
- "writeStats": false,
263
- "rmsScaleAfterCast": true
264
- }
265
  },
266
- "bindings": "rows",
267
- "dispatch": { "workgroups": "normalizedDispatchRows" }
 
 
 
 
268
  }
269
  ]
270
  },
271
  {
272
  "id": "suffix_axis",
273
  "priority": 10,
274
- "when": "suffixAxisOk",
275
- "constants": {
276
  "scalar": "dtypes.V",
277
  "xElement": "dtypes.T",
278
  "usesF16": "dtypes.T == \"f16\" or dtypes.V == \"f16\"",
@@ -285,83 +204,89 @@
285
  {
286
  "id": "main",
287
  "name": "RMSNormalization.SuffixAxis",
288
- "source": {
289
- "shader": "rms-normalization.wgsl.jinja",
290
- "inputs": {
291
- "xShape": "shapes.X",
292
- "scaleShape": "shapes.scale",
293
- "xRank": "ranks.X",
294
- "scaleRank": "ranks.scale",
295
- "writeStats": false,
296
- "rmsScaleAfterCast": true
297
- }
298
  },
299
- "bindings": "rows",
300
- "dispatch": { "workgroups": "normalizedDispatchRows" }
 
 
 
 
301
  }
302
  ]
303
  },
304
  {
305
  "id": "last_axis_row_vec4",
306
  "priority": 110,
307
- "when": ["lastAxisOk", "dtypes.T == dtypes.V", "ranks.scale >= 1", "numel(shapes.scale) == dim(shapes.X, -1)", "dim(shapes.scale, -1) == dim(shapes.X, -1)", "dim(shapes.X, -1) % 4 == 0"],
308
- "constants": { "xElement": "\"vec4<\" ~ dtypes.T ~ \">\"", "ioElement": "\"vec4<\" ~ dtypes.T ~ \">\"" },
309
  "passes": [
310
  {
311
  "id": "main",
312
  "name": "RMSNormalization.LastAxisRow",
313
- "source": {
314
- "shader": "norm-row-stats.wgsl.jinja",
315
- "inputs": {
316
- "mode": "\"rms\"",
317
- "vec4": true,
318
- "writeStats": false,
319
- "rmsScaleAfterCast": true,
320
- "scalar": "dtypes.T",
321
- "usesF16": "dtypes.T == \"f16\"",
322
- "hidden": "dim(shapes.X, -1)",
323
- "wg": "min(normMaxWorkgroup, pow2ceil(max(1, dim(shapes.X, -1) / 4)))",
324
- "epsilon": "attrs.epsilon",
325
- "hiddenVec": "dim(shapes.X, -1) / 4",
326
- "vecType": "\"vec4<\" ~ dtypes.T ~ \">\"",
327
- "combineSubgroups": "hasSubgroupId"
328
- }
 
 
 
 
329
  },
330
- "subgroupCollectivesWidth": "portable",
331
- "bindings": "rows",
332
- "dispatch": { "workgroups": "normalizedDispatchRows" }
333
  }
334
  ]
335
  },
336
  {
337
  "id": "last_axis_row",
338
  "priority": 100,
339
- "when": ["lastAxisOk", "dtypes.T == dtypes.V", "ranks.scale >= 1", "numel(shapes.scale) == dim(shapes.X, -1)", "dim(shapes.scale, -1) == dim(shapes.X, -1)", "true"],
340
- "constants": { "xElement": "dtypes.T", "ioElement": "dtypes.T" },
341
  "passes": [
342
  {
343
  "id": "main",
344
  "name": "RMSNormalization.LastAxisRow",
345
- "source": {
346
- "shader": "norm-row-stats.wgsl.jinja",
347
- "inputs": {
348
- "mode": "\"rms\"",
349
- "vec4": false,
350
- "writeStats": false,
351
- "rmsScaleAfterCast": true,
352
- "scalar": "dtypes.T",
353
- "usesF16": "dtypes.T == \"f16\"",
354
- "hidden": "dim(shapes.X, -1)",
355
- "wg": "min(normMaxWorkgroup, pow2ceil(max(1, dim(shapes.X, -1))))",
356
- "epsilon": "attrs.epsilon",
357
- "hiddenVec": 1,
358
- "vecType": "\"vec4<\" ~ dtypes.T ~ \">\"",
359
- "combineSubgroups": "hasSubgroupId"
360
- }
 
 
 
 
361
  },
362
- "subgroupCollectivesWidth": "portable",
363
- "bindings": "rows",
364
- "dispatch": { "workgroups": "normalizedDispatchRows" }
365
  }
366
  ]
367
  }
 
2
  "domain": "ai.onnx",
3
  "name": "RMSNormalization",
4
  "sinceVersion": 23,
5
+ "inputs": { "x": { "onnx": "X", "dtype": "T" }, "scale": { "dtype": "V" } },
6
+ "outputs": { "y": { "onnx": "Y", "dtype": "V", "rank": "ranks.x", "shape": "shapes.x" } },
7
+ "attributes": { "axis": { "default": -1 }, "epsilon": { "default": 0.00001 }, "stash_type": { "default": 1 } },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  "attributeConstraints": { "stash_type": { "values": [1, 10] } },
9
  "typeConstraints": { "T": ["float32", "float16"], "V": ["float32", "float16"] },
 
 
 
 
 
10
  "tunables": {
11
+ "WORKGROUP_SIZE": { "default": 256 },
12
+ "SPLIT_MAX_ROWS": { "default": 256 },
13
+ "SPLIT_MIN_HIDDEN": { "default": 16384 },
14
+ "SPLIT_TARGET_ELEMENTS": { "default": 4096 },
15
+ "MAX_SPLITS": { "default": 64 }
16
  },
17
  "derive": {
18
  "deviceWorkgroupCap": "min(device.limits.maxComputeInvocationsPerWorkgroup, device.limits.maxComputeWorkgroupSizeX)",
 
20
  "reportedNonWave32Adapter": "not wave32Adapter and (has(device.adapterInfo, \"subgroupMinSize\") or has(device.adapterInfo, \"subgroupMaxSize\"))",
21
  "normMaxWorkgroup": "min(tunables.WORKGROUP_SIZE, deviceWorkgroupCap)",
22
  "hasSubgroupId": "device.features.has(\"subgroups\") and device.wgslLanguageFeatures.has(\"subgroup_id\")",
23
+ "axisNorm": "attrs.axis if attrs.axis >= 0 else attrs.axis + ranks.x",
24
+ "normalizedRows": "outer(shapes.x, axisNorm)",
25
+ "normalizedHidden": "dim(shapes.x, axisNorm) * inner(shapes.x, axisNorm)",
26
  "normalizedDispatchRows": "0 if normalizedHidden == 0 else normalizedRows",
27
  "normalizedWorkgroupHidden": "max(1, normalizedHidden)",
28
+ "normalizationShapeOk": "ranks.x >= 1 and ranks.scale >= 0 and ranks.scale <= ranks.x and sameShape(shapes.y, shapes.x) and attrs.axis + ranks.x >= 0 and attrs.axis < ranks.x and broadcastable(shapes.scale, shapes.x) and f16Ok(dtypes.T) and f16Ok(dtypes.V)",
29
  "baseOk": "normalizationShapeOk and attrs.stash_type == onnxDtypeCode(\"float32\")",
30
  "stashF16Ok": "normalizationShapeOk and attrs.stash_type == onnxDtypeCode(\"float16\")",
31
+ "lastAxisOk": "baseOk and (attrs.axis == -1 or attrs.axis == ranks.x - 1)",
32
+ "suffixAxisOk": "baseOk and ranks.x >= 2 and not (attrs.axis == -1 or attrs.axis == ranks.x - 1)"
33
  },
34
+ "bindings": {
35
+ "x": { "buffer": "read-only-storage", "elementType": "$xElement" },
36
+ "scale": { "buffer": "read-only-storage", "elementType": "$ioElement" },
37
+ "y": { "buffer": "storage", "elementType": "$ioElement" },
38
+ "params": {
39
+ "buffer": "uniform",
40
+ "struct": [
41
+ { "name": "rows", "type": "u32", "value": "normalizedRows" },
42
+ {
43
+ "name": "rowStride",
44
+ "type": "u32",
45
+ "value": "max(1, min(normalizedRows, min(device.limits.maxComputeWorkgroupsPerDimension, 65535)))"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
  }
47
+ ]
48
+ },
49
+ "params_2": {
50
+ "name": "params",
51
+ "buffer": "uniform",
52
+ "struct": [
53
+ { "name": "rows", "type": "u32", "value": "splitRows" },
54
+ {
55
+ "name": "rowStride",
56
+ "type": "u32",
57
+ "value": "max(1, min(splitRows, min(device.limits.maxComputeWorkgroupsPerDimension, 65535)))"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
  }
59
+ ]
60
+ }
61
  },
62
  "variants": [
63
  {
64
  "id": "stash_f16_serial",
65
  "priority": 1000,
66
+ "when": ["stashF16Ok"],
67
+ "derive": {
68
  "scalar": "dtypes.V",
69
  "xElement": "dtypes.T",
70
  "ioElement": "dtypes.V",
 
76
  {
77
  "id": "main",
78
  "name": "RMSNormalization.StashF16Serial",
79
+ "shader": "rms-normalization-stash-f16-serial.wgsl.jinja",
80
+ "derive": {
81
+ "xShape": "shapes.x",
82
+ "scaleShape": "shapes.scale",
83
+ "xRank": "ranks.x",
84
+ "scaleRank": "ranks.scale"
 
 
85
  },
86
+ "bindings": ["x", "scale", "y", "params"],
87
+ "dispatch": {
88
+ "x": "min(normalizedDispatchRows, 65535)",
89
+ "y": "ceilDiv(normalizedDispatchRows, 65535)",
90
+ "z": 1
91
+ }
92
  }
93
  ]
94
  },
95
  {
96
  "id": "suffix_axis_splitk",
97
  "priority": 15,
98
+ "when": ["baseOk", "ranks.x >= 2", "normalizedRows <= tunables.SPLIT_MAX_ROWS", "normalizedHidden >= tunables.SPLIT_MIN_HIDDEN", "min(tunables.MAX_SPLITS, pow2ceil(ceilDiv(normalizedHidden, tunables.SPLIT_TARGET_ELEMENTS))) <= min(device.limits.maxComputeWorkgroupsPerDimension, 65535)", "normalizedRows * min(tunables.MAX_SPLITS, pow2ceil(ceilDiv(normalizedHidden, tunables.SPLIT_TARGET_ELEMENTS))) * 4 <= device.limits.maxStorageBufferBindingSize", "normalizedRows * min(tunables.MAX_SPLITS, pow2ceil(ceilDiv(normalizedHidden, tunables.SPLIT_TARGET_ELEMENTS))) * 4 <= device.limits.maxBufferSize"],
99
+ "demoteWhen": ["reportedNonWave32Adapter"],
100
  "derive": {
101
  "splitRows": "normalizedRows",
102
  "splitHidden": "normalizedHidden",
103
+ "split": "min(tunables.MAX_SPLITS, pow2ceil(ceilDiv(splitHidden, tunables.SPLIT_TARGET_ELEMENTS)))",
 
 
 
 
104
  "scalar": "dtypes.V",
105
  "xElement": "dtypes.T",
106
  "ioElement": "dtypes.V",
107
  "usesF16": "dtypes.T == \"f16\" or dtypes.V == \"f16\"",
108
  "hiddenSize": "splitHidden",
109
  "workgroupSize": "normMaxWorkgroup",
110
+ "epsilon": "attrs.epsilon",
111
+ "normalizeRows": "splitRows"
112
  },
113
  "intermediates": [{ "id": "partials", "dtype": "float32", "shape": "[splitRows * split]" }],
114
  "passes": [
115
  {
116
  "id": "partials",
117
  "name": "RMSNormalization.SplitKPartials",
118
+ "shader": "rms-normalization-splitk-partials.wgsl.jinja",
119
+ "bindings": ["x", { "name": "partials", "buffer": "storage", "elementType": "f32" }, "params_2"],
120
+ "dispatch": {
121
+ "x": "min(splitRows, DISPATCH_FOLD_WIDTH)",
122
+ "y": "ceilDiv(splitRows, DISPATCH_FOLD_WIDTH)",
123
+ "z": "split"
124
+ }
125
  },
126
  {
127
  "id": "normalize",
128
  "name": "RMSNormalization.SplitKNormalize",
129
+ "shader": "rms-normalization-splitk-normalize.wgsl.jinja",
130
+ "derive": {
131
+ "xShape": "shapes.x",
132
+ "scaleShape": "shapes.scale",
133
+ "xRank": "ranks.x",
134
+ "scaleRank": "ranks.scale",
135
+ "writeStats": false,
136
+ "rmsScaleAfterCast": true,
137
+ "normalizeBlocks": "max(split, min(min(device.limits.maxComputeWorkgroupsPerDimension, 65535), ceilDiv(workgroupSize, max(1, normalizeRows)), ceilDiv(hiddenSize, workgroupSize * 4)))",
138
+ "normalizeChunk": "ceilDiv(hiddenSize, normalizeBlocks)"
139
  },
140
+ "bindings": [
141
+ "x",
142
+ "scale",
143
+ { "name": "partials", "buffer": "read-only-storage", "elementType": "f32" },
144
+ "y",
145
+ "params_2"
146
+ ],
147
+ "dispatch": {
148
+ "x": "min(splitRows, DISPATCH_FOLD_WIDTH)",
149
+ "y": "ceilDiv(splitRows, DISPATCH_FOLD_WIDTH)",
150
+ "z": "normalizeBlocks"
151
+ }
152
  }
153
  ]
154
  },
155
  {
156
  "id": "last_axis",
157
  "priority": 0,
158
+ "when": ["lastAxisOk"],
159
+ "derive": {
160
  "scalar": "dtypes.V",
161
  "xElement": "dtypes.T",
162
  "usesF16": "dtypes.T == \"f16\" or dtypes.V == \"f16\"",
 
169
  {
170
  "id": "main",
171
  "name": "RMSNormalization",
172
+ "shader": "rms-normalization.wgsl.jinja",
173
+ "derive": {
174
+ "xShape": "shapes.x",
175
+ "scaleShape": "shapes.scale",
176
+ "xRank": "ranks.x",
177
+ "scaleRank": "ranks.scale",
178
+ "writeStats": false,
179
+ "rmsScaleAfterCast": true
 
 
180
  },
181
+ "bindings": ["x", "scale", "y", "params"],
182
+ "dispatch": {
183
+ "x": "min(normalizedDispatchRows, 65535)",
184
+ "y": "ceilDiv(normalizedDispatchRows, 65535)",
185
+ "z": 1
186
+ }
187
  }
188
  ]
189
  },
190
  {
191
  "id": "suffix_axis",
192
  "priority": 10,
193
+ "when": ["suffixAxisOk"],
194
+ "derive": {
195
  "scalar": "dtypes.V",
196
  "xElement": "dtypes.T",
197
  "usesF16": "dtypes.T == \"f16\" or dtypes.V == \"f16\"",
 
204
  {
205
  "id": "main",
206
  "name": "RMSNormalization.SuffixAxis",
207
+ "shader": "rms-normalization.wgsl.jinja",
208
+ "derive": {
209
+ "xShape": "shapes.x",
210
+ "scaleShape": "shapes.scale",
211
+ "xRank": "ranks.x",
212
+ "scaleRank": "ranks.scale",
213
+ "writeStats": false,
214
+ "rmsScaleAfterCast": true
 
 
215
  },
216
+ "bindings": ["x", "scale", "y", "params"],
217
+ "dispatch": {
218
+ "x": "min(normalizedDispatchRows, 65535)",
219
+ "y": "ceilDiv(normalizedDispatchRows, 65535)",
220
+ "z": 1
221
+ }
222
  }
223
  ]
224
  },
225
  {
226
  "id": "last_axis_row_vec4",
227
  "priority": 110,
228
+ "when": ["lastAxisOk", "dtypes.T == dtypes.V", "ranks.scale >= 1", "numel(shapes.scale) == dim(shapes.x, -1)", "dim(shapes.scale, -1) == dim(shapes.x, -1)", "dim(shapes.x, -1) % 4 == 0"],
229
+ "derive": { "xElement": "\"vec4<\" ~ dtypes.T ~ \">\"", "ioElement": "\"vec4<\" ~ dtypes.T ~ \">\"" },
230
  "passes": [
231
  {
232
  "id": "main",
233
  "name": "RMSNormalization.LastAxisRow",
234
+ "shader": "norm-row-stats.wgsl.jinja",
235
+ "derive": {
236
+ "modeSpec": "\"rms\"",
237
+ "vec4": true,
238
+ "writeStats": false,
239
+ "rmsScaleAfterCast": true,
240
+ "scalar": "dtypes.T",
241
+ "usesF16Spec": "dtypes.T == \"f16\"",
242
+ "hidden": "dim(shapes.x, -1)",
243
+ "wg": "min(normMaxWorkgroup, pow2ceil(max(1, dim(shapes.x, -1) / 4)))",
244
+ "epsilon": "attrs.epsilon",
245
+ "hiddenVec": "dim(shapes.x, -1) / 4",
246
+ "vecType": "\"vec4<\" ~ dtypes.T ~ \">\"",
247
+ "combineSubgroups": "hasSubgroupId"
248
+ },
249
+ "bindings": ["x", "scale", "y", "params"],
250
+ "dispatch": {
251
+ "x": "min(normalizedDispatchRows, 65535)",
252
+ "y": "ceilDiv(normalizedDispatchRows, 65535)",
253
+ "z": 1
254
  },
255
+ "subgroupCollectivesWidth": "portable"
 
 
256
  }
257
  ]
258
  },
259
  {
260
  "id": "last_axis_row",
261
  "priority": 100,
262
+ "when": ["lastAxisOk", "dtypes.T == dtypes.V", "ranks.scale >= 1", "numel(shapes.scale) == dim(shapes.x, -1)", "dim(shapes.scale, -1) == dim(shapes.x, -1)", "true"],
263
+ "derive": { "xElement": "dtypes.T", "ioElement": "dtypes.T" },
264
  "passes": [
265
  {
266
  "id": "main",
267
  "name": "RMSNormalization.LastAxisRow",
268
+ "shader": "norm-row-stats.wgsl.jinja",
269
+ "derive": {
270
+ "modeSpec": "\"rms\"",
271
+ "vec4": false,
272
+ "writeStats": false,
273
+ "rmsScaleAfterCast": true,
274
+ "scalar": "dtypes.T",
275
+ "usesF16Spec": "dtypes.T == \"f16\"",
276
+ "hidden": "dim(shapes.x, -1)",
277
+ "wg": "min(normMaxWorkgroup, pow2ceil(max(1, dim(shapes.x, -1))))",
278
+ "epsilon": "attrs.epsilon",
279
+ "hiddenVec": 1,
280
+ "vecType": "\"vec4<\" ~ dtypes.T ~ \">\"",
281
+ "combineSubgroups": "hasSubgroupId"
282
+ },
283
+ "bindings": ["x", "scale", "y", "params"],
284
+ "dispatch": {
285
+ "x": "min(normalizedDispatchRows, 65535)",
286
+ "y": "ceilDiv(normalizedDispatchRows, 65535)",
287
+ "z": 1
288
  },
289
+ "subgroupCollectivesWidth": "portable"
 
 
290
  }
291
  ]
292
  }
build/webgpu/metadata.json CHANGED
@@ -1,22 +1,32 @@
1
  {
2
  "name": "ai.onnx.RMSNormalization",
3
- "id": "_ai_onnx_rmsnormalization_webgpu_78878c2",
4
  "version": 1,
5
  "license": "Apache-2.0",
6
  "backend": { "type": "webgpu" },
7
  "digest": {
8
  "algorithm": "sha256",
9
  "files": {
10
- "bench.json": "aQ8RZqdCxZw7VI+7n2XQneyE8kM1Qzire3++ZtvURxg=",
11
- "manifest.json": "Nl952QCnY+Pw6VgYi/lKfYZEh3PpBL2LijyCQqtMTTg=",
12
- "norm-row-stats.wgsl.jinja": "uxWNeifDOH5P8jfrDfE95ow3QGhewBtScBqM76ps2YI=",
13
- "rms-normalization-splitk-normalize.wgsl.jinja": "TXhEDbPnIGP5Ba5SckUHyuuAdCWCip2BH5sJLZ43DdE=",
14
- "rms-normalization-splitk-partials.wgsl.jinja": "GbYu7Cj/LLO9y2Rvhw30RJAUAduI0xfN5YS3H/4Z1k8=",
15
- "rms-normalization-stash-f16-serial.wgsl.jinja": "tzxVAVThZ5QRnu0dtHoYwqYErZwth2dViidXHaqsVGo=",
16
- "rms-normalization.wgsl.jinja": "2YtdapcEAWQUL/wotiMPs8i6wfRV3VG+y+CPhdu47nM=",
17
- "test.json": "09ASLvCprHAheaBj+hX9jc5xDu/05mUj7mOoFwJWWyk="
18
  }
19
  },
20
- "provenance": { "kernel": { "sha": "2e7068faf55e7f43df740015f6d1ee49391a41c5", "dirty": false } },
21
- "webgpu": { "manifestSpec": "1.0", "specialized": true, "opPath": "ops/ai.onnx.RMSNormalization" }
 
 
 
 
 
 
 
 
 
 
22
  }
 
1
  {
2
  "name": "ai.onnx.RMSNormalization",
3
+ "id": "_ai_onnx_rmsnormalization_webgpu_9f92cf5",
4
  "version": 1,
5
  "license": "Apache-2.0",
6
  "backend": { "type": "webgpu" },
7
  "digest": {
8
  "algorithm": "sha256",
9
  "files": {
10
+ "bench.json": "aQq6UMoOU5W6oOnS6tWV1CjBpS0e4r93laCsON1jvqk=",
11
+ "manifest.json": "ayMwG0Hl94mrw8rLqrQus65vGITfIySQBSRfgp+6dK0=",
12
+ "norm-row-stats.wgsl.jinja": "eRBO50QnNhvyqRW/Wdw6rzfJRgVlRT0P6oWVqcDPf5w=",
13
+ "rms-normalization-splitk-normalize.wgsl.jinja": "Vs708VdMX/fAhYyv9Q7EZbVRNllO6XVhaUaxt+aSJGg=",
14
+ "rms-normalization-splitk-partials.wgsl.jinja": "Vs4HNsa9ZbLPsW/ZOunRg64qFmbg7WfJ/uE6gqALmSQ=",
15
+ "rms-normalization-stash-f16-serial.wgsl.jinja": "stNcILDu/EW/WEVtmhYEcIpgE0vOVp0XdvomibMkXBU=",
16
+ "rms-normalization.wgsl.jinja": "5+i/fHAcHlyZ+Co5hpTNZFHHw1YO+QdqsGg2har/Pa4=",
17
+ "test.json": "B1fCbyIY2ig58fLsPyM9j4x2gyi1uUuD0TTRN6cUesQ="
18
  }
19
  },
20
+ "provenance": { "kernel": { "sha": "91d990483a174128daf7673f3f37a7c890493ae1", "dirty": false } },
21
+ "webgpu": {
22
+ "manifestSpec": "2.0",
23
+ "variants": {
24
+ "stash_f16_serial": ["rms-normalization-stash-f16-serial.wgsl.jinja"],
25
+ "suffix_axis_splitk": ["rms-normalization-splitk-normalize.wgsl.jinja", "rms-normalization-splitk-partials.wgsl.jinja"],
26
+ "last_axis": ["rms-normalization.wgsl.jinja"],
27
+ "suffix_axis": ["rms-normalization.wgsl.jinja"],
28
+ "last_axis_row_vec4": ["norm-row-stats.wgsl.jinja"],
29
+ "last_axis_row": ["norm-row-stats.wgsl.jinja"]
30
+ }
31
+ }
32
  }
build/webgpu/norm-row-stats.wgsl.jinja CHANGED
@@ -1,10 +1,25 @@
1
- {% if source.usesF16 %}
2
  enable f16;
3
  {% endif %}
4
- {% set combineSubgroups = source.combineSubgroups %}
5
- {% set scalarIo = source.scalarIo if source.scalarIo is defined else false %}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
  {% set rmsScaleVec = "vec4<f32>(scale[i])" %}
7
  {% set rmsScaleScalar = "f32(scale[i])" %}
 
8
  {% set reduceThreadParameters = ", sg_lane: u32, sg_id: u32, num_sg: u32"
9
  if combineSubgroups else ", tid: u32" %}
10
  {% set reduceThreadArguments = ", sg_lane, sg_id, num_sg"
@@ -23,14 +38,57 @@ enable subgroups;
23
  // tree, then every thread applies the fused normalize + affine write.
24
  //
25
  // RMS mode uses sum_sq / HIDDEN without computing or subtracting a mean.
26
- const HIDDEN: u32 = {{ source.hidden }}u;
27
- {% if source.vec4 %}
28
- const HIDDEN_V: u32 = {{ source.hiddenVec }}u;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  {% endif %}
30
- const WG: u32 = {{ source.wg }}u;
31
- const EPSILON: f32 = {{ source.epsilon }};
32
 
 
 
 
 
 
 
 
 
 
 
 
 
33
 
 
 
 
 
 
34
 
35
  {% if combineSubgroups %}
36
  var<workgroup> sg_partials: array<f32, WG>;
@@ -84,7 +142,14 @@ fn main(
84
  return;
85
  }
86
  let tid = lid.x;
87
- {% if source.vec4 and not scalarIo %}
 
 
 
 
 
 
 
88
  let base = row * HIDDEN_V;
89
  {% else %}
90
  let base = row * HIDDEN;
@@ -92,14 +157,26 @@ fn main(
92
 
93
 
94
  var acc = 0.0;
95
- {% if source.vec4 %}
96
  for (var i = tid; i < HIDDEN_V; i = i + WG) {
 
 
 
 
 
 
97
  let v = vec4<f32>(x[base + i]);
 
98
  acc = acc + dot(v, v);
99
  }
100
  {% else %}
101
  for (var i = tid; i < HIDDEN; i = i + WG) {
 
 
 
 
102
  let v = f32(x[base + i]);
 
103
  acc = acc + v * v;
104
  }
105
  {% endif %}
@@ -107,18 +184,70 @@ fn main(
107
  let total = reduce_scalar(acc{{ reduceThreadArguments }});
108
 
109
  let inv = inverseSqrt(total / f32(HIDDEN) + EPSILON);
 
 
 
 
 
110
 
111
- {% if source.vec4 %}
 
 
 
112
  for (var i = tid; i < HIDDEN_V; i = i + WG) {
 
 
 
 
 
 
 
113
  let idx = base + i;
114
  let v = vec4<f32>(x[idx]);
115
- y[idx] = {{ source.vecType }}(v * inv) * {{ source.vecType }}({{ rmsScaleVec }});
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
  {% else %}
118
  for (var i = tid; i < HIDDEN; i = i + WG) {
119
  let idx = base + i;
 
 
 
120
  let v = f32(x[idx]);
121
- y[idx] = {{ source.scalar }}(v * inv) * {{ source.scalar }}({{ rmsScaleScalar }});
 
 
 
 
 
122
  }
123
  {% endif %}
124
  }
 
1
+ {% if usesF16Spec %}
2
  enable f16;
3
  {% endif %}
4
+ {% set combineSubgroups = combineSubgroups %}
5
+ {% set scalarIo = scalarIo if scalarIo is defined else false %}
6
+ {% set packedBf16Embedding = packedBf16Embedding if packedBf16Embedding is defined else false %}
7
+ {% set writeStats = writeStats if writeStats is defined else false %}
8
+ {% set rmsWeightOffset = rmsWeightOffset if rmsWeightOffset is defined else false %}
9
+ {% set rmsScaleAfterCast = rmsScaleAfterCast if rmsScaleAfterCast is defined else false %}
10
+ {% set rmsResidualAdd = rmsResidualAdd if rmsResidualAdd is defined else false %}
11
+ {% set rmsChainNorm = rmsChainNorm if rmsChainNorm is defined else false %}
12
+ {% set hiddenPairs = hiddenPairs | default(0) %}
13
+ {% set numRows = numRows | default(0) %}
14
+ {% set epsilon = epsilon | default("0.0") %}
15
+ {% set epsilon2 = epsilon2 | default("0.0") %}
16
+ {% if rmsWeightOffset %}
17
+ {% set rmsScaleVec = "(vec4<f32>(1.0) + vec4<f32>(scale[i]))" %}
18
+ {% set rmsScaleScalar = "(1.0 + f32(scale[i]))" %}
19
+ {% else %}
20
  {% set rmsScaleVec = "vec4<f32>(scale[i])" %}
21
  {% set rmsScaleScalar = "f32(scale[i])" %}
22
+ {% endif %}
23
  {% set reduceThreadParameters = ", sg_lane: u32, sg_id: u32, num_sg: u32"
24
  if combineSubgroups else ", tid: u32" %}
25
  {% set reduceThreadArguments = ", sg_lane, sg_id, num_sg"
 
38
  // tree, then every thread applies the fused normalize + affine write.
39
  //
40
  // RMS mode uses sum_sq / HIDDEN without computing or subtracting a mean.
41
+ const HIDDEN: u32 = {{ hidden }}u;
42
+ {% if vec4 %}
43
+ const HIDDEN_V: u32 = {{ hiddenVec }}u;
44
+ {% endif %}
45
+ {% if packedBf16Embedding %}
46
+ const HIDDEN_PAIRS: u32 = {{ hiddenPairs }}u;
47
+ const NUM_ROWS: u32 = {{ numRows }}u;
48
+ {% endif %}
49
+ const WG: u32 = {{ wg }}u;
50
+ const EPSILON: f32 = {{ epsilon }};
51
+ {% if rmsChainNorm %}
52
+ const EPSILON2: f32 = {{ epsilon2 }};
53
+ {% endif %}
54
+
55
+ {% if packedBf16Embedding %}
56
+ {% if vec4 %}
57
+ fn unpack_bf16_pair(word: u32) -> vec2<f32> {
58
+ let bits = vec2<u32>(word & 0xffffu, word >> 16u);
59
+ return bitcast<vec2<f32>>(bits << vec2<u32>(16u));
60
+ }
61
+ {% endif %}
62
+
63
+ {% if not vec4 %}
64
+ fn embedding_scalar(source_row: u32, hidden: u32) -> f32 {
65
+ if (source_row >= NUM_ROWS) {
66
+ return 0.0;
67
+ }
68
+ let word = x[source_row * HIDDEN_PAIRS + (hidden >> 1u)];
69
+ let bits = select(word & 0xffffu, word >> 16u, (hidden & 1u) != 0u);
70
+ return bitcast<f32>(bits << 16u);
71
+ }
72
  {% endif %}
 
 
73
 
74
+ {% if vec4 %}
75
+ fn embedding_vec4(source_row: u32, hidden_vec: u32) -> vec4<f32> {
76
+ if (source_row >= NUM_ROWS) {
77
+ return vec4<f32>(0.0);
78
+ }
79
+ let base = source_row * HIDDEN_PAIRS + hidden_vec * 2u;
80
+ let low = unpack_bf16_pair(x[base]);
81
+ let high = unpack_bf16_pair(x[base + 1u]);
82
+ return vec4<f32>(low, high);
83
+ }
84
+ {% endif %}
85
+ {% endif %}
86
 
87
+ {% if vec4 and scalarIo %}
88
+ fn load_vec4(index: u32) -> vec4<f32> {
89
+ return vec4<f32>(x[index], x[index + 1u], x[index + 2u], x[index + 3u]);
90
+ }
91
+ {% endif %}
92
 
93
  {% if combineSubgroups %}
94
  var<workgroup> sg_partials: array<f32, WG>;
 
142
  return;
143
  }
144
  let tid = lid.x;
145
+ {% if packedBf16Embedding %}
146
+ let source_row = indices[row];
147
+ {% if vec4 %}
148
+ let base = row * HIDDEN_V;
149
+ {% else %}
150
+ let base = row * HIDDEN;
151
+ {% endif %}
152
+ {% elif vec4 and not scalarIo %}
153
  let base = row * HIDDEN_V;
154
  {% else %}
155
  let base = row * HIDDEN;
 
157
 
158
 
159
  var acc = 0.0;
160
+ {% if vec4 %}
161
  for (var i = tid; i < HIDDEN_V; i = i + WG) {
162
+ {% if packedBf16Embedding %}
163
+ let v = embedding_vec4(source_row, i);
164
+ embedding_out[base + i] = v;
165
+ {% elif scalarIo %}
166
+ let v = load_vec4(base + i * 4u);
167
+ {% else %}
168
  let v = vec4<f32>(x[base + i]);
169
+ {% endif %}
170
  acc = acc + dot(v, v);
171
  }
172
  {% else %}
173
  for (var i = tid; i < HIDDEN; i = i + WG) {
174
+ {% if packedBf16Embedding %}
175
+ let v = embedding_scalar(source_row, i);
176
+ embedding_out[base + i] = v;
177
+ {% else %}
178
  let v = f32(x[base + i]);
179
+ {% endif %}
180
  acc = acc + v * v;
181
  }
182
  {% endif %}
 
184
  let total = reduce_scalar(acc{{ reduceThreadArguments }});
185
 
186
  let inv = inverseSqrt(total / f32(HIDDEN) + EPSILON);
187
+ {% if writeStats %}
188
+ if (tid == 0u) {
189
+ inv_std_out[row] = inv;
190
+ }
191
+ {% endif %}
192
 
193
+ {% if rmsChainNorm %}
194
+ var acc2 = 0.0;
195
+ {% endif %}
196
+ {% if vec4 %}
197
  for (var i = tid; i < HIDDEN_V; i = i + WG) {
198
+ {% if packedBf16Embedding %}
199
+ let idx = base + i;
200
+ let v = embedding_vec4(source_row, i);
201
+ {% elif scalarIo %}
202
+ let idx = base + i * 4u;
203
+ let v = load_vec4(idx);
204
+ {% else %}
205
  let idx = base + i;
206
  let v = vec4<f32>(x[idx]);
207
+ {% endif %}
208
+ {% if rmsScaleAfterCast %}
209
+ y[idx] = {{ vecType }}(v * inv) * {{ vecType }}({{ rmsScaleVec }});
210
+ {% elif rmsChainNorm %}
211
+ // fma(a, b, 0.0) rounds the weighted product exactly as the decomposed pair's store does,
212
+ // and prevents the compiler from re-contracting it into the residual add.
213
+ let hv = y[idx] + fma(v * inv, {{ rmsScaleVec }}, vec4<f32>(0.0));
214
+ y[idx] = hv;
215
+ acc2 = acc2 + dot(hv, hv);
216
+ {% elif rmsResidualAdd %}
217
+ // See the chained branch: fma(a, b, 0.0) pins the pre-add rounding of the decomposed pair.
218
+ y[idx] = y[idx] + fma(v * inv, {{ rmsScaleVec }}, vec4<f32>(0.0));
219
+ {% else %}
220
+ y[idx] = {{ vecType }}(v * inv * {{ rmsScaleVec }});
221
+ {% endif %}
222
  }
223
+ {% if rmsChainNorm %}
224
+
225
+ // The chained second norm reads the residual row this loop just stored. This
226
+ // barrier completes those stores and any preceding shared-scratch use before
227
+ // the next reduction reuses its scratch; each lane then re-reads only the
228
+ // elements it wrote itself.
229
+ workgroupBarrier();
230
+ let total2 = reduce_scalar(acc2{{ reduceThreadArguments }});
231
+ let inv2 = inverseSqrt(total2 / f32(HIDDEN) + EPSILON2);
232
+ for (var i = tid; i < HIDDEN_V; i = i + WG) {
233
+ let idx = base + i;
234
+ let hv = vec4<f32>(y[idx]);
235
+ normed2[idx] = {{ vecType }}(hv * inv2 * vec4<f32>(scale2[i]));
236
+ }
237
+ {% endif %}
238
  {% else %}
239
  for (var i = tid; i < HIDDEN; i = i + WG) {
240
  let idx = base + i;
241
+ {% if packedBf16Embedding %}
242
+ let v = embedding_scalar(source_row, i);
243
+ {% else %}
244
  let v = f32(x[idx]);
245
+ {% endif %}
246
+ {% if rmsScaleAfterCast %}
247
+ y[idx] = {{ scalar }}(v * inv) * {{ scalar }}({{ rmsScaleScalar }});
248
+ {% else %}
249
+ y[idx] = {{ scalar }}(v * inv * {{ rmsScaleScalar }});
250
+ {% endif %}
251
  }
252
  {% endif %}
253
  }
build/webgpu/rms-normalization-splitk-normalize.wgsl.jinja CHANGED
@@ -1,11 +1,7 @@
1
- // Split-K normalize pass. Each workgroup (row = wg.x, split index = wg.z)
2
- // folds the SPLIT per-row partial sums of squares into the RMS scale, then
3
- // normalizes its HIDDEN/SPLIT slice. SPLIT is small (<=64), so the serial fold
4
- // avoids a third combine pass. Scale offsets follow the suffix-axis broadcast
5
- // contract.
6
- {% if usesF16 %}
7
- enable f16;
8
- {% endif %}
9
  {{ env.wgsl.resourceDeclarations }}
10
 
11
  const HIDDEN: u32 = {{ hiddenSize }}u;
@@ -13,11 +9,11 @@ const EPSILON: f32 = {{ epsilon }};
13
  const WG: u32 = {{ workgroupSize }}u;
14
  const SPLIT: u32 = {{ split }}u;
15
 
16
- {% if source.scaleRank > 0 %}
17
- const X_RANK: u32 = {{ source.xRank }}u;
18
- const SCALE_RANK: u32 = {{ source.scaleRank }}u;
19
- const X_SHAPE: array<u32, {{ source.xRank }}> = array<u32, {{ source.xRank }}>({% for d in source.xShape %}{{ d }}u{% if not loop.last %}, {% endif %}{% endfor %});
20
- const SCALE_SHAPE: array<u32, {{ source.scaleRank }}> = array<u32, {{ source.scaleRank }}>({% for d in source.scaleShape %}{{ d }}u{% if not loop.last %}, {% endif %}{% endfor %});
21
 
22
  fn x_stride(axis: u32) -> u32 {
23
  var stride = 1u;
@@ -36,8 +32,8 @@ fn scale_stride(axis: u32) -> u32 {
36
  }
37
 
38
  {% endif %}
39
- fn scale_offset({% if source.scaleRank > 0 %}out_index: u32{% endif %}) -> u32 {
40
- {% if source.scaleRank == 0 %}
41
  return 0u;
42
  {% else %}
43
  var rem = out_index;
@@ -59,6 +55,8 @@ fn scale_offset({% if source.scaleRank > 0 %}out_index: u32{% endif %}) -> u32 {
59
  }
60
 
61
 
 
 
62
  @compute @workgroup_size(WG, 1, 1)
63
  fn main(@builtin(workgroup_id) wg: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {
64
  let row = wg.x + wg.y * params.rowStride;
@@ -68,12 +66,16 @@ fn main(@builtin(workgroup_id) wg: vec3<u32>, @builtin(local_invocation_id) lid:
68
  let k = wg.z;
69
  let tid = lid.x;
70
 
71
- var total = 0.0;
72
- for (var i = 0u; i < SPLIT; i = i + 1u) {
73
- total = total + partials[row * SPLIT + i];
 
 
 
74
  }
75
- let inv = inverseSqrt(total / f32(HIDDEN) + EPSILON);
76
- let chunk = (HIDDEN + SPLIT - 1u) / SPLIT;
 
77
  let start = k * chunk;
78
  var end = start + chunk;
79
  if (end > HIDDEN) { end = HIDDEN; }
@@ -86,7 +88,7 @@ fn main(@builtin(workgroup_id) wg: vec3<u32>, @builtin(local_invocation_id) lid:
86
  // Preserve the ONNX stage boundary: round Normalized to X's dtype before
87
  // the affine scale is applied.
88
  let normalized = {{ xElement }}(f32(x[index]) * inv);
89
- let value = f32(normalized) * f32(scale[scale_offset({% if source.scaleRank > 0 %}index{% endif %})]);
90
  y[index] = {{ scalar }}(value);
91
  d = d + WG;
92
  }
 
1
+ // Split-K normalize pass. One lane folds the per-row partials in their original
2
+ // order and shares the inverse RMS with its workgroup. Output tiles can outnumber
3
+ // the reduction splits: their independent work does not need additional scratch.
4
+ // Scale offsets follow the suffix-axis broadcast contract.
 
 
 
 
5
  {{ env.wgsl.resourceDeclarations }}
6
 
7
  const HIDDEN: u32 = {{ hiddenSize }}u;
 
9
  const WG: u32 = {{ workgroupSize }}u;
10
  const SPLIT: u32 = {{ split }}u;
11
 
12
+ {% if scaleRank > 0 %}
13
+ const X_RANK: u32 = {{ xRank }}u;
14
+ const SCALE_RANK: u32 = {{ scaleRank }}u;
15
+ const X_SHAPE: array<u32, {{ xRank }}> = array<u32, {{ xRank }}>({% for d in xShape %}{{ d }}u{% if not loop.last %}, {% endif %}{% endfor %});
16
+ const SCALE_SHAPE: array<u32, {{ scaleRank }}> = array<u32, {{ scaleRank }}>({% for d in scaleShape %}{{ d }}u{% if not loop.last %}, {% endif %}{% endfor %});
17
 
18
  fn x_stride(axis: u32) -> u32 {
19
  var stride = 1u;
 
32
  }
33
 
34
  {% endif %}
35
+ fn scale_offset({% if scaleRank > 0 %}out_index: u32{% endif %}) -> u32 {
36
+ {% if scaleRank == 0 %}
37
  return 0u;
38
  {% else %}
39
  var rem = out_index;
 
55
  }
56
 
57
 
58
+ var<workgroup> shared_inv: f32;
59
+
60
  @compute @workgroup_size(WG, 1, 1)
61
  fn main(@builtin(workgroup_id) wg: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {
62
  let row = wg.x + wg.y * params.rowStride;
 
66
  let k = wg.z;
67
  let tid = lid.x;
68
 
69
+ if (tid == 0u) {
70
+ var total = 0.0;
71
+ for (var i = 0u; i < SPLIT; i = i + 1u) {
72
+ total = total + partials[row * SPLIT + i];
73
+ }
74
+ shared_inv = inverseSqrt(total / f32(HIDDEN) + EPSILON);
75
  }
76
+ workgroupBarrier();
77
+ let inv = shared_inv;
78
+ let chunk = {{ normalizeChunk }}u;
79
  let start = k * chunk;
80
  var end = start + chunk;
81
  if (end > HIDDEN) { end = HIDDEN; }
 
88
  // Preserve the ONNX stage boundary: round Normalized to X's dtype before
89
  // the affine scale is applied.
90
  let normalized = {{ xElement }}(f32(x[index]) * inv);
91
+ let value = f32(normalized) * f32(scale[scale_offset({% if scaleRank > 0 %}index{% endif %})]);
92
  y[index] = {{ scalar }}(value);
93
  d = d + WG;
94
  }
build/webgpu/rms-normalization-splitk-partials.wgsl.jinja CHANGED
@@ -51,9 +51,6 @@
51
  sum-of-squares over its HIDDEN/SPLIT slice and writes one partial to scratch.
52
  The normalize pass folds the SPLIT partials per row. Split-K reassociates the
53
  f32 sum, so this route is not bit-identical to the unsplit reduction. */
54
- {% if usesF16 %}
55
- enable f16;
56
- {% endif %}
57
  {{ env.wgsl.resourceDeclarations }}
58
 
59
  const HIDDEN: u32 = {{ hiddenSize }}u;
 
51
  sum-of-squares over its HIDDEN/SPLIT slice and writes one partial to scratch.
52
  The normalize pass folds the SPLIT partials per row. Split-K reassociates the
53
  f32 sum, so this route is not bit-identical to the unsplit reduction. */
 
 
 
54
  {{ env.wgsl.resourceDeclarations }}
55
 
56
  const HIDDEN: u32 = {{ hiddenSize }}u;
build/webgpu/rms-normalization-stash-f16-serial.wgsl.jinja CHANGED
@@ -59,11 +59,11 @@ fn widen_f16_bits(value: u32) -> f32 {
59
  }
60
 
61
 
62
- {% if source.scaleRank > 0 %}
63
- const X_RANK: u32 = {{ source.xRank }}u;
64
- const SCALE_RANK: u32 = {{ source.scaleRank }}u;
65
- const X_SHAPE: array<u32, {{ source.xRank }}> = array<u32, {{ source.xRank }}>({% for d in source.xShape %}{{ d }}u{% if not loop.last %}, {% endif %}{% endfor %});
66
- const SCALE_SHAPE: array<u32, {{ source.scaleRank }}> = array<u32, {{ source.scaleRank }}>({% for d in source.scaleShape %}{{ d }}u{% if not loop.last %}, {% endif %}{% endfor %});
67
 
68
  fn x_stride(axis: u32) -> u32 {
69
  var stride = 1u;
@@ -82,8 +82,8 @@ fn scale_stride(axis: u32) -> u32 {
82
  }
83
 
84
  {% endif %}
85
- fn scale_offset({% if source.scaleRank > 0 %}out_index: u32{% endif %}) -> u32 {
86
- {% if source.scaleRank == 0 %}
87
  return 0u;
88
  {% else %}
89
  var rem = out_index;
@@ -134,7 +134,7 @@ fn main(@builtin(workgroup_id) wg: vec3<u32>) {
134
  let value_f16 = round_f16_bits_rte(f32(x[index]));
135
  let normalized = round_f16_bits_rte(widen_f16_bits(value_f16) / widen_f16_bits(rms));
136
  let value = widen_f16_bits(normalized)
137
- * f32(scale[scale_offset({% if source.scaleRank > 0 %}index{% endif %})]);
138
  y[index] = {{ scalar }}(value);
139
  }
140
  }
 
59
  }
60
 
61
 
62
+ {% if scaleRank > 0 %}
63
+ const X_RANK: u32 = {{ xRank }}u;
64
+ const SCALE_RANK: u32 = {{ scaleRank }}u;
65
+ const X_SHAPE: array<u32, {{ xRank }}> = array<u32, {{ xRank }}>({% for d in xShape %}{{ d }}u{% if not loop.last %}, {% endif %}{% endfor %});
66
+ const SCALE_SHAPE: array<u32, {{ scaleRank }}> = array<u32, {{ scaleRank }}>({% for d in scaleShape %}{{ d }}u{% if not loop.last %}, {% endif %}{% endfor %});
67
 
68
  fn x_stride(axis: u32) -> u32 {
69
  var stride = 1u;
 
82
  }
83
 
84
  {% endif %}
85
+ fn scale_offset({% if scaleRank > 0 %}out_index: u32{% endif %}) -> u32 {
86
+ {% if scaleRank == 0 %}
87
  return 0u;
88
  {% else %}
89
  var rem = out_index;
 
134
  let value_f16 = round_f16_bits_rte(f32(x[index]));
135
  let normalized = round_f16_bits_rte(widen_f16_bits(value_f16) / widen_f16_bits(rms));
136
  let value = widen_f16_bits(normalized)
137
+ * f32(scale[scale_offset({% if scaleRank > 0 %}index{% endif %})]);
138
  y[index] = {{ scalar }}(value);
139
  }
140
  }
build/webgpu/rms-normalization.wgsl.jinja CHANGED
@@ -1,6 +1,3 @@
1
- {% if usesF16 %}
2
- enable f16;
3
- {% endif %}
4
  {{ env.wgsl.resourceDeclarations }}
5
 
6
  const HIDDEN: u32 = {{ hiddenSize }}u;
@@ -9,11 +6,11 @@ const WG: u32 = {{ workgroupSize }}u;
9
 
10
  var<workgroup> partial: array<f32, WG>;
11
 
12
- {% if source.scaleRank > 0 %}
13
- const X_RANK: u32 = {{ source.xRank }}u;
14
- const SCALE_RANK: u32 = {{ source.scaleRank }}u;
15
- const X_SHAPE: array<u32, {{ source.xRank }}> = array<u32, {{ source.xRank }}>({% for d in source.xShape %}{{ d }}u{% if not loop.last %}, {% endif %}{% endfor %});
16
- const SCALE_SHAPE: array<u32, {{ source.scaleRank }}> = array<u32, {{ source.scaleRank }}>({% for d in source.scaleShape %}{{ d }}u{% if not loop.last %}, {% endif %}{% endfor %});
17
 
18
  fn x_stride(axis: u32) -> u32 {
19
  var stride = 1u;
@@ -32,8 +29,8 @@ fn scale_stride(axis: u32) -> u32 {
32
  }
33
 
34
  {% endif %}
35
- fn scale_offset({% if source.scaleRank > 0 %}out_index: u32{% endif %}) -> u32 {
36
- {% if source.scaleRank == 0 %}
37
  return 0u;
38
  {% else %}
39
  var rem = out_index;
@@ -138,7 +135,7 @@ fn main(@builtin(workgroup_id) wg: vec3<u32>, @builtin(local_invocation_id) lid:
138
  // ONNX stage one ends by casting Normalized back to X's dtype; Scale is
139
  // applied only after that rounding point.
140
  let normalized = {{ xElement }}(f32(x[index]) * inv);
141
- let value = f32(normalized) * f32(scale[scale_offset({% if source.scaleRank > 0 %}index{% endif %})]);
142
  y[base + d] = {{ scalar }}(value);
143
  }
144
  }
 
 
 
 
1
  {{ env.wgsl.resourceDeclarations }}
2
 
3
  const HIDDEN: u32 = {{ hiddenSize }}u;
 
6
 
7
  var<workgroup> partial: array<f32, WG>;
8
 
9
+ {% if scaleRank > 0 %}
10
+ const X_RANK: u32 = {{ xRank }}u;
11
+ const SCALE_RANK: u32 = {{ scaleRank }}u;
12
+ const X_SHAPE: array<u32, {{ xRank }}> = array<u32, {{ xRank }}>({% for d in xShape %}{{ d }}u{% if not loop.last %}, {% endif %}{% endfor %});
13
+ const SCALE_SHAPE: array<u32, {{ scaleRank }}> = array<u32, {{ scaleRank }}>({% for d in scaleShape %}{{ d }}u{% if not loop.last %}, {% endif %}{% endfor %});
14
 
15
  fn x_stride(axis: u32) -> u32 {
16
  var stride = 1u;
 
29
  }
30
 
31
  {% endif %}
32
+ fn scale_offset({% if scaleRank > 0 %}out_index: u32{% endif %}) -> u32 {
33
+ {% if scaleRank == 0 %}
34
  return 0u;
35
  {% else %}
36
  var rem = out_index;
 
135
  // ONNX stage one ends by casting Normalized back to X's dtype; Scale is
136
  // applied only after that rounding point.
137
  let normalized = {{ xElement }}(f32(x[index]) * inv);
138
+ let value = f32(normalized) * f32(scale[scale_offset({% if scaleRank > 0 %}index{% endif %})]);
139
  y[base + d] = {{ scalar }}(value);
140
  }
141
  }
build/webgpu/test.json CHANGED
@@ -1,5 +1,4 @@
1
  {
2
- "op": "ai.onnx.RMSNormalization",
3
  "fixtureArrays": {
4
  "f16_scalar_cast_x": [-1.1103515625, 2.982421875, 1.248046875, -1.8544921875],
5
  "f16_scalar_cast_scale": [2.015625],
@@ -46,7 +45,7 @@
46
  "provenance": {
47
  "source": "onnx/defs/nn/defs.cc",
48
  "test": "RMSNormalization-23 schema",
49
- "notes": "Pins the default-epsilon path: no epsilon attribute is passed, so manifest and oracle defaults must both match the ONNX schema default 1e-5. Small-magnitude rows make epsilon dominate the mean-square, so a wrong default (e.g. 1e-6) diverges by >2x."
50
  }
51
  },
52
  {
@@ -153,7 +152,7 @@
153
  "provenance": {
154
  "source": "onnxruntime/test/providers/cpu/nn/rms_norm_op_test.cc",
155
  "test": "RMSNormalizationOpTest.RMSNorm_Scale",
156
- "notes": "Odd hidden-size companion for valid subnormal scale outputs."
157
  },
158
  "attrs": { "epsilon": 0, "axis": -1 },
159
  "inputs": {
@@ -1372,7 +1371,7 @@
1372
  {
1373
  "name": "f16_lastaxis_unaligned_hidden4094",
1374
  "provenance": {
1375
- "notes": "Compact correctness sibling for the f16 unaligned-hidden benchmark cliff; dim=4094 exercises the scalar tail path next to the vec4/subgroup path."
1376
  },
1377
  "attrs": { "epsilon": 0.000001, "axis": -1 },
1378
  "inputs": {
@@ -1585,6 +1584,553 @@
1585
  }
1586
  },
1587
  "outputs": { "y": { "dtype": "float32", "shape": [2, 8], "tolerance": 0.000002 } }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1588
  }
1589
  ]
1590
  }
 
1
  {
 
2
  "fixtureArrays": {
3
  "f16_scalar_cast_x": [-1.1103515625, 2.982421875, 1.248046875, -1.8544921875],
4
  "f16_scalar_cast_scale": [2.015625],
 
45
  "provenance": {
46
  "source": "onnx/defs/nn/defs.cc",
47
  "test": "RMSNormalization-23 schema",
48
+ "notes": "With no epsilon attribute, the ONNX default 1e-5 applies. Small-magnitude rows make epsilon dominate the mean square, so using a different default changes the normalized values substantially."
49
  }
50
  },
51
  {
 
152
  "provenance": {
153
  "source": "onnxruntime/test/providers/cpu/nn/rms_norm_op_test.cc",
154
  "test": "RMSNormalizationOpTest.RMSNorm_Scale",
155
+ "notes": "An odd hidden size exercises scalar-tail normalization with valid subnormal scale outputs."
156
  },
157
  "attrs": { "epsilon": 0, "axis": -1 },
158
  "inputs": {
 
1371
  {
1372
  "name": "f16_lastaxis_unaligned_hidden4094",
1373
  "provenance": {
1374
+ "notes": "A float16 hidden dimension of 4,094 exercises scalar-tail handling after vectorized normalization."
1375
  },
1376
  "attrs": { "epsilon": 0.000001, "axis": -1 },
1377
  "inputs": {
 
1584
  }
1585
  },
1586
  "outputs": { "y": { "dtype": "float32", "shape": [2, 8], "tolerance": 0.000002 } }
1587
+ },
1588
+ {
1589
+ "name": "split_f32-1x16384",
1590
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
1591
+ "tunables": {},
1592
+ "inputs": {
1593
+ "x": {
1594
+ "dtype": "float32",
1595
+ "shape": [1, 16384],
1596
+ "data": { "kind": "fillFloat32", "sinStep": 0.017, "cosStep": 0.023, "scale": 0.5, "offset": 0.0 }
1597
+ },
1598
+ "scale": {
1599
+ "dtype": "float32",
1600
+ "shape": [],
1601
+ "data": { "kind": "fillFloat32", "sinStep": 0.031, "cosStep": 0.009, "scale": 0.25, "offset": 1.0 }
1602
+ }
1603
+ },
1604
+ "outputs": { "y": { "shape": [1, 16384], "dtype": "float32", "tolerance": 0.00001 } }
1605
+ },
1606
+ {
1607
+ "name": "split_f32-1x16385",
1608
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
1609
+ "tunables": {},
1610
+ "inputs": {
1611
+ "x": {
1612
+ "dtype": "float32",
1613
+ "shape": [1, 16385],
1614
+ "data": { "kind": "fillFloat32", "sinStep": 0.017, "cosStep": 0.023, "scale": 0.5, "offset": 0.0 }
1615
+ },
1616
+ "scale": {
1617
+ "dtype": "float32",
1618
+ "shape": [],
1619
+ "data": { "kind": "fillFloat32", "sinStep": 0.031, "cosStep": 0.009, "scale": 0.25, "offset": 1.0 }
1620
+ }
1621
+ },
1622
+ "outputs": { "y": { "shape": [1, 16385], "dtype": "float32", "tolerance": 0.00001 } }
1623
+ },
1624
+ {
1625
+ "name": "split_f32-1x32769",
1626
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
1627
+ "tunables": {},
1628
+ "inputs": {
1629
+ "x": {
1630
+ "dtype": "float32",
1631
+ "shape": [1, 32769],
1632
+ "data": { "kind": "fillFloat32", "sinStep": 0.017, "cosStep": 0.023, "scale": 0.5, "offset": 0.0 }
1633
+ },
1634
+ "scale": {
1635
+ "dtype": "float32",
1636
+ "shape": [],
1637
+ "data": { "kind": "fillFloat32", "sinStep": 0.031, "cosStep": 0.009, "scale": 0.25, "offset": 1.0 }
1638
+ }
1639
+ },
1640
+ "outputs": { "y": { "shape": [1, 32769], "dtype": "float32", "tolerance": 0.00001 } }
1641
+ },
1642
+ {
1643
+ "name": "split_f32-1x65536",
1644
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
1645
+ "tunables": {},
1646
+ "inputs": {
1647
+ "x": {
1648
+ "dtype": "float32",
1649
+ "shape": [1, 65536],
1650
+ "data": { "kind": "fillFloat32", "sinStep": 0.017, "cosStep": 0.023, "scale": 0.5, "offset": 0.0 }
1651
+ },
1652
+ "scale": {
1653
+ "dtype": "float32",
1654
+ "shape": [],
1655
+ "data": { "kind": "fillFloat32", "sinStep": 0.031, "cosStep": 0.009, "scale": 0.25, "offset": 1.0 }
1656
+ }
1657
+ },
1658
+ "outputs": { "y": { "shape": [1, 65536], "dtype": "float32", "tolerance": 0.00001 } }
1659
+ },
1660
+ {
1661
+ "name": "split_f32-1x131072",
1662
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
1663
+ "tunables": {},
1664
+ "inputs": {
1665
+ "x": {
1666
+ "dtype": "float32",
1667
+ "shape": [1, 131072],
1668
+ "data": { "kind": "fillFloat32", "sinStep": 0.017, "cosStep": 0.023, "scale": 0.5, "offset": 0.0 }
1669
+ },
1670
+ "scale": {
1671
+ "dtype": "float32",
1672
+ "shape": [],
1673
+ "data": { "kind": "fillFloat32", "sinStep": 0.031, "cosStep": 0.009, "scale": 0.25, "offset": 1.0 }
1674
+ }
1675
+ },
1676
+ "outputs": { "y": { "shape": [1, 131072], "dtype": "float32", "tolerance": 0.00001 } }
1677
+ },
1678
+ {
1679
+ "name": "split_f32-1x262144",
1680
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
1681
+ "tunables": {},
1682
+ "inputs": {
1683
+ "x": {
1684
+ "dtype": "float32",
1685
+ "shape": [1, 262144],
1686
+ "data": { "kind": "fillFloat32", "sinStep": 0.017, "cosStep": 0.023, "scale": 0.5, "offset": 0.0 }
1687
+ },
1688
+ "scale": {
1689
+ "dtype": "float32",
1690
+ "shape": [],
1691
+ "data": { "kind": "fillFloat32", "sinStep": 0.031, "cosStep": 0.009, "scale": 0.25, "offset": 1.0 }
1692
+ }
1693
+ },
1694
+ "outputs": { "y": { "shape": [1, 262144], "dtype": "float32", "tolerance": 0.00001 } }
1695
+ },
1696
+ {
1697
+ "name": "split_f32-1x524288",
1698
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
1699
+ "tunables": {},
1700
+ "inputs": {
1701
+ "x": {
1702
+ "dtype": "float32",
1703
+ "shape": [1, 524288],
1704
+ "data": { "kind": "fillFloat32", "sinStep": 0.017, "cosStep": 0.023, "scale": 0.5, "offset": 0.0 }
1705
+ },
1706
+ "scale": {
1707
+ "dtype": "float32",
1708
+ "shape": [],
1709
+ "data": { "kind": "fillFloat32", "sinStep": 0.031, "cosStep": 0.009, "scale": 0.25, "offset": 1.0 }
1710
+ }
1711
+ },
1712
+ "outputs": { "y": { "shape": [1, 524288], "dtype": "float32", "tolerance": 0.00001 } }
1713
+ },
1714
+ {
1715
+ "name": "split_f32-1x1048576",
1716
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
1717
+ "tunables": {},
1718
+ "inputs": {
1719
+ "x": {
1720
+ "dtype": "float32",
1721
+ "shape": [1, 1048576],
1722
+ "data": { "kind": "fillFloat32", "sinStep": 0.017, "cosStep": 0.023, "scale": 0.5, "offset": 0.0 }
1723
+ },
1724
+ "scale": {
1725
+ "dtype": "float32",
1726
+ "shape": [],
1727
+ "data": { "kind": "fillFloat32", "sinStep": 0.031, "cosStep": 0.009, "scale": 0.25, "offset": 1.0 }
1728
+ }
1729
+ },
1730
+ "outputs": { "y": { "shape": [1, 1048576], "dtype": "float32", "tolerance": 0.00001 } }
1731
+ },
1732
+ {
1733
+ "name": "split_f32-1x2097152",
1734
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
1735
+ "tunables": {},
1736
+ "inputs": {
1737
+ "x": {
1738
+ "dtype": "float32",
1739
+ "shape": [1, 2097152],
1740
+ "data": { "kind": "fillFloat32", "sinStep": 0.017, "cosStep": 0.023, "scale": 0.5, "offset": 0.0 }
1741
+ },
1742
+ "scale": {
1743
+ "dtype": "float32",
1744
+ "shape": [],
1745
+ "data": { "kind": "fillFloat32", "sinStep": 0.031, "cosStep": 0.009, "scale": 0.25, "offset": 1.0 }
1746
+ }
1747
+ },
1748
+ "outputs": { "y": { "shape": [1, 2097152], "dtype": "float32", "tolerance": 0.00001 } }
1749
+ },
1750
+ {
1751
+ "name": "split_f32-2x131073",
1752
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
1753
+ "tunables": {},
1754
+ "inputs": {
1755
+ "x": {
1756
+ "dtype": "float32",
1757
+ "shape": [2, 131073],
1758
+ "data": { "kind": "fillFloat32", "sinStep": 0.017, "cosStep": 0.023, "scale": 0.5, "offset": 0.0 }
1759
+ },
1760
+ "scale": {
1761
+ "dtype": "float32",
1762
+ "shape": [],
1763
+ "data": { "kind": "fillFloat32", "sinStep": 0.031, "cosStep": 0.009, "scale": 0.25, "offset": 1.0 }
1764
+ }
1765
+ },
1766
+ "outputs": { "y": { "shape": [2, 131073], "dtype": "float32", "tolerance": 0.00001 } }
1767
+ },
1768
+ {
1769
+ "name": "split_f32-3x524289",
1770
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
1771
+ "tunables": {},
1772
+ "inputs": {
1773
+ "x": {
1774
+ "dtype": "float32",
1775
+ "shape": [3, 524289],
1776
+ "data": { "kind": "fillFloat32", "sinStep": 0.017, "cosStep": 0.023, "scale": 0.5, "offset": 0.0 }
1777
+ },
1778
+ "scale": {
1779
+ "dtype": "float32",
1780
+ "shape": [],
1781
+ "data": { "kind": "fillFloat32", "sinStep": 0.031, "cosStep": 0.009, "scale": 0.25, "offset": 1.0 }
1782
+ }
1783
+ },
1784
+ "outputs": { "y": { "shape": [3, 524289], "dtype": "float32", "tolerance": 0.00001 } }
1785
+ },
1786
+ {
1787
+ "name": "split_f32-4x1048576",
1788
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
1789
+ "tunables": {},
1790
+ "inputs": {
1791
+ "x": {
1792
+ "dtype": "float32",
1793
+ "shape": [4, 1048576],
1794
+ "data": { "kind": "fillFloat32", "sinStep": 0.017, "cosStep": 0.023, "scale": 0.5, "offset": 0.0 }
1795
+ },
1796
+ "scale": {
1797
+ "dtype": "float32",
1798
+ "shape": [],
1799
+ "data": { "kind": "fillFloat32", "sinStep": 0.031, "cosStep": 0.009, "scale": 0.25, "offset": 1.0 }
1800
+ }
1801
+ },
1802
+ "outputs": { "y": { "shape": [4, 1048576], "dtype": "float32", "tolerance": 0.00001 } }
1803
+ },
1804
+ {
1805
+ "name": "split_f32-8x16384",
1806
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
1807
+ "tunables": {},
1808
+ "inputs": {
1809
+ "x": {
1810
+ "dtype": "float32",
1811
+ "shape": [8, 16384],
1812
+ "data": { "kind": "fillFloat32", "sinStep": 0.017, "cosStep": 0.023, "scale": 0.5, "offset": 0.0 }
1813
+ },
1814
+ "scale": {
1815
+ "dtype": "float32",
1816
+ "shape": [],
1817
+ "data": { "kind": "fillFloat32", "sinStep": 0.031, "cosStep": 0.009, "scale": 0.25, "offset": 1.0 }
1818
+ }
1819
+ },
1820
+ "outputs": { "y": { "shape": [8, 16384], "dtype": "float32", "tolerance": 0.00001 } }
1821
+ },
1822
+ {
1823
+ "name": "split_f32-16x65536",
1824
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
1825
+ "tunables": {},
1826
+ "inputs": {
1827
+ "x": {
1828
+ "dtype": "float32",
1829
+ "shape": [16, 65536],
1830
+ "data": { "kind": "fillFloat32", "sinStep": 0.017, "cosStep": 0.023, "scale": 0.5, "offset": 0.0 }
1831
+ },
1832
+ "scale": {
1833
+ "dtype": "float32",
1834
+ "shape": [],
1835
+ "data": { "kind": "fillFloat32", "sinStep": 0.031, "cosStep": 0.009, "scale": 0.25, "offset": 1.0 }
1836
+ }
1837
+ },
1838
+ "outputs": { "y": { "shape": [16, 65536], "dtype": "float32", "tolerance": 0.00001 } }
1839
+ },
1840
+ {
1841
+ "name": "split_f32-32x32769",
1842
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
1843
+ "tunables": {},
1844
+ "inputs": {
1845
+ "x": {
1846
+ "dtype": "float32",
1847
+ "shape": [32, 32769],
1848
+ "data": { "kind": "fillFloat32", "sinStep": 0.017, "cosStep": 0.023, "scale": 0.5, "offset": 0.0 }
1849
+ },
1850
+ "scale": {
1851
+ "dtype": "float32",
1852
+ "shape": [],
1853
+ "data": { "kind": "fillFloat32", "sinStep": 0.031, "cosStep": 0.009, "scale": 0.25, "offset": 1.0 }
1854
+ }
1855
+ },
1856
+ "outputs": { "y": { "shape": [32, 32769], "dtype": "float32", "tolerance": 0.00001 } }
1857
+ },
1858
+ {
1859
+ "name": "split_f32-128x16384",
1860
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
1861
+ "tunables": {},
1862
+ "inputs": {
1863
+ "x": {
1864
+ "dtype": "float32",
1865
+ "shape": [128, 16384],
1866
+ "data": { "kind": "fillFloat32", "sinStep": 0.017, "cosStep": 0.023, "scale": 0.5, "offset": 0.0 }
1867
+ },
1868
+ "scale": {
1869
+ "dtype": "float32",
1870
+ "shape": [],
1871
+ "data": { "kind": "fillFloat32", "sinStep": 0.031, "cosStep": 0.009, "scale": 0.25, "offset": 1.0 }
1872
+ }
1873
+ },
1874
+ "outputs": { "y": { "shape": [128, 16384], "dtype": "float32", "tolerance": 0.00001 } }
1875
+ },
1876
+ {
1877
+ "name": "split_f16-1x16385",
1878
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
1879
+ "tunables": {},
1880
+ "inputs": {
1881
+ "x": {
1882
+ "dtype": "float16",
1883
+ "shape": [1, 16385],
1884
+ "data": { "kind": "cycle", "values": [-0.75, -0.5, -0.25, 0.0, 0.25, 0.5, 0.75, 1.0] }
1885
+ },
1886
+ "scale": {
1887
+ "dtype": "float16",
1888
+ "shape": [],
1889
+ "data": { "kind": "fillFloat32", "sinStep": 0.031, "cosStep": 0.009, "scale": 0.25, "offset": 1.0 }
1890
+ }
1891
+ },
1892
+ "outputs": { "y": { "shape": [1, 16385], "dtype": "float16", "tolerance": 0.01 } }
1893
+ },
1894
+ {
1895
+ "name": "split_f16-1x131072",
1896
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
1897
+ "tunables": {},
1898
+ "inputs": {
1899
+ "x": {
1900
+ "dtype": "float16",
1901
+ "shape": [1, 131072],
1902
+ "data": { "kind": "cycle", "values": [-0.75, -0.5, -0.25, 0.0, 0.25, 0.5, 0.75, 1.0] }
1903
+ },
1904
+ "scale": {
1905
+ "dtype": "float16",
1906
+ "shape": [],
1907
+ "data": { "kind": "fillFloat32", "sinStep": 0.031, "cosStep": 0.009, "scale": 0.25, "offset": 1.0 }
1908
+ }
1909
+ },
1910
+ "outputs": { "y": { "shape": [1, 131072], "dtype": "float16", "tolerance": 0.01 } }
1911
+ },
1912
+ {
1913
+ "name": "split_f16-1x524288",
1914
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
1915
+ "tunables": {},
1916
+ "inputs": {
1917
+ "x": {
1918
+ "dtype": "float16",
1919
+ "shape": [1, 524288],
1920
+ "data": { "kind": "cycle", "values": [-0.75, -0.5, -0.25, 0.0, 0.25, 0.5, 0.75, 1.0] }
1921
+ },
1922
+ "scale": {
1923
+ "dtype": "float16",
1924
+ "shape": [],
1925
+ "data": { "kind": "fillFloat32", "sinStep": 0.031, "cosStep": 0.009, "scale": 0.25, "offset": 1.0 }
1926
+ }
1927
+ },
1928
+ "outputs": { "y": { "shape": [1, 524288], "dtype": "float16", "tolerance": 0.01 } }
1929
+ },
1930
+ {
1931
+ "name": "split_f16-1x2097152",
1932
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
1933
+ "tunables": {},
1934
+ "inputs": {
1935
+ "x": {
1936
+ "dtype": "float16",
1937
+ "shape": [1, 2097152],
1938
+ "data": { "kind": "cycle", "values": [-0.75, -0.5, -0.25, 0.0, 0.25, 0.5, 0.75, 1.0] }
1939
+ },
1940
+ "scale": {
1941
+ "dtype": "float16",
1942
+ "shape": [],
1943
+ "data": { "kind": "fillFloat32", "sinStep": 0.031, "cosStep": 0.009, "scale": 0.25, "offset": 1.0 }
1944
+ }
1945
+ },
1946
+ "outputs": { "y": { "shape": [1, 2097152], "dtype": "float16", "tolerance": 0.01 } }
1947
+ },
1948
+ {
1949
+ "name": "split_f16-3x524289",
1950
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
1951
+ "tunables": {},
1952
+ "inputs": {
1953
+ "x": {
1954
+ "dtype": "float16",
1955
+ "shape": [3, 524289],
1956
+ "data": { "kind": "cycle", "values": [-0.75, -0.5, -0.25, 0.0, 0.25, 0.5, 0.75, 1.0] }
1957
+ },
1958
+ "scale": {
1959
+ "dtype": "float16",
1960
+ "shape": [],
1961
+ "data": { "kind": "fillFloat32", "sinStep": 0.031, "cosStep": 0.009, "scale": 0.25, "offset": 1.0 }
1962
+ }
1963
+ },
1964
+ "outputs": { "y": { "shape": [3, 524289], "dtype": "float16", "tolerance": 0.01 } }
1965
+ },
1966
+ {
1967
+ "name": "split_f16-16x65536",
1968
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
1969
+ "tunables": {},
1970
+ "inputs": {
1971
+ "x": {
1972
+ "dtype": "float16",
1973
+ "shape": [16, 65536],
1974
+ "data": { "kind": "cycle", "values": [-0.75, -0.5, -0.25, 0.0, 0.25, 0.5, 0.75, 1.0] }
1975
+ },
1976
+ "scale": {
1977
+ "dtype": "float16",
1978
+ "shape": [],
1979
+ "data": { "kind": "fillFloat32", "sinStep": 0.031, "cosStep": 0.009, "scale": 0.25, "offset": 1.0 }
1980
+ }
1981
+ },
1982
+ "outputs": { "y": { "shape": [16, 65536], "dtype": "float16", "tolerance": 0.01 } }
1983
+ },
1984
+ {
1985
+ "name": "split_f32-f16-2x32769",
1986
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
1987
+ "tunables": {},
1988
+ "inputs": {
1989
+ "x": {
1990
+ "dtype": "float32",
1991
+ "shape": [2, 32769],
1992
+ "data": { "kind": "fillFloat32", "sinStep": 0.017, "cosStep": 0.023, "scale": 0.5, "offset": 0.0 }
1993
+ },
1994
+ "scale": {
1995
+ "dtype": "float16",
1996
+ "shape": [],
1997
+ "data": { "kind": "fillFloat32", "sinStep": 0.031, "cosStep": 0.009, "scale": 0.25, "offset": 1.0 }
1998
+ }
1999
+ },
2000
+ "outputs": { "y": { "shape": [2, 32769], "dtype": "float16", "tolerance": 0.01 } }
2001
+ },
2002
+ {
2003
+ "name": "split_f16-f32-2x32769",
2004
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
2005
+ "tunables": {},
2006
+ "inputs": {
2007
+ "x": {
2008
+ "dtype": "float16",
2009
+ "shape": [2, 32769],
2010
+ "data": { "kind": "cycle", "values": [-0.75, -0.5, -0.25, 0.0, 0.25, 0.5, 0.75, 1.0] }
2011
+ },
2012
+ "scale": {
2013
+ "dtype": "float32",
2014
+ "shape": [],
2015
+ "data": { "kind": "fillFloat32", "sinStep": 0.031, "cosStep": 0.009, "scale": 0.25, "offset": 1.0 }
2016
+ }
2017
+ },
2018
+ "outputs": { "y": { "shape": [2, 32769], "dtype": "float32", "tolerance": 0.00001 } }
2019
+ },
2020
+ {
2021
+ "name": "split_f32-1x16384-split1",
2022
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
2023
+ "tunables": { "MAX_SPLITS": 1 },
2024
+ "inputs": {
2025
+ "x": {
2026
+ "dtype": "float32",
2027
+ "shape": [1, 16384],
2028
+ "data": { "kind": "fillFloat32", "sinStep": 0.017, "cosStep": 0.023, "scale": 0.5, "offset": 0.0 }
2029
+ },
2030
+ "scale": {
2031
+ "dtype": "float32",
2032
+ "shape": [],
2033
+ "data": { "kind": "fillFloat32", "sinStep": 0.031, "cosStep": 0.009, "scale": 0.25, "offset": 1.0 }
2034
+ }
2035
+ },
2036
+ "outputs": { "y": { "shape": [1, 16384], "dtype": "float32", "tolerance": 0.00001 } }
2037
+ },
2038
+ {
2039
+ "name": "split_f32-1x16385-split3",
2040
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
2041
+ "tunables": { "MAX_SPLITS": 3 },
2042
+ "inputs": {
2043
+ "x": {
2044
+ "dtype": "float32",
2045
+ "shape": [1, 16385],
2046
+ "data": { "kind": "fillFloat32", "sinStep": 0.017, "cosStep": 0.023, "scale": 0.5, "offset": 0.0 }
2047
+ },
2048
+ "scale": {
2049
+ "dtype": "float32",
2050
+ "shape": [],
2051
+ "data": { "kind": "fillFloat32", "sinStep": 0.031, "cosStep": 0.009, "scale": 0.25, "offset": 1.0 }
2052
+ }
2053
+ },
2054
+ "outputs": { "y": { "shape": [1, 16385], "dtype": "float32", "tolerance": 0.00001 } }
2055
+ },
2056
+ {
2057
+ "name": "split_f32-2x262145-wg64",
2058
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
2059
+ "tunables": { "WORKGROUP_SIZE": 64 },
2060
+ "inputs": {
2061
+ "x": {
2062
+ "dtype": "float32",
2063
+ "shape": [2, 262145],
2064
+ "data": { "kind": "fillFloat32", "sinStep": 0.017, "cosStep": 0.023, "scale": 0.5, "offset": 0.0 }
2065
+ },
2066
+ "scale": {
2067
+ "dtype": "float32",
2068
+ "shape": [],
2069
+ "data": { "kind": "fillFloat32", "sinStep": 0.031, "cosStep": 0.009, "scale": 0.25, "offset": 1.0 }
2070
+ }
2071
+ },
2072
+ "outputs": { "y": { "shape": [2, 262145], "dtype": "float32", "tolerance": 0.00001 } }
2073
+ },
2074
+ {
2075
+ "name": "split_f32-2x262145-wg128",
2076
+ "attrs": { "axis": -1, "epsilon": 0.000001 },
2077
+ "tunables": { "WORKGROUP_SIZE": 128 },
2078
+ "inputs": {
2079
+ "x": {
2080
+ "dtype": "float32",
2081
+ "shape": [2, 262145],
2082
+ "data": { "kind": "fillFloat32", "sinStep": 0.017, "cosStep": 0.023, "scale": 0.5, "offset": 0.0 }
2083
+ },
2084
+ "scale": {
2085
+ "dtype": "float32",
2086
+ "shape": [],
2087
+ "data": { "kind": "fillFloat32", "sinStep": 0.031, "cosStep": 0.009, "scale": 0.25, "offset": 1.0 }
2088
+ }
2089
+ },
2090
+ "outputs": { "y": { "shape": [2, 262145], "dtype": "float32", "tolerance": 0.00001 } }
2091
+ },
2092
+ {
2093
+ "name": "split_f32_suffix_broadcast_tail",
2094
+ "attrs": { "axis": 1, "epsilon": 0.000001 },
2095
+ "inputs": {
2096
+ "x": {
2097
+ "dtype": "float32",
2098
+ "shape": [3, 17, 4097],
2099
+ "data": { "kind": "cycle", "values": [-0.75, -0.5, -0.25, 0.0, 0.25, 0.5, 0.75, 1.0] }
2100
+ },
2101
+ "scale": {
2102
+ "dtype": "float32",
2103
+ "shape": [1, 17, 1],
2104
+ "data": { "kind": "fillFloat32", "sinStep": 0.31, "cosStep": 0.09, "scale": 0.25, "offset": 1.0 }
2105
+ }
2106
+ },
2107
+ "outputs": { "y": { "dtype": "float32", "shape": [3, 17, 4097], "tolerance": 0.00001 } }
2108
+ },
2109
+ {
2110
+ "name": "split_f16_suffix_broadcast_tail",
2111
+ "attrs": { "axis": 1, "epsilon": 0.000001 },
2112
+ "inputs": {
2113
+ "x": {
2114
+ "dtype": "float16",
2115
+ "shape": [3, 17, 4097],
2116
+ "data": { "kind": "cycle", "values": [-0.75, -0.5, -0.25, 0.0, 0.25, 0.5, 0.75, 1.0] }
2117
+ },
2118
+ "scale": {
2119
+ "dtype": "float16",
2120
+ "shape": [1, 17, 1],
2121
+ "data": { "kind": "fillFloat32", "sinStep": 0.31, "cosStep": 0.09, "scale": 0.25, "offset": 1.0 }
2122
+ }
2123
+ },
2124
+ "outputs": { "y": { "dtype": "float16", "shape": [3, 17, 4097], "tolerance": 0.01 } }
2125
+ },
2126
+ {
2127
+ "name": "split_empty_outer_long_suffix",
2128
+ "attrs": { "axis": 1 },
2129
+ "inputs": {
2130
+ "x": { "dtype": "float32", "shape": [0, 2, 16384], "data": { "kind": "values", "values": [] } },
2131
+ "scale": { "dtype": "float32", "shape": [], "data": { "kind": "values", "values": [1.0] } }
2132
+ },
2133
+ "outputs": { "y": { "dtype": "float32", "shape": [0, 2, 16384], "tolerance": 0 } }
2134
  }
2135
  ]
2136
  }