Xenova HF Staff commited on
Commit
ee8ac59
·
verified ·
1 Parent(s): 0877677

sync 2e7068faf55e

Browse files
README.md CHANGED
@@ -1,3 +1,68 @@
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
+ # ai.onnx.GlobalMaxPool
10
+
11
+ `ai.onnx` · standard ONNX operator · ONNX opset ≥ 1
12
+
13
+ ## Description
14
+
15
+ Applies max pooling across all spatial dimensions of `X`, producing one value per channel. Equivalent to MaxPool with kernel size equal to the full spatial extent of the input; output shape is `(N x C x 1 x ... x 1)`.
16
+
17
+ See the [ONNX `GlobalMaxPool` spec](https://onnx.ai/onnx/operators/onnx__GlobalMaxPool.html) for the reference semantics.
18
+
19
+ ## Inputs
20
+
21
+ | Name | Bind key | Logical dtype | Rank | Shape | Description | Presence |
22
+ | --- | --- | --- | --- | --- | --- | --- |
23
+ | `X` | `x` | `T` | — | — | Input tensor of shape `(N x C x D1 x ... x Dn)`, where `N` is the batch size and `C` is the number of channels. | required |
24
+
25
+ ## Outputs
26
+
27
+ | Name | Bind key | Logical dtype | Rank | Shape | Description | Presence |
28
+ | --- | --- | --- | --- | --- | --- | --- |
29
+ | `Y` | `y` | `T` | same as `X` | — | Output tensor of shape `(N x C x 1 x ... x 1)`; the maximum value over each spatial region per channel. | required |
30
+
31
+ ## Type constraints
32
+
33
+ | Variable | Allowed dtypes |
34
+ | --- | --- |
35
+ | `T` | `float32`, `float16` |
36
+
37
+ ## Files
38
+
39
+ - [`metadata.json`](build/webgpu/metadata.json) — kernel metadata (id, digests, provenance)
40
+ - [`manifest.json`](build/webgpu/manifest.json) — the op contract (source of truth)
41
+ - [`test.json`](build/webgpu/test.json) — correctness cases
42
+ - [`bench.json`](build/webgpu/bench.json) — benchmark + tuning cases
43
+ - [`pool-global-reduction.wgsl.jinja`](build/webgpu/pool-global-reduction.wgsl.jinja)
44
+ - [`pool-global-serial.wgsl.jinja`](build/webgpu/pool-global-serial.wgsl.jinja)
45
+
46
+ ## Use with `@huggingface/kernels`
47
+
48
+ The loader automatically allocates outputs whose metadata it can derive from the manifest contract and this call.
49
+
50
+ The explicit `outputs` entries provide shape and logical dtype metadata for the results listed below:
51
+
52
+ - `y`
53
+
54
+ Each entry either requests an optional result or supplies metadata that cannot be inferred from the inputs.
55
+
56
+ The `version: 1` option selects the published kernel contract; it is independent of any operator opset, contrib `since_version`, or model version.
57
+
58
+ Replace each `*Data` placeholder with a typed array containing the corresponding input data.
59
+
60
+ ```js
61
+ import { getKernel } from "@huggingface/kernels";
62
+
63
+ const kernel = await getKernel("webgpu-kernels/ai.onnx.GlobalMaxPool", { version: 1 });
64
+ // Explicit destinations request optional results or supply metadata that cannot be inferred.
65
+ const { y } = await kernel({ x: { data: xData, shape: [1, 2, 3] } }, {
66
+ outputs: { y: { shape: [1, 2, 1], dtype: "float32" } },
67
+ });
68
+ ```
build/webgpu/bench.json ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "op": "ai.onnx.GlobalMaxPool",
3
+ "cases": [
4
+ {
5
+ "name": "nchw_1x2048x7x7",
6
+ "inputs": { "x": { "dtype": "float32", "shape": [1, 2048, 7, 7] } },
7
+ "outputs": { "y": { "dtype": "float32", "shape": [1, 2048, 1, 1] } }
8
+ },
9
+ {
10
+ "name": "nchw_16x512x64x64_wg_parallel",
11
+ "preset": "smoke",
12
+ "vars": { "batch": 16, "channels": 512, "spatial": 4096 },
13
+ "inputs": { "x": { "dtype": "float32", "shape": [16, 512, 64, 64], "dist": "normal", "seed": 202 } },
14
+ "outputs": { "y": { "dtype": "float32", "shape": [16, 512, 1, 1], "dist": "empty" } },
15
+ "bench": {
16
+ "primary": true,
17
+ "metrics": [{ "type": "bandwidth", "value": "args.batch * args.channels * args.spatial * 4" }]
18
+ }
19
+ },
20
+ {
21
+ "name": "nchw_f16_8x256x32x32_wg_parallel",
22
+ "preset": "smoke",
23
+ "vars": { "dtype": "float16", "batch": 8, "channels": 256, "spatial": 1024 },
24
+ "inputs": { "x": { "dtype": "float16", "shape": [8, 256, 32, 32], "dist": "normal", "seed": 207 } },
25
+ "outputs": { "y": { "dtype": "float16", "shape": [8, 256, 1, 1], "dist": "empty" } },
26
+ "bench": {
27
+ "metrics": [
28
+ { "type": "bandwidth", "value": "args.batch * args.channels * args.spatial * dtypeBytes(args.dtype)" }
29
+ ]
30
+ }
31
+ },
32
+ {
33
+ "name": "nchw_1x2048x7x7_smallspatial_serial",
34
+ "provenance": {
35
+ "notes": "2048 planes of 49 elements: below the plane-parallel floor, so the scalar serial kernel owns this shape."
36
+ },
37
+ "preset": "edge",
38
+ "vars": { "batch": 1, "channels": 2048, "spatial": 49 },
39
+ "inputs": { "x": { "dtype": "float32", "shape": [1, 2048, 7, 7], "dist": "normal", "seed": 501 } },
40
+ "outputs": { "y": { "dtype": "float32", "shape": [1, 2048, 1, 1], "dist": "empty" } },
41
+ "bench": {
42
+ "primary": true,
43
+ "metrics": [{ "type": "bandwidth", "value": "args.batch * args.channels * args.spatial * 4" }]
44
+ }
45
+ },
46
+ {
47
+ "name": "nchw_1x8x512x512_lowoccupancy_8planes",
48
+ "preset": "stress",
49
+ "provenance": {
50
+ "source": "authored for variant coverage",
51
+ "notes": "Low-occupancy eight-plane global reduction that verifies the cooperative plane route; legacy serial paths remain reserved for shapes outside its feature-tier domain."
52
+ },
53
+ "vars": { "batch": 1, "channels": 8, "spatial": 262144 },
54
+ "inputs": { "x": { "dtype": "float32", "shape": [1, 8, 512, 512], "dist": "normal", "seed": 502 } },
55
+ "outputs": { "y": { "dtype": "float32", "shape": [1, 8, 1, 1], "dist": "empty" } },
56
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "args.batch * args.channels * args.spatial * 4" }] }
57
+ },
58
+ {
59
+ "name": "nchw_1x1024x14x14_portable_gate_window",
60
+ "provenance": {
61
+ "notes": "Spatial 196 sits in the window the portable plane-parallel gate excludes (64 with subgroups, 1024 without)."
62
+ },
63
+ "preset": "smoke",
64
+ "vars": { "batch": 1, "channels": 1024, "spatial": 196 },
65
+ "inputs": { "x": { "dtype": "float32", "shape": [1, 1024, 14, 14], "dist": "normal", "seed": 503 } },
66
+ "outputs": { "y": { "dtype": "float32", "shape": [1, 1024, 1, 1], "dist": "empty" } },
67
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "args.batch * args.channels * args.spatial * 4" }] }
68
+ }
69
+ ],
70
+ "tunableSpace": { "WORKGROUP_SIZE": [64, 128, 256] }
71
+ }
build/webgpu/manifest.json ADDED
@@ -0,0 +1,112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "domain": "ai.onnx",
3
+ "name": "GlobalMaxPool",
4
+ "sinceVersion": 1,
5
+ "description": "Applies max pooling across all spatial dimensions of `X`, producing one value per channel. Equivalent to MaxPool with kernel size equal to the full spatial extent of the input; output shape is `(N x C x 1 x ... x 1)`.",
6
+ "inputs": [
7
+ {
8
+ "role": "X",
9
+ "dtype": "T",
10
+ "description": "Input tensor of shape `(N x C x D1 x ... x Dn)`, where `N` is the batch size and `C` is the number of channels."
11
+ }
12
+ ],
13
+ "outputs": [
14
+ {
15
+ "role": "Y",
16
+ "dtype": "T",
17
+ "rank": "ranks.X",
18
+ "description": "Output tensor of shape `(N x C x 1 x ... x 1)`; the maximum value over each spatial region per channel."
19
+ }
20
+ ],
21
+ "typeConstraints": { "T": ["float32", "float16"] },
22
+ "args": {
23
+ "x": { "kind": "tensor", "semantic": "X", "role": "input" },
24
+ "y": { "kind": "tensor", "semantic": "Y", "role": "output" }
25
+ },
26
+ "tunables": {
27
+ "WORKGROUP_SIZE": 256,
28
+ "PLANE_PARALLEL_MIN_SPATIAL": 64,
29
+ "PLANE_PARALLEL_AMORTIZED_SPATIAL": 768,
30
+ "PLANE_PARALLEL_STARVED_PLANES": 1024
31
+ },
32
+ "derive": {
33
+ "baseContract": "f16Ok(dtypes.T) and ranks.X >= 3 and ranks.Y == ranks.X and dim(shapes.Y, 0) == dim(shapes.X, 0) and dim(shapes.Y, 1) == dim(shapes.X, 1) and inner(shapes.Y, 1) == 1",
34
+ "planeParallelEligible": "inner(shapes.X, 1) >= tunables.PLANE_PARALLEL_MIN_SPATIAL and (inner(shapes.X, 1) >= tunables.PLANE_PARALLEL_AMORTIZED_SPATIAL or numel(shapes.Y) <= tunables.PLANE_PARALLEL_STARVED_PLANES) and numel(shapes.Y) <= device.limits.maxComputeWorkgroupsPerDimension"
35
+ },
36
+ "constants": { "scalar": "dtypes.T", "usesF16": "dtypes.T == \"f16\"" },
37
+ "bindingSets": {
38
+ "parallelPlane": [
39
+ {
40
+ "name": "x",
41
+ "arg": "x",
42
+ "semantic": "X",
43
+ "buffer": { "type": "read-only-storage" },
44
+ "elementType": "$planeInput"
45
+ },
46
+ { "name": "y", "arg": "y", "semantic": "Y", "buffer": { "type": "storage" }, "elementType": "$scalar" },
47
+ {
48
+ "name": "params",
49
+ "semantic": "kernel.params",
50
+ "buffer": { "type": "uniform" },
51
+ "struct": { "name": "Params", "fields": [{ "name": "spatial", "type": "u32", "value": "inner(shapes.X, 1)" }] }
52
+ }
53
+ ],
54
+ "serialPlane": [
55
+ { "name": "x", "arg": "x", "semantic": "X", "buffer": { "type": "read-only-storage" }, "elementType": "$scalar" },
56
+ { "name": "y", "arg": "y", "semantic": "Y", "buffer": { "type": "storage" }, "elementType": "$scalar" },
57
+ {
58
+ "name": "params",
59
+ "semantic": "kernel.params",
60
+ "buffer": { "type": "uniform" },
61
+ "struct": {
62
+ "name": "Params",
63
+ "fields": [
64
+ { "name": "spatial", "type": "u32", "value": "inner(shapes.X, 1)" },
65
+ { "name": "count", "type": "u32", "value": "numel(shapes.Y)" }
66
+ ]
67
+ }
68
+ }
69
+ ]
70
+ },
71
+ "variants": [
72
+ {
73
+ "id": "wg_plane_parallel",
74
+ "priority": 30,
75
+ "when": ["baseContract", "planeParallelEligible"],
76
+ "constants": { "planeInput": "\"vec4<\" ~ dtypes.T ~ \">\" if inner(shapes.X, 1) % 4 == 0 else dtypes.T" },
77
+ "passes": [
78
+ {
79
+ "id": "main",
80
+ "name": "GlobalMaxPool.WgPlaneParallel",
81
+ "source": {
82
+ "shader": "pool-global-reduction.wgsl.jinja",
83
+ "inputs": {
84
+ "op": "\"max\"",
85
+ "vec4": "inner(shapes.X, 1) % 4 == 0",
86
+ "workgroupSize": "tunables.WORKGROUP_SIZE",
87
+ "useSubgroups": "device.features.has(\"subgroups\")"
88
+ }
89
+ },
90
+ "bindings": "parallelPlane",
91
+ "dispatch": { "x": "numel(shapes.Y)" }
92
+ }
93
+ ]
94
+ },
95
+ {
96
+ "id": "nchw",
97
+ "when": ["baseContract", "not planeParallelEligible"],
98
+ "passes": [
99
+ {
100
+ "id": "main",
101
+ "name": "GlobalMaxPool.Nchw",
102
+ "source": {
103
+ "shader": "pool-global-serial.wgsl.jinja",
104
+ "inputs": { "op": "\"max\"", "outputsPerInvocation": 1 }
105
+ },
106
+ "bindings": "serialPlane",
107
+ "dispatch": { "threads": "numel(shapes.Y)", "workgroupSize": "tunables.WORKGROUP_SIZE" }
108
+ }
109
+ ]
110
+ }
111
+ ]
112
+ }
build/webgpu/metadata.json ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "ai.onnx.GlobalMaxPool",
3
+ "id": "_ai_onnx_globalmaxpool_webgpu_e1e2a9b",
4
+ "version": 1,
5
+ "license": "Apache-2.0",
6
+ "backend": { "type": "webgpu" },
7
+ "digest": {
8
+ "algorithm": "sha256",
9
+ "files": {
10
+ "bench.json": "Eet2dCeLHwGCclxUWpvzSTP1eo23iWxOYR0Hv0IevB8=",
11
+ "manifest.json": "Er9sIUKGJm7kZSVuRlRzkWCQjRnFZTlvPrketaONZXk=",
12
+ "pool-global-reduction.wgsl.jinja": "pY5tVjS1U8d/Hbabf04MwlObnCibUKA2Bjr0b4W3prk=",
13
+ "pool-global-serial.wgsl.jinja": "t2QTHN0c2huEUxRxnzd9dQZOcXvm89WwJiSzz9pOtzo=",
14
+ "test.json": "g0uQA0LM6LP5qlY6wRsAtFjX/IbNwTJMtiocyw157cI="
15
+ }
16
+ },
17
+ "provenance": { "kernel": { "sha": "2e7068faf55e7f43df740015f6d1ee49391a41c5", "dirty": false } },
18
+ "webgpu": { "manifestSpec": "1.0", "specialized": true, "opPath": "ops/ai.onnx.GlobalMaxPool" }
19
+ }
build/webgpu/pool-global-reduction.wgsl.jinja ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% if usesF16 %}
2
+ enable f16;
3
+ {% endif %}
4
+ {% if source.useSubgroups %}
5
+ enable subgroups;
6
+ {% endif %}
7
+ {{ env.wgsl.resourceDeclarations }}
8
+
9
+ // Workgroup-parallel global pooling: one workgroup reduces one contiguous
10
+ // (n, c) spatial plane (NC[D]HW layout makes the plane contiguous).
11
+ // Threads stride the plane (vec4 loads when the plane size is divisible by 4),
12
+ // then combine the per-thread partials. With subgroups: a subgroup collective
13
+ // + a shared-memory fold of the per-subgroup partials. Without subgroups, a
14
+ // full workgroup tree keeps workgroup-per-plane parallelism
15
+ // instead of falling to the one-thread-per-plane serial scalar kernel. The
16
+ // epilogue finalizes average / max / Lp. Sum reassociates;
17
+ // max is exact.
18
+ const WG: u32 = {{ source.workgroupSize }}u;
19
+ {% if source.useSubgroups %}
20
+ // WebGPU subgroups are at least 4 wide, so a workgroup holds at most WG / 4 subgroups.
21
+ const MAX_SUBGROUPS: u32 = WG / 4u;
22
+ var<workgroup> wg_partials: array<f32, MAX_SUBGROUPS>;
23
+ {% else %}
24
+ var<workgroup> wg_tree: array<f32, WG>;
25
+ {% endif %}
26
+
27
+ fn negative_infinity() -> f32 {
28
+ var bits = 0xff800000u;
29
+ return bitcast<f32>(bits);
30
+ }
31
+ {% if source.useSubgroups %}
32
+
33
+ fn quiet_nan() -> f32 {
34
+ var bits = 0x7fc00000u;
35
+ return bitcast<f32>(bits);
36
+ }
37
+
38
+ {% endif %}
39
+ fn is_nan_f32(value: f32) -> bool {
40
+ let bits = bitcast<u32>(value);
41
+ return (bits & 0x7f800000u) == 0x7f800000u && (bits & 0x007fffffu) != 0u;
42
+ }
43
+
44
+ fn max_propagate_nan(a: f32, b: f32) -> f32 {
45
+ if (is_nan_f32(a)) {
46
+ return a;
47
+ }
48
+ if (is_nan_f32(b)) {
49
+ return b;
50
+ }
51
+ return max(a, b);
52
+ }
53
+
54
+ @compute @workgroup_size(WG)
55
+ fn main(@builtin(workgroup_id) wid: vec3<u32>,
56
+ @builtin(local_invocation_id) lid: vec3<u32>
57
+ {%- if source.useSubgroups %},
58
+ @builtin(subgroup_size) sg_size: u32
59
+ {%- endif %}) {
60
+ let plane = wid.x;
61
+ let tid = lid.x;
62
+ {% if source.useSubgroups %}
63
+
64
+ // Seed cross-subgroup slots with the reduction identity so unwritten slots
65
+ // (when the workgroup has fewer than MAX_SUBGROUPS subgroups) are harmless.
66
+ if (tid < MAX_SUBGROUPS) {
67
+ wg_partials[tid] = negative_infinity();
68
+ }
69
+ workgroupBarrier();
70
+
71
+ {% endif %}
72
+ var partial = negative_infinity();
73
+ {% if source.vec4 %}
74
+ let spatialVec = params.spatial / 4u;
75
+ let base = plane * spatialVec;
76
+ for (var i = tid; i < spatialVec; i = i + WG) {
77
+ let v = vec4<f32>(x[base + i]);
78
+ partial = max_propagate_nan(partial, v.x);
79
+ partial = max_propagate_nan(partial, v.y);
80
+ partial = max_propagate_nan(partial, v.z);
81
+ partial = max_propagate_nan(partial, v.w);
82
+ }
83
+ {% else %}
84
+ let base = plane * params.spatial;
85
+ for (var i = tid; i < params.spatial; i = i + WG) {
86
+ let v = f32(x[base + i]);
87
+ partial = max_propagate_nan(partial, v);
88
+ }
89
+ {% endif %}
90
+
91
+ {% if source.useSubgroups %}
92
+ // subgroupMax does not propagate NaN; carry an explicit NaN flag alongside.
93
+ let lane_nan = is_nan_f32(partial);
94
+ let sg_nan = subgroupAny(lane_nan);
95
+ let sg_max = subgroupMax(select(partial, negative_infinity(), lane_nan));
96
+ if (subgroupElect()) {
97
+ wg_partials[tid / sg_size] = select(sg_max, quiet_nan(), sg_nan);
98
+ }
99
+ workgroupBarrier();
100
+ if (tid == 0u) {
101
+ let nsg = min((WG + sg_size - 1u) / sg_size, MAX_SUBGROUPS);
102
+ var total = negative_infinity();
103
+ for (var i = 0u; i < nsg; i = i + 1u) {
104
+ total = max_propagate_nan(total, wg_partials[i]);
105
+ }
106
+ y[plane] = {{ scalar }}(total);
107
+ }
108
+ {% else %}
109
+ // No-subgroups fallback: full workgroup-tree reduction of the per-thread partials.
110
+ wg_tree[tid] = partial;
111
+ workgroupBarrier();
112
+ for (var step = WG >> 1u; step > 0u; step = step >> 1u) {
113
+ if (tid < step) {
114
+ wg_tree[tid] = max_propagate_nan(wg_tree[tid], wg_tree[tid + step]);
115
+ }
116
+ workgroupBarrier();
117
+ }
118
+ if (tid == 0u) {
119
+ let total = wg_tree[0];
120
+ y[plane] = {{ scalar }}(total);
121
+ }
122
+ {% endif %}
123
+ }
build/webgpu/pool-global-serial.wgsl.jinja ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% if usesF16 %}
2
+ enable f16;
3
+ {% endif %}
4
+ {{ env.wgsl.resourceDeclarations }}
5
+
6
+ fn negative_infinity() -> f32 {
7
+ var bits = 0xff800000u;
8
+ return bitcast<f32>(bits);
9
+ }
10
+
11
+ fn is_nan_f32(value: f32) -> bool {
12
+ let bits = bitcast<u32>(value);
13
+ return (bits & 0x7f800000u) == 0x7f800000u && (bits & 0x007fffffu) != 0u;
14
+ }
15
+
16
+
17
+ fn combine_max(a: f32, b: f32) -> f32 {
18
+ if (is_nan_f32(a)) { return a; }
19
+ if (is_nan_f32(b)) { return b; }
20
+ return max(a, b);
21
+ }
22
+
23
+ fn pool_plane(out_index: u32) -> f32 {
24
+ let base = out_index * params.spatial;
25
+ var result = negative_infinity();
26
+ for (var offset = 0u; offset < params.spatial; offset++) {
27
+ let value = f32(x[base + offset]);
28
+ result = combine_max(result, value);
29
+ }
30
+ return result;
31
+ }
32
+
33
+ @compute @workgroup_size({{ tunables.WORKGROUP_SIZE }})
34
+ fn main(@builtin(global_invocation_id) gid: vec3<u32>, @builtin(num_workgroups) nwg: vec3<u32>) {
35
+ // Each invocation produces one or four channel planes. gid.y carries folded workgroups beyond
36
+ // the device's per-dimension dispatch limit.
37
+ let first = (gid.x + gid.y * nwg.x * {{ tunables.WORKGROUP_SIZE }}u) * {{ source.outputsPerInvocation }}u;
38
+ {% for lane in range(source.outputsPerInvocation) %}
39
+ if (first + {{ lane }}u < params.count) {
40
+ y[first + {{ lane }}u] = {{ scalar }}(pool_plane(first + {{ lane }}u));
41
+ }
42
+ {% endfor %}
43
+ }
build/webgpu/test.json ADDED
@@ -0,0 +1,447 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "op": "ai.onnx.GlobalMaxPool",
3
+ "cases": [
4
+ {
5
+ "name": "dispatch_cliff_ncl1d",
6
+ "inputs": {
7
+ "x": { "dtype": "float32", "shape": [65540, 256, 1], "data": { "kind": "linspace", "start": -1.0, "end": 1.0 } }
8
+ },
9
+ "outputs": { "y": { "dtype": "float32", "shape": [65540, 256, 1], "tolerance": 0 } }
10
+ },
11
+ {
12
+ "name": "nchw",
13
+ "inputs": {
14
+ "x": {
15
+ "dtype": "float32",
16
+ "shape": [2, 3, 2, 4],
17
+ "data": { "kind": "fillFloat32", "sinStep": 0.13, "cosStep": 0.17 }
18
+ }
19
+ },
20
+ "outputs": { "y": { "dtype": "float32", "shape": [2, 3, 1, 1], "tolerance": 0.000001 } }
21
+ },
22
+ {
23
+ "name": "nchw_nan_propagates",
24
+ "inputs": {
25
+ "x": {
26
+ "dtype": "float32",
27
+ "shape": [1, 4, 2, 2],
28
+ "data": {
29
+ "kind": "values",
30
+ "values": [1.0, "NaN", 3.0, 4.0, -5.0, -6.0, -7.0, -8.0, 9.0, 10.0, "NaN", 12.0, 0.0, -1.0, -2.0, -3.0]
31
+ }
32
+ }
33
+ },
34
+ "outputs": { "y": { "dtype": "float32", "shape": [1, 4, 1, 1], "tolerance": 0, "allowNaN": true } }
35
+ },
36
+ {
37
+ "name": "nchw_all_negative_infinity_returns_negative_infinity",
38
+ "inputs": {
39
+ "x": {
40
+ "dtype": "float32",
41
+ "shape": [1, 2, 2, 2],
42
+ "data": {
43
+ "kind": "values",
44
+ "values": ["-Infinity", "-Infinity", "-Infinity", "-Infinity", "-Infinity", "-Infinity", "-Infinity", "-Infinity"]
45
+ }
46
+ }
47
+ },
48
+ "outputs": { "y": { "dtype": "float32", "shape": [1, 2, 1, 1], "tolerance": 0 } }
49
+ },
50
+ {
51
+ "name": "ncl_rank3",
52
+ "inputs": {
53
+ "x": {
54
+ "dtype": "float32",
55
+ "shape": [2, 3, 4],
56
+ "data": {
57
+ "kind": "values",
58
+ "values": [-9.0, -3.0, -7.0, -1.0, 4.0, 4.0, 2.0, -5.0, -100.0, -50.0, -25.0, -75.0, 1.0, 9.0, 3.0, 7.0, -2.0, 6.0, 6.0, 5.0, 0.25, -0.5, 0.75, 0.5]
59
+ }
60
+ }
61
+ },
62
+ "outputs": { "y": { "dtype": "float32", "shape": [2, 3, 1], "tolerance": 0.000001 } }
63
+ },
64
+ {
65
+ "name": "f32_nchw2d_smallspatial_1x16x7x7",
66
+ "provenance": {
67
+ "notes": "Compact f32 sibling for the 7x7 small-spatial vec4-output benchmark; keeps channels small while exercising the same low-spatial output path."
68
+ },
69
+ "inputs": {
70
+ "x": {
71
+ "dtype": "float32",
72
+ "shape": [1, 16, 7, 7],
73
+ "data": { "kind": "fillFloat32", "sinStep": 0.019, "cosStep": 0.029, "scale": 0.4 }
74
+ }
75
+ },
76
+ "outputs": { "y": { "dtype": "float32", "shape": [1, 16, 1, 1], "tolerance": 0.000001 } }
77
+ },
78
+ {
79
+ "name": "f32_positive_subnormal_rank4_vec4out_max_zero_gpu_gap",
80
+ "provenance": {
81
+ "source": "onnxruntime/test/providers/cpu/nn/pool_op_test.cc",
82
+ "test": "PoolTest.GlobalMaxPool",
83
+ "notes": "Exercises the rank-4 vec4-output kernel with subnormal maxima that should beat zero."
84
+ },
85
+ "inputs": {
86
+ "x": {
87
+ "dtype": "float32",
88
+ "shape": [1, 4, 1, 4],
89
+ "data": {
90
+ "kind": "values",
91
+ "values": [0.0, 1e-40, 0.0, 0.0, 0.0, 0.0, 1e-38, 0.0, -1e-40, -2e-40, 0.0, -3e-40, 0.0, 5e-39, 2e-39, 0.0]
92
+ }
93
+ }
94
+ },
95
+ "outputs": { "y": { "dtype": "float32", "shape": [1, 4, 1, 1], "tolerance": 2e-45 } },
96
+ "skipGpu": {
97
+ "category": "permanent",
98
+ "reason": "Portable WGSL floating-point semantics do not guarantee preservation of the subnormal values required by this fixture. Backend evidence: Metal flushes f32 subnormals to zero (FTZ); subnormal-magnitude values cannot survive the GPU arithmetic path."
99
+ }
100
+ },
101
+ {
102
+ "name": "f32_positive_subnormal_rank4_vec4out_tail_max_zero_gpu_gap",
103
+ "provenance": {
104
+ "source": "onnxruntime/test/providers/cpu/nn/pool_op_test.cc",
105
+ "test": "PoolTest.GlobalMaxPool",
106
+ "notes": "Covers the vec4-output tail path when output channels are not a multiple of four."
107
+ },
108
+ "inputs": {
109
+ "x": {
110
+ "dtype": "float32",
111
+ "shape": [1, 5, 1, 4],
112
+ "data": {
113
+ "kind": "values",
114
+ "values": [0.0, 1e-40, 0.0, 0.0, 0.0, 0.0, 1e-38, 0.0, -1e-40, -2e-40, 0.0, -3e-40, 0.0, 5e-39, 2e-39, 0.0, 0.0, 7e-40, 0.0, 2e-40]
115
+ }
116
+ }
117
+ },
118
+ "outputs": { "y": { "dtype": "float32", "shape": [1, 5, 1, 1], "tolerance": 2e-45 } },
119
+ "skipGpu": {
120
+ "category": "permanent",
121
+ "reason": "Portable WGSL floating-point semantics do not guarantee preservation of the subnormal values required by this fixture. Backend evidence: Metal flushes f32 subnormals to zero (FTZ); subnormal-magnitude values cannot survive the GPU arithmetic path."
122
+ }
123
+ },
124
+ {
125
+ "name": "ort_fp16_rank4_tied_max",
126
+ "provenance": {
127
+ "source": "onnxruntime/test/providers/cpu/nn/pool_op_test.cc",
128
+ "test": "PoolTest.GlobalMaxPool",
129
+ "notes": "Compact fp16 projection of ORT's typed GlobalMaxPool coverage."
130
+ },
131
+ "inputs": {
132
+ "x": {
133
+ "dtype": "float16",
134
+ "shape": [1, 2, 2, 3],
135
+ "data": { "kind": "values", "values": [-9.0, -3.0, -7.0, -1.0, -1.0, -5.0, 0.25, 4.0, 4.0, -5.0, 3.5, 3.5] }
136
+ }
137
+ },
138
+ "outputs": {
139
+ "y": {
140
+ "dtype": "float16",
141
+ "shape": [1, 2, 1, 1],
142
+ "data": { "kind": "values", "values": [-1.0, 4.0] },
143
+ "tolerance": 0.001
144
+ }
145
+ }
146
+ },
147
+ {
148
+ "name": "fp16_wg_parallel_8x8_vec4_path",
149
+ "inputs": {
150
+ "x": {
151
+ "dtype": "float16",
152
+ "shape": [1, 2, 8, 8],
153
+ "data": { "kind": "fillFloat32", "sinStep": 0.09, "cosStep": 0.13, "scale": 0.2 }
154
+ }
155
+ },
156
+ "outputs": { "y": { "dtype": "float16", "shape": [1, 2, 1, 1], "tolerance": 0.001 } }
157
+ },
158
+ {
159
+ "name": "ncl_all_negative_infinity_returns_negative_infinity",
160
+ "inputs": {
161
+ "x": {
162
+ "dtype": "float32",
163
+ "shape": [1, 2, 3],
164
+ "data": {
165
+ "kind": "values",
166
+ "values": ["-Infinity", "-Infinity", "-Infinity", "-Infinity", "-Infinity", "-Infinity"]
167
+ }
168
+ }
169
+ },
170
+ "outputs": { "y": { "dtype": "float32", "shape": [1, 2, 1], "tolerance": 0 } }
171
+ },
172
+ {
173
+ "name": "ncl_nan_propagates",
174
+ "inputs": {
175
+ "x": {
176
+ "dtype": "float32",
177
+ "shape": [1, 2, 4],
178
+ "data": { "kind": "values", "values": [1.0, "NaN", 3.0, 4.0, -5.0, -6.0, -7.0, -8.0] }
179
+ }
180
+ },
181
+ "outputs": { "y": { "dtype": "float32", "shape": [1, 2, 1], "tolerance": 0, "allowNaN": true } }
182
+ },
183
+ {
184
+ "name": "ncdhw_rank5",
185
+ "inputs": {
186
+ "x": {
187
+ "dtype": "float32",
188
+ "shape": [1, 2, 2, 2, 2],
189
+ "data": {
190
+ "kind": "values",
191
+ "values": [-9.0, -3.0, -7.0, -1.0, -5.0, -8.0, -2.0, -4.0, 10.0, 20.0, 15.0, 5.0, 80.0, 60.0, 70.0, 40.0]
192
+ }
193
+ }
194
+ },
195
+ "outputs": { "y": { "dtype": "float32", "shape": [1, 2, 1, 1, 1], "tolerance": 0.000001 } }
196
+ },
197
+ {
198
+ "name": "zero_batch_dim_rank4",
199
+ "inputs": { "x": { "dtype": "float32", "shape": [0, 2, 3, 4], "data": { "kind": "values", "values": [] } } },
200
+ "outputs": { "y": { "dtype": "float32", "shape": [0, 2, 1, 1], "tolerance": 0 } }
201
+ },
202
+ {
203
+ "name": "ort_rank4_1x3x8x8_values",
204
+ "provenance": { "source": "onnxruntime/test/providers/cpu/nn/pool_op_test.cc", "test": "PoolTest.GlobalMaxPool" },
205
+ "inputs": {
206
+ "x": {
207
+ "dtype": "float32",
208
+ "shape": [1, 3, 8, 8],
209
+ "data": {
210
+ "kind": "values",
211
+ "values": [0.19151945412158966, 0.6221087574958801, 0.43772774934768677, 0.7853586077690125, 0.7799758315086365, 0.27259260416030884, 0.2764642536640167, 0.801872193813324, 0.9581393599510193, 0.8759326338768005, 0.35781726241111755, 0.5009950995445251, 0.683462917804718, 0.7127020359039307, 0.37025076150894165, 0.5611962080001831, 0.5030831694602966, 0.013768449425697327, 0.772826611995697, 0.8826411962509155, 0.36488598585128784, 0.6153962016105652, 0.07538124173879623, 0.3688240051269531, 0.9331400990486145, 0.6513781547546387, 0.39720258116722107, 0.7887301445007324, 0.3168361186981201, 0.5680986642837524, 0.8691273927688599, 0.4361734092235565, 0.802147626876831, 0.14376682043075562, 0.7042609453201294, 0.7045813202857971, 0.2187921106815338, 0.9248676300048828, 0.44214075803756714, 0.9093159437179565, 0.05980922281742096, 0.18428708612918854, 0.047355279326438904, 0.6748809218406677, 0.5946247577667236, 0.5333101749420166, 0.043324064463377, 0.5614330768585205, 0.32966843247413635, 0.5029668211936951, 0.11189431697130203, 0.6071937084197998, 0.5659446716308594, 0.006764062214642763, 0.617441713809967, 0.912122905254364, 0.7905241250991821, 0.9920814633369446, 0.9588017463684082, 0.7919641137123108, 0.2852509617805481, 0.6249167323112488, 0.47809380292892456, 0.19567517936229706, 0.382317453622818, 0.053873684257268906, 0.45164841413497925, 0.9820047616958618, 0.12394270300865173, 0.1193808987736702, 0.7385230660438538, 0.587303638458252, 0.47163254022598267, 0.10712681710720062, 0.22921857237815857, 0.8999651670455933, 0.41675353050231934, 0.5358516573905945, 0.0062085166573524475, 0.3006417155265808, 0.43689316511154175, 0.6121490001678467, 0.9181980490684509, 0.625736653804779, 0.7059975862503052, 0.14983370900154114, 0.7460634112358093, 0.8310070037841797, 0.6337257623672485, 0.4383098781108856, 0.15257278084754944, 0.5684096217155457, 0.5282242894172668, 0.9514287710189819, 0.48035916686058044, 0.5025595426559448, 0.5368781685829163, 0.8192020654678345, 0.05711563676595688, 0.6694217324256897, 0.7671166062355042, 0.7081153392791748, 0.7968671917915344, 0.5577608346939087, 0.9658365249633789, 0.14715689420700073, 0.02964700013399124, 0.5938934683799744, 0.11406569927930832, 0.9508098363876343, 0.32570740580558777, 0.19361868500709534, 0.4578116536140442, 0.9204025864601135, 0.8790691494941711, 0.252615749835968, 0.34800878167152405, 0.18258872628211975, 0.9017960429191589, 0.7065281867980957, 0.7266584634780884, 0.900087833404541, 0.7791637778282166, 0.5991547703742981, 0.29112523794174194, 0.1513952612876892, 0.33517464995384216, 0.6575517654418945, 0.07334254682064056, 0.055006396025419235, 0.32319480180740356, 0.5904818177223206, 0.8538985848426819, 0.2870624363422394, 0.17306722700595856, 0.13402120769023895, 0.9946538209915161, 0.1794978678226471, 0.3175468146800995, 0.568291425704956, 0.009348574094474316, 0.9006485939025879, 0.9772414565086365, 0.5568946599960327, 0.08477384597063065, 0.3330024778842926, 0.7284286618232727, 0.14243537187576294, 0.5524689555168152, 0.2730432450771332, 0.9744951128959656, 0.6677868962287903, 0.2556532919406891, 0.1083114966750145, 0.7761807441711426, 0.7824779748916626, 0.7616038918495178, 0.9144031405448914, 0.6586228013038635, 0.568367600440979, 0.20175568759441376, 0.6982963681221008, 0.952195405960083, 0.8899632692337036, 0.9935673475265503, 0.8187035322189331, 0.5451221466064453, 0.45125406980514526, 0.8905571699142456, 0.9732648134231567, 0.5934113264083862, 0.36607450246810913, 0.3230946958065033, 0.8714232444763184, 0.2156340628862381, 0.7349451780319214, 0.36561909317970276, 0.8016026020050049, 0.7827355861663818, 0.7013553977012634, 0.6227765679359436, 0.4936826527118683, 0.8405377268791199, 0.7120969891548157, 0.4439089894294739, 0.031034860759973526, 0.36323976516723633, 0.7307217717170715, 0.475566565990448, 0.3444169759750366, 0.6408804059028625, 0.12620532512664795]
212
+ }
213
+ }
214
+ },
215
+ "outputs": { "y": { "dtype": "float32", "shape": [1, 3, 1, 1], "tolerance": 0.000001 } }
216
+ },
217
+ {
218
+ "name": "ort_rank4_1x3x8x8_generated",
219
+ "provenance": {
220
+ "source": "onnxruntime/test/providers/cpu/nn/pool_op_test.cc",
221
+ "test": "PoolTest.GlobalMaxPool",
222
+ "notes": "Uses the ORT rank-4 shape; fixture values are generated deterministically."
223
+ },
224
+ "inputs": {
225
+ "x": {
226
+ "dtype": "float32",
227
+ "shape": [1, 3, 8, 8],
228
+ "data": { "kind": "fillFloat32", "sinStep": 0.037, "cosStep": 0.011, "scale": 1.5 }
229
+ }
230
+ },
231
+ "outputs": { "y": { "dtype": "float32", "shape": [1, 3, 1, 1], "tolerance": 0.000001 } }
232
+ },
233
+ {
234
+ "name": "ort_rank5_1x3x8x4x2_generated",
235
+ "provenance": {
236
+ "source": "onnxruntime/test/providers/cpu/nn/pool_op_test.cc",
237
+ "test": "PoolTest.GlobalMaxPool3D",
238
+ "notes": "Uses the ORT rank-5 shape; fixture values are generated deterministically."
239
+ },
240
+ "inputs": {
241
+ "x": {
242
+ "dtype": "float32",
243
+ "shape": [1, 3, 8, 4, 2],
244
+ "data": { "kind": "fillFloat32", "sinStep": 0.029, "cosStep": 0.017, "scale": 1.25 }
245
+ }
246
+ },
247
+ "outputs": { "y": { "dtype": "float32", "shape": [1, 3, 1, 1, 1], "tolerance": 0.000001 } }
248
+ },
249
+ {
250
+ "name": "onnx_backend_precomputed_3x3",
251
+ "provenance": { "source": "cmake/external/onnx/onnx/backend/test/data/node/test_globalmaxpool_precomputed" },
252
+ "inputs": {
253
+ "x": {
254
+ "dtype": "float32",
255
+ "shape": [1, 1, 3, 3],
256
+ "data": { "kind": "values", "values": [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0] }
257
+ }
258
+ },
259
+ "outputs": { "y": { "dtype": "float32", "shape": [1, 1, 1, 1], "tolerance": 0.000001 } }
260
+ },
261
+ {
262
+ "name": "onnx_backend_globalmaxpool",
263
+ "inputs": {
264
+ "x": {
265
+ "dtype": "float32",
266
+ "shape": [1, 3, 5, 5],
267
+ "data": {
268
+ "kind": "values",
269
+ "values": [1.764052391052246, 0.40015721321105957, 0.978738009929657, 2.2408931255340576, 1.8675580024719238, -0.9772778749465942, 0.9500884413719177, -0.15135720372200012, -0.10321885347366333, 0.4105985164642334, 0.14404356479644775, 1.4542734622955322, 0.7610377073287964, 0.12167501449584961, 0.44386324286460876, 0.3336743414402008, 1.4940791130065918, -0.2051582634449005, 0.3130677044391632, -0.8540957570075989, -2.5529897212982178, 0.653618574142456, 0.8644362092018127, -0.7421650290489197, 2.269754648208618, -1.4543657302856445, 0.04575851559638977, -0.18718385696411133, 1.5327792167663574, 1.4693588018417358, 0.154947429895401, 0.37816253304481506, -0.8877857327461243, -1.980796456336975, -0.34791216254234314, 0.15634897351264954, 1.2302906513214111, 1.202379822731018, -0.38732680678367615, -0.302302747964859, -1.0485529899597168, -1.420017957687378, -1.7062702178955078, 1.950775384902954, -0.5096521973609924, -0.4380742907524109, -1.2527953386306763, 0.7774903774261475, -1.6138978004455566, -0.21274028718471527, -0.8954665660858154, 0.38690251111984253, -0.5108051300048828, -1.18063223361969, -0.02818222902715206, 0.4283318817615509, 0.06651721894741058, 0.30247190594673157, -0.6343221068382263, -0.3627411723136902, -0.6724604368209839, -0.35955315828323364, -0.8131462931632996, -1.7262825965881348, 0.17742614448070526, -0.4017809331417084, -1.630198359489441, 0.46278226375579834, -0.9072983860969543, 0.05194539576768875, 0.7290905714035034, 0.12898291647434235, 1.1394007205963135, -1.234825849533081, 0.4023416340351105]
270
+ }
271
+ }
272
+ },
273
+ "outputs": { "y": { "dtype": "float32", "shape": [1, 3, 1, 1] } },
274
+ "provenance": { "source": "cmake/external/onnx/onnx/backend/test/data/node/test_globalmaxpool" }
275
+ },
276
+ {
277
+ "name": "onnx_backend_globalmaxpool_precomputed",
278
+ "provenance": { "source": "cmake/external/onnx/onnx/backend/test/data/node/test_globalmaxpool_precomputed" },
279
+ "inputs": {
280
+ "x": {
281
+ "dtype": "float32",
282
+ "shape": [1, 1, 3, 3],
283
+ "data": { "kind": "values", "values": [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0] }
284
+ }
285
+ },
286
+ "outputs": { "y": { "dtype": "float32", "shape": [1, 1, 1, 1], "tolerance": 0.00001 } }
287
+ },
288
+ {
289
+ "name": "wg_parallel_9x9_scalar_path",
290
+ "inputs": {
291
+ "x": {
292
+ "dtype": "float32",
293
+ "shape": [2, 3, 9, 9],
294
+ "data": { "kind": "fillFloat32", "sinStep": 0.13, "cosStep": 0.17 }
295
+ }
296
+ },
297
+ "outputs": { "y": { "dtype": "float32", "shape": [2, 3, 1, 1], "tolerance": 0 } }
298
+ },
299
+ {
300
+ "name": "wg_parallel_16x16_vec4_path",
301
+ "inputs": {
302
+ "x": {
303
+ "dtype": "float32",
304
+ "shape": [1, 2, 16, 16],
305
+ "data": { "kind": "fillFloat32", "sinStep": 0.31, "cosStep": 0.07 }
306
+ }
307
+ },
308
+ "outputs": { "y": { "dtype": "float32", "shape": [1, 2, 1, 1], "tolerance": 0 } }
309
+ },
310
+ {
311
+ "name": "wg_parallel_large_spatial_1024_vec4",
312
+ "provenance": {
313
+ "notes": "Spatial extent 1024 clears the no-subgroups planeParallelEligible threshold (inner >= 1024 without subgroups, vs >= 64 with), so wg_plane_parallel runs on the no-subgroups tier where every smaller-spatial case falls back to nchw. 1024 % 4 == 0 selects the vec4 plane-reduction sub-path."
314
+ },
315
+ "inputs": {
316
+ "x": {
317
+ "dtype": "float32",
318
+ "shape": [1, 2, 1024],
319
+ "data": { "kind": "fillFloat32", "sinStep": 0.013, "cosStep": 0.019 }
320
+ }
321
+ },
322
+ "outputs": { "y": { "dtype": "float32", "shape": [1, 2, 1], "tolerance": 0 } }
323
+ },
324
+ {
325
+ "name": "wg_parallel_large_spatial_1030_scalar",
326
+ "provenance": {
327
+ "notes": "Spatial 1030 also clears the no-subgroups threshold but 1030 % 4 != 0 selects the scalar plane-reduction sub-path of wg_plane_parallel (planeInput = scalar), covering the non-vec4 reduction on the no-subgroups tier."
328
+ },
329
+ "inputs": {
330
+ "x": {
331
+ "dtype": "float32",
332
+ "shape": [1, 2, 1030],
333
+ "data": { "kind": "fillFloat32", "sinStep": 0.007, "cosStep": 0.023 }
334
+ }
335
+ },
336
+ "outputs": { "y": { "dtype": "float32", "shape": [1, 2, 1], "tolerance": 0 } }
337
+ },
338
+ {
339
+ "name": "wg_parallel_nan_propagates_8x8",
340
+ "inputs": {
341
+ "x": {
342
+ "dtype": "float32",
343
+ "shape": [1, 1, 8, 8],
344
+ "data": {
345
+ "kind": "values",
346
+ "values": [-0.3, -0.29, -0.28, -0.27, -0.26, -0.25, -0.24, -0.23, -0.22, -0.21, -0.2, -0.19, -0.18, "NaN", -0.16, -0.15, -0.14, -0.13, -0.12, -0.11, -0.1, -0.09, -0.08, -0.07, -0.06, -0.05, -0.04, -0.03, -0.02, -0.01, 0.0, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.1, 0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.2, 0.21, 0.22, 0.23, 0.24, 0.25, 0.26, "NaN", 0.28, 0.29, 0.3, 0.31, 0.32, 0.33]
347
+ }
348
+ }
349
+ },
350
+ "outputs": { "y": { "dtype": "float32", "shape": [1, 1, 1, 1], "tolerance": 0, "allowNaN": true } }
351
+ },
352
+ {
353
+ "name": "wg_parallel_all_negative_infinity_8x8",
354
+ "inputs": { "x": { "dtype": "float32", "shape": [1, 2, 8, 8], "data": { "kind": "negativeInfinity" } } },
355
+ "outputs": { "y": { "dtype": "float32", "shape": [1, 2, 1, 1], "tolerance": 0 } }
356
+ },
357
+ {
358
+ "name": "rank4_channels_not_div4_vec4out_tail_unwritten",
359
+ "inputs": {
360
+ "x": {
361
+ "dtype": "float32",
362
+ "shape": [1, 5, 3, 3],
363
+ "data": {
364
+ "kind": "values",
365
+ "values": [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, -9.0, -8.0, -7.0, -6.0, -5.0, -4.0, -3.0, -2.0, -1.0, 10.0, 9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 5.0, 4.0, 3.0, 2.0, 1.0, 0.0, -1.0, -2.0, -3.0]
366
+ }
367
+ }
368
+ },
369
+ "outputs": {
370
+ "y": {
371
+ "dtype": "float32",
372
+ "shape": [1, 5, 1, 1],
373
+ "data": { "kind": "values", "values": [9.0, -1.0, 10.0, 1.0, 5.0] },
374
+ "tolerance": 0
375
+ }
376
+ }
377
+ },
378
+ {
379
+ "name": "rank4_channels_3_not_div4_wg_parallel_tail",
380
+ "inputs": {
381
+ "x": {
382
+ "dtype": "float32",
383
+ "shape": [1, 3, 8, 8],
384
+ "data": { "kind": "fillFloat32", "sinStep": 0.11, "cosStep": 0.17, "scale": 1.0 }
385
+ }
386
+ },
387
+ "outputs": { "y": { "dtype": "float32", "shape": [1, 3, 1, 1], "tolerance": 0 } }
388
+ },
389
+ {
390
+ "name": "rank4_all_positive_infinity",
391
+ "inputs": {
392
+ "x": {
393
+ "dtype": "float32",
394
+ "shape": [1, 2, 2, 2],
395
+ "data": {
396
+ "kind": "values",
397
+ "values": ["Infinity", "Infinity", "Infinity", "Infinity", "Infinity", "Infinity", "Infinity", "Infinity"]
398
+ }
399
+ }
400
+ },
401
+ "outputs": { "y": { "dtype": "float32", "shape": [1, 2, 1, 1], "tolerance": 0 } }
402
+ },
403
+ {
404
+ "name": "rank4_channels_not_div4_vec4out_6channels",
405
+ "inputs": {
406
+ "x": {
407
+ "dtype": "float32",
408
+ "shape": [1, 6, 2, 2],
409
+ "data": {
410
+ "kind": "values",
411
+ "values": [1.0, 2.0, 3.0, 4.0, -1.0, -2.0, -3.0, -4.0, 5.0, 6.0, 7.0, 8.0, -5.0, -6.0, -7.0, -8.0, 0.0, 0.5, 0.25, 0.75, -9.0, 9.0, -9.0, 9.0]
412
+ }
413
+ }
414
+ },
415
+ "outputs": {
416
+ "y": {
417
+ "dtype": "float32",
418
+ "shape": [1, 6, 1, 1],
419
+ "data": { "kind": "values", "values": [4.0, -1.0, 8.0, -5.0, 0.75, 9.0] },
420
+ "tolerance": 0
421
+ }
422
+ }
423
+ },
424
+ {
425
+ "name": "rank6_four_spatial_dims",
426
+ "inputs": {
427
+ "x": {
428
+ "dtype": "float32",
429
+ "shape": [1, 2, 2, 2, 2, 2],
430
+ "data": { "kind": "fillFloat32", "sinStep": 0.17, "cosStep": 0.29, "scale": 2.0 }
431
+ }
432
+ },
433
+ "outputs": { "y": { "dtype": "float32", "shape": [1, 2, 1, 1, 1, 1], "tolerance": 0 } }
434
+ },
435
+ {
436
+ "name": "rank8_six_spatial_dims",
437
+ "inputs": {
438
+ "x": {
439
+ "dtype": "float32",
440
+ "shape": [1, 2, 2, 2, 2, 2, 2, 2],
441
+ "data": { "kind": "fillFloat32", "sinStep": 0.13, "cosStep": 0.27 }
442
+ }
443
+ },
444
+ "outputs": { "y": { "dtype": "float32", "shape": [1, 2, 1, 1, 1, 1, 1, 1], "tolerance": 0 } }
445
+ }
446
+ ]
447
+ }