sync 6fdf6301e2bb
Browse files- README.md +11 -2
- build/webgpu/average-pool2d-nchw-horizontal-reuse.wgsl.jinja +7 -2
- build/webgpu/average-pool2d-nchw-w3s1-reuse.wgsl.jinja +9 -4
- build/webgpu/bench.json +86 -0
- build/webgpu/manifest.json +176 -64
- build/webgpu/metadata.json +15 -11
- build/webgpu/pool-global-reduction.wgsl.jinja +31 -30
- build/webgpu/pool-window-nd.wgsl.jinja +7 -2
- build/webgpu/pool-window-reduction.wgsl.jinja +198 -0
- build/webgpu/pool-window-unroll.wgsl.jinja +11 -9
- build/webgpu/test.json +286 -4
README.md
CHANGED
|
@@ -48,23 +48,32 @@ Attributes and default values (overridable per request):
|
|
| 48 |
| --- | --- |
|
| 49 |
| `T` | `float32`, `float16` |
|
| 50 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 51 |
## Files
|
| 52 |
|
| 53 |
- [`metadata.json`](build/webgpu/metadata.json) — kernel metadata (id, digests, per-variant templates, provenance)
|
| 54 |
- [`manifest.json`](build/webgpu/manifest.json) — the op contract (source of truth)
|
| 55 |
- [`test.json`](build/webgpu/test.json) — correctness cases
|
| 56 |
-
- [`bench.json`](build/webgpu/bench.json) — benchmark
|
| 57 |
- [`average-pool2d-nchw-horizontal-reuse.wgsl.jinja`](build/webgpu/average-pool2d-nchw-horizontal-reuse.wgsl.jinja)
|
| 58 |
- [`average-pool2d-nchw-w3s1-reuse.wgsl.jinja`](build/webgpu/average-pool2d-nchw-w3s1-reuse.wgsl.jinja)
|
| 59 |
- [`pool-global-reduction.wgsl.jinja`](build/webgpu/pool-global-reduction.wgsl.jinja)
|
| 60 |
- [`pool-window-nd.wgsl.jinja`](build/webgpu/pool-window-nd.wgsl.jinja)
|
|
|
|
| 61 |
- [`pool-window-unroll.wgsl.jinja`](build/webgpu/pool-window-unroll.wgsl.jinja)
|
| 62 |
- [`pool2d-nchw-separable.wgsl.jinja`](build/webgpu/pool2d-nchw-separable.wgsl.jinja)
|
| 63 |
|
| 64 |
## Use with `@huggingface/kernels`
|
| 65 |
|
| 66 |
```sh
|
| 67 |
-
npm install --save-exact @huggingface/kernels@0.0.1-preview.
|
| 68 |
```
|
| 69 |
|
| 70 |
Required output shapes and logical data types are inferred from the supplied inputs and attributes; result tensors are allocated automatically.
|
|
|
|
| 48 |
| --- | --- |
|
| 49 |
| `T` | `float32`, `float16` |
|
| 50 |
|
| 51 |
+
## Implementation variants
|
| 52 |
+
|
| 53 |
+
One implementation is selected per call from the device capabilities, the request shapes and the dtypes; these notes say what each one covers.
|
| 54 |
+
|
| 55 |
+
- `window_parallel_ncl1d` — Workgroup-cooperative average pooling over a 1-D window: one workgroup reduces a single output element's kernel window, its invocations striding the flattened taps. Chosen when the serial one-invocation-per-output route cannot fill the device and the window is long. Padded taps leave the divisor unless `count_include_pad` is set.
|
| 56 |
+
- `window_parallel_nchw2d` — Workgroup-cooperative average pooling over a 2-D window: one workgroup reduces a single output element's kernel window, its invocations striding the flattened taps. Chosen when the serial one-invocation-per-output route cannot fill the device and the window is long. Padded taps leave the divisor unless `count_include_pad` is set.
|
| 57 |
+
- `window_parallel_ncdhw3d` — Workgroup-cooperative average pooling over a 3-D window: one workgroup reduces a single output element's kernel window, its invocations striding the flattened taps. Chosen when the serial one-invocation-per-output route cannot fill the device and the window is long. Padded taps leave the divisor unless `count_include_pad` is set.
|
| 58 |
+
|
| 59 |
## Files
|
| 60 |
|
| 61 |
- [`metadata.json`](build/webgpu/metadata.json) — kernel metadata (id, digests, per-variant templates, provenance)
|
| 62 |
- [`manifest.json`](build/webgpu/manifest.json) — the op contract (source of truth)
|
| 63 |
- [`test.json`](build/webgpu/test.json) — correctness cases
|
| 64 |
+
- [`bench.json`](build/webgpu/bench.json) — benchmark cases
|
| 65 |
- [`average-pool2d-nchw-horizontal-reuse.wgsl.jinja`](build/webgpu/average-pool2d-nchw-horizontal-reuse.wgsl.jinja)
|
| 66 |
- [`average-pool2d-nchw-w3s1-reuse.wgsl.jinja`](build/webgpu/average-pool2d-nchw-w3s1-reuse.wgsl.jinja)
|
| 67 |
- [`pool-global-reduction.wgsl.jinja`](build/webgpu/pool-global-reduction.wgsl.jinja)
|
| 68 |
- [`pool-window-nd.wgsl.jinja`](build/webgpu/pool-window-nd.wgsl.jinja)
|
| 69 |
+
- [`pool-window-reduction.wgsl.jinja`](build/webgpu/pool-window-reduction.wgsl.jinja)
|
| 70 |
- [`pool-window-unroll.wgsl.jinja`](build/webgpu/pool-window-unroll.wgsl.jinja)
|
| 71 |
- [`pool2d-nchw-separable.wgsl.jinja`](build/webgpu/pool2d-nchw-separable.wgsl.jinja)
|
| 72 |
|
| 73 |
## Use with `@huggingface/kernels`
|
| 74 |
|
| 75 |
```sh
|
| 76 |
+
npm install --save-exact @huggingface/kernels@0.0.1-preview.3
|
| 77 |
```
|
| 78 |
|
| 79 |
Required output shapes and logical data types are inferred from the supplied inputs and attributes; result tensors are allocated automatically.
|
build/webgpu/average-pool2d-nchw-horizontal-reuse.wgsl.jinja
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
{{ env.wgsl.resourceDeclarations }}
|
| 2 |
|
| 3 |
// Four adjacent windows share source columns. For a K-wide, dilation-D window
|
|
@@ -22,8 +28,7 @@ fn load_value(validRow: bool, base: u32, col: i32) -> f32 {
|
|
| 22 |
|
| 23 |
@compute @workgroup_size({{ tunables.WORKGROUP_SIZE }})
|
| 24 |
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
| 25 |
-
|
| 26 |
-
if (q >= COUNT4) { return; }
|
| 27 |
|
| 28 |
let ow0 = (q % OUT_W4) * 4u;
|
| 29 |
var t = q / OUT_W4;
|
|
|
|
| 1 |
+
{% macro flat_index_2d(workgroupSize, name="i", bound="params.count", guardInline=false) %}
|
| 2 |
+
{% set wgTerm = workgroupSize ~ "u" if workgroupSize is number else workgroupSize %}
|
| 3 |
+
// 2D-folded flat index: gid.y carries the high bits past the dispatch's
|
| 4 |
+
// per-axis workgroup fold width.
|
| 5 |
+
let {{ name }} = gid.x + gid.y * {{ DISPATCH_FOLD_WIDTH }}u * {{ wgTerm }};
|
| 6 |
+
if ({{ name }} >= {{ bound }}) { return; }{% endmacro %}
|
| 7 |
{{ env.wgsl.resourceDeclarations }}
|
| 8 |
|
| 9 |
// Four adjacent windows share source columns. For a K-wide, dilation-D window
|
|
|
|
| 28 |
|
| 29 |
@compute @workgroup_size({{ tunables.WORKGROUP_SIZE }})
|
| 30 |
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
| 31 |
+
{{ flat_index_2d("WG", "q", "COUNT4", guardInline=true) }}
|
|
|
|
| 32 |
|
| 33 |
let ow0 = (q % OUT_W4) * 4u;
|
| 34 |
var t = q / OUT_W4;
|
build/webgpu/average-pool2d-nchw-w3s1-reuse.wgsl.jinja
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
{{ env.wgsl.resourceDeclarations }}
|
| 2 |
|
| 3 |
// 2D NCHW AveragePool specialised for a 3-wide / stride-1 / pad-1 / dilation-1
|
|
@@ -32,10 +40,7 @@ fn col_valid(rowValid: bool, col: i32) -> u32 {
|
|
| 32 |
|
| 33 |
@compute @workgroup_size({{ tunables.WORKGROUP_SIZE }})
|
| 34 |
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
| 35 |
-
|
| 36 |
-
if (tile >= params.tileCount) {
|
| 37 |
-
return;
|
| 38 |
-
}
|
| 39 |
|
| 40 |
let colTile = tile % OUT_W_Q; // which group-of-four columns in this row
|
| 41 |
var t = tile / OUT_W_Q;
|
|
|
|
| 1 |
+
{% macro flat_index_2d(workgroupSize, name="i", bound="params.count", guardInline=false) %}
|
| 2 |
+
{% set wgTerm = workgroupSize ~ "u" if workgroupSize is number else workgroupSize %}
|
| 3 |
+
// 2D-folded flat index: gid.y carries the high bits past the dispatch's
|
| 4 |
+
// per-axis workgroup fold width.
|
| 5 |
+
let {{ name }} = gid.x + gid.y * {{ DISPATCH_FOLD_WIDTH }}u * {{ wgTerm }};
|
| 6 |
+
if ({{ name }} >= {{ bound }}) {
|
| 7 |
+
return;
|
| 8 |
+
}{% endmacro %}
|
| 9 |
{{ env.wgsl.resourceDeclarations }}
|
| 10 |
|
| 11 |
// 2D NCHW AveragePool specialised for a 3-wide / stride-1 / pad-1 / dilation-1
|
|
|
|
| 40 |
|
| 41 |
@compute @workgroup_size({{ tunables.WORKGROUP_SIZE }})
|
| 42 |
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
| 43 |
+
{{ flat_index_2d(tunables.WORKGROUP_SIZE, "tile", "params.tileCount") }}
|
|
|
|
|
|
|
|
|
|
| 44 |
|
| 45 |
let colTile = tile % OUT_W_Q; // which group-of-four columns in this row
|
| 46 |
var t = tile / OUT_W_Q;
|
build/webgpu/bench.json
CHANGED
|
@@ -36,6 +36,17 @@
|
|
| 36 |
"metrics": [{ "type": "bandwidth", "value": "args.batch * args.channels * args.inH * args.inW * 2 * 2" }]
|
| 37 |
}
|
| 38 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 39 |
{
|
| 40 |
"name": "average-pool-f32-b1c64-224x224-k7s2p3-generic",
|
| 41 |
"preset": "smoke",
|
|
@@ -198,6 +209,81 @@
|
|
| 198 |
"inputs": { "x": { "dtype": "float32", "shape": [8, 64, 56, 56] } },
|
| 199 |
"outputs": { "y": { "dtype": "float32", "shape": [8, 64, 8, 8] } },
|
| 200 |
"bench": { "metrics": [{ "type": "bandwidth", "value": "(numel(shapes.x) + numel(shapes.y)) * 4" }] }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 201 |
}
|
| 202 |
]
|
| 203 |
}
|
|
|
|
| 36 |
"metrics": [{ "type": "bandwidth", "value": "args.batch * args.channels * args.inH * args.inW * 2 * 2" }]
|
| 37 |
}
|
| 38 |
},
|
| 39 |
+
{
|
| 40 |
+
"name": "nchw_f16_1x128x56x56_k3s1p1",
|
| 41 |
+
"preset": "model",
|
| 42 |
+
"vars": { "batch": 1, "channels": 128, "inH": 56, "inW": 56 },
|
| 43 |
+
"attrs": { "kernel_shape": [3, 3], "strides": [1, 1], "pads": [1, 1, 1, 1] },
|
| 44 |
+
"inputs": { "x": { "dtype": "float16", "shape": [1, 128, 56, 56], "dist": "normal", "seed": 207 } },
|
| 45 |
+
"outputs": { "y": { "dtype": "float16", "shape": [1, 128, 56, 56], "dist": "empty" } },
|
| 46 |
+
"bench": {
|
| 47 |
+
"metrics": [{ "type": "bandwidth", "value": "args.batch * args.channels * args.inH * args.inW * 2 * 2" }]
|
| 48 |
+
}
|
| 49 |
+
},
|
| 50 |
{
|
| 51 |
"name": "average-pool-f32-b1c64-224x224-k7s2p3-generic",
|
| 52 |
"preset": "smoke",
|
|
|
|
| 209 |
"inputs": { "x": { "dtype": "float32", "shape": [8, 64, 56, 56] } },
|
| 210 |
"outputs": { "y": { "dtype": "float32", "shape": [8, 64, 8, 8] } },
|
| 211 |
"bench": { "metrics": [{ "type": "bandwidth", "value": "(numel(shapes.x) + numel(shapes.y)) * 4" }] }
|
| 212 |
+
},
|
| 213 |
+
{
|
| 214 |
+
"name": "average-pool-f32-b1c32-24x24-k12s1p2-window-parallel-starved",
|
| 215 |
+
"preset": "stress",
|
| 216 |
+
"provenance": {
|
| 217 |
+
"source": "synthetic benchmark",
|
| 218 |
+
"notes": "A 144-tap padded window produces 9,248 outputs across 32 channels. This brackets the region where output parallelism exceeds the number of taps."
|
| 219 |
+
},
|
| 220 |
+
"attrs": { "count_include_pad": 0, "kernel_shape": [12, 12], "strides": [1, 1], "pads": [2, 2, 2, 2] },
|
| 221 |
+
"inputs": { "x": { "dtype": "float32", "shape": [1, 32, 24, 24], "dist": "normal", "seed": 4301, "scale": 0.2 } },
|
| 222 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 32, 17, 17], "dist": "empty" } },
|
| 223 |
+
"bench": { "metrics": [{ "type": "bandwidth", "value": "(numel(shapes.x) + numel(shapes.y)) * 4" }] }
|
| 224 |
+
},
|
| 225 |
+
{
|
| 226 |
+
"name": "average-pool-f32-b1c64-24x24-k12s1p2-serial-side-of-gate",
|
| 227 |
+
"preset": "stress",
|
| 228 |
+
"provenance": {
|
| 229 |
+
"source": "synthetic benchmark",
|
| 230 |
+
"notes": "Measures average pooling with a 12x12 window and padding 2 over 64 channels of a 24x24 input, producing a 17x17 (18,496-element) output."
|
| 231 |
+
},
|
| 232 |
+
"attrs": { "count_include_pad": 0, "kernel_shape": [12, 12], "strides": [1, 1], "pads": [2, 2, 2, 2] },
|
| 233 |
+
"inputs": { "x": { "dtype": "float32", "shape": [1, 64, 24, 24], "dist": "normal", "seed": 4302, "scale": 0.2 } },
|
| 234 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 64, 17, 17], "dist": "empty" } },
|
| 235 |
+
"bench": { "metrics": [{ "type": "bandwidth", "value": "(numel(shapes.x) + numel(shapes.y)) * 4" }] }
|
| 236 |
+
},
|
| 237 |
+
{
|
| 238 |
+
"name": "average-pool-f32-b1c16-56x56-k28s28-window-parallel-extreme-starved",
|
| 239 |
+
"preset": "stress",
|
| 240 |
+
"provenance": {
|
| 241 |
+
"source": "synthetic benchmark",
|
| 242 |
+
"notes": "A 784-tap non-overlapping window leaving 64 outputs: the serial route dispatches a single workgroup and loops 784 taps on each of 64 invocations."
|
| 243 |
+
},
|
| 244 |
+
"attrs": { "count_include_pad": 0, "kernel_shape": [28, 28], "strides": [28, 28], "pads": [0, 0, 0, 0] },
|
| 245 |
+
"inputs": { "x": { "dtype": "float32", "shape": [1, 16, 56, 56], "dist": "normal", "seed": 4303, "scale": 0.2 } },
|
| 246 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 16, 2, 2], "dist": "empty" } },
|
| 247 |
+
"bench": { "metrics": [{ "type": "bandwidth", "value": "(numel(shapes.x) + numel(shapes.y)) * 4" }] }
|
| 248 |
+
},
|
| 249 |
+
{
|
| 250 |
+
"name": "average-pool-f32-b1c64-14x14-k14s1p6-padded-near-global",
|
| 251 |
+
"preset": "stress",
|
| 252 |
+
"provenance": {
|
| 253 |
+
"source": "synthetic benchmark",
|
| 254 |
+
"notes": "A padded near-global pool from a classifier head: a 196-tap window over a 14x14 map with pad 6 leaves 10816 outputs, 43 serial dispatch groups."
|
| 255 |
+
},
|
| 256 |
+
"attrs": { "count_include_pad": 0, "kernel_shape": [14, 14], "strides": [1, 1], "pads": [6, 6, 6, 6] },
|
| 257 |
+
"inputs": { "x": { "dtype": "float32", "shape": [1, 64, 14, 14], "dist": "normal", "seed": 4304, "scale": 0.2 } },
|
| 258 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 64, 13, 13], "dist": "empty" } },
|
| 259 |
+
"bench": { "metrics": [{ "type": "bandwidth", "value": "(numel(shapes.x) + numel(shapes.y)) * 4" }] }
|
| 260 |
+
},
|
| 261 |
+
{
|
| 262 |
+
"name": "occupancy-window_parallel_nchw2d_count_include_pad_k12p2_small_output",
|
| 263 |
+
"preset": "stress",
|
| 264 |
+
"attrs": {
|
| 265 |
+
"kernel_shape": [12, 12],
|
| 266 |
+
"strides": [2, 2],
|
| 267 |
+
"pads": [2, 2, 2, 2],
|
| 268 |
+
"count_include_pad": 1,
|
| 269 |
+
"ceil_mode": 0
|
| 270 |
+
},
|
| 271 |
+
"inputs": { "x": { "dtype": "float32", "shape": [1, 1, 24, 24], "dist": "normal", "seed": 5482, "scale": 0.2 } },
|
| 272 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 1, 9, 9] } }
|
| 273 |
+
},
|
| 274 |
+
{
|
| 275 |
+
"name": "occupancy-window_parallel_outputs_to_taps_boundary_128",
|
| 276 |
+
"preset": "stress",
|
| 277 |
+
"attrs": { "kernel_shape": [128], "strides": [1] },
|
| 278 |
+
"inputs": { "x": { "dtype": "float32", "shape": [1, 1, 255], "dist": "normal", "seed": 5482, "scale": 0.2 } },
|
| 279 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 1, 128] } }
|
| 280 |
+
},
|
| 281 |
+
{
|
| 282 |
+
"name": "occupancy-window_parallel_outputs_to_taps_boundary_129",
|
| 283 |
+
"preset": "stress",
|
| 284 |
+
"attrs": { "kernel_shape": [128], "strides": [1] },
|
| 285 |
+
"inputs": { "x": { "dtype": "float32", "shape": [1, 1, 256], "dist": "normal", "seed": 5482, "scale": 0.2 } },
|
| 286 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 1, 129] } }
|
| 287 |
}
|
| 288 |
]
|
| 289 |
}
|
build/webgpu/manifest.json
CHANGED
|
@@ -20,10 +20,16 @@
|
|
| 20 |
"kernel_shape": { "required": true }
|
| 21 |
},
|
| 22 |
"typeConstraints": { "T": ["float32", "float16"] },
|
| 23 |
-
"tunables": {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 24 |
"derive": {
|
| 25 |
"spatialRank": "ranks.x - 2",
|
| 26 |
"narrowSubgroupRange": "has(device.adapterInfo, \"subgroupMinSize\") and has(device.adapterInfo, \"subgroupMaxSize\") and device.adapterInfo.subgroupMinSize < device.adapterInfo.subgroupMaxSize and device.adapterInfo.subgroupMaxSize <= 16",
|
|
|
|
| 27 |
"kernelShapeLengthOk": "not has(attrs, \"kernel_shape\") or (attrs.kernel_shape | length) == spatialRank",
|
| 28 |
"stridesLengthOk": "not has(attrs, \"strides\") or (attrs.strides | length) == spatialRank",
|
| 29 |
"dilationsLengthOk": "not has(attrs, \"dilations\") or (attrs.dilations | length) == spatialRank",
|
|
@@ -43,7 +49,6 @@
|
|
| 43 |
"padBack": "attrs.pads[spatialRank] if padsLengthOk and has(attrs, \"pads\") and spatialRank == 3 else 0",
|
| 44 |
"padBottom": "attrs.pads[2 * spatialRank - 2] if padsLengthOk and has(attrs, \"pads\") and spatialRank >= 2 else 0",
|
| 45 |
"padRight": "attrs.pads[2 * spatialRank - 1] if padsLengthOk and has(attrs, \"pads\") and spatialRank >= 1 else 0",
|
| 46 |
-
"poolBaseOk": "f16Ok(dtypes.T) and ranks.x >= 3 and ranks.x <= 5 and ranks.y == ranks.x and has(attrs, \"kernel_shape\") and kernelShapeLengthOk and stridesLengthOk and dilationsLengthOk and padsLengthOk and kernelD > 0 and kernelH > 0 and kernelW > 0 and strideD > 0 and strideH > 0 and strideW > 0 and dilationD > 0 and dilationH > 0 and dilationW > 0 and padFront >= 0 and padTop >= 0 and padLeft >= 0 and padBack >= 0 and padBottom >= 0 and padRight >= 0 and (attrs.auto_pad == \"NOTSET\" or not has(attrs, \"pads\")) and dim(shapes.y, 0) == dim(shapes.x, 0) and dim(shapes.y, 1) == dim(shapes.x, 1)",
|
| 47 |
"explicitOutW": "min(ceil((dim(shapes.x, ranks.x - 1) + padLeft + padRight - ((kernelW - 1) * dilationW + 1)) / strideW) + 1, ceil((dim(shapes.x, ranks.x - 1) + padLeft) / strideW)) if attrs.ceil_mode != 0 else floor((dim(shapes.x, ranks.x - 1) + padLeft + padRight - ((kernelW - 1) * dilationW + 1)) / strideW) + 1",
|
| 48 |
"explicitOutH": "min(ceil((dim(shapes.x, ranks.x - 2) + padTop + padBottom - ((kernelH - 1) * dilationH + 1)) / strideH) + 1, ceil((dim(shapes.x, ranks.x - 2) + padTop) / strideH)) if attrs.ceil_mode != 0 else floor((dim(shapes.x, ranks.x - 2) + padTop + padBottom - ((kernelH - 1) * dilationH + 1)) / strideH) + 1",
|
| 49 |
"explicitOutD": "(min(ceil((dim(shapes.x, 2) + padFront + padBack - ((kernelD - 1) * dilationD + 1)) / strideD) + 1, ceil((dim(shapes.x, 2) + padFront) / strideD)) if attrs.ceil_mode != 0 else floor((dim(shapes.x, 2) + padFront + padBack - ((kernelD - 1) * dilationD + 1)) / strideD) + 1) if ranks.x == 5 else 0",
|
|
@@ -54,20 +59,78 @@
|
|
| 54 |
"autoPadTotalD": "max(0, (dim(shapes.y, 2) - 1) * strideD + ((kernelD - 1) * dilationD + 1) - dim(shapes.x, 2)) if ranks.x == 5 else 0",
|
| 55 |
"autoPadTotalH": "max(0, (dim(shapes.y, ranks.x - 2) - 1) * strideH + ((kernelH - 1) * dilationH + 1) - dim(shapes.x, ranks.x - 2)) if ranks.x >= 4 else 0",
|
| 56 |
"autoPadTotalW": "max(0, (dim(shapes.y, ranks.x - 1) - 1) * strideW + ((kernelW - 1) * dilationW + 1) - dim(shapes.x, ranks.x - 1))",
|
| 57 |
-
"
|
| 58 |
-
"
|
| 59 |
-
"
|
| 60 |
-
"
|
| 61 |
-
"
|
| 62 |
-
"effectivePadRight": "autoPadTotalW - effectivePadLeft if (attrs.auto_pad == \"SAME_UPPER\" or attrs.auto_pad == \"SAME_LOWER\") else padRight",
|
| 63 |
-
"narrowF32W3UnrolledPreferred": "narrowSubgroupRange and dtypes.T == \"f32\"",
|
| 64 |
-
"globalWindowParallelCovered": "poolBaseOk and numel(shapes.y) == dim(shapes.x, 0) * dim(shapes.x, 1) and numel(shapes.y) <= min(device.limits.maxComputeWorkgroupsPerDimension, 65535) and attrs.auto_pad == \"NOTSET\" and strideD == 1 and strideH == 1 and strideW == 1 and dilationD == 1 and dilationH == 1 and dilationW == 1 and padFront == 0 and padTop == 0 and padLeft == 0 and padBack == 0 and padBottom == 0 and padRight == 0 and ((ranks.x == 3 and kernelW == dim(shapes.x, 2)) or (ranks.x == 4 and kernelH == dim(shapes.x, 2) and kernelW == dim(shapes.x, 3)) or (ranks.x == 5 and kernelD == dim(shapes.x, 2) and kernelH == dim(shapes.x, 3) and kernelW == dim(shapes.x, 4))) and inner(shapes.x, 1) >= 256",
|
| 65 |
"separableTmpElements": "dim(shapes.x, 0) * dim(shapes.x, 1) * dim(shapes.x, 2) * dim(shapes.y, 3)",
|
| 66 |
"separableFits": "separableTmpElements * 4 <= min(device.limits.maxStorageBufferBindingSize, device.limits.maxBufferSize) and ceilDiv(separableTmpElements, tunables.WORKGROUP_SIZE) <= min(device.limits.maxComputeWorkgroupsPerDimension, 65535) * min(device.limits.maxComputeWorkgroupsPerDimension, 65535)",
|
| 67 |
-
"
|
| 68 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 69 |
},
|
| 70 |
-
"bindings": { "y_2": { "name": "y", "buffer": "storage", "elementType": "$outputElement" } },
|
| 71 |
"variants": [
|
| 72 |
{
|
| 73 |
"id": "global_window_parallel",
|
|
@@ -81,7 +144,6 @@
|
|
| 81 |
"id": "main",
|
| 82 |
"name": "AveragePool.GlobalWindowParallel",
|
| 83 |
"shader": "pool-global-reduction.wgsl.jinja",
|
| 84 |
-
"subgroupCollectivesWidth": "portable",
|
| 85 |
"derive": {
|
| 86 |
"op": "\"average\"",
|
| 87 |
"vec4": "inner(shapes.x, 1) % 4 == 0",
|
|
@@ -97,10 +159,85 @@
|
|
| 97 |
}
|
| 98 |
]
|
| 99 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 100 |
{
|
| 101 |
"id": "nchw2d_k7s1_reuse_tail",
|
| 102 |
"priority": 34,
|
| 103 |
-
"when": ["poolBaseOk", "ranks.x == 4", "kernelH == 7", "kernelW == 7", "strideH == 1", "strideW == 1", "dilationH == 1", "dilationW == 1", "
|
| 104 |
"derive": { "outputElement": "dtypes.T" },
|
| 105 |
"passes": [
|
| 106 |
{
|
|
@@ -116,16 +253,11 @@
|
|
| 116 |
"dilationWSpec": 1,
|
| 117 |
"padTopSpec": 3,
|
| 118 |
"padLeftSpec": 3,
|
| 119 |
-
"inH": "dim(shapes.x, 2)",
|
| 120 |
-
"inW": "dim(shapes.x, 3)",
|
| 121 |
-
"inPlane": "dim(shapes.x, 2) * dim(shapes.x, 3)",
|
| 122 |
-
"outH": "dim(shapes.y, 2)",
|
| 123 |
-
"outW": "dim(shapes.y, 3)",
|
| 124 |
"outW4": "ceilDiv(dim(shapes.y, 3), 4)",
|
| 125 |
"count4": "dim(shapes.y, 0) * dim(shapes.y, 1) * dim(shapes.y, 2) * ceilDiv(dim(shapes.y, 3), 4)",
|
| 126 |
"scalarOutput": true
|
| 127 |
},
|
| 128 |
-
"bindings": ["x", "
|
| 129 |
"dispatch": {
|
| 130 |
"x": "min(ceilDiv((dim(shapes.y, 0) * dim(shapes.y, 1) * dim(shapes.y, 2) * ceilDiv(dim(shapes.y, 3), 4)), (tunables.WORKGROUP_SIZE)), 65535)",
|
| 131 |
"y": "ceilDiv(ceilDiv((dim(shapes.y, 0) * dim(shapes.y, 1) * dim(shapes.y, 2) * ceilDiv(dim(shapes.y, 3), 4)), (tunables.WORKGROUP_SIZE)), 65535)",
|
|
@@ -137,8 +269,8 @@
|
|
| 137 |
{
|
| 138 |
"id": "nchw2d_w3s1_reuse",
|
| 139 |
"priority": 30,
|
| 140 |
-
"when": ["poolBaseOk", "ranks.x == 4", "kernelW == 3", "strideW == 1", "dilationW == 1", "
|
| 141 |
-
"demoteWhen": ["narrowF32W3UnrolledPreferred"],
|
| 142 |
"passes": [
|
| 143 |
{
|
| 144 |
"id": "main",
|
|
@@ -147,12 +279,7 @@
|
|
| 147 |
"derive": {
|
| 148 |
"kernelHSpec": "kernelH",
|
| 149 |
"dilationHSpec": "dilationH",
|
| 150 |
-
"padTopSpec": "
|
| 151 |
-
"inH": "dim(shapes.x, 2)",
|
| 152 |
-
"inW": "dim(shapes.x, 3)",
|
| 153 |
-
"inPlane": "dim(shapes.x, 2) * dim(shapes.x, 3)",
|
| 154 |
-
"outH": "dim(shapes.y, 2)",
|
| 155 |
-
"outW": "dim(shapes.y, 3)",
|
| 156 |
"outWQuarter": "floor(dim(shapes.y, 3) / 4)"
|
| 157 |
},
|
| 158 |
"bindings": [
|
|
@@ -171,7 +298,7 @@
|
|
| 171 |
{
|
| 172 |
"id": "nchw2d_w3s1_reuse_tail",
|
| 173 |
"priority": 29,
|
| 174 |
-
"when": ["poolBaseOk", "ranks.x == 4", "kernelW == 3", "strideW == 1", "dilationW == 1", "
|
| 175 |
"derive": { "outputElement": "dtypes.T" },
|
| 176 |
"passes": [
|
| 177 |
{
|
|
@@ -185,18 +312,13 @@
|
|
| 185 |
"strideWSpec": 1,
|
| 186 |
"dilationHSpec": "dilationH",
|
| 187 |
"dilationWSpec": 1,
|
| 188 |
-
"padTopSpec": "
|
| 189 |
"padLeftSpec": 1,
|
| 190 |
-
"inH": "dim(shapes.x, 2)",
|
| 191 |
-
"inW": "dim(shapes.x, 3)",
|
| 192 |
-
"inPlane": "dim(shapes.x, 2) * dim(shapes.x, 3)",
|
| 193 |
-
"outH": "dim(shapes.y, 2)",
|
| 194 |
-
"outW": "dim(shapes.y, 3)",
|
| 195 |
"outW4": "ceilDiv(dim(shapes.y, 3), 4)",
|
| 196 |
"count4": "dim(shapes.y, 0) * dim(shapes.y, 1) * dim(shapes.y, 2) * ceilDiv(dim(shapes.y, 3), 4)",
|
| 197 |
"scalarOutput": true
|
| 198 |
},
|
| 199 |
-
"bindings": ["x", "
|
| 200 |
"dispatch": {
|
| 201 |
"x": "min(ceilDiv((dim(shapes.y, 0) * dim(shapes.y, 1) * dim(shapes.y, 2) * ceilDiv(dim(shapes.y, 3), 4)), (tunables.WORKGROUP_SIZE)), 65535)",
|
| 202 |
"y": "ceilDiv(ceilDiv((dim(shapes.y, 0) * dim(shapes.y, 1) * dim(shapes.y, 2) * ceilDiv(dim(shapes.y, 3), 4)), (tunables.WORKGROUP_SIZE)), 65535)",
|
|
@@ -209,7 +331,7 @@
|
|
| 209 |
"id": "nchw2d_separable",
|
| 210 |
"priority": 22,
|
| 211 |
"when": ["poolBaseOk", "ranks.x == 4", "ranks.y == 4", "dim(shapes.y, 2) == inferredOutH", "dim(shapes.y, 3) == inferredOutW", "dim(shapes.y, 2) > 0", "dim(shapes.y, 3) > 0", "kernelH > 1", "kernelW > 1", "kernelH * kernelW >= tunables.SEPARABLE_MIN_WINDOW", "strideH < kernelH", "wholeWindowDenominator", "separableFits"],
|
| 212 |
-
"derive": { "scalar": "dtypes.T"
|
| 213 |
"intermediates": [{ "id": "tmp", "dtype": "float32", "shape": "[separableTmpElements]" }],
|
| 214 |
"passes": [
|
| 215 |
{
|
|
@@ -219,7 +341,7 @@
|
|
| 219 |
"derive": { "axisSpec": "\"w\"", "op": "\"avg\"", "windowArea": "kernelH * kernelW" },
|
| 220 |
"bindings": [
|
| 221 |
"x",
|
| 222 |
-
{ "name": "tmp", "
|
| 223 |
{
|
| 224 |
"name": "params",
|
| 225 |
"struct": [
|
|
@@ -229,7 +351,7 @@
|
|
| 229 |
{ "name": "kernelW", "type": "u32", "value": "kernelW" },
|
| 230 |
{ "name": "strideW", "type": "u32", "value": "strideW" },
|
| 231 |
{ "name": "dilationW", "type": "u32", "value": "dilationW" },
|
| 232 |
-
{ "name": "padW", "type": "i32", "value": "
|
| 233 |
{ "name": "tmpCount", "type": "u32", "value": "separableTmpElements" }
|
| 234 |
]
|
| 235 |
}
|
|
@@ -257,7 +379,7 @@
|
|
| 257 |
{ "name": "kernelH", "type": "u32", "value": "kernelH" },
|
| 258 |
{ "name": "strideH", "type": "u32", "value": "strideH" },
|
| 259 |
{ "name": "dilationH", "type": "u32", "value": "dilationH" },
|
| 260 |
-
{ "name": "padH", "type": "i32", "value": "
|
| 261 |
{ "name": "count", "type": "u32", "value": "numel(shapes.y)" }
|
| 262 |
]
|
| 263 |
}
|
|
@@ -287,8 +409,8 @@
|
|
| 287 |
"strideWSpec": "strideW",
|
| 288 |
"dilationHSpec": "dilationH",
|
| 289 |
"dilationWSpec": "dilationW",
|
| 290 |
-
"padTopSpec": "
|
| 291 |
-
"padLeftSpec": "
|
| 292 |
"inH": "dim(shapes.x, 2)",
|
| 293 |
"inW": "dim(shapes.x, 3)",
|
| 294 |
"outH": "dim(shapes.y, 2)",
|
|
@@ -332,7 +454,7 @@
|
|
| 332 |
{ "name": "kernelW", "type": "u32", "value": "kernelW" },
|
| 333 |
{ "name": "strideW", "type": "u32", "value": "strideW" },
|
| 334 |
{ "name": "dilationW", "type": "u32", "value": "dilationW" },
|
| 335 |
-
{ "name": "padLeft", "type": "i32", "value": "
|
| 336 |
{ "name": "padRight", "type": "i32", "value": "effectivePadRight" },
|
| 337 |
{ "name": "countIncludePad", "type": "u32", "value": "attrs.count_include_pad" },
|
| 338 |
{ "name": "count", "type": "u32", "value": "numel(shapes.y)" }
|
|
@@ -353,7 +475,7 @@
|
|
| 353 |
"passes": [
|
| 354 |
{
|
| 355 |
"id": "main",
|
| 356 |
-
"name": "
|
| 357 |
"shader": "pool-window-nd.wgsl.jinja",
|
| 358 |
"derive": { "op": "\"average\"", "spatialRankSpec": 2 },
|
| 359 |
"bindings": [
|
|
@@ -373,8 +495,8 @@
|
|
| 373 |
{ "name": "strideW", "type": "u32", "value": "strideW" },
|
| 374 |
{ "name": "dilationH", "type": "u32", "value": "dilationH" },
|
| 375 |
{ "name": "dilationW", "type": "u32", "value": "dilationW" },
|
| 376 |
-
{ "name": "padTop", "type": "i32", "value": "
|
| 377 |
-
{ "name": "padLeft", "type": "i32", "value": "
|
| 378 |
{ "name": "padBottom", "type": "i32", "value": "effectivePadBottom" },
|
| 379 |
{ "name": "padRight", "type": "i32", "value": "effectivePadRight" },
|
| 380 |
{ "name": "countIncludePad", "type": "u32", "value": "attrs.count_include_pad" },
|
|
@@ -423,9 +545,9 @@
|
|
| 423 |
{ "name": "dilationD", "type": "u32", "value": "dilationD" },
|
| 424 |
{ "name": "dilationH", "type": "u32", "value": "dilationH" },
|
| 425 |
{ "name": "dilationW", "type": "u32", "value": "dilationW" },
|
| 426 |
-
{ "name": "padFront", "type": "i32", "value": "
|
| 427 |
-
{ "name": "padTop", "type": "i32", "value": "
|
| 428 |
-
{ "name": "padLeft", "type": "i32", "value": "
|
| 429 |
{ "name": "padBack", "type": "i32", "value": "effectivePadBack" },
|
| 430 |
{ "name": "padBottom", "type": "i32", "value": "effectivePadBottom" },
|
| 431 |
{ "name": "padRight", "type": "i32", "value": "effectivePadRight" },
|
|
@@ -445,7 +567,7 @@
|
|
| 445 |
{
|
| 446 |
"id": "nchw2d_k7s2_reuse",
|
| 447 |
"priority": 36,
|
| 448 |
-
"when": ["poolBaseOk", "ranks.x == 4", "kernelH == 7", "kernelW == 7", "strideH == 2", "strideW == 2", "dilationH == 1", "dilationW == 1", "
|
| 449 |
"derive": { "outputElement": "\"vec4<\" ~ dtypes.T ~ \">\"", "vectorScalar": "\"vec4<\" ~ dtypes.T ~ \">\"" },
|
| 450 |
"passes": [
|
| 451 |
{
|
|
@@ -461,15 +583,10 @@
|
|
| 461 |
"dilationWSpec": 1,
|
| 462 |
"padTopSpec": 3,
|
| 463 |
"padLeftSpec": 3,
|
| 464 |
-
"inH": "dim(shapes.x, 2)",
|
| 465 |
-
"inW": "dim(shapes.x, 3)",
|
| 466 |
-
"inPlane": "dim(shapes.x, 2) * dim(shapes.x, 3)",
|
| 467 |
-
"outH": "dim(shapes.y, 2)",
|
| 468 |
-
"outW": "dim(shapes.y, 3)",
|
| 469 |
"outW4": "dim(shapes.y, 3) / 4",
|
| 470 |
"count4": "numel(shapes.y) / 4"
|
| 471 |
},
|
| 472 |
-
"bindings": ["x", "
|
| 473 |
"dispatch": {
|
| 474 |
"x": "min(ceilDiv((numel(shapes.y) / 4), (tunables.WORKGROUP_SIZE)), 65535)",
|
| 475 |
"y": "ceilDiv(ceilDiv((numel(shapes.y) / 4), (tunables.WORKGROUP_SIZE)), 65535)",
|
|
@@ -481,7 +598,7 @@
|
|
| 481 |
{
|
| 482 |
"id": "nchw2d_k7s1_reuse",
|
| 483 |
"priority": 35,
|
| 484 |
-
"when": ["poolBaseOk", "ranks.x == 4", "kernelH == 7", "kernelW == 7", "strideH == 1", "strideW == 1", "dilationH == 1", "dilationW == 1", "
|
| 485 |
"derive": { "outputElement": "\"vec4<\" ~ dtypes.T ~ \">\"", "vectorScalar": "\"vec4<\" ~ dtypes.T ~ \">\"" },
|
| 486 |
"passes": [
|
| 487 |
{
|
|
@@ -497,15 +614,10 @@
|
|
| 497 |
"dilationWSpec": 1,
|
| 498 |
"padTopSpec": 3,
|
| 499 |
"padLeftSpec": 3,
|
| 500 |
-
"inH": "dim(shapes.x, 2)",
|
| 501 |
-
"inW": "dim(shapes.x, 3)",
|
| 502 |
-
"inPlane": "dim(shapes.x, 2) * dim(shapes.x, 3)",
|
| 503 |
-
"outH": "dim(shapes.y, 2)",
|
| 504 |
-
"outW": "dim(shapes.y, 3)",
|
| 505 |
"outW4": "dim(shapes.y, 3) / 4",
|
| 506 |
"count4": "numel(shapes.y) / 4"
|
| 507 |
},
|
| 508 |
-
"bindings": ["x", "
|
| 509 |
"dispatch": {
|
| 510 |
"x": "min(ceilDiv((numel(shapes.y) / 4), (tunables.WORKGROUP_SIZE)), 65535)",
|
| 511 |
"y": "ceilDiv(ceilDiv((numel(shapes.y) / 4), (tunables.WORKGROUP_SIZE)), 65535)",
|
|
|
|
| 20 |
"kernel_shape": { "required": true }
|
| 21 |
},
|
| 22 |
"typeConstraints": { "T": ["float32", "float16"] },
|
| 23 |
+
"tunables": {
|
| 24 |
+
"WORKGROUP_SIZE": { "default": 256 },
|
| 25 |
+
"SEPARABLE_MIN_WINDOW": { "default": 25 },
|
| 26 |
+
"WINDOW_PARALLEL_MIN_TAPS": { "default": 128 },
|
| 27 |
+
"WINDOW_PARALLEL_MAX_SERIAL_GROUPS": { "default": 64 }
|
| 28 |
+
},
|
| 29 |
"derive": {
|
| 30 |
"spatialRank": "ranks.x - 2",
|
| 31 |
"narrowSubgroupRange": "has(device.adapterInfo, \"subgroupMinSize\") and has(device.adapterInfo, \"subgroupMaxSize\") and device.adapterInfo.subgroupMinSize < device.adapterInfo.subgroupMaxSize and device.adapterInfo.subgroupMaxSize <= 16",
|
| 32 |
+
"variableSubgroup16To32": "device.features.has(\"subgroups\") and has(device.adapterInfo, \"subgroupMinSize\") and has(device.adapterInfo, \"subgroupMaxSize\") and device.adapterInfo.subgroupMinSize == 16 and device.adapterInfo.subgroupMaxSize == 32",
|
| 33 |
"kernelShapeLengthOk": "not has(attrs, \"kernel_shape\") or (attrs.kernel_shape | length) == spatialRank",
|
| 34 |
"stridesLengthOk": "not has(attrs, \"strides\") or (attrs.strides | length) == spatialRank",
|
| 35 |
"dilationsLengthOk": "not has(attrs, \"dilations\") or (attrs.dilations | length) == spatialRank",
|
|
|
|
| 49 |
"padBack": "attrs.pads[spatialRank] if padsLengthOk and has(attrs, \"pads\") and spatialRank == 3 else 0",
|
| 50 |
"padBottom": "attrs.pads[2 * spatialRank - 2] if padsLengthOk and has(attrs, \"pads\") and spatialRank >= 2 else 0",
|
| 51 |
"padRight": "attrs.pads[2 * spatialRank - 1] if padsLengthOk and has(attrs, \"pads\") and spatialRank >= 1 else 0",
|
|
|
|
| 52 |
"explicitOutW": "min(ceil((dim(shapes.x, ranks.x - 1) + padLeft + padRight - ((kernelW - 1) * dilationW + 1)) / strideW) + 1, ceil((dim(shapes.x, ranks.x - 1) + padLeft) / strideW)) if attrs.ceil_mode != 0 else floor((dim(shapes.x, ranks.x - 1) + padLeft + padRight - ((kernelW - 1) * dilationW + 1)) / strideW) + 1",
|
| 53 |
"explicitOutH": "min(ceil((dim(shapes.x, ranks.x - 2) + padTop + padBottom - ((kernelH - 1) * dilationH + 1)) / strideH) + 1, ceil((dim(shapes.x, ranks.x - 2) + padTop) / strideH)) if attrs.ceil_mode != 0 else floor((dim(shapes.x, ranks.x - 2) + padTop + padBottom - ((kernelH - 1) * dilationH + 1)) / strideH) + 1",
|
| 54 |
"explicitOutD": "(min(ceil((dim(shapes.x, 2) + padFront + padBack - ((kernelD - 1) * dilationD + 1)) / strideD) + 1, ceil((dim(shapes.x, 2) + padFront) / strideD)) if attrs.ceil_mode != 0 else floor((dim(shapes.x, 2) + padFront + padBack - ((kernelD - 1) * dilationD + 1)) / strideD) + 1) if ranks.x == 5 else 0",
|
|
|
|
| 59 |
"autoPadTotalD": "max(0, (dim(shapes.y, 2) - 1) * strideD + ((kernelD - 1) * dilationD + 1) - dim(shapes.x, 2)) if ranks.x == 5 else 0",
|
| 60 |
"autoPadTotalH": "max(0, (dim(shapes.y, ranks.x - 2) - 1) * strideH + ((kernelH - 1) * dilationH + 1) - dim(shapes.x, ranks.x - 2)) if ranks.x >= 4 else 0",
|
| 61 |
"autoPadTotalW": "max(0, (dim(shapes.y, ranks.x - 1) - 1) * strideW + ((kernelW - 1) * dilationW + 1) - dim(shapes.x, ranks.x - 1))",
|
| 62 |
+
"effectivePadD": "(floor(autoPadTotalD / 2) if attrs.auto_pad == \"SAME_UPPER\" else autoPadTotalD - floor(autoPadTotalD / 2)) if (attrs.auto_pad == \"SAME_UPPER\" or attrs.auto_pad == \"SAME_LOWER\") else padFront",
|
| 63 |
+
"effectivePadH": "(floor(autoPadTotalH / 2) if attrs.auto_pad == \"SAME_UPPER\" else autoPadTotalH - floor(autoPadTotalH / 2)) if (attrs.auto_pad == \"SAME_UPPER\" or attrs.auto_pad == \"SAME_LOWER\") else padTop",
|
| 64 |
+
"effectivePadW": "(floor(autoPadTotalW / 2) if attrs.auto_pad == \"SAME_UPPER\" else autoPadTotalW - floor(autoPadTotalW / 2)) if (attrs.auto_pad == \"SAME_UPPER\" or attrs.auto_pad == \"SAME_LOWER\") else padLeft",
|
| 65 |
+
"windowTaps": "kernelD * kernelH * kernelW",
|
| 66 |
+
"windowParallelEligible": "numel(shapes.y) > 0 and windowTaps >= tunables.WINDOW_PARALLEL_MIN_TAPS and ceilDiv(numel(shapes.y), tunables.WORKGROUP_SIZE) < tunables.WINDOW_PARALLEL_MAX_SERIAL_GROUPS and numel(shapes.y) <= min(device.limits.maxComputeWorkgroupsPerDimension, 65535) and numel(shapes.y) <= windowTaps",
|
|
|
|
|
|
|
|
|
|
| 67 |
"separableTmpElements": "dim(shapes.x, 0) * dim(shapes.x, 1) * dim(shapes.x, 2) * dim(shapes.y, 3)",
|
| 68 |
"separableFits": "separableTmpElements * 4 <= min(device.limits.maxStorageBufferBindingSize, device.limits.maxBufferSize) and ceilDiv(separableTmpElements, tunables.WORKGROUP_SIZE) <= min(device.limits.maxComputeWorkgroupsPerDimension, 65535) * min(device.limits.maxComputeWorkgroupsPerDimension, 65535)",
|
| 69 |
+
"poolBaseOk": "f16Ok(dtypes.T) and ranks.x >= 3 and ranks.x <= 5 and ranks.y == ranks.x and has(attrs, \"kernel_shape\") and kernelShapeLengthOk and stridesLengthOk and dilationsLengthOk and padsLengthOk and kernelD > 0 and kernelH > 0 and kernelW > 0 and strideD > 0 and strideH > 0 and strideW > 0 and dilationD > 0 and dilationH > 0 and dilationW > 0 and padFront >= 0 and padTop >= 0 and padLeft >= 0 and padBack >= 0 and padBottom >= 0 and padRight >= 0 and (attrs.auto_pad == \"NOTSET\" or not has(attrs, \"pads\")) and dim(shapes.y, 0) == dim(shapes.x, 0) and dim(shapes.y, 1) == dim(shapes.x, 1)",
|
| 70 |
+
"effectivePadBack": "autoPadTotalD - effectivePadD if (attrs.auto_pad == \"SAME_UPPER\" or attrs.auto_pad == \"SAME_LOWER\") else padBack",
|
| 71 |
+
"effectivePadBottom": "autoPadTotalH - effectivePadH if (attrs.auto_pad == \"SAME_UPPER\" or attrs.auto_pad == \"SAME_LOWER\") else padBottom",
|
| 72 |
+
"effectivePadRight": "autoPadTotalW - effectivePadW if (attrs.auto_pad == \"SAME_UPPER\" or attrs.auto_pad == \"SAME_LOWER\") else padRight",
|
| 73 |
+
"narrowF32W3UnrolledPreferred": "narrowSubgroupRange and dtypes.T == \"f32\"",
|
| 74 |
+
"globalWindowParallelCovered": "poolBaseOk and numel(shapes.y) == dim(shapes.x, 0) * dim(shapes.x, 1) and numel(shapes.y) <= min(device.limits.maxComputeWorkgroupsPerDimension, 65535) and attrs.auto_pad == \"NOTSET\" and strideD == 1 and strideH == 1 and strideW == 1 and dilationD == 1 and dilationH == 1 and dilationW == 1 and padFront == 0 and padTop == 0 and padLeft == 0 and padBack == 0 and padBottom == 0 and padRight == 0 and ((ranks.x == 3 and kernelW == dim(shapes.x, 2)) or (ranks.x == 4 and kernelH == dim(shapes.x, 2) and kernelW == dim(shapes.x, 3)) or (ranks.x == 5 and kernelD == dim(shapes.x, 2) and kernelH == dim(shapes.x, 3) and kernelW == dim(shapes.x, 4))) and inner(shapes.x, 1) >= 256",
|
| 75 |
+
"wholeWindowDenominator": "attrs.ceil_mode == 0 and (attrs.count_include_pad == 1 or (effectivePadH == 0 and effectivePadW == 0 and effectivePadBottom == 0 and effectivePadRight == 0))",
|
| 76 |
+
"scalar": "dtypes.T",
|
| 77 |
+
"inH": "dim(shapes.x, 2)",
|
| 78 |
+
"inPlane": "dim(shapes.x, 2) * dim(shapes.x, 3)",
|
| 79 |
+
"inW": "dim(shapes.x, 3)",
|
| 80 |
+
"outH": "dim(shapes.y, 2)",
|
| 81 |
+
"outW": "dim(shapes.y, 3)"
|
| 82 |
+
},
|
| 83 |
+
"bindings": {
|
| 84 |
+
"y_main": { "name": "y", "elementType": "$outputElement" },
|
| 85 |
+
"params_window_ncl1d": {
|
| 86 |
+
"name": "params",
|
| 87 |
+
"struct": [
|
| 88 |
+
{ "name": "channels", "type": "u32", "value": "dim(shapes.x, 1)" },
|
| 89 |
+
{ "name": "inW", "type": "u32", "value": "dim(shapes.x, 2)" },
|
| 90 |
+
{ "name": "outW", "type": "u32", "value": "dim(shapes.y, 2)" },
|
| 91 |
+
{ "name": "strideW", "type": "u32", "value": "strideW" },
|
| 92 |
+
{ "name": "dilationW", "type": "u32", "value": "dilationW" },
|
| 93 |
+
{ "name": "padW", "type": "i32", "value": "effectivePadW" }
|
| 94 |
+
]
|
| 95 |
+
},
|
| 96 |
+
"params_window_nchw2d": {
|
| 97 |
+
"name": "params",
|
| 98 |
+
"struct": [
|
| 99 |
+
{ "name": "channels", "type": "u32", "value": "dim(shapes.x, 1)" },
|
| 100 |
+
{ "name": "inH", "type": "u32", "value": "dim(shapes.x, 2)" },
|
| 101 |
+
{ "name": "inW", "type": "u32", "value": "dim(shapes.x, 3)" },
|
| 102 |
+
{ "name": "outH", "type": "u32", "value": "dim(shapes.y, 2)" },
|
| 103 |
+
{ "name": "outW", "type": "u32", "value": "dim(shapes.y, 3)" },
|
| 104 |
+
{ "name": "strideH", "type": "u32", "value": "strideH" },
|
| 105 |
+
{ "name": "strideW", "type": "u32", "value": "strideW" },
|
| 106 |
+
{ "name": "dilationH", "type": "u32", "value": "dilationH" },
|
| 107 |
+
{ "name": "dilationW", "type": "u32", "value": "dilationW" },
|
| 108 |
+
{ "name": "padH", "type": "i32", "value": "effectivePadH" },
|
| 109 |
+
{ "name": "padW", "type": "i32", "value": "effectivePadW" }
|
| 110 |
+
]
|
| 111 |
+
},
|
| 112 |
+
"params_window_ncdhw3d": {
|
| 113 |
+
"name": "params",
|
| 114 |
+
"struct": [
|
| 115 |
+
{ "name": "channels", "type": "u32", "value": "dim(shapes.x, 1)" },
|
| 116 |
+
{ "name": "inD", "type": "u32", "value": "dim(shapes.x, 2)" },
|
| 117 |
+
{ "name": "inH", "type": "u32", "value": "dim(shapes.x, 3)" },
|
| 118 |
+
{ "name": "inW", "type": "u32", "value": "dim(shapes.x, 4)" },
|
| 119 |
+
{ "name": "outD", "type": "u32", "value": "dim(shapes.y, 2)" },
|
| 120 |
+
{ "name": "outH", "type": "u32", "value": "dim(shapes.y, 3)" },
|
| 121 |
+
{ "name": "outW", "type": "u32", "value": "dim(shapes.y, 4)" },
|
| 122 |
+
{ "name": "strideD", "type": "u32", "value": "strideD" },
|
| 123 |
+
{ "name": "strideH", "type": "u32", "value": "strideH" },
|
| 124 |
+
{ "name": "strideW", "type": "u32", "value": "strideW" },
|
| 125 |
+
{ "name": "dilationD", "type": "u32", "value": "dilationD" },
|
| 126 |
+
{ "name": "dilationH", "type": "u32", "value": "dilationH" },
|
| 127 |
+
{ "name": "dilationW", "type": "u32", "value": "dilationW" },
|
| 128 |
+
{ "name": "padD", "type": "i32", "value": "effectivePadD" },
|
| 129 |
+
{ "name": "padH", "type": "i32", "value": "effectivePadH" },
|
| 130 |
+
{ "name": "padW", "type": "i32", "value": "effectivePadW" }
|
| 131 |
+
]
|
| 132 |
+
}
|
| 133 |
},
|
|
|
|
| 134 |
"variants": [
|
| 135 |
{
|
| 136 |
"id": "global_window_parallel",
|
|
|
|
| 144 |
"id": "main",
|
| 145 |
"name": "AveragePool.GlobalWindowParallel",
|
| 146 |
"shader": "pool-global-reduction.wgsl.jinja",
|
|
|
|
| 147 |
"derive": {
|
| 148 |
"op": "\"average\"",
|
| 149 |
"vec4": "inner(shapes.x, 1) % 4 == 0",
|
|
|
|
| 159 |
}
|
| 160 |
]
|
| 161 |
},
|
| 162 |
+
{
|
| 163 |
+
"id": "window_parallel_ncl1d",
|
| 164 |
+
"priority": 28,
|
| 165 |
+
"when": ["poolBaseOk", "ranks.x == 3", "dim(shapes.y, 2) == inferredOutW", "attrs.count_include_pad == 0 or attrs.ceil_mode == 0", "windowParallelEligible"],
|
| 166 |
+
"supersededBy": ["global_window_parallel"],
|
| 167 |
+
"passes": [
|
| 168 |
+
{
|
| 169 |
+
"id": "main",
|
| 170 |
+
"name": "AveragePool.WindowParallelNcl1d",
|
| 171 |
+
"shader": "pool-window-reduction.wgsl.jinja",
|
| 172 |
+
"derive": {
|
| 173 |
+
"op": "\"average\"",
|
| 174 |
+
"spatialRankSpec": 1,
|
| 175 |
+
"kernelDSpec": "kernelD",
|
| 176 |
+
"kernelHSpec": "kernelH",
|
| 177 |
+
"kernelWSpec": "kernelW",
|
| 178 |
+
"workgroupSizeSpec": "tunables.WORKGROUP_SIZE",
|
| 179 |
+
"useSubgroups": "device.features.has(\"subgroups\")",
|
| 180 |
+
"countIncludePad": "attrs.count_include_pad != 0"
|
| 181 |
+
},
|
| 182 |
+
"bindings": ["x", "y", "params_window_ncl1d"],
|
| 183 |
+
"dispatch": { "x": "numel(shapes.y)" }
|
| 184 |
+
}
|
| 185 |
+
]
|
| 186 |
+
},
|
| 187 |
+
{
|
| 188 |
+
"id": "window_parallel_nchw2d",
|
| 189 |
+
"priority": 28,
|
| 190 |
+
"when": ["poolBaseOk", "ranks.x == 4", "dim(shapes.y, 2) == inferredOutH", "dim(shapes.y, 3) == inferredOutW", "attrs.count_include_pad == 0 or attrs.ceil_mode == 0", "windowParallelEligible"],
|
| 191 |
+
"supersededBy": ["global_window_parallel"],
|
| 192 |
+
"passes": [
|
| 193 |
+
{
|
| 194 |
+
"id": "main",
|
| 195 |
+
"name": "AveragePool.WindowParallelNchw2d",
|
| 196 |
+
"shader": "pool-window-reduction.wgsl.jinja",
|
| 197 |
+
"derive": {
|
| 198 |
+
"op": "\"average\"",
|
| 199 |
+
"spatialRankSpec": 2,
|
| 200 |
+
"kernelDSpec": "kernelD",
|
| 201 |
+
"kernelHSpec": "kernelH",
|
| 202 |
+
"kernelWSpec": "kernelW",
|
| 203 |
+
"workgroupSizeSpec": "tunables.WORKGROUP_SIZE",
|
| 204 |
+
"useSubgroups": "device.features.has(\"subgroups\")",
|
| 205 |
+
"countIncludePad": "attrs.count_include_pad != 0"
|
| 206 |
+
},
|
| 207 |
+
"bindings": ["x", "y", "params_window_nchw2d"],
|
| 208 |
+
"dispatch": { "x": "numel(shapes.y)" }
|
| 209 |
+
}
|
| 210 |
+
]
|
| 211 |
+
},
|
| 212 |
+
{
|
| 213 |
+
"id": "window_parallel_ncdhw3d",
|
| 214 |
+
"priority": 28,
|
| 215 |
+
"when": ["poolBaseOk", "ranks.x == 5", "dim(shapes.y, 2) == inferredOutD", "dim(shapes.y, 3) == inferredOutH", "dim(shapes.y, 4) == inferredOutW", "attrs.count_include_pad == 0 or attrs.ceil_mode == 0", "windowParallelEligible"],
|
| 216 |
+
"supersededBy": ["global_window_parallel"],
|
| 217 |
+
"passes": [
|
| 218 |
+
{
|
| 219 |
+
"id": "main",
|
| 220 |
+
"name": "AveragePool.WindowParallelNcdhw3d",
|
| 221 |
+
"shader": "pool-window-reduction.wgsl.jinja",
|
| 222 |
+
"derive": {
|
| 223 |
+
"op": "\"average\"",
|
| 224 |
+
"spatialRankSpec": 3,
|
| 225 |
+
"kernelDSpec": "kernelD",
|
| 226 |
+
"kernelHSpec": "kernelH",
|
| 227 |
+
"kernelWSpec": "kernelW",
|
| 228 |
+
"workgroupSizeSpec": "tunables.WORKGROUP_SIZE",
|
| 229 |
+
"useSubgroups": "device.features.has(\"subgroups\")",
|
| 230 |
+
"countIncludePad": "attrs.count_include_pad != 0"
|
| 231 |
+
},
|
| 232 |
+
"bindings": ["x", "y", "params_window_ncdhw3d"],
|
| 233 |
+
"dispatch": { "x": "numel(shapes.y)" }
|
| 234 |
+
}
|
| 235 |
+
]
|
| 236 |
+
},
|
| 237 |
{
|
| 238 |
"id": "nchw2d_k7s1_reuse_tail",
|
| 239 |
"priority": 34,
|
| 240 |
+
"when": ["poolBaseOk", "ranks.x == 4", "kernelH == 7", "kernelW == 7", "strideH == 1", "strideW == 1", "dilationH == 1", "dilationW == 1", "effectivePadH == 3", "effectivePadBottom == 3", "effectivePadW == 3", "effectivePadRight == 3", "attrs.count_include_pad == 0", "attrs.ceil_mode == 0", "dim(shapes.x, 3) % 4 != 0", "dim(shapes.y, 2) == dim(shapes.x, 2)", "dim(shapes.y, 3) == dim(shapes.x, 3)", "dim(shapes.y, 2) > 0", "dim(shapes.y, 3) > 0"],
|
| 241 |
"derive": { "outputElement": "dtypes.T" },
|
| 242 |
"passes": [
|
| 243 |
{
|
|
|
|
| 253 |
"dilationWSpec": 1,
|
| 254 |
"padTopSpec": 3,
|
| 255 |
"padLeftSpec": 3,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 256 |
"outW4": "ceilDiv(dim(shapes.y, 3), 4)",
|
| 257 |
"count4": "dim(shapes.y, 0) * dim(shapes.y, 1) * dim(shapes.y, 2) * ceilDiv(dim(shapes.y, 3), 4)",
|
| 258 |
"scalarOutput": true
|
| 259 |
},
|
| 260 |
+
"bindings": ["x", "y_main"],
|
| 261 |
"dispatch": {
|
| 262 |
"x": "min(ceilDiv((dim(shapes.y, 0) * dim(shapes.y, 1) * dim(shapes.y, 2) * ceilDiv(dim(shapes.y, 3), 4)), (tunables.WORKGROUP_SIZE)), 65535)",
|
| 263 |
"y": "ceilDiv(ceilDiv((dim(shapes.y, 0) * dim(shapes.y, 1) * dim(shapes.y, 2) * ceilDiv(dim(shapes.y, 3), 4)), (tunables.WORKGROUP_SIZE)), 65535)",
|
|
|
|
| 269 |
{
|
| 270 |
"id": "nchw2d_w3s1_reuse",
|
| 271 |
"priority": 30,
|
| 272 |
+
"when": ["poolBaseOk", "ranks.x == 4", "kernelW == 3", "strideW == 1", "dilationW == 1", "effectivePadW == 1", "effectivePadRight == 1", "kernelH >= 1", "kernelH <= 3", "strideH == 1", "dilationH >= 1", "attrs.count_include_pad == 0", "attrs.ceil_mode == 0", "dim(shapes.x, 3) % 4 == 0", "dim(shapes.y, 2) == dim(shapes.x, 2) + effectivePadH + effectivePadBottom - ((kernelH - 1) * dilationH + 1) + 1", "dim(shapes.y, 3) == dim(shapes.x, 3)", "dim(shapes.y, 2) > 0", "dim(shapes.y, 3) > 0"],
|
| 273 |
+
"demoteWhen": ["narrowF32W3UnrolledPreferred", "variableSubgroup16To32 and dtypes.T == \"f16\""],
|
| 274 |
"passes": [
|
| 275 |
{
|
| 276 |
"id": "main",
|
|
|
|
| 279 |
"derive": {
|
| 280 |
"kernelHSpec": "kernelH",
|
| 281 |
"dilationHSpec": "dilationH",
|
| 282 |
+
"padTopSpec": "effectivePadH",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 283 |
"outWQuarter": "floor(dim(shapes.y, 3) / 4)"
|
| 284 |
},
|
| 285 |
"bindings": [
|
|
|
|
| 298 |
{
|
| 299 |
"id": "nchw2d_w3s1_reuse_tail",
|
| 300 |
"priority": 29,
|
| 301 |
+
"when": ["poolBaseOk", "ranks.x == 4", "kernelW == 3", "strideW == 1", "dilationW == 1", "effectivePadW == 1", "effectivePadRight == 1", "kernelH >= 1", "kernelH <= 3", "strideH == 1", "dilationH >= 1", "attrs.count_include_pad == 0", "attrs.ceil_mode == 0", "dim(shapes.x, 3) % 4 != 0", "dim(shapes.y, 2) == dim(shapes.x, 2) + effectivePadH + effectivePadBottom - ((kernelH - 1) * dilationH + 1) + 1", "dim(shapes.y, 3) == dim(shapes.x, 3)", "dim(shapes.y, 2) > 0", "dim(shapes.y, 3) > 0"],
|
| 302 |
"derive": { "outputElement": "dtypes.T" },
|
| 303 |
"passes": [
|
| 304 |
{
|
|
|
|
| 312 |
"strideWSpec": 1,
|
| 313 |
"dilationHSpec": "dilationH",
|
| 314 |
"dilationWSpec": 1,
|
| 315 |
+
"padTopSpec": "effectivePadH",
|
| 316 |
"padLeftSpec": 1,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 317 |
"outW4": "ceilDiv(dim(shapes.y, 3), 4)",
|
| 318 |
"count4": "dim(shapes.y, 0) * dim(shapes.y, 1) * dim(shapes.y, 2) * ceilDiv(dim(shapes.y, 3), 4)",
|
| 319 |
"scalarOutput": true
|
| 320 |
},
|
| 321 |
+
"bindings": ["x", "y_main"],
|
| 322 |
"dispatch": {
|
| 323 |
"x": "min(ceilDiv((dim(shapes.y, 0) * dim(shapes.y, 1) * dim(shapes.y, 2) * ceilDiv(dim(shapes.y, 3), 4)), (tunables.WORKGROUP_SIZE)), 65535)",
|
| 324 |
"y": "ceilDiv(ceilDiv((dim(shapes.y, 0) * dim(shapes.y, 1) * dim(shapes.y, 2) * ceilDiv(dim(shapes.y, 3), 4)), (tunables.WORKGROUP_SIZE)), 65535)",
|
|
|
|
| 331 |
"id": "nchw2d_separable",
|
| 332 |
"priority": 22,
|
| 333 |
"when": ["poolBaseOk", "ranks.x == 4", "ranks.y == 4", "dim(shapes.y, 2) == inferredOutH", "dim(shapes.y, 3) == inferredOutW", "dim(shapes.y, 2) > 0", "dim(shapes.y, 3) > 0", "kernelH > 1", "kernelW > 1", "kernelH * kernelW >= tunables.SEPARABLE_MIN_WINDOW", "strideH < kernelH", "wholeWindowDenominator", "separableFits"],
|
| 334 |
+
"derive": { "scalar": "dtypes.T" },
|
| 335 |
"intermediates": [{ "id": "tmp", "dtype": "float32", "shape": "[separableTmpElements]" }],
|
| 336 |
"passes": [
|
| 337 |
{
|
|
|
|
| 341 |
"derive": { "axisSpec": "\"w\"", "op": "\"avg\"", "windowArea": "kernelH * kernelW" },
|
| 342 |
"bindings": [
|
| 343 |
"x",
|
| 344 |
+
{ "name": "tmp", "elementType": "f32" },
|
| 345 |
{
|
| 346 |
"name": "params",
|
| 347 |
"struct": [
|
|
|
|
| 351 |
{ "name": "kernelW", "type": "u32", "value": "kernelW" },
|
| 352 |
{ "name": "strideW", "type": "u32", "value": "strideW" },
|
| 353 |
{ "name": "dilationW", "type": "u32", "value": "dilationW" },
|
| 354 |
+
{ "name": "padW", "type": "i32", "value": "effectivePadW" },
|
| 355 |
{ "name": "tmpCount", "type": "u32", "value": "separableTmpElements" }
|
| 356 |
]
|
| 357 |
}
|
|
|
|
| 379 |
{ "name": "kernelH", "type": "u32", "value": "kernelH" },
|
| 380 |
{ "name": "strideH", "type": "u32", "value": "strideH" },
|
| 381 |
{ "name": "dilationH", "type": "u32", "value": "dilationH" },
|
| 382 |
+
{ "name": "padH", "type": "i32", "value": "effectivePadH" },
|
| 383 |
{ "name": "count", "type": "u32", "value": "numel(shapes.y)" }
|
| 384 |
]
|
| 385 |
}
|
|
|
|
| 409 |
"strideWSpec": "strideW",
|
| 410 |
"dilationHSpec": "dilationH",
|
| 411 |
"dilationWSpec": "dilationW",
|
| 412 |
+
"padTopSpec": "effectivePadH",
|
| 413 |
+
"padLeftSpec": "effectivePadW",
|
| 414 |
"inH": "dim(shapes.x, 2)",
|
| 415 |
"inW": "dim(shapes.x, 3)",
|
| 416 |
"outH": "dim(shapes.y, 2)",
|
|
|
|
| 454 |
{ "name": "kernelW", "type": "u32", "value": "kernelW" },
|
| 455 |
{ "name": "strideW", "type": "u32", "value": "strideW" },
|
| 456 |
{ "name": "dilationW", "type": "u32", "value": "dilationW" },
|
| 457 |
+
{ "name": "padLeft", "type": "i32", "value": "effectivePadW" },
|
| 458 |
{ "name": "padRight", "type": "i32", "value": "effectivePadRight" },
|
| 459 |
{ "name": "countIncludePad", "type": "u32", "value": "attrs.count_include_pad" },
|
| 460 |
{ "name": "count", "type": "u32", "value": "numel(shapes.y)" }
|
|
|
|
| 475 |
"passes": [
|
| 476 |
{
|
| 477 |
"id": "main",
|
| 478 |
+
"name": "AveragePool.Nchw2d",
|
| 479 |
"shader": "pool-window-nd.wgsl.jinja",
|
| 480 |
"derive": { "op": "\"average\"", "spatialRankSpec": 2 },
|
| 481 |
"bindings": [
|
|
|
|
| 495 |
{ "name": "strideW", "type": "u32", "value": "strideW" },
|
| 496 |
{ "name": "dilationH", "type": "u32", "value": "dilationH" },
|
| 497 |
{ "name": "dilationW", "type": "u32", "value": "dilationW" },
|
| 498 |
+
{ "name": "padTop", "type": "i32", "value": "effectivePadH" },
|
| 499 |
+
{ "name": "padLeft", "type": "i32", "value": "effectivePadW" },
|
| 500 |
{ "name": "padBottom", "type": "i32", "value": "effectivePadBottom" },
|
| 501 |
{ "name": "padRight", "type": "i32", "value": "effectivePadRight" },
|
| 502 |
{ "name": "countIncludePad", "type": "u32", "value": "attrs.count_include_pad" },
|
|
|
|
| 545 |
{ "name": "dilationD", "type": "u32", "value": "dilationD" },
|
| 546 |
{ "name": "dilationH", "type": "u32", "value": "dilationH" },
|
| 547 |
{ "name": "dilationW", "type": "u32", "value": "dilationW" },
|
| 548 |
+
{ "name": "padFront", "type": "i32", "value": "effectivePadD" },
|
| 549 |
+
{ "name": "padTop", "type": "i32", "value": "effectivePadH" },
|
| 550 |
+
{ "name": "padLeft", "type": "i32", "value": "effectivePadW" },
|
| 551 |
{ "name": "padBack", "type": "i32", "value": "effectivePadBack" },
|
| 552 |
{ "name": "padBottom", "type": "i32", "value": "effectivePadBottom" },
|
| 553 |
{ "name": "padRight", "type": "i32", "value": "effectivePadRight" },
|
|
|
|
| 567 |
{
|
| 568 |
"id": "nchw2d_k7s2_reuse",
|
| 569 |
"priority": 36,
|
| 570 |
+
"when": ["poolBaseOk", "ranks.x == 4", "kernelH == 7", "kernelW == 7", "strideH == 2", "strideW == 2", "dilationH == 1", "dilationW == 1", "effectivePadH == 3", "effectivePadBottom == 3", "effectivePadW == 3", "effectivePadRight == 3", "attrs.count_include_pad == 0", "attrs.ceil_mode == 0", "dim(shapes.y, 2) == inferredOutH", "dim(shapes.y, 3) == inferredOutW", "dim(shapes.y, 3) % 4 == 0", "dim(shapes.y, 2) > 0", "dim(shapes.y, 3) > 0"],
|
| 571 |
"derive": { "outputElement": "\"vec4<\" ~ dtypes.T ~ \">\"", "vectorScalar": "\"vec4<\" ~ dtypes.T ~ \">\"" },
|
| 572 |
"passes": [
|
| 573 |
{
|
|
|
|
| 583 |
"dilationWSpec": 1,
|
| 584 |
"padTopSpec": 3,
|
| 585 |
"padLeftSpec": 3,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 586 |
"outW4": "dim(shapes.y, 3) / 4",
|
| 587 |
"count4": "numel(shapes.y) / 4"
|
| 588 |
},
|
| 589 |
+
"bindings": ["x", "y_main"],
|
| 590 |
"dispatch": {
|
| 591 |
"x": "min(ceilDiv((numel(shapes.y) / 4), (tunables.WORKGROUP_SIZE)), 65535)",
|
| 592 |
"y": "ceilDiv(ceilDiv((numel(shapes.y) / 4), (tunables.WORKGROUP_SIZE)), 65535)",
|
|
|
|
| 598 |
{
|
| 599 |
"id": "nchw2d_k7s1_reuse",
|
| 600 |
"priority": 35,
|
| 601 |
+
"when": ["poolBaseOk", "ranks.x == 4", "kernelH == 7", "kernelW == 7", "strideH == 1", "strideW == 1", "dilationH == 1", "dilationW == 1", "effectivePadH == 3", "effectivePadBottom == 3", "effectivePadW == 3", "effectivePadRight == 3", "attrs.count_include_pad == 0", "attrs.ceil_mode == 0", "dim(shapes.x, 3) % 4 == 0", "dim(shapes.y, 2) == dim(shapes.x, 2)", "dim(shapes.y, 3) == dim(shapes.x, 3)", "dim(shapes.y, 2) > 0", "dim(shapes.y, 3) > 0"],
|
| 602 |
"derive": { "outputElement": "\"vec4<\" ~ dtypes.T ~ \">\"", "vectorScalar": "\"vec4<\" ~ dtypes.T ~ \">\"" },
|
| 603 |
"passes": [
|
| 604 |
{
|
|
|
|
| 614 |
"dilationWSpec": 1,
|
| 615 |
"padTopSpec": 3,
|
| 616 |
"padLeftSpec": 3,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 617 |
"outW4": "dim(shapes.y, 3) / 4",
|
| 618 |
"count4": "numel(shapes.y) / 4"
|
| 619 |
},
|
| 620 |
+
"bindings": ["x", "y_main"],
|
| 621 |
"dispatch": {
|
| 622 |
"x": "min(ceilDiv((numel(shapes.y) / 4), (tunables.WORKGROUP_SIZE)), 65535)",
|
| 623 |
"y": "ceilDiv(ceilDiv((numel(shapes.y) / 4), (tunables.WORKGROUP_SIZE)), 65535)",
|
build/webgpu/metadata.json
CHANGED
|
@@ -1,28 +1,32 @@
|
|
| 1 |
{
|
| 2 |
"name": "ai.onnx.AveragePool",
|
| 3 |
-
"id": "
|
| 4 |
"version": 1,
|
| 5 |
"license": "Apache-2.0",
|
| 6 |
"backend": { "type": "webgpu" },
|
| 7 |
"digest": {
|
| 8 |
"algorithm": "sha256",
|
| 9 |
"files": {
|
| 10 |
-
"average-pool2d-nchw-horizontal-reuse.wgsl.jinja": "
|
| 11 |
-
"average-pool2d-nchw-w3s1-reuse.wgsl.jinja": "
|
| 12 |
-
"bench.json": "
|
| 13 |
-
"manifest.json": "
|
| 14 |
-
"pool-global-reduction.wgsl.jinja": "
|
| 15 |
-
"pool-window-nd.wgsl.jinja": "
|
| 16 |
-
"pool-window-
|
|
|
|
| 17 |
"pool2d-nchw-separable.wgsl.jinja": "GgafQWV6Pn5SqSn5gMns0EJEHGqk2WkdCdVurt3MgA8=",
|
| 18 |
-
"test.json": "
|
| 19 |
}
|
| 20 |
},
|
| 21 |
-
"provenance": { "kernel": { "sha": "
|
| 22 |
"webgpu": {
|
| 23 |
-
"manifestSpec": "2.
|
| 24 |
"variants": {
|
| 25 |
"global_window_parallel": ["pool-global-reduction.wgsl.jinja"],
|
|
|
|
|
|
|
|
|
|
| 26 |
"nchw2d_k7s1_reuse_tail": ["average-pool2d-nchw-horizontal-reuse.wgsl.jinja"],
|
| 27 |
"nchw2d_w3s1_reuse": ["average-pool2d-nchw-w3s1-reuse.wgsl.jinja"],
|
| 28 |
"nchw2d_w3s1_reuse_tail": ["average-pool2d-nchw-horizontal-reuse.wgsl.jinja"],
|
|
|
|
| 1 |
{
|
| 2 |
"name": "ai.onnx.AveragePool",
|
| 3 |
+
"id": "_ai_onnx_averagepool_webgpu_6441176",
|
| 4 |
"version": 1,
|
| 5 |
"license": "Apache-2.0",
|
| 6 |
"backend": { "type": "webgpu" },
|
| 7 |
"digest": {
|
| 8 |
"algorithm": "sha256",
|
| 9 |
"files": {
|
| 10 |
+
"average-pool2d-nchw-horizontal-reuse.wgsl.jinja": "heeYKFbnmrXdEohH7tUG5PzItrk5yPz3hEgnuNihBWg=",
|
| 11 |
+
"average-pool2d-nchw-w3s1-reuse.wgsl.jinja": "D4razLs8qLkk5zubCU+wUa9OVgFisNZ95cGwXipOvwI=",
|
| 12 |
+
"bench.json": "ZvF9gqBTship90W+TiMfWNyrdsJYyEAwZAdZ5r6/vc0=",
|
| 13 |
+
"manifest.json": "/fTFl6NMtKYnbxuSbihY039sqo+P8xhGXVjFtj2gA6c=",
|
| 14 |
+
"pool-global-reduction.wgsl.jinja": "uCrSccgj/Fibd866kxpiYkprR8g6q1vofgQZZ/oxGkE=",
|
| 15 |
+
"pool-window-nd.wgsl.jinja": "QCtdlEJy4LmSU9g7oUOR0YbZ9cZuxH6P1ERT3m7YACY=",
|
| 16 |
+
"pool-window-reduction.wgsl.jinja": "Jv5CY3dfoWUzgoxb4H35nlKspu9GKe10Z1bRjGQ4DPk=",
|
| 17 |
+
"pool-window-unroll.wgsl.jinja": "UWhk8iANx6euYlJV5W31BP0D4FaJEC+lV/3y95T2wOQ=",
|
| 18 |
"pool2d-nchw-separable.wgsl.jinja": "GgafQWV6Pn5SqSn5gMns0EJEHGqk2WkdCdVurt3MgA8=",
|
| 19 |
+
"test.json": "zw4aG7ZsPYmGpRG2g8Yi++TwV5Fvas/zLR5Gesmxys8="
|
| 20 |
}
|
| 21 |
},
|
| 22 |
+
"provenance": { "kernel": { "sha": "6fdf6301e2bbcc2f03bf1eaf493b7ad55ef33afc", "dirty": false } },
|
| 23 |
"webgpu": {
|
| 24 |
+
"manifestSpec": "2.1",
|
| 25 |
"variants": {
|
| 26 |
"global_window_parallel": ["pool-global-reduction.wgsl.jinja"],
|
| 27 |
+
"window_parallel_ncl1d": ["pool-window-reduction.wgsl.jinja"],
|
| 28 |
+
"window_parallel_nchw2d": ["pool-window-reduction.wgsl.jinja"],
|
| 29 |
+
"window_parallel_ncdhw3d": ["pool-window-reduction.wgsl.jinja"],
|
| 30 |
"nchw2d_k7s1_reuse_tail": ["average-pool2d-nchw-horizontal-reuse.wgsl.jinja"],
|
| 31 |
"nchw2d_w3s1_reuse": ["average-pool2d-nchw-w3s1-reuse.wgsl.jinja"],
|
| 32 |
"nchw2d_w3s1_reuse_tail": ["average-pool2d-nchw-horizontal-reuse.wgsl.jinja"],
|
build/webgpu/pool-global-reduction.wgsl.jinja
CHANGED
|
@@ -22,13 +22,11 @@ var<workgroup> wg_partials: array<f32, WG>;
|
|
| 22 |
var<workgroup> wg_tree: array<f32, WG>;
|
| 23 |
{% endif %}
|
| 24 |
|
| 25 |
-
|
| 26 |
@compute @workgroup_size(WG)
|
| 27 |
fn main(@builtin(workgroup_id) wid: vec3<u32>,
|
| 28 |
-
@builtin(local_invocation_id) lid: vec3<u32>
|
| 29 |
-
|
| 30 |
-
@builtin(subgroup_size) sg_size: u32
|
| 31 |
-
{%- endif %}) {
|
| 32 |
let plane = wid.x;
|
| 33 |
let tid = lid.x;
|
| 34 |
var partial = 0.0;
|
|
@@ -50,32 +48,35 @@ fn main(@builtin(workgroup_id) wid: vec3<u32>,
|
|
| 50 |
{% endif %}
|
| 51 |
|
| 52 |
{% if useSubgroups %}
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
|
|
|
|
|
|
| 75 |
}
|
|
|
|
|
|
|
|
|
|
| 76 |
if (tid == 0u) {
|
| 77 |
-
y[plane] = {{ scalar }}(total / f32(params.spatial));
|
| 78 |
-
}
|
| 79 |
{% else %}
|
| 80 |
// No-subgroups fallback: full workgroup-tree reduction of the per-thread partials.
|
| 81 |
wg_tree[tid] = partial;
|
|
@@ -88,7 +89,7 @@ fn main(@builtin(workgroup_id) wid: vec3<u32>,
|
|
| 88 |
}
|
| 89 |
if (tid == 0u) {
|
| 90 |
let total = wg_tree[0];
|
|
|
|
| 91 |
y[plane] = {{ scalar }}(total / f32(params.spatial));
|
| 92 |
}
|
| 93 |
-
{% endif %}
|
| 94 |
}
|
|
|
|
| 22 |
var<workgroup> wg_tree: array<f32, WG>;
|
| 23 |
{% endif %}
|
| 24 |
|
|
|
|
| 25 |
@compute @workgroup_size(WG)
|
| 26 |
fn main(@builtin(workgroup_id) wid: vec3<u32>,
|
| 27 |
+
@builtin(local_invocation_id) lid: vec3<u32>{% if useSubgroups %},
|
| 28 |
+
@builtin(subgroup_invocation_id) sg_lane: u32,
|
| 29 |
+
@builtin(subgroup_size) sg_size: u32{% endif %}) {
|
|
|
|
| 30 |
let plane = wid.x;
|
| 31 |
let tid = lid.x;
|
| 32 |
var partial = 0.0;
|
|
|
|
| 48 |
{% endif %}
|
| 49 |
|
| 50 |
{% if useSubgroups %}
|
| 51 |
+
{% filter indent(2, true) %}
|
| 52 |
+
var total = subgroupAdd(partial);
|
| 53 |
+
// Cross-subgroup fold that assumes nothing about which invocations share a
|
| 54 |
+
// subgroup or how many subgroups there are (it does require the uniform
|
| 55 |
+
// control flow this entry point already has): every invocation owns the slot
|
| 56 |
+
// at its own index, the elected lane
|
| 57 |
+
// publishes its subgroup partial there and every other lane publishes the
|
| 58 |
+
// reduction identity. Each subgroup then folds all WG slots — lane `sg_lane`
|
| 59 |
+
// walks slots sg_lane, sg_lane + sg_size, ... — and one more collective merges
|
| 60 |
+
// the lane partials, so every slot is merged exactly once at any legal width.
|
| 61 |
+
// The coordinates are the BUILTINS, never `subgroupExclusiveAdd(1u)` /
|
| 62 |
+
// `subgroupAdd(1u)`: those agree with them under this contract, but a driver
|
| 63 |
+
// in the wild answers a claim derived from them with zero. A one-subgroup
|
| 64 |
+
// workgroup skips shared memory entirely; that test reads the `subgroup_size`
|
| 65 |
+
// builtin, which is uniform, because a collective's result is not uniform to
|
| 66 |
+
// WGSL's analysis and may not guard a barrier.
|
| 67 |
+
if (sg_size != WG) {
|
| 68 |
+
let rank = sg_lane;
|
| 69 |
+
let lanes = sg_size;
|
| 70 |
+
wg_partials[tid] = select(0.0, total, rank == 0u);
|
| 71 |
+
workgroupBarrier();
|
| 72 |
+
var acc = 0.0;
|
| 73 |
+
for (var i = rank; i < WG; i = i + lanes) {
|
| 74 |
+
acc = acc + wg_partials[i];
|
| 75 |
}
|
| 76 |
+
total = subgroupAdd(acc);
|
| 77 |
+
}
|
| 78 |
+
{% endfilter %}
|
| 79 |
if (tid == 0u) {
|
|
|
|
|
|
|
| 80 |
{% else %}
|
| 81 |
// No-subgroups fallback: full workgroup-tree reduction of the per-thread partials.
|
| 82 |
wg_tree[tid] = partial;
|
|
|
|
| 89 |
}
|
| 90 |
if (tid == 0u) {
|
| 91 |
let total = wg_tree[0];
|
| 92 |
+
{% endif %}
|
| 93 |
y[plane] = {{ scalar }}(total / f32(params.spatial));
|
| 94 |
}
|
|
|
|
| 95 |
}
|
build/webgpu/pool-window-nd.wgsl.jinja
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
{{ env.wgsl.resourceDeclarations }}
|
| 2 |
|
| 3 |
// Direct spatial-pooling traversal for a channels-first tensor.
|
| 4 |
@compute @workgroup_size({{ tunables.WORKGROUP_SIZE }})
|
| 5 |
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
| 6 |
-
|
| 7 |
-
if (index >= params.count) { return; }
|
| 8 |
|
| 9 |
let ow = index % params.outW;
|
| 10 |
var t = index / params.outW;
|
|
|
|
| 1 |
+
{% macro flat_index_2d(workgroupSize, name="i", bound="params.count", guardInline=false) %}
|
| 2 |
+
{% set wgTerm = workgroupSize ~ "u" if workgroupSize is number else workgroupSize %}
|
| 3 |
+
// 2D-folded flat index: gid.y carries the high bits past the dispatch's
|
| 4 |
+
// per-axis workgroup fold width.
|
| 5 |
+
let {{ name }} = gid.x + gid.y * {{ DISPATCH_FOLD_WIDTH }}u * {{ wgTerm }};
|
| 6 |
+
if ({{ name }} >= {{ bound }}) { return; }{% endmacro %}
|
| 7 |
{{ env.wgsl.resourceDeclarations }}
|
| 8 |
|
| 9 |
// Direct spatial-pooling traversal for a channels-first tensor.
|
| 10 |
@compute @workgroup_size({{ tunables.WORKGROUP_SIZE }})
|
| 11 |
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
| 12 |
+
{{ flat_index_2d(tunables.WORKGROUP_SIZE, "index", guardInline=true) }}
|
|
|
|
| 13 |
|
| 14 |
let ow = index % params.outW;
|
| 15 |
var t = index / params.outW;
|
build/webgpu/pool-window-reduction.wgsl.jinja
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{% set needsCount = op == "max" or (op == "average" and not countIncludePad) %}
|
| 2 |
+
{% if useSubgroups %}
|
| 3 |
+
enable subgroups;
|
| 4 |
+
{% endif %}
|
| 5 |
+
{{ env.wgsl.resourceDeclarations }}
|
| 6 |
+
|
| 7 |
+
// Workgroup-cooperative windowed pooling: one workgroup reduces the kernel
|
| 8 |
+
// window of ONE output element. The serial route gives each output element a
|
| 9 |
+
// single invocation that loops the whole window, so its only parallelism is the
|
| 10 |
+
// output element count; when that count launches too few workgroups and the window is
|
| 11 |
+
// long, the window itself is the parallelism worth spending. Threads here stride
|
| 12 |
+
// the flattened tap index [kD x] kH x kW, each tap resolving its own padded,
|
| 13 |
+
// strided and dilated input coordinate, then combine the per-thread partials.
|
| 14 |
+
// With subgroups: a subgroup collective, then one shared-memory slot per
|
| 15 |
+
// invocation (the subgroup partial from its elected lane, the identity from
|
| 16 |
+
// every other lane) that every subgroup folds. Without subgroups, a full
|
| 17 |
+
// workgroup tree combines the per-thread partials.
|
| 18 |
+
{% if countIncludePad %}
|
| 19 |
+
// count_include_pad == 1 with ceil_mode == 0 makes every tap of every window
|
| 20 |
+
// land inside the padded extent, so the divisor is the baked tap count and no
|
| 21 |
+
// second reduction is needed. The tree changes the association of additions.
|
| 22 |
+
{% else %}
|
| 23 |
+
// count_include_pad == 0 divides by the in-bounds tap count, which is reduced
|
| 24 |
+
// across the workgroup alongside the sum. An output whose window is entirely
|
| 25 |
+
// out of bounds writes 0, matching the serial route. The tree changes the
|
| 26 |
+
// association of additions.
|
| 27 |
+
{% endif %}
|
| 28 |
+
const WG: u32 = {{ workgroupSizeSpec }}u;
|
| 29 |
+
const KW: u32 = {{ kernelWSpec }}u;
|
| 30 |
+
{% if spatialRankSpec >= 2 %}
|
| 31 |
+
const KH: u32 = {{ kernelHSpec }}u;
|
| 32 |
+
{% endif %}
|
| 33 |
+
// Flattened tap count of the whole window; the loop bound and, for
|
| 34 |
+
// count_include_pad == 1, the divisor.
|
| 35 |
+
const TAPS: u32 = {{ kernelDSpec * kernelHSpec * kernelWSpec }}u;
|
| 36 |
+
// One slot per invocation: the cross-subgroup fold below indexes by
|
| 37 |
+
// local_invocation_id, never by a subgroup ordinal, so no subgroup width or
|
| 38 |
+
// partition can overflow or alias it.
|
| 39 |
+
var<workgroup> wg_partials: array<f32, WG>;
|
| 40 |
+
{% if needsCount %}
|
| 41 |
+
var<workgroup> wg_counts: array<f32, WG>;
|
| 42 |
+
{% endif %}
|
| 43 |
+
|
| 44 |
+
@compute @workgroup_size(WG)
|
| 45 |
+
fn main(@builtin(workgroup_id) wid: vec3<u32>,
|
| 46 |
+
@builtin(local_invocation_id) lid: vec3<u32>{% if useSubgroups %},
|
| 47 |
+
@builtin(subgroup_invocation_id) sg_lane: u32,
|
| 48 |
+
@builtin(subgroup_size) sg_size: u32{% endif %}) {
|
| 49 |
+
// One workgroup per output element: the dispatch is exactly numel(y), so no
|
| 50 |
+
// bounds guard is needed here.
|
| 51 |
+
let index = wid.x;
|
| 52 |
+
let tid = lid.x;
|
| 53 |
+
|
| 54 |
+
let ow = index % params.outW;
|
| 55 |
+
var t = index / params.outW;
|
| 56 |
+
{% if spatialRankSpec >= 2 %}
|
| 57 |
+
let oh = t % params.outH;
|
| 58 |
+
t /= params.outH;
|
| 59 |
+
{% endif %}
|
| 60 |
+
{% if spatialRankSpec == 3 %}
|
| 61 |
+
let od = t % params.outD;
|
| 62 |
+
t /= params.outD;
|
| 63 |
+
{% endif %}
|
| 64 |
+
let channel = t % params.channels;
|
| 65 |
+
let batch = t / params.channels;
|
| 66 |
+
|
| 67 |
+
let startW = i32(ow * params.strideW) - params.padW;
|
| 68 |
+
{% if spatialRankSpec >= 2 %}
|
| 69 |
+
let startH = i32(oh * params.strideH) - params.padH;
|
| 70 |
+
{% endif %}
|
| 71 |
+
{% if spatialRankSpec == 3 %}
|
| 72 |
+
let startD = i32(od * params.strideD) - params.padD;
|
| 73 |
+
{% endif %}
|
| 74 |
+
{% if spatialRankSpec == 1 %}
|
| 75 |
+
let planeBase = (batch * params.channels + channel) * params.inW;
|
| 76 |
+
{% elif spatialRankSpec == 2 %}
|
| 77 |
+
let planeBase = (batch * params.channels + channel) * params.inH * params.inW;
|
| 78 |
+
{% else %}
|
| 79 |
+
let planeBase = (batch * params.channels + channel) * params.inD * params.inH * params.inW;
|
| 80 |
+
{% endif %}
|
| 81 |
+
|
| 82 |
+
var partial = 0.0;
|
| 83 |
+
{% if needsCount %}
|
| 84 |
+
var counted = 0.0;
|
| 85 |
+
{% endif %}
|
| 86 |
+
for (var tap = tid; tap < TAPS; tap = tap + WG) {
|
| 87 |
+
let kw = tap % KW;
|
| 88 |
+
{% if spatialRankSpec >= 2 %}
|
| 89 |
+
let rest = tap / KW;
|
| 90 |
+
let kh = rest % KH;
|
| 91 |
+
{% endif %}
|
| 92 |
+
{% if spatialRankSpec == 3 %}
|
| 93 |
+
let kd = rest / KH;
|
| 94 |
+
{% endif %}
|
| 95 |
+
let iw = startW + i32(kw * params.dilationW);
|
| 96 |
+
{% if spatialRankSpec >= 2 %}
|
| 97 |
+
let ih = startH + i32(kh * params.dilationH);
|
| 98 |
+
{% endif %}
|
| 99 |
+
{% if spatialRankSpec == 3 %}
|
| 100 |
+
let id = startD + i32(kd * params.dilationD);
|
| 101 |
+
{% endif %}
|
| 102 |
+
{% if spatialRankSpec == 1 %}
|
| 103 |
+
let inBounds = iw >= 0 && iw < i32(params.inW);
|
| 104 |
+
{% elif spatialRankSpec == 2 %}
|
| 105 |
+
let inBounds = iw >= 0 && iw < i32(params.inW) && ih >= 0 && ih < i32(params.inH);
|
| 106 |
+
{% else %}
|
| 107 |
+
let inBounds = iw >= 0 && iw < i32(params.inW) && ih >= 0 && ih < i32(params.inH) && id >= 0 && id < i32(params.inD);
|
| 108 |
+
{% endif %}
|
| 109 |
+
if (inBounds) {
|
| 110 |
+
{% if spatialRankSpec == 1 %}
|
| 111 |
+
let value = f32(x[planeBase + u32(iw)]);
|
| 112 |
+
{% elif spatialRankSpec == 2 %}
|
| 113 |
+
let value = f32(x[planeBase + u32(ih) * params.inW + u32(iw)]);
|
| 114 |
+
{% else %}
|
| 115 |
+
let value = f32(x[planeBase + (u32(id) * params.inH + u32(ih)) * params.inW + u32(iw)]);
|
| 116 |
+
{% endif %}
|
| 117 |
+
partial = partial + value;
|
| 118 |
+
{% if needsCount %}
|
| 119 |
+
counted = counted + 1.0;
|
| 120 |
+
{% endif %}
|
| 121 |
+
}
|
| 122 |
+
}
|
| 123 |
+
|
| 124 |
+
{% if useSubgroups %}
|
| 125 |
+
{% filter indent(2, true) %}
|
| 126 |
+
var total = subgroupAdd(partial);
|
| 127 |
+
{% if needsCount %}
|
| 128 |
+
var countTotal = subgroupAdd(counted);
|
| 129 |
+
{% endif %}
|
| 130 |
+
// Cross-subgroup fold that assumes nothing about which invocations share a
|
| 131 |
+
// subgroup or how many subgroups there are (it does require the uniform
|
| 132 |
+
// control flow this entry point already has): every invocation owns the slot
|
| 133 |
+
// at its own index, the elected lane
|
| 134 |
+
// publishes its subgroup partial there and every other lane publishes the
|
| 135 |
+
// reduction identity. Each subgroup then folds all WG slots — lane `sg_lane`
|
| 136 |
+
// walks slots sg_lane, sg_lane + sg_size, ... — and one more collective merges
|
| 137 |
+
// the lane partials, so every slot is merged exactly once at any legal width.
|
| 138 |
+
// The coordinates are the BUILTINS, never `subgroupExclusiveAdd(1u)` /
|
| 139 |
+
// `subgroupAdd(1u)`: those agree with them under this contract, but a driver
|
| 140 |
+
// in the wild answers a claim derived from them with zero. A one-subgroup
|
| 141 |
+
// workgroup skips shared memory entirely; that test reads the `subgroup_size`
|
| 142 |
+
// builtin, which is uniform, because a collective's result is not uniform to
|
| 143 |
+
// WGSL's analysis and may not guard a barrier.
|
| 144 |
+
if (sg_size != WG) {
|
| 145 |
+
let rank = sg_lane;
|
| 146 |
+
let lanes = sg_size;
|
| 147 |
+
wg_partials[tid] = select(0.0, total, rank == 0u);
|
| 148 |
+
{% if needsCount %}
|
| 149 |
+
wg_counts[tid] = select(0.0, countTotal, rank == 0u);
|
| 150 |
+
{% endif %}
|
| 151 |
+
workgroupBarrier();
|
| 152 |
+
var acc = 0.0;
|
| 153 |
+
{% if needsCount %}
|
| 154 |
+
var countAcc = 0.0;
|
| 155 |
+
{% endif %}
|
| 156 |
+
for (var i = rank; i < WG; i = i + lanes) {
|
| 157 |
+
acc = acc + wg_partials[i];
|
| 158 |
+
{% if needsCount %}
|
| 159 |
+
countAcc = countAcc + wg_counts[i];
|
| 160 |
+
{% endif %}
|
| 161 |
+
}
|
| 162 |
+
total = subgroupAdd(acc);
|
| 163 |
+
{% if needsCount %}
|
| 164 |
+
countTotal = subgroupAdd(countAcc);
|
| 165 |
+
{% endif %}
|
| 166 |
+
}
|
| 167 |
+
{% endfilter %}
|
| 168 |
+
{% else %}
|
| 169 |
+
// No-subgroups fallback: full workgroup-tree reduction of the per-thread
|
| 170 |
+
// partials, carrying the unpaired entry forward for odd active widths.
|
| 171 |
+
wg_partials[tid] = partial;
|
| 172 |
+
{% if needsCount %}
|
| 173 |
+
wg_counts[tid] = counted;
|
| 174 |
+
{% endif %}
|
| 175 |
+
workgroupBarrier();
|
| 176 |
+
for (var liveCount = WG; liveCount > 1u; liveCount = (liveCount + 1u) / 2u) {
|
| 177 |
+
let step = (liveCount + 1u) / 2u;
|
| 178 |
+
if (tid + step < liveCount) {
|
| 179 |
+
wg_partials[tid] = wg_partials[tid] + wg_partials[tid + step];
|
| 180 |
+
{% if needsCount %}
|
| 181 |
+
wg_counts[tid] = wg_counts[tid] + wg_counts[tid + step];
|
| 182 |
+
{% endif %}
|
| 183 |
+
}
|
| 184 |
+
workgroupBarrier();
|
| 185 |
+
}
|
| 186 |
+
let total = wg_partials[0];
|
| 187 |
+
{% if needsCount %}
|
| 188 |
+
let countTotal = wg_counts[0];
|
| 189 |
+
{% endif %}
|
| 190 |
+
{% endif %}
|
| 191 |
+
if (tid == 0u) {
|
| 192 |
+
{% if countIncludePad %}
|
| 193 |
+
y[index] = {{ scalar }}(total / f32(TAPS));
|
| 194 |
+
{% else %}
|
| 195 |
+
y[index] = {{ scalar }}(select(0.0, total / countTotal, countTotal > 0.0));
|
| 196 |
+
{% endif %}
|
| 197 |
+
}
|
| 198 |
+
}
|
build/webgpu/pool-window-unroll.wgsl.jinja
CHANGED
|
@@ -1,8 +1,13 @@
|
|
| 1 |
// Compile-time-unrolled 2D NCHW pooling for small windows. Accumulation remains
|
| 2 |
// kh-major/kw-minor, matching the loop-based implementations.
|
| 3 |
-
{%
|
| 4 |
-
{% set
|
| 5 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
{{ env.wgsl.resourceDeclarations }}
|
| 7 |
|
| 8 |
const OUT_W: u32 = {{ outW }}u;
|
|
@@ -24,11 +29,7 @@ const PAD_RIGHT: i32 = {{ padRightSpec }};
|
|
| 24 |
fn main(
|
| 25 |
@builtin(global_invocation_id) gid: vec3<u32>
|
| 26 |
) {
|
| 27 |
-
|
| 28 |
-
let index = gid.x + gid.y * {{ DISPATCH_FOLD_WIDTH }}u * {{ tunables.WORKGROUP_SIZE }}u;
|
| 29 |
-
if (index >= params.count) {
|
| 30 |
-
return;
|
| 31 |
-
}
|
| 32 |
|
| 33 |
let ow = index % OUT_W;
|
| 34 |
var plane = index / OUT_W;
|
|
@@ -58,8 +59,8 @@ fn main(
|
|
| 58 |
{% endfor %}
|
| 59 |
}
|
| 60 |
{% endfor %}
|
| 61 |
-
|
| 62 |
{% if op == "average" and countIncludePad %}
|
|
|
|
| 63 |
var denominator = 0u;
|
| 64 |
{% for kh in range(kernelHSpec) %}
|
| 65 |
if (ih_{{ kh }} >= -PAD_TOP && ih_{{ kh }} < IN_H + PAD_BOTTOM) {
|
|
@@ -71,6 +72,7 @@ fn main(
|
|
| 71 |
}
|
| 72 |
{% endfor %}
|
| 73 |
{% else %}
|
|
|
|
| 74 |
let denominator = seen;
|
| 75 |
{% endif %}
|
| 76 |
|
|
|
|
| 1 |
// Compile-time-unrolled 2D NCHW pooling for small windows. Accumulation remains
|
| 2 |
// kh-major/kw-minor, matching the loop-based implementations.
|
| 3 |
+
{% macro flat_index_2d(workgroupSize, name="i", bound="params.count", guardInline=false) %}
|
| 4 |
+
{% set wgTerm = workgroupSize ~ "u" if workgroupSize is number else workgroupSize %}
|
| 5 |
+
// 2D-folded flat index: gid.y carries the high bits past the dispatch's
|
| 6 |
+
// per-axis workgroup fold width.
|
| 7 |
+
let {{ name }} = gid.x + gid.y * {{ DISPATCH_FOLD_WIDTH }}u * {{ wgTerm }};
|
| 8 |
+
if ({{ name }} >= {{ bound }}) {
|
| 9 |
+
return;
|
| 10 |
+
}{% endmacro %}
|
| 11 |
{{ env.wgsl.resourceDeclarations }}
|
| 12 |
|
| 13 |
const OUT_W: u32 = {{ outW }}u;
|
|
|
|
| 29 |
fn main(
|
| 30 |
@builtin(global_invocation_id) gid: vec3<u32>
|
| 31 |
) {
|
| 32 |
+
{{ flat_index_2d(tunables.WORKGROUP_SIZE, "index") }}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
|
| 34 |
let ow = index % OUT_W;
|
| 35 |
var plane = index / OUT_W;
|
|
|
|
| 59 |
{% endfor %}
|
| 60 |
}
|
| 61 |
{% endfor %}
|
|
|
|
| 62 |
{% if op == "average" and countIncludePad %}
|
| 63 |
+
|
| 64 |
var denominator = 0u;
|
| 65 |
{% for kh in range(kernelHSpec) %}
|
| 66 |
if (ih_{{ kh }} >= -PAD_TOP && ih_{{ kh }} < IN_H + PAD_BOTTOM) {
|
|
|
|
| 72 |
}
|
| 73 |
{% endfor %}
|
| 74 |
{% else %}
|
| 75 |
+
|
| 76 |
let denominator = seen;
|
| 77 |
{% endif %}
|
| 78 |
|
build/webgpu/test.json
CHANGED
|
@@ -93,7 +93,7 @@
|
|
| 93 |
"provenance": {
|
| 94 |
"source": "onnxruntime/test/providers/cpu/nn/pool_op_test.cc",
|
| 95 |
"test": "PoolTest.AveragePool",
|
| 96 |
-
"notes": "A 4x1
|
| 97 |
},
|
| 98 |
"attrs": { "count_include_pad": 0, "kernel_shape": [4, 1], "strides": [1, 1], "pads": [0, 0, 0, 0] },
|
| 99 |
"inputs": {
|
|
@@ -985,7 +985,7 @@
|
|
| 985 |
{
|
| 986 |
"name": "f16_generic_global7x7_b1c256_nchw",
|
| 987 |
"provenance": {
|
| 988 |
-
"notes": "
|
| 989 |
},
|
| 990 |
"attrs": { "count_include_pad": 0, "kernel_shape": [7, 7], "strides": [1, 1], "pads": [0, 0, 0, 0] },
|
| 991 |
"inputs": {
|
|
@@ -1000,7 +1000,7 @@
|
|
| 1000 |
{
|
| 1001 |
"name": "f16_generic_count_include_pad_k5s1p2_b1c32_16x16",
|
| 1002 |
"provenance": {
|
| 1003 |
-
"notes": "A
|
| 1004 |
},
|
| 1005 |
"attrs": { "count_include_pad": 1, "kernel_shape": [5, 5], "strides": [1, 1], "pads": [2, 2, 2, 2] },
|
| 1006 |
"inputs": {
|
|
@@ -1129,7 +1129,7 @@
|
|
| 1129 |
{
|
| 1130 |
"name": "k7s2p3_horizontal_reuse_f32",
|
| 1131 |
"provenance": {
|
| 1132 |
-
"notes": "
|
| 1133 |
},
|
| 1134 |
"attrs": { "count_include_pad": 0, "kernel_shape": [7, 7], "strides": [2, 2], "pads": [3, 3, 3, 3] },
|
| 1135 |
"inputs": {
|
|
@@ -1170,6 +1170,288 @@
|
|
| 1170 |
}
|
| 1171 |
},
|
| 1172 |
"outputs": { "y": { "dtype": "float32", "shape": [1, 2, 8, 10], "tolerance": 0.00001 } }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1173 |
}
|
| 1174 |
]
|
| 1175 |
}
|
|
|
|
| 93 |
"provenance": {
|
| 94 |
"source": "onnxruntime/test/providers/cpu/nn/pool_op_test.cc",
|
| 95 |
"test": "PoolTest.AveragePool",
|
| 96 |
+
"notes": "A 4x1 pooling window checks a valid subnormal average over a non-square reduction."
|
| 97 |
},
|
| 98 |
"attrs": { "count_include_pad": 0, "kernel_shape": [4, 1], "strides": [1, 1], "pads": [0, 0, 0, 0] },
|
| 99 |
"inputs": {
|
|
|
|
| 985 |
{
|
| 986 |
"name": "f16_generic_global7x7_b1c256_nchw",
|
| 987 |
"provenance": {
|
| 988 |
+
"notes": "A full 7x7 float16 reduction from [1,256,7,7] to [1,256,1,1] checks global pooling across every channel."
|
| 989 |
},
|
| 990 |
"attrs": { "count_include_pad": 0, "kernel_shape": [7, 7], "strides": [1, 1], "pads": [0, 0, 0, 0] },
|
| 991 |
"inputs": {
|
|
|
|
| 1000 |
{
|
| 1001 |
"name": "f16_generic_count_include_pad_k5s1p2_b1c32_16x16",
|
| 1002 |
"provenance": {
|
| 1003 |
+
"notes": "A [1,32,16,16] float16 pool with a 5x5 window, stride one, padding two, and count_include_pad=1; edge windows divide by the full padded window size."
|
| 1004 |
},
|
| 1005 |
"attrs": { "count_include_pad": 1, "kernel_shape": [5, 5], "strides": [1, 1], "pads": [2, 2, 2, 2] },
|
| 1006 |
"inputs": {
|
|
|
|
| 1129 |
{
|
| 1130 |
"name": "k7s2p3_horizontal_reuse_f32",
|
| 1131 |
"provenance": {
|
| 1132 |
+
"notes": "A 7x7, stride-2, pad-3 pool checks horizontal output positions and exclude-pad edge divisors."
|
| 1133 |
},
|
| 1134 |
"attrs": { "count_include_pad": 0, "kernel_shape": [7, 7], "strides": [2, 2], "pads": [3, 3, 3, 3] },
|
| 1135 |
"inputs": {
|
|
|
|
| 1170 |
}
|
| 1171 |
},
|
| 1172 |
"outputs": { "y": { "dtype": "float32", "shape": [1, 2, 8, 10], "tolerance": 0.00001 } }
|
| 1173 |
+
},
|
| 1174 |
+
{
|
| 1175 |
+
"name": "ort_avgpool_large_kernel_small_output_pad2",
|
| 1176 |
+
"provenance": {
|
| 1177 |
+
"source": "onnxruntime/test/providers/cpu/nn/pool_op_test.cc",
|
| 1178 |
+
"test": "PoolTest.AveragePool_LargeKernelMultiElementOutput_WebGpu",
|
| 1179 |
+
"notes": "A 12x12 average-pool window with padding 2 over a 24x24 input produces a 17x17 output, a large window behind a small output; padding is excluded from the divisor. Transcribed from onnxruntime's PoolTest.AveragePool_LargeKernelMultiElementOutput_WebGpu."
|
| 1180 |
+
},
|
| 1181 |
+
"attrs": {
|
| 1182 |
+
"kernel_shape": [12, 12],
|
| 1183 |
+
"pads": [2, 2, 2, 2],
|
| 1184 |
+
"strides": [1, 1],
|
| 1185 |
+
"count_include_pad": 0,
|
| 1186 |
+
"ceil_mode": 0
|
| 1187 |
+
},
|
| 1188 |
+
"inputs": {
|
| 1189 |
+
"x": { "dtype": "float32", "shape": [1, 2, 24, 24], "data": { "kind": "linspace", "start": 0.0, "end": 11.51 } }
|
| 1190 |
+
},
|
| 1191 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 2, 17, 17], "tolerance": 0.00001 } }
|
| 1192 |
+
},
|
| 1193 |
+
{
|
| 1194 |
+
"name": "window_parallel_nchw2d_count_include_pad_k12p2",
|
| 1195 |
+
"provenance": {
|
| 1196 |
+
"notes": "A 12x12 window with padding two over a 24x24 input and count_include_pad=1 produces 867 outputs; edge windows divide by the full padded tap count."
|
| 1197 |
+
},
|
| 1198 |
+
"attrs": {
|
| 1199 |
+
"kernel_shape": [12, 12],
|
| 1200 |
+
"strides": [1, 1],
|
| 1201 |
+
"pads": [2, 2, 2, 2],
|
| 1202 |
+
"count_include_pad": 1,
|
| 1203 |
+
"ceil_mode": 0
|
| 1204 |
+
},
|
| 1205 |
+
"inputs": {
|
| 1206 |
+
"x": {
|
| 1207 |
+
"dtype": "float32",
|
| 1208 |
+
"shape": [1, 3, 24, 24],
|
| 1209 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.031, "cosStep": 0.053, "scale": 0.7 }
|
| 1210 |
+
}
|
| 1211 |
+
},
|
| 1212 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 3, 17, 17], "tolerance": 0.00001 } }
|
| 1213 |
+
},
|
| 1214 |
+
{
|
| 1215 |
+
"name": "window_parallel_nchw2d_ceil_mode_dilation_stride_overhang",
|
| 1216 |
+
"provenance": {
|
| 1217 |
+
"notes": "ceil_mode=1 with dilation 2, stride 5 and asymmetric pads: the last window in each axis starts inside the input and runs past both the input and the padded extent, so the cooperative reduction must reduce the in-bounds tap count as well as the sum."
|
| 1218 |
+
},
|
| 1219 |
+
"attrs": {
|
| 1220 |
+
"kernel_shape": [12, 12],
|
| 1221 |
+
"strides": [5, 5],
|
| 1222 |
+
"pads": [3, 2, 4, 3],
|
| 1223 |
+
"dilations": [2, 2],
|
| 1224 |
+
"count_include_pad": 0,
|
| 1225 |
+
"ceil_mode": 1
|
| 1226 |
+
},
|
| 1227 |
+
"inputs": {
|
| 1228 |
+
"x": {
|
| 1229 |
+
"dtype": "float32",
|
| 1230 |
+
"shape": [1, 4, 30, 30],
|
| 1231 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.029, "cosStep": 0.047, "scale": 0.8 }
|
| 1232 |
+
}
|
| 1233 |
+
},
|
| 1234 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 4, 4, 4], "tolerance": 0.00001 } }
|
| 1235 |
+
},
|
| 1236 |
+
{
|
| 1237 |
+
"name": "window_parallel_ncl1d_k128_at_min_taps",
|
| 1238 |
+
"provenance": {
|
| 1239 |
+
"notes": "A 512-element row is reduced by a 128-element average-pool window to 4 outputs per channel; a 127-element sibling window in this file reduces the same row by one fewer tap."
|
| 1240 |
+
},
|
| 1241 |
+
"attrs": { "kernel_shape": [128], "strides": [128], "pads": [0, 0] },
|
| 1242 |
+
"inputs": {
|
| 1243 |
+
"x": {
|
| 1244 |
+
"dtype": "float32",
|
| 1245 |
+
"shape": [1, 8, 512],
|
| 1246 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.013, "cosStep": 0.023, "scale": 0.5 }
|
| 1247 |
+
}
|
| 1248 |
+
},
|
| 1249 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 8, 4], "tolerance": 0.00001 } }
|
| 1250 |
+
},
|
| 1251 |
+
{
|
| 1252 |
+
"name": "window_parallel_ncl1d_k127_below_min_taps",
|
| 1253 |
+
"provenance": {
|
| 1254 |
+
"notes": "A 512-element row is reduced by a 127-element average-pool window to 4 outputs per channel; its 128-element sibling in this file uses one more tap over the same row."
|
| 1255 |
+
},
|
| 1256 |
+
"attrs": { "kernel_shape": [127], "strides": [127], "pads": [0, 0] },
|
| 1257 |
+
"inputs": {
|
| 1258 |
+
"x": {
|
| 1259 |
+
"dtype": "float32",
|
| 1260 |
+
"shape": [1, 8, 512],
|
| 1261 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.013, "cosStep": 0.023, "scale": 0.5 }
|
| 1262 |
+
}
|
| 1263 |
+
},
|
| 1264 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 8, 4], "tolerance": 0.00001 } }
|
| 1265 |
+
},
|
| 1266 |
+
{
|
| 1267 |
+
"name": "window_parallel_ncdhw3d_k8_pads_512_taps",
|
| 1268 |
+
"provenance": {
|
| 1269 |
+
"notes": "A 3-D 8x8x8 window with one pad on every face: 512 taps behind 32 outputs, the shape the serial route parallelises worst."
|
| 1270 |
+
},
|
| 1271 |
+
"attrs": { "kernel_shape": [8, 8, 8], "strides": [8, 8, 8], "pads": [1, 1, 1, 1, 1, 1], "count_include_pad": 0 },
|
| 1272 |
+
"inputs": {
|
| 1273 |
+
"x": {
|
| 1274 |
+
"dtype": "float32",
|
| 1275 |
+
"shape": [1, 4, 16, 16, 16],
|
| 1276 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.011, "cosStep": 0.019, "scale": 0.5 }
|
| 1277 |
+
}
|
| 1278 |
+
},
|
| 1279 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 4, 2, 2, 2], "tolerance": 0.00001 } }
|
| 1280 |
+
},
|
| 1281 |
+
{
|
| 1282 |
+
"name": "window_parallel_nchw2d_serial_groups_at_gate",
|
| 1283 |
+
"provenance": { "notes": "A 16,128-element output checks pooling across many independent windows." },
|
| 1284 |
+
"attrs": {
|
| 1285 |
+
"kernel_shape": [12, 12],
|
| 1286 |
+
"strides": [1, 1],
|
| 1287 |
+
"pads": [2, 2, 2, 2],
|
| 1288 |
+
"count_include_pad": 0,
|
| 1289 |
+
"ceil_mode": 0
|
| 1290 |
+
},
|
| 1291 |
+
"inputs": {
|
| 1292 |
+
"x": {
|
| 1293 |
+
"dtype": "float32",
|
| 1294 |
+
"shape": [1, 63, 23, 23],
|
| 1295 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.017, "cosStep": 0.037, "scale": 0.4 }
|
| 1296 |
+
}
|
| 1297 |
+
},
|
| 1298 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 63, 16, 16], "tolerance": 0.00001 } }
|
| 1299 |
+
},
|
| 1300 |
+
{
|
| 1301 |
+
"name": "window_parallel_nchw2d_serial_groups_over_gate",
|
| 1302 |
+
"provenance": {
|
| 1303 |
+
"notes": "One channel more than its sibling puts the output at exactly 64 serial dispatch groups, so the serial route is assumed to fill the device on its own and the cooperative reduction is rejected."
|
| 1304 |
+
},
|
| 1305 |
+
"attrs": {
|
| 1306 |
+
"kernel_shape": [12, 12],
|
| 1307 |
+
"strides": [1, 1],
|
| 1308 |
+
"pads": [2, 2, 2, 2],
|
| 1309 |
+
"count_include_pad": 0,
|
| 1310 |
+
"ceil_mode": 0
|
| 1311 |
+
},
|
| 1312 |
+
"inputs": {
|
| 1313 |
+
"x": {
|
| 1314 |
+
"dtype": "float32",
|
| 1315 |
+
"shape": [1, 64, 23, 23],
|
| 1316 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.017, "cosStep": 0.037, "scale": 0.4 }
|
| 1317 |
+
}
|
| 1318 |
+
},
|
| 1319 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 64, 16, 16], "tolerance": 0.00001 } }
|
| 1320 |
+
},
|
| 1321 |
+
{
|
| 1322 |
+
"name": "window_parallel_gate_ceil_mode_with_count_include_pad",
|
| 1323 |
+
"provenance": {
|
| 1324 |
+
"notes": "A 12x12 average-pool window with dilation 2, stride 5 and padding [3,2,4,3] combines ceil_mode and count_include_pad, both enabled, over a 30x30 input to produce a 4x4 output."
|
| 1325 |
+
},
|
| 1326 |
+
"attrs": {
|
| 1327 |
+
"kernel_shape": [12, 12],
|
| 1328 |
+
"strides": [5, 5],
|
| 1329 |
+
"pads": [3, 2, 4, 3],
|
| 1330 |
+
"dilations": [2, 2],
|
| 1331 |
+
"count_include_pad": 1,
|
| 1332 |
+
"ceil_mode": 1
|
| 1333 |
+
},
|
| 1334 |
+
"inputs": {
|
| 1335 |
+
"x": {
|
| 1336 |
+
"dtype": "float32",
|
| 1337 |
+
"shape": [1, 4, 30, 30],
|
| 1338 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.029, "cosStep": 0.047, "scale": 0.8 }
|
| 1339 |
+
}
|
| 1340 |
+
},
|
| 1341 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 4, 4, 4], "tolerance": 0.00001 } }
|
| 1342 |
+
},
|
| 1343 |
+
{
|
| 1344 |
+
"name": "window_parallel_nchw2d_f16_k12p2",
|
| 1345 |
+
"provenance": {
|
| 1346 |
+
"notes": "float16 input and output through the cooperative window reduction, which loads and accumulates in f32 and narrows once at the store."
|
| 1347 |
+
},
|
| 1348 |
+
"attrs": {
|
| 1349 |
+
"kernel_shape": [12, 12],
|
| 1350 |
+
"strides": [1, 1],
|
| 1351 |
+
"pads": [2, 2, 2, 2],
|
| 1352 |
+
"count_include_pad": 0,
|
| 1353 |
+
"ceil_mode": 0
|
| 1354 |
+
},
|
| 1355 |
+
"inputs": {
|
| 1356 |
+
"x": {
|
| 1357 |
+
"dtype": "float16",
|
| 1358 |
+
"shape": [1, 3, 24, 24],
|
| 1359 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.041, "cosStep": 0.057, "scale": 1.1 }
|
| 1360 |
+
}
|
| 1361 |
+
},
|
| 1362 |
+
"outputs": { "y": { "dtype": "float16", "shape": [1, 3, 17, 17], "tolerance": 0.003 } }
|
| 1363 |
+
},
|
| 1364 |
+
{
|
| 1365 |
+
"name": "window_parallel_nchw2d_count_include_pad_k12p2_small_output",
|
| 1366 |
+
"provenance": {
|
| 1367 |
+
"notes": "A 12x12 window with stride two and padding two over a 24x24 input and count_include_pad=1 produces 81 outputs; edge windows divide by the full padded tap count."
|
| 1368 |
+
},
|
| 1369 |
+
"attrs": {
|
| 1370 |
+
"kernel_shape": [12, 12],
|
| 1371 |
+
"strides": [2, 2],
|
| 1372 |
+
"pads": [2, 2, 2, 2],
|
| 1373 |
+
"count_include_pad": 1,
|
| 1374 |
+
"ceil_mode": 0
|
| 1375 |
+
},
|
| 1376 |
+
"inputs": {
|
| 1377 |
+
"x": {
|
| 1378 |
+
"dtype": "float32",
|
| 1379 |
+
"shape": [1, 1, 24, 24],
|
| 1380 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.031, "cosStep": 0.053, "scale": 0.7 }
|
| 1381 |
+
}
|
| 1382 |
+
},
|
| 1383 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 1, 9, 9], "tolerance": 0.00001 } }
|
| 1384 |
+
},
|
| 1385 |
+
{
|
| 1386 |
+
"name": "window_parallel_nchw2d_f16_k12p2_small_output",
|
| 1387 |
+
"provenance": {
|
| 1388 |
+
"notes": "float16 input and output through the cooperative window reduction, which loads and accumulates in f32 and narrows once at the store."
|
| 1389 |
+
},
|
| 1390 |
+
"attrs": {
|
| 1391 |
+
"kernel_shape": [12, 12],
|
| 1392 |
+
"strides": [2, 2],
|
| 1393 |
+
"pads": [2, 2, 2, 2],
|
| 1394 |
+
"count_include_pad": 0,
|
| 1395 |
+
"ceil_mode": 0
|
| 1396 |
+
},
|
| 1397 |
+
"inputs": {
|
| 1398 |
+
"x": {
|
| 1399 |
+
"dtype": "float16",
|
| 1400 |
+
"shape": [1, 1, 24, 24],
|
| 1401 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.041, "cosStep": 0.057, "scale": 1.1 }
|
| 1402 |
+
}
|
| 1403 |
+
},
|
| 1404 |
+
"outputs": { "y": { "dtype": "float16", "shape": [1, 1, 9, 9], "tolerance": 0.003 } }
|
| 1405 |
+
},
|
| 1406 |
+
{
|
| 1407 |
+
"name": "window_parallel_outputs_to_taps_boundary_128",
|
| 1408 |
+
"attrs": { "kernel_shape": [128], "strides": [1] },
|
| 1409 |
+
"inputs": { "x": { "dtype": "float32", "shape": [1, 1, 255], "data": { "kind": "fillFloat32", "scale": 0.3 } } },
|
| 1410 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 1, 128] } }
|
| 1411 |
+
},
|
| 1412 |
+
{
|
| 1413 |
+
"name": "window_parallel_outputs_to_taps_boundary_129",
|
| 1414 |
+
"attrs": { "kernel_shape": [128], "strides": [1] },
|
| 1415 |
+
"inputs": { "x": { "dtype": "float32", "shape": [1, 1, 256], "data": { "kind": "fillFloat32", "scale": 0.3 } } },
|
| 1416 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 1, 129] } }
|
| 1417 |
+
},
|
| 1418 |
+
{
|
| 1419 |
+
"name": "window_parallel_genuinely_empty_dilated_window",
|
| 1420 |
+
"attrs": { "kernel_shape": [128], "dilations": [2], "pads": [127, 127] },
|
| 1421 |
+
"inputs": { "x": { "dtype": "float32", "shape": [1, 1, 1], "data": { "kind": "constant", "value": 7.0 } } },
|
| 1422 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 1, 1] } }
|
| 1423 |
+
},
|
| 1424 |
+
{
|
| 1425 |
+
"name": "window_parallel_arbitrary_workgroup_96",
|
| 1426 |
+
"tunables": { "WORKGROUP_SIZE": 96 },
|
| 1427 |
+
"attrs": { "kernel_shape": [128], "strides": [128] },
|
| 1428 |
+
"inputs": {
|
| 1429 |
+
"x": {
|
| 1430 |
+
"dtype": "float32",
|
| 1431 |
+
"shape": [1, 1, 128],
|
| 1432 |
+
"data": {
|
| 1433 |
+
"kind": "values",
|
| 1434 |
+
"values": [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 17.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]
|
| 1435 |
+
}
|
| 1436 |
+
}
|
| 1437 |
+
},
|
| 1438 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 1, 1] } }
|
| 1439 |
+
},
|
| 1440 |
+
{
|
| 1441 |
+
"name": "window_parallel_arbitrary_workgroup_127",
|
| 1442 |
+
"tunables": { "WORKGROUP_SIZE": 127 },
|
| 1443 |
+
"attrs": { "kernel_shape": [128], "strides": [128] },
|
| 1444 |
+
"inputs": {
|
| 1445 |
+
"x": {
|
| 1446 |
+
"dtype": "float32",
|
| 1447 |
+
"shape": [1, 1, 128],
|
| 1448 |
+
"data": {
|
| 1449 |
+
"kind": "values",
|
| 1450 |
+
"values": [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 17.0, 1.0]
|
| 1451 |
+
}
|
| 1452 |
+
}
|
| 1453 |
+
},
|
| 1454 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 1, 1] } }
|
| 1455 |
}
|
| 1456 |
]
|
| 1457 |
}
|