Xenova HF Staff commited on
Commit
2760d09
·
verified ·
1 Parent(s): 07147ca

sync 2e7068faf55e

Browse files
README.md CHANGED
@@ -1,3 +1,77 @@
1
  ---
 
2
  license: apache-2.0
 
 
 
 
3
  ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ library_name: kernels
3
  license: apache-2.0
4
+ tags:
5
+ - kernel
6
+ - webgpu
7
+ - wgsl
8
  ---
9
+ # com.microsoft.SkipLayerNormalization
10
+
11
+ `com.microsoft` · ONNX Runtime contrib operator · contrib since_version 1
12
+
13
+ ## Description
14
+
15
+ Fuses skip addition with layer normalization. The rank-3 standard surface currently supports float32, required `beta`, no `bias` or residual output, hidden sizes divisible by four, and exact or documented broadcast skip shapes. The provider's rank-2 extension supports float32 output-only with optional `beta`, or `beta` with optional `bias` when emitting the residual; its float16 path requires `beta`, `bias`, a residual output, and four-wide hidden size. Other combinations, bfloat16, and training statistics are not implemented.
16
+
17
+ See the [ONNX Runtime `SkipLayerNormalization` contrib-operator spec](https://github.com/microsoft/onnxruntime/blob/main/docs/ContribOperators.md#com.microsoft.SkipLayerNormalization) for the reference semantics.
18
+
19
+ ## Inputs
20
+
21
+ | Name | Bind key | Logical dtype | Rank | Shape | Description | Presence |
22
+ | --- | --- | --- | --- | --- | --- | --- |
23
+ | `input` | `inputT` | `T` | — | — | Primary input normalized over the final hidden-size axis. Rank 3 is the public shape; rank 2 is an ONNX Runtime provider extension supported by this package. | required |
24
+ | `skip` | `skipT` | `T` | — | — | Residual tensor. For rank-3 input it is exact shape, `(1, sequence_length, hidden_size)`, or `(sequence_length, hidden_size)`; rank-2 input requires exact shape. | required |
25
+ | `gamma` | `gammaT` | `T` | `1` | — | Layer-norm scale weights of shape `(hidden_size)`. | required |
26
+ | `beta` | `betaT` | `T` | `1` | — | Layer-norm bias weights of shape `(hidden_size)`. | optional |
27
+ | `bias` | `biasT` | `T` | `1` | — | Optional additive bias of shape `(hidden_size)` added to `input + skip` before normalization. | optional |
28
+
29
+ ## Outputs
30
+
31
+ | Name | Bind key | Logical dtype | Rank | Shape | Description | Presence |
32
+ | --- | --- | --- | --- | --- | --- | --- |
33
+ | `output` | `outputT` | `T` | same as `input` | same as `input` | Normalized output tensor with the same shape as `input`. | required |
34
+ | `input_skip_bias_sum` | `residualT` | `T` | same as `input` | same as `input` | Sum of `input`, `skip`, and `bias` (when present) before normalization, with the same shape as `input`. | optional |
35
+
36
+ ## Attributes
37
+
38
+ Default values (overridable per request):
39
+
40
+ | Attribute | Default | Description |
41
+ | --- | --- | --- |
42
+ | `epsilon` | `9.999999960041972e-13` | Non-negative epsilon added to the variance before taking the square root. |
43
+
44
+ ## Type constraints
45
+
46
+ | Variable | Allowed dtypes |
47
+ | --- | --- |
48
+ | `T` | `float32`, `float16` |
49
+
50
+ ## Files
51
+
52
+ - [`metadata.json`](build/webgpu/metadata.json) — kernel metadata (id, digests, provenance)
53
+ - [`manifest.json`](build/webgpu/manifest.json) — the op contract (source of truth)
54
+ - [`test.json`](build/webgpu/test.json) — correctness cases
55
+ - [`bench.json`](build/webgpu/bench.json) — benchmark + tuning cases
56
+ - [`norm-skip-row-vec4.wgsl.jinja`](build/webgpu/norm-skip-row-vec4.wgsl.jinja)
57
+ - [`norm-skip-row.wgsl.jinja`](build/webgpu/norm-skip-row.wgsl.jinja)
58
+
59
+ ## Use with `@huggingface/kernels`
60
+
61
+ The loader derives every required output's shape and logical dtype from the manifest contract and this call.
62
+ It then allocates the result tensors automatically.
63
+
64
+ The `version: 1` option selects the published kernel contract; it is independent of any operator opset, contrib `since_version`, or model version.
65
+
66
+ Replace each `*Data` placeholder with a typed array containing the corresponding input data.
67
+
68
+ ```js
69
+ import { getKernel } from "@huggingface/kernels";
70
+
71
+ const kernel = await getKernel("webgpu-kernels/com.microsoft.SkipLayerNormalization", { version: 1 });
72
+ const { outputT } = await kernel({
73
+ inputT: { data: inputTData, shape: [2, 4] },
74
+ skipT: { data: skipTData, shape: [2, 4] },
75
+ gammaT: { data: gammaTData, shape: [4] },
76
+ });
77
+ ```
build/webgpu/bench.json ADDED
@@ -0,0 +1,246 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "op": "com.microsoft.SkipLayerNormalization",
3
+ "cases": [
4
+ {
5
+ "name": "skip-layernorm-f32-256x128",
6
+ "preset": "smoke",
7
+ "vars": { "rows": 256, "hidden": 128 },
8
+ "attrs": { "epsilon": 0.00001 },
9
+ "inputs": {
10
+ "inputT": { "shape": [256, 128], "dtype": "float32", "dist": "normal", "seed": 213, "scale": 0.2 },
11
+ "skipT": { "shape": [256, 128], "dtype": "float32", "dist": "normal", "seed": 214, "scale": 0.2 },
12
+ "gammaT": { "shape": [128], "dtype": "float32", "dist": "uniform", "seed": 215, "scale": 0.1, "offset": 1 },
13
+ "betaT": { "shape": [128], "dtype": "float32", "dist": "normal", "seed": 216, "scale": 0.1 }
14
+ },
15
+ "outputs": {
16
+ "outputT": { "shape": [256, 128], "dtype": "float32" },
17
+ "residualT": { "shape": [256, 128], "dtype": "float32" }
18
+ },
19
+ "bench": {
20
+ "primary": true,
21
+ "metrics": [{ "type": "bandwidth", "value": "4 * (4 * args.rows * args.hidden + 2 * args.hidden)" }]
22
+ }
23
+ },
24
+ {
25
+ "name": "skip-layernorm-f32-no-beta-output-256x128",
26
+ "preset": "smoke",
27
+ "vars": { "rows": 256, "hidden": 128 },
28
+ "attrs": { "epsilon": 0.00001 },
29
+ "inputs": {
30
+ "inputT": { "shape": [256, 128], "dtype": "float32", "dist": "normal", "seed": 219, "scale": 0.2 },
31
+ "skipT": { "shape": [256, 128], "dtype": "float32", "dist": "normal", "seed": 220, "scale": 0.2 },
32
+ "gammaT": { "shape": [128], "dtype": "float32", "dist": "uniform", "seed": 221, "scale": 0.1, "offset": 1 }
33
+ },
34
+ "outputs": { "outputT": { "shape": [256, 128], "dtype": "float32" } },
35
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "4 * (3 * args.rows * args.hidden + args.hidden)" }] }
36
+ },
37
+ {
38
+ "name": "skip-layernorm-f32-bias-256x128",
39
+ "preset": "smoke",
40
+ "vars": { "rows": 256, "hidden": 128 },
41
+ "attrs": { "epsilon": 0.00001 },
42
+ "inputs": {
43
+ "inputT": { "shape": [256, 128], "dtype": "float32", "dist": "normal", "seed": 214, "scale": 0.2 },
44
+ "skipT": { "shape": [256, 128], "dtype": "float32", "dist": "normal", "seed": 215, "scale": 0.2 },
45
+ "gammaT": { "shape": [128], "dtype": "float32", "dist": "uniform", "seed": 216, "scale": 0.1, "offset": 1 },
46
+ "betaT": { "shape": [128], "dtype": "float32", "dist": "normal", "seed": 217, "scale": 0.1 },
47
+ "biasT": { "shape": [128], "dtype": "float32", "dist": "normal", "seed": 218, "scale": 0.05 }
48
+ },
49
+ "outputs": {
50
+ "outputT": { "shape": [256, 128], "dtype": "float32" },
51
+ "residualT": { "shape": [256, 128], "dtype": "float32" }
52
+ },
53
+ "bench": {
54
+ "primary": true,
55
+ "metrics": [{ "type": "bandwidth", "value": "4 * (4 * args.rows * args.hidden + 3 * args.hidden)" }]
56
+ }
57
+ },
58
+ {
59
+ "name": "skip-layernorm-f32-4096x768",
60
+ "preset": "model",
61
+ "vars": { "rows": 4096, "hidden": 768 },
62
+ "attrs": { "epsilon": 0.00001 },
63
+ "inputs": {
64
+ "inputT": { "shape": [4096, 768], "dtype": "float32", "dist": "normal", "seed": 313, "scale": 0.2 },
65
+ "skipT": { "shape": [4096, 768], "dtype": "float32", "dist": "normal", "seed": 314, "scale": 0.2 },
66
+ "gammaT": { "shape": [768], "dtype": "float32", "dist": "uniform", "seed": 315, "scale": 0.1, "offset": 1 },
67
+ "betaT": { "shape": [768], "dtype": "float32", "dist": "normal", "seed": 316, "scale": 0.1 }
68
+ },
69
+ "outputs": {
70
+ "outputT": { "shape": [4096, 768], "dtype": "float32" },
71
+ "residualT": { "shape": [4096, 768], "dtype": "float32" }
72
+ },
73
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "4 * (4 * args.rows * args.hidden + 2 * args.hidden)" }] }
74
+ },
75
+ {
76
+ "name": "skip-layernorm-f32-no-beta-output-4096x768",
77
+ "preset": "model",
78
+ "vars": { "rows": 4096, "hidden": 768 },
79
+ "attrs": { "epsilon": 0.00001 },
80
+ "inputs": {
81
+ "inputT": { "shape": [4096, 768], "dtype": "float32", "dist": "normal", "seed": 319, "scale": 0.2 },
82
+ "skipT": { "shape": [4096, 768], "dtype": "float32", "dist": "normal", "seed": 320, "scale": 0.2 },
83
+ "gammaT": { "shape": [768], "dtype": "float32", "dist": "uniform", "seed": 321, "scale": 0.1, "offset": 1 }
84
+ },
85
+ "outputs": { "outputT": { "shape": [4096, 768], "dtype": "float32" } },
86
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "4 * (3 * args.rows * args.hidden + args.hidden)" }] }
87
+ },
88
+ {
89
+ "name": "skip-layernorm-f32-bias-4096x768",
90
+ "preset": "model",
91
+ "vars": { "rows": 4096, "hidden": 768 },
92
+ "attrs": { "epsilon": 0.00001 },
93
+ "inputs": {
94
+ "inputT": { "shape": [4096, 768], "dtype": "float32", "dist": "normal", "seed": 314, "scale": 0.2 },
95
+ "skipT": { "shape": [4096, 768], "dtype": "float32", "dist": "normal", "seed": 315, "scale": 0.2 },
96
+ "gammaT": { "shape": [768], "dtype": "float32", "dist": "uniform", "seed": 316, "scale": 0.1, "offset": 1 },
97
+ "betaT": { "shape": [768], "dtype": "float32", "dist": "normal", "seed": 317, "scale": 0.1 },
98
+ "biasT": { "shape": [768], "dtype": "float32", "dist": "normal", "seed": 318, "scale": 0.05 }
99
+ },
100
+ "outputs": {
101
+ "outputT": { "shape": [4096, 768], "dtype": "float32" },
102
+ "residualT": { "shape": [4096, 768], "dtype": "float32" }
103
+ },
104
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "4 * (4 * args.rows * args.hidden + 3 * args.hidden)" }] }
105
+ },
106
+ {
107
+ "name": "skip-layernorm-f32-bias-output-only-4096x768",
108
+ "preset": "model",
109
+ "provenance": {
110
+ "notes": "Ordinary inference shape with bias present and all three optional outputs omitted. It uses six storage buffers and writes only the primary output, isolating the output-only path from the full-output sibling at the same geometry."
111
+ },
112
+ "vars": { "rows": 4096, "hidden": 768 },
113
+ "attrs": { "epsilon": 0.00001 },
114
+ "inputs": {
115
+ "inputT": { "shape": [4096, 768], "dtype": "float32", "dist": "normal", "seed": 314, "scale": 0.2 },
116
+ "skipT": { "shape": [4096, 768], "dtype": "float32", "dist": "normal", "seed": 315, "scale": 0.2 },
117
+ "gammaT": { "shape": [768], "dtype": "float32", "dist": "uniform", "seed": 316, "scale": 0.1, "offset": 1 },
118
+ "betaT": { "shape": [768], "dtype": "float32", "dist": "normal", "seed": 317, "scale": 0.1 },
119
+ "biasT": { "shape": [768], "dtype": "float32", "dist": "normal", "seed": 318, "scale": 0.05 }
120
+ },
121
+ "outputs": { "outputT": { "shape": [4096, 768], "dtype": "float32" } },
122
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "4 * (3 * args.rows * args.hidden + 3 * args.hidden)" }] }
123
+ },
124
+ {
125
+ "name": "skip-layernorm-f32-4096x770-hidden770-unaligned",
126
+ "preset": "model",
127
+ "vars": { "rows": 4096, "hidden": 770 },
128
+ "attrs": { "epsilon": 0.00001 },
129
+ "inputs": {
130
+ "inputT": { "shape": [4096, 770], "dtype": "float32", "dist": "normal", "seed": 413, "scale": 0.2 },
131
+ "skipT": { "shape": [4096, 770], "dtype": "float32", "dist": "normal", "seed": 414, "scale": 0.2 },
132
+ "gammaT": { "shape": [770], "dtype": "float32", "dist": "uniform", "seed": 415, "scale": 0.1, "offset": 1 },
133
+ "betaT": { "shape": [770], "dtype": "float32", "dist": "normal", "seed": 416, "scale": 0.1 }
134
+ },
135
+ "outputs": {
136
+ "outputT": { "shape": [4096, 770], "dtype": "float32" },
137
+ "residualT": { "shape": [4096, 770], "dtype": "float32" }
138
+ },
139
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "4 * (4 * args.rows * args.hidden + 2 * args.hidden)" }] }
140
+ },
141
+ {
142
+ "name": "skip-layernorm-f32-4096x768-hidden768-aligned-sibling",
143
+ "preset": "model",
144
+ "vars": { "rows": 4096, "hidden": 768 },
145
+ "attrs": { "epsilon": 0.00001 },
146
+ "inputs": {
147
+ "inputT": { "shape": [4096, 768], "dtype": "float32", "dist": "normal", "seed": 413, "scale": 0.2 },
148
+ "skipT": { "shape": [4096, 768], "dtype": "float32", "dist": "normal", "seed": 414, "scale": 0.2 },
149
+ "gammaT": { "shape": [768], "dtype": "float32", "dist": "uniform", "seed": 415, "scale": 0.1, "offset": 1 },
150
+ "betaT": { "shape": [768], "dtype": "float32", "dist": "normal", "seed": 416, "scale": 0.1 }
151
+ },
152
+ "outputs": {
153
+ "outputT": { "shape": [4096, 768], "dtype": "float32" },
154
+ "residualT": { "shape": [4096, 768], "dtype": "float32" }
155
+ },
156
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "4 * (4 * args.rows * args.hidden + 2 * args.hidden)" }] }
157
+ },
158
+ {
159
+ "name": "skip-layernorm-f32-rows1-hidden4096-decode",
160
+ "preset": "model",
161
+ "vars": { "rows": 1, "hidden": 4096 },
162
+ "attrs": { "epsilon": 0.00001 },
163
+ "inputs": {
164
+ "inputT": { "shape": [1, 4096], "dtype": "float32", "dist": "normal", "seed": 513, "scale": 0.2 },
165
+ "skipT": { "shape": [1, 4096], "dtype": "float32", "dist": "normal", "seed": 514, "scale": 0.2 },
166
+ "gammaT": { "shape": [4096], "dtype": "float32", "dist": "uniform", "seed": 515, "scale": 0.1, "offset": 1 },
167
+ "betaT": { "shape": [4096], "dtype": "float32", "dist": "normal", "seed": 516, "scale": 0.1 }
168
+ },
169
+ "outputs": {
170
+ "outputT": { "shape": [1, 4096], "dtype": "float32" },
171
+ "residualT": { "shape": [1, 4096], "dtype": "float32" }
172
+ },
173
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "4 * (4 * args.rows * args.hidden + 2 * args.hidden)" }] }
174
+ },
175
+ {
176
+ "name": "skip-layernorm-f32-rows4096-hidden4096-prefill-sibling",
177
+ "preset": "model",
178
+ "vars": { "rows": 4096, "hidden": 4096 },
179
+ "attrs": { "epsilon": 0.00001 },
180
+ "inputs": {
181
+ "inputT": { "shape": [4096, 4096], "dtype": "float32", "dist": "normal", "seed": 513, "scale": 0.2 },
182
+ "skipT": { "shape": [4096, 4096], "dtype": "float32", "dist": "normal", "seed": 514, "scale": 0.2 },
183
+ "gammaT": { "shape": [4096], "dtype": "float32", "dist": "uniform", "seed": 515, "scale": 0.1, "offset": 1 },
184
+ "betaT": { "shape": [4096], "dtype": "float32", "dist": "normal", "seed": 516, "scale": 0.1 }
185
+ },
186
+ "outputs": {
187
+ "outputT": { "shape": [4096, 4096], "dtype": "float32" },
188
+ "residualT": { "shape": [4096, 4096], "dtype": "float32" }
189
+ },
190
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "4 * (4 * args.rows * args.hidden + 2 * args.hidden)" }] }
191
+ },
192
+ {
193
+ "name": "skip-layernorm-f32-4096x4095-hidden4095-unaligned-largewidth",
194
+ "preset": "model",
195
+ "vars": { "rows": 4096, "hidden": 4095 },
196
+ "attrs": { "epsilon": 0.00001 },
197
+ "inputs": {
198
+ "inputT": { "shape": [4096, 4095], "dtype": "float32", "dist": "normal", "seed": 613, "scale": 0.2 },
199
+ "skipT": { "shape": [4096, 4095], "dtype": "float32", "dist": "normal", "seed": 614, "scale": 0.2 },
200
+ "gammaT": { "shape": [4095], "dtype": "float32", "dist": "uniform", "seed": 615, "scale": 0.1, "offset": 1 },
201
+ "betaT": { "shape": [4095], "dtype": "float32", "dist": "normal", "seed": 616, "scale": 0.1 }
202
+ },
203
+ "outputs": {
204
+ "outputT": { "shape": [4096, 4095], "dtype": "float32" },
205
+ "residualT": { "shape": [4096, 4095], "dtype": "float32" }
206
+ },
207
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "4 * (4 * args.rows * args.hidden + 2 * args.hidden)" }] }
208
+ },
209
+ {
210
+ "name": "skip-layernorm-f32-bias-8192x1025-unaligned-twopass-fallback",
211
+ "preset": "stress",
212
+ "vars": { "rows": 8192, "hidden": 1025 },
213
+ "attrs": { "epsilon": 0.00001 },
214
+ "inputs": {
215
+ "inputT": { "shape": [8192, 1025], "dtype": "float32", "dist": "normal", "seed": 713, "scale": 0.2 },
216
+ "skipT": { "shape": [8192, 1025], "dtype": "float32", "dist": "normal", "seed": 714, "scale": 0.2 },
217
+ "gammaT": { "shape": [1025], "dtype": "float32", "dist": "uniform", "seed": 715, "scale": 0.1, "offset": 1 },
218
+ "betaT": { "shape": [1025], "dtype": "float32", "dist": "normal", "seed": 716, "scale": 0.1 },
219
+ "biasT": { "shape": [1025], "dtype": "float32", "dist": "normal", "seed": 717, "scale": 0.05 }
220
+ },
221
+ "outputs": {
222
+ "outputT": { "shape": [8192, 1025], "dtype": "float32" },
223
+ "residualT": { "shape": [8192, 1025], "dtype": "float32" }
224
+ },
225
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "4 * (4 * args.rows * args.hidden + 3 * args.hidden)" }] }
226
+ },
227
+ {
228
+ "name": "skip-layernorm-f32-bias-65535x1-wg1-lowoccupancy-fallback",
229
+ "preset": "edge",
230
+ "vars": { "rows": 65535, "hidden": 1 },
231
+ "attrs": { "epsilon": 0.00001 },
232
+ "inputs": {
233
+ "inputT": { "shape": [65535, 1], "dtype": "float32", "dist": "normal", "seed": 813, "scale": 0.2 },
234
+ "skipT": { "shape": [65535, 1], "dtype": "float32", "dist": "normal", "seed": 814, "scale": 0.2 },
235
+ "gammaT": { "shape": [1], "dtype": "float32", "dist": "uniform", "seed": 815, "scale": 0.1, "offset": 1 },
236
+ "betaT": { "shape": [1], "dtype": "float32", "dist": "normal", "seed": 816, "scale": 0.1 },
237
+ "biasT": { "shape": [1], "dtype": "float32", "dist": "normal", "seed": 817, "scale": 0.05 }
238
+ },
239
+ "outputs": {
240
+ "outputT": { "shape": [65535, 1], "dtype": "float32" },
241
+ "residualT": { "shape": [65535, 1], "dtype": "float32" }
242
+ },
243
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "4 * (4 * args.rows * args.hidden + 3 * args.hidden)" }] }
244
+ }
245
+ ]
246
+ }
build/webgpu/manifest.json ADDED
@@ -0,0 +1,1108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "domain": "com.microsoft",
3
+ "name": "SkipLayerNormalization",
4
+ "sinceVersion": 1,
5
+ "description": "Fuses skip addition with layer normalization. The rank-3 standard surface currently supports float32, required `beta`, no `bias` or residual output, hidden sizes divisible by four, and exact or documented broadcast skip shapes. The provider's rank-2 extension supports float32 output-only with optional `beta`, or `beta` with optional `bias` when emitting the residual; its float16 path requires `beta`, `bias`, a residual output, and four-wide hidden size. Other combinations, bfloat16, and training statistics are not implemented.",
6
+ "inputs": [
7
+ {
8
+ "role": "input",
9
+ "dtype": "T",
10
+ "description": "Primary input normalized over the final hidden-size axis. Rank 3 is the public shape; rank 2 is an ONNX Runtime provider extension supported by this package."
11
+ },
12
+ {
13
+ "role": "skip",
14
+ "dtype": "T",
15
+ "description": "Residual tensor. For rank-3 input it is exact shape, `(1, sequence_length, hidden_size)`, or `(sequence_length, hidden_size)`; rank-2 input requires exact shape."
16
+ },
17
+ { "role": "gamma", "dtype": "T", "rank": 1, "description": "Layer-norm scale weights of shape `(hidden_size)`." },
18
+ {
19
+ "role": "beta",
20
+ "dtype": "T",
21
+ "rank": 1,
22
+ "optional": true,
23
+ "description": "Layer-norm bias weights of shape `(hidden_size)`."
24
+ },
25
+ {
26
+ "role": "bias",
27
+ "dtype": "T",
28
+ "rank": 1,
29
+ "optional": true,
30
+ "description": "Optional additive bias of shape `(hidden_size)` added to `input + skip` before normalization."
31
+ }
32
+ ],
33
+ "outputs": [
34
+ {
35
+ "role": "output",
36
+ "dtype": "T",
37
+ "rank": "ranks.inputT",
38
+ "shape": "shapes.inputT",
39
+ "description": "Normalized output tensor with the same shape as `input`."
40
+ },
41
+ {
42
+ "role": "input_skip_bias_sum",
43
+ "dtype": "T",
44
+ "rank": "ranks.inputT",
45
+ "optional": true,
46
+ "shape": "shapes.inputT",
47
+ "description": "Sum of `input`, `skip`, and `bias` (when present) before normalization, with the same shape as `input`."
48
+ }
49
+ ],
50
+ "attributes": { "epsilon": 9.999999960041972e-13 },
51
+ "attributeDescriptions": { "epsilon": "Non-negative epsilon added to the variance before taking the square root." },
52
+ "args": {
53
+ "inputT": { "kind": "tensor", "semantic": "input", "role": "input" },
54
+ "skipT": { "kind": "tensor", "semantic": "skip", "role": "input" },
55
+ "gammaT": { "kind": "tensor", "semantic": "gamma", "role": "input" },
56
+ "betaT": { "kind": "tensor", "semantic": "beta", "role": "input", "required": false },
57
+ "biasT": { "kind": "tensor", "semantic": "bias", "role": "input", "required": false },
58
+ "outputT": { "kind": "tensor", "semantic": "output", "role": "output" },
59
+ "residualT": { "kind": "tensor", "semantic": "input_skip_bias_sum", "role": "output", "required": false }
60
+ },
61
+ "typeConstraints": { "T": ["float32", "float16"] },
62
+ "derive": {
63
+ "rowCount": "dim(shapes.inputT, 0)",
64
+ "hiddenSize": "dim(shapes.inputT, 1)",
65
+ "skipWg": "max(1, min(tunables.MAX_WORKGROUP_SIZE, device.limits.maxComputeInvocationsPerWorkgroup, device.limits.maxComputeWorkgroupSizeX, pow2ceil(hiddenSize)))",
66
+ "skipWgVec4": "max(1, min(tunables.MAX_WORKGROUP_SIZE, device.limits.maxComputeInvocationsPerWorkgroup, device.limits.maxComputeWorkgroupSizeX, pow2ceil(ceilDiv(hiddenSize, 4))))",
67
+ "portableWideExecution": "not has(device.adapterInfo, \"subgroupMinSize\") or device.adapterInfo.subgroupMinSize >= 32",
68
+ "broadcastRows": "dim(shapes.inputT, 0) * dim(shapes.inputT, 1)",
69
+ "broadcastHiddenSize": "dim(shapes.inputT, 2)",
70
+ "broadcastSkipWgVec4": "max(1, min(tunables.MAX_WORKGROUP_SIZE, device.limits.maxComputeInvocationsPerWorkgroup, device.limits.maxComputeWorkgroupSizeX, pow2ceil(ceilDiv(broadcastHiddenSize, 4))))",
71
+ "rowDispatchFits": "rowCount <= device.limits.maxComputeWorkgroupsPerDimension * device.limits.maxComputeWorkgroupsPerDimension",
72
+ "broadcastDispatchFits": "broadcastRows <= device.limits.maxComputeWorkgroupsPerDimension * device.limits.maxComputeWorkgroupsPerDimension",
73
+ "normResourcesFit": "skipWg * 8 <= device.limits.maxComputeWorkgroupStorageSize and skipWgVec4 * 8 <= device.limits.maxComputeWorkgroupStorageSize",
74
+ "broadcastResourcesFit": "broadcastSkipWgVec4 * 8 <= device.limits.maxComputeWorkgroupStorageSize",
75
+ "epsilonOk": "attrs.epsilon >= 0",
76
+ "rank2CoreContract": "epsilonOk and ranks.inputT == 2 and ranks.skipT == 2 and ranks.gammaT == 1 and ranks.outputT == 2 and dim(shapes.inputT, 0) == dim(shapes.skipT, 0) and dim(shapes.inputT, 1) == dim(shapes.skipT, 1) and dim(shapes.inputT, 1) > 0 and dim(shapes.gammaT, 0) == dim(shapes.inputT, 1) and dim(shapes.outputT, 0) == dim(shapes.inputT, 0) and dim(shapes.outputT, 1) == dim(shapes.inputT, 1)",
77
+ "residualOutputContract": "present.residualT and ranks.residualT == 2 and dim(shapes.residualT, 0) == dim(shapes.inputT, 0) and dim(shapes.residualT, 1) == dim(shapes.inputT, 1)",
78
+ "outputOnlyContract": "not present.residualT",
79
+ "betaContract": "false if not present.betaT else (ranks.betaT == 1 and dim(shapes.betaT, 0) == dim(shapes.inputT, 1))",
80
+ "noBetaContract": "not present.betaT",
81
+ "f32MainDtypes": "tensorDtypes.inputT == \"float32\" and tensorDtypes.skipT == \"float32\" and tensorDtypes.gammaT == \"float32\" and tensorDtypes.outputT == \"float32\"",
82
+ "f16MainDtypes": "tensorDtypes.inputT == \"float16\" and tensorDtypes.skipT == \"float16\" and tensorDtypes.gammaT == \"float16\" and tensorDtypes.outputT == \"float16\"",
83
+ "f32ResidualDtypes": "f32MainDtypes and tensorDtypes.residualT == \"float32\" if present.residualT else false",
84
+ "f16ResidualDtypes": "f16MainDtypes and tensorDtypes.residualT == \"float16\" if present.residualT else false",
85
+ "vec4Aligned": "dim(shapes.inputT, 1) % 4 == 0",
86
+ "broadcastSkipShapeOk": "(ranks.skipT == 2 and dim(shapes.skipT, 0) == dim(shapes.inputT, 1) and dim(shapes.skipT, 1) == dim(shapes.inputT, 2)) or (ranks.skipT == 3 and ((dim(shapes.skipT, 0) == 1 and dim(shapes.skipT, 1) == dim(shapes.inputT, 1) and dim(shapes.skipT, 2) == dim(shapes.inputT, 2)) or sameShape(shapes.skipT, shapes.inputT)))",
87
+ "broadcastOutputOnlyContract": "false if ranks.inputT != 3 or not present.betaT else (epsilonOk and not present.biasT and not present.residualT and dim(shapes.inputT, 2) % 4 == 0 and broadcastSkipShapeOk and ranks.gammaT == 1 and ranks.betaT == 1 and ranks.outputT == 3 and tensorDtypes.inputT == \"float32\" and tensorDtypes.skipT == \"float32\" and tensorDtypes.gammaT == \"float32\" and tensorDtypes.betaT == \"float32\" and tensorDtypes.outputT == \"float32\" and dim(shapes.inputT, 2) > 0 and dim(shapes.gammaT, 0) == dim(shapes.inputT, 2) and dim(shapes.betaT, 0) == dim(shapes.inputT, 2) and sameShape(shapes.outputT, shapes.inputT))",
88
+ "hasSubgroups": "device.features.has(\"subgroups\") and device.wgslLanguageFeatures.has(\"subgroup_id\")",
89
+ "hasF16": "device.features.has(\"shader-f16\")",
90
+ "f32_beta_no_bias_residual_contract": "rank2CoreContract and residualOutputContract and betaContract and f32ResidualDtypes and not present.biasT and tensorDtypes.betaT == \"float32\"",
91
+ "f32_beta_bias_residual_contract": "false if not present.biasT else (rank2CoreContract and residualOutputContract and betaContract and f32ResidualDtypes and ranks.biasT == 1 and tensorDtypes.betaT == \"float32\" and tensorDtypes.biasT == \"float32\" and dim(shapes.biasT, 0) == hiddenSize)",
92
+ "f16_beta_bias_residual_contract": "false if not present.biasT else (hasF16 and rank2CoreContract and residualOutputContract and betaContract and f16ResidualDtypes and ranks.biasT == 1 and tensorDtypes.betaT == \"float16\" and tensorDtypes.biasT == \"float16\" and dim(shapes.biasT, 0) == hiddenSize)",
93
+ "f32_no_beta_output_contract": "rank2CoreContract and outputOnlyContract and noBetaContract and f32MainDtypes and not present.biasT",
94
+ "f32_beta_no_bias_output_only_contract": "rank2CoreContract and outputOnlyContract and betaContract and f32MainDtypes and not present.biasT and tensorDtypes.betaT == \"float32\"",
95
+ "f32_beta_bias_output_only_contract": "false if not present.biasT else (rank2CoreContract and outputOnlyContract and betaContract and f32MainDtypes and ranks.biasT == 1 and tensorDtypes.betaT == \"float32\" and tensorDtypes.biasT == \"float32\" and dim(shapes.biasT, 0) == hiddenSize)"
96
+ },
97
+ "bindingSets": {
98
+ "scalar_no_bias_residual": [
99
+ {
100
+ "name": "input",
101
+ "arg": "inputT",
102
+ "semantic": "input",
103
+ "buffer": { "type": "read-only-storage" },
104
+ "elementType": "$scalar"
105
+ },
106
+ {
107
+ "name": "skip",
108
+ "arg": "skipT",
109
+ "semantic": "skip",
110
+ "buffer": { "type": "read-only-storage" },
111
+ "elementType": "$scalar"
112
+ },
113
+ {
114
+ "name": "gamma",
115
+ "arg": "gammaT",
116
+ "semantic": "gamma",
117
+ "buffer": { "type": "read-only-storage" },
118
+ "elementType": "$scalar",
119
+ "length": "$HIDDEN_LEN"
120
+ },
121
+ {
122
+ "name": "beta",
123
+ "arg": "betaT",
124
+ "semantic": "beta",
125
+ "buffer": { "type": "read-only-storage" },
126
+ "elementType": "$scalar",
127
+ "length": "$HIDDEN_LEN"
128
+ },
129
+ {
130
+ "name": "output",
131
+ "arg": "outputT",
132
+ "semantic": "output",
133
+ "buffer": { "type": "storage" },
134
+ "elementType": "$scalar"
135
+ },
136
+ {
137
+ "name": "input_skip_bias_sum",
138
+ "arg": "residualT",
139
+ "semantic": "input_skip_bias_sum",
140
+ "buffer": { "type": "storage" },
141
+ "elementType": "$scalar"
142
+ },
143
+ {
144
+ "name": "params",
145
+ "semantic": "kernel.params",
146
+ "buffer": { "type": "uniform" },
147
+ "struct": {
148
+ "name": "Params",
149
+ "fields": [
150
+ { "name": "rows", "type": "u32", "value": "rowCount" },
151
+ { "name": "epsilon", "type": "f32", "value": "attrs.epsilon" }
152
+ ]
153
+ }
154
+ }
155
+ ],
156
+ "scalar_bias_output_residual": [
157
+ {
158
+ "name": "input",
159
+ "arg": "inputT",
160
+ "semantic": "input",
161
+ "buffer": { "type": "read-only-storage" },
162
+ "elementType": "$scalar"
163
+ },
164
+ {
165
+ "name": "skip",
166
+ "arg": "skipT",
167
+ "semantic": "skip",
168
+ "buffer": { "type": "read-only-storage" },
169
+ "elementType": "$scalar"
170
+ },
171
+ {
172
+ "name": "bias",
173
+ "arg": "biasT",
174
+ "semantic": "bias",
175
+ "buffer": { "type": "read-only-storage" },
176
+ "elementType": "$scalar",
177
+ "length": "$HIDDEN_LEN"
178
+ },
179
+ {
180
+ "name": "gamma",
181
+ "arg": "gammaT",
182
+ "semantic": "gamma",
183
+ "buffer": { "type": "read-only-storage" },
184
+ "elementType": "$scalar",
185
+ "length": "$HIDDEN_LEN"
186
+ },
187
+ {
188
+ "name": "beta",
189
+ "arg": "betaT",
190
+ "semantic": "beta",
191
+ "buffer": { "type": "read-only-storage" },
192
+ "elementType": "$scalar",
193
+ "length": "$HIDDEN_LEN"
194
+ },
195
+ {
196
+ "name": "output",
197
+ "arg": "outputT",
198
+ "semantic": "output",
199
+ "buffer": { "type": "storage" },
200
+ "elementType": "$scalar"
201
+ },
202
+ {
203
+ "name": "input_skip_bias_sum",
204
+ "arg": "residualT",
205
+ "semantic": "input_skip_bias_sum",
206
+ "buffer": { "type": "storage" },
207
+ "elementType": "$scalar"
208
+ },
209
+ {
210
+ "name": "params",
211
+ "semantic": "kernel.params",
212
+ "buffer": { "type": "uniform" },
213
+ "struct": {
214
+ "name": "Params",
215
+ "fields": [
216
+ { "name": "rows", "type": "u32", "value": "rowCount" },
217
+ { "name": "epsilon", "type": "f32", "value": "attrs.epsilon" }
218
+ ]
219
+ }
220
+ }
221
+ ],
222
+ "vec4_bias_output_residual": [
223
+ {
224
+ "name": "input",
225
+ "arg": "inputT",
226
+ "semantic": "input",
227
+ "buffer": { "type": "read-only-storage" },
228
+ "elementType": "$vectorScalar"
229
+ },
230
+ {
231
+ "name": "skip",
232
+ "arg": "skipT",
233
+ "semantic": "skip",
234
+ "buffer": { "type": "read-only-storage" },
235
+ "elementType": "$vectorScalar"
236
+ },
237
+ {
238
+ "name": "bias",
239
+ "arg": "biasT",
240
+ "semantic": "bias",
241
+ "buffer": { "type": "read-only-storage" },
242
+ "elementType": "$vectorScalar",
243
+ "length": "$HIDDEN_LEN"
244
+ },
245
+ {
246
+ "name": "gamma",
247
+ "arg": "gammaT",
248
+ "semantic": "gamma",
249
+ "buffer": { "type": "read-only-storage" },
250
+ "elementType": "$vectorScalar",
251
+ "length": "$HIDDEN_LEN"
252
+ },
253
+ {
254
+ "name": "beta",
255
+ "arg": "betaT",
256
+ "semantic": "beta",
257
+ "buffer": { "type": "read-only-storage" },
258
+ "elementType": "$vectorScalar",
259
+ "length": "$HIDDEN_LEN"
260
+ },
261
+ {
262
+ "name": "output",
263
+ "arg": "outputT",
264
+ "semantic": "output",
265
+ "buffer": { "type": "storage" },
266
+ "elementType": "$vectorScalar"
267
+ },
268
+ {
269
+ "name": "input_skip_bias_sum",
270
+ "arg": "residualT",
271
+ "semantic": "input_skip_bias_sum",
272
+ "buffer": { "type": "storage" },
273
+ "elementType": "$vectorScalar"
274
+ },
275
+ {
276
+ "name": "params",
277
+ "semantic": "kernel.params",
278
+ "buffer": { "type": "uniform" },
279
+ "struct": {
280
+ "name": "Params",
281
+ "fields": [
282
+ { "name": "rows", "type": "u32", "value": "rowCount" },
283
+ {
284
+ "name": "rowStride",
285
+ "type": "u32",
286
+ "value": "max(1, min(rowCount, device.limits.maxComputeWorkgroupsPerDimension))"
287
+ },
288
+ { "name": "epsilon", "type": "f32", "value": "attrs.epsilon" }
289
+ ]
290
+ }
291
+ }
292
+ ],
293
+ "scalar_no_bias_output_only": [
294
+ {
295
+ "name": "input",
296
+ "arg": "inputT",
297
+ "semantic": "input",
298
+ "buffer": { "type": "read-only-storage" },
299
+ "elementType": "$scalar"
300
+ },
301
+ {
302
+ "name": "skip",
303
+ "arg": "skipT",
304
+ "semantic": "skip",
305
+ "buffer": { "type": "read-only-storage" },
306
+ "elementType": "$scalar"
307
+ },
308
+ {
309
+ "name": "gamma",
310
+ "arg": "gammaT",
311
+ "semantic": "gamma",
312
+ "buffer": { "type": "read-only-storage" },
313
+ "elementType": "$scalar",
314
+ "length": "$HIDDEN_LEN"
315
+ },
316
+ {
317
+ "name": "beta",
318
+ "arg": "betaT",
319
+ "semantic": "beta",
320
+ "buffer": { "type": "read-only-storage" },
321
+ "elementType": "$scalar",
322
+ "length": "$HIDDEN_LEN"
323
+ },
324
+ {
325
+ "name": "output",
326
+ "arg": "outputT",
327
+ "semantic": "output",
328
+ "buffer": { "type": "storage" },
329
+ "elementType": "$scalar"
330
+ },
331
+ {
332
+ "name": "params",
333
+ "semantic": "kernel.params",
334
+ "buffer": { "type": "uniform" },
335
+ "struct": {
336
+ "name": "Params",
337
+ "fields": [
338
+ { "name": "rows", "type": "u32", "value": "rowCount" },
339
+ { "name": "epsilon", "type": "f32", "value": "attrs.epsilon" }
340
+ ]
341
+ }
342
+ }
343
+ ],
344
+ "scalar_bias_output_only": [
345
+ {
346
+ "name": "input",
347
+ "arg": "inputT",
348
+ "semantic": "input",
349
+ "buffer": { "type": "read-only-storage" },
350
+ "elementType": "$scalar"
351
+ },
352
+ {
353
+ "name": "skip",
354
+ "arg": "skipT",
355
+ "semantic": "skip",
356
+ "buffer": { "type": "read-only-storage" },
357
+ "elementType": "$scalar"
358
+ },
359
+ {
360
+ "name": "bias",
361
+ "arg": "biasT",
362
+ "semantic": "bias",
363
+ "buffer": { "type": "read-only-storage" },
364
+ "elementType": "$scalar",
365
+ "length": "$HIDDEN_LEN"
366
+ },
367
+ {
368
+ "name": "gamma",
369
+ "arg": "gammaT",
370
+ "semantic": "gamma",
371
+ "buffer": { "type": "read-only-storage" },
372
+ "elementType": "$scalar",
373
+ "length": "$HIDDEN_LEN"
374
+ },
375
+ {
376
+ "name": "beta",
377
+ "arg": "betaT",
378
+ "semantic": "beta",
379
+ "buffer": { "type": "read-only-storage" },
380
+ "elementType": "$scalar",
381
+ "length": "$HIDDEN_LEN"
382
+ },
383
+ {
384
+ "name": "output",
385
+ "arg": "outputT",
386
+ "semantic": "output",
387
+ "buffer": { "type": "storage" },
388
+ "elementType": "$scalar"
389
+ },
390
+ {
391
+ "name": "params",
392
+ "semantic": "kernel.params",
393
+ "buffer": { "type": "uniform" },
394
+ "struct": {
395
+ "name": "Params",
396
+ "fields": [
397
+ { "name": "rows", "type": "u32", "value": "rowCount" },
398
+ { "name": "epsilon", "type": "f32", "value": "attrs.epsilon" }
399
+ ]
400
+ }
401
+ }
402
+ ],
403
+ "scalar_no_beta_output_only": [
404
+ {
405
+ "name": "input",
406
+ "arg": "inputT",
407
+ "semantic": "input",
408
+ "buffer": { "type": "read-only-storage" },
409
+ "elementType": "$scalar"
410
+ },
411
+ {
412
+ "name": "skip",
413
+ "arg": "skipT",
414
+ "semantic": "skip",
415
+ "buffer": { "type": "read-only-storage" },
416
+ "elementType": "$scalar"
417
+ },
418
+ {
419
+ "name": "gamma",
420
+ "arg": "gammaT",
421
+ "semantic": "gamma",
422
+ "buffer": { "type": "read-only-storage" },
423
+ "elementType": "$scalar",
424
+ "length": "$HIDDEN_LEN"
425
+ },
426
+ {
427
+ "name": "output",
428
+ "arg": "outputT",
429
+ "semantic": "output",
430
+ "buffer": { "type": "storage" },
431
+ "elementType": "$scalar"
432
+ },
433
+ {
434
+ "name": "params",
435
+ "semantic": "kernel.params",
436
+ "buffer": { "type": "uniform" },
437
+ "struct": {
438
+ "name": "Params",
439
+ "fields": [
440
+ { "name": "rows", "type": "u32", "value": "rowCount" },
441
+ { "name": "epsilon", "type": "f32", "value": "attrs.epsilon" }
442
+ ]
443
+ }
444
+ }
445
+ ],
446
+ "vec4_no_bias_residual": [
447
+ {
448
+ "name": "input",
449
+ "arg": "inputT",
450
+ "semantic": "input",
451
+ "buffer": { "type": "read-only-storage" },
452
+ "elementType": "$vectorScalar"
453
+ },
454
+ {
455
+ "name": "skip",
456
+ "arg": "skipT",
457
+ "semantic": "skip",
458
+ "buffer": { "type": "read-only-storage" },
459
+ "elementType": "$vectorScalar"
460
+ },
461
+ {
462
+ "name": "gamma",
463
+ "arg": "gammaT",
464
+ "semantic": "gamma",
465
+ "buffer": { "type": "read-only-storage" },
466
+ "elementType": "$vectorScalar",
467
+ "length": "$HIDDEN_LEN"
468
+ },
469
+ {
470
+ "name": "beta",
471
+ "arg": "betaT",
472
+ "semantic": "beta",
473
+ "buffer": { "type": "read-only-storage" },
474
+ "elementType": "$vectorScalar",
475
+ "length": "$HIDDEN_LEN"
476
+ },
477
+ {
478
+ "name": "output",
479
+ "arg": "outputT",
480
+ "semantic": "output",
481
+ "buffer": { "type": "storage" },
482
+ "elementType": "$vectorScalar"
483
+ },
484
+ {
485
+ "name": "input_skip_bias_sum",
486
+ "arg": "residualT",
487
+ "semantic": "input_skip_bias_sum",
488
+ "buffer": { "type": "storage" },
489
+ "elementType": "$vectorScalar"
490
+ },
491
+ {
492
+ "name": "params",
493
+ "semantic": "kernel.params",
494
+ "buffer": { "type": "uniform" },
495
+ "struct": {
496
+ "name": "Params",
497
+ "fields": [
498
+ { "name": "rows", "type": "u32", "value": "rowCount" },
499
+ {
500
+ "name": "rowStride",
501
+ "type": "u32",
502
+ "value": "max(1, min(rowCount, device.limits.maxComputeWorkgroupsPerDimension))"
503
+ },
504
+ { "name": "epsilon", "type": "f32", "value": "attrs.epsilon" }
505
+ ]
506
+ }
507
+ }
508
+ ],
509
+ "vec4_no_bias_output_only": [
510
+ {
511
+ "name": "input",
512
+ "arg": "inputT",
513
+ "semantic": "input",
514
+ "buffer": { "type": "read-only-storage" },
515
+ "elementType": "$vectorScalar"
516
+ },
517
+ {
518
+ "name": "skip",
519
+ "arg": "skipT",
520
+ "semantic": "skip",
521
+ "buffer": { "type": "read-only-storage" },
522
+ "elementType": "$vectorScalar"
523
+ },
524
+ {
525
+ "name": "gamma",
526
+ "arg": "gammaT",
527
+ "semantic": "gamma",
528
+ "buffer": { "type": "read-only-storage" },
529
+ "elementType": "$vectorScalar",
530
+ "length": "$HIDDEN_LEN"
531
+ },
532
+ {
533
+ "name": "beta",
534
+ "arg": "betaT",
535
+ "semantic": "beta",
536
+ "buffer": { "type": "read-only-storage" },
537
+ "elementType": "$vectorScalar",
538
+ "length": "$HIDDEN_LEN"
539
+ },
540
+ {
541
+ "name": "output",
542
+ "arg": "outputT",
543
+ "semantic": "output",
544
+ "buffer": { "type": "storage" },
545
+ "elementType": "$vectorScalar"
546
+ },
547
+ {
548
+ "name": "params",
549
+ "semantic": "kernel.params",
550
+ "buffer": { "type": "uniform" },
551
+ "struct": {
552
+ "name": "Params",
553
+ "fields": [
554
+ { "name": "rows", "type": "u32", "value": "rowCount" },
555
+ {
556
+ "name": "rowStride",
557
+ "type": "u32",
558
+ "value": "max(1, min(rowCount, device.limits.maxComputeWorkgroupsPerDimension))"
559
+ },
560
+ { "name": "epsilon", "type": "f32", "value": "attrs.epsilon" }
561
+ ]
562
+ }
563
+ }
564
+ ],
565
+ "vec4_bias_output_only": [
566
+ {
567
+ "name": "input",
568
+ "arg": "inputT",
569
+ "semantic": "input",
570
+ "buffer": { "type": "read-only-storage" },
571
+ "elementType": "$vectorScalar"
572
+ },
573
+ {
574
+ "name": "skip",
575
+ "arg": "skipT",
576
+ "semantic": "skip",
577
+ "buffer": { "type": "read-only-storage" },
578
+ "elementType": "$vectorScalar"
579
+ },
580
+ {
581
+ "name": "gamma",
582
+ "arg": "gammaT",
583
+ "semantic": "gamma",
584
+ "buffer": { "type": "read-only-storage" },
585
+ "elementType": "$vectorScalar",
586
+ "length": "$HIDDEN_LEN"
587
+ },
588
+ {
589
+ "name": "beta",
590
+ "arg": "betaT",
591
+ "semantic": "beta",
592
+ "buffer": { "type": "read-only-storage" },
593
+ "elementType": "$vectorScalar",
594
+ "length": "$HIDDEN_LEN"
595
+ },
596
+ {
597
+ "name": "bias",
598
+ "arg": "biasT",
599
+ "semantic": "bias",
600
+ "buffer": { "type": "read-only-storage" },
601
+ "elementType": "$vectorScalar",
602
+ "length": "$HIDDEN_LEN"
603
+ },
604
+ {
605
+ "name": "output",
606
+ "arg": "outputT",
607
+ "semantic": "output",
608
+ "buffer": { "type": "storage" },
609
+ "elementType": "$vectorScalar"
610
+ },
611
+ {
612
+ "name": "params",
613
+ "semantic": "kernel.params",
614
+ "buffer": { "type": "uniform" },
615
+ "struct": {
616
+ "name": "Params",
617
+ "fields": [
618
+ { "name": "rows", "type": "u32", "value": "rowCount" },
619
+ {
620
+ "name": "rowStride",
621
+ "type": "u32",
622
+ "value": "max(1, min(rowCount, device.limits.maxComputeWorkgroupsPerDimension))"
623
+ },
624
+ { "name": "epsilon", "type": "f32", "value": "attrs.epsilon" }
625
+ ]
626
+ }
627
+ }
628
+ ],
629
+ "vec4_no_beta_output_only": [
630
+ {
631
+ "name": "input",
632
+ "arg": "inputT",
633
+ "semantic": "input",
634
+ "buffer": { "type": "read-only-storage" },
635
+ "elementType": "$vectorScalar"
636
+ },
637
+ {
638
+ "name": "skip",
639
+ "arg": "skipT",
640
+ "semantic": "skip",
641
+ "buffer": { "type": "read-only-storage" },
642
+ "elementType": "$vectorScalar"
643
+ },
644
+ {
645
+ "name": "gamma",
646
+ "arg": "gammaT",
647
+ "semantic": "gamma",
648
+ "buffer": { "type": "read-only-storage" },
649
+ "elementType": "$vectorScalar",
650
+ "length": "$HIDDEN_LEN"
651
+ },
652
+ {
653
+ "name": "output",
654
+ "arg": "outputT",
655
+ "semantic": "output",
656
+ "buffer": { "type": "storage" },
657
+ "elementType": "$vectorScalar"
658
+ },
659
+ {
660
+ "name": "params",
661
+ "semantic": "kernel.params",
662
+ "buffer": { "type": "uniform" },
663
+ "struct": {
664
+ "name": "Params",
665
+ "fields": [
666
+ { "name": "rows", "type": "u32", "value": "rowCount" },
667
+ {
668
+ "name": "rowStride",
669
+ "type": "u32",
670
+ "value": "max(1, min(rowCount, device.limits.maxComputeWorkgroupsPerDimension))"
671
+ },
672
+ { "name": "epsilon", "type": "f32", "value": "attrs.epsilon" }
673
+ ]
674
+ }
675
+ }
676
+ ],
677
+ "vec4_beta_broadcast_output_only": [
678
+ {
679
+ "name": "input",
680
+ "arg": "inputT",
681
+ "semantic": "input",
682
+ "buffer": { "type": "read-only-storage" },
683
+ "elementType": "$vectorScalar"
684
+ },
685
+ {
686
+ "name": "skip",
687
+ "arg": "skipT",
688
+ "semantic": "skip",
689
+ "buffer": { "type": "read-only-storage" },
690
+ "elementType": "$vectorScalar"
691
+ },
692
+ {
693
+ "name": "gamma",
694
+ "arg": "gammaT",
695
+ "semantic": "gamma",
696
+ "buffer": { "type": "read-only-storage" },
697
+ "elementType": "$vectorScalar",
698
+ "length": "$HIDDEN_LEN"
699
+ },
700
+ {
701
+ "name": "beta",
702
+ "arg": "betaT",
703
+ "semantic": "beta",
704
+ "buffer": { "type": "read-only-storage" },
705
+ "elementType": "$vectorScalar",
706
+ "length": "$HIDDEN_LEN"
707
+ },
708
+ {
709
+ "name": "output",
710
+ "arg": "outputT",
711
+ "semantic": "output",
712
+ "buffer": { "type": "storage" },
713
+ "elementType": "$vectorScalar"
714
+ },
715
+ {
716
+ "name": "params",
717
+ "semantic": "kernel.params",
718
+ "buffer": { "type": "uniform" },
719
+ "struct": {
720
+ "name": "Params",
721
+ "fields": [
722
+ { "name": "rows", "type": "u32", "value": "dim(shapes.inputT, 0) * dim(shapes.inputT, 1)" },
723
+ {
724
+ "name": "rowStride",
725
+ "type": "u32",
726
+ "value": "max(1, min(broadcastRows, device.limits.maxComputeWorkgroupsPerDimension))"
727
+ },
728
+ { "name": "epsilon", "type": "f32", "value": "attrs.epsilon" },
729
+ { "name": "skipRows", "type": "u32", "value": "numel(shapes.skipT) / broadcastHiddenSize" }
730
+ ]
731
+ }
732
+ }
733
+ ]
734
+ },
735
+ "variants": [
736
+ {
737
+ "id": "beta_output_only_vec4_broadcast",
738
+ "priority": 19,
739
+ "when": ["broadcastOutputOnlyContract", "broadcastResourcesFit", "broadcastDispatchFits"],
740
+ "constants": { "scalar": "\"f32\"", "vectorScalar": "\"vec4<f32>\"", "HIDDEN_LEN": "broadcastHiddenSize / 4" },
741
+ "passes": [
742
+ {
743
+ "id": "main",
744
+ "name": "SkipLayerNormalization.BroadcastSkip",
745
+ "source": {
746
+ "shader": "norm-skip-row-vec4.wgsl.jinja",
747
+ "inputs": {
748
+ "simplified": false,
749
+ "hasBias": false,
750
+ "hasBeta": true,
751
+ "writeResidualSum": false,
752
+ "usesF16": false,
753
+ "broadcastSkip": true,
754
+ "hidden": "broadcastHiddenSize",
755
+ "hiddenVec": "broadcastHiddenSize / 4",
756
+ "wg": "broadcastSkipWgVec4",
757
+ "vecType": "\"vec4<f32>\"",
758
+ "useSubgroups": "hasSubgroups"
759
+ }
760
+ },
761
+ "subgroupCollectivesWidth": "portable",
762
+ "bindings": "vec4_beta_broadcast_output_only",
763
+ "dispatch": { "workgroups": "broadcastRows" }
764
+ }
765
+ ]
766
+ },
767
+ {
768
+ "id": "beta_bias_vec4",
769
+ "priority": 15,
770
+ "when": ["f32_beta_bias_residual_contract", "vec4Aligned", "hasSubgroups or \"bias\" == \"bias\" or portableWideExecution", "normResourcesFit", "rowDispatchFits"],
771
+ "constants": {
772
+ "scalar": "\"f32\"",
773
+ "vectorScalar": "\"vec4<f32>\"",
774
+ "hasBias": "\"bias\" == \"bias\"",
775
+ "hiddenSize": "hiddenSize",
776
+ "workgroupSize": "skipWg",
777
+ "HIDDEN_LEN": "hiddenSize / 4"
778
+ },
779
+ "passes": [
780
+ {
781
+ "id": "normalize",
782
+ "name": "SkipLayerNormalization.Vec4.Normalize",
783
+ "source": {
784
+ "shader": "norm-skip-row-vec4.wgsl.jinja",
785
+ "inputs": {
786
+ "simplified": false,
787
+ "hasBias": "\"bias\" == \"bias\"",
788
+ "hasBeta": true,
789
+ "writeResidualSum": true,
790
+ "usesF16": false,
791
+ "hidden": "hiddenSize",
792
+ "hiddenVec": "hiddenSize / 4",
793
+ "wg": "skipWgVec4",
794
+ "vecType": "\"vec4<f32>\"",
795
+ "useSubgroups": "hasSubgroups"
796
+ }
797
+ },
798
+ "subgroupCollectivesWidth": "portable",
799
+ "bindings": "vec4_bias_output_residual",
800
+ "dispatch": { "workgroups": "rowCount" }
801
+ }
802
+ ]
803
+ },
804
+ {
805
+ "id": "beta_bias_row",
806
+ "priority": 5,
807
+ "when": ["f32_beta_bias_residual_contract", "normResourcesFit", "rowDispatchFits"],
808
+ "constants": {
809
+ "simplified": false,
810
+ "useSubgroups": "hasSubgroups",
811
+ "hasBeta": true,
812
+ "writeResidualSum": true,
813
+ "hasBias": "\"bias\" == \"bias\"",
814
+ "scalar": "\"f32\"",
815
+ "hiddenSize": "hiddenSize",
816
+ "workgroupSize": "skipWg",
817
+ "HIDDEN_LEN": "hiddenSize"
818
+ },
819
+ "passes": [
820
+ {
821
+ "id": "normalize",
822
+ "name": "SkipLayerNormalization.Row.Normalize",
823
+ "shader": "norm-skip-row.wgsl.jinja",
824
+ "subgroupCollectivesWidth": "portable",
825
+ "bindings": "scalar_bias_output_residual",
826
+ "dispatch": { "workgroups": "rowCount" },
827
+ "constants": { "writeResidualSum": true }
828
+ }
829
+ ]
830
+ },
831
+ {
832
+ "id": "beta_bias_vec4_f16",
833
+ "priority": 21,
834
+ "when": ["f16_beta_bias_residual_contract", "vec4Aligned", "normResourcesFit", "rowDispatchFits"],
835
+ "constants": { "scalar": "\"f16\"", "vectorScalar": "\"vec4<f16>\"", "HIDDEN_LEN": "hiddenSize / 4" },
836
+ "passes": [
837
+ {
838
+ "id": "main",
839
+ "name": "SkipLayerNormalization.Vec4",
840
+ "source": {
841
+ "shader": "norm-skip-row-vec4.wgsl.jinja",
842
+ "inputs": {
843
+ "simplified": false,
844
+ "hasBias": true,
845
+ "hasBeta": true,
846
+ "writeResidualSum": true,
847
+ "usesF16": true,
848
+ "hidden": "hiddenSize",
849
+ "hiddenVec": "hiddenSize / 4",
850
+ "wg": "skipWgVec4",
851
+ "vecType": "\"vec4<f16>\"",
852
+ "useSubgroups": "hasSubgroups"
853
+ }
854
+ },
855
+ "subgroupCollectivesWidth": "portable",
856
+ "bindings": "vec4_bias_output_residual",
857
+ "dispatch": { "workgroups": "rowCount" }
858
+ }
859
+ ]
860
+ },
861
+ {
862
+ "id": "no_beta_output_only_vec4",
863
+ "priority": 20,
864
+ "when": ["f32_no_beta_output_contract", "vec4Aligned", "normResourcesFit", "rowDispatchFits"],
865
+ "constants": { "scalar": "\"f32\"", "vectorScalar": "\"vec4<f32>\"", "HIDDEN_LEN": "hiddenSize / 4" },
866
+ "passes": [
867
+ {
868
+ "id": "main",
869
+ "name": "SkipLayerNormalization.NoBetaOutputOnly.Vec4",
870
+ "source": {
871
+ "shader": "norm-skip-row-vec4.wgsl.jinja",
872
+ "inputs": {
873
+ "simplified": false,
874
+ "hasBias": false,
875
+ "hasBeta": false,
876
+ "writeResidualSum": false,
877
+ "usesF16": false,
878
+ "hidden": "hiddenSize",
879
+ "hiddenVec": "hiddenSize / 4",
880
+ "wg": "skipWgVec4",
881
+ "vecType": "\"vec4<f32>\"",
882
+ "useSubgroups": "hasSubgroups"
883
+ }
884
+ },
885
+ "subgroupCollectivesWidth": "portable",
886
+ "bindings": "vec4_no_beta_output_only",
887
+ "dispatch": { "workgroups": "rowCount" }
888
+ }
889
+ ]
890
+ },
891
+ {
892
+ "id": "no_beta_output_only_row",
893
+ "priority": 10,
894
+ "when": ["f32_no_beta_output_contract", "normResourcesFit", "rowDispatchFits"],
895
+ "constants": {
896
+ "simplified": false,
897
+ "hasBias": false,
898
+ "hasBeta": false,
899
+ "writeResidualSum": false,
900
+ "useSubgroups": "hasSubgroups",
901
+ "scalar": "\"f32\"",
902
+ "hiddenSize": "hiddenSize",
903
+ "workgroupSize": "skipWg",
904
+ "HIDDEN_LEN": "hiddenSize"
905
+ },
906
+ "passes": [
907
+ {
908
+ "id": "main",
909
+ "name": "SkipLayerNormalization.NoBetaOutputOnly.Row",
910
+ "shader": "norm-skip-row.wgsl.jinja",
911
+ "subgroupCollectivesWidth": "portable",
912
+ "bindings": "scalar_no_beta_output_only",
913
+ "dispatch": { "workgroups": "rowCount" }
914
+ }
915
+ ]
916
+ },
917
+ {
918
+ "id": "beta_no_bias_vec4",
919
+ "priority": 20,
920
+ "when": ["f32_beta_no_bias_residual_contract", "vec4Aligned", "hasSubgroups or portableWideExecution", "normResourcesFit", "rowDispatchFits"],
921
+ "constants": {
922
+ "scalar": "\"f32\"",
923
+ "vectorScalar": "\"vec4<f32>\"",
924
+ "hasBias": "\"no_bias\" == \"bias\"",
925
+ "hiddenSize": "hiddenSize",
926
+ "workgroupSize": "skipWg",
927
+ "HIDDEN_LEN": "hiddenSize / 4"
928
+ },
929
+ "passes": [
930
+ {
931
+ "id": "main",
932
+ "name": "SkipLayerNormalization.Vec4",
933
+ "source": {
934
+ "shader": "norm-skip-row-vec4.wgsl.jinja",
935
+ "inputs": {
936
+ "simplified": false,
937
+ "hasBias": "\"no_bias\" == \"bias\"",
938
+ "hasBeta": true,
939
+ "writeResidualSum": true,
940
+ "usesF16": false,
941
+ "hidden": "hiddenSize",
942
+ "hiddenVec": "hiddenSize / 4",
943
+ "wg": "skipWgVec4",
944
+ "vecType": "\"vec4<f32>\"",
945
+ "useSubgroups": "hasSubgroups"
946
+ }
947
+ },
948
+ "subgroupCollectivesWidth": "portable",
949
+ "bindings": "vec4_no_bias_residual",
950
+ "dispatch": { "workgroups": "rowCount" }
951
+ }
952
+ ]
953
+ },
954
+ {
955
+ "id": "beta_no_bias_row",
956
+ "priority": 10,
957
+ "when": ["f32_beta_no_bias_residual_contract", "normResourcesFit", "rowDispatchFits"],
958
+ "constants": {
959
+ "simplified": false,
960
+ "useSubgroups": "hasSubgroups",
961
+ "hasBeta": true,
962
+ "writeResidualSum": true,
963
+ "hasBias": "\"no_bias\" == \"bias\"",
964
+ "scalar": "\"f32\"",
965
+ "hiddenSize": "hiddenSize",
966
+ "workgroupSize": "skipWg",
967
+ "HIDDEN_LEN": "hiddenSize"
968
+ },
969
+ "passes": [
970
+ {
971
+ "id": "main",
972
+ "name": "SkipLayerNormalization.Row",
973
+ "shader": "norm-skip-row.wgsl.jinja",
974
+ "subgroupCollectivesWidth": "portable",
975
+ "bindings": "scalar_no_bias_residual",
976
+ "dispatch": { "workgroups": "rowCount" }
977
+ }
978
+ ]
979
+ },
980
+ {
981
+ "id": "beta_no_bias_output_only_vec4",
982
+ "priority": 20,
983
+ "when": ["f32_beta_no_bias_output_only_contract", "vec4Aligned", "hasSubgroups or \"no_bias\" == \"bias\" or portableWideExecution", "normResourcesFit", "rowDispatchFits"],
984
+ "constants": {
985
+ "scalar": "\"f32\"",
986
+ "vectorScalar": "\"vec4<f32>\"",
987
+ "hasBias": "\"no_bias\" == \"bias\"",
988
+ "hiddenSize": "hiddenSize",
989
+ "workgroupSize": "skipWg",
990
+ "HIDDEN_LEN": "hiddenSize / 4"
991
+ },
992
+ "passes": [
993
+ {
994
+ "id": "main",
995
+ "name": "SkipLayerNormalization.Vec4",
996
+ "source": {
997
+ "shader": "norm-skip-row-vec4.wgsl.jinja",
998
+ "inputs": {
999
+ "simplified": false,
1000
+ "hasBias": "\"no_bias\" == \"bias\"",
1001
+ "hasBeta": true,
1002
+ "writeResidualSum": false,
1003
+ "usesF16": false,
1004
+ "hidden": "hiddenSize",
1005
+ "hiddenVec": "hiddenSize / 4",
1006
+ "wg": "skipWgVec4",
1007
+ "vecType": "\"vec4<f32>\"",
1008
+ "useSubgroups": "hasSubgroups"
1009
+ }
1010
+ },
1011
+ "subgroupCollectivesWidth": "portable",
1012
+ "bindings": "vec4_no_bias_output_only",
1013
+ "dispatch": { "workgroups": "rowCount" }
1014
+ }
1015
+ ]
1016
+ },
1017
+ {
1018
+ "id": "beta_no_bias_output_only_row",
1019
+ "priority": 10,
1020
+ "when": ["f32_beta_no_bias_output_only_contract", "normResourcesFit", "rowDispatchFits"],
1021
+ "constants": {
1022
+ "simplified": false,
1023
+ "useSubgroups": "hasSubgroups",
1024
+ "hasBeta": true,
1025
+ "writeResidualSum": false,
1026
+ "hasBias": "\"no_bias\" == \"bias\"",
1027
+ "scalar": "\"f32\"",
1028
+ "hiddenSize": "hiddenSize",
1029
+ "workgroupSize": "skipWg",
1030
+ "HIDDEN_LEN": "hiddenSize"
1031
+ },
1032
+ "passes": [
1033
+ {
1034
+ "id": "main",
1035
+ "name": "SkipLayerNormalization.Row",
1036
+ "shader": "norm-skip-row.wgsl.jinja",
1037
+ "subgroupCollectivesWidth": "portable",
1038
+ "bindings": "scalar_no_bias_output_only",
1039
+ "dispatch": { "workgroups": "rowCount" }
1040
+ }
1041
+ ]
1042
+ },
1043
+ {
1044
+ "id": "beta_bias_output_only_vec4",
1045
+ "priority": 20,
1046
+ "when": ["f32_beta_bias_output_only_contract", "vec4Aligned", "hasSubgroups or \"bias\" == \"bias\" or portableWideExecution", "normResourcesFit", "rowDispatchFits"],
1047
+ "constants": {
1048
+ "scalar": "\"f32\"",
1049
+ "vectorScalar": "\"vec4<f32>\"",
1050
+ "hasBias": "\"bias\" == \"bias\"",
1051
+ "hiddenSize": "hiddenSize",
1052
+ "workgroupSize": "skipWg",
1053
+ "HIDDEN_LEN": "hiddenSize / 4"
1054
+ },
1055
+ "passes": [
1056
+ {
1057
+ "id": "main",
1058
+ "name": "SkipLayerNormalization.Vec4",
1059
+ "source": {
1060
+ "shader": "norm-skip-row-vec4.wgsl.jinja",
1061
+ "inputs": {
1062
+ "simplified": false,
1063
+ "hasBias": "\"bias\" == \"bias\"",
1064
+ "hasBeta": true,
1065
+ "writeResidualSum": false,
1066
+ "usesF16": false,
1067
+ "hidden": "hiddenSize",
1068
+ "hiddenVec": "hiddenSize / 4",
1069
+ "wg": "skipWgVec4",
1070
+ "vecType": "\"vec4<f32>\"",
1071
+ "useSubgroups": "hasSubgroups"
1072
+ }
1073
+ },
1074
+ "subgroupCollectivesWidth": "portable",
1075
+ "bindings": "vec4_bias_output_only",
1076
+ "dispatch": { "workgroups": "rowCount" }
1077
+ }
1078
+ ]
1079
+ },
1080
+ {
1081
+ "id": "beta_bias_output_only_row",
1082
+ "priority": 10,
1083
+ "when": ["f32_beta_bias_output_only_contract", "normResourcesFit", "rowDispatchFits"],
1084
+ "constants": {
1085
+ "simplified": false,
1086
+ "useSubgroups": "hasSubgroups",
1087
+ "hasBeta": true,
1088
+ "writeResidualSum": false,
1089
+ "hasBias": "\"bias\" == \"bias\"",
1090
+ "scalar": "\"f32\"",
1091
+ "hiddenSize": "hiddenSize",
1092
+ "workgroupSize": "skipWg",
1093
+ "HIDDEN_LEN": "hiddenSize"
1094
+ },
1095
+ "passes": [
1096
+ {
1097
+ "id": "main",
1098
+ "name": "SkipLayerNormalization.Row",
1099
+ "shader": "norm-skip-row.wgsl.jinja",
1100
+ "subgroupCollectivesWidth": "portable",
1101
+ "bindings": "scalar_bias_output_only",
1102
+ "dispatch": { "workgroups": "rowCount" }
1103
+ }
1104
+ ]
1105
+ }
1106
+ ],
1107
+ "tunables": { "MAX_WORKGROUP_SIZE": 256 }
1108
+ }
build/webgpu/metadata.json ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "com.microsoft.SkipLayerNormalization",
3
+ "id": "_com_microsoft_skiplayernormalization_webgpu_1767bd7",
4
+ "version": 1,
5
+ "license": "Apache-2.0",
6
+ "backend": { "type": "webgpu" },
7
+ "digest": {
8
+ "algorithm": "sha256",
9
+ "files": {
10
+ "bench.json": "STz1miuskWFMJijUblWNS3pG/DHJsRwQo0M+up/ng3s=",
11
+ "manifest.json": "MM5RYZ3xnC2rbelhnBH9kdS+qwkWaQmvEVXhBmag8jg=",
12
+ "norm-skip-row-vec4.wgsl.jinja": "qHoa8QjoRD1rgxTGGuJpfVb16Jou8PEg2CF1GjDt78s=",
13
+ "norm-skip-row.wgsl.jinja": "ck3s/G7WRph2YZRJs4LTft+R0IDjMPeE5Oy4UXDsqQs=",
14
+ "test.json": "Dkphsy4eO4Z8f2ZY1wfBJVmLcKNVWcOupJHOighE3RU="
15
+ }
16
+ },
17
+ "provenance": { "kernel": { "sha": "2e7068faf55e7f43df740015f6d1ee49391a41c5", "dirty": false } },
18
+ "webgpu": { "manifestSpec": "1.0", "specialized": true, "opPath": "ops/com.microsoft.SkipLayerNormalization" }
19
+ }
build/webgpu/norm-skip-row-vec4.wgsl.jinja ADDED
@@ -0,0 +1,145 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% macro wgsl_tree_fold_stmt(a, op, idx, svar) %}
2
+ {% if op == "max" %}
3
+ {{ a }}[{{ idx }}] = max({{ a }}[{{ idx }}], {{ a }}[{{ idx }} + {{ svar }}]);
4
+ {%- else %}
5
+ {{ a }}[{{ idx }}] = {{ a }}[{{ idx }}] + {{ a }}[{{ idx }} + {{ svar }}];
6
+ {%- endif %}
7
+ {% endmacro %}
8
+ {% macro wgsl_tree_fold(arrays, op="add", idx="lid", wg="WORKGROUP_SIZE", svar="stride", typed=false, form="tail", breakInline=false, bodyInline=false, barrierFirst=false) %}
9
+ var {{ svar }}{{ ": u32 " if typed else " " }}= {{ wg }} / 2u;
10
+ loop {
11
+ {% if form == "head" %}
12
+ {% if breakInline %}
13
+ if ({{ svar }} == 0u) { break; }
14
+ {% else %}
15
+ if ({{ svar }} == 0u) {
16
+ break;
17
+ }
18
+ {% endif %}
19
+ {% endif %}
20
+ {% if bodyInline %}
21
+ if ({{ idx }} < {{ svar }}) { {{ wgsl_tree_fold_stmt(arrays[0], op, idx, svar) }} }
22
+ {% else %}
23
+ if ({{ idx }} < {{ svar }}) {
24
+ {% for a in arrays %}
25
+ {{ wgsl_tree_fold_stmt(a, op, idx, svar) }}
26
+ {% endfor %}
27
+ }
28
+ {% endif %}
29
+ {% if form == "head" %}
30
+ {% if barrierFirst %}
31
+ workgroupBarrier();
32
+ {{ svar }} = {{ svar }} / 2u;
33
+ {% else %}
34
+ {{ svar }} = {{ svar }} / 2u;
35
+ workgroupBarrier();
36
+ {% endif %}
37
+ {% else %}
38
+ workgroupBarrier();
39
+ if ({{ svar }} == 1u) {
40
+ break;
41
+ }
42
+ {{ svar }} = {{ svar }} / 2u;
43
+ {% endif %}
44
+ }
45
+ {%- endmacro %}{% set useSubgroups = source.useSubgroups %}
46
+ {% if source.usesF16 %}
47
+ enable f16;
48
+ {% endif %}
49
+ {% if useSubgroups %}
50
+ enable subgroups;
51
+ {% endif %}
52
+ {{ env.wgsl.resourceDeclarations }}
53
+
54
+ const HIDDEN: u32 = {{ source.hidden }}u;
55
+ const HIDDEN_V: u32 = {{ source.hiddenVec }}u;
56
+ const WG: u32 = {{ source.wg }}u;
57
+
58
+ var<workgroup> sg_partials: array<vec2<f32>, WG>;
59
+
60
+ fn reduce_pair(value: vec2<f32>{% if useSubgroups %}, sg_lane: u32, sg_id: u32, num_sg: u32{% else %}, tid: u32{% endif %}) -> vec2<f32> {
61
+ {% if useSubgroups %}
62
+ let s = vec2<f32>(subgroupAdd(value.x), subgroupAdd(value.y));
63
+ if (num_sg == 1u) {
64
+ return s;
65
+ }
66
+ if (sg_lane == 0u) {
67
+ sg_partials[sg_id] = s;
68
+ }
69
+ workgroupBarrier();
70
+ var total = vec2<f32>(0.0, 0.0);
71
+ for (var i = 0u; i < num_sg; i = i + 1u) {
72
+ total = total + sg_partials[i];
73
+ }
74
+ return total;
75
+ {% else %}
76
+ // No-subgroup tier: workgroup barrier tree-reduction (WG is a power of two).
77
+ sg_partials[tid] = value;
78
+ workgroupBarrier();
79
+ {{ wgsl_tree_fold(["sg_partials"], idx="tid", wg="WG", form="head", breakInline=true) }}
80
+ return sg_partials[0];
81
+ {% endif %}
82
+ }
83
+
84
+ // 4 contiguous residual elements (input[idx] + skip[skip_idx] [+ bias]) at vec4
85
+ // index `vi`. skip_idx == idx for the normal (non-broadcast) path; for a skip
86
+ // that broadcasts across the leading/batch dim uses a folded index.
87
+ fn residual_value(idx: u32, skip_idx: u32{% if source.hasBias %}, vi: u32{% endif %}) -> vec4<f32> {
88
+ var value = vec4<f32>(input[idx]) + vec4<f32>(skip[skip_idx]);
89
+ {% if source.hasBias %}
90
+ value = value + vec4<f32>(bias[vi]);
91
+ {% endif %}
92
+ return value;
93
+ }
94
+
95
+ @compute @workgroup_size(WG, 1, 1)
96
+ fn main(
97
+ @builtin(workgroup_id) wg_id: vec3<u32>,
98
+ @builtin(local_invocation_id) lid: vec3<u32>{% if useSubgroups %},
99
+ @builtin(subgroup_invocation_id) sg_lane: u32,
100
+ @builtin(subgroup_id) sg_id: u32,
101
+ @builtin(num_subgroups) num_sg: u32{% endif %}
102
+ ) {
103
+ let row = wg_id.x + wg_id.y * params.rowStride;
104
+ if (row >= params.rows) {
105
+ return;
106
+ }
107
+ let tid = lid.x;
108
+ let base = row * HIDDEN_V;
109
+ {% if source.broadcastSkip %}
110
+ // skip broadcasts across the batch dim: fold row into [0, skipRows) so every
111
+ // batch reuses the same skip row (skipRows == params.rows ⇒ identity).
112
+ let skip_base = (row % params.skipRows) * HIDDEN_V;
113
+ {% else %}
114
+ let skip_base = base;
115
+ {% endif %}
116
+
117
+ let shift = residual_value(base, skip_base{% if source.hasBias %}, 0u{% endif %}).x;
118
+
119
+ var acc = vec2<f32>(0.0, 0.0);
120
+ for (var i = tid; i < HIDDEN_V; i = i + WG) {
121
+ let v = residual_value(base + i, skip_base + i{% if source.hasBias %}, i{% endif %});
122
+ let d = v - vec4<f32>(shift);
123
+ acc.x = acc.x + d.x + d.y + d.z + d.w;
124
+ acc.y = acc.y + dot(d, d);
125
+ }
126
+
127
+ let totals = reduce_pair(acc{% if useSubgroups %}, sg_lane, sg_id, num_sg{% else %}, tid{% endif %});
128
+ let mean_d = totals.x / f32(HIDDEN);
129
+ let variance = max(totals.y / f32(HIDDEN) - mean_d * mean_d, 0.0);
130
+ let row_inv = inverseSqrt(variance + params.epsilon);
131
+ let row_mean = shift + mean_d;
132
+
133
+ for (var i = tid; i < HIDDEN_V; i = i + WG) {
134
+ let idx = base + i;
135
+ let residual = residual_value(idx, skip_base + i{% if source.hasBias %}, i{% endif %});
136
+ {% if source.writeResidualSum %}
137
+ input_skip_bias_sum[idx] = {{ source.vecType }}(residual);
138
+ {% endif %}
139
+ var value = (residual - vec4<f32>(row_mean)) * row_inv * vec4<f32>(gamma[i]);
140
+ {% if source.hasBeta %}
141
+ value = value + vec4<f32>(beta[i]);
142
+ {% endif %}
143
+ output[idx] = {{ source.vecType }}(value);
144
+ }
145
+ }
build/webgpu/norm-skip-row.wgsl.jinja ADDED
@@ -0,0 +1,226 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% macro wgsl_tree_fold_stmt(a, op, idx, svar) %}
2
+ {% if op == "max" %}
3
+ {{ a }}[{{ idx }}] = max({{ a }}[{{ idx }}], {{ a }}[{{ idx }} + {{ svar }}]);
4
+ {%- else %}
5
+ {{ a }}[{{ idx }}] = {{ a }}[{{ idx }}] + {{ a }}[{{ idx }} + {{ svar }}];
6
+ {%- endif %}
7
+ {% endmacro %}
8
+ {% macro wgsl_tree_fold(arrays, op="add", idx="lid", wg="WORKGROUP_SIZE", svar="stride", typed=false, form="tail", breakInline=false, bodyInline=false, barrierFirst=false) %}
9
+ var {{ svar }}{{ ": u32 " if typed else " " }}= {{ wg }} / 2u;
10
+ loop {
11
+ {% if form == "head" %}
12
+ {% if breakInline %}
13
+ if ({{ svar }} == 0u) { break; }
14
+ {% else %}
15
+ if ({{ svar }} == 0u) {
16
+ break;
17
+ }
18
+ {% endif %}
19
+ {% endif %}
20
+ {% if bodyInline %}
21
+ if ({{ idx }} < {{ svar }}) { {{ wgsl_tree_fold_stmt(arrays[0], op, idx, svar) }} }
22
+ {% else %}
23
+ if ({{ idx }} < {{ svar }}) {
24
+ {% for a in arrays %}
25
+ {{ wgsl_tree_fold_stmt(a, op, idx, svar) }}
26
+ {% endfor %}
27
+ }
28
+ {% endif %}
29
+ {% if form == "head" %}
30
+ {% if barrierFirst %}
31
+ workgroupBarrier();
32
+ {{ svar }} = {{ svar }} / 2u;
33
+ {% else %}
34
+ {{ svar }} = {{ svar }} / 2u;
35
+ workgroupBarrier();
36
+ {% endif %}
37
+ {% else %}
38
+ workgroupBarrier();
39
+ if ({{ svar }} == 1u) {
40
+ break;
41
+ }
42
+ {{ svar }} = {{ svar }} / 2u;
43
+ {% endif %}
44
+ }
45
+ {%- endmacro %}
46
+
47
+ /* One workgroup normalizes each row of residual = input + skip, with an
48
+ * optional bias. */
49
+ {% set degenerateRow = (not simplified) and hiddenSize == 1 %}
50
+ {% if useSubgroups and not degenerateRow %}
51
+ enable subgroups;
52
+ {% endif %}
53
+ {{ env.wgsl.resourceDeclarations }}
54
+
55
+ {% if not degenerateRow or writeResidualSum %}
56
+ const HIDDEN: u32 = {{ hiddenSize }}u;
57
+ {% endif %}
58
+ const WG: u32 = {{ workgroupSize }}u;
59
+ {% if simplified %}
60
+
61
+ var<workgroup> partial: array<f32, WG>;
62
+ {% macro wgsl_tree_reduce_f32(name, mode, buffer="partial", wg="WG", trailingBarrier=true) %}
63
+ fn {{ name }}(value: f32, tid: u32) -> f32 {
64
+ {{ buffer }}[tid] = value;
65
+ workgroupBarrier();
66
+ // Ceil-halving keeps every lane when the workgroup size is not a power of
67
+ // two. For even n this matches the power-of-two tree order; for odd n, lanes
68
+ // [0, n-half) fold the upper tail while the middle lane carries forward.
69
+ var n: u32 = {{ wg }};
70
+ loop {
71
+ let half = (n + 1u) / 2u;
72
+ if (tid < n - half) {
73
+ {% if mode == "max" %}
74
+ {{ buffer }}[tid] = max({{ buffer }}[tid], {{ buffer }}[tid + half]);
75
+ {% else %}
76
+ {{ buffer }}[tid] = {{ buffer }}[tid] + {{ buffer }}[tid + half];
77
+ {% endif %}
78
+ }
79
+ workgroupBarrier();
80
+ n = half;
81
+ if (n == 1u) {
82
+ break;
83
+ }
84
+ }
85
+ // The default trailing barrier makes this helper safe for back-to-back calls: every lane reads
86
+ // slot 0 here, so the next call's first store must not run until all lanes have read it.
87
+ // `trailingBarrier=false` is safe only when the buffer is never written again before kernel exit.
88
+ let reduced = {{ buffer }}[0];
89
+ {% if trailingBarrier %}
90
+ workgroupBarrier();
91
+ {% endif %}
92
+ return reduced;
93
+ }
94
+ {% endmacro %}
95
+
96
+ {{ wgsl_tree_reduce_f32("reduce_sum", "add", "partial", "WG") }}
97
+ var<workgroup> row_inv: f32;
98
+ {% else %}
99
+ {% if not degenerateRow %}
100
+
101
+ var<workgroup> pair_partial: array<vec2<f32>, WG>;
102
+
103
+ {% if useSubgroups %}
104
+ fn reduce_pair(value: vec2<f32>, sg_lane: u32, sg_id: u32, num_sg: u32) -> vec2<f32> {
105
+ let s = vec2<f32>(subgroupAdd(value.x), subgroupAdd(value.y));
106
+ if (num_sg == 1u) {
107
+ return s;
108
+ }
109
+ if (sg_lane == 0u) {
110
+ pair_partial[sg_id] = s;
111
+ }
112
+ workgroupBarrier();
113
+ var total = vec2<f32>(0.0, 0.0);
114
+ for (var i = 0u; i < num_sg; i = i + 1u) {
115
+ total = total + pair_partial[i];
116
+ }
117
+ return total;
118
+ }
119
+ {% else %}
120
+ fn reduce_pair(value: vec2<f32>, tid: u32) -> vec2<f32> {
121
+ pair_partial[tid] = value;
122
+ workgroupBarrier();
123
+ {{ wgsl_tree_fold(["pair_partial"], idx="tid", wg="WG", form="head") }}
124
+ return pair_partial[0];
125
+ }
126
+ {% endif %}
127
+ {% endif %}
128
+ {% endif %}
129
+
130
+ {% if not degenerateRow or writeResidualSum %}
131
+ fn residual_value(row: u32, d: u32) -> f32 {
132
+ let index = row * HIDDEN + d;
133
+ var value = f32(input[index]) + f32(skip[index]);
134
+ {% if hasBias %}
135
+ value = value + f32(bias[d]);
136
+ {% endif %}
137
+ return value;
138
+ }
139
+ {% endif %}
140
+
141
+ @compute @workgroup_size(WG, 1, 1)
142
+ fn main(
143
+ @builtin(workgroup_id) wg: vec3<u32>,
144
+ @builtin(num_workgroups) nwg: vec3<u32>{% if not degenerateRow %},
145
+ @builtin(local_invocation_id) lid: vec3<u32>{% endif %}{% if useSubgroups and not degenerateRow %},
146
+ @builtin(subgroup_invocation_id) sg_lane: u32,
147
+ @builtin(subgroup_id) sg_id: u32,
148
+ @builtin(num_subgroups) num_sg: u32{% endif %}
149
+ ) {
150
+ // 2D-folded row index: wg.y carries the high bits past the maxComputeWorkgroupsPerDimension
151
+ // workgroup-per-dimension dispatch limit. Reduces to wg.x when nwg.y == 1;
152
+ // the row >= params.rows guard drops the over-dispatched tail.
153
+ let row = wg.x + wg.y * nwg.x;
154
+ if (row >= params.rows) {
155
+ return;
156
+ }
157
+ {% if not degenerateRow %}
158
+ let tid = lid.x;
159
+ {% endif %}
160
+ {% if simplified %}
161
+
162
+ // RMS normalization uses one sum-of-squares sweep, without a mean or beta.
163
+
164
+ var local_sq = 0.0;
165
+ for (var d: u32 = tid; d < HIDDEN; d = d + WG) {
166
+ let value = residual_value(row, d);
167
+ local_sq = local_sq + value * value;
168
+ }
169
+ let sq = reduce_sum(local_sq, tid);
170
+ if (tid == 0u) {
171
+ row_inv = inverseSqrt(sq / f32(HIDDEN) + params.epsilon);
172
+ }
173
+ workgroupBarrier();
174
+
175
+ for (var d: u32 = tid; d < HIDDEN; d = d + WG) {
176
+ let index = row * HIDDEN + d;
177
+ let residual = residual_value(row, d);
178
+ {% if writeResidualSum %}
179
+ input_skip_bias_sum[index] = {{ scalar }}(residual);
180
+ {% endif %}
181
+ output[index] = {{ scalar }}(residual * row_inv * f32(gamma[d]));
182
+ }
183
+ {% elif degenerateRow %}
184
+
185
+ // HIDDEN == 1: the row's mean is its only element, so the centered value and
186
+ // the variance are exactly zero and the output reduces to beta. The closed
187
+ // form avoids computing that zero by subtracting two equal rounded values.
188
+ let row_inv = inverseSqrt(params.epsilon);
189
+ {% if writeResidualSum %}
190
+ let residual = residual_value(row, 0u);
191
+ input_skip_bias_sum[row] = {{ scalar }}(residual);
192
+ {% endif %}
193
+ // 0.0 * row_inv keeps the IEEE result when epsilon == 0 makes row_inv +Inf.
194
+ output[row] = {{ scalar }}(0.0 * row_inv * f32(gamma[0]){% if hasBeta %} + f32(beta[0]){% endif %});
195
+ {% else %}
196
+
197
+ // Shifted moments: accumulating (x - x[0], (x - x[0])^2) keeps the sums
198
+ // small for rows with a large common offset; every thread reconstructs the
199
+ // row mean and variance from the merged pair.
200
+ let shift = residual_value(row, 0u);
201
+ var acc = vec2<f32>(0.0, 0.0);
202
+ for (var d = tid; d < HIDDEN; d = d + WG) {
203
+ let centered = residual_value(row, d) - shift;
204
+ acc.x = acc.x + centered;
205
+ acc.y = acc.y + centered * centered;
206
+ }
207
+
208
+ {% if useSubgroups %}
209
+ let totals = reduce_pair(acc, sg_lane, sg_id, num_sg);
210
+ {% else %}
211
+ let totals = reduce_pair(acc, tid);
212
+ {% endif %}
213
+ let mean_delta = totals.x / f32(HIDDEN);
214
+ let row_mean = shift + mean_delta;
215
+ let variance = max(totals.y / f32(HIDDEN) - mean_delta * mean_delta, 0.0);
216
+ let row_inv = inverseSqrt(variance + params.epsilon);
217
+ for (var d = tid; d < HIDDEN; d = d + WG) {
218
+ let index = row * HIDDEN + d;
219
+ let residual = residual_value(row, d);
220
+ {% if writeResidualSum %}
221
+ input_skip_bias_sum[index] = {{ scalar }}(residual);
222
+ {% endif %}
223
+ output[index] = {{ scalar }}((residual - row_mean) * row_inv * f32(gamma[d]){% if hasBeta %} + f32(beta[d]){% endif %});
224
+ }
225
+ {% endif %}
226
+ }
build/webgpu/test.json ADDED
@@ -0,0 +1,939 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "op": "com.microsoft.SkipLayerNormalization",
3
+ "fixtureArrays": {
4
+ "ort_batch2_bias_flattened_tokens_input_skipT": [0.1, -0.2, 0.3, 1, 0.5, 0.1, 0.4, 1.6, 1.8, -0.3, 0, 1, -0.5, 0.4, 0.8, -0.6],
5
+ "ort_batch2_flattened_tokens_input_inputT": [0.8, -0.5, 0, 1, 0.5, 0.2, 0.3, -0.6, 0.8, -0.5, 0, 1, 0.5, 0.2, 0.3, -0.6],
6
+ "ort_batch2_skip_broadcast_no_batch_size_output_outputT": [0.2843385934829712, -0.17090578377246857, -0.9289716482162476, 4.692415237426758, 0.4611165225505829, -0.21333980560302734, -0.29631003737449646, 3.5148544311523438, 0.2843385934829712, -0.17090578377246857, -0.9289716482162476, 4.692415237426758, 0.4611165225505829, -0.21333980560302734, -0.29631003737449646, 3.5148544311523438]
7
+ },
8
+ "cases": [
9
+ {
10
+ "name": "rank3_exact_skip_shape",
11
+ "provenance": {
12
+ "source": "onnxruntime/contrib_ops/cpu/bert/skip_layer_norm.cc",
13
+ "notes": "Pins the public rank-3 same-shape skip mode independently of the two documented broadcast forms."
14
+ },
15
+ "attrs": { "epsilon": 0.00001 },
16
+ "inputs": {
17
+ "inputT": { "dtype": "float32", "shape": [2, 2, 4], "data": { "kind": "linspace", "start": -1.5, "end": 1.5 } },
18
+ "skipT": { "dtype": "float32", "shape": [2, 2, 4], "data": { "kind": "linspace", "start": 0.75, "end": -0.25 } },
19
+ "gammaT": { "dtype": "float32", "shape": [4], "data": { "kind": "values", "values": [1.0, 0.5, 1.5, -0.25] } },
20
+ "betaT": { "dtype": "float32", "shape": [4], "data": { "kind": "values", "values": [0.1, -0.2, 0.3, -0.4] } }
21
+ },
22
+ "outputs": { "outputT": { "dtype": "float32", "shape": [2, 2, 4], "tolerance": 0.00002 } }
23
+ },
24
+ {
25
+ "name": "no_bias",
26
+ "attrs": { "epsilon": 0.00001 },
27
+ "inputs": {
28
+ "inputT": {
29
+ "dtype": "float32",
30
+ "shape": [3, 8],
31
+ "data": { "kind": "fillFloat32", "sinStep": 0.17, "cosStep": 0.31 }
32
+ },
33
+ "skipT": {
34
+ "dtype": "float32",
35
+ "shape": [3, 8],
36
+ "data": { "kind": "fillFloat32", "sinStep": 0.11, "cosStep": 0.23 }
37
+ },
38
+ "gammaT": {
39
+ "dtype": "float32",
40
+ "shape": [8],
41
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.41, "scale": 0.2 }
42
+ },
43
+ "betaT": {
44
+ "dtype": "float32",
45
+ "shape": [8],
46
+ "data": { "kind": "fillFloat32", "sinStep": 0.19, "cosStep": 0.13, "scale": 0.1 }
47
+ }
48
+ },
49
+ "outputs": {
50
+ "outputT": { "dtype": "float32", "shape": [3, 8], "tolerance": 0.00002 },
51
+ "residualT": { "dtype": "float32", "shape": [3, 8], "tolerance": 0.000001 }
52
+ }
53
+ },
54
+ {
55
+ "name": "f32_epsilon_zero_explicit_tiny_variance",
56
+ "attrs": { "epsilon": 0 },
57
+ "provenance": {
58
+ "source": "onnxruntime/contrib_ops/webgpu/bert/skip_layer_norm.h",
59
+ "test": "GetAttrOrDefault epsilon semantics",
60
+ "notes": "An explicit epsilon=0.0 must be honored, not replaced by the 1e-12 schema default via a truthiness fallback. The 1e-7-scale rows make that difference numerically observable."
61
+ },
62
+ "inputs": {
63
+ "inputT": {
64
+ "dtype": "float32",
65
+ "shape": [3, 8],
66
+ "data": { "kind": "fillFloat32", "sinStep": 0.17, "cosStep": 0.31, "scale": 1e-7 }
67
+ },
68
+ "skipT": {
69
+ "dtype": "float32",
70
+ "shape": [3, 8],
71
+ "data": { "kind": "fillFloat32", "sinStep": 0.11, "cosStep": 0.23, "scale": 1e-7 }
72
+ },
73
+ "gammaT": {
74
+ "dtype": "float32",
75
+ "shape": [8],
76
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.41, "scale": 0.2 }
77
+ },
78
+ "betaT": {
79
+ "dtype": "float32",
80
+ "shape": [8],
81
+ "data": { "kind": "fillFloat32", "sinStep": 0.19, "cosStep": 0.13, "scale": 0.1 }
82
+ }
83
+ },
84
+ "outputs": {
85
+ "outputT": { "dtype": "float32", "shape": [3, 8], "tolerance": 0.0001 },
86
+ "residualT": { "dtype": "float32", "shape": [3, 8], "tolerance": 1e-9 }
87
+ }
88
+ },
89
+ {
90
+ "name": "bias",
91
+ "attrs": { "epsilon": 0.00001 },
92
+ "inputs": {
93
+ "inputT": {
94
+ "dtype": "float32",
95
+ "shape": [3, 8],
96
+ "data": { "kind": "fillFloat32", "sinStep": 0.17, "cosStep": 0.31 }
97
+ },
98
+ "skipT": {
99
+ "dtype": "float32",
100
+ "shape": [3, 8],
101
+ "data": { "kind": "fillFloat32", "sinStep": 0.11, "cosStep": 0.23 }
102
+ },
103
+ "gammaT": {
104
+ "dtype": "float32",
105
+ "shape": [8],
106
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.41, "scale": 0.2 }
107
+ },
108
+ "betaT": {
109
+ "dtype": "float32",
110
+ "shape": [8],
111
+ "data": { "kind": "fillFloat32", "sinStep": 0.19, "cosStep": 0.13, "scale": 0.1 }
112
+ },
113
+ "biasT": {
114
+ "dtype": "float32",
115
+ "shape": [8],
116
+ "data": { "kind": "fillFloat32", "sinStep": 0.29, "cosStep": 0.17, "scale": 0.08 }
117
+ }
118
+ },
119
+ "outputs": {
120
+ "outputT": { "dtype": "float32", "shape": [3, 8], "tolerance": 0.00002 },
121
+ "residualT": { "dtype": "float32", "shape": [3, 8], "tolerance": 0.000001 }
122
+ }
123
+ },
124
+ {
125
+ "name": "zero_variance_returns_beta",
126
+ "attrs": { "epsilon": 0.00001 },
127
+ "inputs": {
128
+ "inputT": {
129
+ "dtype": "float32",
130
+ "shape": [2, 4],
131
+ "data": { "kind": "values", "values": [5.0, 5.0, 5.0, 5.0, -3.0, -3.0, -3.0, -3.0] }
132
+ },
133
+ "skipT": {
134
+ "dtype": "float32",
135
+ "shape": [2, 4],
136
+ "data": { "kind": "values", "values": [1.0, 1.0, 1.0, 1.0, 7.0, 7.0, 7.0, 7.0] }
137
+ },
138
+ "gammaT": { "dtype": "float32", "shape": [4], "data": { "kind": "values", "values": [10.0, -2.0, 3.0, 4.0] } },
139
+ "betaT": { "dtype": "float32", "shape": [4], "data": { "kind": "values", "values": [0.5, -1.0, 2.0, -3.0] } }
140
+ },
141
+ "outputs": {
142
+ "outputT": { "dtype": "float32", "shape": [2, 4], "tolerance": 0.000001 },
143
+ "residualT": { "dtype": "float32", "shape": [2, 4], "tolerance": 0.000001 }
144
+ }
145
+ },
146
+ {
147
+ "name": "hidden_size_one_bias_path",
148
+ "attrs": { "epsilon": 0.00001 },
149
+ "inputs": {
150
+ "inputT": { "dtype": "float32", "shape": [3, 1], "data": { "kind": "values", "values": [2.0, -4.0, 0.5] } },
151
+ "skipT": { "dtype": "float32", "shape": [3, 1], "data": { "kind": "values", "values": [3.0, 1.0, -0.5] } },
152
+ "gammaT": { "dtype": "float32", "shape": [1], "data": { "kind": "values", "values": [7.0] } },
153
+ "betaT": { "dtype": "float32", "shape": [1], "data": { "kind": "values", "values": [-2.0] } },
154
+ "biasT": { "dtype": "float32", "shape": [1], "data": { "kind": "values", "values": [0.25] } }
155
+ },
156
+ "outputs": {
157
+ "outputT": { "dtype": "float32", "shape": [3, 1], "tolerance": 0.000001 },
158
+ "residualT": { "dtype": "float32", "shape": [3, 1], "tolerance": 0.000001 }
159
+ }
160
+ },
161
+ {
162
+ "name": "hidden_size_one_bias_output_only",
163
+ "provenance": {
164
+ "notes": "Pins the scalar hidden-size-one closed form when the optional residual sum is not requested."
165
+ },
166
+ "attrs": { "epsilon": 0.00001 },
167
+ "inputs": {
168
+ "inputT": { "dtype": "float32", "shape": [1, 1], "data": { "kind": "values", "values": [2.0] } },
169
+ "skipT": { "dtype": "float32", "shape": [1, 1], "data": { "kind": "values", "values": [3.0] } },
170
+ "gammaT": { "dtype": "float32", "shape": [1], "data": { "kind": "values", "values": [7.0] } },
171
+ "betaT": { "dtype": "float32", "shape": [1], "data": { "kind": "values", "values": [-2.0] } },
172
+ "biasT": { "dtype": "float32", "shape": [1], "data": { "kind": "values", "values": [0.25] } }
173
+ },
174
+ "outputs": { "outputT": { "dtype": "float32", "shape": [1, 1], "tolerance": 0.000001 } }
175
+ },
176
+ {
177
+ "name": "hidden_size_one_no_beta_output_only",
178
+ "provenance": {
179
+ "notes": "Pins the supported no-beta hidden-size-one closed form: every centered value is zero, so the output is zero."
180
+ },
181
+ "attrs": { "epsilon": 0.00001 },
182
+ "inputs": {
183
+ "inputT": { "dtype": "float32", "shape": [1, 1], "data": { "kind": "values", "values": [2.0] } },
184
+ "skipT": { "dtype": "float32", "shape": [1, 1], "data": { "kind": "values", "values": [3.0] } },
185
+ "gammaT": { "dtype": "float32", "shape": [1], "data": { "kind": "values", "values": [7.0] } }
186
+ },
187
+ "outputs": { "outputT": { "dtype": "float32", "shape": [1, 1], "tolerance": 0.000001 } }
188
+ },
189
+ {
190
+ "name": "hidden_size_one_bias_rows65535_dispatch_edge",
191
+ "provenance": {
192
+ "notes": "Correctness sibling for the low-occupancy hidden=1 benchmark at rows=65535, the maximum single-dimension workgroup count edge."
193
+ },
194
+ "attrs": { "epsilon": 0.00001 },
195
+ "inputs": {
196
+ "inputT": {
197
+ "dtype": "float32",
198
+ "shape": [65535, 1],
199
+ "data": { "kind": "fillFloat32", "scale": 0.2, "sinStep": 0.017, "cosStep": 0.031 }
200
+ },
201
+ "skipT": {
202
+ "dtype": "float32",
203
+ "shape": [65535, 1],
204
+ "data": { "kind": "fillFloat32", "scale": 0.2, "sinStep": 0.011, "cosStep": 0.023 }
205
+ },
206
+ "gammaT": { "dtype": "float32", "shape": [1], "data": { "kind": "values", "values": [1.125] } },
207
+ "betaT": { "dtype": "float32", "shape": [1], "data": { "kind": "values", "values": [-0.25] } },
208
+ "biasT": { "dtype": "float32", "shape": [1], "data": { "kind": "values", "values": [0.125] } }
209
+ },
210
+ "outputs": {
211
+ "outputT": { "dtype": "float32", "shape": [65535, 1], "tolerance": 0.000001 },
212
+ "residualT": { "dtype": "float32", "shape": [65535, 1], "tolerance": 0.000001 }
213
+ }
214
+ },
215
+ {
216
+ "name": "large_mean_small_variance_centered",
217
+ "attrs": { "epsilon": 0.00001 },
218
+ "inputs": {
219
+ "inputT": {
220
+ "dtype": "float32",
221
+ "shape": [1, 4],
222
+ "data": { "kind": "values", "values": [40000.0, 40001.0, 40002.0, 40003.0] }
223
+ },
224
+ "skipT": {
225
+ "dtype": "float32",
226
+ "shape": [1, 4],
227
+ "data": { "kind": "values", "values": [-39999.0, -40000.0, -40001.0, -40002.0] }
228
+ },
229
+ "gammaT": { "dtype": "float32", "shape": [4], "data": { "kind": "values", "values": [1.0, 2.0, -1.0, 0.5] } },
230
+ "betaT": { "dtype": "float32", "shape": [4], "data": { "kind": "values", "values": [0.0, 0.5, -0.25, 1.0] } }
231
+ },
232
+ "outputs": {
233
+ "outputT": { "dtype": "float32", "shape": [1, 4], "tolerance": 0.000001 },
234
+ "residualT": { "dtype": "float32", "shape": [1, 4], "tolerance": 0.000001 }
235
+ }
236
+ },
237
+ {
238
+ "name": "ort_zero_tokens_null_input",
239
+ "provenance": {
240
+ "source": "onnxruntime/test/contrib_ops/skiplayernorm_op_test.cc",
241
+ "test": "SkipLayerNormTest.SkipLayerNormNullInput",
242
+ "notes": "ORT shape [1, 0, 4] is represented as lowered token rows [0, 4]."
243
+ },
244
+ "attrs": { "epsilon": 1e-12 },
245
+ "inputs": {
246
+ "inputT": { "dtype": "float32", "shape": [0, 4], "data": { "kind": "values", "values": [] } },
247
+ "skipT": { "dtype": "float32", "shape": [0, 4], "data": { "kind": "values", "values": [] } },
248
+ "gammaT": { "dtype": "float32", "shape": [4], "data": { "kind": "values", "values": [0.3, 0.2, 4.0, 2.2] } },
249
+ "betaT": { "dtype": "float32", "shape": [4], "data": { "kind": "values", "values": [0.2, 0.1, 0.4, 1.6] } }
250
+ },
251
+ "outputs": {
252
+ "outputT": { "dtype": "float32", "shape": [0, 4], "tolerance": 0 },
253
+ "residualT": { "dtype": "float32", "shape": [0, 4], "tolerance": 0 }
254
+ }
255
+ },
256
+ {
257
+ "name": "ort_batch1_flattened_tokens",
258
+ "provenance": {
259
+ "source": "onnxruntime/test/contrib_ops/skiplayernorm_op_test.cc",
260
+ "test": "SkipLayerNormTest.SkipLayerNormBatch1",
261
+ "notes": "ORT shape [1, 2, 4] is represented as [2, 4] tokens by this lowered kernel. Epsilon is omitted to exercise the schema default of 1e-12."
262
+ },
263
+ "inputs": {
264
+ "inputT": {
265
+ "dtype": "float32",
266
+ "shape": [2, 4],
267
+ "data": { "kind": "values", "values": [0.8, -0.5, 0.0, 1.0, 0.5, 0.2, 0.3, -0.6] }
268
+ },
269
+ "skipT": {
270
+ "dtype": "float32",
271
+ "shape": [2, 4],
272
+ "data": { "kind": "values", "values": [0.1, -0.2, 0.3, 1.0, 0.5, 0.1, 0.4, 1.6] }
273
+ },
274
+ "gammaT": { "dtype": "float32", "shape": [4], "data": { "kind": "values", "values": [0.3, 0.2, 4.0, 2.2] } },
275
+ "betaT": { "dtype": "float32", "shape": [4], "data": { "kind": "values", "values": [0.2, 0.1, 0.4, 1.6] } }
276
+ },
277
+ "outputs": {
278
+ "outputT": { "dtype": "float32", "shape": [2, 4], "tolerance": 0.00002 },
279
+ "residualT": { "dtype": "float32", "shape": [2, 4], "tolerance": 0.000001 }
280
+ }
281
+ },
282
+ {
283
+ "name": "ort_batch2_bias_flattened_tokens",
284
+ "provenance": {
285
+ "source": "onnxruntime/test/contrib_ops/skiplayernorm_op_test.cc",
286
+ "test": "SkipLayerNormTest.SkipLayerNormBatch2_Bias",
287
+ "notes": "ORT shape [2, 2, 4] is represented as [4, 4] tokens by this lowered kernel."
288
+ },
289
+ "attrs": { "epsilon": 1e-12 },
290
+ "inputs": {
291
+ "inputT": {
292
+ "dtype": "float32",
293
+ "shape": [4, 4],
294
+ "data": {
295
+ "kind": "values",
296
+ "values": [0.7, -0.4, -0.2, 1.2, 0.4, 0.3, 0.1, -0.4, 0.7, -0.4, -0.2, 1.2, 0.4, 0.3, 0.1, -0.4]
297
+ }
298
+ },
299
+ "skipT": {
300
+ "dtype": "float32",
301
+ "shape": [4, 4],
302
+ "data": {
303
+ "kind": "values",
304
+ "values": { "$ref": "#/fixtureArrays/ort_batch2_bias_flattened_tokens_input_skipT" }
305
+ }
306
+ },
307
+ "gammaT": { "dtype": "float32", "shape": [4], "data": { "kind": "values", "values": [0.3, 0.2, 4.0, 2.2] } },
308
+ "betaT": { "dtype": "float32", "shape": [4], "data": { "kind": "values", "values": [0.2, 0.1, 0.4, 1.6] } },
309
+ "biasT": { "dtype": "float32", "shape": [4], "data": { "kind": "values", "values": [0.1, -0.1, 0.2, -0.2] } }
310
+ },
311
+ "outputs": {
312
+ "outputT": { "dtype": "float32", "shape": [4, 4], "tolerance": 0.00002 },
313
+ "residualT": { "dtype": "float32", "shape": [4, 4], "tolerance": 0.000001 }
314
+ }
315
+ },
316
+ {
317
+ "name": "ort_batch2_flattened_tokens",
318
+ "provenance": {
319
+ "source": "onnxruntime/test/contrib_ops/skiplayernorm_op_test.cc",
320
+ "test": "SkipLayerNormTest.SkipLayerNormBatch2",
321
+ "notes": "ORT shape [2, 2, 4] is represented as [4, 4] tokens by this lowered kernel."
322
+ },
323
+ "attrs": { "epsilon": 1e-12 },
324
+ "inputs": {
325
+ "inputT": {
326
+ "dtype": "float32",
327
+ "shape": [4, 4],
328
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/ort_batch2_flattened_tokens_input_inputT" } }
329
+ },
330
+ "skipT": {
331
+ "dtype": "float32",
332
+ "shape": [4, 4],
333
+ "data": {
334
+ "kind": "values",
335
+ "values": { "$ref": "#/fixtureArrays/ort_batch2_bias_flattened_tokens_input_skipT" }
336
+ }
337
+ },
338
+ "gammaT": { "dtype": "float32", "shape": [4], "data": { "kind": "values", "values": [0.3, 0.2, 4.0, 2.2] } },
339
+ "betaT": { "dtype": "float32", "shape": [4], "data": { "kind": "values", "values": [0.2, 0.1, 0.4, 1.6] } }
340
+ },
341
+ "outputs": {
342
+ "outputT": { "dtype": "float32", "shape": [4, 4], "tolerance": 0.00002 },
343
+ "residualT": { "dtype": "float32", "shape": [4, 4], "tolerance": 0.000001 }
344
+ }
345
+ },
346
+ {
347
+ "name": "large_hidden_320_no_bias",
348
+ "attrs": { "epsilon": 0.00001 },
349
+ "inputs": {
350
+ "inputT": {
351
+ "dtype": "float32",
352
+ "shape": [2, 320],
353
+ "data": { "kind": "fillFloat32", "scale": 0.2, "sinStep": 0.017, "cosStep": 0.031 }
354
+ },
355
+ "skipT": {
356
+ "dtype": "float32",
357
+ "shape": [2, 320],
358
+ "data": { "kind": "fillFloat32", "scale": 0.2, "sinStep": 0.011, "cosStep": 0.023 }
359
+ },
360
+ "gammaT": {
361
+ "dtype": "float32",
362
+ "shape": [320],
363
+ "data": { "kind": "fillFloat32", "scale": 0.1, "offset": 1.0, "sinStep": 0.007, "cosStep": 0.041 }
364
+ },
365
+ "betaT": {
366
+ "dtype": "float32",
367
+ "shape": [320],
368
+ "data": { "kind": "fillFloat32", "scale": 0.1, "sinStep": 0.019, "cosStep": 0.013 }
369
+ }
370
+ },
371
+ "outputs": {
372
+ "outputT": { "dtype": "float32", "shape": [2, 320], "tolerance": 0.0002 },
373
+ "residualT": { "dtype": "float32", "shape": [2, 320], "tolerance": 0.000001 }
374
+ }
375
+ },
376
+ {
377
+ "name": "large_hidden_320_bias",
378
+ "attrs": { "epsilon": 0.00001 },
379
+ "inputs": {
380
+ "inputT": {
381
+ "dtype": "float32",
382
+ "shape": [2, 320],
383
+ "data": { "kind": "fillFloat32", "scale": 0.2, "sinStep": 0.013, "cosStep": 0.029 }
384
+ },
385
+ "skipT": {
386
+ "dtype": "float32",
387
+ "shape": [2, 320],
388
+ "data": { "kind": "fillFloat32", "scale": 0.2, "sinStep": 0.019, "cosStep": 0.037 }
389
+ },
390
+ "gammaT": {
391
+ "dtype": "float32",
392
+ "shape": [320],
393
+ "data": { "kind": "fillFloat32", "scale": 0.1, "offset": 1.0, "sinStep": 0.029, "cosStep": 0.017 }
394
+ },
395
+ "betaT": {
396
+ "dtype": "float32",
397
+ "shape": [320],
398
+ "data": { "kind": "fillFloat32", "scale": 0.1, "sinStep": 0.023, "cosStep": 0.011 }
399
+ },
400
+ "biasT": {
401
+ "dtype": "float32",
402
+ "shape": [320],
403
+ "data": { "kind": "fillFloat32", "scale": 0.05, "sinStep": 0.031, "cosStep": 0.007 }
404
+ }
405
+ },
406
+ "outputs": {
407
+ "outputT": { "dtype": "float32", "shape": [2, 320], "tolerance": 0.0002 },
408
+ "residualT": { "dtype": "float32", "shape": [2, 320], "tolerance": 0.000001 }
409
+ }
410
+ },
411
+ {
412
+ "name": "ort_batch2_skip_broadcast_no_batch_size",
413
+ "provenance": {
414
+ "source": "onnxruntime/test/contrib_ops/skiplayernorm_op_test.cc",
415
+ "test": "SkipLayerNormTest.SkipLayerNormBatch2_Skip_Broadcast_No_Batch_Size"
416
+ },
417
+ "attrs": { "epsilon": 1e-12 },
418
+ "inputs": {
419
+ "inputT": {
420
+ "dtype": "float32",
421
+ "shape": [2, 2, 4],
422
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/ort_batch2_flattened_tokens_input_inputT" } }
423
+ },
424
+ "skipT": {
425
+ "dtype": "float32",
426
+ "shape": [2, 4],
427
+ "data": { "kind": "values", "values": [0.1, -0.2, 0.3, 1.0, 0.5, 0.1, 0.4, 1.6] }
428
+ },
429
+ "gammaT": { "dtype": "float32", "shape": [4], "data": { "kind": "values", "values": [0.3, 0.2, 4.0, 2.2] } },
430
+ "betaT": { "dtype": "float32", "shape": [4], "data": { "kind": "values", "values": [0.2, 0.1, 0.4, 1.6] } }
431
+ },
432
+ "outputs": {
433
+ "outputT": {
434
+ "dtype": "float32",
435
+ "shape": [2, 2, 4],
436
+ "tolerance": 0.00002,
437
+ "data": {
438
+ "kind": "values",
439
+ "values": { "$ref": "#/fixtureArrays/ort_batch2_skip_broadcast_no_batch_size_output_outputT" }
440
+ }
441
+ }
442
+ }
443
+ },
444
+ {
445
+ "name": "ort_batch1_no_beta_flattened_tokens",
446
+ "provenance": {
447
+ "source": "onnxruntime/test/contrib_ops/skiplayernorm_op_test.cc",
448
+ "test": "SkipLayerNormTest.SkipLayerNormBatch1_NoBeta",
449
+ "notes": "ORT shape [1, 2, 4] is represented as [2, 4] tokens by this lowered fixture, with beta omitted."
450
+ },
451
+ "attrs": { "epsilon": 1e-12 },
452
+ "inputs": {
453
+ "inputT": {
454
+ "dtype": "float32",
455
+ "shape": [2, 4],
456
+ "data": { "kind": "values", "values": [0.8, -0.5, 0.0, 1.0, 0.5, 0.2, 0.3, -0.6] }
457
+ },
458
+ "skipT": {
459
+ "dtype": "float32",
460
+ "shape": [2, 4],
461
+ "data": { "kind": "values", "values": [0.1, -0.2, 0.3, 1.0, 0.5, 0.1, 0.4, 1.6] }
462
+ },
463
+ "gammaT": { "dtype": "float32", "shape": [4], "data": { "kind": "values", "values": [0.3, 0.2, 4.0, 2.2] } }
464
+ },
465
+ "outputs": {
466
+ "outputT": {
467
+ "dtype": "float32",
468
+ "shape": [2, 4],
469
+ "tolerance": 0.00002,
470
+ "data": {
471
+ "kind": "values",
472
+ "values": [0.0843385934829712, -0.27090578377246854, -1.3289716482162477, 3.092415237426758, 0.2611165225505829, -0.3133398056030273, -0.6963100373744965, 1.9148544311523439]
473
+ }
474
+ }
475
+ }
476
+ },
477
+ {
478
+ "name": "no_beta_output_only_hidden6_unaligned_row",
479
+ "provenance": {
480
+ "notes": "Only coverage for the scalar no_beta_output_only_row variant: beta omitted with output as the sole output picks the no-beta output-only pair, and hidden=6 is not a multiple of 4, so the vec4 sibling's vec4Aligned guard is false and the row kernel is selected on every tier."
481
+ },
482
+ "attrs": { "epsilon": 0.00001 },
483
+ "inputs": {
484
+ "inputT": {
485
+ "dtype": "float32",
486
+ "shape": [2, 6],
487
+ "data": { "kind": "fillFloat32", "sinStep": 0.17, "cosStep": 0.31 }
488
+ },
489
+ "skipT": {
490
+ "dtype": "float32",
491
+ "shape": [2, 6],
492
+ "data": { "kind": "fillFloat32", "sinStep": 0.11, "cosStep": 0.23 }
493
+ },
494
+ "gammaT": {
495
+ "dtype": "float32",
496
+ "shape": [6],
497
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.41, "scale": 0.2 }
498
+ }
499
+ },
500
+ "outputs": { "outputT": { "dtype": "float32", "shape": [2, 6], "tolerance": 0.00002 } }
501
+ },
502
+ {
503
+ "name": "beta_no_bias_output_only",
504
+ "provenance": {
505
+ "notes": "Exercises beta with all three optional auxiliary outputs absent, using a vec4-aligned hidden size of 8."
506
+ },
507
+ "attrs": { "epsilon": 0.00001 },
508
+ "inputs": {
509
+ "inputT": {
510
+ "dtype": "float32",
511
+ "shape": [3, 8],
512
+ "data": { "kind": "fillFloat32", "sinStep": 0.17, "cosStep": 0.31 }
513
+ },
514
+ "skipT": {
515
+ "dtype": "float32",
516
+ "shape": [3, 8],
517
+ "data": { "kind": "fillFloat32", "sinStep": 0.11, "cosStep": 0.23 }
518
+ },
519
+ "gammaT": {
520
+ "dtype": "float32",
521
+ "shape": [8],
522
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.41, "scale": 0.2 }
523
+ },
524
+ "betaT": {
525
+ "dtype": "float32",
526
+ "shape": [8],
527
+ "data": { "kind": "fillFloat32", "sinStep": 0.13, "cosStep": 0.29, "scale": 0.1 }
528
+ }
529
+ },
530
+ "outputs": { "outputT": { "dtype": "float32", "shape": [3, 8], "tolerance": 0.00002 } }
531
+ },
532
+ {
533
+ "name": "beta_no_bias_output_only_hidden6_unaligned_row",
534
+ "provenance": {
535
+ "notes": "Row-kernel arm of beta_no_bias_output_only: hidden=6 fails vec4Aligned, so the scalar sibling is selected on every tier."
536
+ },
537
+ "attrs": { "epsilon": 0.00001 },
538
+ "inputs": {
539
+ "inputT": {
540
+ "dtype": "float32",
541
+ "shape": [2, 6],
542
+ "data": { "kind": "fillFloat32", "sinStep": 0.19, "cosStep": 0.37 }
543
+ },
544
+ "skipT": {
545
+ "dtype": "float32",
546
+ "shape": [2, 6],
547
+ "data": { "kind": "fillFloat32", "sinStep": 0.23, "cosStep": 0.43 }
548
+ },
549
+ "gammaT": {
550
+ "dtype": "float32",
551
+ "shape": [6],
552
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.41, "scale": 0.2 }
553
+ },
554
+ "betaT": {
555
+ "dtype": "float32",
556
+ "shape": [6],
557
+ "data": { "kind": "fillFloat32", "sinStep": 0.13, "cosStep": 0.29, "scale": 0.1 }
558
+ }
559
+ },
560
+ "outputs": { "outputT": { "dtype": "float32", "shape": [2, 6], "tolerance": 0.00002 } }
561
+ },
562
+ {
563
+ "name": "beta_bias_output_only",
564
+ "provenance": {
565
+ "notes": "bias + beta with no optional outputs uses six storage buffers instead of the nine required when all optional outputs are present. It therefore remains valid at WebGPU's guaranteed minimum of eight storage buffers."
566
+ },
567
+ "attrs": { "epsilon": 0.00001 },
568
+ "inputs": {
569
+ "inputT": {
570
+ "dtype": "float32",
571
+ "shape": [3, 8],
572
+ "data": { "kind": "fillFloat32", "sinStep": 0.17, "cosStep": 0.31 }
573
+ },
574
+ "skipT": {
575
+ "dtype": "float32",
576
+ "shape": [3, 8],
577
+ "data": { "kind": "fillFloat32", "sinStep": 0.11, "cosStep": 0.23 }
578
+ },
579
+ "gammaT": {
580
+ "dtype": "float32",
581
+ "shape": [8],
582
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.41, "scale": 0.2 }
583
+ },
584
+ "betaT": {
585
+ "dtype": "float32",
586
+ "shape": [8],
587
+ "data": { "kind": "fillFloat32", "sinStep": 0.13, "cosStep": 0.29, "scale": 0.1 }
588
+ },
589
+ "biasT": {
590
+ "dtype": "float32",
591
+ "shape": [8],
592
+ "data": { "kind": "fillFloat32", "sinStep": 0.05, "cosStep": 0.47, "scale": 0.3 }
593
+ }
594
+ },
595
+ "outputs": { "outputT": { "dtype": "float32", "shape": [3, 8], "tolerance": 0.00002 } }
596
+ },
597
+ {
598
+ "name": "beta_bias_output_only_hidden6_unaligned_row",
599
+ "provenance": {
600
+ "notes": "Row-kernel arm of beta_bias_output_only: hidden=6 fails vec4Aligned. 6 storage buffers."
601
+ },
602
+ "attrs": { "epsilon": 0.00001 },
603
+ "inputs": {
604
+ "inputT": {
605
+ "dtype": "float32",
606
+ "shape": [2, 6],
607
+ "data": { "kind": "fillFloat32", "sinStep": 0.19, "cosStep": 0.37 }
608
+ },
609
+ "skipT": {
610
+ "dtype": "float32",
611
+ "shape": [2, 6],
612
+ "data": { "kind": "fillFloat32", "sinStep": 0.23, "cosStep": 0.43 }
613
+ },
614
+ "gammaT": {
615
+ "dtype": "float32",
616
+ "shape": [6],
617
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.41, "scale": 0.2 }
618
+ },
619
+ "betaT": {
620
+ "dtype": "float32",
621
+ "shape": [6],
622
+ "data": { "kind": "fillFloat32", "sinStep": 0.13, "cosStep": 0.29, "scale": 0.1 }
623
+ },
624
+ "biasT": {
625
+ "dtype": "float32",
626
+ "shape": [6],
627
+ "data": { "kind": "fillFloat32", "sinStep": 0.05, "cosStep": 0.47, "scale": 0.3 }
628
+ }
629
+ },
630
+ "outputs": { "outputT": { "dtype": "float32", "shape": [2, 6], "tolerance": 0.00002 } }
631
+ },
632
+ {
633
+ "name": "ort_batch2_skip_broadcast_batch_size_one",
634
+ "provenance": {
635
+ "source": "onnxruntime/test/contrib_ops/skiplayernorm_op_test.cc",
636
+ "test": "SkipLayerNormTest.SkipLayerNormBatch2_Skip_Broadcast_Batch_Size_1"
637
+ },
638
+ "attrs": { "epsilon": 1e-12 },
639
+ "inputs": {
640
+ "inputT": {
641
+ "dtype": "float32",
642
+ "shape": [2, 2, 4],
643
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/ort_batch2_flattened_tokens_input_inputT" } }
644
+ },
645
+ "skipT": {
646
+ "dtype": "float32",
647
+ "shape": [1, 2, 4],
648
+ "data": { "kind": "values", "values": [0.1, -0.2, 0.3, 1.0, 0.5, 0.1, 0.4, 1.6] }
649
+ },
650
+ "gammaT": { "dtype": "float32", "shape": [4], "data": { "kind": "values", "values": [0.3, 0.2, 4.0, 2.2] } },
651
+ "betaT": { "dtype": "float32", "shape": [4], "data": { "kind": "values", "values": [0.2, 0.1, 0.4, 1.6] } }
652
+ },
653
+ "outputs": {
654
+ "outputT": {
655
+ "dtype": "float32",
656
+ "shape": [2, 2, 4],
657
+ "tolerance": 0.00002,
658
+ "data": {
659
+ "kind": "values",
660
+ "values": { "$ref": "#/fixtureArrays/ort_batch2_skip_broadcast_no_batch_size_output_outputT" }
661
+ }
662
+ }
663
+ }
664
+ },
665
+ {
666
+ "name": "f16_hidden768_bias_residual",
667
+ "requires": { "features": ["shader-f16"] },
668
+ "attrs": { "epsilon": 0.00001 },
669
+ "inputs": {
670
+ "inputT": {
671
+ "dtype": "float16",
672
+ "shape": [4, 768],
673
+ "data": { "kind": "fillFloat32", "scale": 0.2, "sinStep": 0.017, "cosStep": 0.031 }
674
+ },
675
+ "skipT": {
676
+ "dtype": "float16",
677
+ "shape": [4, 768],
678
+ "data": { "kind": "fillFloat32", "scale": 0.2, "sinStep": 0.011, "cosStep": 0.023 }
679
+ },
680
+ "gammaT": {
681
+ "dtype": "float16",
682
+ "shape": [768],
683
+ "data": { "kind": "fillFloat32", "scale": 0.1, "offset": 1.0, "sinStep": 0.007, "cosStep": 0.041 }
684
+ },
685
+ "betaT": {
686
+ "dtype": "float16",
687
+ "shape": [768],
688
+ "data": { "kind": "fillFloat32", "scale": 0.1, "sinStep": 0.019, "cosStep": 0.013 }
689
+ },
690
+ "biasT": {
691
+ "dtype": "float16",
692
+ "shape": [768],
693
+ "data": { "kind": "fillFloat32", "scale": 0.05, "sinStep": 0.031, "cosStep": 0.007 }
694
+ }
695
+ },
696
+ "outputs": {
697
+ "outputT": { "dtype": "float16", "shape": [4, 768], "tolerance": 0.01 },
698
+ "residualT": { "dtype": "float16", "shape": [4, 768], "tolerance": 0.005 }
699
+ }
700
+ },
701
+ {
702
+ "name": "f32_hidden768_no_bias_residual",
703
+ "provenance": {
704
+ "notes": "Compact companion for bench cases skip-layernorm-f32-4096x768 and skip-layernorm-f32-4096x768-hidden768-aligned-sibling, where reduced tiers expose a subgroup fallback gap."
705
+ },
706
+ "attrs": { "epsilon": 0.00001 },
707
+ "inputs": {
708
+ "inputT": {
709
+ "dtype": "float32",
710
+ "shape": [4, 768],
711
+ "data": { "kind": "fillFloat32", "scale": 0.2, "sinStep": 0.017, "cosStep": 0.031 }
712
+ },
713
+ "skipT": {
714
+ "dtype": "float32",
715
+ "shape": [4, 768],
716
+ "data": { "kind": "fillFloat32", "scale": 0.2, "sinStep": 0.011, "cosStep": 0.023 }
717
+ },
718
+ "gammaT": {
719
+ "dtype": "float32",
720
+ "shape": [768],
721
+ "data": { "kind": "fillFloat32", "scale": 0.1, "offset": 1.0, "sinStep": 0.007, "cosStep": 0.041 }
722
+ },
723
+ "betaT": {
724
+ "dtype": "float32",
725
+ "shape": [768],
726
+ "data": { "kind": "fillFloat32", "scale": 0.1, "sinStep": 0.019, "cosStep": 0.013 }
727
+ }
728
+ },
729
+ "outputs": {
730
+ "outputT": { "dtype": "float32", "shape": [4, 768], "tolerance": 0.0002 },
731
+ "residualT": { "dtype": "float32", "shape": [4, 768], "tolerance": 0.000002 }
732
+ }
733
+ },
734
+ {
735
+ "name": "f32_hidden2048_bias_residual",
736
+ "attrs": { "epsilon": 0.00001 },
737
+ "inputs": {
738
+ "inputT": {
739
+ "dtype": "float32",
740
+ "shape": [2, 2048],
741
+ "data": { "kind": "fillFloat32", "scale": 0.2, "sinStep": 0.013, "cosStep": 0.029 }
742
+ },
743
+ "skipT": {
744
+ "dtype": "float32",
745
+ "shape": [2, 2048],
746
+ "data": { "kind": "fillFloat32", "scale": 0.2, "sinStep": 0.019, "cosStep": 0.037 }
747
+ },
748
+ "gammaT": {
749
+ "dtype": "float32",
750
+ "shape": [2048],
751
+ "data": { "kind": "fillFloat32", "scale": 0.1, "offset": 1.0, "sinStep": 0.029, "cosStep": 0.017 }
752
+ },
753
+ "betaT": {
754
+ "dtype": "float32",
755
+ "shape": [2048],
756
+ "data": { "kind": "fillFloat32", "scale": 0.1, "sinStep": 0.023, "cosStep": 0.011 }
757
+ },
758
+ "biasT": {
759
+ "dtype": "float32",
760
+ "shape": [2048],
761
+ "data": { "kind": "fillFloat32", "scale": 0.05, "sinStep": 0.031, "cosStep": 0.007 }
762
+ }
763
+ },
764
+ "outputs": {
765
+ "outputT": { "dtype": "float32", "shape": [2, 2048], "tolerance": 0.0005 },
766
+ "residualT": { "dtype": "float32", "shape": [2, 2048], "tolerance": 0.000002 }
767
+ }
768
+ },
769
+ {
770
+ "name": "f32_hidden1025_bias_residual",
771
+ "provenance": {
772
+ "notes": "Compact companion for bench case skip-layernorm-f32-bias-8192x1025-unaligned-twopass-fallback, preserving the odd hidden-size bias path."
773
+ },
774
+ "attrs": { "epsilon": 0.00001 },
775
+ "inputs": {
776
+ "inputT": {
777
+ "dtype": "float32",
778
+ "shape": [3, 1025],
779
+ "data": { "kind": "fillFloat32", "scale": 0.2, "sinStep": 0.013, "cosStep": 0.029 }
780
+ },
781
+ "skipT": {
782
+ "dtype": "float32",
783
+ "shape": [3, 1025],
784
+ "data": { "kind": "fillFloat32", "scale": 0.2, "sinStep": 0.019, "cosStep": 0.037 }
785
+ },
786
+ "gammaT": {
787
+ "dtype": "float32",
788
+ "shape": [1025],
789
+ "data": { "kind": "fillFloat32", "scale": 0.1, "offset": 1.0, "sinStep": 0.029, "cosStep": 0.017 }
790
+ },
791
+ "betaT": {
792
+ "dtype": "float32",
793
+ "shape": [1025],
794
+ "data": { "kind": "fillFloat32", "scale": 0.1, "sinStep": 0.023, "cosStep": 0.011 }
795
+ },
796
+ "biasT": {
797
+ "dtype": "float32",
798
+ "shape": [1025],
799
+ "data": { "kind": "fillFloat32", "scale": 0.05, "sinStep": 0.031, "cosStep": 0.007 }
800
+ }
801
+ },
802
+ "outputs": {
803
+ "outputT": { "dtype": "float32", "shape": [3, 1025], "tolerance": 0.0005 },
804
+ "residualT": { "dtype": "float32", "shape": [3, 1025], "tolerance": 0.000002 }
805
+ }
806
+ },
807
+ {
808
+ "name": "f32_hidden770_unaligned_beta_bias_scalar_subgroup",
809
+ "attrs": { "epsilon": 0.00001 },
810
+ "inputs": {
811
+ "inputT": {
812
+ "dtype": "float32",
813
+ "shape": [3, 770],
814
+ "data": { "kind": "fillFloat32", "scale": 0.2, "sinStep": 0.017, "cosStep": 0.031 }
815
+ },
816
+ "skipT": {
817
+ "dtype": "float32",
818
+ "shape": [3, 770],
819
+ "data": { "kind": "fillFloat32", "scale": 0.2, "sinStep": 0.011, "cosStep": 0.023 }
820
+ },
821
+ "gammaT": {
822
+ "dtype": "float32",
823
+ "shape": [770],
824
+ "data": { "kind": "fillFloat32", "scale": 0.1, "offset": 1.0, "sinStep": 0.007, "cosStep": 0.041 }
825
+ },
826
+ "betaT": {
827
+ "dtype": "float32",
828
+ "shape": [770],
829
+ "data": { "kind": "fillFloat32", "scale": 0.1, "sinStep": 0.019, "cosStep": 0.013 }
830
+ },
831
+ "biasT": {
832
+ "dtype": "float32",
833
+ "shape": [770],
834
+ "data": { "kind": "fillFloat32", "scale": 0.05, "sinStep": 0.031, "cosStep": 0.007 }
835
+ }
836
+ },
837
+ "outputs": {
838
+ "outputT": { "dtype": "float32", "shape": [3, 770], "tolerance": 0.0002 },
839
+ "residualT": { "dtype": "float32", "shape": [3, 770], "tolerance": 0.000002 }
840
+ }
841
+ },
842
+ {
843
+ "name": "f32_rows1_hidden4096_decode",
844
+ "attrs": { "epsilon": 0.00001 },
845
+ "inputs": {
846
+ "inputT": {
847
+ "dtype": "float32",
848
+ "shape": [1, 4096],
849
+ "data": { "kind": "fillFloat32", "scale": 0.2, "sinStep": 0.017, "cosStep": 0.031 }
850
+ },
851
+ "skipT": {
852
+ "dtype": "float32",
853
+ "shape": [1, 4096],
854
+ "data": { "kind": "fillFloat32", "scale": 0.2, "sinStep": 0.011, "cosStep": 0.023 }
855
+ },
856
+ "gammaT": {
857
+ "dtype": "float32",
858
+ "shape": [4096],
859
+ "data": { "kind": "fillFloat32", "scale": 0.1, "offset": 1.0, "sinStep": 0.007, "cosStep": 0.041 }
860
+ },
861
+ "betaT": {
862
+ "dtype": "float32",
863
+ "shape": [4096],
864
+ "data": { "kind": "fillFloat32", "scale": 0.1, "sinStep": 0.019, "cosStep": 0.013 }
865
+ }
866
+ },
867
+ "outputs": {
868
+ "outputT": { "dtype": "float32", "shape": [1, 4096], "tolerance": 0.0005 },
869
+ "residualT": { "dtype": "float32", "shape": [1, 4096], "tolerance": 0.000002 }
870
+ }
871
+ },
872
+ {
873
+ "name": "empty_tokens_bias_residual_twopass",
874
+ "attrs": { "epsilon": 1e-12 },
875
+ "inputs": {
876
+ "inputT": { "dtype": "float32", "shape": [0, 4], "data": { "kind": "values", "values": [] } },
877
+ "skipT": { "dtype": "float32", "shape": [0, 4], "data": { "kind": "values", "values": [] } },
878
+ "gammaT": { "dtype": "float32", "shape": [4], "data": { "kind": "values", "values": [0.3, 0.2, 4.0, 2.2] } },
879
+ "betaT": { "dtype": "float32", "shape": [4], "data": { "kind": "values", "values": [0.2, 0.1, 0.4, 1.6] } },
880
+ "biasT": { "dtype": "float32", "shape": [4], "data": { "kind": "values", "values": [0.1, -0.1, 0.2, -0.2] } }
881
+ },
882
+ "outputs": {
883
+ "outputT": { "dtype": "float32", "shape": [0, 4], "tolerance": 0 },
884
+ "residualT": { "dtype": "float32", "shape": [0, 4], "tolerance": 0 }
885
+ }
886
+ },
887
+ {
888
+ "name": "rows65537_hidden3_fold_lastrow_guard",
889
+ "provenance": {
890
+ "notes": "Pins the two-dimensional dispatch fold and final-row guard with 65,537 hidden-size-3 rows; near-constant rows exercise float32 one-pass variance while the residual sum remains exact."
891
+ },
892
+ "attrs": { "epsilon": 0.00001 },
893
+ "inputs": {
894
+ "inputT": {
895
+ "dtype": "float32",
896
+ "shape": [65537, 3],
897
+ "data": { "kind": "fillFloat32", "scale": 0.2, "sinStep": 0.017, "cosStep": 0.031 }
898
+ },
899
+ "skipT": {
900
+ "dtype": "float32",
901
+ "shape": [65537, 3],
902
+ "data": { "kind": "fillFloat32", "scale": 0.2, "sinStep": 0.011, "cosStep": 0.023 }
903
+ },
904
+ "gammaT": { "dtype": "float32", "shape": [3], "data": { "kind": "values", "values": [1.0, 2.0, -1.0] } },
905
+ "betaT": { "dtype": "float32", "shape": [3], "data": { "kind": "values", "values": [0.5, -0.25, 1.0] } }
906
+ },
907
+ "outputs": {
908
+ "outputT": { "dtype": "float32", "shape": [65537, 3], "tolerance": 0.0021 },
909
+ "residualT": { "dtype": "float32", "shape": [65537, 3], "tolerance": 0.000002 }
910
+ }
911
+ },
912
+ {
913
+ "name": "hidden_size_one_bias_many_rows",
914
+ "provenance": {
915
+ "notes": "Compact correctness sibling for the hidden-size-one low-occupancy benchmark; many rows with hidden=1 keep the variance-zero bias path honest without using benchmark-scale dimensions."
916
+ },
917
+ "attrs": { "epsilon": 0.00001 },
918
+ "inputs": {
919
+ "inputT": {
920
+ "dtype": "float32",
921
+ "shape": [257, 1],
922
+ "data": { "kind": "fillFloat32", "scale": 0.2, "sinStep": 0.017, "cosStep": 0.031 }
923
+ },
924
+ "skipT": {
925
+ "dtype": "float32",
926
+ "shape": [257, 1],
927
+ "data": { "kind": "fillFloat32", "scale": 0.2, "sinStep": 0.011, "cosStep": 0.023 }
928
+ },
929
+ "gammaT": { "dtype": "float32", "shape": [1], "data": { "kind": "values", "values": [1.25] } },
930
+ "betaT": { "dtype": "float32", "shape": [1], "data": { "kind": "values", "values": [-0.5] } },
931
+ "biasT": { "dtype": "float32", "shape": [1], "data": { "kind": "values", "values": [0.125] } }
932
+ },
933
+ "outputs": {
934
+ "outputT": { "dtype": "float32", "shape": [257, 1], "tolerance": 0.000001 },
935
+ "residualT": { "dtype": "float32", "shape": [257, 1], "tolerance": 0.000001 }
936
+ }
937
+ }
938
+ ]
939
+ }