Xenova HF Staff commited on
Commit
e467b91
·
verified ·
1 Parent(s): 7fed370

sync 6fdf6301e2bb

Browse files
README.md CHANGED
@@ -1,3 +1,102 @@
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.SkipGroupNorm
10
+
11
+ `com.microsoft` · ONNX Runtime contrib operator · contrib since_version 1
12
+
13
+ ## Description
14
+
15
+ Adds a residual and an optional bias to the input, then group-normalizes the sum with an optional fused SiLU: `S = X + skip + bias`, `Y = gamma * (S - mean) / sqrt(variance + epsilon) + beta`. Statistics are taken per batch item over each group of `C / groups` channels and every spatial position, under either layout. `skip` is either exactly `X`'s shape or a per-channel `(N, C)` / `(N, 1, 1, C)` residual. The sum is rounded to the tensor type before the statistics see it, so `Y` does not depend on whether `S` was requested. `X` and `gamma`/`beta` carry independent element types.
16
+
17
+ See the [ONNX Runtime `SkipGroupNorm` contrib-operator spec](https://github.com/microsoft/onnxruntime/blob/main/docs/ContribOperators.md#com.microsoft.SkipGroupNorm) for the reference semantics.
18
+
19
+ ## Inputs
20
+
21
+ | Name | Logical dtype | Rank | Shape | Description | Presence |
22
+ | --- | --- | --- | --- | --- | --- |
23
+ | `X` | `T` | `4` | — | Input image tensor, `(N, H, W, C)` when `channels_last` is 1 and `(N, C, H, W)` otherwise. | required |
24
+ | `gamma` | `M` | `1` | — | Per-channel affine scale of shape `(C)`. | required |
25
+ | `beta` | `M` | `1` | — | Per-channel affine offset of shape `(C)`. | required |
26
+ | `skip` | `T` | — | — | Residual added to `X`. Either exactly `X`'s shape, or `(N, C)` / `(N, 1, 1, C)` to broadcast one value per batch item and channel. A `(N, 1, 1, C)` tensor at `H = W = 1` is an exact match and takes the non-broadcast route, which is what upstream does. | required |
27
+ | `bias` | `T` | `1` | — | Optional per-channel bias of shape `(C)` added to `X + skip` before normalization. | optional |
28
+
29
+ ## Outputs
30
+
31
+ | Name | Logical dtype | Rank | Shape | Description | Presence |
32
+ | --- | --- | --- | --- | --- | --- |
33
+ | `Y` | `T` | `4` | same as `X` | Normalized tensor with the same shape and element type as `X`. | required |
34
+ | `S` | `T` | `4` | same as `X` | Optional second output holding `X + skip + bias` at the tensor's element type, the values the statistics are taken over. | optional |
35
+
36
+ ## Attributes
37
+
38
+ Attributes and default values (overridable per request):
39
+
40
+ | Attribute | Default | Description |
41
+ | --- | --- | --- |
42
+ | `activation` | — | Activation applied after the affine transform: `0` for none, `1` for SiLU. The request must supply it; the operator declares no default. |
43
+ | `channels_last` | `1` | `1` when `X` and `Y` are `(N, H, W, C)`, `0` when they are `(N, C, H, W)`. Defaults to `1`. Any non-zero value selects the channels-last layout. |
44
+ | `epsilon` | `0.00001` | Value added to the group variance before the reciprocal square root. Defaults to `1e-5`. |
45
+ | `groups` | — | Number of channel groups the statistics are taken over. It must divide `C`. The request must supply it; the operator declares no default. |
46
+
47
+ ## Type constraints
48
+
49
+ | Variable | Allowed dtypes |
50
+ | --- | --- |
51
+ | `T` | `float32`, `float16` |
52
+ | `M` | `float32`, `float16` |
53
+
54
+ ## Implementation variants
55
+
56
+ One implementation is selected per call from the device capabilities, the request shapes and the dtypes; these notes say what each one covers.
57
+
58
+ - `split_bias_sum` — Three dispatches: partial group statistics, combine mean and reciprocal standard deviation, then normalize and apply affine weights. Channels-last statistics use four, two, or one aligned values per lane; group blocks and spatial rows follow device limits. Fuses skip, optional bias, and optional residual output.
59
+ - `fused_bias_sum` — One workgroup per batch item and group for a request with a bias and the residual sum output, walking the group twice inside a single dispatch: once to form the residual sum and its moments, once to write the affine result.
60
+ - `split_bias_plain` — Three dispatches: partial group statistics, combine mean and reciprocal standard deviation, then normalize and apply affine weights. Channels-last statistics use four, two, or one aligned values per lane; group blocks and spatial rows follow device limits. Fuses skip, optional bias, and optional residual output.
61
+ - `fused_bias_plain` — One workgroup per batch item and group for a request with a bias and no residual sum output, walking the group twice inside a single dispatch: once to form the residual sum and its moments, once to write the affine result.
62
+ - `split_sum` — Three dispatches: partial group statistics, combine mean and reciprocal standard deviation, then normalize and apply affine weights. Channels-last statistics use four, two, or one aligned values per lane; group blocks and spatial rows follow device limits. Fuses skip, optional bias, and optional residual output.
63
+ - `fused_sum` — One workgroup per batch item and group for a request with no bias and the residual sum output, walking the group twice inside a single dispatch: once to form the residual sum and its moments, once to write the affine result.
64
+ - `split_plain` — Three dispatches: partial group statistics, combine mean and reciprocal standard deviation, then normalize and apply affine weights. Channels-last statistics use four, two, or one aligned values per lane; group blocks and spatial rows follow device limits. Fuses skip, optional bias, and optional residual output.
65
+ - `fused_plain` — One workgroup per batch item and group for a request with neither a bias nor the residual sum output, walking the group twice inside a single dispatch: once to form the residual sum and its moments, once to write the affine result.
66
+
67
+ ## Files
68
+
69
+ - [`metadata.json`](build/webgpu/metadata.json) — kernel metadata (id, digests, per-variant templates, provenance)
70
+ - [`manifest.json`](build/webgpu/manifest.json) — the op contract (source of truth)
71
+ - [`test.json`](build/webgpu/test.json) — correctness cases
72
+ - [`bench.json`](build/webgpu/bench.json) — benchmark cases
73
+ - [`group-norm-combine.wgsl.jinja`](build/webgpu/group-norm-combine.wgsl.jinja)
74
+ - [`group-norm-fused.wgsl.jinja`](build/webgpu/group-norm-fused.wgsl.jinja)
75
+ - [`group-norm-slab.wgsl.jinja`](build/webgpu/group-norm-slab.wgsl.jinja)
76
+
77
+ ## Use with `@huggingface/kernels`
78
+
79
+ ```sh
80
+ npm install --save-exact @huggingface/kernels@0.0.1-preview.3
81
+ ```
82
+
83
+ Required output shapes and logical data types are inferred from the supplied inputs and attributes; result tensors are allocated automatically.
84
+
85
+ The `version: 1` option selects the published kernel contract; it is independent of any operator opset, contrib `since_version`, or model version.
86
+ It follows the `v1` branch as fixes land. To pin exact artifact bytes, pass a 40-character commit `revision` instead of `version`.
87
+
88
+ Replace each `*Data` placeholder with a typed array containing the corresponding input data.
89
+
90
+ ```js
91
+ import { getKernel } from "@huggingface/kernels";
92
+
93
+ const kernel = await getKernel("webgpu-kernels/com.microsoft.SkipGroupNorm", { version: 1 });
94
+ const { Y } = await kernel({
95
+ X: { data: XData, shape: [2, 3, 2, 8] },
96
+ gamma: { data: gammaData, shape: [8] },
97
+ beta: { data: betaData, shape: [8] },
98
+ skip: { data: skipData, shape: [2, 8] },
99
+ }, {
100
+ attrs: { groups: 2, activation: 0 },
101
+ });
102
+ ```
build/webgpu/bench.json ADDED
@@ -0,0 +1,504 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "tunableSpace": { "WORKGROUP_SIZE": [128, 256] },
3
+ "cases": [
4
+ {
5
+ "name": "flux-vae-mid-1x64x64x512-g32-f16-sum",
6
+ "preset": "smoke",
7
+ "provenance": { "note": "Flux.2 VAE decoder resnet: the residual feeds the next block, so S is requested" },
8
+ "vars": {
9
+ "dtype": "float16",
10
+ "weightDtype": "float32",
11
+ "count": 2097152,
12
+ "channels": 512,
13
+ "streams": 3,
14
+ "skipElements": 2097152
15
+ },
16
+ "attrs": { "groups": 32, "activation": 1, "channels_last": 1, "epsilon": 0.000001 },
17
+ "inputs": {
18
+ "X": { "dtype": "float16", "shape": [1, 64, 64, 512], "dist": "normal", "seed": 400, "scale": 0.5 },
19
+ "gamma": { "dtype": "float32", "shape": [512], "dist": "uniform", "seed": 401, "scale": 0.25, "offset": 1 },
20
+ "beta": { "dtype": "float32", "shape": [512], "dist": "normal", "seed": 402, "scale": 0.1 },
21
+ "skip": { "dtype": "float16", "shape": [1, 64, 64, 512], "dist": "normal", "seed": 403, "scale": 0.5 },
22
+ "bias": { "dtype": "float16", "shape": [512], "dist": "normal", "seed": 404, "scale": 0.1 }
23
+ },
24
+ "outputs": {
25
+ "Y": { "dtype": "float16", "shape": [1, 64, 64, 512], "dist": "empty" },
26
+ "S": { "dtype": "float16", "shape": [1, 64, 64, 512], "dist": "empty" }
27
+ },
28
+ "bench": {
29
+ "metrics": [
30
+ {
31
+ "type": "bandwidth",
32
+ "value": "(args.count * args.streams + args.skipElements) * dtypeBytes(args.dtype) + args.channels * 2 * dtypeBytes(args.weightDtype)"
33
+ }
34
+ ],
35
+ "primary": true
36
+ }
37
+ },
38
+ {
39
+ "name": "flux-vae-mid-1x64x64x512-g32-f16-nosum",
40
+ "preset": "smoke",
41
+ "provenance": {
42
+ "note": "The same node with S not requested: the sum is round-tripped through Y instead of a second output"
43
+ },
44
+ "vars": {
45
+ "dtype": "float16",
46
+ "weightDtype": "float32",
47
+ "count": 2097152,
48
+ "channels": 512,
49
+ "streams": 2,
50
+ "skipElements": 2097152
51
+ },
52
+ "attrs": { "groups": 32, "activation": 1, "channels_last": 1, "epsilon": 0.000001 },
53
+ "inputs": {
54
+ "X": { "dtype": "float16", "shape": [1, 64, 64, 512], "dist": "normal", "seed": 410, "scale": 0.5 },
55
+ "gamma": { "dtype": "float32", "shape": [512], "dist": "uniform", "seed": 411, "scale": 0.25, "offset": 1 },
56
+ "beta": { "dtype": "float32", "shape": [512], "dist": "normal", "seed": 412, "scale": 0.1 },
57
+ "skip": { "dtype": "float16", "shape": [1, 64, 64, 512], "dist": "normal", "seed": 413, "scale": 0.5 },
58
+ "bias": { "dtype": "float16", "shape": [512], "dist": "normal", "seed": 414, "scale": 0.1 }
59
+ },
60
+ "outputs": { "Y": { "dtype": "float16", "shape": [1, 64, 64, 512], "dist": "empty" } },
61
+ "bench": {
62
+ "metrics": [
63
+ {
64
+ "type": "bandwidth",
65
+ "value": "(args.count * args.streams + args.skipElements) * dtypeBytes(args.dtype) + args.channels * 2 * dtypeBytes(args.weightDtype)"
66
+ }
67
+ ]
68
+ }
69
+ },
70
+ {
71
+ "name": "sd15-unet-2x64x64x320-g32-f16-sum",
72
+ "preset": "smoke",
73
+ "provenance": {
74
+ "note": "Stable-Diffusion-1.5 UNet resnet at the classifier-free-guidance batch; 10 channels per group, no bias"
75
+ },
76
+ "vars": {
77
+ "dtype": "float16",
78
+ "weightDtype": "float32",
79
+ "count": 2621440,
80
+ "channels": 320,
81
+ "streams": 3,
82
+ "skipElements": 2621440
83
+ },
84
+ "attrs": { "groups": 32, "activation": 1, "channels_last": 1 },
85
+ "inputs": {
86
+ "X": { "dtype": "float16", "shape": [2, 64, 64, 320], "dist": "normal", "seed": 420, "scale": 0.5 },
87
+ "gamma": { "dtype": "float32", "shape": [320], "dist": "uniform", "seed": 421, "scale": 0.25, "offset": 1 },
88
+ "beta": { "dtype": "float32", "shape": [320], "dist": "normal", "seed": 422, "scale": 0.1 },
89
+ "skip": { "dtype": "float16", "shape": [2, 64, 64, 320], "dist": "normal", "seed": 423, "scale": 0.5 }
90
+ },
91
+ "outputs": {
92
+ "Y": { "dtype": "float16", "shape": [2, 64, 64, 320], "dist": "empty" },
93
+ "S": { "dtype": "float16", "shape": [2, 64, 64, 320], "dist": "empty" }
94
+ },
95
+ "bench": {
96
+ "metrics": [
97
+ {
98
+ "type": "bandwidth",
99
+ "value": "(args.count * args.streams + args.skipElements) * dtypeBytes(args.dtype) + args.channels * 2 * dtypeBytes(args.weightDtype)"
100
+ }
101
+ ]
102
+ }
103
+ },
104
+ {
105
+ "name": "sd15-unet-2x32x32x640-g32-f16-nosum",
106
+ "preset": "smoke",
107
+ "provenance": {
108
+ "note": "Stable-Diffusion-1.5 UNet mid-resolution resnet without the activation or the second output"
109
+ },
110
+ "vars": {
111
+ "dtype": "float16",
112
+ "weightDtype": "float32",
113
+ "count": 1310720,
114
+ "channels": 640,
115
+ "streams": 2,
116
+ "skipElements": 1310720
117
+ },
118
+ "attrs": { "groups": 32, "activation": 0, "channels_last": 1 },
119
+ "inputs": {
120
+ "X": { "dtype": "float16", "shape": [2, 32, 32, 640], "dist": "normal", "seed": 430, "scale": 0.5 },
121
+ "gamma": { "dtype": "float32", "shape": [640], "dist": "uniform", "seed": 431, "scale": 0.25, "offset": 1 },
122
+ "beta": { "dtype": "float32", "shape": [640], "dist": "normal", "seed": 432, "scale": 0.1 },
123
+ "skip": { "dtype": "float16", "shape": [2, 32, 32, 640], "dist": "normal", "seed": 433, "scale": 0.5 }
124
+ },
125
+ "outputs": { "Y": { "dtype": "float16", "shape": [2, 32, 32, 640], "dist": "empty" } },
126
+ "bench": {
127
+ "metrics": [
128
+ {
129
+ "type": "bandwidth",
130
+ "value": "(args.count * args.streams + args.skipElements) * dtypeBytes(args.dtype) + args.channels * 2 * dtypeBytes(args.weightDtype)"
131
+ }
132
+ ]
133
+ }
134
+ },
135
+ {
136
+ "name": "sdxl-1x144x112x640-g32-f16-sum",
137
+ "preset": "smoke",
138
+ "provenance": { "note": "An SDXL non-square aspect grid, where a spatial-divisor block split degenerates" },
139
+ "vars": {
140
+ "dtype": "float16",
141
+ "weightDtype": "float32",
142
+ "count": 10321920,
143
+ "channels": 640,
144
+ "streams": 3,
145
+ "skipElements": 10321920
146
+ },
147
+ "attrs": { "groups": 32, "activation": 1, "channels_last": 1 },
148
+ "inputs": {
149
+ "X": { "dtype": "float16", "shape": [1, 144, 112, 640], "dist": "normal", "seed": 440, "scale": 0.5 },
150
+ "gamma": { "dtype": "float32", "shape": [640], "dist": "uniform", "seed": 441, "scale": 0.25, "offset": 1 },
151
+ "beta": { "dtype": "float32", "shape": [640], "dist": "normal", "seed": 442, "scale": 0.1 },
152
+ "skip": { "dtype": "float16", "shape": [1, 144, 112, 640], "dist": "normal", "seed": 443, "scale": 0.5 },
153
+ "bias": { "dtype": "float16", "shape": [640], "dist": "normal", "seed": 444, "scale": 0.1 }
154
+ },
155
+ "outputs": {
156
+ "Y": { "dtype": "float16", "shape": [1, 144, 112, 640], "dist": "empty" },
157
+ "S": { "dtype": "float16", "shape": [1, 144, 112, 640], "dist": "empty" }
158
+ },
159
+ "bench": {
160
+ "metrics": [
161
+ {
162
+ "type": "bandwidth",
163
+ "value": "(args.count * args.streams + args.skipElements) * dtypeBytes(args.dtype) + args.channels * 2 * dtypeBytes(args.weightDtype)"
164
+ }
165
+ ]
166
+ }
167
+ },
168
+ {
169
+ "name": "broadcast-skip-rank2-1x32x32x320-g32-f16",
170
+ "preset": "smoke",
171
+ "provenance": { "note": "Per-channel residual spelled (N, C)" },
172
+ "vars": {
173
+ "dtype": "float16",
174
+ "weightDtype": "float32",
175
+ "count": 327680,
176
+ "channels": 320,
177
+ "streams": 3,
178
+ "skipElements": 320
179
+ },
180
+ "attrs": { "groups": 32, "activation": 1, "channels_last": 1 },
181
+ "inputs": {
182
+ "X": { "dtype": "float16", "shape": [1, 32, 32, 320], "dist": "normal", "seed": 450, "scale": 0.5 },
183
+ "gamma": { "dtype": "float32", "shape": [320], "dist": "uniform", "seed": 451, "scale": 0.25, "offset": 1 },
184
+ "beta": { "dtype": "float32", "shape": [320], "dist": "normal", "seed": 452, "scale": 0.1 },
185
+ "skip": { "dtype": "float16", "shape": [1, 320], "dist": "normal", "seed": 453, "scale": 0.5 },
186
+ "bias": { "dtype": "float16", "shape": [320], "dist": "normal", "seed": 454, "scale": 0.1 }
187
+ },
188
+ "outputs": {
189
+ "Y": { "dtype": "float16", "shape": [1, 32, 32, 320], "dist": "empty" },
190
+ "S": { "dtype": "float16", "shape": [1, 32, 32, 320], "dist": "empty" }
191
+ },
192
+ "bench": {
193
+ "metrics": [
194
+ {
195
+ "type": "bandwidth",
196
+ "value": "(args.count * args.streams + args.skipElements) * dtypeBytes(args.dtype) + args.channels * 2 * dtypeBytes(args.weightDtype)"
197
+ }
198
+ ]
199
+ }
200
+ },
201
+ {
202
+ "name": "broadcast-skip-rank4-1x32x32x320-g32-f16",
203
+ "preset": "smoke",
204
+ "provenance": {
205
+ "note": "The same per-channel residual and the same data spelled (N, 1, 1, C), to measure the two spellings against each other"
206
+ },
207
+ "vars": {
208
+ "dtype": "float16",
209
+ "weightDtype": "float32",
210
+ "count": 327680,
211
+ "channels": 320,
212
+ "streams": 3,
213
+ "skipElements": 320
214
+ },
215
+ "attrs": { "groups": 32, "activation": 1, "channels_last": 1 },
216
+ "inputs": {
217
+ "X": { "dtype": "float16", "shape": [1, 32, 32, 320], "dist": "normal", "seed": 450, "scale": 0.5 },
218
+ "gamma": { "dtype": "float32", "shape": [320], "dist": "uniform", "seed": 451, "scale": 0.25, "offset": 1 },
219
+ "beta": { "dtype": "float32", "shape": [320], "dist": "normal", "seed": 452, "scale": 0.1 },
220
+ "skip": { "dtype": "float16", "shape": [1, 1, 1, 320], "dist": "normal", "seed": 453, "scale": 0.5 },
221
+ "bias": { "dtype": "float16", "shape": [320], "dist": "normal", "seed": 454, "scale": 0.1 }
222
+ },
223
+ "outputs": {
224
+ "Y": { "dtype": "float16", "shape": [1, 32, 32, 320], "dist": "empty" },
225
+ "S": { "dtype": "float16", "shape": [1, 32, 32, 320], "dist": "empty" }
226
+ },
227
+ "bench": {
228
+ "metrics": [
229
+ {
230
+ "type": "bandwidth",
231
+ "value": "(args.count * args.streams + args.skipElements) * dtypeBytes(args.dtype) + args.channels * 2 * dtypeBytes(args.weightDtype)"
232
+ }
233
+ ]
234
+ }
235
+ },
236
+ {
237
+ "name": "nchw-2x320x64x64-g32-f16-sum",
238
+ "preset": "smoke",
239
+ "provenance": { "note": "Channels-first Stable-Diffusion resnet width with the fused SiLU" },
240
+ "vars": {
241
+ "dtype": "float16",
242
+ "weightDtype": "float32",
243
+ "count": 2621440,
244
+ "channels": 320,
245
+ "streams": 3,
246
+ "skipElements": 2621440
247
+ },
248
+ "attrs": { "groups": 32, "activation": 1, "channels_last": 0 },
249
+ "inputs": {
250
+ "X": { "dtype": "float16", "shape": [2, 320, 64, 64], "dist": "normal", "seed": 460, "scale": 0.5 },
251
+ "gamma": { "dtype": "float32", "shape": [320], "dist": "uniform", "seed": 461, "scale": 0.25, "offset": 1 },
252
+ "beta": { "dtype": "float32", "shape": [320], "dist": "normal", "seed": 462, "scale": 0.1 },
253
+ "skip": { "dtype": "float16", "shape": [2, 320, 64, 64], "dist": "normal", "seed": 463, "scale": 0.5 },
254
+ "bias": { "dtype": "float16", "shape": [320], "dist": "normal", "seed": 464, "scale": 0.1 }
255
+ },
256
+ "outputs": {
257
+ "Y": { "dtype": "float16", "shape": [2, 320, 64, 64], "dist": "empty" },
258
+ "S": { "dtype": "float16", "shape": [2, 320, 64, 64], "dist": "empty" }
259
+ },
260
+ "bench": {
261
+ "metrics": [
262
+ {
263
+ "type": "bandwidth",
264
+ "value": "(args.count * args.streams + args.skipElements) * dtypeBytes(args.dtype) + args.channels * 2 * dtypeBytes(args.weightDtype)"
265
+ }
266
+ ]
267
+ }
268
+ },
269
+ {
270
+ "name": "micro-2x2x2x16-g4-f16-sum",
271
+ "preset": "smoke",
272
+ "provenance": {
273
+ "note": "ORT: onnxruntime/test/contrib_ops/skip_group_norm_op_test.cc SkipGroupNormTest.SkipGroupNorm_with_bias geometry"
274
+ },
275
+ "vars": {
276
+ "dtype": "float16",
277
+ "weightDtype": "float32",
278
+ "count": 128,
279
+ "channels": 16,
280
+ "streams": 3,
281
+ "skipElements": 128
282
+ },
283
+ "attrs": { "groups": 4, "activation": 0, "channels_last": 1 },
284
+ "inputs": {
285
+ "X": { "dtype": "float16", "shape": [2, 2, 2, 16], "dist": "normal", "seed": 470, "scale": 0.5 },
286
+ "gamma": { "dtype": "float32", "shape": [16], "dist": "uniform", "seed": 471, "scale": 0.25, "offset": 1 },
287
+ "beta": { "dtype": "float32", "shape": [16], "dist": "normal", "seed": 472, "scale": 0.1 },
288
+ "skip": { "dtype": "float16", "shape": [2, 2, 2, 16], "dist": "normal", "seed": 473, "scale": 0.5 },
289
+ "bias": { "dtype": "float16", "shape": [16], "dist": "normal", "seed": 474, "scale": 0.1 }
290
+ },
291
+ "outputs": {
292
+ "Y": { "dtype": "float16", "shape": [2, 2, 2, 16], "dist": "empty" },
293
+ "S": { "dtype": "float16", "shape": [2, 2, 2, 16], "dist": "empty" }
294
+ },
295
+ "bench": {
296
+ "metrics": [
297
+ {
298
+ "type": "bandwidth",
299
+ "value": "(args.count * args.streams + args.skipElements) * dtypeBytes(args.dtype) + args.channels * 2 * dtypeBytes(args.weightDtype)"
300
+ }
301
+ ]
302
+ }
303
+ },
304
+ {
305
+ "name": "flux-vae-up-1x256x256x256-g32-f16-sum",
306
+ "preset": "scale",
307
+ "provenance": { "note": "Flux.2 VAE decoder after the second 2x upsample" },
308
+ "vars": {
309
+ "dtype": "float16",
310
+ "weightDtype": "float32",
311
+ "count": 16777216,
312
+ "channels": 256,
313
+ "streams": 3,
314
+ "skipElements": 16777216
315
+ },
316
+ "attrs": { "groups": 32, "activation": 1, "channels_last": 1, "epsilon": 0.000001 },
317
+ "inputs": {
318
+ "X": { "dtype": "float16", "shape": [1, 256, 256, 256], "dist": "normal", "seed": 480, "scale": 0.5 },
319
+ "gamma": { "dtype": "float32", "shape": [256], "dist": "uniform", "seed": 481, "scale": 0.25, "offset": 1 },
320
+ "beta": { "dtype": "float32", "shape": [256], "dist": "normal", "seed": 482, "scale": 0.1 },
321
+ "skip": { "dtype": "float16", "shape": [1, 256, 256, 256], "dist": "normal", "seed": 483, "scale": 0.5 },
322
+ "bias": { "dtype": "float16", "shape": [256], "dist": "normal", "seed": 484, "scale": 0.1 }
323
+ },
324
+ "outputs": {
325
+ "Y": { "dtype": "float16", "shape": [1, 256, 256, 256], "dist": "empty" },
326
+ "S": { "dtype": "float16", "shape": [1, 256, 256, 256], "dist": "empty" }
327
+ },
328
+ "bench": {
329
+ "metrics": [
330
+ {
331
+ "type": "bandwidth",
332
+ "value": "(args.count * args.streams + args.skipElements) * dtypeBytes(args.dtype) + args.channels * 2 * dtypeBytes(args.weightDtype)"
333
+ }
334
+ ]
335
+ }
336
+ },
337
+ {
338
+ "name": "flux-vae-convout-1x512x512x128-g32-f16-nosum",
339
+ "preset": "model",
340
+ "provenance": { "note": "Flux.2 VAE conv_norm_out geometry: the largest single dispatch in the decoder" },
341
+ "vars": {
342
+ "dtype": "float16",
343
+ "weightDtype": "float32",
344
+ "count": 33554432,
345
+ "channels": 128,
346
+ "streams": 2,
347
+ "skipElements": 33554432
348
+ },
349
+ "attrs": { "groups": 32, "activation": 1, "channels_last": 1, "epsilon": 0.000001 },
350
+ "inputs": {
351
+ "X": { "dtype": "float16", "shape": [1, 512, 512, 128], "dist": "normal", "seed": 490, "scale": 0.5 },
352
+ "gamma": { "dtype": "float32", "shape": [128], "dist": "uniform", "seed": 491, "scale": 0.25, "offset": 1 },
353
+ "beta": { "dtype": "float32", "shape": [128], "dist": "normal", "seed": 492, "scale": 0.1 },
354
+ "skip": { "dtype": "float16", "shape": [1, 512, 512, 128], "dist": "normal", "seed": 493, "scale": 0.5 },
355
+ "bias": { "dtype": "float16", "shape": [128], "dist": "normal", "seed": 494, "scale": 0.1 }
356
+ },
357
+ "outputs": { "Y": { "dtype": "float16", "shape": [1, 512, 512, 128], "dist": "empty" } },
358
+ "bench": {
359
+ "metrics": [
360
+ {
361
+ "type": "bandwidth",
362
+ "value": "(args.count * args.streams + args.skipElements) * dtypeBytes(args.dtype) + args.channels * 2 * dtypeBytes(args.weightDtype)"
363
+ }
364
+ ]
365
+ }
366
+ },
367
+ {
368
+ "name": "nhwc-even-groups-2x64x64x320-g32-f32",
369
+ "preset": "smoke",
370
+ "provenance": {
371
+ "note": "Even channel-group widths spanning one, multiple, and capacity-limited channel rows per workgroup, including float32 activations. Same distributions as the authored large NHWC case."
372
+ },
373
+ "vars": {
374
+ "dtype": "float32",
375
+ "weightDtype": "float32",
376
+ "count": 2621440,
377
+ "channels": 320,
378
+ "streams": 3,
379
+ "skipElements": 2621440
380
+ },
381
+ "attrs": { "groups": 32, "activation": 1, "channels_last": 1 },
382
+ "inputs": {
383
+ "X": { "dtype": "float32", "shape": [2, 64, 64, 320], "dist": "normal", "seed": 420, "scale": 0.5 },
384
+ "gamma": { "dtype": "float32", "shape": [320], "dist": "uniform", "seed": 421, "scale": 0.25, "offset": 1 },
385
+ "beta": { "dtype": "float32", "shape": [320], "dist": "normal", "seed": 422, "scale": 0.1 },
386
+ "skip": { "dtype": "float32", "shape": [2, 64, 64, 320], "dist": "normal", "seed": 423, "scale": 0.5 }
387
+ },
388
+ "outputs": {
389
+ "Y": { "dtype": "float32", "shape": [2, 64, 64, 320], "dist": "empty" },
390
+ "S": { "dtype": "float32", "shape": [2, 64, 64, 320], "dist": "empty" }
391
+ },
392
+ "bench": {
393
+ "metrics": [
394
+ {
395
+ "type": "bandwidth",
396
+ "value": "(args.count * args.streams + args.skipElements) * dtypeBytes(args.dtype) + args.channels * 2 * dtypeBytes(args.weightDtype)"
397
+ }
398
+ ]
399
+ }
400
+ },
401
+ {
402
+ "name": "nhwc-even-groups-2x64x64x64-g32-f16",
403
+ "preset": "smoke",
404
+ "provenance": {
405
+ "note": "Even channel-group widths spanning one, multiple, and capacity-limited channel rows per workgroup, including float32 activations. Same distributions as the authored large NHWC case."
406
+ },
407
+ "vars": {
408
+ "dtype": "float16",
409
+ "weightDtype": "float32",
410
+ "count": 524288,
411
+ "channels": 64,
412
+ "streams": 3,
413
+ "skipElements": 524288
414
+ },
415
+ "attrs": { "groups": 32, "activation": 1, "channels_last": 1 },
416
+ "inputs": {
417
+ "X": { "dtype": "float16", "shape": [2, 64, 64, 64], "dist": "normal", "seed": 420, "scale": 0.5 },
418
+ "gamma": { "dtype": "float32", "shape": [64], "dist": "uniform", "seed": 421, "scale": 0.25, "offset": 1 },
419
+ "beta": { "dtype": "float32", "shape": [64], "dist": "normal", "seed": 422, "scale": 0.1 },
420
+ "skip": { "dtype": "float16", "shape": [2, 64, 64, 64], "dist": "normal", "seed": 423, "scale": 0.5 }
421
+ },
422
+ "outputs": {
423
+ "Y": { "dtype": "float16", "shape": [2, 64, 64, 64], "dist": "empty" },
424
+ "S": { "dtype": "float16", "shape": [2, 64, 64, 64], "dist": "empty" }
425
+ },
426
+ "bench": {
427
+ "metrics": [
428
+ {
429
+ "type": "bandwidth",
430
+ "value": "(args.count * args.streams + args.skipElements) * dtypeBytes(args.dtype) + args.channels * 2 * dtypeBytes(args.weightDtype)"
431
+ }
432
+ ]
433
+ }
434
+ },
435
+ {
436
+ "name": "nhwc-even-groups-2x64x64x192-g32-f16",
437
+ "preset": "smoke",
438
+ "provenance": {
439
+ "note": "Even channel-group widths spanning one, multiple, and capacity-limited channel rows per workgroup, including float32 activations. Same distributions as the authored large NHWC case."
440
+ },
441
+ "vars": {
442
+ "dtype": "float16",
443
+ "weightDtype": "float32",
444
+ "count": 1572864,
445
+ "channels": 192,
446
+ "streams": 3,
447
+ "skipElements": 1572864
448
+ },
449
+ "attrs": { "groups": 32, "activation": 1, "channels_last": 1 },
450
+ "inputs": {
451
+ "X": { "dtype": "float16", "shape": [2, 64, 64, 192], "dist": "normal", "seed": 420, "scale": 0.5 },
452
+ "gamma": { "dtype": "float32", "shape": [192], "dist": "uniform", "seed": 421, "scale": 0.25, "offset": 1 },
453
+ "beta": { "dtype": "float32", "shape": [192], "dist": "normal", "seed": 422, "scale": 0.1 },
454
+ "skip": { "dtype": "float16", "shape": [2, 64, 64, 192], "dist": "normal", "seed": 423, "scale": 0.5 }
455
+ },
456
+ "outputs": {
457
+ "Y": { "dtype": "float16", "shape": [2, 64, 64, 192], "dist": "empty" },
458
+ "S": { "dtype": "float16", "shape": [2, 64, 64, 192], "dist": "empty" }
459
+ },
460
+ "bench": {
461
+ "metrics": [
462
+ {
463
+ "type": "bandwidth",
464
+ "value": "(args.count * args.streams + args.skipElements) * dtypeBytes(args.dtype) + args.channels * 2 * dtypeBytes(args.weightDtype)"
465
+ }
466
+ ]
467
+ }
468
+ },
469
+ {
470
+ "name": "nhwc-even-groups-2x64x64x448-g32-f16",
471
+ "preset": "smoke",
472
+ "provenance": {
473
+ "note": "Even channel-group widths spanning one, multiple, and capacity-limited channel rows per workgroup, including float32 activations. Same distributions as the authored large NHWC case."
474
+ },
475
+ "vars": {
476
+ "dtype": "float16",
477
+ "weightDtype": "float32",
478
+ "count": 3670016,
479
+ "channels": 448,
480
+ "streams": 3,
481
+ "skipElements": 3670016
482
+ },
483
+ "attrs": { "groups": 32, "activation": 1, "channels_last": 1 },
484
+ "inputs": {
485
+ "X": { "dtype": "float16", "shape": [2, 64, 64, 448], "dist": "normal", "seed": 420, "scale": 0.5 },
486
+ "gamma": { "dtype": "float32", "shape": [448], "dist": "uniform", "seed": 421, "scale": 0.25, "offset": 1 },
487
+ "beta": { "dtype": "float32", "shape": [448], "dist": "normal", "seed": 422, "scale": 0.1 },
488
+ "skip": { "dtype": "float16", "shape": [2, 64, 64, 448], "dist": "normal", "seed": 423, "scale": 0.5 }
489
+ },
490
+ "outputs": {
491
+ "Y": { "dtype": "float16", "shape": [2, 64, 64, 448], "dist": "empty" },
492
+ "S": { "dtype": "float16", "shape": [2, 64, 64, 448], "dist": "empty" }
493
+ },
494
+ "bench": {
495
+ "metrics": [
496
+ {
497
+ "type": "bandwidth",
498
+ "value": "(args.count * args.streams + args.skipElements) * dtypeBytes(args.dtype) + args.channels * 2 * dtypeBytes(args.weightDtype)"
499
+ }
500
+ ]
501
+ }
502
+ }
503
+ ]
504
+ }
build/webgpu/group-norm-combine.wgsl.jinja ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% set comp0 = ".x" if vecSpec > 1 else "" %}
2
+ {% macro flat_index_2d(workgroupSize, name="i", bound="params.count", guardInline=false) %}
3
+ {% set wgTerm = workgroupSize ~ "u" if workgroupSize is number else workgroupSize %}
4
+ // 2D-folded flat index: gid.y carries the high bits past the dispatch's
5
+ // per-axis workgroup fold width.
6
+ let {{ name }} = gid.x + gid.y * {{ DISPATCH_FOLD_WIDTH }}u * {{ wgTerm }};
7
+ if ({{ name }} >= {{ bound }}) {
8
+ return;
9
+ }{% endmacro %}
10
+ {{ env.wgsl.resourceDeclarations }}
11
+
12
+ // The partials hold sum(value - shift) and sum((value - shift)^2) over disjoint blocks
13
+ // of the group, all taken against the same `shift` — the group's first element — so
14
+ // they add directly. Recovering the mean adds the shift back; the variance is formed
15
+ // from the shifted second moment and clamped at zero, which is where a group whose
16
+ // values are all equal would otherwise land a few ulp below it.
17
+ const GROUPS: u32 = {{ groupsSpec }}u;
18
+ const CPG: u32 = {{ cpgSpec }}u;
19
+ const ROWS: u32 = {{ normRowsSpec }}u;
20
+ const PARTIALS_PER_ROW: u32 = {{ partialsPerRowSpec }}u;
21
+ const GROUP_SIZE: f32 = {{ groupSizeSpec }}.0;
22
+ const EPSILON: f32 = {{ epsilonSpec }};
23
+ const WG: u32 = {{ combineWgSpec }}u;
24
+ {% if phaseLayout %}
25
+ const HW: u32 = {{ dimHWSpec }}u;
26
+ const CHUNKS: u32 = {{ chunksSpec }}u;
27
+ const VEC: u32 = {{ vecSpec }}u;
28
+ {% else %}
29
+ const CHANNELS: u32 = {{ dimCSpec }}u;
30
+ const PLANE_V: u32 = {{ planeVecsSpec }}u;
31
+ {% endif %}
32
+
33
+ @compute @workgroup_size(WG)
34
+ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
35
+ {{ flat_index_2d("WG", "row", "ROWS") }}
36
+ let n = row / GROUPS;
37
+ let g = row % GROUPS;
38
+ {% if phaseLayout %}
39
+ let shift = f32(src[n * HW * CHUNKS + g * (CPG / VEC)]{{ comp0 }});
40
+ {% else %}
41
+ let shift = f32(src[(n * CHANNELS + g * CPG) * PLANE_V]{{ comp0 }});
42
+ {% endif %}
43
+ var total = vec2<f32>(0.0);
44
+ for (var k = 0u; k < PARTIALS_PER_ROW; k = k + 1u) {
45
+ total = total + partials[row * PARTIALS_PER_ROW + k];
46
+ }
47
+ let mean_d = total.x / GROUP_SIZE;
48
+ let variance = max(total.y / GROUP_SIZE - mean_d * mean_d, 0.0);
49
+ stats[row] = vec2<f32>(shift + mean_d, inverseSqrt(variance + EPSILON));
50
+ }
build/webgpu/group-norm-fused.wgsl.jinja ADDED
@@ -0,0 +1,190 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% set comp0 = ".x" if useVec4 else "" %}
2
+ {% macro pre_norm(idx, sidx) %}
3
+ {% set x = vecF32 ~ "(X[" ~ idx ~ "])" %}
4
+ {% set skipTerm = "skip_v" if broadcastSkip else vecF32 ~ "(skip[" ~ sidx ~ "])" %}
5
+ {{ vecF32 ~ "(" ~ storeElement ~ "(" ~ x ~ " + " ~ skipTerm ~ " + bias_v))" if hasSkip else x }}{% endmacro %}
6
+ {% macro shift_at(idx, sidx, ch) %}
7
+ {% set x = "f32(X[" ~ idx ~ "]" ~ comp0 ~ ")" %}
8
+ {% set skipTerm = "f32(skip[" ~ sidx ~ "]" ~ ("" if broadcastSkip else comp0) ~ ")" %}
9
+ {% set biasTerm = " + f32(bias[" ~ ch ~ "])" if hasBias else "" %}
10
+ {{ "f32(" ~ tScalar ~ "(" ~ x ~ " + " ~ skipTerm ~ biasTerm ~ "))" if hasSkip else x }}{% endmacro %}
11
+ {{ env.wgsl.resourceDeclarations }}
12
+
13
+ // Group normalization in one dispatch. The workgroup accumulates the group's shifted
14
+ // moments, folds them through workgroup memory, then walks the same elements again to
15
+ // write `gamma * (value - mean) * inv_std + beta`. Every intermediate is f32 whatever
16
+ // the tensor type; only the store narrows. The reduction is a plain halving tree over
17
+ // a power-of-two-padded scratch array, so it is deterministic and needs no subgroup
18
+ // support.
19
+ const CPG: u32 = {{ cpgSpec }}u;
20
+ const GROUPS: u32 = {{ groupsSpec }}u;
21
+ const ROWS: u32 = {{ normRowsSpec }}u;
22
+ const GROUP_SIZE: f32 = {{ groupSizeSpec }}.0;
23
+ const EPSILON: f32 = {{ epsilonSpec }};
24
+ const WG: u32 = {{ wgSpec }}u;
25
+ const LANES: u32 = {{ ldsSpec }}u;
26
+ {% if phaseLayout %}
27
+ const HW: u32 = {{ dimHWSpec }}u;
28
+ const VEC: u32 = {{ vecSpec }}u;
29
+ const CHUNKS: u32 = {{ chunksSpec }}u;
30
+ const SEGMENT: u32 = {{ fusedChunksSpec }}u;
31
+ const SUB_ROWS: u32 = {{ fusedRowsSpec }}u;
32
+ {% if hasSkip and broadcastSkip %}
33
+ const CHANNELS: u32 = {{ dimCSpec }}u;
34
+ {% endif %}
35
+ {% else %}
36
+ const CHANNELS: u32 = {{ dimCSpec }}u;
37
+ const PLANE_V: u32 = {{ planeVecsSpec }}u;
38
+ const SPAN_V: u32 = {{ spanVecsSpec }}u;
39
+ {% endif %}
40
+
41
+ // LANES is WG rounded up to a power of two; the lanes past WG are zeroed so the
42
+ // halving tree below stays uniform.
43
+ var<workgroup> lane_sums: array<vec2<f32>, LANES>;
44
+ {% if activationSpec == 1 %}
45
+
46
+ fn silu_e(v: {{ vecF32 }}) -> {{ vecF32 }} {
47
+ return v / ({{ vecF32 }}(1.0) + exp(-v));
48
+ }
49
+ {% endif %}
50
+
51
+ @compute @workgroup_size(WG)
52
+ fn main(@builtin(workgroup_id) wg: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {
53
+ // 2D-folded row index: wg.y carries the high bits past the dispatch's per-axis
54
+ // workgroup fold width.
55
+ let row = wg.x + wg.y * {{ DISPATCH_FOLD_WIDTH }}u;
56
+ if (row >= ROWS) {
57
+ return;
58
+ }
59
+ let n = row / GROUPS;
60
+ let g = row - n * GROUPS;
61
+ {% if phaseLayout %}
62
+ let chunk = lid.x % SEGMENT;
63
+ let sub_row = lid.x / SEGMENT;
64
+ let c0 = g * CPG + chunk * VEC;
65
+ let base_v = n * HW * CHUNKS + g * SEGMENT;
66
+ let shift_index = base_v;
67
+ {% if broadcastSkip %}
68
+ let shift_skip = n * CHANNELS + g * CPG;
69
+ {% else %}
70
+ let skip_base = base_v;
71
+ let shift_skip = base_v;
72
+ {% endif %}
73
+ {% else %}
74
+ let base_v = (n * CHANNELS + g * CPG) * PLANE_V;
75
+ let shift_index = base_v;
76
+ {% if broadcastSkip %}
77
+ let shift_skip = n * CHANNELS + g * CPG;
78
+ {% else %}
79
+ let skip_base = base_v;
80
+ let shift_skip = base_v;
81
+ {% endif %}
82
+ {% endif %}
83
+ {% if hasBias %}
84
+ {% if phaseLayout %}
85
+ {% if useVec4 %}
86
+ let bias_v = vec4<f32>(f32(bias[c0]), f32(bias[c0 + 1u]), f32(bias[c0 + 2u]), f32(bias[c0 + 3u]));
87
+ {% else %}
88
+ let bias_v = f32(bias[c0]);
89
+ {% endif %}
90
+ {% else %}
91
+ // Channels first: the channel changes as this workgroup's walk crosses a plane, so
92
+ // the per-channel bias is refreshed inside the loop rather than hoisted.
93
+ var bias_v = {{ vecF32 }}(0.0);
94
+ {% endif %}
95
+ {% else %}
96
+ let bias_v = {{ vecF32 }}(0.0);
97
+ {% endif %}
98
+ {% if broadcastSkip %}
99
+ {% if phaseLayout %}
100
+ {% set sb = "n * CHANNELS + c0" %}
101
+ {% if useVec4 %}
102
+ let skip_v = vec4<f32>(f32(skip[{{ sb }}]), f32(skip[{{ sb }} + 1u]), f32(skip[{{ sb }} + 2u]), f32(skip[{{ sb }} + 3u]));
103
+ {% else %}
104
+ let skip_v = f32(skip[{{ sb }}]);
105
+ {% endif %}
106
+ {% else %}
107
+ // Channels first: this workgroup owns a whole group, so the channel — and with it
108
+ // the broadcast skip value — changes as the walk crosses a channel plane.
109
+ var skip_v = {{ vecF32 }}(0.0);
110
+ {% endif %}
111
+ {% endif %}
112
+ let shift = {{ shift_at("shift_index", "shift_skip", "g * CPG") }};
113
+ var acc = vec2<f32>(0.0);
114
+ {% if phaseLayout %}
115
+ for (var hw = sub_row; hw < HW; hw = hw + SUB_ROWS) {
116
+ let idx = base_v + hw * CHUNKS + chunk;
117
+ let v = {{ pre_norm("idx", "skip_base + hw * CHUNKS + chunk") }};
118
+ {% else %}
119
+ for (var i = lid.x; i < SPAN_V; i = i + WG) {
120
+ let idx = base_v + i;
121
+ {% if hasSkip and (hasBias or broadcastSkip) %}
122
+ let channel = g * CPG + i / PLANE_V;
123
+ {% if hasBias %}
124
+ bias_v = {{ vecF32 }}(f32(bias[channel]));
125
+ {% endif %}
126
+ {% if broadcastSkip %}
127
+ skip_v = {{ vecF32 }}(f32(skip[n * CHANNELS + channel]));
128
+ {% endif %}
129
+ {% endif %}
130
+ let v = {{ pre_norm("idx", "skip_base + i") }};
131
+ {% endif %}
132
+ {{ fusedSrc }}[idx] = {{ storeElement }}(v);
133
+ let d = v - {{ vecF32 }}(shift);
134
+ {% if useVec4 %}
135
+ acc = acc + vec2<f32>(d.x + d.y + d.z + d.w, dot(d, d));
136
+ {% else %}
137
+ acc = acc + vec2<f32>(d, d * d);
138
+ {% endif %}
139
+ }
140
+ lane_sums[lid.x] = acc;
141
+ if (lid.x + WG < LANES) {
142
+ lane_sums[lid.x + WG] = vec2<f32>(0.0);
143
+ }
144
+ workgroupBarrier();
145
+ var stride = LANES / 2u;
146
+ loop {
147
+ if (stride == 0u) {
148
+ break;
149
+ }
150
+ if (lid.x < stride) {
151
+ lane_sums[lid.x] = lane_sums[lid.x] + lane_sums[lid.x + stride];
152
+ }
153
+ workgroupBarrier();
154
+ stride = stride / 2u;
155
+ }
156
+ let total = lane_sums[0];
157
+ let mean_d = total.x / GROUP_SIZE;
158
+ let variance = max(total.y / GROUP_SIZE - mean_d * mean_d, 0.0);
159
+ let mean = {{ vecF32 }}(shift + mean_d);
160
+ let inv_std = {{ vecF32 }}(inverseSqrt(variance + EPSILON));
161
+ {% if phaseLayout %}
162
+ {% if useVec4 %}
163
+ let gamma_v = vec4<f32>(f32(gamma[c0]), f32(gamma[c0 + 1u]), f32(gamma[c0 + 2u]), f32(gamma[c0 + 3u]));
164
+ let beta_v = vec4<f32>(f32(beta[c0]), f32(beta[c0 + 1u]), f32(beta[c0 + 2u]), f32(beta[c0 + 3u]));
165
+ {% else %}
166
+ let gamma_v = f32(gamma[c0]);
167
+ let beta_v = f32(beta[c0]);
168
+ {% endif %}
169
+ for (var hw = sub_row; hw < HW; hw = hw + SUB_ROWS) {
170
+ let idx = base_v + hw * CHUNKS + chunk;
171
+ {% else %}
172
+ for (var i = lid.x; i < SPAN_V; i = i + WG) {
173
+ let idx = base_v + i;
174
+ let channel = g * CPG + i / PLANE_V;
175
+ {% if useVec4 %}
176
+ let gamma_v = vec4<f32>(f32(gamma[channel]));
177
+ let beta_v = vec4<f32>(f32(beta[channel]));
178
+ {% else %}
179
+ let gamma_v = f32(gamma[channel]);
180
+ let beta_v = f32(beta[channel]);
181
+ {% endif %}
182
+ {% endif %}
183
+ let normalized = ({{ vecF32 }}({{ fusedSrc }}[idx]) - mean) * inv_std;
184
+ {% if activationSpec == 1 %}
185
+ Y[idx] = {{ storeElement }}(silu_e(gamma_v * normalized + beta_v));
186
+ {% else %}
187
+ Y[idx] = {{ storeElement }}(gamma_v * normalized + beta_v);
188
+ {% endif %}
189
+ }
190
+ }
build/webgpu/group-norm-slab.wgsl.jinja ADDED
@@ -0,0 +1,277 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% set blockedStats = phase == "stats" and phaseLayout and (statsBlockedSpec | default(false)) %}
2
+ {% set useVector = vecSpec > 1 %}
3
+ {% set comp0 = ".x" if useVector else "" %}
4
+ {% macro channel_values(buffer, channel) %}
5
+ {{ vecF32 }}({% for i in range(vecSpec) %}f32({{ buffer }}[{{ channel }}{% if i > 0 %} + {{ i }}u{% endif %}]){% if not loop.last %}, {% endif %}{% endfor %}){% endmacro %}
6
+ {% macro component_sum(value) %}
7
+ {% for i in range(vecSpec) %}{{ value }}.{{ "xyzw"[i] }}{% if not loop.last %} + {% endif %}{% endfor %}{% endmacro %}
8
+ {% macro pre_norm(idx, sidx) %}
9
+ {% set x = vecF32 ~ "(X[" ~ idx ~ "])" %}
10
+ {% set skipTerm = "skip_v" if broadcastSkip else vecF32 ~ "(skip[" ~ sidx ~ "])" %}
11
+ {{ vecF32 ~ "(" ~ storeElement ~ "(" ~ x ~ " + " ~ skipTerm ~ " + bias_v))" if hasSkip else x }}{% endmacro %}
12
+ {% macro shift_at(idx, sidx, ch) %}
13
+ {% set x = "f32(X[" ~ idx ~ "]" ~ comp0 ~ ")" %}
14
+ {% set skipTerm = "f32(skip[" ~ sidx ~ "]" ~ ("" if broadcastSkip else comp0) ~ ")" %}
15
+ {% set biasTerm = " + f32(bias[" ~ ch ~ "])" if hasBias else "" %}
16
+ {{ "f32(" ~ tScalar ~ "(" ~ x ~ " + " ~ skipTerm ~ biasTerm ~ "))" if hasSkip else x }}{% endmacro %}
17
+ {{ env.wgsl.resourceDeclarations }}
18
+
19
+ // One phase of group normalization over a 4-D image tensor.
20
+ //
21
+ // A group is every spatial position of `CPG` adjacent channels of one batch item. The
22
+ // statistics phase accumulates the sum and the sum of squares of `value - shift`,
23
+ // where `shift` is the group's first element: subtracting one member of the group
24
+ // removes the common offset before the second moment is formed, so the variance the
25
+ // combine pass derives does not cancel against a large mean. The apply phase reads the
26
+ // combined mean and reciprocal standard deviation back and writes
27
+ // `gamma * (value - mean) * inv_std + beta`, optionally through SiLU.
28
+ //
29
+ // Every accumulation and the whole affine are f32 whatever the tensor type; only the
30
+ // store narrows.
31
+ const CPG: u32 = {{ cpgSpec }}u;
32
+ const GROUPS: u32 = {{ groupsSpec }}u;
33
+ const WG: u32 = {{ wgSpec }}u;
34
+ const UNITS: u32 = {{ unitsSpec }}u;
35
+ {% if phaseLayout %}
36
+ const HW: u32 = {{ dimHWSpec }}u;
37
+ const VEC: u32 = {{ vecSpec }}u;
38
+ const CHUNKS: u32 = {{ chunksSpec }}u;
39
+ const ROWS_PER_STEP: u32 = {{ rowsPerStepSpec }}u;
40
+ const ROWS_PER_SLAB: u32 = {{ rowsPerSlabSpec }}u;
41
+ const SLABS: u32 = {{ splitSpec }}u;
42
+ {% if blockedStats %}
43
+ const GROUP_BLOCKS: u32 = {{ statsGroupBlocksSpec }}u;
44
+ const GROUPS_PER_BLOCK: u32 = {{ statsGroupsPerBlockSpec }}u;
45
+ const TILE_CHUNKS: u32 = {{ statsTileChunksSpec }}u;
46
+ {% endif %}
47
+ {% if hasSkip and broadcastSkip and phase == "stats" %}
48
+ const CHANNELS: u32 = {{ dimCSpec }}u;
49
+ {% endif %}
50
+ {% else %}
51
+ const CHANNELS: u32 = {{ dimCSpec }}u;
52
+ const PLANE_V: u32 = {{ planeVecsSpec }}u;
53
+ const CHUNK_V: u32 = {{ chunkVecsSpec }}u;
54
+ const SPLITS: u32 = {{ splitSpec }}u;
55
+ {% endif %}
56
+ {% if phase == "stats" %}
57
+ {% if not phaseLayout %}
58
+ const PARTIALS_PER_ROW: u32 = {{ partialsPerRowSpec }}u;
59
+ {% endif %}
60
+
61
+ // Per-lane moments, combined below: the channels-last arm folds one contiguous
62
+ // segment per group out of this array, the channels-first arm folds all of it.
63
+ var<workgroup> lane_sums: array<vec2<f32>, WG>;
64
+ {% endif %}
65
+ {% if phase == "apply" and activationSpec == 1 %}
66
+
67
+ fn silu_e(v: {{ vecF32 }}) -> {{ vecF32 }} {
68
+ return v / ({{ vecF32 }}(1.0) + exp(-v));
69
+ }
70
+ {% endif %}
71
+
72
+ @compute @workgroup_size(WG)
73
+ fn main(@builtin(workgroup_id) wg: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {
74
+ // 2D-folded work-unit index: wg.y carries the high bits past the dispatch's
75
+ // per-axis workgroup fold width.
76
+ let unit = wg.x + wg.y * {{ DISPATCH_FOLD_WIDTH }}u;
77
+ if (unit >= UNITS) {
78
+ return;
79
+ }
80
+ {% if phaseLayout %}
81
+ // Channels last. The workgroup owns one batch item and one slab of spatial rows and
82
+ // covers every channel of those rows: lane `lid.x` keeps channel chunk
83
+ // `lid.x % CHUNKS` and steps through the slab `ROWS_PER_STEP` rows at a time, so the
84
+ // workgroup reads whole contiguous channel rows and each lane's group is fixed.
85
+ {% if blockedStats %}
86
+ let spatial_unit = unit / GROUP_BLOCKS;
87
+ let group_begin = (unit % GROUP_BLOCKS) * GROUPS_PER_BLOCK;
88
+ let n = spatial_unit / SLABS;
89
+ let slab = spatial_unit - n * SLABS;
90
+ let chunk = group_begin * (CPG / VEC) + lid.x % TILE_CHUNKS;
91
+ let sub_row = lid.x / TILE_CHUNKS;
92
+ {% else %}
93
+ let n = unit / SLABS;
94
+ let slab = unit - n * SLABS;
95
+ let chunk = lid.x % CHUNKS;
96
+ let sub_row = lid.x / CHUNKS;
97
+ {% endif %}
98
+ let c0 = chunk * VEC;
99
+ {% if phase == "stats" or groupUniform %}
100
+ let g = c0 / CPG;
101
+ {% endif %}
102
+ let image_base = n * HW * CHUNKS;
103
+ let hw_begin = slab * ROWS_PER_SLAB;
104
+ let hw_end = min(hw_begin + ROWS_PER_SLAB, HW);
105
+ {% else %}
106
+ // Channels first. The workgroup owns one contiguous chunk of one (batch item,
107
+ // channel) plane, so every lane shares the channel and the group and the loads are
108
+ // contiguous across the workgroup. Adjacent units are adjacent chunks of one plane.
109
+ let plane = unit / SPLITS;
110
+ let part = unit - plane * SPLITS;
111
+ let n = plane / CHANNELS;
112
+ let c = plane % CHANNELS;
113
+ let g = c / CPG;
114
+ let base_v = plane * PLANE_V;
115
+ let chunk_begin = part * CHUNK_V;
116
+ let chunk_end = min(chunk_begin + CHUNK_V, PLANE_V);
117
+ {% endif %}
118
+ {% if phase == "stats" %}
119
+ {% if blockedStats %}
120
+ var acc = vec2<f32>(0.0);
121
+ // Keep tail lanes participating in the barrier without reading outside the group.
122
+ if (g < GROUPS) {
123
+ {% endif %}
124
+ {% if phaseLayout %}
125
+ let shift_index = image_base + g * (CPG / VEC);
126
+ {% else %}
127
+ let shift_index = (n * CHANNELS + g * CPG) * PLANE_V;
128
+ {% endif %}
129
+ {% if broadcastSkip %}
130
+ let shift_skip = n * CHANNELS + g * CPG;
131
+ {% elif phaseLayout %}
132
+ let skip_base = image_base;
133
+ let shift_skip = shift_index;
134
+ {% else %}
135
+ let skip_base = base_v;
136
+ let shift_skip = shift_index;
137
+ {% endif %}
138
+ {% if hasBias %}
139
+ {% if useVector %}
140
+ {% if phaseLayout %}
141
+ let bias_v = {{ channel_values("bias", "c0") }};
142
+ {% else %}
143
+ let bias_v = {{ vecF32 }}(f32(bias[c]));
144
+ {% endif %}
145
+ {% else %}
146
+ {% if phaseLayout %}
147
+ let bias_v = f32(bias[c0]);
148
+ {% else %}
149
+ let bias_v = f32(bias[c]);
150
+ {% endif %}
151
+ {% endif %}
152
+ {% else %}
153
+ let bias_v = {{ vecF32 }}(0.0);
154
+ {% endif %}
155
+ {% if broadcastSkip %}
156
+ {% if phaseLayout %}
157
+ {% set sb = "n * CHANNELS + c0" %}
158
+ {% if useVector %}
159
+ let skip_v = {{ channel_values("skip", sb) }};
160
+ {% else %}
161
+ let skip_v = f32(skip[{{ sb }}]);
162
+ {% endif %}
163
+ {% else %}
164
+ // A broadcast skip is one value per (batch item, channel); this whole workgroup
165
+ // shares a channel, so it is read once and splatted.
166
+ let skip_v = {{ vecF32 }}(f32(skip[n * CHANNELS + c]));
167
+ {% endif %}
168
+ {% endif %}
169
+ let shift = {{ shift_at("shift_index", "shift_skip", "g * CPG") }};
170
+ {% if not blockedStats %}
171
+ var acc = vec2<f32>(0.0);
172
+ {% endif %}
173
+ {% if phaseLayout %}
174
+ for (var hw = hw_begin + sub_row; hw < hw_end; hw = hw + ROWS_PER_STEP) {
175
+ let idx = image_base + hw * CHUNKS + chunk;
176
+ let v = {{ pre_norm("idx", "skip_base + hw * CHUNKS + chunk") }};
177
+ {% else %}
178
+ for (var i = chunk_begin + lid.x; i < chunk_end; i = i + WG) {
179
+ let idx = base_v + i;
180
+ let v = {{ pre_norm("idx", "skip_base + i") }};
181
+ {% endif %}
182
+ sum_dst[idx] = {{ storeElement }}(v);
183
+ let d = v - {{ vecF32 }}(shift);
184
+ {% if useVector %}
185
+ acc = acc + vec2<f32>({{ component_sum("d") }}, dot(d, d));
186
+ {% else %}
187
+ acc = acc + vec2<f32>(d, d * d);
188
+ {% endif %}
189
+ }
190
+ {% if blockedStats %}
191
+ }
192
+ {% endif %}
193
+ lane_sums[lid.x] = acc;
194
+ workgroupBarrier();
195
+ {% if phaseLayout %}
196
+ // One aligned segment of `CPG / VEC` lanes per group per sub-row. Each group's
197
+ // partial is summed in a fixed order by a single lane, so the value does not depend
198
+ // on how the workgroup was scheduled.
199
+ let segment = CPG / VEC;
200
+ for (var sel = lid.x; sel < {% if blockedStats %}min(GROUPS_PER_BLOCK, GROUPS - group_begin){% else %}GROUPS{% endif %}; sel = sel + WG) {
201
+ var total = vec2<f32>(0.0);
202
+ for (var r = 0u; r < ROWS_PER_STEP; r = r + 1u) {
203
+ let seg_base = r * {% if blockedStats %}TILE_CHUNKS{% else %}CHUNKS{% endif %} + sel * segment;
204
+ for (var t = 0u; t < segment; t = t + 1u) {
205
+ total = total + lane_sums[seg_base + t];
206
+ }
207
+ }
208
+ partials[(n * GROUPS + {% if blockedStats %}group_begin + {% endif %}sel) * SLABS + slab] = total;
209
+ }
210
+ {% else %}
211
+ // WG is a power of two on this arm, so the halving stride is uniform across the
212
+ // workgroup and every lane reaches every barrier.
213
+ var stride = WG / 2u;
214
+ loop {
215
+ if (stride == 0u) {
216
+ break;
217
+ }
218
+ if (lid.x < stride) {
219
+ lane_sums[lid.x] = lane_sums[lid.x] + lane_sums[lid.x + stride];
220
+ }
221
+ workgroupBarrier();
222
+ stride = stride / 2u;
223
+ }
224
+ if (lid.x == 0u) {
225
+ partials[(n * GROUPS + g) * PARTIALS_PER_ROW + (c - g * CPG) * SPLITS + part] = lane_sums[0];
226
+ }
227
+ {% endif %}
228
+ {% else %}
229
+ {% if groupUniform %}
230
+ let st = stats[n * GROUPS + g];
231
+ let mean = {{ vecF32 }}(st.x);
232
+ let inv_std = {{ vecF32 }}(st.y);
233
+ {% else %}
234
+ // The four channels this lane holds do not all belong to one group, which is what
235
+ // `channels_per_group % 4 != 0` means. The statistics are still read once per lane,
236
+ // as a component-wise gather over at most two adjacent groups.
237
+ let row_base = n * GROUPS;
238
+ let s0 = stats[row_base + c0 / CPG];
239
+ let s1 = stats[row_base + (c0 + 1u) / CPG];
240
+ let s2 = stats[row_base + (c0 + 2u) / CPG];
241
+ let s3 = stats[row_base + (c0 + 3u) / CPG];
242
+ let mean = vec4<f32>(s0.x, s1.x, s2.x, s3.x);
243
+ let inv_std = vec4<f32>(s0.y, s1.y, s2.y, s3.y);
244
+ {% endif %}
245
+ {% if useVector %}
246
+ {% if phaseLayout %}
247
+ let gamma_v = {{ channel_values("gamma", "c0") }};
248
+ let beta_v = {{ channel_values("beta", "c0") }};
249
+ {% else %}
250
+ let gamma_v = {{ vecF32 }}(f32(gamma[c]));
251
+ let beta_v = {{ vecF32 }}(f32(beta[c]));
252
+ {% endif %}
253
+ {% else %}
254
+ {% if phaseLayout %}
255
+ let gamma_v = f32(gamma[c0]);
256
+ let beta_v = f32(beta[c0]);
257
+ {% else %}
258
+ let gamma_v = f32(gamma[c]);
259
+ let beta_v = f32(beta[c]);
260
+ {% endif %}
261
+ {% endif %}
262
+ {% if phaseLayout %}
263
+ for (var hw = hw_begin + sub_row; hw < hw_end; hw = hw + ROWS_PER_STEP) {
264
+ let idx = image_base + hw * CHUNKS + chunk;
265
+ {% else %}
266
+ for (var i = chunk_begin + lid.x; i < chunk_end; i = i + WG) {
267
+ let idx = base_v + i;
268
+ {% endif %}
269
+ let normalized = ({{ vecF32 }}({{ applySrc }}[idx]) - mean) * inv_std;
270
+ {% if activationSpec == 1 %}
271
+ Y[idx] = {{ storeElement }}(silu_e(gamma_v * normalized + beta_v));
272
+ {% else %}
273
+ Y[idx] = {{ storeElement }}(gamma_v * normalized + beta_v);
274
+ {% endif %}
275
+ }
276
+ {% endif %}
277
+ }
build/webgpu/manifest.json ADDED
@@ -0,0 +1,633 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "domain": "com.microsoft",
3
+ "name": "SkipGroupNorm",
4
+ "sinceVersion": 1,
5
+ "inputs": {
6
+ "X": { "dtype": "T", "rank": 4 },
7
+ "gamma": { "dtype": "M", "rank": 1 },
8
+ "beta": { "dtype": "M", "rank": 1 },
9
+ "skip": { "dtype": "T" },
10
+ "bias": { "dtype": "T", "rank": 1, "optional": true }
11
+ },
12
+ "outputs": {
13
+ "Y": { "dtype": "T", "rank": 4, "shape": "shapes.X" },
14
+ "S": { "dtype": "T", "rank": 4, "optional": true, "shape": "shapes.X" }
15
+ },
16
+ "attributes": { "activation": {}, "groups": {}, "channels_last": { "default": 1 }, "epsilon": { "default": 0.00001 } },
17
+ "attributeConstraints": { "activation": { "required": true, "values": [0, 1] }, "groups": { "required": true } },
18
+ "typeConstraints": { "T": ["float32", "float16"], "M": ["float32", "float16"] },
19
+ "tunables": {
20
+ "WORKGROUP_SIZE": { "default": 256 },
21
+ "MAX_SPLITS": { "default": 256 },
22
+ "VALUES_PER_SPLIT": { "default": 4096 },
23
+ "SPLIT_MIN_ELEMENTS": { "default": 262144 },
24
+ "APPLY_SLAB_ELEMENTS": { "default": 8192 },
25
+ "FUSED_MIN_ROWS": { "default": 64 },
26
+ "FUSED_MAX_GROUP_BYTES": { "default": 131072 }
27
+ },
28
+ "derive": {
29
+ "attrsPresent": "has(attrs, \"groups\") and has(attrs, \"activation\")",
30
+ "numGroups": "attrs.groups if attrsPresent else 0",
31
+ "activationKind": "attrs.activation if attrsPresent else 0",
32
+ "channelsLast": "attrs.channels_last != 0",
33
+ "rankOk": "ranks.X == 4 and ranks.Y == 4 and ranks.gamma == 1 and ranks.beta == 1",
34
+ "dimN": "dim(shapes.X, 0) if rankOk else 0",
35
+ "dimC": "(dim(shapes.X, 3) if channelsLast else dim(shapes.X, 1)) if rankOk else 0",
36
+ "dimHW": "(dim(shapes.X, 1) * dim(shapes.X, 2) if channelsLast else dim(shapes.X, 2) * dim(shapes.X, 3)) if rankOk else 0",
37
+ "groupsOk": "numGroups >= 1 and dimC >= 1 and dimC % numGroups == 0",
38
+ "channelsPerGroup": "dimC / numGroups if groupsOk else 0",
39
+ "planeCount": "dimN * dimC",
40
+ "groupSize": "channelsPerGroup * dimHW",
41
+ "normRows": "dimN * numGroups",
42
+ "elementCount": "numel(shapes.X) if rankOk else 0",
43
+ "shapeOk": "rankOk and groupsOk and dimN > 0 and dimHW > 0 and groupSize > 0 and sameShape(shapes.Y, shapes.X) and dim(shapes.gamma, 0) == dimC and dim(shapes.beta, 0) == dimC",
44
+ "deviceWorkgroupCap": "min(device.limits.maxComputeInvocationsPerWorkgroup, device.limits.maxComputeWorkgroupSizeX)",
45
+ "storageBufferLimit": "min(device.limits.maxStorageBufferBindingSize, device.limits.maxBufferSize)",
46
+ "foldedDispatchCapacity": "min(device.limits.maxComputeWorkgroupsPerDimension, 65535) * min(device.limits.maxComputeWorkgroupsPerDimension, 65535)",
47
+ "statsVec4Ok": "(channelsPerGroup % 4 == 0 and dimC % 4 == 0) if channelsLast else (dimHW % 4 == 0)",
48
+ "applyVec4Ok": "(dimC % 4 == 0) if channelsLast else (dimHW % 4 == 0)",
49
+ "fusedVecWidth": "4 if statsVec4Ok else 1",
50
+ "statsVecWidth": "4 if statsVec4Ok else (2 if channelsLast and channelsPerGroup % 2 == 0 else 1)",
51
+ "applyVecWidth": "4 if applyVec4Ok else 1",
52
+ "workgroupCap": "max(1, floor(pow2ceil(min(tunables.WORKGROUP_SIZE, deviceWorkgroupCap) + 1) / 2))",
53
+ "statsChunks": "max(1, floor(dimC / statsVecWidth))",
54
+ "fusedRowChunks": "max(1, floor(dimC / fusedVecWidth))",
55
+ "statsSegment": "max(1, floor(channelsPerGroup / statsVecWidth))",
56
+ "statsGroupsPerBlock": "max(1, min(numGroups, floor(workgroupCap / statsSegment))) if channelsLast and statsChunks > deviceWorkgroupCap and statsSegment <= workgroupCap else max(1, numGroups)",
57
+ "statsGroupBlocks": "ceilDiv(max(1, numGroups), statsGroupsPerBlock)",
58
+ "statsTileChunks": "statsGroupsPerBlock * statsSegment if statsGroupBlocks > 1 else statsChunks",
59
+ "applyChunks": "max(1, floor(dimC / applyVecWidth))",
60
+ "statsRowsPerStep": "max(1, floor(workgroupCap / statsTileChunks))",
61
+ "applyRowsPerStep": "max(1, floor(workgroupCap / applyChunks))",
62
+ "planeVecs": "max(1, floor(dimHW / statsVecWidth))",
63
+ "slabCount": "ceilDiv(dimHW, ceilDiv(dimHW, max(1, min(tunables.MAX_SPLITS, dimHW, ceilDiv(dimHW * dimC, tunables.VALUES_PER_SPLIT)))))",
64
+ "planeSplits": "max(1, min(tunables.MAX_SPLITS, planeVecs, ceilDiv(dimHW, tunables.VALUES_PER_SPLIT)))",
65
+ "splitCount": "slabCount if channelsLast else planeSplits",
66
+ "partialsPerRow": "slabCount if channelsLast else max(1, channelsPerGroup) * planeSplits",
67
+ "partialElements": "max(1, normRows * partialsPerRow)",
68
+ "statsElements": "max(1, normRows)",
69
+ "statsWorkgroup": "(statsTileChunks * statsRowsPerStep) if channelsLast else min(workgroupCap, max(32, pow2ceil(ceilDiv(planeVecs, planeSplits))))",
70
+ "applyWorkgroup": "(applyChunks * applyRowsPerStep) if channelsLast else statsWorkgroup",
71
+ "applySlabCount": "ceilDiv(dimHW, ceilDiv(dimHW, max(1, min(dimHW, min(device.limits.maxComputeWorkgroupsPerDimension, 65535), ceilDiv(elementCount, tunables.APPLY_SLAB_ELEMENTS)))))",
72
+ "applySplit": "applySlabCount if channelsLast else planeSplits",
73
+ "applyUnits": "(dimN * applySlabCount) if channelsLast else (planeCount * planeSplits)",
74
+ "workUnits": "(dimN * slabCount * statsGroupBlocks) if channelsLast else (planeCount * planeSplits)",
75
+ "splitFits": "statsWorkgroup <= deviceWorkgroupCap and applyWorkgroup <= deviceWorkgroupCap and statsWorkgroup * 8 <= device.limits.maxComputeWorkgroupStorageSize and partialElements * 8 <= storageBufferLimit and workUnits > 0 and workUnits <= foldedDispatchCapacity and applyUnits <= foldedDispatchCapacity",
76
+ "fusedChunks": "max(1, floor(channelsPerGroup / fusedVecWidth)) if channelsLast else 1",
77
+ "fusedWorkgroup": "(fusedChunks * max(1, floor(workgroupCap / fusedChunks))) if channelsLast else min(workgroupCap, max(32, pow2ceil(max(1, floor(groupSize / fusedVecWidth)))))",
78
+ "fusedLanes": "pow2ceil(fusedWorkgroup)",
79
+ "fusedFits": "fusedWorkgroup <= deviceWorkgroupCap and fusedLanes * 8 <= device.limits.maxComputeWorkgroupStorageSize and normRows <= min(device.limits.maxComputeWorkgroupsPerDimension, 65535) * min(device.limits.maxComputeWorkgroupsPerDimension, 65535)",
80
+ "combineWorkgroup": "min(workgroupCap, 64)",
81
+ "statsElement": "(\"vec\" ~ statsVecWidth ~ \"<\" ~ dtypes.T ~ \">\") if statsVecWidth > 1 else dtypes.T",
82
+ "fusedElement": "(\"vec4<\" ~ dtypes.T ~ \">\") if statsVec4Ok else dtypes.T",
83
+ "applyElement": "(\"vec4<\" ~ dtypes.T ~ \">\") if applyVec4Ok else dtypes.T",
84
+ "mScalar": "dtypes.M",
85
+ "tScalar": "dtypes.T",
86
+ "skipExact": "rankOk and ranks.skip == 4 and sameShape(shapes.skip, shapes.X)",
87
+ "skipBroadcast2": "rankOk and ranks.skip == 2 and dim(shapes.skip, 0) == dimN and dim(shapes.skip, 1) == dimC",
88
+ "skipBroadcast4": "rankOk and ranks.skip == 4 and dim(shapes.skip, 0) == dimN and dim(shapes.skip, 1) == 1 and dim(shapes.skip, 2) == 1 and dim(shapes.skip, 3) == dimC",
89
+ "broadcastSkipSpec": "(not skipExact) and (skipBroadcast2 or skipBroadcast4)",
90
+ "skipOk": "skipExact or broadcastSkipSpec",
91
+ "biasOk": "(not present.bias) or (ranks.bias == 1 and dim(shapes.bias, 0) == dimC)",
92
+ "sumOk": "(not present.S) or (ranks.S == 4 and sameShape(shapes.S, shapes.X))",
93
+ "contractOk": "shapeOk and skipOk and biasOk and sumOk and f16Ok(dtypes.T) and f16Ok(dtypes.M)",
94
+ "skipElement": "dtypes.T if broadcastSkipSpec else statsElement"
95
+ },
96
+ "when": ["contractOk"],
97
+ "bindings": {
98
+ "xIn": { "arg": "X", "name": "X", "elementType": "$statsElement" },
99
+ "gamma": { "elementType": "$mScalar" },
100
+ "beta": { "elementType": "$mScalar" },
101
+ "yOut": { "arg": "Y", "name": "Y", "elementType": "$applyElement" },
102
+ "partialsW": { "name": "partials", "buffer": "storage", "elementType": "vec2<f32>" },
103
+ "partialsR": { "name": "partials", "buffer": "read-only-storage", "elementType": "vec2<f32>" },
104
+ "statsW": { "name": "stats", "buffer": "storage", "elementType": "vec2<f32>" },
105
+ "statsR": { "name": "stats", "buffer": "read-only-storage", "elementType": "vec2<f32>" },
106
+ "yFused": { "arg": "Y", "name": "Y", "elementType": "$statsElement" },
107
+ "skipIn": { "arg": "skip", "name": "skip", "elementType": "$skipElement" },
108
+ "biasIn": { "arg": "bias", "name": "bias", "elementType": "$tScalar" },
109
+ "sumDstS": { "arg": "S", "name": "sum_dst", "elementType": "$statsElement" },
110
+ "sumDstY": { "arg": "Y", "name": "sum_dst", "elementType": "$statsElement" },
111
+ "srcCombineS": { "arg": "S", "name": "src", "buffer": "read-only-storage", "elementType": "$statsElement" },
112
+ "srcCombineY": { "arg": "Y", "name": "src", "buffer": "read-only-storage", "elementType": "$statsElement" },
113
+ "srcApplyS": { "arg": "S", "name": "src", "buffer": "read-only-storage", "elementType": "$applyElement" }
114
+ },
115
+ "variants": [
116
+ {
117
+ "id": "split_bias_sum",
118
+ "priority": 20,
119
+ "when": ["splitFits", "present.bias", "present.S"],
120
+ "demoteWhen": ["elementCount < tunables.SPLIT_MIN_ELEMENTS * statsGroupBlocks", "(not channelsLast) and normRows >= tunables.FUSED_MIN_ROWS and groupSize * dtypeBytes(tensorDtypes.X) <= tunables.FUSED_MAX_GROUP_BYTES"],
121
+ "derive": {
122
+ "phaseLayout": "channelsLast",
123
+ "hasSkip": "true",
124
+ "hasBias": "true",
125
+ "broadcastSkip": "broadcastSkipSpec",
126
+ "vecSpec": "statsVecWidth",
127
+ "dimCSpec": "dimC",
128
+ "dimHWSpec": "dimHW",
129
+ "cpgSpec": "channelsPerGroup",
130
+ "groupsSpec": "numGroups",
131
+ "groupSizeSpec": "groupSize",
132
+ "normRowsSpec": "normRows",
133
+ "epsilonSpec": "attrs.epsilon",
134
+ "activationSpec": "activationKind",
135
+ "chunksSpec": "statsChunks",
136
+ "rowsPerStepSpec": "statsRowsPerStep",
137
+ "splitSpec": "splitCount",
138
+ "rowsPerSlabSpec": "ceilDiv(dimHW, slabCount)",
139
+ "planeVecsSpec": "planeVecs",
140
+ "chunkVecsSpec": "ceilDiv(planeVecs, planeSplits)",
141
+ "partialsPerRowSpec": "partialsPerRow",
142
+ "wgSpec": "statsWorkgroup",
143
+ "combineWgSpec": "combineWorkgroup",
144
+ "vecF32": "(\"vec\" ~ statsVecWidth ~ \"<f32>\") if statsVecWidth > 1 else \"f32\"",
145
+ "storeElement": "statsElement",
146
+ "applySrc": "\"src\"",
147
+ "groupUniform": "true"
148
+ },
149
+ "intermediates": [
150
+ { "id": "partials", "dtype": "float32", "shape": "[partialElements, 2]" },
151
+ { "id": "stats", "dtype": "float32", "shape": "[statsElements, 2]" }
152
+ ],
153
+ "passes": [
154
+ {
155
+ "id": "stats",
156
+ "name": "GroupNorm.Partials",
157
+ "shader": "group-norm-slab.wgsl.jinja",
158
+ "derive": {
159
+ "phase": "\"stats\"",
160
+ "unitsSpec": "workUnits",
161
+ "statsBlockedSpec": "channelsLast and statsGroupBlocks > 1",
162
+ "statsGroupsPerBlockSpec": "statsGroupsPerBlock",
163
+ "statsGroupBlocksSpec": "statsGroupBlocks",
164
+ "statsTileChunksSpec": "statsTileChunks"
165
+ },
166
+ "bindings": ["xIn", "skipIn", "biasIn", "sumDstS", "partialsW"],
167
+ "dispatch": { "x": "min(workUnits, 65535)", "y": "ceilDiv(workUnits, 65535)", "z": 1 }
168
+ },
169
+ {
170
+ "id": "combine",
171
+ "name": "GroupNorm.Combine",
172
+ "shader": "group-norm-combine.wgsl.jinja",
173
+ "bindings": ["srcCombineS", "partialsR", "statsW"],
174
+ "dispatch": {
175
+ "x": "min(ceilDiv((normRows), (combineWorkgroup)), 65535)",
176
+ "y": "ceilDiv(ceilDiv((normRows), (combineWorkgroup)), 65535)",
177
+ "z": 1
178
+ }
179
+ },
180
+ {
181
+ "id": "apply",
182
+ "name": "GroupNorm.Apply",
183
+ "shader": "group-norm-slab.wgsl.jinja",
184
+ "derive": {
185
+ "phase": "\"apply\"",
186
+ "vecSpec": "applyVecWidth",
187
+ "chunksSpec": "applyChunks",
188
+ "rowsPerStepSpec": "applyRowsPerStep",
189
+ "wgSpec": "applyWorkgroup",
190
+ "splitSpec": "applySplit",
191
+ "rowsPerSlabSpec": "ceilDiv(dimHW, applySlabCount)",
192
+ "groupUniform": "(channelsPerGroup % applyVecWidth == 0) if channelsLast else true",
193
+ "storeElement": "applyElement",
194
+ "vecF32": "\"vec4<f32>\" if applyVec4Ok else \"f32\"",
195
+ "unitsSpec": "applyUnits",
196
+ "applySrc": "\"src\""
197
+ },
198
+ "bindings": ["srcApplyS", "gamma", "beta", "statsR", "yOut"],
199
+ "dispatch": { "x": "min(applyUnits, 65535)", "y": "ceilDiv(applyUnits, 65535)", "z": 1 }
200
+ }
201
+ ]
202
+ },
203
+ {
204
+ "id": "fused_bias_sum",
205
+ "priority": 10,
206
+ "when": ["fusedFits", "present.bias", "present.S"],
207
+ "derive": {
208
+ "statsElement": "fusedElement",
209
+ "phaseLayout": "channelsLast",
210
+ "hasSkip": "true",
211
+ "hasBias": "true",
212
+ "broadcastSkip": "broadcastSkipSpec",
213
+ "useVec4": "statsVec4Ok",
214
+ "vecSpec": "fusedVecWidth",
215
+ "dimCSpec": "dimC",
216
+ "dimHWSpec": "dimHW",
217
+ "cpgSpec": "channelsPerGroup",
218
+ "groupsSpec": "numGroups",
219
+ "groupSizeSpec": "groupSize",
220
+ "normRowsSpec": "normRows",
221
+ "epsilonSpec": "attrs.epsilon",
222
+ "activationSpec": "activationKind",
223
+ "chunksSpec": "fusedRowChunks",
224
+ "fusedChunksSpec": "fusedChunks",
225
+ "fusedRowsSpec": "max(1, floor(fusedWorkgroup / fusedChunks))",
226
+ "spanVecsSpec": "max(1, floor(groupSize / fusedVecWidth))",
227
+ "wgSpec": "fusedWorkgroup",
228
+ "ldsSpec": "fusedLanes",
229
+ "vecF32": "\"vec4<f32>\" if statsVec4Ok else \"f32\"",
230
+ "storeElement": "fusedElement",
231
+ "fusedSrc": "\"sum_dst\"",
232
+ "planeVecsSpec": "planeVecs",
233
+ "skipElement": "tScalar if broadcastSkipSpec else fusedElement"
234
+ },
235
+ "passes": [
236
+ {
237
+ "id": "main",
238
+ "name": "GroupNorm.Fused",
239
+ "shader": "group-norm-fused.wgsl.jinja",
240
+ "bindings": ["xIn", "skipIn", "biasIn", "gamma", "beta", "sumDstS", "yFused"],
241
+ "dispatch": { "x": "min(normRows, 65535)", "y": "ceilDiv(normRows, 65535)", "z": 1 }
242
+ }
243
+ ]
244
+ },
245
+ {
246
+ "id": "split_bias_plain",
247
+ "priority": 20,
248
+ "when": ["splitFits", "present.bias", "not present.S"],
249
+ "demoteWhen": ["elementCount < tunables.SPLIT_MIN_ELEMENTS * statsGroupBlocks", "(not channelsLast) and normRows >= tunables.FUSED_MIN_ROWS and groupSize * dtypeBytes(tensorDtypes.X) <= tunables.FUSED_MAX_GROUP_BYTES"],
250
+ "derive": {
251
+ "phaseLayout": "channelsLast",
252
+ "hasSkip": "true",
253
+ "hasBias": "true",
254
+ "broadcastSkip": "broadcastSkipSpec",
255
+ "vecSpec": "statsVecWidth",
256
+ "dimCSpec": "dimC",
257
+ "dimHWSpec": "dimHW",
258
+ "cpgSpec": "channelsPerGroup",
259
+ "groupsSpec": "numGroups",
260
+ "groupSizeSpec": "groupSize",
261
+ "normRowsSpec": "normRows",
262
+ "epsilonSpec": "attrs.epsilon",
263
+ "activationSpec": "activationKind",
264
+ "chunksSpec": "statsChunks",
265
+ "rowsPerStepSpec": "statsRowsPerStep",
266
+ "splitSpec": "splitCount",
267
+ "rowsPerSlabSpec": "ceilDiv(dimHW, slabCount)",
268
+ "planeVecsSpec": "planeVecs",
269
+ "chunkVecsSpec": "ceilDiv(planeVecs, planeSplits)",
270
+ "partialsPerRowSpec": "partialsPerRow",
271
+ "wgSpec": "statsWorkgroup",
272
+ "combineWgSpec": "combineWorkgroup",
273
+ "vecF32": "(\"vec\" ~ statsVecWidth ~ \"<f32>\") if statsVecWidth > 1 else \"f32\"",
274
+ "storeElement": "statsElement",
275
+ "applySrc": "\"Y\"",
276
+ "groupUniform": "true"
277
+ },
278
+ "intermediates": [
279
+ { "id": "partials", "dtype": "float32", "shape": "[partialElements, 2]" },
280
+ { "id": "stats", "dtype": "float32", "shape": "[statsElements, 2]" }
281
+ ],
282
+ "passes": [
283
+ {
284
+ "id": "stats",
285
+ "name": "GroupNorm.Partials",
286
+ "shader": "group-norm-slab.wgsl.jinja",
287
+ "derive": {
288
+ "phase": "\"stats\"",
289
+ "unitsSpec": "workUnits",
290
+ "statsBlockedSpec": "channelsLast and statsGroupBlocks > 1",
291
+ "statsGroupsPerBlockSpec": "statsGroupsPerBlock",
292
+ "statsGroupBlocksSpec": "statsGroupBlocks",
293
+ "statsTileChunksSpec": "statsTileChunks"
294
+ },
295
+ "bindings": ["xIn", "skipIn", "biasIn", "sumDstY", "partialsW"],
296
+ "dispatch": { "x": "min(workUnits, 65535)", "y": "ceilDiv(workUnits, 65535)", "z": 1 }
297
+ },
298
+ {
299
+ "id": "combine",
300
+ "name": "GroupNorm.Combine",
301
+ "shader": "group-norm-combine.wgsl.jinja",
302
+ "bindings": ["srcCombineY", "partialsR", "statsW"],
303
+ "dispatch": {
304
+ "x": "min(ceilDiv((normRows), (combineWorkgroup)), 65535)",
305
+ "y": "ceilDiv(ceilDiv((normRows), (combineWorkgroup)), 65535)",
306
+ "z": 1
307
+ }
308
+ },
309
+ {
310
+ "id": "apply",
311
+ "name": "GroupNorm.Apply",
312
+ "shader": "group-norm-slab.wgsl.jinja",
313
+ "derive": {
314
+ "phase": "\"apply\"",
315
+ "vecSpec": "applyVecWidth",
316
+ "chunksSpec": "applyChunks",
317
+ "rowsPerStepSpec": "applyRowsPerStep",
318
+ "wgSpec": "applyWorkgroup",
319
+ "splitSpec": "applySplit",
320
+ "rowsPerSlabSpec": "ceilDiv(dimHW, applySlabCount)",
321
+ "groupUniform": "(channelsPerGroup % applyVecWidth == 0) if channelsLast else true",
322
+ "storeElement": "applyElement",
323
+ "vecF32": "\"vec4<f32>\" if applyVec4Ok else \"f32\"",
324
+ "unitsSpec": "applyUnits",
325
+ "applySrc": "\"Y\""
326
+ },
327
+ "bindings": ["gamma", "beta", "statsR", "yOut"],
328
+ "dispatch": { "x": "min(applyUnits, 65535)", "y": "ceilDiv(applyUnits, 65535)", "z": 1 }
329
+ }
330
+ ]
331
+ },
332
+ {
333
+ "id": "fused_bias_plain",
334
+ "priority": 10,
335
+ "when": ["fusedFits", "present.bias", "not present.S"],
336
+ "derive": {
337
+ "statsElement": "fusedElement",
338
+ "phaseLayout": "channelsLast",
339
+ "hasSkip": "true",
340
+ "hasBias": "true",
341
+ "broadcastSkip": "broadcastSkipSpec",
342
+ "useVec4": "statsVec4Ok",
343
+ "vecSpec": "fusedVecWidth",
344
+ "dimCSpec": "dimC",
345
+ "dimHWSpec": "dimHW",
346
+ "cpgSpec": "channelsPerGroup",
347
+ "groupsSpec": "numGroups",
348
+ "groupSizeSpec": "groupSize",
349
+ "normRowsSpec": "normRows",
350
+ "epsilonSpec": "attrs.epsilon",
351
+ "activationSpec": "activationKind",
352
+ "chunksSpec": "fusedRowChunks",
353
+ "fusedChunksSpec": "fusedChunks",
354
+ "fusedRowsSpec": "max(1, floor(fusedWorkgroup / fusedChunks))",
355
+ "spanVecsSpec": "max(1, floor(groupSize / fusedVecWidth))",
356
+ "wgSpec": "fusedWorkgroup",
357
+ "ldsSpec": "fusedLanes",
358
+ "vecF32": "\"vec4<f32>\" if statsVec4Ok else \"f32\"",
359
+ "storeElement": "fusedElement",
360
+ "fusedSrc": "\"Y\"",
361
+ "planeVecsSpec": "planeVecs",
362
+ "skipElement": "tScalar if broadcastSkipSpec else fusedElement"
363
+ },
364
+ "passes": [
365
+ {
366
+ "id": "main",
367
+ "name": "GroupNorm.Fused",
368
+ "shader": "group-norm-fused.wgsl.jinja",
369
+ "bindings": ["xIn", "skipIn", "biasIn", "gamma", "beta", "yFused"],
370
+ "dispatch": { "x": "min(normRows, 65535)", "y": "ceilDiv(normRows, 65535)", "z": 1 }
371
+ }
372
+ ]
373
+ },
374
+ {
375
+ "id": "split_sum",
376
+ "priority": 20,
377
+ "when": ["splitFits", "not present.bias", "present.S"],
378
+ "demoteWhen": ["elementCount < tunables.SPLIT_MIN_ELEMENTS * statsGroupBlocks", "(not channelsLast) and normRows >= tunables.FUSED_MIN_ROWS and groupSize * dtypeBytes(tensorDtypes.X) <= tunables.FUSED_MAX_GROUP_BYTES"],
379
+ "derive": {
380
+ "phaseLayout": "channelsLast",
381
+ "hasSkip": "true",
382
+ "hasBias": "false",
383
+ "broadcastSkip": "broadcastSkipSpec",
384
+ "vecSpec": "statsVecWidth",
385
+ "dimCSpec": "dimC",
386
+ "dimHWSpec": "dimHW",
387
+ "cpgSpec": "channelsPerGroup",
388
+ "groupsSpec": "numGroups",
389
+ "groupSizeSpec": "groupSize",
390
+ "normRowsSpec": "normRows",
391
+ "epsilonSpec": "attrs.epsilon",
392
+ "activationSpec": "activationKind",
393
+ "chunksSpec": "statsChunks",
394
+ "rowsPerStepSpec": "statsRowsPerStep",
395
+ "splitSpec": "splitCount",
396
+ "rowsPerSlabSpec": "ceilDiv(dimHW, slabCount)",
397
+ "planeVecsSpec": "planeVecs",
398
+ "chunkVecsSpec": "ceilDiv(planeVecs, planeSplits)",
399
+ "partialsPerRowSpec": "partialsPerRow",
400
+ "wgSpec": "statsWorkgroup",
401
+ "combineWgSpec": "combineWorkgroup",
402
+ "vecF32": "(\"vec\" ~ statsVecWidth ~ \"<f32>\") if statsVecWidth > 1 else \"f32\"",
403
+ "storeElement": "statsElement",
404
+ "applySrc": "\"src\"",
405
+ "groupUniform": "true"
406
+ },
407
+ "intermediates": [
408
+ { "id": "partials", "dtype": "float32", "shape": "[partialElements, 2]" },
409
+ { "id": "stats", "dtype": "float32", "shape": "[statsElements, 2]" }
410
+ ],
411
+ "passes": [
412
+ {
413
+ "id": "stats",
414
+ "name": "GroupNorm.Partials",
415
+ "shader": "group-norm-slab.wgsl.jinja",
416
+ "derive": {
417
+ "phase": "\"stats\"",
418
+ "unitsSpec": "workUnits",
419
+ "statsBlockedSpec": "channelsLast and statsGroupBlocks > 1",
420
+ "statsGroupsPerBlockSpec": "statsGroupsPerBlock",
421
+ "statsGroupBlocksSpec": "statsGroupBlocks",
422
+ "statsTileChunksSpec": "statsTileChunks"
423
+ },
424
+ "bindings": ["xIn", "skipIn", "sumDstS", "partialsW"],
425
+ "dispatch": { "x": "min(workUnits, 65535)", "y": "ceilDiv(workUnits, 65535)", "z": 1 }
426
+ },
427
+ {
428
+ "id": "combine",
429
+ "name": "GroupNorm.Combine",
430
+ "shader": "group-norm-combine.wgsl.jinja",
431
+ "bindings": ["srcCombineS", "partialsR", "statsW"],
432
+ "dispatch": {
433
+ "x": "min(ceilDiv((normRows), (combineWorkgroup)), 65535)",
434
+ "y": "ceilDiv(ceilDiv((normRows), (combineWorkgroup)), 65535)",
435
+ "z": 1
436
+ }
437
+ },
438
+ {
439
+ "id": "apply",
440
+ "name": "GroupNorm.Apply",
441
+ "shader": "group-norm-slab.wgsl.jinja",
442
+ "derive": {
443
+ "phase": "\"apply\"",
444
+ "vecSpec": "applyVecWidth",
445
+ "chunksSpec": "applyChunks",
446
+ "rowsPerStepSpec": "applyRowsPerStep",
447
+ "wgSpec": "applyWorkgroup",
448
+ "splitSpec": "applySplit",
449
+ "rowsPerSlabSpec": "ceilDiv(dimHW, applySlabCount)",
450
+ "groupUniform": "(channelsPerGroup % applyVecWidth == 0) if channelsLast else true",
451
+ "storeElement": "applyElement",
452
+ "vecF32": "\"vec4<f32>\" if applyVec4Ok else \"f32\"",
453
+ "unitsSpec": "applyUnits",
454
+ "applySrc": "\"src\""
455
+ },
456
+ "bindings": ["srcApplyS", "gamma", "beta", "statsR", "yOut"],
457
+ "dispatch": { "x": "min(applyUnits, 65535)", "y": "ceilDiv(applyUnits, 65535)", "z": 1 }
458
+ }
459
+ ]
460
+ },
461
+ {
462
+ "id": "fused_sum",
463
+ "priority": 10,
464
+ "when": ["fusedFits", "not present.bias", "present.S"],
465
+ "derive": {
466
+ "statsElement": "fusedElement",
467
+ "phaseLayout": "channelsLast",
468
+ "hasSkip": "true",
469
+ "hasBias": "false",
470
+ "broadcastSkip": "broadcastSkipSpec",
471
+ "useVec4": "statsVec4Ok",
472
+ "vecSpec": "fusedVecWidth",
473
+ "dimCSpec": "dimC",
474
+ "dimHWSpec": "dimHW",
475
+ "cpgSpec": "channelsPerGroup",
476
+ "groupsSpec": "numGroups",
477
+ "groupSizeSpec": "groupSize",
478
+ "normRowsSpec": "normRows",
479
+ "epsilonSpec": "attrs.epsilon",
480
+ "activationSpec": "activationKind",
481
+ "chunksSpec": "fusedRowChunks",
482
+ "fusedChunksSpec": "fusedChunks",
483
+ "fusedRowsSpec": "max(1, floor(fusedWorkgroup / fusedChunks))",
484
+ "spanVecsSpec": "max(1, floor(groupSize / fusedVecWidth))",
485
+ "wgSpec": "fusedWorkgroup",
486
+ "ldsSpec": "fusedLanes",
487
+ "vecF32": "\"vec4<f32>\" if statsVec4Ok else \"f32\"",
488
+ "storeElement": "fusedElement",
489
+ "fusedSrc": "\"sum_dst\"",
490
+ "planeVecsSpec": "planeVecs",
491
+ "skipElement": "tScalar if broadcastSkipSpec else fusedElement"
492
+ },
493
+ "passes": [
494
+ {
495
+ "id": "main",
496
+ "name": "GroupNorm.Fused",
497
+ "shader": "group-norm-fused.wgsl.jinja",
498
+ "bindings": ["xIn", "skipIn", "gamma", "beta", "sumDstS", "yFused"],
499
+ "dispatch": { "x": "min(normRows, 65535)", "y": "ceilDiv(normRows, 65535)", "z": 1 }
500
+ }
501
+ ]
502
+ },
503
+ {
504
+ "id": "split_plain",
505
+ "priority": 20,
506
+ "when": ["splitFits", "not present.bias", "not present.S"],
507
+ "demoteWhen": ["elementCount < tunables.SPLIT_MIN_ELEMENTS * statsGroupBlocks", "(not channelsLast) and normRows >= tunables.FUSED_MIN_ROWS and groupSize * dtypeBytes(tensorDtypes.X) <= tunables.FUSED_MAX_GROUP_BYTES"],
508
+ "derive": {
509
+ "phaseLayout": "channelsLast",
510
+ "hasSkip": "true",
511
+ "hasBias": "false",
512
+ "broadcastSkip": "broadcastSkipSpec",
513
+ "vecSpec": "statsVecWidth",
514
+ "dimCSpec": "dimC",
515
+ "dimHWSpec": "dimHW",
516
+ "cpgSpec": "channelsPerGroup",
517
+ "groupsSpec": "numGroups",
518
+ "groupSizeSpec": "groupSize",
519
+ "normRowsSpec": "normRows",
520
+ "epsilonSpec": "attrs.epsilon",
521
+ "activationSpec": "activationKind",
522
+ "chunksSpec": "statsChunks",
523
+ "rowsPerStepSpec": "statsRowsPerStep",
524
+ "splitSpec": "splitCount",
525
+ "rowsPerSlabSpec": "ceilDiv(dimHW, slabCount)",
526
+ "planeVecsSpec": "planeVecs",
527
+ "chunkVecsSpec": "ceilDiv(planeVecs, planeSplits)",
528
+ "partialsPerRowSpec": "partialsPerRow",
529
+ "wgSpec": "statsWorkgroup",
530
+ "combineWgSpec": "combineWorkgroup",
531
+ "vecF32": "(\"vec\" ~ statsVecWidth ~ \"<f32>\") if statsVecWidth > 1 else \"f32\"",
532
+ "storeElement": "statsElement",
533
+ "applySrc": "\"Y\"",
534
+ "groupUniform": "true"
535
+ },
536
+ "intermediates": [
537
+ { "id": "partials", "dtype": "float32", "shape": "[partialElements, 2]" },
538
+ { "id": "stats", "dtype": "float32", "shape": "[statsElements, 2]" }
539
+ ],
540
+ "passes": [
541
+ {
542
+ "id": "stats",
543
+ "name": "GroupNorm.Partials",
544
+ "shader": "group-norm-slab.wgsl.jinja",
545
+ "derive": {
546
+ "phase": "\"stats\"",
547
+ "unitsSpec": "workUnits",
548
+ "statsBlockedSpec": "channelsLast and statsGroupBlocks > 1",
549
+ "statsGroupsPerBlockSpec": "statsGroupsPerBlock",
550
+ "statsGroupBlocksSpec": "statsGroupBlocks",
551
+ "statsTileChunksSpec": "statsTileChunks"
552
+ },
553
+ "bindings": ["xIn", "skipIn", "sumDstY", "partialsW"],
554
+ "dispatch": { "x": "min(workUnits, 65535)", "y": "ceilDiv(workUnits, 65535)", "z": 1 }
555
+ },
556
+ {
557
+ "id": "combine",
558
+ "name": "GroupNorm.Combine",
559
+ "shader": "group-norm-combine.wgsl.jinja",
560
+ "bindings": ["srcCombineY", "partialsR", "statsW"],
561
+ "dispatch": {
562
+ "x": "min(ceilDiv((normRows), (combineWorkgroup)), 65535)",
563
+ "y": "ceilDiv(ceilDiv((normRows), (combineWorkgroup)), 65535)",
564
+ "z": 1
565
+ }
566
+ },
567
+ {
568
+ "id": "apply",
569
+ "name": "GroupNorm.Apply",
570
+ "shader": "group-norm-slab.wgsl.jinja",
571
+ "derive": {
572
+ "phase": "\"apply\"",
573
+ "vecSpec": "applyVecWidth",
574
+ "chunksSpec": "applyChunks",
575
+ "rowsPerStepSpec": "applyRowsPerStep",
576
+ "wgSpec": "applyWorkgroup",
577
+ "splitSpec": "applySplit",
578
+ "rowsPerSlabSpec": "ceilDiv(dimHW, applySlabCount)",
579
+ "groupUniform": "(channelsPerGroup % applyVecWidth == 0) if channelsLast else true",
580
+ "storeElement": "applyElement",
581
+ "vecF32": "\"vec4<f32>\" if applyVec4Ok else \"f32\"",
582
+ "unitsSpec": "applyUnits",
583
+ "applySrc": "\"Y\""
584
+ },
585
+ "bindings": ["gamma", "beta", "statsR", "yOut"],
586
+ "dispatch": { "x": "min(applyUnits, 65535)", "y": "ceilDiv(applyUnits, 65535)", "z": 1 }
587
+ }
588
+ ]
589
+ },
590
+ {
591
+ "id": "fused_plain",
592
+ "priority": 10,
593
+ "when": ["fusedFits", "not present.bias", "not present.S"],
594
+ "derive": {
595
+ "statsElement": "fusedElement",
596
+ "phaseLayout": "channelsLast",
597
+ "hasSkip": "true",
598
+ "hasBias": "false",
599
+ "broadcastSkip": "broadcastSkipSpec",
600
+ "useVec4": "statsVec4Ok",
601
+ "vecSpec": "fusedVecWidth",
602
+ "dimCSpec": "dimC",
603
+ "dimHWSpec": "dimHW",
604
+ "cpgSpec": "channelsPerGroup",
605
+ "groupsSpec": "numGroups",
606
+ "groupSizeSpec": "groupSize",
607
+ "normRowsSpec": "normRows",
608
+ "epsilonSpec": "attrs.epsilon",
609
+ "activationSpec": "activationKind",
610
+ "chunksSpec": "fusedRowChunks",
611
+ "fusedChunksSpec": "fusedChunks",
612
+ "fusedRowsSpec": "max(1, floor(fusedWorkgroup / fusedChunks))",
613
+ "spanVecsSpec": "max(1, floor(groupSize / fusedVecWidth))",
614
+ "wgSpec": "fusedWorkgroup",
615
+ "ldsSpec": "fusedLanes",
616
+ "vecF32": "\"vec4<f32>\" if statsVec4Ok else \"f32\"",
617
+ "storeElement": "fusedElement",
618
+ "fusedSrc": "\"Y\"",
619
+ "planeVecsSpec": "planeVecs",
620
+ "skipElement": "tScalar if broadcastSkipSpec else fusedElement"
621
+ },
622
+ "passes": [
623
+ {
624
+ "id": "main",
625
+ "name": "GroupNorm.Fused",
626
+ "shader": "group-norm-fused.wgsl.jinja",
627
+ "bindings": ["xIn", "skipIn", "gamma", "beta", "yFused"],
628
+ "dispatch": { "x": "min(normRows, 65535)", "y": "ceilDiv(normRows, 65535)", "z": 1 }
629
+ }
630
+ ]
631
+ }
632
+ ]
633
+ }
build/webgpu/metadata.json ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "com.microsoft.SkipGroupNorm",
3
+ "id": "_com_microsoft_skipgroupnorm_webgpu_92ea3fc",
4
+ "version": 1,
5
+ "license": "Apache-2.0",
6
+ "backend": { "type": "webgpu" },
7
+ "digest": {
8
+ "algorithm": "sha256",
9
+ "files": {
10
+ "bench.json": "VviePAedFI1tXjO4aRxUsDVvypknA6GNCHfB/ySq07c=",
11
+ "group-norm-combine.wgsl.jinja": "weqcoPzdY5lQ8K/lZVEF03/sdbu1c/2jwdrW/KT9xr4=",
12
+ "group-norm-fused.wgsl.jinja": "523MK9Q6GT26VjwUdiq/KsvpQdE6BH38iuS9ftCxDeY=",
13
+ "group-norm-slab.wgsl.jinja": "gsFbtBGWwxpdm/76plQtm7psUEN6HoFrM05U0y+LwBM=",
14
+ "manifest.json": "KRDZNaGuWK334a4ewL0oA0L3/sAdyt9pwqbJb8Ms4O8=",
15
+ "test.json": "w/W+fF5md2sOc+Q6Db/HPoF8z1qw48sJpvma6ph27Bs="
16
+ }
17
+ },
18
+ "provenance": { "kernel": { "sha": "6fdf6301e2bbcc2f03bf1eaf493b7ad55ef33afc", "dirty": false } },
19
+ "webgpu": {
20
+ "manifestSpec": "2.1",
21
+ "variants": {
22
+ "split_bias_sum": ["group-norm-combine.wgsl.jinja", "group-norm-slab.wgsl.jinja"],
23
+ "fused_bias_sum": ["group-norm-fused.wgsl.jinja"],
24
+ "split_bias_plain": ["group-norm-combine.wgsl.jinja", "group-norm-slab.wgsl.jinja"],
25
+ "fused_bias_plain": ["group-norm-fused.wgsl.jinja"],
26
+ "split_sum": ["group-norm-combine.wgsl.jinja", "group-norm-slab.wgsl.jinja"],
27
+ "fused_sum": ["group-norm-fused.wgsl.jinja"],
28
+ "split_plain": ["group-norm-combine.wgsl.jinja", "group-norm-slab.wgsl.jinja"],
29
+ "fused_plain": ["group-norm-fused.wgsl.jinja"]
30
+ }
31
+ }
32
+ }
build/webgpu/test.json ADDED
@@ -0,0 +1,1664 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "fixtureArrays": {
3
+ "wb_input": [-0.768555, 1.575195, -0.698242, 1.587891, 0.371826, -0.280029, -1.328125, 0.127197, -0.197144, 0.982422, -0.671387, -1.925781, 1.800781, -0.020218, -0.782227, 1.291992, -0.935059, 1.782227, -0.674316, -1.943359, -0.218994, 0.054138, -1.539062, -0.546387, -2.160156, 1.195312, 1.65332, -0.674316, 0.224731, -0.093262, 1.160156, -0.389404, 1.748047, 0.766113, 0.234375, 0.011177, -0.055847, -0.930664, -0.490234, -0.655762, -0.382568, -0.554688, 0.910645, -0.227295, 1.6875, 0.028397, -0.241699, -0.480957, -0.355713, -2.095703, -0.443359, -0.126221, -0.815918, 0.792969, -0.450439, -0.952148, -1.174805, 0.242798, 0.13855, -0.237061, -0.994141, 0.346436, 0.147705, 0.125854, -0.51709, 0.253906, 0.400146, -0.540039, -0.788574, 0.146606, -0.409668, 0.281982, 1.444336, 0.044434, -0.366699, 2.25, -0.453613, -0.652344, 1.828125, -0.244751, 0.307129, -0.051361, 0.106384, 0.844727, 1.648438, -0.904785, -0.35376, 0.510742, 0.074829, -0.311279, 0.274902, 1.594727, 1.367188, 0.098755, 0.043304, -0.207397, 0.068298, -0.601074, 0.083008, 0.264893, -0.65918, -0.216797, -0.086548, -0.683594, -0.964844, -2.591797, -0.817383, -0.461914, -1.84082, -0.712402, -0.052094, -0.583008, 1.114258, 0.190308, 1.087891, 0.005146, 1.041992, 1.363281, -0.273682, -0.465576, -0.027618, 1.345703, 0.789551, -0.015991, 0.401611, 0.726562, 0.598633, 0.133667],
4
+ "wb_gamma": [0.241255, 0.55666, -0.835532, 0.564596, -1.338308, -0.278924, 0.357326, -1.745484, 0.277184, 0.101415, -0.018637, -0.526188, -0.011698, -2.349411, 0.206578, 0.357679],
5
+ "wb_beta": [-1.194839, 0.209146, -0.677225, -0.547338, 1.275685, -1.099577, 0.470916, 0.293907, -1.094209, 2.350204, -1.633769, 0.248753, -0.180166, 0.365134, -0.555731, 1.843083],
6
+ "wb_skip": [0.892578, -0.471924, -0.423096, 1.277344, 0.25708, -1.366211, 1.552734, 0.441406, -0.033142, -0.059418, 1.536133, -0.225464, 1.472656, 0.591309, -0.38623, -2.197266, 0.0896, -0.256592, -1.873047, 0.916992, 0.39209, 0.015526, -0.949219, 0.566895, -0.220459, 1.262695, -0.437744, -2.283203, -0.264893, -0.660156, 2.353516, 1.992188, 0.865723, -0.854004, -1.014648, 0.899414, -1.041016, 1.378906, -0.075073, -2.541016, -0.883789, -0.428711, 0.981934, -0.072754, 2.214844, 0.658203, 0.170166, -1.727539, -0.672363, -1.373047, 0.318115, 0.422363, 0.260742, -0.547852, 0.545898, -0.155762, 0.679688, 2.861328, -0.300781, -0.504883, 1.548828, 0.35376, -0.387695, -1.595703, -0.170166, -0.002897, 0.273193, -0.383545, -1.082031, -0.894043, -1.048828, -0.044708, 0.049286, 0.220215, 0.272705, -0.853027, -0.489258, 0.513672, 0.977051, 0.310547, -0.577148, -0.479004, 0.838867, 0.872559, -0.510254, 0.101807, -0.299805, -1.179688, -1.555664, 0.668457, 0.939453, 0.118103, -0.376709, 0.735352, -0.214233, -1.987305, -0.931152, 1.268555, 1.427734, -0.757812, -1.324219, 0.375488, 1.364258, -1.708008, 0.976562, -0.037659, -1.779297, -0.196655, 1.636719, 0.69043, 0.941895, -1.882812, 0.431641, 0.203857, 1.306641, -0.126343, 1.408203, 1.188477, 0.432861, -2.296875, -0.475342, 1.517578, -0.824219, 1.288086, -0.028244, 1.918945, 0.352295, 0.693359],
7
+ "wb_bias": [-0.537598, 0.500488, -0.252441, -0.460693, -1.640625, -1.298828, 0.331787, -1.588867, 1.000977, 1.458984, 0.702637, 0.147827, 1.143555, 0.533691, -0.07251, 0.51123],
8
+ "wb_norm": [-1.213867, 0.856445, -0.119141, 0.386475, 0.714355, -0.804688, 1.048828, -0.42627, -1.091797, 2.435547, -1.641602, 0.989746, -0.200928, 0.267334, -0.800781, 1.577148, -1.357422, 1.000977, 0.613281, -0.963867, 1.179688, -1.169922, 0.30835, 0.304199, -1.396484, 2.513672, -1.644531, 1.206055, -0.180664, 1.896484, -0.294678, 2.046875, -0.844238, 0.448486, -0.294189, -0.291504, 2.480469, -1.250977, 0.833008, 4.59375, -1.238281, 2.335938, -1.651367, 0.491943, -0.204834, 0.12561, -0.682129, 1.333984, -1.384766, -0.708008, -0.630859, -0.504883, 1.924805, -1.208008, 1.013672, 1.80957, -1.128906, 2.546875, -1.631836, 0.61084, -0.184326, 0.110046, -0.700195, 1.47168, -1.511719, 0.492188, -0.847168, -1.373047, 2.837891, -0.998047, 0.521484, 0.262207, -0.810547, 2.400391, -1.628906, 0.049896, -0.174927, 1.076172, -0.252197, 1.78418, -1.418945, 0.09082, -1.056641, 0.002945, 0.627441, -0.989746, 0.679199, 1.130859, -1.371094, 2.408203, -1.645508, -0.062988, -0.192017, -0.655762, -0.718262, 1.170898, -1.550781, 0.706055, -1.492188, -1.148438, 2.921875, -1.136719, 1.058594, 2.78125, -1.089844, 2.201172, -1.597656, 0.785645, -0.181396, 0.868164, -0.552246, 1.097656, -1.015625, 0.56543, -2.173828, -0.955078, -0.336426, -1.503906, 0.838867, 3.136719, -1.186523, 2.580078, -1.629883, 0.094604, -0.186523, -3.884766, -0.54248, 1.990234],
9
+ "wb_add_out": [-0.414062, 1.604492, -1.374023, 2.404297, -1.011719, -2.945312, 0.556641, -1.020508, 0.770508, 2.382812, 1.567383, -2.003906, 4.417969, 1.105469, -1.240234, -0.394531, -1.382812, 2.027344, -2.800781, -1.487305, -1.466797, -1.229492, -2.15625, -1.568359, -1.379883, 3.917969, 1.917969, -2.808594, 1.103516, -0.219727, 3.441406, 2.113281, 2.076172, 0.412598, -1.033203, 0.449951, -2.738281, -0.851562, -0.233521, -4.785156, -0.265625, 0.475586, 2.595703, -0.152222, 5.046875, 1.220703, -0.144043, -1.697266, -1.566406, -2.96875, -0.377686, -0.164551, -2.195312, -1.053711, 0.427246, -2.697266, 0.505859, 4.5625, 0.540527, -0.594238, 1.698242, 1.233398, -0.3125, -0.958496, -1.224609, 0.751465, 0.420898, -1.384766, -3.511719, -2.046875, -1.126953, -1.351562, 2.494141, 1.724609, 0.608398, 1.544922, 0.200684, 0.39502, 2.732422, 0.577148, -0.807617, -0.029785, 0.692871, 1.256836, -0.502441, -2.101562, -0.321777, -2.257812, -0.479492, 1.816406, 1.916992, 1.860352, 2.134766, 1.367188, -0.243408, -1.683594, -1.400391, 1.167969, 1.257812, -0.953613, -3.625, -1.140625, 1.609375, -3.980469, 1.012695, -1.170898, -1.894531, -0.510742, 0.939453, 0.511719, 0.817383, -1.955078, 1.007812, 0.894531, 2.142578, -0.582031, 0.80957, 1.25293, 0.490967, -4.351562, 0.497803, 4.320312, 0.667969, 1.419922, 1.516602, 3.179688, 0.878906, 1.337891],
10
+ "bc_input": [0.588867, 0.896484, -0.213623, 0.803223, 0.65918, -0.216187, 1.197266, -0.486084, -0.71875, 0.332031, -0.364746, -0.831543, -0.031219, -1.05957, 0.161621, 1.519531, 0.169312, 1.048828, 1.330078, 0.450195, -2.867188, -1.456055, 0.708496, -1.120117, -1.208984, -1.199219, -1.505859, -0.549316, 0.505371, 0.723145, -0.359131, -0.250977, -0.879883, -0.305664, 0.709473, 0.81543, 0.617676, -0.638672, 0.066772, -2.330078, -1.316406, 1.744141, 1.12207, -0.633789, -1.802734, -0.825684, 0.622559, -0.481689, -1.364258, -0.536621, -0.464111, 0.247437, -0.213989, 0.384521, 0.556641, -0.303711, -0.160034, 0.882324, -0.212036, -0.796387, 0.153076, -1.311523, 2.212891, 0.685059],
11
+ "bc_gamma": [0.789682, 0.869051, -0.010169, -0.021685, 0.506611, 1.267444, -0.312695, 0.877844, 0.598637, 0.598314, -1.721544, -0.593328, 0.986705, -0.419391, -0.852584, -0.572351, 0.912797, -0.586863, 0.477761, -0.484418, -0.193835, 0.347757, 0.327637, -1.100304, 1.233108, -0.272569, -0.688656, 0.687245, 0.398386, 0.888089, -0.792587, -0.769029, -0.427778, 0.100768, -2.18706, 1.279301, 1.109054, 0.375992, 1.514775, 1.271436, 0.822896, -0.47675, 0.475507, -1.011297, 1.177197, 1.58654, -1.059944, -0.145351, 0.841555, -2.014113, -0.230498, 0.302128, -0.180508, 0.980534, -0.126871, 0.203151, -0.754841, 0.42057, -1.085798, 1.335042, -0.67493, 2.453507, 2.139259, 1.087436],
12
+ "bc_beta": [-0.064518, -0.262683, 0.827528, -0.960938, 1.062519, 2.417941, 0.212789, -1.63843, 1.875453, -0.883058, -0.006704, 0.424894, -0.869972, 0.727008, 0.879303, -3.024141, -2.610873, 1.269641, 0.883006, 0.804167, -1.510324, 2.258091, -0.00675, -1.553668, -1.659453, 0.579603, 0.652358, 0.007077, 0.09918, 0.418658, -0.273778, -1.036199, -1.128691, -0.296022, -0.224056, 1.476306, 0.577624, -0.372049, -0.581659, -1.841807, -0.361721, 0.05116, -0.749332, -2.634807, 0.562719, -0.738667, 0.024864, -1.135937, -1.368144, -1.458886, -0.946683, 1.953936, -1.198661, 0.166648, 0.447206, -0.45814, -0.553395, 0.1129, 0.255989, -0.184551, 1.254163, -0.260479, -1.232429, 1.902575],
13
+ "bc_skip": [0.952148, 1.342773, -0.172974, -0.395264, 1.119141, 0.330566, 0.281494, 0.4729, -0.692871, -0.634766, 0.013504, -1.866211, -0.428223, 0.669922, -0.323486, 0.713867, -0.350586, 0.65918, -0.288574, 0.324219, -0.300781, -0.789551, -0.216431, -0.221436, -0.08667, 0.366211, -0.643555, -0.977051, 0.001021, 0.415527, -0.271729, 0.836426, 0.03537, -0.806152, 0.936035, -0.021332, -1.095703, 0.97168, 1.648438, 0.84082, 0.837402, 0.60791, -1.894531, 0.666016, -0.171143, 1.625977, -0.620117, -0.039581, 1.702148, -2.410156, 1.56543, -0.756348, 1.446289, 0.583496, -0.497559, -0.271729, -0.956055, -1.642578, 0.833496, -1.136719, 1.248047, -2.515625, 0.080383, 0.376221],
14
+ "bc_norm": [0.494873, 1.017578, 0.841797, -0.949219, 1.552734, 1.333984, 0.012703, -2.511719, 1.424805, -0.818359, -0.128418, 1.462891, -0.882812, 0.709961, 0.693848, -4.210938, -2.505859, 0.513184, 1.300781, 0.460938, -1.172852, 1.851562, 0.167969, -0.885254, -2.535156, 0.656738, 1.683594, -0.627441, 0.478271, 1.782227, -0.196777, -1.824219, -0.791016, -0.398682, -3.197266, 2.275391, 0.052704, -0.286865, 1.567383, -3.552734, -0.646973, -0.927734, -1.032227, -2.722656, -1.337891, 0.432129, -0.040253, -1.080078, -1.118164, 3.123047, -1.15332, 1.84375, -1.378906, 0.941406, 0.437256, -0.542969, -0.218872, 0.006115, -0.265869, -1.356445, 0.649902, -4.882812, 1.696289, 2.679688],
15
+ "bc_add_out": [1.541016, 2.238281, -0.386719, 0.407959, 1.77832, 0.11438, 1.478516, -0.013184, -1.412109, -0.302734, -0.351318, -2.697266, -0.459473, -0.389648, -0.161865, 2.234375, -0.181274, 1.708008, 1.041016, 0.774414, -3.167969, -2.246094, 0.492188, -1.341797, -1.295898, -0.833008, -2.148438, -1.526367, 0.506348, 1.138672, -0.630859, 0.585449, -0.844727, -1.111328, 1.645508, 0.793945, -0.478027, 0.333008, 1.714844, -1.489258, -0.479004, 2.351562, -0.772461, 0.032227, -1.973633, 0.800293, 0.002441, -0.521484, 0.337891, -2.947266, 1.101562, -0.508789, 1.232422, 0.967773, 0.059082, -0.575195, -1.116211, -0.760254, 0.621582, -1.933594, 1.401367, -3.828125, 2.292969, 1.061523],
16
+ "nhwc_group_block_tail_c320_float32_input_X": [-0.5, -0.4375, -0.375, -0.3125, -0.25, -0.1875, -0.125, -0.0625, 0, 0.0625, 0.125, 0.1875, 0.25, 0.3125, 0.375, 0.4375, 0.5]
17
+ },
18
+ "cases": [
19
+ {
20
+ "name": "ort_skip_group_norm_with_bias",
21
+ "provenance": {
22
+ "source": "onnxruntime/test/contrib_ops/skip_group_norm_op_test.cc",
23
+ "test": "SkipGroupNormTest.SkipGroupNorm_with_bias",
24
+ "note": "explicit channels_last = 1"
25
+ },
26
+ "attrs": { "groups": 4, "activation": 0, "channels_last": 1, "epsilon": 0.00001 },
27
+ "inputs": {
28
+ "X": {
29
+ "dtype": "float16",
30
+ "shape": [2, 2, 2, 16],
31
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/wb_input" } }
32
+ },
33
+ "gamma": {
34
+ "dtype": "float32",
35
+ "shape": [16],
36
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/wb_gamma" } }
37
+ },
38
+ "beta": {
39
+ "dtype": "float32",
40
+ "shape": [16],
41
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/wb_beta" } }
42
+ },
43
+ "skip": {
44
+ "dtype": "float16",
45
+ "shape": [2, 2, 2, 16],
46
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/wb_skip" } }
47
+ },
48
+ "bias": {
49
+ "dtype": "float16",
50
+ "shape": [16],
51
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/wb_bias" } }
52
+ }
53
+ },
54
+ "outputs": {
55
+ "Y": {
56
+ "dtype": "float16",
57
+ "shape": [2, 2, 2, 16],
58
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/wb_norm" } },
59
+ "tolerance": 0.02,
60
+ "relTolerance": 0.004
61
+ },
62
+ "S": {
63
+ "dtype": "float16",
64
+ "shape": [2, 2, 2, 16],
65
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/wb_add_out" } },
66
+ "tolerance": 0.02,
67
+ "relTolerance": 0.004
68
+ }
69
+ }
70
+ },
71
+ {
72
+ "name": "ort_skip_group_norm_with_bias_default_layout",
73
+ "provenance": {
74
+ "source": "onnxruntime/test/contrib_ops/skip_group_norm_op_test.cc",
75
+ "test": "SkipGroupNormTest.SkipGroupNorm_with_bias",
76
+ "note": "channels_last left at its default, the gtest's channels_last = -1 instantiation"
77
+ },
78
+ "attrs": { "groups": 4, "activation": 0, "epsilon": 0.00001 },
79
+ "inputs": {
80
+ "X": {
81
+ "dtype": "float16",
82
+ "shape": [2, 2, 2, 16],
83
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/wb_input" } }
84
+ },
85
+ "gamma": {
86
+ "dtype": "float32",
87
+ "shape": [16],
88
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/wb_gamma" } }
89
+ },
90
+ "beta": {
91
+ "dtype": "float32",
92
+ "shape": [16],
93
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/wb_beta" } }
94
+ },
95
+ "skip": {
96
+ "dtype": "float16",
97
+ "shape": [2, 2, 2, 16],
98
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/wb_skip" } }
99
+ },
100
+ "bias": {
101
+ "dtype": "float16",
102
+ "shape": [16],
103
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/wb_bias" } }
104
+ }
105
+ },
106
+ "outputs": {
107
+ "Y": {
108
+ "dtype": "float16",
109
+ "shape": [2, 2, 2, 16],
110
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/wb_norm" } },
111
+ "tolerance": 0.02,
112
+ "relTolerance": 0.004
113
+ },
114
+ "S": {
115
+ "dtype": "float16",
116
+ "shape": [2, 2, 2, 16],
117
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/wb_add_out" } },
118
+ "tolerance": 0.02,
119
+ "relTolerance": 0.004
120
+ }
121
+ }
122
+ },
123
+ {
124
+ "name": "ort_skip_group_norm_with_bias_no_sum_output",
125
+ "provenance": {
126
+ "source": "onnxruntime/test/contrib_ops/skip_group_norm_op_test.cc",
127
+ "test": "SkipGroupNormTest.SkipGroupNorm_with_bias",
128
+ "note": "the same table with the optional S output not requested; Y is unchanged because the sum is round-tripped at the tensor type either way"
129
+ },
130
+ "attrs": { "groups": 4, "activation": 0, "channels_last": 1, "epsilon": 0.00001 },
131
+ "inputs": {
132
+ "X": {
133
+ "dtype": "float16",
134
+ "shape": [2, 2, 2, 16],
135
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/wb_input" } }
136
+ },
137
+ "gamma": {
138
+ "dtype": "float32",
139
+ "shape": [16],
140
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/wb_gamma" } }
141
+ },
142
+ "beta": {
143
+ "dtype": "float32",
144
+ "shape": [16],
145
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/wb_beta" } }
146
+ },
147
+ "skip": {
148
+ "dtype": "float16",
149
+ "shape": [2, 2, 2, 16],
150
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/wb_skip" } }
151
+ },
152
+ "bias": {
153
+ "dtype": "float16",
154
+ "shape": [16],
155
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/wb_bias" } }
156
+ }
157
+ },
158
+ "outputs": {
159
+ "Y": {
160
+ "dtype": "float16",
161
+ "shape": [2, 2, 2, 16],
162
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/wb_norm" } },
163
+ "tolerance": 0.02,
164
+ "relTolerance": 0.004
165
+ }
166
+ }
167
+ },
168
+ {
169
+ "name": "ort_skip_group_norm_broadcast_skip_rank2_with_sum",
170
+ "provenance": {
171
+ "source": "onnxruntime/test/contrib_ops/skip_group_norm_op_test.cc",
172
+ "test": "SkipGroupNormTest.SkipGroupNorm_no_bias_broadcast_skip",
173
+ "note": "skip spelled (N, C), which broadcasts; S requested"
174
+ },
175
+ "attrs": { "groups": 8, "activation": 0, "channels_last": 1, "epsilon": 0.00001 },
176
+ "inputs": {
177
+ "X": {
178
+ "dtype": "float16",
179
+ "shape": [1, 1, 1, 64],
180
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/bc_input" } }
181
+ },
182
+ "gamma": {
183
+ "dtype": "float32",
184
+ "shape": [64],
185
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/bc_gamma" } }
186
+ },
187
+ "beta": {
188
+ "dtype": "float32",
189
+ "shape": [64],
190
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/bc_beta" } }
191
+ },
192
+ "skip": {
193
+ "dtype": "float16",
194
+ "shape": [1, 64],
195
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/bc_skip" } }
196
+ }
197
+ },
198
+ "outputs": {
199
+ "Y": {
200
+ "dtype": "float16",
201
+ "shape": [1, 1, 1, 64],
202
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/bc_norm" } },
203
+ "tolerance": 0.02,
204
+ "relTolerance": 0.004
205
+ },
206
+ "S": {
207
+ "dtype": "float16",
208
+ "shape": [1, 1, 1, 64],
209
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/bc_add_out" } },
210
+ "tolerance": 0.02,
211
+ "relTolerance": 0.004
212
+ }
213
+ }
214
+ },
215
+ {
216
+ "name": "ort_skip_group_norm_broadcast_skip_rank2_no_sum",
217
+ "provenance": {
218
+ "source": "onnxruntime/test/contrib_ops/skip_group_norm_op_test.cc",
219
+ "test": "SkipGroupNormTest.SkipGroupNorm_no_bias_broadcast_skip",
220
+ "note": "skip spelled (N, C), which broadcasts; S not requested"
221
+ },
222
+ "attrs": { "groups": 8, "activation": 0, "channels_last": 1, "epsilon": 0.00001 },
223
+ "inputs": {
224
+ "X": {
225
+ "dtype": "float16",
226
+ "shape": [1, 1, 1, 64],
227
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/bc_input" } }
228
+ },
229
+ "gamma": {
230
+ "dtype": "float32",
231
+ "shape": [64],
232
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/bc_gamma" } }
233
+ },
234
+ "beta": {
235
+ "dtype": "float32",
236
+ "shape": [64],
237
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/bc_beta" } }
238
+ },
239
+ "skip": {
240
+ "dtype": "float16",
241
+ "shape": [1, 64],
242
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/bc_skip" } }
243
+ }
244
+ },
245
+ "outputs": {
246
+ "Y": {
247
+ "dtype": "float16",
248
+ "shape": [1, 1, 1, 64],
249
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/bc_norm" } },
250
+ "tolerance": 0.02,
251
+ "relTolerance": 0.004
252
+ }
253
+ }
254
+ },
255
+ {
256
+ "name": "ort_skip_group_norm_broadcast_skip_rank4_with_sum",
257
+ "provenance": {
258
+ "source": "onnxruntime/test/contrib_ops/skip_group_norm_op_test.cc",
259
+ "test": "SkipGroupNormTest.SkipGroupNorm_no_bias_broadcast_skip",
260
+ "note": "skip spelled (N, 1, 1, C), which at H = W = 1 is an exact shape match and takes the non-broadcast route; S requested"
261
+ },
262
+ "attrs": { "groups": 8, "activation": 0, "channels_last": 1, "epsilon": 0.00001 },
263
+ "inputs": {
264
+ "X": {
265
+ "dtype": "float16",
266
+ "shape": [1, 1, 1, 64],
267
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/bc_input" } }
268
+ },
269
+ "gamma": {
270
+ "dtype": "float32",
271
+ "shape": [64],
272
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/bc_gamma" } }
273
+ },
274
+ "beta": {
275
+ "dtype": "float32",
276
+ "shape": [64],
277
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/bc_beta" } }
278
+ },
279
+ "skip": {
280
+ "dtype": "float16",
281
+ "shape": [1, 1, 1, 64],
282
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/bc_skip" } }
283
+ }
284
+ },
285
+ "outputs": {
286
+ "Y": {
287
+ "dtype": "float16",
288
+ "shape": [1, 1, 1, 64],
289
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/bc_norm" } },
290
+ "tolerance": 0.02,
291
+ "relTolerance": 0.004
292
+ },
293
+ "S": {
294
+ "dtype": "float16",
295
+ "shape": [1, 1, 1, 64],
296
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/bc_add_out" } },
297
+ "tolerance": 0.02,
298
+ "relTolerance": 0.004
299
+ }
300
+ }
301
+ },
302
+ {
303
+ "name": "ort_skip_group_norm_broadcast_skip_rank4_no_sum",
304
+ "provenance": {
305
+ "source": "onnxruntime/test/contrib_ops/skip_group_norm_op_test.cc",
306
+ "test": "SkipGroupNormTest.SkipGroupNorm_no_bias_broadcast_skip",
307
+ "note": "skip spelled (N, 1, 1, C), which at H = W = 1 is an exact shape match and takes the non-broadcast route; S not requested"
308
+ },
309
+ "attrs": { "groups": 8, "activation": 0, "channels_last": 1, "epsilon": 0.00001 },
310
+ "inputs": {
311
+ "X": {
312
+ "dtype": "float16",
313
+ "shape": [1, 1, 1, 64],
314
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/bc_input" } }
315
+ },
316
+ "gamma": {
317
+ "dtype": "float32",
318
+ "shape": [64],
319
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/bc_gamma" } }
320
+ },
321
+ "beta": {
322
+ "dtype": "float32",
323
+ "shape": [64],
324
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/bc_beta" } }
325
+ },
326
+ "skip": {
327
+ "dtype": "float16",
328
+ "shape": [1, 1, 1, 64],
329
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/bc_skip" } }
330
+ }
331
+ },
332
+ "outputs": {
333
+ "Y": {
334
+ "dtype": "float16",
335
+ "shape": [1, 1, 1, 64],
336
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/bc_norm" } },
337
+ "tolerance": 0.02,
338
+ "relTolerance": 0.004
339
+ }
340
+ }
341
+ },
342
+ {
343
+ "name": "nhwc_vec4_bias_sum_silu_f16",
344
+ "attrs": { "groups": 8, "activation": 1, "channels_last": 1 },
345
+ "inputs": {
346
+ "X": {
347
+ "dtype": "float16",
348
+ "shape": [1, 32, 32, 64],
349
+ "data": { "kind": "fillFloat32", "sinStep": 0.11, "cosStep": 0.28 }
350
+ },
351
+ "gamma": {
352
+ "dtype": "float32",
353
+ "shape": [64],
354
+ "data": { "kind": "fillFloat32", "sinStep": 0.29, "cosStep": 0.13 }
355
+ },
356
+ "beta": {
357
+ "dtype": "float32",
358
+ "shape": [64],
359
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.23 }
360
+ },
361
+ "skip": {
362
+ "dtype": "float16",
363
+ "shape": [1, 32, 32, 64],
364
+ "data": { "kind": "fillFloat32", "sinStep": 0.42, "cosStep": 0.16 }
365
+ },
366
+ "bias": {
367
+ "dtype": "float16",
368
+ "shape": [64],
369
+ "data": { "kind": "fillFloat32", "sinStep": 0.19, "cosStep": 0.37 }
370
+ }
371
+ },
372
+ "outputs": {
373
+ "Y": { "dtype": "float16", "shape": [1, 32, 32, 64], "tolerance": 0.01, "relTolerance": 0.004 },
374
+ "S": { "dtype": "float16", "shape": [1, 32, 32, 64], "tolerance": 0.01, "relTolerance": 0.004 }
375
+ }
376
+ },
377
+ {
378
+ "name": "nhwc_vec4_bias_nosum_f32",
379
+ "attrs": { "groups": 8, "activation": 0, "channels_last": 1 },
380
+ "inputs": {
381
+ "X": {
382
+ "dtype": "float32",
383
+ "shape": [1, 32, 32, 64],
384
+ "data": { "kind": "fillFloat32", "sinStep": 0.13, "cosStep": 0.30000000000000004 }
385
+ },
386
+ "gamma": {
387
+ "dtype": "float32",
388
+ "shape": [64],
389
+ "data": { "kind": "fillFloat32", "sinStep": 0.29, "cosStep": 0.13 }
390
+ },
391
+ "beta": {
392
+ "dtype": "float32",
393
+ "shape": [64],
394
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.23 }
395
+ },
396
+ "skip": {
397
+ "dtype": "float32",
398
+ "shape": [1, 32, 32, 64],
399
+ "data": { "kind": "fillFloat32", "sinStep": 0.44, "cosStep": 0.18 }
400
+ },
401
+ "bias": {
402
+ "dtype": "float32",
403
+ "shape": [64],
404
+ "data": { "kind": "fillFloat32", "sinStep": 0.19, "cosStep": 0.37 }
405
+ }
406
+ },
407
+ "outputs": { "Y": { "dtype": "float32", "shape": [1, 32, 32, 64], "tolerance": 0.0005, "relTolerance": 0.0005 } }
408
+ },
409
+ {
410
+ "name": "nhwc_vec4_nobias_sum_f32",
411
+ "attrs": { "groups": 4, "activation": 1, "channels_last": 1 },
412
+ "inputs": {
413
+ "X": {
414
+ "dtype": "float32",
415
+ "shape": [2, 8, 8, 32],
416
+ "data": { "kind": "fillFloat32", "sinStep": 0.17, "cosStep": 0.34 }
417
+ },
418
+ "gamma": {
419
+ "dtype": "float32",
420
+ "shape": [32],
421
+ "data": { "kind": "fillFloat32", "sinStep": 0.29, "cosStep": 0.13 }
422
+ },
423
+ "beta": {
424
+ "dtype": "float32",
425
+ "shape": [32],
426
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.23 }
427
+ },
428
+ "skip": {
429
+ "dtype": "float32",
430
+ "shape": [2, 8, 8, 32],
431
+ "data": { "kind": "fillFloat32", "sinStep": 0.48, "cosStep": 0.22000000000000003 }
432
+ }
433
+ },
434
+ "outputs": {
435
+ "Y": { "dtype": "float32", "shape": [2, 8, 8, 32], "tolerance": 0.0005, "relTolerance": 0.0005 },
436
+ "S": { "dtype": "float32", "shape": [2, 8, 8, 32], "tolerance": 0.0005, "relTolerance": 0.0005 }
437
+ }
438
+ },
439
+ {
440
+ "name": "nhwc_vec4_nobias_nosum_f16",
441
+ "attrs": { "groups": 4, "activation": 0, "channels_last": 1 },
442
+ "inputs": {
443
+ "X": {
444
+ "dtype": "float16",
445
+ "shape": [2, 8, 8, 32],
446
+ "data": { "kind": "fillFloat32", "sinStep": 0.17, "cosStep": 0.34 }
447
+ },
448
+ "gamma": {
449
+ "dtype": "float32",
450
+ "shape": [32],
451
+ "data": { "kind": "fillFloat32", "sinStep": 0.29, "cosStep": 0.13 }
452
+ },
453
+ "beta": {
454
+ "dtype": "float32",
455
+ "shape": [32],
456
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.23 }
457
+ },
458
+ "skip": {
459
+ "dtype": "float16",
460
+ "shape": [2, 8, 8, 32],
461
+ "data": { "kind": "fillFloat32", "sinStep": 0.48, "cosStep": 0.22000000000000003 }
462
+ }
463
+ },
464
+ "outputs": { "Y": { "dtype": "float16", "shape": [2, 8, 8, 32], "tolerance": 0.01, "relTolerance": 0.004 } }
465
+ },
466
+ {
467
+ "name": "nhwc_scalar_odd_cpg_bias_sum",
468
+ "attrs": { "groups": 32, "activation": 1, "channels_last": 1 },
469
+ "inputs": {
470
+ "X": {
471
+ "dtype": "float32",
472
+ "shape": [2, 3, 3, 96],
473
+ "data": { "kind": "fillFloat32", "sinStep": 0.19, "cosStep": 0.36 }
474
+ },
475
+ "gamma": {
476
+ "dtype": "float32",
477
+ "shape": [96],
478
+ "data": { "kind": "fillFloat32", "sinStep": 0.29, "cosStep": 0.13 }
479
+ },
480
+ "beta": {
481
+ "dtype": "float32",
482
+ "shape": [96],
483
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.23 }
484
+ },
485
+ "skip": {
486
+ "dtype": "float32",
487
+ "shape": [2, 3, 3, 96],
488
+ "data": { "kind": "fillFloat32", "sinStep": 0.5, "cosStep": 0.24 }
489
+ },
490
+ "bias": {
491
+ "dtype": "float32",
492
+ "shape": [96],
493
+ "data": { "kind": "fillFloat32", "sinStep": 0.19, "cosStep": 0.37 }
494
+ }
495
+ },
496
+ "outputs": {
497
+ "Y": { "dtype": "float32", "shape": [2, 3, 3, 96], "tolerance": 0.0005, "relTolerance": 0.0005 },
498
+ "S": { "dtype": "float32", "shape": [2, 3, 3, 96], "tolerance": 0.0005, "relTolerance": 0.0005 }
499
+ }
500
+ },
501
+ {
502
+ "name": "nhwc_scalar_odd_cpg_nobias_nosum_f16",
503
+ "attrs": { "groups": 32, "activation": 0, "channels_last": 1 },
504
+ "inputs": {
505
+ "X": {
506
+ "dtype": "float16",
507
+ "shape": [2, 3, 3, 96],
508
+ "data": { "kind": "fillFloat32", "sinStep": 0.19, "cosStep": 0.36 }
509
+ },
510
+ "gamma": {
511
+ "dtype": "float32",
512
+ "shape": [96],
513
+ "data": { "kind": "fillFloat32", "sinStep": 0.29, "cosStep": 0.13 }
514
+ },
515
+ "beta": {
516
+ "dtype": "float32",
517
+ "shape": [96],
518
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.23 }
519
+ },
520
+ "skip": {
521
+ "dtype": "float16",
522
+ "shape": [2, 3, 3, 96],
523
+ "data": { "kind": "fillFloat32", "sinStep": 0.5, "cosStep": 0.24 }
524
+ }
525
+ },
526
+ "outputs": { "Y": { "dtype": "float16", "shape": [2, 3, 3, 96], "tolerance": 0.01, "relTolerance": 0.004 } }
527
+ },
528
+ {
529
+ "name": "nhwc_broadcast_skip_rank2_bias_sum",
530
+ "attrs": { "groups": 4, "activation": 0, "channels_last": 1 },
531
+ "inputs": {
532
+ "X": {
533
+ "dtype": "float32",
534
+ "shape": [2, 4, 4, 32],
535
+ "data": { "kind": "fillFloat32", "sinStep": 0.23, "cosStep": 0.4 }
536
+ },
537
+ "gamma": {
538
+ "dtype": "float32",
539
+ "shape": [32],
540
+ "data": { "kind": "fillFloat32", "sinStep": 0.29, "cosStep": 0.13 }
541
+ },
542
+ "beta": {
543
+ "dtype": "float32",
544
+ "shape": [32],
545
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.23 }
546
+ },
547
+ "skip": {
548
+ "dtype": "float32",
549
+ "shape": [2, 32],
550
+ "data": { "kind": "fillFloat32", "sinStep": 0.54, "cosStep": 0.28 }
551
+ },
552
+ "bias": {
553
+ "dtype": "float32",
554
+ "shape": [32],
555
+ "data": { "kind": "fillFloat32", "sinStep": 0.19, "cosStep": 0.37 }
556
+ }
557
+ },
558
+ "outputs": {
559
+ "Y": { "dtype": "float32", "shape": [2, 4, 4, 32], "tolerance": 0.0005, "relTolerance": 0.0005 },
560
+ "S": { "dtype": "float32", "shape": [2, 4, 4, 32], "tolerance": 0.0005, "relTolerance": 0.0005 }
561
+ }
562
+ },
563
+ {
564
+ "name": "nhwc_broadcast_skip_rank4_nobias_sum_f16",
565
+ "attrs": { "groups": 4, "activation": 1, "channels_last": 1 },
566
+ "inputs": {
567
+ "X": {
568
+ "dtype": "float16",
569
+ "shape": [2, 4, 4, 32],
570
+ "data": { "kind": "fillFloat32", "sinStep": 0.23, "cosStep": 0.4 }
571
+ },
572
+ "gamma": {
573
+ "dtype": "float32",
574
+ "shape": [32],
575
+ "data": { "kind": "fillFloat32", "sinStep": 0.29, "cosStep": 0.13 }
576
+ },
577
+ "beta": {
578
+ "dtype": "float32",
579
+ "shape": [32],
580
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.23 }
581
+ },
582
+ "skip": {
583
+ "dtype": "float16",
584
+ "shape": [2, 1, 1, 32],
585
+ "data": { "kind": "fillFloat32", "sinStep": 0.54, "cosStep": 0.28 }
586
+ }
587
+ },
588
+ "outputs": {
589
+ "Y": { "dtype": "float16", "shape": [2, 4, 4, 32], "tolerance": 0.01, "relTolerance": 0.004 },
590
+ "S": { "dtype": "float16", "shape": [2, 4, 4, 32], "tolerance": 0.01, "relTolerance": 0.004 }
591
+ }
592
+ },
593
+ {
594
+ "name": "nhwc_broadcast_skip_scalar_cpg_nosum",
595
+ "attrs": { "groups": 4, "activation": 1, "channels_last": 1 },
596
+ "inputs": {
597
+ "X": {
598
+ "dtype": "float32",
599
+ "shape": [1, 5, 5, 12],
600
+ "data": { "kind": "fillFloat32", "sinStep": 0.29, "cosStep": 0.45999999999999996 }
601
+ },
602
+ "gamma": {
603
+ "dtype": "float32",
604
+ "shape": [12],
605
+ "data": { "kind": "fillFloat32", "sinStep": 0.29, "cosStep": 0.13 }
606
+ },
607
+ "beta": {
608
+ "dtype": "float32",
609
+ "shape": [12],
610
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.23 }
611
+ },
612
+ "skip": {
613
+ "dtype": "float32",
614
+ "shape": [1, 12],
615
+ "data": { "kind": "fillFloat32", "sinStep": 0.6, "cosStep": 0.33999999999999997 }
616
+ },
617
+ "bias": {
618
+ "dtype": "float32",
619
+ "shape": [12],
620
+ "data": { "kind": "fillFloat32", "sinStep": 0.19, "cosStep": 0.37 }
621
+ }
622
+ },
623
+ "outputs": { "Y": { "dtype": "float32", "shape": [1, 5, 5, 12], "tolerance": 0.0005, "relTolerance": 0.0005 } }
624
+ },
625
+ {
626
+ "name": "nchw_vec4_bias_sum_f32",
627
+ "attrs": { "groups": 4, "activation": 0, "channels_last": 0 },
628
+ "inputs": {
629
+ "X": {
630
+ "dtype": "float32",
631
+ "shape": [1, 16, 32, 32],
632
+ "data": { "kind": "fillFloat32", "sinStep": 0.31, "cosStep": 0.48 }
633
+ },
634
+ "gamma": {
635
+ "dtype": "float32",
636
+ "shape": [16],
637
+ "data": { "kind": "fillFloat32", "sinStep": 0.29, "cosStep": 0.13 }
638
+ },
639
+ "beta": {
640
+ "dtype": "float32",
641
+ "shape": [16],
642
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.23 }
643
+ },
644
+ "skip": {
645
+ "dtype": "float32",
646
+ "shape": [1, 16, 32, 32],
647
+ "data": { "kind": "fillFloat32", "sinStep": 0.62, "cosStep": 0.36 }
648
+ },
649
+ "bias": {
650
+ "dtype": "float32",
651
+ "shape": [16],
652
+ "data": { "kind": "fillFloat32", "sinStep": 0.19, "cosStep": 0.37 }
653
+ }
654
+ },
655
+ "outputs": {
656
+ "Y": { "dtype": "float32", "shape": [1, 16, 32, 32], "tolerance": 0.0005, "relTolerance": 0.0005 },
657
+ "S": { "dtype": "float32", "shape": [1, 16, 32, 32], "tolerance": 0.0005, "relTolerance": 0.0005 }
658
+ }
659
+ },
660
+ {
661
+ "name": "nchw_vec4_nobias_sum_silu_f16",
662
+ "attrs": { "groups": 4, "activation": 1, "channels_last": 0 },
663
+ "inputs": {
664
+ "X": {
665
+ "dtype": "float16",
666
+ "shape": [1, 16, 32, 32],
667
+ "data": { "kind": "fillFloat32", "sinStep": 0.31, "cosStep": 0.48 }
668
+ },
669
+ "gamma": {
670
+ "dtype": "float32",
671
+ "shape": [16],
672
+ "data": { "kind": "fillFloat32", "sinStep": 0.29, "cosStep": 0.13 }
673
+ },
674
+ "beta": {
675
+ "dtype": "float32",
676
+ "shape": [16],
677
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.23 }
678
+ },
679
+ "skip": {
680
+ "dtype": "float16",
681
+ "shape": [1, 16, 32, 32],
682
+ "data": { "kind": "fillFloat32", "sinStep": 0.62, "cosStep": 0.36 }
683
+ }
684
+ },
685
+ "outputs": {
686
+ "Y": { "dtype": "float16", "shape": [1, 16, 32, 32], "tolerance": 0.01, "relTolerance": 0.004 },
687
+ "S": { "dtype": "float16", "shape": [1, 16, 32, 32], "tolerance": 0.01, "relTolerance": 0.004 }
688
+ }
689
+ },
690
+ {
691
+ "name": "nchw_scalar_hw9_bias_nosum",
692
+ "attrs": { "groups": 3, "activation": 1, "channels_last": 0 },
693
+ "inputs": {
694
+ "X": {
695
+ "dtype": "float32",
696
+ "shape": [2, 6, 3, 3],
697
+ "data": { "kind": "fillFloat32", "sinStep": 0.37, "cosStep": 0.54 }
698
+ },
699
+ "gamma": {
700
+ "dtype": "float32",
701
+ "shape": [6],
702
+ "data": { "kind": "fillFloat32", "sinStep": 0.29, "cosStep": 0.13 }
703
+ },
704
+ "beta": {
705
+ "dtype": "float32",
706
+ "shape": [6],
707
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.23 }
708
+ },
709
+ "skip": {
710
+ "dtype": "float32",
711
+ "shape": [2, 6, 3, 3],
712
+ "data": { "kind": "fillFloat32", "sinStep": 0.6799999999999999, "cosStep": 0.42 }
713
+ },
714
+ "bias": {
715
+ "dtype": "float32",
716
+ "shape": [6],
717
+ "data": { "kind": "fillFloat32", "sinStep": 0.19, "cosStep": 0.37 }
718
+ }
719
+ },
720
+ "outputs": { "Y": { "dtype": "float32", "shape": [2, 6, 3, 3], "tolerance": 0.0005, "relTolerance": 0.0005 } }
721
+ },
722
+ {
723
+ "name": "nchw_broadcast_skip_rank2_bias_sum",
724
+ "attrs": { "groups": 2, "activation": 0, "channels_last": 0 },
725
+ "inputs": {
726
+ "X": {
727
+ "dtype": "float32",
728
+ "shape": [2, 8, 4, 4],
729
+ "data": { "kind": "fillFloat32", "sinStep": 0.41, "cosStep": 0.58 }
730
+ },
731
+ "gamma": {
732
+ "dtype": "float32",
733
+ "shape": [8],
734
+ "data": { "kind": "fillFloat32", "sinStep": 0.29, "cosStep": 0.13 }
735
+ },
736
+ "beta": {
737
+ "dtype": "float32",
738
+ "shape": [8],
739
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.23 }
740
+ },
741
+ "skip": {
742
+ "dtype": "float32",
743
+ "shape": [2, 8],
744
+ "data": { "kind": "fillFloat32", "sinStep": 0.72, "cosStep": 0.45999999999999996 }
745
+ },
746
+ "bias": {
747
+ "dtype": "float32",
748
+ "shape": [8],
749
+ "data": { "kind": "fillFloat32", "sinStep": 0.19, "cosStep": 0.37 }
750
+ }
751
+ },
752
+ "outputs": {
753
+ "Y": { "dtype": "float32", "shape": [2, 8, 4, 4], "tolerance": 0.0005, "relTolerance": 0.0005 },
754
+ "S": { "dtype": "float32", "shape": [2, 8, 4, 4], "tolerance": 0.0005, "relTolerance": 0.0005 }
755
+ }
756
+ },
757
+ {
758
+ "name": "nchw_broadcast_skip_rank4_nobias_nosum_f16",
759
+ "attrs": { "groups": 2, "activation": 1, "channels_last": 0 },
760
+ "inputs": {
761
+ "X": {
762
+ "dtype": "float16",
763
+ "shape": [2, 8, 4, 4],
764
+ "data": { "kind": "fillFloat32", "sinStep": 0.41, "cosStep": 0.58 }
765
+ },
766
+ "gamma": {
767
+ "dtype": "float32",
768
+ "shape": [8],
769
+ "data": { "kind": "fillFloat32", "sinStep": 0.29, "cosStep": 0.13 }
770
+ },
771
+ "beta": {
772
+ "dtype": "float32",
773
+ "shape": [8],
774
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.23 }
775
+ },
776
+ "skip": {
777
+ "dtype": "float16",
778
+ "shape": [2, 1, 1, 8],
779
+ "data": { "kind": "fillFloat32", "sinStep": 0.72, "cosStep": 0.45999999999999996 }
780
+ }
781
+ },
782
+ "outputs": { "Y": { "dtype": "float16", "shape": [2, 8, 4, 4], "tolerance": 0.01, "relTolerance": 0.004 } }
783
+ },
784
+ {
785
+ "name": "nhwc_f16_weights_bias_sum",
786
+ "attrs": { "groups": 2, "activation": 1, "channels_last": 1 },
787
+ "inputs": {
788
+ "X": {
789
+ "dtype": "float32",
790
+ "shape": [1, 8, 8, 16],
791
+ "data": { "kind": "fillFloat32", "sinStep": 0.43, "cosStep": 0.6 }
792
+ },
793
+ "gamma": {
794
+ "dtype": "float16",
795
+ "shape": [16],
796
+ "data": { "kind": "fillFloat32", "sinStep": 0.29, "cosStep": 0.13 }
797
+ },
798
+ "beta": {
799
+ "dtype": "float16",
800
+ "shape": [16],
801
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.23 }
802
+ },
803
+ "skip": {
804
+ "dtype": "float32",
805
+ "shape": [1, 8, 8, 16],
806
+ "data": { "kind": "fillFloat32", "sinStep": 0.74, "cosStep": 0.48 }
807
+ },
808
+ "bias": {
809
+ "dtype": "float32",
810
+ "shape": [16],
811
+ "data": { "kind": "fillFloat32", "sinStep": 0.19, "cosStep": 0.37 }
812
+ }
813
+ },
814
+ "outputs": {
815
+ "Y": { "dtype": "float32", "shape": [1, 8, 8, 16], "tolerance": 0.0005, "relTolerance": 0.0005 },
816
+ "S": { "dtype": "float32", "shape": [1, 8, 8, 16], "tolerance": 0.0005, "relTolerance": 0.0005 }
817
+ }
818
+ },
819
+ {
820
+ "name": "nhwc_all_f16_nobias_sum",
821
+ "attrs": { "groups": 2, "activation": 0, "channels_last": 1 },
822
+ "inputs": {
823
+ "X": {
824
+ "dtype": "float16",
825
+ "shape": [1, 8, 8, 16],
826
+ "data": { "kind": "fillFloat32", "sinStep": 0.47, "cosStep": 0.64 }
827
+ },
828
+ "gamma": {
829
+ "dtype": "float16",
830
+ "shape": [16],
831
+ "data": { "kind": "fillFloat32", "sinStep": 0.29, "cosStep": 0.13 }
832
+ },
833
+ "beta": {
834
+ "dtype": "float16",
835
+ "shape": [16],
836
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.23 }
837
+ },
838
+ "skip": {
839
+ "dtype": "float16",
840
+ "shape": [1, 8, 8, 16],
841
+ "data": { "kind": "fillFloat32", "sinStep": 0.78, "cosStep": 0.52 }
842
+ }
843
+ },
844
+ "outputs": {
845
+ "Y": { "dtype": "float16", "shape": [1, 8, 8, 16], "tolerance": 0.01, "relTolerance": 0.004 },
846
+ "S": { "dtype": "float16", "shape": [1, 8, 8, 16], "tolerance": 0.01, "relTolerance": 0.004 }
847
+ }
848
+ },
849
+ {
850
+ "name": "nhwc_vec4_large_epsilon_bias_nosum",
851
+ "attrs": { "groups": 2, "activation": 0, "channels_last": 1, "epsilon": 0.5 },
852
+ "inputs": {
853
+ "X": {
854
+ "dtype": "float32",
855
+ "shape": [1, 4, 4, 8],
856
+ "data": { "kind": "fillFloat32", "sinStep": 0.53, "cosStep": 0.7000000000000001 }
857
+ },
858
+ "gamma": {
859
+ "dtype": "float32",
860
+ "shape": [8],
861
+ "data": { "kind": "fillFloat32", "sinStep": 0.29, "cosStep": 0.13 }
862
+ },
863
+ "beta": {
864
+ "dtype": "float32",
865
+ "shape": [8],
866
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.23 }
867
+ },
868
+ "skip": {
869
+ "dtype": "float32",
870
+ "shape": [1, 4, 4, 8],
871
+ "data": { "kind": "fillFloat32", "sinStep": 0.8400000000000001, "cosStep": 0.5800000000000001 }
872
+ },
873
+ "bias": {
874
+ "dtype": "float32",
875
+ "shape": [8],
876
+ "data": { "kind": "fillFloat32", "sinStep": 0.19, "cosStep": 0.37 }
877
+ }
878
+ },
879
+ "outputs": { "Y": { "dtype": "float32", "shape": [1, 4, 4, 8], "tolerance": 0.0005, "relTolerance": 0.0005 } }
880
+ },
881
+ {
882
+ "name": "nchw_multi_split_bias_sum_f32",
883
+ "attrs": { "groups": 4, "activation": 0, "channels_last": 0 },
884
+ "inputs": {
885
+ "X": {
886
+ "dtype": "float32",
887
+ "shape": [1, 16, 96, 96],
888
+ "data": { "kind": "fillFloat32", "sinStep": 0.59, "cosStep": 0.76 }
889
+ },
890
+ "gamma": {
891
+ "dtype": "float32",
892
+ "shape": [16],
893
+ "data": { "kind": "fillFloat32", "sinStep": 0.29, "cosStep": 0.13 }
894
+ },
895
+ "beta": {
896
+ "dtype": "float32",
897
+ "shape": [16],
898
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.23 }
899
+ },
900
+ "skip": {
901
+ "dtype": "float32",
902
+ "shape": [1, 16, 96, 96],
903
+ "data": { "kind": "fillFloat32", "sinStep": 0.8999999999999999, "cosStep": 0.64 }
904
+ },
905
+ "bias": {
906
+ "dtype": "float32",
907
+ "shape": [16],
908
+ "data": { "kind": "fillFloat32", "sinStep": 0.19, "cosStep": 0.37 }
909
+ }
910
+ },
911
+ "outputs": {
912
+ "Y": { "dtype": "float32", "shape": [1, 16, 96, 96], "tolerance": 0.0005, "relTolerance": 0.0005 },
913
+ "S": { "dtype": "float32", "shape": [1, 16, 96, 96], "tolerance": 0.0005, "relTolerance": 0.0005 }
914
+ }
915
+ },
916
+ {
917
+ "name": "nhwc_multi_slab_nobias_sum_f16_silu",
918
+ "attrs": { "groups": 8, "activation": 1, "channels_last": 1 },
919
+ "inputs": {
920
+ "X": {
921
+ "dtype": "float16",
922
+ "shape": [1, 32, 32, 64],
923
+ "data": { "kind": "fillFloat32", "sinStep": 0.61, "cosStep": 0.78 }
924
+ },
925
+ "gamma": {
926
+ "dtype": "float32",
927
+ "shape": [64],
928
+ "data": { "kind": "fillFloat32", "sinStep": 0.29, "cosStep": 0.13 }
929
+ },
930
+ "beta": {
931
+ "dtype": "float32",
932
+ "shape": [64],
933
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.23 }
934
+ },
935
+ "skip": {
936
+ "dtype": "float16",
937
+ "shape": [1, 32, 32, 64],
938
+ "data": { "kind": "fillFloat32", "sinStep": 0.9199999999999999, "cosStep": 0.66 }
939
+ }
940
+ },
941
+ "outputs": {
942
+ "Y": { "dtype": "float16", "shape": [1, 32, 32, 64], "tolerance": 0.01, "relTolerance": 0.004 },
943
+ "S": { "dtype": "float16", "shape": [1, 32, 32, 64], "tolerance": 0.01, "relTolerance": 0.004 }
944
+ }
945
+ },
946
+ {
947
+ "name": "nhwc_scalar_channels_not_multiple_of_four_bias_sum",
948
+ "attrs": { "groups": 3, "activation": 1, "channels_last": 1 },
949
+ "inputs": {
950
+ "X": {
951
+ "dtype": "float32",
952
+ "shape": [2, 3, 3, 6],
953
+ "data": { "kind": "fillFloat32", "sinStep": 0.73, "cosStep": 0.9 }
954
+ },
955
+ "gamma": {
956
+ "dtype": "float32",
957
+ "shape": [6],
958
+ "data": { "kind": "fillFloat32", "sinStep": 0.29, "cosStep": 0.13 }
959
+ },
960
+ "beta": {
961
+ "dtype": "float32",
962
+ "shape": [6],
963
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.23 }
964
+ },
965
+ "skip": {
966
+ "dtype": "float32",
967
+ "shape": [2, 3, 3, 6],
968
+ "data": { "kind": "fillFloat32", "sinStep": 0.41, "cosStep": 0.17 }
969
+ },
970
+ "bias": {
971
+ "dtype": "float32",
972
+ "shape": [6],
973
+ "data": { "kind": "fillFloat32", "sinStep": 0.19, "cosStep": 0.37 }
974
+ }
975
+ },
976
+ "outputs": {
977
+ "Y": { "dtype": "float32", "shape": [2, 3, 3, 6], "tolerance": 0.0005, "relTolerance": 0.0005 },
978
+ "S": { "dtype": "float32", "shape": [2, 3, 3, 6], "tolerance": 0.0005, "relTolerance": 0.0005 }
979
+ }
980
+ },
981
+ {
982
+ "name": "nhwc_scalar_channels_not_multiple_of_four_broadcast_nosum",
983
+ "attrs": { "groups": 5, "activation": 0, "channels_last": 1 },
984
+ "inputs": {
985
+ "X": {
986
+ "dtype": "float32",
987
+ "shape": [2, 4, 4, 10],
988
+ "data": { "kind": "fillFloat32", "sinStep": 0.79, "cosStep": 0.31 }
989
+ },
990
+ "gamma": {
991
+ "dtype": "float32",
992
+ "shape": [10],
993
+ "data": { "kind": "fillFloat32", "sinStep": 0.29, "cosStep": 0.13 }
994
+ },
995
+ "beta": {
996
+ "dtype": "float32",
997
+ "shape": [10],
998
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.23 }
999
+ },
1000
+ "skip": {
1001
+ "dtype": "float32",
1002
+ "shape": [2, 10],
1003
+ "data": { "kind": "fillFloat32", "sinStep": 0.43, "cosStep": 0.11 }
1004
+ }
1005
+ },
1006
+ "outputs": { "Y": { "dtype": "float32", "shape": [2, 4, 4, 10], "tolerance": 0.0005, "relTolerance": 0.0005 } }
1007
+ },
1008
+ {
1009
+ "name": "nhwc_group_block_tail_c320_float32",
1010
+ "attrs": { "groups": 32, "activation": 0, "channels_last": 1 },
1011
+ "tunables": { "WORKGROUP_SIZE": 64, "SPLIT_MIN_ELEMENTS": 0 },
1012
+ "inputs": {
1013
+ "X": {
1014
+ "dtype": "float32",
1015
+ "shape": [1, 17, 19, 320],
1016
+ "data": {
1017
+ "kind": "cycle",
1018
+ "values": { "$ref": "#/fixtureArrays/nhwc_group_block_tail_c320_float32_input_X" }
1019
+ }
1020
+ },
1021
+ "gamma": {
1022
+ "dtype": "float16",
1023
+ "shape": [320],
1024
+ "data": { "kind": "fillFloat32", "sinStep": 0.29, "cosStep": 0.13 }
1025
+ },
1026
+ "beta": {
1027
+ "dtype": "float16",
1028
+ "shape": [320],
1029
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.23 }
1030
+ },
1031
+ "skip": {
1032
+ "dtype": "float32",
1033
+ "shape": [1, 17, 19, 320],
1034
+ "data": {
1035
+ "kind": "cycle",
1036
+ "values": [-0.625, -0.5, -0.375, -0.25, -0.125, 0.0, 0.125, 0.25, 0.375, 0.5, 0.625]
1037
+ }
1038
+ },
1039
+ "bias": {
1040
+ "dtype": "float32",
1041
+ "shape": [320],
1042
+ "data": { "kind": "cycle", "values": [-0.375, 0.125, 0.25, -0.5, 0.0625, 0.1875, 0.3125] }
1043
+ }
1044
+ },
1045
+ "outputs": {
1046
+ "Y": { "dtype": "float32", "shape": [1, 17, 19, 320], "tolerance": 0.0005, "relTolerance": 0.0005 },
1047
+ "S": { "dtype": "float32", "shape": [1, 17, 19, 320], "tolerance": 0, "relTolerance": 0 }
1048
+ }
1049
+ },
1050
+ {
1051
+ "name": "nhwc_group_block_tail_c320_float16",
1052
+ "attrs": { "groups": 32, "activation": 1, "channels_last": 1 },
1053
+ "tunables": { "WORKGROUP_SIZE": 64, "SPLIT_MIN_ELEMENTS": 0 },
1054
+ "inputs": {
1055
+ "X": {
1056
+ "dtype": "float16",
1057
+ "shape": [1, 17, 19, 320],
1058
+ "data": { "kind": "fillFloat32", "sinStep": 0.19, "cosStep": 0.36 }
1059
+ },
1060
+ "gamma": {
1061
+ "dtype": "float32",
1062
+ "shape": [320],
1063
+ "data": { "kind": "fillFloat32", "sinStep": 0.29, "cosStep": 0.13 }
1064
+ },
1065
+ "beta": {
1066
+ "dtype": "float32",
1067
+ "shape": [320],
1068
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.23 }
1069
+ },
1070
+ "skip": {
1071
+ "dtype": "float16",
1072
+ "shape": [1, 17, 19, 320],
1073
+ "data": { "kind": "fillFloat32", "sinStep": 0.5, "cosStep": 0.24 }
1074
+ }
1075
+ },
1076
+ "outputs": { "Y": { "dtype": "float16", "shape": [1, 17, 19, 320], "tolerance": 0.01, "relTolerance": 0.002 } }
1077
+ },
1078
+ {
1079
+ "name": "nhwc_group_block_tail_c96_float32",
1080
+ "attrs": { "groups": 32, "activation": 0, "channels_last": 1 },
1081
+ "tunables": { "WORKGROUP_SIZE": 64, "SPLIT_MIN_ELEMENTS": 0 },
1082
+ "inputs": {
1083
+ "X": {
1084
+ "dtype": "float32",
1085
+ "shape": [1, 17, 19, 96],
1086
+ "data": {
1087
+ "kind": "cycle",
1088
+ "values": { "$ref": "#/fixtureArrays/nhwc_group_block_tail_c320_float32_input_X" }
1089
+ }
1090
+ },
1091
+ "gamma": {
1092
+ "dtype": "float32",
1093
+ "shape": [96],
1094
+ "data": { "kind": "fillFloat32", "sinStep": 0.29, "cosStep": 0.13 }
1095
+ },
1096
+ "beta": {
1097
+ "dtype": "float32",
1098
+ "shape": [96],
1099
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.23 }
1100
+ },
1101
+ "skip": {
1102
+ "dtype": "float32",
1103
+ "shape": [1, 96],
1104
+ "data": {
1105
+ "kind": "cycle",
1106
+ "values": [-0.625, -0.5, -0.375, -0.25, -0.125, 0.0, 0.125, 0.25, 0.375, 0.5, 0.625]
1107
+ }
1108
+ },
1109
+ "bias": {
1110
+ "dtype": "float32",
1111
+ "shape": [96],
1112
+ "data": { "kind": "cycle", "values": [-0.375, 0.125, 0.25, -0.5, 0.0625, 0.1875, 0.3125] }
1113
+ }
1114
+ },
1115
+ "outputs": {
1116
+ "Y": { "dtype": "float32", "shape": [1, 17, 19, 96], "tolerance": 0.0005, "relTolerance": 0.0005 },
1117
+ "S": { "dtype": "float32", "shape": [1, 17, 19, 96], "tolerance": 0, "relTolerance": 0 }
1118
+ }
1119
+ },
1120
+ {
1121
+ "name": "nhwc_group_block_tail_c384_float16",
1122
+ "attrs": { "groups": 32, "activation": 1, "channels_last": 1 },
1123
+ "tunables": { "WORKGROUP_SIZE": 64, "SPLIT_MIN_ELEMENTS": 0 },
1124
+ "inputs": {
1125
+ "X": {
1126
+ "dtype": "float16",
1127
+ "shape": [1, 17, 19, 384],
1128
+ "data": { "kind": "fillFloat32", "sinStep": 0.19, "cosStep": 0.36 }
1129
+ },
1130
+ "gamma": {
1131
+ "dtype": "float32",
1132
+ "shape": [384],
1133
+ "data": { "kind": "fillFloat32", "sinStep": 0.29, "cosStep": 0.13 }
1134
+ },
1135
+ "beta": {
1136
+ "dtype": "float32",
1137
+ "shape": [384],
1138
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.23 }
1139
+ },
1140
+ "skip": {
1141
+ "dtype": "float16",
1142
+ "shape": [1, 384],
1143
+ "data": { "kind": "fillFloat32", "sinStep": 0.5, "cosStep": 0.24 }
1144
+ },
1145
+ "bias": {
1146
+ "dtype": "float16",
1147
+ "shape": [384],
1148
+ "data": { "kind": "fillFloat32", "sinStep": 0.19, "cosStep": 0.37 }
1149
+ }
1150
+ },
1151
+ "outputs": { "Y": { "dtype": "float16", "shape": [1, 17, 19, 384], "tolerance": 0.01, "relTolerance": 0.002 } }
1152
+ },
1153
+ {
1154
+ "name": "nhwc_group_block_tail_c320_float32_nonexact_inputs",
1155
+ "attrs": { "groups": 32, "activation": 0, "channels_last": 1 },
1156
+ "tunables": { "WORKGROUP_SIZE": 64, "SPLIT_MIN_ELEMENTS": 0 },
1157
+ "inputs": {
1158
+ "X": {
1159
+ "dtype": "float32",
1160
+ "shape": [1, 17, 19, 320],
1161
+ "data": { "kind": "fillFloat32", "sinStep": 0.19, "cosStep": 0.36 }
1162
+ },
1163
+ "gamma": {
1164
+ "dtype": "float16",
1165
+ "shape": [320],
1166
+ "data": { "kind": "fillFloat32", "sinStep": 0.29, "cosStep": 0.13 }
1167
+ },
1168
+ "beta": {
1169
+ "dtype": "float16",
1170
+ "shape": [320],
1171
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.23 }
1172
+ },
1173
+ "skip": {
1174
+ "dtype": "float32",
1175
+ "shape": [1, 17, 19, 320],
1176
+ "data": { "kind": "fillFloat32", "sinStep": 0.5, "cosStep": 0.24 }
1177
+ },
1178
+ "bias": {
1179
+ "dtype": "float32",
1180
+ "shape": [320],
1181
+ "data": { "kind": "fillFloat32", "sinStep": 0.19, "cosStep": 0.37 }
1182
+ }
1183
+ },
1184
+ "outputs": {
1185
+ "Y": { "dtype": "float32", "shape": [1, 17, 19, 320], "tolerance": 0.0005, "relTolerance": 0.0005 },
1186
+ "S": { "dtype": "float32", "shape": [1, 17, 19, 320], "tolerance": 0.0005, "relTolerance": 0.0005 }
1187
+ }
1188
+ },
1189
+ {
1190
+ "name": "nhwc_group_block_tail_c96_float32_nonexact_inputs",
1191
+ "attrs": { "groups": 32, "activation": 0, "channels_last": 1 },
1192
+ "tunables": { "WORKGROUP_SIZE": 64, "SPLIT_MIN_ELEMENTS": 0 },
1193
+ "inputs": {
1194
+ "X": {
1195
+ "dtype": "float32",
1196
+ "shape": [1, 17, 19, 96],
1197
+ "data": { "kind": "fillFloat32", "sinStep": 0.19, "cosStep": 0.36 }
1198
+ },
1199
+ "gamma": {
1200
+ "dtype": "float32",
1201
+ "shape": [96],
1202
+ "data": { "kind": "fillFloat32", "sinStep": 0.29, "cosStep": 0.13 }
1203
+ },
1204
+ "beta": {
1205
+ "dtype": "float32",
1206
+ "shape": [96],
1207
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.23 }
1208
+ },
1209
+ "skip": {
1210
+ "dtype": "float32",
1211
+ "shape": [1, 96],
1212
+ "data": { "kind": "fillFloat32", "sinStep": 0.5, "cosStep": 0.24 }
1213
+ },
1214
+ "bias": {
1215
+ "dtype": "float32",
1216
+ "shape": [96],
1217
+ "data": { "kind": "fillFloat32", "sinStep": 0.19, "cosStep": 0.37 }
1218
+ }
1219
+ },
1220
+ "outputs": {
1221
+ "Y": { "dtype": "float32", "shape": [1, 17, 19, 96], "tolerance": 0.0005, "relTolerance": 0.0005 },
1222
+ "S": { "dtype": "float32", "shape": [1, 17, 19, 96], "tolerance": 0.0005, "relTolerance": 0.0005 }
1223
+ }
1224
+ },
1225
+ {
1226
+ "name": "nhwc_pair_stats_c64_float32",
1227
+ "attrs": { "groups": 32, "activation": 0, "channels_last": 1 },
1228
+ "tunables": { "SPLIT_MIN_ELEMENTS": 0 },
1229
+ "inputs": {
1230
+ "X": {
1231
+ "dtype": "float32",
1232
+ "shape": [2, 17, 19, 64],
1233
+ "data": { "kind": "fillFloat32", "sinStep": 0.19, "cosStep": 0.36 }
1234
+ },
1235
+ "gamma": {
1236
+ "dtype": "float32",
1237
+ "shape": [64],
1238
+ "data": { "kind": "fillFloat32", "sinStep": 0.29, "cosStep": 0.13 }
1239
+ },
1240
+ "beta": {
1241
+ "dtype": "float32",
1242
+ "shape": [64],
1243
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.23 }
1244
+ },
1245
+ "skip": {
1246
+ "dtype": "float32",
1247
+ "shape": [2, 17, 19, 64],
1248
+ "data": { "kind": "fillFloat32", "sinStep": 0.5, "cosStep": 0.24 }
1249
+ }
1250
+ },
1251
+ "outputs": {
1252
+ "Y": { "dtype": "float32", "shape": [2, 17, 19, 64], "tolerance": 0.0005, "relTolerance": 0.0005 },
1253
+ "S": { "dtype": "float32", "shape": [2, 17, 19, 64], "tolerance": 0, "relTolerance": 0 }
1254
+ }
1255
+ },
1256
+ {
1257
+ "name": "nhwc_pair_stats_c64_float16",
1258
+ "attrs": { "groups": 32, "activation": 1, "channels_last": 1 },
1259
+ "tunables": { "SPLIT_MIN_ELEMENTS": 0 },
1260
+ "inputs": {
1261
+ "X": {
1262
+ "dtype": "float16",
1263
+ "shape": [2, 17, 19, 64],
1264
+ "data": { "kind": "fillFloat32", "sinStep": 0.19, "cosStep": 0.36 }
1265
+ },
1266
+ "gamma": {
1267
+ "dtype": "float32",
1268
+ "shape": [64],
1269
+ "data": { "kind": "fillFloat32", "sinStep": 0.29, "cosStep": 0.13 }
1270
+ },
1271
+ "beta": {
1272
+ "dtype": "float32",
1273
+ "shape": [64],
1274
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.23 }
1275
+ },
1276
+ "skip": {
1277
+ "dtype": "float16",
1278
+ "shape": [2, 17, 19, 64],
1279
+ "data": { "kind": "fillFloat32", "sinStep": 0.5, "cosStep": 0.24 }
1280
+ }
1281
+ },
1282
+ "outputs": {
1283
+ "Y": { "dtype": "float16", "shape": [2, 17, 19, 64], "tolerance": 0.01, "relTolerance": 0.002 },
1284
+ "S": { "dtype": "float16", "shape": [2, 17, 19, 64], "tolerance": 0, "relTolerance": 0 }
1285
+ }
1286
+ },
1287
+ {
1288
+ "name": "nhwc_pair_stats_c192_float32",
1289
+ "attrs": { "groups": 32, "activation": 0, "channels_last": 1 },
1290
+ "tunables": { "SPLIT_MIN_ELEMENTS": 0 },
1291
+ "inputs": {
1292
+ "X": {
1293
+ "dtype": "float32",
1294
+ "shape": [2, 17, 19, 192],
1295
+ "data": { "kind": "fillFloat32", "sinStep": 0.19, "cosStep": 0.36 }
1296
+ },
1297
+ "gamma": {
1298
+ "dtype": "float32",
1299
+ "shape": [192],
1300
+ "data": { "kind": "fillFloat32", "sinStep": 0.29, "cosStep": 0.13 }
1301
+ },
1302
+ "beta": {
1303
+ "dtype": "float32",
1304
+ "shape": [192],
1305
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.23 }
1306
+ },
1307
+ "skip": {
1308
+ "dtype": "float32",
1309
+ "shape": [2, 17, 19, 192],
1310
+ "data": { "kind": "fillFloat32", "sinStep": 0.5, "cosStep": 0.24 }
1311
+ }
1312
+ },
1313
+ "outputs": {
1314
+ "Y": { "dtype": "float32", "shape": [2, 17, 19, 192], "tolerance": 0.0005, "relTolerance": 0.0005 },
1315
+ "S": { "dtype": "float32", "shape": [2, 17, 19, 192], "tolerance": 0, "relTolerance": 0 }
1316
+ }
1317
+ },
1318
+ {
1319
+ "name": "nhwc_pair_stats_c192_float16",
1320
+ "attrs": { "groups": 32, "activation": 1, "channels_last": 1 },
1321
+ "tunables": { "SPLIT_MIN_ELEMENTS": 0 },
1322
+ "inputs": {
1323
+ "X": {
1324
+ "dtype": "float16",
1325
+ "shape": [2, 17, 19, 192],
1326
+ "data": { "kind": "fillFloat32", "sinStep": 0.19, "cosStep": 0.36 }
1327
+ },
1328
+ "gamma": {
1329
+ "dtype": "float32",
1330
+ "shape": [192],
1331
+ "data": { "kind": "fillFloat32", "sinStep": 0.29, "cosStep": 0.13 }
1332
+ },
1333
+ "beta": {
1334
+ "dtype": "float32",
1335
+ "shape": [192],
1336
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.23 }
1337
+ },
1338
+ "skip": {
1339
+ "dtype": "float16",
1340
+ "shape": [2, 17, 19, 192],
1341
+ "data": { "kind": "fillFloat32", "sinStep": 0.5, "cosStep": 0.24 }
1342
+ }
1343
+ },
1344
+ "outputs": {
1345
+ "Y": { "dtype": "float16", "shape": [2, 17, 19, 192], "tolerance": 0.01, "relTolerance": 0.002 },
1346
+ "S": { "dtype": "float16", "shape": [2, 17, 19, 192], "tolerance": 0, "relTolerance": 0 }
1347
+ }
1348
+ },
1349
+ {
1350
+ "name": "nhwc_pair_stats_c448_float32",
1351
+ "attrs": { "groups": 32, "activation": 0, "channels_last": 1 },
1352
+ "tunables": { "SPLIT_MIN_ELEMENTS": 0 },
1353
+ "inputs": {
1354
+ "X": {
1355
+ "dtype": "float32",
1356
+ "shape": [2, 17, 19, 448],
1357
+ "data": { "kind": "cycle", "values": [-0.75, -0.5, -0.25, 0.0, 0.25, 0.5, 0.75] }
1358
+ },
1359
+ "gamma": {
1360
+ "dtype": "float32",
1361
+ "shape": [448],
1362
+ "data": { "kind": "fillFloat32", "sinStep": 0.29, "cosStep": 0.13 }
1363
+ },
1364
+ "beta": {
1365
+ "dtype": "float32",
1366
+ "shape": [448],
1367
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.23 }
1368
+ },
1369
+ "skip": {
1370
+ "dtype": "float32",
1371
+ "shape": [2, 1, 1, 448],
1372
+ "data": { "kind": "cycle", "values": [-0.625, -0.375, -0.125, 0.125, 0.375, 0.625] }
1373
+ },
1374
+ "bias": {
1375
+ "dtype": "float32",
1376
+ "shape": [448],
1377
+ "data": { "kind": "cycle", "values": [-0.375, 0.125, 0.25, -0.5, 0.0625, 0.1875, 0.3125] }
1378
+ }
1379
+ },
1380
+ "outputs": {
1381
+ "Y": { "dtype": "float32", "shape": [2, 17, 19, 448], "tolerance": 0.0005, "relTolerance": 0.0005 },
1382
+ "S": { "dtype": "float32", "shape": [2, 17, 19, 448], "tolerance": 0, "relTolerance": 0 }
1383
+ }
1384
+ },
1385
+ {
1386
+ "name": "nhwc_pair_stats_c448_float16",
1387
+ "attrs": { "groups": 32, "activation": 1, "channels_last": 1 },
1388
+ "tunables": { "SPLIT_MIN_ELEMENTS": 0 },
1389
+ "inputs": {
1390
+ "X": {
1391
+ "dtype": "float16",
1392
+ "shape": [2, 17, 19, 448],
1393
+ "data": { "kind": "cycle", "values": [-0.75, -0.5, -0.25, 0.0, 0.25, 0.5, 0.75] }
1394
+ },
1395
+ "gamma": {
1396
+ "dtype": "float32",
1397
+ "shape": [448],
1398
+ "data": { "kind": "fillFloat32", "sinStep": 0.29, "cosStep": 0.13 }
1399
+ },
1400
+ "beta": {
1401
+ "dtype": "float32",
1402
+ "shape": [448],
1403
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.23 }
1404
+ },
1405
+ "skip": {
1406
+ "dtype": "float16",
1407
+ "shape": [2, 1, 1, 448],
1408
+ "data": { "kind": "cycle", "values": [-0.625, -0.375, -0.125, 0.125, 0.375, 0.625] }
1409
+ },
1410
+ "bias": {
1411
+ "dtype": "float16",
1412
+ "shape": [448],
1413
+ "data": { "kind": "cycle", "values": [-0.375, 0.125, 0.25, -0.5, 0.0625, 0.1875, 0.3125] }
1414
+ }
1415
+ },
1416
+ "outputs": {
1417
+ "Y": { "dtype": "float16", "shape": [2, 17, 19, 448], "tolerance": 0.01, "relTolerance": 0.002 },
1418
+ "S": { "dtype": "float16", "shape": [2, 17, 19, 448], "tolerance": 0, "relTolerance": 0 }
1419
+ }
1420
+ },
1421
+ {
1422
+ "name": "nhwc_min_limit_group_tail_c288_g96_float32",
1423
+ "attrs": { "groups": 96, "activation": 0, "channels_last": 1 },
1424
+ "tunables": { "WORKGROUP_SIZE": 64, "SPLIT_MIN_ELEMENTS": 0 },
1425
+ "inputs": {
1426
+ "X": {
1427
+ "dtype": "float32",
1428
+ "shape": [1, 17, 19, 288],
1429
+ "data": {
1430
+ "kind": "cycle",
1431
+ "values": { "$ref": "#/fixtureArrays/nhwc_group_block_tail_c320_float32_input_X" }
1432
+ }
1433
+ },
1434
+ "gamma": {
1435
+ "dtype": "float32",
1436
+ "shape": [288],
1437
+ "data": { "kind": "fillFloat32", "sinStep": 0.29, "cosStep": 0.13 }
1438
+ },
1439
+ "beta": {
1440
+ "dtype": "float32",
1441
+ "shape": [288],
1442
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.23 }
1443
+ },
1444
+ "skip": {
1445
+ "dtype": "float32",
1446
+ "shape": [1, 288],
1447
+ "data": {
1448
+ "kind": "cycle",
1449
+ "values": [-0.625, -0.5, -0.375, -0.25, -0.125, 0.0, 0.125, 0.25, 0.375, 0.5, 0.625]
1450
+ }
1451
+ },
1452
+ "bias": {
1453
+ "dtype": "float32",
1454
+ "shape": [288],
1455
+ "data": { "kind": "cycle", "values": [-0.375, 0.125, 0.25, -0.5, 0.0625, 0.1875, 0.3125] }
1456
+ }
1457
+ },
1458
+ "outputs": {
1459
+ "Y": { "dtype": "float32", "shape": [1, 17, 19, 288], "tolerance": 0.0005, "relTolerance": 0.0005 },
1460
+ "S": { "dtype": "float32", "shape": [1, 17, 19, 288], "tolerance": 0, "relTolerance": 0 }
1461
+ },
1462
+ "provenance": {
1463
+ "notes": "Complete-group statistics blocks with a partial final block under the standard 256-invocation WebGPU minimum tier. Odd groups retain scalar loads; even groups exercise vec2 blocks."
1464
+ }
1465
+ },
1466
+ {
1467
+ "name": "nhwc_min_limit_group_tail_c288_g96_float16",
1468
+ "attrs": { "groups": 96, "activation": 0, "channels_last": 1 },
1469
+ "tunables": { "WORKGROUP_SIZE": 64, "SPLIT_MIN_ELEMENTS": 0 },
1470
+ "inputs": {
1471
+ "X": {
1472
+ "dtype": "float16",
1473
+ "shape": [1, 17, 19, 288],
1474
+ "data": {
1475
+ "kind": "cycle",
1476
+ "values": { "$ref": "#/fixtureArrays/nhwc_group_block_tail_c320_float32_input_X" }
1477
+ }
1478
+ },
1479
+ "gamma": {
1480
+ "dtype": "float16",
1481
+ "shape": [288],
1482
+ "data": { "kind": "fillFloat32", "sinStep": 0.29, "cosStep": 0.13 }
1483
+ },
1484
+ "beta": {
1485
+ "dtype": "float16",
1486
+ "shape": [288],
1487
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.23 }
1488
+ },
1489
+ "skip": {
1490
+ "dtype": "float16",
1491
+ "shape": [1, 288],
1492
+ "data": {
1493
+ "kind": "cycle",
1494
+ "values": [-0.625, -0.5, -0.375, -0.25, -0.125, 0.0, 0.125, 0.25, 0.375, 0.5, 0.625]
1495
+ }
1496
+ },
1497
+ "bias": {
1498
+ "dtype": "float16",
1499
+ "shape": [288],
1500
+ "data": { "kind": "cycle", "values": [-0.375, 0.125, 0.25, -0.5, 0.0625, 0.1875, 0.3125] }
1501
+ }
1502
+ },
1503
+ "outputs": {
1504
+ "Y": { "dtype": "float16", "shape": [1, 17, 19, 288], "tolerance": 0.01, "relTolerance": 0.002 },
1505
+ "S": { "dtype": "float16", "shape": [1, 17, 19, 288], "tolerance": 0, "relTolerance": 0 }
1506
+ },
1507
+ "provenance": {
1508
+ "notes": "Complete-group statistics blocks with a partial final block under the standard 256-invocation WebGPU minimum tier. Odd groups retain scalar loads; even groups exercise vec2 blocks."
1509
+ }
1510
+ },
1511
+ {
1512
+ "name": "nhwc_min_limit_group_tail_c640_g64_float32",
1513
+ "attrs": { "groups": 64, "activation": 0, "channels_last": 1 },
1514
+ "tunables": { "WORKGROUP_SIZE": 64, "SPLIT_MIN_ELEMENTS": 0 },
1515
+ "inputs": {
1516
+ "X": {
1517
+ "dtype": "float32",
1518
+ "shape": [1, 17, 19, 640],
1519
+ "data": {
1520
+ "kind": "cycle",
1521
+ "values": { "$ref": "#/fixtureArrays/nhwc_group_block_tail_c320_float32_input_X" }
1522
+ }
1523
+ },
1524
+ "gamma": {
1525
+ "dtype": "float32",
1526
+ "shape": [640],
1527
+ "data": { "kind": "fillFloat32", "sinStep": 0.29, "cosStep": 0.13 }
1528
+ },
1529
+ "beta": {
1530
+ "dtype": "float32",
1531
+ "shape": [640],
1532
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.23 }
1533
+ },
1534
+ "skip": {
1535
+ "dtype": "float32",
1536
+ "shape": [1, 640],
1537
+ "data": {
1538
+ "kind": "cycle",
1539
+ "values": [-0.625, -0.5, -0.375, -0.25, -0.125, 0.0, 0.125, 0.25, 0.375, 0.5, 0.625]
1540
+ }
1541
+ },
1542
+ "bias": {
1543
+ "dtype": "float32",
1544
+ "shape": [640],
1545
+ "data": { "kind": "cycle", "values": [-0.375, 0.125, 0.25, -0.5, 0.0625, 0.1875, 0.3125] }
1546
+ }
1547
+ },
1548
+ "outputs": {
1549
+ "Y": { "dtype": "float32", "shape": [1, 17, 19, 640], "tolerance": 0.0005, "relTolerance": 0.0005 },
1550
+ "S": { "dtype": "float32", "shape": [1, 17, 19, 640], "tolerance": 0, "relTolerance": 0 }
1551
+ },
1552
+ "provenance": {
1553
+ "notes": "Complete-group statistics blocks with a partial final block under the standard 256-invocation WebGPU minimum tier. Odd groups retain scalar loads; even groups exercise vec2 blocks."
1554
+ }
1555
+ },
1556
+ {
1557
+ "name": "nhwc_min_limit_group_tail_c640_g64_float16",
1558
+ "attrs": { "groups": 64, "activation": 0, "channels_last": 1 },
1559
+ "tunables": { "WORKGROUP_SIZE": 64, "SPLIT_MIN_ELEMENTS": 0 },
1560
+ "inputs": {
1561
+ "X": {
1562
+ "dtype": "float16",
1563
+ "shape": [1, 17, 19, 640],
1564
+ "data": {
1565
+ "kind": "cycle",
1566
+ "values": { "$ref": "#/fixtureArrays/nhwc_group_block_tail_c320_float32_input_X" }
1567
+ }
1568
+ },
1569
+ "gamma": {
1570
+ "dtype": "float16",
1571
+ "shape": [640],
1572
+ "data": { "kind": "fillFloat32", "sinStep": 0.29, "cosStep": 0.13 }
1573
+ },
1574
+ "beta": {
1575
+ "dtype": "float16",
1576
+ "shape": [640],
1577
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.23 }
1578
+ },
1579
+ "skip": {
1580
+ "dtype": "float16",
1581
+ "shape": [1, 640],
1582
+ "data": {
1583
+ "kind": "cycle",
1584
+ "values": [-0.625, -0.5, -0.375, -0.25, -0.125, 0.0, 0.125, 0.25, 0.375, 0.5, 0.625]
1585
+ }
1586
+ },
1587
+ "bias": {
1588
+ "dtype": "float16",
1589
+ "shape": [640],
1590
+ "data": { "kind": "cycle", "values": [-0.375, 0.125, 0.25, -0.5, 0.0625, 0.1875, 0.3125] }
1591
+ }
1592
+ },
1593
+ "outputs": {
1594
+ "Y": { "dtype": "float16", "shape": [1, 17, 19, 640], "tolerance": 0.01, "relTolerance": 0.002 },
1595
+ "S": { "dtype": "float16", "shape": [1, 17, 19, 640], "tolerance": 0, "relTolerance": 0 }
1596
+ },
1597
+ "provenance": {
1598
+ "notes": "Complete-group statistics blocks with a partial final block under the standard 256-invocation WebGPU minimum tier. Odd groups retain scalar loads; even groups exercise vec2 blocks."
1599
+ }
1600
+ },
1601
+ {
1602
+ "name": "ort_skip_group_norm_webgpu_cpg2_c6_g3_broadcast_n11c_bias_sum",
1603
+ "attrs": { "groups": 3, "activation": 0, "channels_last": 1, "epsilon": 0.00001 },
1604
+ "inputs": {
1605
+ "X": {
1606
+ "dtype": "float16",
1607
+ "shape": [2, 3, 2, 6],
1608
+ "data": { "kind": "fillFloat32", "sinStep": 0.23, "cosStep": 0.41 }
1609
+ },
1610
+ "gamma": {
1611
+ "dtype": "float32",
1612
+ "shape": [6],
1613
+ "data": { "kind": "fillFloat32", "sinStep": 0.29, "cosStep": 0.13, "offset": 1.0, "scale": 0.5 }
1614
+ },
1615
+ "beta": {
1616
+ "dtype": "float32",
1617
+ "shape": [6],
1618
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.23, "scale": 0.5 }
1619
+ },
1620
+ "skip": {
1621
+ "dtype": "float16",
1622
+ "shape": [2, 1, 1, 6],
1623
+ "data": { "kind": "fillFloat32", "sinStep": 0.37, "cosStep": 0.19 }
1624
+ },
1625
+ "bias": {
1626
+ "dtype": "float16",
1627
+ "shape": [6],
1628
+ "data": { "kind": "fillFloat32", "sinStep": 0.11, "cosStep": 0.53, "scale": 0.5 }
1629
+ }
1630
+ },
1631
+ "outputs": {
1632
+ "Y": { "dtype": "float16", "shape": [2, 3, 2, 6], "tolerance": 0.01, "relTolerance": 0.004 },
1633
+ "S": { "dtype": "float16", "shape": [2, 3, 2, 6], "tolerance": 0.01, "relTolerance": 0.004 }
1634
+ }
1635
+ },
1636
+ {
1637
+ "name": "ort_skip_group_norm_webgpu_cpg4_c8_g2_broadcast_nc_nobias_nosum",
1638
+ "attrs": { "groups": 2, "activation": 0, "channels_last": 1, "epsilon": 0.00001 },
1639
+ "inputs": {
1640
+ "X": {
1641
+ "dtype": "float32",
1642
+ "shape": [2, 3, 2, 8],
1643
+ "data": { "kind": "fillFloat32", "sinStep": 0.23, "cosStep": 0.41 }
1644
+ },
1645
+ "gamma": {
1646
+ "dtype": "float32",
1647
+ "shape": [8],
1648
+ "data": { "kind": "fillFloat32", "sinStep": 0.29, "cosStep": 0.13, "offset": 1.0, "scale": 0.5 }
1649
+ },
1650
+ "beta": {
1651
+ "dtype": "float32",
1652
+ "shape": [8],
1653
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.23, "scale": 0.5 }
1654
+ },
1655
+ "skip": {
1656
+ "dtype": "float32",
1657
+ "shape": [2, 8],
1658
+ "data": { "kind": "fillFloat32", "sinStep": 0.37, "cosStep": 0.19 }
1659
+ }
1660
+ },
1661
+ "outputs": { "Y": { "dtype": "float32", "shape": [2, 3, 2, 8], "tolerance": 0.0005, "relTolerance": 0.0005 } }
1662
+ }
1663
+ ]
1664
+ }