sync 91d990483a17
Browse files- README.md +11 -7
- build/webgpu/bench.json +0 -1
- build/webgpu/manifest.json +111 -179
- build/webgpu/mean-variance-normalization-serial-rows.wgsl.jinja +14 -15
- build/webgpu/mean-variance-normalization-subgroup.wgsl.jinja +49 -46
- build/webgpu/metadata.json +20 -11
- build/webgpu/norm-flat-apply.wgsl.jinja +5 -6
- build/webgpu/norm-flat-splitk-combine.wgsl.jinja +2 -2
- build/webgpu/norm-flat-splitk-partials.wgsl.jinja +3 -3
- build/webgpu/test.json +21 -5
README.md
CHANGED
|
@@ -18,15 +18,15 @@ See the [ONNX `MeanVarianceNormalization` spec](https://onnx.ai/onnx/operators/o
|
|
| 18 |
|
| 19 |
## Inputs
|
| 20 |
|
| 21 |
-
| Name |
|
| 22 |
| --- | --- | --- | --- | --- | --- | --- |
|
| 23 |
-
| `
|
| 24 |
|
| 25 |
## Outputs
|
| 26 |
|
| 27 |
-
| Name |
|
| 28 |
| --- | --- | --- | --- | --- | --- | --- |
|
| 29 |
-
| `
|
| 30 |
|
| 31 |
## Attributes
|
| 32 |
|
|
@@ -44,7 +44,7 @@ Default values (overridable per request):
|
|
| 44 |
|
| 45 |
## Files
|
| 46 |
|
| 47 |
-
- [`metadata.json`](build/webgpu/metadata.json) — kernel metadata (id, digests, provenance)
|
| 48 |
- [`manifest.json`](build/webgpu/manifest.json) — the op contract (source of truth)
|
| 49 |
- [`test.json`](build/webgpu/test.json) — correctness cases
|
| 50 |
- [`bench.json`](build/webgpu/bench.json) — benchmark + tuning cases
|
|
@@ -57,10 +57,14 @@ Default values (overridable per request):
|
|
| 57 |
|
| 58 |
## Use with `@huggingface/kernels`
|
| 59 |
|
| 60 |
-
|
| 61 |
-
|
|
|
|
|
|
|
|
|
|
| 62 |
|
| 63 |
The `version: 1` option selects the published kernel contract; it is independent of any operator opset, contrib `since_version`, or model version.
|
|
|
|
| 64 |
|
| 65 |
Replace each `*Data` placeholder with a typed array containing the corresponding input data.
|
| 66 |
|
|
|
|
| 18 |
|
| 19 |
## Inputs
|
| 20 |
|
| 21 |
+
| Name | Upstream name | Logical dtype | Rank | Shape | Description | Presence |
|
| 22 |
| --- | --- | --- | --- | --- | --- | --- |
|
| 23 |
+
| `x` | `X` | `T` | — | — | Input tensor to normalize. | required |
|
| 24 |
|
| 25 |
## Outputs
|
| 26 |
|
| 27 |
+
| Name | Upstream name | Logical dtype | Rank | Shape | Description | Presence |
|
| 28 |
| --- | --- | --- | --- | --- | --- | --- |
|
| 29 |
+
| `y` | `Y` | `T` | same as `x` | same as `x` | Normalized tensor with the same shape as `X`. | required |
|
| 30 |
|
| 31 |
## Attributes
|
| 32 |
|
|
|
|
| 44 |
|
| 45 |
## Files
|
| 46 |
|
| 47 |
+
- [`metadata.json`](build/webgpu/metadata.json) — kernel metadata (id, digests, per-variant templates, provenance)
|
| 48 |
- [`manifest.json`](build/webgpu/manifest.json) — the op contract (source of truth)
|
| 49 |
- [`test.json`](build/webgpu/test.json) — correctness cases
|
| 50 |
- [`bench.json`](build/webgpu/bench.json) — benchmark + tuning cases
|
|
|
|
| 57 |
|
| 58 |
## Use with `@huggingface/kernels`
|
| 59 |
|
| 60 |
+
```sh
|
| 61 |
+
npm install --save-exact @huggingface/kernels@0.0.1-preview.2
|
| 62 |
+
```
|
| 63 |
+
|
| 64 |
+
Required output shapes and logical data types are inferred from the supplied inputs and attributes; result tensors are allocated automatically.
|
| 65 |
|
| 66 |
The `version: 1` option selects the published kernel contract; it is independent of any operator opset, contrib `since_version`, or model version.
|
| 67 |
+
It follows the `v1` branch as fixes land. To pin exact artifact bytes, pass a 40-character commit `revision` instead of `version`.
|
| 68 |
|
| 69 |
Replace each `*Data` placeholder with a typed array containing the corresponding input data.
|
| 70 |
|
build/webgpu/bench.json
CHANGED
|
@@ -1,5 +1,4 @@
|
|
| 1 |
{
|
| 2 |
-
"op": "ai.onnx.MeanVarianceNormalization",
|
| 3 |
"cases": [
|
| 4 |
{
|
| 5 |
"name": "1x32x32x32_default_axes",
|
|
|
|
| 1 |
{
|
|
|
|
| 2 |
"cases": [
|
| 3 |
{
|
| 4 |
"name": "1x32x32x32_default_axes",
|
build/webgpu/manifest.json
CHANGED
|
@@ -2,44 +2,30 @@
|
|
| 2 |
"domain": "ai.onnx",
|
| 3 |
"name": "MeanVarianceNormalization",
|
| 4 |
"sinceVersion": 13,
|
| 5 |
-
"
|
| 6 |
-
"
|
| 7 |
-
"
|
| 8 |
-
{
|
| 9 |
-
"role": "Y",
|
| 10 |
-
"dtype": "T",
|
| 11 |
-
"rank": "ranks.X",
|
| 12 |
-
"description": "Normalized tensor with the same shape as `X`.",
|
| 13 |
-
"shape": "shapes.X"
|
| 14 |
-
}
|
| 15 |
-
],
|
| 16 |
-
"attributes": { "axes": [0, 2, 3] },
|
| 17 |
-
"attributeDescriptions": { "axes": "Axes that share a mean and variance; negative values count from the back." },
|
| 18 |
"typeConstraints": { "T": ["float32", "float16"] },
|
| 19 |
-
"args": {
|
| 20 |
-
"x": { "kind": "tensor", "semantic": "X", "role": "input" },
|
| 21 |
-
"y": { "kind": "tensor", "semantic": "Y", "role": "output" }
|
| 22 |
-
},
|
| 23 |
"tunables": {
|
| 24 |
-
"WORKGROUP_SIZE": 256,
|
| 25 |
-
"SERIAL_WORKGROUP_SIZE": 256,
|
| 26 |
-
"SERIAL_TINY_WORKGROUP_SIZE": 64,
|
| 27 |
-
"SERIAL_MAX_REDUCTION": 128,
|
| 28 |
-
"SERIAL_MIN_ROWS": 256,
|
| 29 |
-
"TREE_MEDIUM_WORKGROUP_SIZE": 64,
|
| 30 |
-
"VEC4_MIN_REDUCTION": 8,
|
| 31 |
-
"FLAT_SPLIT_MIN_ELEMENTS": 65536,
|
| 32 |
-
"FLAT_SPLIT_TARGET_ELEMENTS": 4096,
|
| 33 |
-
"MAX_FLAT_SPLITS": 256
|
| 34 |
},
|
| 35 |
"derive": {
|
| 36 |
"deviceWorkgroupCap": "min(device.limits.maxComputeInvocationsPerWorkgroup, device.limits.maxComputeWorkgroupSizeX)",
|
| 37 |
-
"foldedDispatchCapacity": "device.limits.maxComputeWorkgroupsPerDimension * device.limits.maxComputeWorkgroupsPerDimension",
|
| 38 |
-
"shapeContract": "ranks.
|
| 39 |
-
"reduceCount": "(dim(shapes.
|
| 40 |
-
"rowCount": "numel(shapes.
|
| 41 |
-
"allAxesReduced": "hasAxis(attrs.axes, 0, ranks.
|
| 42 |
-
"vec4Eligible": "((ranks.
|
| 43 |
"maxWorkgroupSize": "min(tunables.WORKGROUP_SIZE, deviceWorkgroupCap)",
|
| 44 |
"minSubgroupSize": "device.adapterInfo.subgroupMinSize if has(device.adapterInfo, \"subgroupMinSize\") else 1",
|
| 45 |
"useSubgroups": "device.features.has(\"subgroups\") and has(device.adapterInfo, \"subgroupMinSize\") and minSubgroupSize > 0",
|
|
@@ -48,93 +34,36 @@
|
|
| 48 |
"serialWorkgroupSize": "min(device.limits.maxComputeInvocationsPerWorkgroup, device.limits.maxComputeWorkgroupSizeX, (tunables.SERIAL_TINY_WORKGROUP_SIZE if reduceCount <= 4 else tunables.SERIAL_WORKGROUP_SIZE))",
|
| 49 |
"rowDispatchFits": "rowCount <= foldedDispatchCapacity",
|
| 50 |
"serialDispatchFits": "ceilDiv(rowCount, serialWorkgroupSize) <= foldedDispatchCapacity",
|
| 51 |
-
"applyDispatchFits": "ceilDiv(numel(shapes.
|
| 52 |
"scalarStorageFits": "scalarWorkgroupSize * 8 <= device.limits.maxComputeWorkgroupStorageSize",
|
| 53 |
"vectorStorageFits": "vectorWorkgroupSize * 8 <= device.limits.maxComputeWorkgroupStorageSize",
|
| 54 |
-
"flatSplit": "min(tunables.MAX_FLAT_SPLITS, pow2ceil(ceilDiv(numel(shapes.
|
| 55 |
"flatScratchBytes": "flatSplit * 8",
|
| 56 |
-
"flatPathFits": "flatSplit <= device.limits.maxComputeWorkgroupsPerDimension and flatScratchBytes <= device.limits.maxStorageBufferBindingSize and flatScratchBytes <= device.limits.maxBufferSize and maxWorkgroupSize * 8 <= device.limits.maxComputeWorkgroupStorageSize and applyDispatchFits"
|
| 57 |
},
|
| 58 |
-
"
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
"name": "params",
|
| 70 |
-
"semantic": "kernel.params",
|
| 71 |
-
"buffer": { "type": "uniform" },
|
| 72 |
-
"struct": { "name": "Params", "fields": [{ "name": "rows", "type": "u32", "value": "rowCount" }] }
|
| 73 |
-
}
|
| 74 |
-
],
|
| 75 |
-
"flatPartials": [
|
| 76 |
-
{ "name": "x", "arg": "x", "semantic": "X", "buffer": { "type": "read-only-storage" }, "elementType": "$scalar" },
|
| 77 |
-
{ "name": "partials", "semantic": "partials", "buffer": { "type": "storage" }, "elementType": "vec2<f32>" },
|
| 78 |
-
{
|
| 79 |
-
"name": "params",
|
| 80 |
-
"semantic": "kernel.params",
|
| 81 |
-
"buffer": { "type": "uniform" },
|
| 82 |
-
"struct": { "name": "Params", "fields": [{ "name": "count", "type": "u32", "value": "numel(shapes.X)" }] }
|
| 83 |
-
}
|
| 84 |
-
],
|
| 85 |
-
"flatCombine": [
|
| 86 |
-
{ "name": "x", "arg": "x", "semantic": "X", "buffer": { "type": "read-only-storage" }, "elementType": "$scalar" },
|
| 87 |
-
{
|
| 88 |
-
"name": "partials",
|
| 89 |
-
"semantic": "partials",
|
| 90 |
-
"buffer": { "type": "read-only-storage" },
|
| 91 |
-
"elementType": "vec2<f32>"
|
| 92 |
-
},
|
| 93 |
-
{ "name": "stats", "semantic": "stats", "buffer": { "type": "storage" }, "elementType": "f32", "length": 2 },
|
| 94 |
-
{
|
| 95 |
-
"name": "params",
|
| 96 |
-
"semantic": "kernel.params",
|
| 97 |
-
"buffer": { "type": "uniform" },
|
| 98 |
-
"struct": { "name": "Params", "fields": [{ "name": "count", "type": "u32", "value": "numel(shapes.X)" }] }
|
| 99 |
-
}
|
| 100 |
-
],
|
| 101 |
-
"flatApply": [
|
| 102 |
-
{ "name": "x", "arg": "x", "semantic": "X", "buffer": { "type": "read-only-storage" }, "elementType": "$scalar" },
|
| 103 |
-
{
|
| 104 |
-
"name": "stats",
|
| 105 |
-
"semantic": "stats",
|
| 106 |
-
"buffer": { "type": "read-only-storage" },
|
| 107 |
-
"elementType": "f32",
|
| 108 |
-
"length": 2
|
| 109 |
-
},
|
| 110 |
-
{ "name": "y", "arg": "y", "semantic": "Y", "buffer": { "type": "storage" }, "elementType": "$scalar" },
|
| 111 |
-
{
|
| 112 |
-
"name": "params",
|
| 113 |
-
"semantic": "kernel.params",
|
| 114 |
-
"buffer": { "type": "uniform" },
|
| 115 |
-
"struct": { "name": "Params", "fields": [{ "name": "count", "type": "u32", "value": "numel(shapes.Y)" }] }
|
| 116 |
-
}
|
| 117 |
-
],
|
| 118 |
-
"noopParams": [
|
| 119 |
-
{
|
| 120 |
-
"name": "params",
|
| 121 |
-
"semantic": "kernel.params",
|
| 122 |
-
"buffer": { "type": "uniform" },
|
| 123 |
-
"struct": { "name": "Params", "fields": [{ "name": "dummy", "type": "u32", "value": 0 }] }
|
| 124 |
-
}
|
| 125 |
-
]
|
| 126 |
},
|
| 127 |
"variants": [
|
| 128 |
{
|
| 129 |
"id": "empty_noop",
|
| 130 |
"priority": 200,
|
| 131 |
-
"when": ["
|
| 132 |
"passes": [
|
| 133 |
{
|
| 134 |
"id": "noop",
|
| 135 |
"name": "MeanVarianceNormalization.Empty",
|
| 136 |
"shader": "noop.wgsl.jinja",
|
| 137 |
-
"bindings": "
|
| 138 |
"dispatch": { "x": 0 }
|
| 139 |
}
|
| 140 |
]
|
|
@@ -142,8 +71,8 @@
|
|
| 142 |
{
|
| 143 |
"id": "all_axes_flat_split",
|
| 144 |
"priority": 120,
|
| 145 |
-
"when": ["
|
| 146 |
-
"
|
| 147 |
"intermediates": [
|
| 148 |
{ "id": "partials", "dtype": "float32", "shape": "[flatSplit, 2]" },
|
| 149 |
{ "id": "stats", "dtype": "float32", "shape": "[2]" }
|
|
@@ -152,120 +81,123 @@
|
|
| 152 |
{
|
| 153 |
"id": "partials",
|
| 154 |
"name": "MeanVarianceNormalization.FlatPartials",
|
| 155 |
-
"
|
| 156 |
-
|
| 157 |
-
"
|
|
|
|
|
|
|
| 158 |
},
|
| 159 |
-
"bindings": "
|
| 160 |
-
"dispatch": { "
|
| 161 |
},
|
| 162 |
{
|
| 163 |
"id": "combine",
|
| 164 |
"name": "MeanVarianceNormalization.FlatCombine",
|
| 165 |
-
"
|
| 166 |
-
|
| 167 |
-
|
| 168 |
-
|
| 169 |
-
|
| 170 |
-
|
|
|
|
|
|
|
|
|
|
| 171 |
},
|
| 172 |
{
|
| 173 |
"id": "apply",
|
| 174 |
"name": "MeanVarianceNormalization.FlatApply",
|
| 175 |
-
"
|
| 176 |
-
|
| 177 |
-
"
|
|
|
|
|
|
|
| 178 |
},
|
| 179 |
-
"bindings":
|
| 180 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 181 |
}
|
| 182 |
]
|
| 183 |
},
|
| 184 |
{
|
| 185 |
"id": "serial_rows",
|
| 186 |
"priority": 115,
|
| 187 |
-
"when": ["
|
| 188 |
-
"
|
| 189 |
"passes": [
|
| 190 |
{
|
| 191 |
"id": "main",
|
| 192 |
"name": "MeanVarianceNormalization.SerialRows",
|
| 193 |
-
"
|
| 194 |
-
|
| 195 |
-
"
|
| 196 |
-
|
| 197 |
-
|
| 198 |
-
|
| 199 |
-
|
| 200 |
-
"scalar": "dtypes.T",
|
| 201 |
-
"usesF16": "dtypes.T == \"f16\""
|
| 202 |
-
}
|
| 203 |
},
|
| 204 |
-
"bindings": "
|
| 205 |
-
"dispatch": {
|
|
|
|
|
|
|
|
|
|
|
|
|
| 206 |
}
|
| 207 |
]
|
| 208 |
},
|
| 209 |
{
|
| 210 |
"id": "cooperative_vec4",
|
| 211 |
"priority": 110,
|
| 212 |
-
"when": ["
|
| 213 |
-
"
|
| 214 |
-
"scalar": "dtypes.T",
|
| 215 |
-
"vectorScalar": "\"vec4<\" ~ dtypes.T ~ \">\"",
|
| 216 |
-
"ioElement": "\"vec4<\" ~ dtypes.T ~ \">\""
|
| 217 |
-
},
|
| 218 |
"passes": [
|
| 219 |
{
|
| 220 |
"id": "main",
|
| 221 |
"name": "MeanVarianceNormalization.CooperativeVec4",
|
| 222 |
-
"
|
| 223 |
-
|
| 224 |
-
|
| 225 |
-
|
| 226 |
-
|
| 227 |
-
|
| 228 |
-
|
| 229 |
-
|
| 230 |
-
|
| 231 |
-
|
| 232 |
-
"vecType": "\"vec4<\" ~ dtypes.T ~ \">\"",
|
| 233 |
-
"usesF16": "dtypes.T == \"f16\"",
|
| 234 |
-
"useSubgroups": "useSubgroups",
|
| 235 |
-
"vectorized": true
|
| 236 |
-
}
|
| 237 |
},
|
| 238 |
-
"bindings": "
|
| 239 |
-
"dispatch": { "
|
| 240 |
}
|
| 241 |
]
|
| 242 |
},
|
| 243 |
{
|
| 244 |
"id": "cooperative_scalar",
|
| 245 |
"priority": 100,
|
| 246 |
-
"when": ["
|
| 247 |
-
"
|
| 248 |
"passes": [
|
| 249 |
{
|
| 250 |
"id": "main",
|
| 251 |
"name": "MeanVarianceNormalization.CooperativeScalar",
|
| 252 |
-
"
|
| 253 |
-
|
| 254 |
-
|
| 255 |
-
|
| 256 |
-
|
| 257 |
-
|
| 258 |
-
|
| 259 |
-
|
| 260 |
-
|
| 261 |
-
"scalar": "dtypes.T",
|
| 262 |
-
"usesF16": "dtypes.T == \"f16\"",
|
| 263 |
-
"useSubgroups": "useSubgroups",
|
| 264 |
-
"vectorized": false
|
| 265 |
-
}
|
| 266 |
},
|
| 267 |
-
"bindings": "
|
| 268 |
-
"dispatch": { "
|
| 269 |
}
|
| 270 |
]
|
| 271 |
}
|
|
|
|
| 2 |
"domain": "ai.onnx",
|
| 3 |
"name": "MeanVarianceNormalization",
|
| 4 |
"sinceVersion": 13,
|
| 5 |
+
"inputs": { "x": { "onnx": "X", "dtype": "T" } },
|
| 6 |
+
"outputs": { "y": { "onnx": "Y", "dtype": "T", "rank": "ranks.x", "shape": "shapes.x" } },
|
| 7 |
+
"attributes": { "axes": { "default": [0, 2, 3] } },
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
"typeConstraints": { "T": ["float32", "float16"] },
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
"tunables": {
|
| 10 |
+
"WORKGROUP_SIZE": { "default": 256 },
|
| 11 |
+
"SERIAL_WORKGROUP_SIZE": { "default": 256 },
|
| 12 |
+
"SERIAL_TINY_WORKGROUP_SIZE": { "default": 64 },
|
| 13 |
+
"SERIAL_MAX_REDUCTION": { "default": 128 },
|
| 14 |
+
"SERIAL_MIN_ROWS": { "default": 256 },
|
| 15 |
+
"TREE_MEDIUM_WORKGROUP_SIZE": { "default": 64 },
|
| 16 |
+
"VEC4_MIN_REDUCTION": { "default": 8 },
|
| 17 |
+
"FLAT_SPLIT_MIN_ELEMENTS": { "default": 65536 },
|
| 18 |
+
"FLAT_SPLIT_TARGET_ELEMENTS": { "default": 4096 },
|
| 19 |
+
"MAX_FLAT_SPLITS": { "default": 256 }
|
| 20 |
},
|
| 21 |
"derive": {
|
| 22 |
"deviceWorkgroupCap": "min(device.limits.maxComputeInvocationsPerWorkgroup, device.limits.maxComputeWorkgroupSizeX)",
|
| 23 |
+
"foldedDispatchCapacity": "min(device.limits.maxComputeWorkgroupsPerDimension, 65535) * min(device.limits.maxComputeWorkgroupsPerDimension, 65535)",
|
| 24 |
+
"shapeContract": "ranks.x >= 3 and ranks.x <= 8 and ranks.y == ranks.x and sameShape(shapes.y, shapes.x) and f16Ok(dtypes.T)",
|
| 25 |
+
"reduceCount": "(dim(shapes.x, 0) if hasAxis(attrs.axes, 0, ranks.x) else 1) * (dim(shapes.x, 1) if hasAxis(attrs.axes, 1, ranks.x) else 1) * (dim(shapes.x, 2) if hasAxis(attrs.axes, 2, ranks.x) else 1) * (dim(shapes.x, 3) if ranks.x >= 4 and hasAxis(attrs.axes, 3, ranks.x) else 1) * (dim(shapes.x, 4) if ranks.x >= 5 and hasAxis(attrs.axes, 4, ranks.x) else 1) * (dim(shapes.x, 5) if ranks.x >= 6 and hasAxis(attrs.axes, 5, ranks.x) else 1) * (dim(shapes.x, 6) if ranks.x >= 7 and hasAxis(attrs.axes, 6, ranks.x) else 1) * (dim(shapes.x, 7) if ranks.x >= 8 and hasAxis(attrs.axes, 7, ranks.x) else 1)",
|
| 26 |
+
"rowCount": "numel(shapes.x) / max(1, reduceCount)",
|
| 27 |
+
"allAxesReduced": "hasAxis(attrs.axes, 0, ranks.x) and hasAxis(attrs.axes, 1, ranks.x) and hasAxis(attrs.axes, 2, ranks.x) and (ranks.x < 4 or hasAxis(attrs.axes, 3, ranks.x)) and (ranks.x < 5 or hasAxis(attrs.axes, 4, ranks.x)) and (ranks.x < 6 or hasAxis(attrs.axes, 5, ranks.x)) and (ranks.x < 7 or hasAxis(attrs.axes, 6, ranks.x)) and (ranks.x < 8 or hasAxis(attrs.axes, 7, ranks.x))",
|
| 28 |
+
"vec4Eligible": "((ranks.x == 3 and hasAxis(attrs.axes, 2, 3) and (dim(shapes.x, 2) % 4 == 0 or (hasAxis(attrs.axes, 1, 3) and dim(shapes.x, 1) * dim(shapes.x, 2) % 4 == 0) or (hasAxis(attrs.axes, 0, 3) and hasAxis(attrs.axes, 1, 3) and numel(shapes.x) % 4 == 0))) or (ranks.x == 4 and hasAxis(attrs.axes, 3, 4) and (dim(shapes.x, 3) % 4 == 0 or (hasAxis(attrs.axes, 2, 4) and dim(shapes.x, 2) * dim(shapes.x, 3) % 4 == 0) or (hasAxis(attrs.axes, 1, 4) and hasAxis(attrs.axes, 2, 4) and dim(shapes.x, 1) * dim(shapes.x, 2) * dim(shapes.x, 3) % 4 == 0) or (hasAxis(attrs.axes, 0, 4) and hasAxis(attrs.axes, 1, 4) and hasAxis(attrs.axes, 2, 4) and numel(shapes.x) % 4 == 0))) or (ranks.x == 5 and hasAxis(attrs.axes, 4, 5) and (dim(shapes.x, 4) % 4 == 0 or (hasAxis(attrs.axes, 3, 5) and dim(shapes.x, 3) * dim(shapes.x, 4) % 4 == 0) or (hasAxis(attrs.axes, 2, 5) and hasAxis(attrs.axes, 3, 5) and dim(shapes.x, 2) * dim(shapes.x, 3) * dim(shapes.x, 4) % 4 == 0) or (hasAxis(attrs.axes, 1, 5) and hasAxis(attrs.axes, 2, 5) and hasAxis(attrs.axes, 3, 5) and dim(shapes.x, 1) * dim(shapes.x, 2) * dim(shapes.x, 3) * dim(shapes.x, 4) % 4 == 0) or (allAxesReduced and numel(shapes.x) % 4 == 0))) or (ranks.x == 6 and hasAxis(attrs.axes, 5, 6) and (dim(shapes.x, 5) % 4 == 0 or (hasAxis(attrs.axes, 4, 6) and dim(shapes.x, 4) * dim(shapes.x, 5) % 4 == 0) or (hasAxis(attrs.axes, 3, 6) and hasAxis(attrs.axes, 4, 6) and dim(shapes.x, 3) * dim(shapes.x, 4) * dim(shapes.x, 5) % 4 == 0) or (hasAxis(attrs.axes, 2, 6) and hasAxis(attrs.axes, 3, 6) and hasAxis(attrs.axes, 4, 6) and dim(shapes.x, 2) * dim(shapes.x, 3) * dim(shapes.x, 4) * dim(shapes.x, 5) % 4 == 0) or (hasAxis(attrs.axes, 1, 6) and hasAxis(attrs.axes, 2, 6) and hasAxis(attrs.axes, 3, 6) and hasAxis(attrs.axes, 4, 6) and dim(shapes.x, 1) * dim(shapes.x, 2) * dim(shapes.x, 3) * dim(shapes.x, 4) * dim(shapes.x, 5) % 4 == 0) or (allAxesReduced and numel(shapes.x) % 4 == 0))))",
|
| 29 |
"maxWorkgroupSize": "min(tunables.WORKGROUP_SIZE, deviceWorkgroupCap)",
|
| 30 |
"minSubgroupSize": "device.adapterInfo.subgroupMinSize if has(device.adapterInfo, \"subgroupMinSize\") else 1",
|
| 31 |
"useSubgroups": "device.features.has(\"subgroups\") and has(device.adapterInfo, \"subgroupMinSize\") and minSubgroupSize > 0",
|
|
|
|
| 34 |
"serialWorkgroupSize": "min(device.limits.maxComputeInvocationsPerWorkgroup, device.limits.maxComputeWorkgroupSizeX, (tunables.SERIAL_TINY_WORKGROUP_SIZE if reduceCount <= 4 else tunables.SERIAL_WORKGROUP_SIZE))",
|
| 35 |
"rowDispatchFits": "rowCount <= foldedDispatchCapacity",
|
| 36 |
"serialDispatchFits": "ceilDiv(rowCount, serialWorkgroupSize) <= foldedDispatchCapacity",
|
| 37 |
+
"applyDispatchFits": "ceilDiv(numel(shapes.y), maxWorkgroupSize) <= foldedDispatchCapacity",
|
| 38 |
"scalarStorageFits": "scalarWorkgroupSize * 8 <= device.limits.maxComputeWorkgroupStorageSize",
|
| 39 |
"vectorStorageFits": "vectorWorkgroupSize * 8 <= device.limits.maxComputeWorkgroupStorageSize",
|
| 40 |
+
"flatSplit": "min(tunables.MAX_FLAT_SPLITS, pow2ceil(ceilDiv(numel(shapes.x), tunables.FLAT_SPLIT_TARGET_ELEMENTS)))",
|
| 41 |
"flatScratchBytes": "flatSplit * 8",
|
| 42 |
+
"flatPathFits": "flatSplit <= min(device.limits.maxComputeWorkgroupsPerDimension, 65535) and flatScratchBytes <= device.limits.maxStorageBufferBindingSize and flatScratchBytes <= device.limits.maxBufferSize and maxWorkgroupSize * 8 <= device.limits.maxComputeWorkgroupStorageSize and applyDispatchFits"
|
| 43 |
},
|
| 44 |
+
"when": ["shapeContract"],
|
| 45 |
+
"bindings": {
|
| 46 |
+
"x": { "buffer": "read-only-storage", "elementType": "$scalar" },
|
| 47 |
+
"params": { "buffer": "uniform", "struct": [{ "name": "count", "type": "u32", "value": "numel(shapes.x)" }] },
|
| 48 |
+
"x_2": { "name": "x", "buffer": "read-only-storage", "elementType": "$ioElement" },
|
| 49 |
+
"y_2": { "name": "y", "buffer": "storage", "elementType": "$ioElement" },
|
| 50 |
+
"params_4": {
|
| 51 |
+
"name": "params",
|
| 52 |
+
"buffer": "uniform",
|
| 53 |
+
"struct": [{ "name": "rows", "type": "u32", "value": "rowCount" }]
|
| 54 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 55 |
},
|
| 56 |
"variants": [
|
| 57 |
{
|
| 58 |
"id": "empty_noop",
|
| 59 |
"priority": 200,
|
| 60 |
+
"when": ["numel(shapes.x) == 0"],
|
| 61 |
"passes": [
|
| 62 |
{
|
| 63 |
"id": "noop",
|
| 64 |
"name": "MeanVarianceNormalization.Empty",
|
| 65 |
"shader": "noop.wgsl.jinja",
|
| 66 |
+
"bindings": [{ "name": "params", "struct": [{ "name": "dummy", "type": "u32", "value": 0 }] }],
|
| 67 |
"dispatch": { "x": 0 }
|
| 68 |
}
|
| 69 |
]
|
|
|
|
| 71 |
{
|
| 72 |
"id": "all_axes_flat_split",
|
| 73 |
"priority": 120,
|
| 74 |
+
"when": ["numel(shapes.x) > 0", "allAxesReduced", "numel(shapes.x) >= tunables.FLAT_SPLIT_MIN_ELEMENTS", "flatPathFits"],
|
| 75 |
+
"derive": { "scalar": "dtypes.T" },
|
| 76 |
"intermediates": [
|
| 77 |
{ "id": "partials", "dtype": "float32", "shape": "[flatSplit, 2]" },
|
| 78 |
{ "id": "stats", "dtype": "float32", "shape": "[2]" }
|
|
|
|
| 81 |
{
|
| 82 |
"id": "partials",
|
| 83 |
"name": "MeanVarianceNormalization.FlatPartials",
|
| 84 |
+
"shader": "norm-flat-splitk-partials.wgsl.jinja",
|
| 85 |
+
"derive": {
|
| 86 |
+
"workgroupSizeSpec": "maxWorkgroupSize",
|
| 87 |
+
"splitSpec": "flatSplit",
|
| 88 |
+
"usesF16Spec": "dtypes.T == \"f16\""
|
| 89 |
},
|
| 90 |
+
"bindings": ["x", { "name": "partials", "buffer": "storage", "elementType": "vec2<f32>" }, "params"],
|
| 91 |
+
"dispatch": { "x": "min(flatSplit, 65535)", "y": "ceilDiv(flatSplit, 65535)", "z": 1 }
|
| 92 |
},
|
| 93 |
{
|
| 94 |
"id": "combine",
|
| 95 |
"name": "MeanVarianceNormalization.FlatCombine",
|
| 96 |
+
"shader": "norm-flat-splitk-combine.wgsl.jinja",
|
| 97 |
+
"derive": { "splitSpec": "flatSplit", "usesF16Spec": "dtypes.T == \"f16\"" },
|
| 98 |
+
"bindings": [
|
| 99 |
+
"x",
|
| 100 |
+
{ "name": "partials", "buffer": "read-only-storage", "elementType": "vec2<f32>" },
|
| 101 |
+
{ "name": "stats", "buffer": "storage", "elementType": "f32", "length": 2 },
|
| 102 |
+
"params"
|
| 103 |
+
],
|
| 104 |
+
"dispatch": { "x": "min(1, 65535)", "y": "ceilDiv(1, 65535)", "z": 1 }
|
| 105 |
},
|
| 106 |
{
|
| 107 |
"id": "apply",
|
| 108 |
"name": "MeanVarianceNormalization.FlatApply",
|
| 109 |
+
"shader": "norm-flat-apply.wgsl.jinja",
|
| 110 |
+
"derive": {
|
| 111 |
+
"workgroupSizeSpec": "maxWorkgroupSize",
|
| 112 |
+
"scalar": "dtypes.T",
|
| 113 |
+
"usesF16Spec": "dtypes.T == \"f16\""
|
| 114 |
},
|
| 115 |
+
"bindings": [
|
| 116 |
+
"x",
|
| 117 |
+
{ "name": "stats", "buffer": "read-only-storage", "elementType": "f32", "length": 2 },
|
| 118 |
+
{ "arg": "y", "elementType": "$scalar" },
|
| 119 |
+
{ "name": "params", "struct": [{ "name": "count", "type": "u32", "value": "numel(shapes.y)" }] }
|
| 120 |
+
],
|
| 121 |
+
"dispatch": {
|
| 122 |
+
"x": "min(ceilDiv((numel(shapes.y)), (maxWorkgroupSize)), 65535)",
|
| 123 |
+
"y": "ceilDiv(ceilDiv((numel(shapes.y)), (maxWorkgroupSize)), 65535)",
|
| 124 |
+
"z": 1
|
| 125 |
+
}
|
| 126 |
}
|
| 127 |
]
|
| 128 |
},
|
| 129 |
{
|
| 130 |
"id": "serial_rows",
|
| 131 |
"priority": 115,
|
| 132 |
+
"when": ["numel(shapes.x) > 0", "reduceCount <= tunables.SERIAL_MAX_REDUCTION", "rowCount >= tunables.SERIAL_MIN_ROWS", "serialDispatchFits"],
|
| 133 |
+
"derive": { "scalar": "dtypes.T", "ioElement": "dtypes.T" },
|
| 134 |
"passes": [
|
| 135 |
{
|
| 136 |
"id": "main",
|
| 137 |
"name": "MeanVarianceNormalization.SerialRows",
|
| 138 |
+
"shader": "mean-variance-normalization-serial-rows.wgsl.jinja",
|
| 139 |
+
"derive": {
|
| 140 |
+
"xShape": "shapes.x",
|
| 141 |
+
"reduce": ["hasAxis(attrs.axes, 0, ranks.x)", "hasAxis(attrs.axes, 1, ranks.x)", "hasAxis(attrs.axes, 2, ranks.x)", "hasAxis(attrs.axes, 3, ranks.x)", "hasAxis(attrs.axes, 4, ranks.x)", "hasAxis(attrs.axes, 5, ranks.x)", "hasAxis(attrs.axes, 6, ranks.x)", "hasAxis(attrs.axes, 7, ranks.x)"],
|
| 142 |
+
"workgroupSizeSpec": "serialWorkgroupSize",
|
| 143 |
+
"scalar": "dtypes.T",
|
| 144 |
+
"usesF16Spec": "dtypes.T == \"f16\""
|
|
|
|
|
|
|
|
|
|
| 145 |
},
|
| 146 |
+
"bindings": ["x_2", "y_2", "params_4"],
|
| 147 |
+
"dispatch": {
|
| 148 |
+
"x": "min(ceilDiv((rowCount), (serialWorkgroupSize)), 65535)",
|
| 149 |
+
"y": "ceilDiv(ceilDiv((rowCount), (serialWorkgroupSize)), 65535)",
|
| 150 |
+
"z": 1
|
| 151 |
+
}
|
| 152 |
}
|
| 153 |
]
|
| 154 |
},
|
| 155 |
{
|
| 156 |
"id": "cooperative_vec4",
|
| 157 |
"priority": 110,
|
| 158 |
+
"when": ["numel(shapes.x) > 0", "reduceCount >= tunables.VEC4_MIN_REDUCTION", "vec4Eligible", "rowDispatchFits", "vectorStorageFits"],
|
| 159 |
+
"derive": { "scalar": "dtypes.T", "ioElement": "\"vec4<\" ~ dtypes.T ~ \">\"" },
|
|
|
|
|
|
|
|
|
|
|
|
|
| 160 |
"passes": [
|
| 161 |
{
|
| 162 |
"id": "main",
|
| 163 |
"name": "MeanVarianceNormalization.CooperativeVec4",
|
| 164 |
+
"shader": "mean-variance-normalization-subgroup.wgsl.jinja",
|
| 165 |
+
"subgroupCollectivesWidth": "portable",
|
| 166 |
+
"derive": {
|
| 167 |
+
"xShape": "shapes.x",
|
| 168 |
+
"reduce": ["hasAxis(attrs.axes, 0, ranks.x)", "hasAxis(attrs.axes, 1, ranks.x)", "hasAxis(attrs.axes, 2, ranks.x)", "hasAxis(attrs.axes, 3, ranks.x)", "hasAxis(attrs.axes, 4, ranks.x)", "hasAxis(attrs.axes, 5, ranks.x)", "hasAxis(attrs.axes, 6, ranks.x)", "hasAxis(attrs.axes, 7, ranks.x)"],
|
| 169 |
+
"wg": "vectorWorkgroupSize",
|
| 170 |
+
"scalar": "dtypes.T",
|
| 171 |
+
"vecType": "\"vec4<\" ~ dtypes.T ~ \">\"",
|
| 172 |
+
"usesF16Spec": "dtypes.T == \"f16\"",
|
| 173 |
+
"vectorizedSpec": true
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 174 |
},
|
| 175 |
+
"bindings": ["x_2", "y_2", "params_4"],
|
| 176 |
+
"dispatch": { "x": "min(rowCount, 65535)", "y": "ceilDiv(rowCount, 65535)", "z": 1 }
|
| 177 |
}
|
| 178 |
]
|
| 179 |
},
|
| 180 |
{
|
| 181 |
"id": "cooperative_scalar",
|
| 182 |
"priority": 100,
|
| 183 |
+
"when": ["numel(shapes.x) > 0", "rowDispatchFits", "scalarStorageFits"],
|
| 184 |
+
"derive": { "scalar": "dtypes.T", "ioElement": "dtypes.T" },
|
| 185 |
"passes": [
|
| 186 |
{
|
| 187 |
"id": "main",
|
| 188 |
"name": "MeanVarianceNormalization.CooperativeScalar",
|
| 189 |
+
"shader": "mean-variance-normalization-subgroup.wgsl.jinja",
|
| 190 |
+
"subgroupCollectivesWidth": "portable",
|
| 191 |
+
"derive": {
|
| 192 |
+
"xShape": "shapes.x",
|
| 193 |
+
"reduce": ["hasAxis(attrs.axes, 0, ranks.x)", "hasAxis(attrs.axes, 1, ranks.x)", "hasAxis(attrs.axes, 2, ranks.x)", "hasAxis(attrs.axes, 3, ranks.x)", "hasAxis(attrs.axes, 4, ranks.x)", "hasAxis(attrs.axes, 5, ranks.x)", "hasAxis(attrs.axes, 6, ranks.x)", "hasAxis(attrs.axes, 7, ranks.x)"],
|
| 194 |
+
"wg": "scalarWorkgroupSize",
|
| 195 |
+
"scalar": "dtypes.T",
|
| 196 |
+
"usesF16Spec": "dtypes.T == \"f16\"",
|
| 197 |
+
"vectorizedSpec": false
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 198 |
},
|
| 199 |
+
"bindings": ["x_2", "y_2", "params_4"],
|
| 200 |
+
"dispatch": { "x": "min(rowCount, 65535)", "y": "ceilDiv(rowCount, 65535)", "z": 1 }
|
| 201 |
}
|
| 202 |
]
|
| 203 |
}
|
build/webgpu/mean-variance-normalization-serial-rows.wgsl.jinja
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
{% if
|
| 2 |
enable f16;
|
| 3 |
{% endif %}
|
| 4 |
{{ env.wgsl.resourceDeclarations }}
|
|
@@ -10,42 +10,41 @@ enable f16;
|
|
| 10 |
// The reduction is shifted by its first value before accumulating moments. This
|
| 11 |
// stabilizes the variance calculation while retaining the zero-variance ONNX
|
| 12 |
// result as 0/0 = NaN.
|
| 13 |
-
{% macro nd_offset(target, index, reduced
|
| 14 |
-
{% set rank =
|
| 15 |
{% for i in range(rank) %}
|
| 16 |
-
{% if
|
| 17 |
{% set pa = namespace(v=1) %}
|
| 18 |
{% set st = namespace(v=1) %}
|
| 19 |
{% for j in range(i + 1, rank) %}
|
| 20 |
-
{% set st.v = st.v *
|
| 21 |
-
{% if
|
| 22 |
{% endfor %}
|
| 23 |
-
{{
|
| 24 |
{% endif %}
|
| 25 |
{% endfor %}
|
| 26 |
{% endmacro %}
|
| 27 |
-
const WG: u32 = {{
|
| 28 |
-
const R: u32 = {{
|
| 29 |
|
| 30 |
@compute @workgroup_size(WG, 1, 1)
|
| 31 |
fn main(
|
| 32 |
-
@builtin(global_invocation_id) gid: vec3<u32>
|
| 33 |
-
@builtin(num_workgroups) nwg: vec3<u32>
|
| 34 |
) {
|
| 35 |
// `threads` dispatches fold past the WebGPU x-dimension limit into y.
|
| 36 |
-
let row = gid.x + gid.y *
|
| 37 |
if (row >= params.rows) {
|
| 38 |
return;
|
| 39 |
}
|
| 40 |
|
| 41 |
var base_off = 0u;
|
| 42 |
-
{{ nd_offset("base_off", "row", 0,
|
| 43 |
let shift = f32(x[base_off]);
|
| 44 |
var sum_d = 0.0;
|
| 45 |
var sum_d2 = 0.0;
|
| 46 |
for (var r = 0u; r < R; r = r + 1u) {
|
| 47 |
var off = base_off;
|
| 48 |
-
{{ nd_offset("off", "r", 1,
|
| 49 |
sum_d = sum_d + d;
|
| 50 |
sum_d2 = sum_d2 + d * d;
|
| 51 |
}
|
|
@@ -57,6 +56,6 @@ fn main(
|
|
| 57 |
|
| 58 |
for (var r = 0u; r < R; r = r + 1u) {
|
| 59 |
var off = base_off;
|
| 60 |
-
{{ nd_offset("off", "r", 1,
|
| 61 |
}
|
| 62 |
}
|
|
|
|
| 1 |
+
{% if usesF16Spec %}
|
| 2 |
enable f16;
|
| 3 |
{% endif %}
|
| 4 |
{{ env.wgsl.resourceDeclarations }}
|
|
|
|
| 10 |
// The reduction is shifted by its first value before accumulating moments. This
|
| 11 |
// stabilizes the variance calculation while retaining the zero-variance ONNX
|
| 12 |
// result as 0/0 = NaN.
|
| 13 |
+
{% macro nd_offset(target, index, reduced) %}
|
| 14 |
+
{% set rank = xShape | length %}
|
| 15 |
{% for i in range(rank) %}
|
| 16 |
+
{% if reduce[i] if reduced else not reduce[i] %}
|
| 17 |
{% set pa = namespace(v=1) %}
|
| 18 |
{% set st = namespace(v=1) %}
|
| 19 |
{% for j in range(i + 1, rank) %}
|
| 20 |
+
{% set st.v = st.v * xShape[j] %}
|
| 21 |
+
{% if reduce[j] if reduced else not reduce[j] %}{% set pa.v = pa.v * xShape[j] %}{% endif %}
|
| 22 |
{% endfor %}
|
| 23 |
+
{{ target }} = {{ target }} + (({{ index }} / {{ pa.v }}u) % {{ xShape[i] }}u) * {{ st.v }}u;
|
| 24 |
{% endif %}
|
| 25 |
{% endfor %}
|
| 26 |
{% endmacro %}
|
| 27 |
+
const WG: u32 = {{ workgroupSizeSpec }}u;
|
| 28 |
+
const R: u32 = {{ reduceCount }}u;
|
| 29 |
|
| 30 |
@compute @workgroup_size(WG, 1, 1)
|
| 31 |
fn main(
|
| 32 |
+
@builtin(global_invocation_id) gid: vec3<u32>
|
|
|
|
| 33 |
) {
|
| 34 |
// `threads` dispatches fold past the WebGPU x-dimension limit into y.
|
| 35 |
+
let row = gid.x + gid.y * {{ DISPATCH_FOLD_WIDTH }}u * WG;
|
| 36 |
if (row >= params.rows) {
|
| 37 |
return;
|
| 38 |
}
|
| 39 |
|
| 40 |
var base_off = 0u;
|
| 41 |
+
{{ nd_offset("base_off", "row", 0) | indent(2, true) }}
|
| 42 |
let shift = f32(x[base_off]);
|
| 43 |
var sum_d = 0.0;
|
| 44 |
var sum_d2 = 0.0;
|
| 45 |
for (var r = 0u; r < R; r = r + 1u) {
|
| 46 |
var off = base_off;
|
| 47 |
+
{{ nd_offset("off", "r", 1) | indent(4, true) }} let d = f32(x[off]) - shift;
|
| 48 |
sum_d = sum_d + d;
|
| 49 |
sum_d2 = sum_d2 + d * d;
|
| 50 |
}
|
|
|
|
| 56 |
|
| 57 |
for (var r = 0u; r < R; r = r + 1u) {
|
| 58 |
var off = base_off;
|
| 59 |
+
{{ nd_offset("off", "r", 1) | indent(4, true) }} y[off] = {{ scalar }}((f32(x[off]) - mean) / denom);
|
| 60 |
}
|
| 61 |
}
|
build/webgpu/mean-variance-normalization-subgroup.wgsl.jinja
CHANGED
|
@@ -1,58 +1,67 @@
|
|
| 1 |
-
{% if
|
| 2 |
enable f16;
|
| 3 |
{% endif %}
|
| 4 |
-
{% if
|
| 5 |
enable subgroups;
|
| 6 |
{% endif %}
|
| 7 |
{{ env.wgsl.resourceDeclarations }}
|
| 8 |
|
| 9 |
-
{% macro nd_offset(target, index, reduced
|
| 10 |
-
{% set rank =
|
| 11 |
{% for i in range(rank) %}
|
| 12 |
-
{% if
|
| 13 |
{% set pa = namespace(v=1) %}
|
| 14 |
{% set st = namespace(v=1) %}
|
| 15 |
{% for j in range(i + 1, rank) %}
|
| 16 |
-
{% set st.v = st.v *
|
| 17 |
-
{% if
|
| 18 |
{% endfor %}
|
| 19 |
-
{{
|
| 20 |
{% endif %}
|
| 21 |
{% endfor %}
|
| 22 |
{% endmacro %}
|
| 23 |
-
const WG: u32 = {{
|
| 24 |
-
const R: u32 = {{
|
| 25 |
-
{% if
|
| 26 |
const RV: u32 = R / 4u;
|
| 27 |
|
| 28 |
{% endif %}
|
| 29 |
-
{% if
|
| 30 |
-
|
| 31 |
-
//
|
| 32 |
-
|
| 33 |
-
var<workgroup> sg_partials: array<vec2<f32>,
|
| 34 |
-
{% endif %}
|
| 35 |
{% else %}
|
| 36 |
var<workgroup> wg_red: array<vec2<f32>, WG>;
|
| 37 |
{% endif %}
|
| 38 |
|
| 39 |
-
fn reduce_pair(value: vec2<f32>
|
| 40 |
-
{% if
|
| 41 |
let s = vec2<f32>(subgroupAdd(value.x), subgroupAdd(value.y));
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
|
|
|
|
|
|
|
|
|
| 45 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 46 |
workgroupBarrier();
|
| 47 |
-
let num_sg = (WG + sg_size - 1u) / sg_size;
|
| 48 |
var total = vec2<f32>(0.0, 0.0);
|
| 49 |
-
for (var i =
|
| 50 |
total = total + sg_partials[i];
|
| 51 |
}
|
| 52 |
-
return total;
|
| 53 |
-
{% else %}
|
| 54 |
-
return s;
|
| 55 |
-
{% endif %}
|
| 56 |
{% else %}
|
| 57 |
wg_red[tid] = value;
|
| 58 |
workgroupBarrier();
|
|
@@ -69,14 +78,12 @@ fn reduce_pair(value: vec2<f32>{% if not source.useSubgroups or source.wg > sour
|
|
| 69 |
@compute @workgroup_size(WG, 1, 1)
|
| 70 |
fn main(
|
| 71 |
@builtin(workgroup_id) wg_id: vec3<u32>,
|
| 72 |
-
@builtin(local_invocation_id) lid: vec3<u32>
|
| 73 |
-
|
| 74 |
-
{%- if source.useSubgroups and source.wg > source.minSubgroupSize %},
|
| 75 |
-
@builtin(subgroup_invocation_id) sg_lane: u32,
|
| 76 |
@builtin(subgroup_size) sg_size: u32
|
| 77 |
{%- endif %}
|
| 78 |
) {
|
| 79 |
-
let row = wg_id.x + wg_id.y *
|
| 80 |
if (row >= params.rows) {
|
| 81 |
return;
|
| 82 |
}
|
|
@@ -84,21 +91,21 @@ fn main(
|
|
| 84 |
|
| 85 |
// Base offset from the kept-axis coordinates.
|
| 86 |
var base_off = 0u;
|
| 87 |
-
{{ nd_offset("base_off", "row", 0,
|
| 88 |
-
{% if
|
| 89 |
let shift = f32(x[base_off / 4u].x);
|
| 90 |
{% else %}
|
| 91 |
let shift = f32(x[base_off]);
|
| 92 |
{% endif %}
|
| 93 |
var acc = vec2<f32>(0.0, 0.0);
|
| 94 |
-
{% if
|
| 95 |
for (var q = tid; q < RV; q = q + WG) {
|
| 96 |
let r = q * 4u;
|
| 97 |
{% else %}
|
| 98 |
for (var r = tid; r < R; r = r + WG) {
|
| 99 |
{% endif %}
|
| 100 |
var off = base_off;
|
| 101 |
-
{{ nd_offset("off", "r", 1,
|
| 102 |
let d = vec4<f32>(x[off / 4u]) - vec4<f32>(shift);
|
| 103 |
acc.x = acc.x + d.x + d.y + d.z + d.w;
|
| 104 |
acc.y = acc.y + dot(d, d);
|
|
@@ -109,28 +116,24 @@ fn main(
|
|
| 109 |
{% endif %}
|
| 110 |
}
|
| 111 |
|
| 112 |
-
{% if
|
| 113 |
-
let totals = reduce_pair(acc{% if source.wg > source.minSubgroupSize %}, tid, sg_lane, sg_size{% endif %});
|
| 114 |
-
{% else %}
|
| 115 |
-
let totals = reduce_pair(acc, tid);
|
| 116 |
-
{% endif %}
|
| 117 |
let mean_d = totals.x / f32(R);
|
| 118 |
let variance = max(totals.y / f32(R) - mean_d * mean_d, 0.0);
|
| 119 |
let mean = shift + mean_d;
|
| 120 |
let denom = sqrt(variance);
|
| 121 |
|
| 122 |
-
{% if
|
| 123 |
for (var q = tid; q < RV; q = q + WG) {
|
| 124 |
let r = q * 4u;
|
| 125 |
{% else %}
|
| 126 |
for (var r = tid; r < R; r = r + WG) {
|
| 127 |
{% endif %}
|
| 128 |
var off = base_off;
|
| 129 |
-
{{ nd_offset("off", "r", 1,
|
| 130 |
let v = vec4<f32>(x[off / 4u]);
|
| 131 |
-
y[off / 4u] = {{
|
| 132 |
{% else %}
|
| 133 |
-
y[off] = {{
|
| 134 |
{% endif %}
|
| 135 |
}
|
| 136 |
}
|
|
|
|
| 1 |
+
{% if usesF16Spec %}
|
| 2 |
enable f16;
|
| 3 |
{% endif %}
|
| 4 |
+
{% if useSubgroups %}
|
| 5 |
enable subgroups;
|
| 6 |
{% endif %}
|
| 7 |
{{ env.wgsl.resourceDeclarations }}
|
| 8 |
|
| 9 |
+
{% macro nd_offset(target, index, reduced) %}
|
| 10 |
+
{% set rank = xShape | length %}
|
| 11 |
{% for i in range(rank) %}
|
| 12 |
+
{% if reduce[i] if reduced else not reduce[i] %}
|
| 13 |
{% set pa = namespace(v=1) %}
|
| 14 |
{% set st = namespace(v=1) %}
|
| 15 |
{% for j in range(i + 1, rank) %}
|
| 16 |
+
{% set st.v = st.v * xShape[j] %}
|
| 17 |
+
{% if reduce[j] if reduced else not reduce[j] %}{% set pa.v = pa.v * xShape[j] %}{% endif %}
|
| 18 |
{% endfor %}
|
| 19 |
+
{{ target }} = {{ target }} + (({{ index }} / {{ pa.v }}u) % {{ xShape[i] }}u) * {{ st.v }}u;
|
| 20 |
{% endif %}
|
| 21 |
{% endfor %}
|
| 22 |
{% endmacro %}
|
| 23 |
+
const WG: u32 = {{ wg }}u;
|
| 24 |
+
const R: u32 = {{ reduceCount }}u;
|
| 25 |
+
{% if vectorizedSpec %}
|
| 26 |
const RV: u32 = R / 4u;
|
| 27 |
|
| 28 |
{% endif %}
|
| 29 |
+
{% if useSubgroups %}
|
| 30 |
+
// One slot per invocation: the cross-subgroup fold indexes by
|
| 31 |
+
// local_invocation_id, never by a subgroup ordinal, so no subgroup width or
|
| 32 |
+
// partition can overflow or alias it.
|
| 33 |
+
var<workgroup> sg_partials: array<vec2<f32>, WG>;
|
|
|
|
| 34 |
{% else %}
|
| 35 |
var<workgroup> wg_red: array<vec2<f32>, WG>;
|
| 36 |
{% endif %}
|
| 37 |
|
| 38 |
+
fn reduce_pair(value: vec2<f32>, tid: u32{% if useSubgroups %}, sg_size: u32{% endif %}) -> vec2<f32> {
|
| 39 |
+
{% if useSubgroups %}
|
| 40 |
let s = vec2<f32>(subgroupAdd(value.x), subgroupAdd(value.y));
|
| 41 |
+
// The whole workgroup is one subgroup: the collective above already covers it
|
| 42 |
+
// (no shared memory, no barrier). The test reads the `subgroup_size` builtin,
|
| 43 |
+
// which is uniform; a collective's result is not uniform to WGSL's analysis
|
| 44 |
+
// and may not guard a barrier.
|
| 45 |
+
if (sg_size == WG) {
|
| 46 |
+
return s;
|
| 47 |
}
|
| 48 |
+
// Cross-subgroup fold that assumes nothing about which invocations share a
|
| 49 |
+
// subgroup, how many subgroups there are, or which of a subgroup's lanes are
|
| 50 |
+
// active: every invocation owns the slot at its own index, the elected lane
|
| 51 |
+
// publishes its subgroup pair there and every other lane publishes the sum
|
| 52 |
+
// identity. Each subgroup then folds all WG slots — lane `rank`, its dense
|
| 53 |
+
// position among the active lanes, walks slots rank, rank + count, ... — and
|
| 54 |
+
// one more collective merges the lane partials, so every slot is added
|
| 55 |
+
// exactly once at any legal width and partition.
|
| 56 |
+
let rank = subgroupExclusiveAdd(1u);
|
| 57 |
+
let count = subgroupAdd(1u);
|
| 58 |
+
sg_partials[tid] = select(vec2<f32>(0.0, 0.0), s, rank == 0u);
|
| 59 |
workgroupBarrier();
|
|
|
|
| 60 |
var total = vec2<f32>(0.0, 0.0);
|
| 61 |
+
for (var i = rank; i < WG; i = i + count) {
|
| 62 |
total = total + sg_partials[i];
|
| 63 |
}
|
| 64 |
+
return vec2<f32>(subgroupAdd(total.x), subgroupAdd(total.y));
|
|
|
|
|
|
|
|
|
|
| 65 |
{% else %}
|
| 66 |
wg_red[tid] = value;
|
| 67 |
workgroupBarrier();
|
|
|
|
| 78 |
@compute @workgroup_size(WG, 1, 1)
|
| 79 |
fn main(
|
| 80 |
@builtin(workgroup_id) wg_id: vec3<u32>,
|
| 81 |
+
@builtin(local_invocation_id) lid: vec3<u32>
|
| 82 |
+
{%- if useSubgroups %},
|
|
|
|
|
|
|
| 83 |
@builtin(subgroup_size) sg_size: u32
|
| 84 |
{%- endif %}
|
| 85 |
) {
|
| 86 |
+
let row = wg_id.x + wg_id.y * {{ DISPATCH_FOLD_WIDTH }}u;
|
| 87 |
if (row >= params.rows) {
|
| 88 |
return;
|
| 89 |
}
|
|
|
|
| 91 |
|
| 92 |
// Base offset from the kept-axis coordinates.
|
| 93 |
var base_off = 0u;
|
| 94 |
+
{{ nd_offset("base_off", "row", 0) | indent(2, true) }}
|
| 95 |
+
{% if vectorizedSpec %}
|
| 96 |
let shift = f32(x[base_off / 4u].x);
|
| 97 |
{% else %}
|
| 98 |
let shift = f32(x[base_off]);
|
| 99 |
{% endif %}
|
| 100 |
var acc = vec2<f32>(0.0, 0.0);
|
| 101 |
+
{% if vectorizedSpec %}
|
| 102 |
for (var q = tid; q < RV; q = q + WG) {
|
| 103 |
let r = q * 4u;
|
| 104 |
{% else %}
|
| 105 |
for (var r = tid; r < R; r = r + WG) {
|
| 106 |
{% endif %}
|
| 107 |
var off = base_off;
|
| 108 |
+
{{ nd_offset("off", "r", 1) | indent(4, true) }}{% if vectorizedSpec %}
|
| 109 |
let d = vec4<f32>(x[off / 4u]) - vec4<f32>(shift);
|
| 110 |
acc.x = acc.x + d.x + d.y + d.z + d.w;
|
| 111 |
acc.y = acc.y + dot(d, d);
|
|
|
|
| 116 |
{% endif %}
|
| 117 |
}
|
| 118 |
|
| 119 |
+
let totals = reduce_pair(acc, tid{% if useSubgroups %}, sg_size{% endif %});
|
|
|
|
|
|
|
|
|
|
|
|
|
| 120 |
let mean_d = totals.x / f32(R);
|
| 121 |
let variance = max(totals.y / f32(R) - mean_d * mean_d, 0.0);
|
| 122 |
let mean = shift + mean_d;
|
| 123 |
let denom = sqrt(variance);
|
| 124 |
|
| 125 |
+
{% if vectorizedSpec %}
|
| 126 |
for (var q = tid; q < RV; q = q + WG) {
|
| 127 |
let r = q * 4u;
|
| 128 |
{% else %}
|
| 129 |
for (var r = tid; r < R; r = r + WG) {
|
| 130 |
{% endif %}
|
| 131 |
var off = base_off;
|
| 132 |
+
{{ nd_offset("off", "r", 1) | indent(4, true) }}{% if vectorizedSpec %}
|
| 133 |
let v = vec4<f32>(x[off / 4u]);
|
| 134 |
+
y[off / 4u] = {{ vecType }}((v - vec4<f32>(mean)) / vec4<f32>(denom));
|
| 135 |
{% else %}
|
| 136 |
+
y[off] = {{ scalar }}((f32(x[off]) - mean) / denom);
|
| 137 |
{% endif %}
|
| 138 |
}
|
| 139 |
}
|
build/webgpu/metadata.json
CHANGED
|
@@ -1,23 +1,32 @@
|
|
| 1 |
{
|
| 2 |
"name": "ai.onnx.MeanVarianceNormalization",
|
| 3 |
-
"id": "
|
| 4 |
"version": 1,
|
| 5 |
"license": "Apache-2.0",
|
| 6 |
"backend": { "type": "webgpu" },
|
| 7 |
"digest": {
|
| 8 |
"algorithm": "sha256",
|
| 9 |
"files": {
|
| 10 |
-
"bench.json": "
|
| 11 |
-
"manifest.json": "
|
| 12 |
-
"mean-variance-normalization-serial-rows.wgsl.jinja": "
|
| 13 |
-
"mean-variance-normalization-subgroup.wgsl.jinja": "
|
| 14 |
"noop.wgsl.jinja": "k/5BMD6UO81N7XlF+t4iSKyt3dbtcqNMCru5aUKNBKE=",
|
| 15 |
-
"norm-flat-apply.wgsl.jinja": "
|
| 16 |
-
"norm-flat-splitk-combine.wgsl.jinja": "
|
| 17 |
-
"norm-flat-splitk-partials.wgsl.jinja": "
|
| 18 |
-
"test.json": "
|
| 19 |
}
|
| 20 |
},
|
| 21 |
-
"provenance": { "kernel": { "sha": "
|
| 22 |
-
"webgpu": {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 23 |
}
|
|
|
|
| 1 |
{
|
| 2 |
"name": "ai.onnx.MeanVarianceNormalization",
|
| 3 |
+
"id": "_ai_onnx_meanvariancenormalization_webgpu_b716a78",
|
| 4 |
"version": 1,
|
| 5 |
"license": "Apache-2.0",
|
| 6 |
"backend": { "type": "webgpu" },
|
| 7 |
"digest": {
|
| 8 |
"algorithm": "sha256",
|
| 9 |
"files": {
|
| 10 |
+
"bench.json": "zH0PcLLzlKTcTGM2WzPi8keFUjvDcCnttgcQLxJ9WuU=",
|
| 11 |
+
"manifest.json": "Snfz0B5Kkd7enbnP+ETHCh/vyME+C3vu4puxVB1xF3c=",
|
| 12 |
+
"mean-variance-normalization-serial-rows.wgsl.jinja": "qcoGxwmc0jShVeozos6da6awjOJbbIIKLfoMCTyzNuk=",
|
| 13 |
+
"mean-variance-normalization-subgroup.wgsl.jinja": "GTbYa5JP9Z186OoP6/BZ6w9CyZD2iihXHHl2Cil91pE=",
|
| 14 |
"noop.wgsl.jinja": "k/5BMD6UO81N7XlF+t4iSKyt3dbtcqNMCru5aUKNBKE=",
|
| 15 |
+
"norm-flat-apply.wgsl.jinja": "fJkwUp+SOc5+EV2M+skzaoOyf4cCAj6RE/l9EFpRzlw=",
|
| 16 |
+
"norm-flat-splitk-combine.wgsl.jinja": "qrWEZGCTfaNnkDSBX7p6j+pnJHKCaAwFmHIXe0DJQC0=",
|
| 17 |
+
"norm-flat-splitk-partials.wgsl.jinja": "mQFvRpYjvQsoFwdFiShP0nMYFrWbaGmWxYIMXrSi4Sc=",
|
| 18 |
+
"test.json": "bGHJmclwK4mv21Rm4JYKnWsrwe5GeHdDnBXy+q8fIj8="
|
| 19 |
}
|
| 20 |
},
|
| 21 |
+
"provenance": { "kernel": { "sha": "91d990483a174128daf7673f3f37a7c890493ae1", "dirty": false } },
|
| 22 |
+
"webgpu": {
|
| 23 |
+
"manifestSpec": "2.0",
|
| 24 |
+
"variants": {
|
| 25 |
+
"empty_noop": ["noop.wgsl.jinja"],
|
| 26 |
+
"all_axes_flat_split": ["norm-flat-apply.wgsl.jinja", "norm-flat-splitk-combine.wgsl.jinja", "norm-flat-splitk-partials.wgsl.jinja"],
|
| 27 |
+
"serial_rows": ["mean-variance-normalization-serial-rows.wgsl.jinja"],
|
| 28 |
+
"cooperative_vec4": ["mean-variance-normalization-subgroup.wgsl.jinja"],
|
| 29 |
+
"cooperative_scalar": ["mean-variance-normalization-subgroup.wgsl.jinja"]
|
| 30 |
+
}
|
| 31 |
+
}
|
| 32 |
}
|
build/webgpu/norm-flat-apply.wgsl.jinja
CHANGED
|
@@ -1,14 +1,13 @@
|
|
| 1 |
-
{% if
|
| 2 |
enable f16;
|
| 3 |
{% endif %}
|
| 4 |
{{ env.wgsl.resourceDeclarations }}
|
| 5 |
|
| 6 |
-
@compute @workgroup_size({{
|
| 7 |
-
fn main(@builtin(global_invocation_id) gid: vec3<u32>
|
| 8 |
-
|
| 9 |
-
let i = gid.x + gid.y * nwg.x * {{ source.workgroupSize }}u;
|
| 10 |
if (i >= params.count) {
|
| 11 |
return;
|
| 12 |
}
|
| 13 |
-
y[i] = {{
|
| 14 |
}
|
|
|
|
| 1 |
+
{% if usesF16Spec %}
|
| 2 |
enable f16;
|
| 3 |
{% endif %}
|
| 4 |
{{ env.wgsl.resourceDeclarations }}
|
| 5 |
|
| 6 |
+
@compute @workgroup_size({{ workgroupSizeSpec }}, 1, 1)
|
| 7 |
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
| 8 |
+
let i = gid.x + gid.y * {{ DISPATCH_FOLD_WIDTH }}u * {{ workgroupSizeSpec }}u;
|
|
|
|
| 9 |
if (i >= params.count) {
|
| 10 |
return;
|
| 11 |
}
|
| 12 |
+
y[i] = {{ scalar }}((f32(x[i]) - stats[0]) / stats[1]);
|
| 13 |
}
|
build/webgpu/norm-flat-splitk-combine.wgsl.jinja
CHANGED
|
@@ -1,9 +1,9 @@
|
|
| 1 |
-
{% if
|
| 2 |
enable f16;
|
| 3 |
{% endif %}
|
| 4 |
{{ env.wgsl.resourceDeclarations }}
|
| 5 |
|
| 6 |
-
const SPLIT: u32 = {{
|
| 7 |
|
| 8 |
@compute @workgroup_size(1, 1, 1)
|
| 9 |
fn main() {
|
|
|
|
| 1 |
+
{% if usesF16Spec %}
|
| 2 |
enable f16;
|
| 3 |
{% endif %}
|
| 4 |
{{ env.wgsl.resourceDeclarations }}
|
| 5 |
|
| 6 |
+
const SPLIT: u32 = {{ splitSpec }}u;
|
| 7 |
|
| 8 |
@compute @workgroup_size(1, 1, 1)
|
| 9 |
fn main() {
|
build/webgpu/norm-flat-splitk-partials.wgsl.jinja
CHANGED
|
@@ -1,10 +1,10 @@
|
|
| 1 |
-
{% if
|
| 2 |
enable f16;
|
| 3 |
{% endif %}
|
| 4 |
{{ env.wgsl.resourceDeclarations }}
|
| 5 |
|
| 6 |
-
const WG: u32 = {{
|
| 7 |
-
const SPLIT: u32 = {{
|
| 8 |
|
| 9 |
var<workgroup> reduction: array<vec2<f32>, WG>;
|
| 10 |
|
|
|
|
| 1 |
+
{% if usesF16Spec %}
|
| 2 |
enable f16;
|
| 3 |
{% endif %}
|
| 4 |
{{ env.wgsl.resourceDeclarations }}
|
| 5 |
|
| 6 |
+
const WG: u32 = {{ workgroupSizeSpec }}u;
|
| 7 |
+
const SPLIT: u32 = {{ splitSpec }}u;
|
| 8 |
|
| 9 |
var<workgroup> reduction: array<vec2<f32>, WG>;
|
| 10 |
|
build/webgpu/test.json
CHANGED
|
@@ -1,5 +1,4 @@
|
|
| 1 |
{
|
| 2 |
-
"op": "ai.onnx.MeanVarianceNormalization",
|
| 3 |
"fixtureArrays": {
|
| 4 |
"ort_axes_subset_rank5_0_2_4_input_x": [0.6369617, 0.2697867, 0.0409735, 0.0165276, 0.8132702, 0.9127556, 0.6066358, 0.7294966, 0.543625, 0.9350724, 0.8158536, 0.0027385, 0.8574043, 0.0335856, 0.7296554, 0.1756556, 0.8631789, 0.5414612, 0.2997119, 0.4226872, 0.0283197, 0.1242833, 0.6706244, 0.6471895, 0.6153851, 0.3836776, 0.9972099, 0.9808353, 0.685542, 0.6504593, 0.6884467, 0.3889214]
|
| 5 |
},
|
|
@@ -144,7 +143,7 @@
|
|
| 144 |
"provenance": {
|
| 145 |
"source": "onnxruntime/test/providers/cpu/tensor/mean_variance_normalization_test.cc",
|
| 146 |
"test": "MeanVarianceNormalizationTest.DefaultAxes",
|
| 147 |
-
"notes": "
|
| 148 |
},
|
| 149 |
"attrs": { "axes": [0, 2, 3] },
|
| 150 |
"inputs": {
|
|
@@ -165,7 +164,7 @@
|
|
| 165 |
"provenance": {
|
| 166 |
"source": "onnxruntime/test/providers/cpu/tensor/mean_variance_normalization_test.cc",
|
| 167 |
"test": "MeanVarianceNormalizationTest.DefaultAxes",
|
| 168 |
-
"notes": "
|
| 169 |
},
|
| 170 |
"attrs": { "axes": [0, 2, 3, 4] },
|
| 171 |
"inputs": {
|
|
@@ -259,7 +258,7 @@
|
|
| 259 |
{
|
| 260 |
"name": "f32_spatial_axes_2x8x32x32",
|
| 261 |
"provenance": {
|
| 262 |
-
"notes": "
|
| 263 |
},
|
| 264 |
"attrs": { "axes": [2, 3] },
|
| 265 |
"inputs": {
|
|
@@ -566,7 +565,7 @@
|
|
| 566 |
{
|
| 567 |
"name": "rank5_serial_rows_channel_axis_f16",
|
| 568 |
"provenance": {
|
| 569 |
-
"notes": "
|
| 570 |
},
|
| 571 |
"attrs": { "axes": [1] },
|
| 572 |
"inputs": {
|
|
@@ -577,6 +576,23 @@
|
|
| 577 |
}
|
| 578 |
},
|
| 579 |
"outputs": { "y": { "dtype": "float16", "shape": [2, 32, 8, 8, 4], "tolerance": 0.02 } }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 580 |
}
|
| 581 |
]
|
| 582 |
}
|
|
|
|
| 1 |
{
|
|
|
|
| 2 |
"fixtureArrays": {
|
| 3 |
"ort_axes_subset_rank5_0_2_4_input_x": [0.6369617, 0.2697867, 0.0409735, 0.0165276, 0.8132702, 0.9127556, 0.6066358, 0.7294966, 0.543625, 0.9350724, 0.8158536, 0.0027385, 0.8574043, 0.0335856, 0.7296554, 0.1756556, 0.8631789, 0.5414612, 0.2997119, 0.4226872, 0.0283197, 0.1242833, 0.6706244, 0.6471895, 0.6153851, 0.3836776, 0.9972099, 0.9808353, 0.685542, 0.6504593, 0.6884467, 0.3889214]
|
| 4 |
},
|
|
|
|
| 143 |
"provenance": {
|
| 144 |
"source": "onnxruntime/test/providers/cpu/tensor/mean_variance_normalization_test.cc",
|
| 145 |
"test": "MeanVarianceNormalizationTest.DefaultAxes",
|
| 146 |
+
"notes": "With rank-4 default spatial axes, a positive subnormal variance must produce a finite normalized output."
|
| 147 |
},
|
| 148 |
"attrs": { "axes": [0, 2, 3] },
|
| 149 |
"inputs": {
|
|
|
|
| 164 |
"provenance": {
|
| 165 |
"source": "onnxruntime/test/providers/cpu/tensor/mean_variance_normalization_test.cc",
|
| 166 |
"test": "MeanVarianceNormalizationTest.DefaultAxes",
|
| 167 |
+
"notes": "With a rank-5 input, a positive subnormal reduced variance must produce finite normalized values."
|
| 168 |
},
|
| 169 |
"attrs": { "axes": [0, 2, 3, 4] },
|
| 170 |
"inputs": {
|
|
|
|
| 258 |
{
|
| 259 |
"name": "f32_spatial_axes_2x8x32x32",
|
| 260 |
"provenance": {
|
| 261 |
+
"notes": "A compact input exercises axes [2,3] over many channel planes without benchmark-scale tensors."
|
| 262 |
},
|
| 263 |
"attrs": { "axes": [2, 3] },
|
| 264 |
"inputs": {
|
|
|
|
| 565 |
{
|
| 566 |
"name": "rank5_serial_rows_channel_axis_f16",
|
| 567 |
"provenance": {
|
| 568 |
+
"notes": "Float16 data exercises the coalesced serial-row path with at least SERIAL_MIN_ROWS independent rows and a reduction within SERIAL_MAX_REDUCTION."
|
| 569 |
},
|
| 570 |
"attrs": { "axes": [1] },
|
| 571 |
"inputs": {
|
|
|
|
| 576 |
}
|
| 577 |
},
|
| 578 |
"outputs": { "y": { "dtype": "float16", "shape": [2, 32, 8, 8, 4], "tolerance": 0.02 } }
|
| 579 |
+
},
|
| 580 |
+
{
|
| 581 |
+
"name": "rank7_last_axis_above_axis_table",
|
| 582 |
+
"provenance": {
|
| 583 |
+
"notes": "A rank-7 input reduced along its final axis exercises axis 6. Each independent 64-element row must be normalized across that last dimension."
|
| 584 |
+
},
|
| 585 |
+
"attrs": { "axes": [-1] },
|
| 586 |
+
"inputs": {
|
| 587 |
+
"x": {
|
| 588 |
+
"dtype": "float32",
|
| 589 |
+
"shape": [1, 4, 2, 2, 2, 2, 64],
|
| 590 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.013, "cosStep": 0.029, "scale": 1.0 }
|
| 591 |
+
}
|
| 592 |
+
},
|
| 593 |
+
"outputs": {
|
| 594 |
+
"y": { "dtype": "float32", "shape": [1, 4, 2, 2, 2, 2, 64], "tolerance": 0.00002, "relTolerance": 0.00002 }
|
| 595 |
+
}
|
| 596 |
}
|
| 597 |
]
|
| 598 |
}
|