Xenova's picture
Xenova HF Staff
sync 2e7068faf55e
386747d verified
Raw
History Blame
14.7 kB
{
"domain": "ai.onnx",
"name": "MeanVarianceNormalization",
"sinceVersion": 13,
"description": "Normalizes each group as `(X - mean) / sqrt(variance)`, reducing over `axes` (default `[0, 2, 3]`).",
"inputs": [{ "role": "X", "dtype": "T", "description": "Input tensor to normalize." }],
"outputs": [
{
"role": "Y",
"dtype": "T",
"rank": "ranks.X",
"description": "Normalized tensor with the same shape as `X`.",
"shape": "shapes.X"
}
],
"attributes": { "axes": [0, 2, 3] },
"attributeDescriptions": { "axes": "Axes that share a mean and variance; negative values count from the back." },
"typeConstraints": { "T": ["float32", "float16"] },
"args": {
"x": { "kind": "tensor", "semantic": "X", "role": "input" },
"y": { "kind": "tensor", "semantic": "Y", "role": "output" }
},
"tunables": {
"WORKGROUP_SIZE": 256,
"SERIAL_WORKGROUP_SIZE": 256,
"SERIAL_TINY_WORKGROUP_SIZE": 64,
"SERIAL_MAX_REDUCTION": 128,
"SERIAL_MIN_ROWS": 256,
"TREE_MEDIUM_WORKGROUP_SIZE": 64,
"VEC4_MIN_REDUCTION": 8,
"FLAT_SPLIT_MIN_ELEMENTS": 65536,
"FLAT_SPLIT_TARGET_ELEMENTS": 4096,
"MAX_FLAT_SPLITS": 256
},
"derive": {
"deviceWorkgroupCap": "min(device.limits.maxComputeInvocationsPerWorkgroup, device.limits.maxComputeWorkgroupSizeX)",
"foldedDispatchCapacity": "device.limits.maxComputeWorkgroupsPerDimension * device.limits.maxComputeWorkgroupsPerDimension",
"shapeContract": "ranks.X >= 3 and ranks.Y == ranks.X and sameShape(shapes.Y, shapes.X) and f16Ok(dtypes.T)",
"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)",
"rowCount": "numel(shapes.X) / max(1, reduceCount)",
"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))",
"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))))",
"maxWorkgroupSize": "min(tunables.WORKGROUP_SIZE, deviceWorkgroupCap)",
"minSubgroupSize": "device.adapterInfo.subgroupMinSize if has(device.adapterInfo, \"subgroupMinSize\") else 1",
"useSubgroups": "device.features.has(\"subgroups\") and has(device.adapterInfo, \"subgroupMinSize\") and minSubgroupSize > 0",
"scalarWorkgroupSize": "min(maxWorkgroupSize, tunables.TREE_MEDIUM_WORKGROUP_SIZE) if not useSubgroups and reduceCount > tunables.TREE_MEDIUM_WORKGROUP_SIZE and reduceCount <= 2 * tunables.TREE_MEDIUM_WORKGROUP_SIZE else min(maxWorkgroupSize, max(1, pow2ceil(reduceCount)))",
"vectorWorkgroupSize": "min(maxWorkgroupSize, max(1, pow2ceil(ceilDiv(reduceCount, 4))))",
"serialWorkgroupSize": "min(device.limits.maxComputeInvocationsPerWorkgroup, device.limits.maxComputeWorkgroupSizeX, (tunables.SERIAL_TINY_WORKGROUP_SIZE if reduceCount <= 4 else tunables.SERIAL_WORKGROUP_SIZE))",
"rowDispatchFits": "rowCount <= foldedDispatchCapacity",
"serialDispatchFits": "ceilDiv(rowCount, serialWorkgroupSize) <= foldedDispatchCapacity",
"applyDispatchFits": "ceilDiv(numel(shapes.Y), maxWorkgroupSize) <= foldedDispatchCapacity",
"scalarStorageFits": "scalarWorkgroupSize * 8 <= device.limits.maxComputeWorkgroupStorageSize",
"vectorStorageFits": "vectorWorkgroupSize * 8 <= device.limits.maxComputeWorkgroupStorageSize",
"flatSplit": "min(tunables.MAX_FLAT_SPLITS, pow2ceil(ceilDiv(numel(shapes.X), tunables.FLAT_SPLIT_TARGET_ELEMENTS)))",
"flatScratchBytes": "flatSplit * 8",
"flatPathFits": "flatSplit <= device.limits.maxComputeWorkgroupsPerDimension and flatScratchBytes <= device.limits.maxStorageBufferBindingSize and flatScratchBytes <= device.limits.maxBufferSize and maxWorkgroupSize * 8 <= device.limits.maxComputeWorkgroupStorageSize and applyDispatchFits"
},
"bindingSets": {
"rows": [
{
"name": "x",
"arg": "x",
"semantic": "X",
"buffer": { "type": "read-only-storage" },
"elementType": "$ioElement"
},
{ "name": "y", "arg": "y", "semantic": "Y", "buffer": { "type": "storage" }, "elementType": "$ioElement" },
{
"name": "params",
"semantic": "kernel.params",
"buffer": { "type": "uniform" },
"struct": { "name": "Params", "fields": [{ "name": "rows", "type": "u32", "value": "rowCount" }] }
}
],
"flatPartials": [
{ "name": "x", "arg": "x", "semantic": "X", "buffer": { "type": "read-only-storage" }, "elementType": "$scalar" },
{ "name": "partials", "semantic": "partials", "buffer": { "type": "storage" }, "elementType": "vec2<f32>" },
{
"name": "params",
"semantic": "kernel.params",
"buffer": { "type": "uniform" },
"struct": { "name": "Params", "fields": [{ "name": "count", "type": "u32", "value": "numel(shapes.X)" }] }
}
],
"flatCombine": [
{ "name": "x", "arg": "x", "semantic": "X", "buffer": { "type": "read-only-storage" }, "elementType": "$scalar" },
{
"name": "partials",
"semantic": "partials",
"buffer": { "type": "read-only-storage" },
"elementType": "vec2<f32>"
},
{ "name": "stats", "semantic": "stats", "buffer": { "type": "storage" }, "elementType": "f32", "length": 2 },
{
"name": "params",
"semantic": "kernel.params",
"buffer": { "type": "uniform" },
"struct": { "name": "Params", "fields": [{ "name": "count", "type": "u32", "value": "numel(shapes.X)" }] }
}
],
"flatApply": [
{ "name": "x", "arg": "x", "semantic": "X", "buffer": { "type": "read-only-storage" }, "elementType": "$scalar" },
{
"name": "stats",
"semantic": "stats",
"buffer": { "type": "read-only-storage" },
"elementType": "f32",
"length": 2
},
{ "name": "y", "arg": "y", "semantic": "Y", "buffer": { "type": "storage" }, "elementType": "$scalar" },
{
"name": "params",
"semantic": "kernel.params",
"buffer": { "type": "uniform" },
"struct": { "name": "Params", "fields": [{ "name": "count", "type": "u32", "value": "numel(shapes.Y)" }] }
}
],
"noopParams": [
{
"name": "params",
"semantic": "kernel.params",
"buffer": { "type": "uniform" },
"struct": { "name": "Params", "fields": [{ "name": "dummy", "type": "u32", "value": 0 }] }
}
]
},
"variants": [
{
"id": "empty_noop",
"priority": 200,
"when": ["shapeContract", "numel(shapes.X) == 0"],
"passes": [
{
"id": "noop",
"name": "MeanVarianceNormalization.Empty",
"shader": "noop.wgsl.jinja",
"bindings": "noopParams",
"dispatch": { "x": 0 }
}
]
},
{
"id": "all_axes_flat_split",
"priority": 120,
"when": ["shapeContract", "numel(shapes.X) > 0", "allAxesReduced", "numel(shapes.X) >= tunables.FLAT_SPLIT_MIN_ELEMENTS", "flatPathFits"],
"constants": { "scalar": "dtypes.T" },
"intermediates": [
{ "id": "partials", "dtype": "float32", "shape": "[flatSplit, 2]" },
{ "id": "stats", "dtype": "float32", "shape": "[2]" }
],
"passes": [
{
"id": "partials",
"name": "MeanVarianceNormalization.FlatPartials",
"source": {
"shader": "norm-flat-splitk-partials.wgsl.jinja",
"inputs": { "workgroupSize": "maxWorkgroupSize", "split": "flatSplit", "usesF16": "dtypes.T == \"f16\"" }
},
"bindings": "flatPartials",
"dispatch": { "workgroups": "flatSplit" }
},
{
"id": "combine",
"name": "MeanVarianceNormalization.FlatCombine",
"source": {
"shader": "norm-flat-splitk-combine.wgsl.jinja",
"inputs": { "split": "flatSplit", "usesF16": "dtypes.T == \"f16\"" }
},
"bindings": "flatCombine",
"dispatch": { "workgroups": 1 }
},
{
"id": "apply",
"name": "MeanVarianceNormalization.FlatApply",
"source": {
"shader": "norm-flat-apply.wgsl.jinja",
"inputs": { "workgroupSize": "maxWorkgroupSize", "scalar": "dtypes.T", "usesF16": "dtypes.T == \"f16\"" }
},
"bindings": "flatApply",
"dispatch": { "threads": "numel(shapes.Y)", "workgroupSize": "maxWorkgroupSize" }
}
]
},
{
"id": "serial_rows",
"priority": 115,
"when": ["shapeContract", "numel(shapes.X) > 0", "reduceCount <= tunables.SERIAL_MAX_REDUCTION", "rowCount >= tunables.SERIAL_MIN_ROWS", "serialDispatchFits"],
"constants": { "scalar": "dtypes.T", "ioElement": "dtypes.T" },
"passes": [
{
"id": "main",
"name": "MeanVarianceNormalization.SerialRows",
"source": {
"shader": "mean-variance-normalization-serial-rows.wgsl.jinja",
"inputs": {
"xShape": "shapes.X",
"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)"],
"reduceCount": "reduceCount",
"workgroupSize": "serialWorkgroupSize",
"scalar": "dtypes.T",
"usesF16": "dtypes.T == \"f16\""
}
},
"bindings": "rows",
"dispatch": { "threads": "rowCount", "workgroupSize": "serialWorkgroupSize" }
}
]
},
{
"id": "cooperative_vec4",
"priority": 110,
"when": ["shapeContract", "numel(shapes.X) > 0", "reduceCount >= tunables.VEC4_MIN_REDUCTION", "vec4Eligible", "rowDispatchFits", "vectorStorageFits"],
"constants": {
"scalar": "dtypes.T",
"vectorScalar": "\"vec4<\" ~ dtypes.T ~ \">\"",
"ioElement": "\"vec4<\" ~ dtypes.T ~ \">\""
},
"passes": [
{
"id": "main",
"name": "MeanVarianceNormalization.CooperativeVec4",
"source": {
"shader": "mean-variance-normalization-subgroup.wgsl.jinja",
"inputs": {
"xShape": "shapes.X",
"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)"],
"reduceCount": "reduceCount",
"wg": "vectorWorkgroupSize",
"minSubgroupSize": "minSubgroupSize",
"maxSubgroups": "ceilDiv(vectorWorkgroupSize, minSubgroupSize)",
"scalar": "dtypes.T",
"vecType": "\"vec4<\" ~ dtypes.T ~ \">\"",
"usesF16": "dtypes.T == \"f16\"",
"useSubgroups": "useSubgroups",
"vectorized": true
}
},
"bindings": "rows",
"dispatch": { "workgroups": "rowCount" }
}
]
},
{
"id": "cooperative_scalar",
"priority": 100,
"when": ["shapeContract", "numel(shapes.X) > 0", "rowDispatchFits", "scalarStorageFits"],
"constants": { "scalar": "dtypes.T", "ioElement": "dtypes.T" },
"passes": [
{
"id": "main",
"name": "MeanVarianceNormalization.CooperativeScalar",
"source": {
"shader": "mean-variance-normalization-subgroup.wgsl.jinja",
"inputs": {
"xShape": "shapes.X",
"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)"],
"reduceCount": "reduceCount",
"wg": "scalarWorkgroupSize",
"minSubgroupSize": "minSubgroupSize",
"maxSubgroups": "ceilDiv(scalarWorkgroupSize, minSubgroupSize)",
"scalar": "dtypes.T",
"usesF16": "dtypes.T == \"f16\"",
"useSubgroups": "useSubgroups",
"vectorized": false
}
},
"bindings": "rows",
"dispatch": { "workgroups": "rowCount" }
}
]
}
]
}