sync 91d990483a17
Browse files- README.md +18 -15
- build/webgpu/bench.json +0 -1
- build/webgpu/datamove-flat-copy.wgsl.jinja +1 -4
- build/webgpu/datamove-split-block.wgsl.jinja +26 -29
- build/webgpu/manifest.json +194 -333
- build/webgpu/metadata.json +22 -9
- build/webgpu/split-n.wgsl.jinja +12 -15
- build/webgpu/test.json +10 -11
README.md
CHANGED
|
@@ -18,20 +18,20 @@ See the [ONNX `Split` spec](https://onnx.ai/onnx/operators/onnx__Split.html) for
|
|
| 18 |
|
| 19 |
## Inputs
|
| 20 |
|
| 21 |
-
| Name |
|
| 22 |
-
| --- | --- | --- | --- | --- | --- | --- |
|
| 23 |
-
| `input` | `
|
| 24 |
-
| `split` | `
|
| 25 |
|
| 26 |
## Outputs
|
| 27 |
|
| 28 |
-
| Name |
|
| 29 |
| --- | --- | --- | --- | --- | --- | --- |
|
| 30 |
-
| `
|
| 31 |
-
| `
|
| 32 |
-
| `
|
| 33 |
-
| `
|
| 34 |
-
| `
|
| 35 |
|
| 36 |
## Attributes
|
| 37 |
|
|
@@ -51,7 +51,7 @@ Attributes and default values (overridable per request):
|
|
| 51 |
|
| 52 |
## Files
|
| 53 |
|
| 54 |
-
- [`metadata.json`](build/webgpu/metadata.json) — kernel metadata (id, digests, provenance)
|
| 55 |
- [`manifest.json`](build/webgpu/manifest.json) — the op contract (source of truth)
|
| 56 |
- [`test.json`](build/webgpu/test.json) — correctness cases
|
| 57 |
- [`bench.json`](build/webgpu/bench.json) — benchmark + tuning cases
|
|
@@ -61,17 +61,20 @@ Attributes and default values (overridable per request):
|
|
| 61 |
|
| 62 |
## Use with `@huggingface/kernels`
|
| 63 |
|
| 64 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 65 |
|
| 66 |
-
|
| 67 |
|
| 68 |
- `y0`
|
| 69 |
- `y1`
|
| 70 |
- `y2`
|
| 71 |
|
| 72 |
-
Each entry either requests an optional result or supplies metadata that cannot be inferred from the inputs.
|
| 73 |
-
|
| 74 |
The `version: 1` option selects the published kernel contract; it is independent of any operator opset, contrib `since_version`, or model version.
|
|
|
|
| 75 |
|
| 76 |
Replace each `*Data` placeholder with a typed array containing the corresponding input data.
|
| 77 |
|
|
|
|
| 18 |
|
| 19 |
## Inputs
|
| 20 |
|
| 21 |
+
| Name | Logical dtype | WebGPU storage | Rank | Shape | Description | Presence |
|
| 22 |
+
| --- | --- | --- | --- | --- | --- | --- |
|
| 23 |
+
| `input` | `T` | runtime-selected; narrow integers and bool use 32-bit slots | — | — | The tensor to split. | required |
|
| 24 |
+
| `split` | `S` | `uint32` | `1` | — | Optional logical int64 1-D tensor specifying the size of each output along the split axis; values must be non-negative, sum to the axis dimension, and use uint32 WebGPU storage. | optional |
|
| 25 |
|
| 26 |
## Outputs
|
| 27 |
|
| 28 |
+
| Name | Upstream name | Logical dtype | Rank | Shape | Description | Presence |
|
| 29 |
| --- | --- | --- | --- | --- | --- | --- |
|
| 30 |
+
| `y0` | `Y0` | `T` | same as `input` | — | First output slice after splitting. | required |
|
| 31 |
+
| `y1` | `Y1` | `T` | same as `input` | — | Second output slice after splitting (optional). | optional |
|
| 32 |
+
| `y2` | `Y2` | `T` | same as `input` | — | Third output slice after splitting. | optional |
|
| 33 |
+
| `y3` | `Y3` | `T` | same as `input` | — | Fourth output slice after splitting. | optional |
|
| 34 |
+
| `y4` | `Y4` | `T` | same as `input` | — | Fifth output slice after splitting. | optional |
|
| 35 |
|
| 36 |
## Attributes
|
| 37 |
|
|
|
|
| 51 |
|
| 52 |
## Files
|
| 53 |
|
| 54 |
+
- [`metadata.json`](build/webgpu/metadata.json) — kernel metadata (id, digests, per-variant templates, provenance)
|
| 55 |
- [`manifest.json`](build/webgpu/manifest.json) — the op contract (source of truth)
|
| 56 |
- [`test.json`](build/webgpu/test.json) — correctness cases
|
| 57 |
- [`bench.json`](build/webgpu/bench.json) — benchmark + tuning cases
|
|
|
|
| 61 |
|
| 62 |
## Use with `@huggingface/kernels`
|
| 63 |
|
| 64 |
+
```sh
|
| 65 |
+
npm install --save-exact @huggingface/kernels@0.0.1-preview.2
|
| 66 |
+
```
|
| 67 |
+
|
| 68 |
+
Outputs with inferable metadata are allocated automatically. Explicit `outputs` entries request optional results or provide metadata that cannot be inferred from the supplied inputs and attributes.
|
| 69 |
|
| 70 |
+
This example supplies explicit metadata for:
|
| 71 |
|
| 72 |
- `y0`
|
| 73 |
- `y1`
|
| 74 |
- `y2`
|
| 75 |
|
|
|
|
|
|
|
| 76 |
The `version: 1` option selects the published kernel contract; it is independent of any operator opset, contrib `since_version`, or model version.
|
| 77 |
+
It follows the `v1` branch as fixes land. To pin exact artifact bytes, pass a 40-character commit `revision` instead of `version`.
|
| 78 |
|
| 79 |
Replace each `*Data` placeholder with a typed array containing the corresponding input data.
|
| 80 |
|
build/webgpu/bench.json
CHANGED
|
@@ -1,5 +1,4 @@
|
|
| 1 |
{
|
| 2 |
-
"op": "ai.onnx.Split",
|
| 3 |
"cases": [
|
| 4 |
{
|
| 5 |
"name": "qkv_like",
|
|
|
|
| 1 |
{
|
|
|
|
| 2 |
"cases": [
|
| 3 |
{
|
| 4 |
"name": "qkv_like",
|
build/webgpu/datamove-flat-copy.wgsl.jinja
CHANGED
|
@@ -1,9 +1,6 @@
|
|
| 1 |
-
{% if usesF16 %}
|
| 2 |
-
enable f16;
|
| 3 |
-
{% endif %}
|
| 4 |
{{ env.wgsl.resourceDeclarations }}
|
| 5 |
|
| 6 |
-
const COUNT: u32 = {{
|
| 7 |
const WG: u32 = {{ tunables.WORKGROUP_SIZE }}u;
|
| 8 |
|
| 9 |
@compute @workgroup_size({{ tunables.WORKGROUP_SIZE }})
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
{{ env.wgsl.resourceDeclarations }}
|
| 2 |
|
| 3 |
+
const COUNT: u32 = {{ count }}u;
|
| 4 |
const WG: u32 = {{ tunables.WORKGROUP_SIZE }}u;
|
| 5 |
|
| 6 |
@compute @workgroup_size({{ tunables.WORKGROUP_SIZE }})
|
build/webgpu/datamove-split-block.wgsl.jinja
CHANGED
|
@@ -3,35 +3,32 @@
|
|
| 3 |
// divisible by four, all run boundaries are vec4-aligned and the input and
|
| 4 |
// every output bind as vec4<T>. One division and one remainder per element
|
| 5 |
// replace the per-axis coordinate decomposition of the scalar fallback.
|
| 6 |
-
{% if usesF16 %}
|
| 7 |
-
enable f16;
|
| 8 |
-
{% endif %}
|
| 9 |
{{ env.wgsl.resourceDeclarations }}
|
| 10 |
|
| 11 |
{% set inner = namespace(value=1) %}
|
| 12 |
-
{% for j in range(
|
| 13 |
-
{% set inner.value = inner.value *
|
| 14 |
{% endfor %}
|
| 15 |
-
{% set y2Shape =
|
| 16 |
-
{% if
|
| 17 |
// Scalar-bound x4 mode keeps arbitrary split boundaries legal. Each invocation
|
| 18 |
// owns one four-scalar group within one outer slice, so a group never crosses
|
| 19 |
// into the next slice; only the final group of a run needs scalar tail guards.
|
| 20 |
-
{% set inner_in_scalar =
|
| 21 |
-
{% set run0_scalar =
|
| 22 |
-
{% set run1_scalar =
|
| 23 |
{% set groups0 = (((run0_scalar + 3) / 4) | int) %}
|
| 24 |
{% set groups1 = (((run1_scalar + 3) / 4) | int) %}
|
| 25 |
{% set outer_count = namespace(value=1) %}
|
| 26 |
-
{% for j in range(
|
| 27 |
-
{% set outer_count.value = outer_count.value *
|
| 28 |
{% endfor %}
|
| 29 |
{% set count0_groups = outer_count.value * groups0 %}
|
| 30 |
{% set count1_groups = outer_count.value * groups1 %}
|
| 31 |
{% set max_groups = namespace(value=count0_groups) %}
|
| 32 |
{% if count1_groups > max_groups.value %}{% set max_groups.value = count1_groups %}{% endif %}
|
| 33 |
{% set start1_scalar = run0_scalar %}
|
| 34 |
-
{% set run2_scalar = y2Shape[
|
| 35 |
{% set groups2 = (((run2_scalar + 3) / 4) | int) %}
|
| 36 |
{% set count2_groups = outer_count.value * groups2 %}
|
| 37 |
{% set start2_scalar = start1_scalar + run1_scalar %}
|
|
@@ -69,36 +66,36 @@ fn main(
|
|
| 69 |
}
|
| 70 |
}
|
| 71 |
{% else %}
|
| 72 |
-
{% set inner_in = (((
|
| 73 |
-
{% set run0 = (((
|
| 74 |
-
{% set run1 = (((
|
| 75 |
{% set has_nonempty_run = namespace(value=(run0 > 0 or run1 > 0)) %}
|
| 76 |
{% set start1 = run0 %}
|
| 77 |
{% set count0 = namespace(value=run0) %}
|
| 78 |
{% set count1 = namespace(value=run1) %}
|
| 79 |
-
{% for j in range(
|
| 80 |
-
{% set count0.value = count0.value *
|
| 81 |
-
{% set count1.value = count1.value *
|
| 82 |
{% endfor %}
|
| 83 |
{% set max_count = namespace(value=count0.value) %}
|
| 84 |
{% if count1.value > max_count.value %}{% set max_count.value = count1.value %}{% endif %}
|
| 85 |
-
{% if
|
| 86 |
-
{% set run2 = (((y2Shape[
|
| 87 |
{% if run2 > 0 %}{% set has_nonempty_run.value = true %}{% endif %}
|
| 88 |
{% set start2 = start1 + run1 %}
|
| 89 |
{% set count2 = namespace(value=run2) %}
|
| 90 |
-
{% for j in range(
|
| 91 |
-
{% set count2.value = count2.value *
|
| 92 |
{% endfor %}
|
| 93 |
{% if count2.value > max_count.value %}{% set max_count.value = count2.value %}{% endif %}
|
| 94 |
{% endif %}
|
| 95 |
-
{% if
|
| 96 |
-
{% set run3 = (((
|
| 97 |
{% if run3 > 0 %}{% set has_nonempty_run.value = true %}{% endif %}
|
| 98 |
{% set start3 = start2 + run2 %}
|
| 99 |
{% set count3 = namespace(value=run3) %}
|
| 100 |
-
{% for j in range(
|
| 101 |
-
{% set count3.value = count3.value *
|
| 102 |
{% endfor %}
|
| 103 |
{% if count3.value > max_count.value %}{% set max_count.value = count3.value %}{% endif %}
|
| 104 |
{% endif %}
|
|
@@ -125,12 +122,12 @@ fn main(
|
|
| 125 |
y1[i] = input[(i / {{ run1 }}u) * INNER_IN + {{ start1 }}u + (i % {{ run1 }}u)];
|
| 126 |
}
|
| 127 |
{% endif %}
|
| 128 |
-
{% if
|
| 129 |
if (i < {{ count2.value }}u) {
|
| 130 |
y2[i] = input[(i / {{ run2 }}u) * INNER_IN + {{ start2 }}u + (i % {{ run2 }}u)];
|
| 131 |
}
|
| 132 |
{% endif %}
|
| 133 |
-
{% if
|
| 134 |
if (i < {{ count3.value }}u) {
|
| 135 |
y3[i] = input[(i / {{ run3 }}u) * INNER_IN + {{ start3 }}u + (i % {{ run3 }}u)];
|
| 136 |
}
|
|
|
|
| 3 |
// divisible by four, all run boundaries are vec4-aligned and the input and
|
| 4 |
// every output bind as vec4<T>. One division and one remainder per element
|
| 5 |
// replace the per-axis coordinate decomposition of the scalar fallback.
|
|
|
|
|
|
|
|
|
|
| 6 |
{{ env.wgsl.resourceDeclarations }}
|
| 7 |
|
| 8 |
{% set inner = namespace(value=1) %}
|
| 9 |
+
{% for j in range(axisSpec + 1, rank) %}
|
| 10 |
+
{% set inner.value = inner.value * inputShape[j] %}
|
| 11 |
{% endfor %}
|
| 12 |
+
{% set y2Shape = y2Shape | default([]) %}
|
| 13 |
+
{% if scalarBoundX4 %}
|
| 14 |
// Scalar-bound x4 mode keeps arbitrary split boundaries legal. Each invocation
|
| 15 |
// owns one four-scalar group within one outer slice, so a group never crosses
|
| 16 |
// into the next slice; only the final group of a run needs scalar tail guards.
|
| 17 |
+
{% set inner_in_scalar = inputShape[axisSpec] * inner.value %}
|
| 18 |
+
{% set run0_scalar = y0Shape[axisSpec] * inner.value %}
|
| 19 |
+
{% set run1_scalar = y1Shape[axisSpec] * inner.value %}
|
| 20 |
{% set groups0 = (((run0_scalar + 3) / 4) | int) %}
|
| 21 |
{% set groups1 = (((run1_scalar + 3) / 4) | int) %}
|
| 22 |
{% set outer_count = namespace(value=1) %}
|
| 23 |
+
{% for j in range(axisSpec) %}
|
| 24 |
+
{% set outer_count.value = outer_count.value * inputShape[j] %}
|
| 25 |
{% endfor %}
|
| 26 |
{% set count0_groups = outer_count.value * groups0 %}
|
| 27 |
{% set count1_groups = outer_count.value * groups1 %}
|
| 28 |
{% set max_groups = namespace(value=count0_groups) %}
|
| 29 |
{% if count1_groups > max_groups.value %}{% set max_groups.value = count1_groups %}{% endif %}
|
| 30 |
{% set start1_scalar = run0_scalar %}
|
| 31 |
+
{% set run2_scalar = y2Shape[axisSpec] * inner.value %}
|
| 32 |
{% set groups2 = (((run2_scalar + 3) / 4) | int) %}
|
| 33 |
{% set count2_groups = outer_count.value * groups2 %}
|
| 34 |
{% set start2_scalar = start1_scalar + run1_scalar %}
|
|
|
|
| 66 |
}
|
| 67 |
}
|
| 68 |
{% else %}
|
| 69 |
+
{% set inner_in = (((inputShape[axisSpec] * inner.value) / 4) | int) %}
|
| 70 |
+
{% set run0 = (((y0Shape[axisSpec] * inner.value) / 4) | int) %}
|
| 71 |
+
{% set run1 = (((y1Shape[axisSpec] * inner.value) / 4) | int) %}
|
| 72 |
{% set has_nonempty_run = namespace(value=(run0 > 0 or run1 > 0)) %}
|
| 73 |
{% set start1 = run0 %}
|
| 74 |
{% set count0 = namespace(value=run0) %}
|
| 75 |
{% set count1 = namespace(value=run1) %}
|
| 76 |
+
{% for j in range(axisSpec) %}
|
| 77 |
+
{% set count0.value = count0.value * inputShape[j] %}
|
| 78 |
+
{% set count1.value = count1.value * inputShape[j] %}
|
| 79 |
{% endfor %}
|
| 80 |
{% set max_count = namespace(value=count0.value) %}
|
| 81 |
{% if count1.value > max_count.value %}{% set max_count.value = count1.value %}{% endif %}
|
| 82 |
+
{% if outputCountSpec >= 3 %}
|
| 83 |
+
{% set run2 = (((y2Shape[axisSpec] * inner.value) / 4) | int) %}
|
| 84 |
{% if run2 > 0 %}{% set has_nonempty_run.value = true %}{% endif %}
|
| 85 |
{% set start2 = start1 + run1 %}
|
| 86 |
{% set count2 = namespace(value=run2) %}
|
| 87 |
+
{% for j in range(axisSpec) %}
|
| 88 |
+
{% set count2.value = count2.value * inputShape[j] %}
|
| 89 |
{% endfor %}
|
| 90 |
{% if count2.value > max_count.value %}{% set max_count.value = count2.value %}{% endif %}
|
| 91 |
{% endif %}
|
| 92 |
+
{% if outputCountSpec >= 4 %}
|
| 93 |
+
{% set run3 = (((y3Shape[axisSpec] * inner.value) / 4) | int) %}
|
| 94 |
{% if run3 > 0 %}{% set has_nonempty_run.value = true %}{% endif %}
|
| 95 |
{% set start3 = start2 + run2 %}
|
| 96 |
{% set count3 = namespace(value=run3) %}
|
| 97 |
+
{% for j in range(axisSpec) %}
|
| 98 |
+
{% set count3.value = count3.value * inputShape[j] %}
|
| 99 |
{% endfor %}
|
| 100 |
{% if count3.value > max_count.value %}{% set max_count.value = count3.value %}{% endif %}
|
| 101 |
{% endif %}
|
|
|
|
| 122 |
y1[i] = input[(i / {{ run1 }}u) * INNER_IN + {{ start1 }}u + (i % {{ run1 }}u)];
|
| 123 |
}
|
| 124 |
{% endif %}
|
| 125 |
+
{% if outputCountSpec >= 3 and run2 > 0 %}
|
| 126 |
if (i < {{ count2.value }}u) {
|
| 127 |
y2[i] = input[(i / {{ run2 }}u) * INNER_IN + {{ start2 }}u + (i % {{ run2 }}u)];
|
| 128 |
}
|
| 129 |
{% endif %}
|
| 130 |
+
{% if outputCountSpec >= 4 and run3 > 0 %}
|
| 131 |
if (i < {{ count3.value }}u) {
|
| 132 |
y3[i] = input[(i / {{ run3 }}u) * INNER_IN + {{ start3 }}u + (i % {{ run3 }}u)];
|
| 133 |
}
|
build/webgpu/manifest.json
CHANGED
|
@@ -2,74 +2,23 @@
|
|
| 2 |
"domain": "ai.onnx",
|
| 3 |
"name": "Split",
|
| 4 |
"sinceVersion": 18,
|
| 5 |
-
"
|
| 6 |
-
|
| 7 |
-
{ "
|
| 8 |
-
{
|
| 9 |
-
"role": "split",
|
| 10 |
-
"dtype": "S",
|
| 11 |
-
"rank": 1,
|
| 12 |
-
"optional": true,
|
| 13 |
-
"description": "Optional logical int64 1-D tensor specifying the size of each output along the split axis; values must be non-negative, sum to the axis dimension, and use uint32 WebGPU storage."
|
| 14 |
-
}
|
| 15 |
-
],
|
| 16 |
-
"outputs": [
|
| 17 |
-
{ "role": "Y0", "dtype": "T", "description": "First output slice after splitting.", "rank": "ranks.input" },
|
| 18 |
-
{
|
| 19 |
-
"role": "Y1",
|
| 20 |
-
"dtype": "T",
|
| 21 |
-
"optional": true,
|
| 22 |
-
"description": "Second output slice after splitting (optional).",
|
| 23 |
-
"rank": "ranks.input"
|
| 24 |
-
},
|
| 25 |
-
{
|
| 26 |
-
"role": "Y2",
|
| 27 |
-
"dtype": "T",
|
| 28 |
-
"optional": true,
|
| 29 |
-
"description": "Third output slice after splitting.",
|
| 30 |
-
"rank": "ranks.input"
|
| 31 |
-
},
|
| 32 |
-
{
|
| 33 |
-
"role": "Y3",
|
| 34 |
-
"dtype": "T",
|
| 35 |
-
"optional": true,
|
| 36 |
-
"description": "Fourth output slice after splitting.",
|
| 37 |
-
"rank": "ranks.input"
|
| 38 |
-
},
|
| 39 |
-
{
|
| 40 |
-
"role": "Y4",
|
| 41 |
-
"dtype": "T",
|
| 42 |
-
"optional": true,
|
| 43 |
-
"description": "Fifth output slice after splitting.",
|
| 44 |
-
"rank": "ranks.input"
|
| 45 |
-
}
|
| 46 |
-
],
|
| 47 |
-
"attributes": { "axis": 0 },
|
| 48 |
-
"attributeDescriptions": {
|
| 49 |
-
"axis": "The axis along which to split. Negative values count from the end; accepted range is `[-rank, rank-1]`.",
|
| 50 |
-
"num_outputs": "Optional number of outputs when the `split` input is omitted. The final output may be smaller when the axis dimension is not evenly divisible."
|
| 51 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 52 |
"typeConstraints": {
|
| 53 |
"T": ["float32", "float16", "uint32", "int32", "int16", "uint8", "int8", "bool"],
|
| 54 |
"S": ["int64"]
|
| 55 |
},
|
| 56 |
-
"
|
| 57 |
-
"input": { "kind": "tensor", "semantic": "input", "role": "input" },
|
| 58 |
-
"split": {
|
| 59 |
-
"kind": "tensor",
|
| 60 |
-
"semantic": "split",
|
| 61 |
-
"role": "split",
|
| 62 |
-
"dtype": "uint32",
|
| 63 |
-
"narrowing": "checked",
|
| 64 |
-
"required": false
|
| 65 |
-
},
|
| 66 |
-
"y0": { "kind": "tensor", "semantic": "Y0", "role": "output" },
|
| 67 |
-
"y1": { "kind": "tensor", "semantic": "Y1", "role": "output", "required": false },
|
| 68 |
-
"y2": { "kind": "tensor", "semantic": "Y2", "role": "output", "required": false },
|
| 69 |
-
"y3": { "kind": "tensor", "semantic": "Y3", "role": "output", "required": false },
|
| 70 |
-
"y4": { "kind": "tensor", "semantic": "Y4", "role": "output", "required": false }
|
| 71 |
-
},
|
| 72 |
-
"tunables": { "WORKGROUP_SIZE": 256 },
|
| 73 |
"derive": {
|
| 74 |
"deviceWorkgroupCap": "min(device.limits.maxComputeInvocationsPerWorkgroup, device.limits.maxComputeWorkgroupSizeX)",
|
| 75 |
"axis": "attrs.axis if attrs.axis >= 0 else attrs.axis + ranks.input",
|
|
@@ -77,167 +26,67 @@
|
|
| 77 |
"numOutputsContract": "not has(attrs, \"num_outputs\") or attrs.num_outputs == outputCount",
|
| 78 |
"workgroupSize": "min(tunables.WORKGROUP_SIZE, deviceWorkgroupCap)",
|
| 79 |
"baseContract": "ranks.input >= 1 and axis >= 0 and axis < ranks.input and numOutputsContract and f16Ok(dtypes.T)",
|
| 80 |
-
"oneOutputContract": "baseContract and not present.y1 and not present.y2 and not present.y3 and not present.y4 and sameShape(shapes.input, shapes.
|
| 81 |
-
"twoOutputContract": "baseContract and present.y1 and not present.y2 and ranks.input == ranks.
|
| 82 |
-
"threeOutputContract": "baseContract and present.y1 and present.y2 and not present.y3 and ranks.input == ranks.
|
| 83 |
-
"fourOutputContract": "baseContract and present.y1 and present.y2 and present.y3 and not present.y4 and ranks.input == ranks.
|
| 84 |
-
"fiveOutputContract": "baseContract and present.y1 and present.y2 and present.y3 and present.y4 and ranks.input == ranks.
|
| 85 |
-
"twoBlockContract": "twoOutputContract and outer(shapes.
|
| 86 |
-
"threeBlockContract": "threeOutputContract and outer(shapes.
|
| 87 |
-
"fourBlockContract": "fourOutputContract and outer(shapes.
|
|
|
|
| 88 |
},
|
| 89 |
-
"
|
| 90 |
-
|
| 91 |
-
"
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
"name": "
|
| 104 |
-
"
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
"name": "
|
| 115 |
-
"
|
| 116 |
-
"
|
| 117 |
-
"
|
| 118 |
-
"
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
"name": "
|
| 127 |
-
"
|
| 128 |
-
"
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
"arg": "input",
|
| 141 |
-
"semantic": "input",
|
| 142 |
-
"buffer": { "type": "read-only-storage" },
|
| 143 |
-
"elementType": "$scalar"
|
| 144 |
-
},
|
| 145 |
-
{ "name": "y0", "arg": "y0", "semantic": "Y0", "buffer": { "type": "storage" }, "elementType": "$scalar" },
|
| 146 |
-
{ "name": "y1", "arg": "y1", "semantic": "Y1", "buffer": { "type": "storage" }, "elementType": "$scalar" },
|
| 147 |
-
{
|
| 148 |
-
"name": "params",
|
| 149 |
-
"semantic": "kernel.params",
|
| 150 |
-
"buffer": { "type": "uniform" },
|
| 151 |
-
"struct": {
|
| 152 |
-
"name": "Params",
|
| 153 |
-
"fields": [
|
| 154 |
-
{ "name": "y0Count", "type": "u32", "value": "numel(shapes.Y0)" },
|
| 155 |
-
{ "name": "y1Count", "type": "u32", "value": "numel(shapes.Y1)" }
|
| 156 |
-
]
|
| 157 |
-
}
|
| 158 |
-
}
|
| 159 |
-
],
|
| 160 |
-
"fiveScalar": [
|
| 161 |
-
{
|
| 162 |
-
"name": "input",
|
| 163 |
-
"arg": "input",
|
| 164 |
-
"semantic": "input",
|
| 165 |
-
"buffer": { "type": "read-only-storage" },
|
| 166 |
-
"elementType": "$scalar"
|
| 167 |
-
},
|
| 168 |
-
{ "name": "y0", "arg": "y0", "semantic": "Y0", "buffer": { "type": "storage" }, "elementType": "$scalar" },
|
| 169 |
-
{ "name": "y1", "arg": "y1", "semantic": "Y1", "buffer": { "type": "storage" }, "elementType": "$scalar" },
|
| 170 |
-
{ "name": "y2", "arg": "y2", "semantic": "Y2", "buffer": { "type": "storage" }, "elementType": "$scalar" },
|
| 171 |
-
{ "name": "y3", "arg": "y3", "semantic": "Y3", "buffer": { "type": "storage" }, "elementType": "$scalar" },
|
| 172 |
-
{ "name": "y4", "arg": "y4", "semantic": "Y4", "buffer": { "type": "storage" }, "elementType": "$scalar" },
|
| 173 |
-
{
|
| 174 |
-
"name": "params",
|
| 175 |
-
"semantic": "kernel.params",
|
| 176 |
-
"buffer": { "type": "uniform" },
|
| 177 |
-
"struct": {
|
| 178 |
-
"name": "Params",
|
| 179 |
-
"fields": [
|
| 180 |
-
{ "name": "y0Count", "type": "u32", "value": "numel(shapes.Y0)" },
|
| 181 |
-
{ "name": "y1Count", "type": "u32", "value": "numel(shapes.Y1)" },
|
| 182 |
-
{ "name": "y2Count", "type": "u32", "value": "numel(shapes.Y2)" },
|
| 183 |
-
{ "name": "y3Count", "type": "u32", "value": "numel(shapes.Y3)" },
|
| 184 |
-
{ "name": "y4Count", "type": "u32", "value": "numel(shapes.Y4)" }
|
| 185 |
-
]
|
| 186 |
-
}
|
| 187 |
-
}
|
| 188 |
-
],
|
| 189 |
-
"fourScalar": [
|
| 190 |
-
{
|
| 191 |
-
"name": "input",
|
| 192 |
-
"arg": "input",
|
| 193 |
-
"semantic": "input",
|
| 194 |
-
"buffer": { "type": "read-only-storage" },
|
| 195 |
-
"elementType": "$scalar"
|
| 196 |
-
},
|
| 197 |
-
{ "name": "y0", "arg": "y0", "semantic": "Y0", "buffer": { "type": "storage" }, "elementType": "$scalar" },
|
| 198 |
-
{ "name": "y1", "arg": "y1", "semantic": "Y1", "buffer": { "type": "storage" }, "elementType": "$scalar" },
|
| 199 |
-
{ "name": "y2", "arg": "y2", "semantic": "Y2", "buffer": { "type": "storage" }, "elementType": "$scalar" },
|
| 200 |
-
{ "name": "y3", "arg": "y3", "semantic": "Y3", "buffer": { "type": "storage" }, "elementType": "$scalar" },
|
| 201 |
-
{
|
| 202 |
-
"name": "params",
|
| 203 |
-
"semantic": "kernel.params",
|
| 204 |
-
"buffer": { "type": "uniform" },
|
| 205 |
-
"struct": {
|
| 206 |
-
"name": "Params",
|
| 207 |
-
"fields": [
|
| 208 |
-
{ "name": "y0Count", "type": "u32", "value": "numel(shapes.Y0)" },
|
| 209 |
-
{ "name": "y1Count", "type": "u32", "value": "numel(shapes.Y1)" },
|
| 210 |
-
{ "name": "y2Count", "type": "u32", "value": "numel(shapes.Y2)" },
|
| 211 |
-
{ "name": "y3Count", "type": "u32", "value": "numel(shapes.Y3)" }
|
| 212 |
-
]
|
| 213 |
-
}
|
| 214 |
-
}
|
| 215 |
-
],
|
| 216 |
-
"threeScalar": [
|
| 217 |
-
{
|
| 218 |
-
"name": "input",
|
| 219 |
-
"arg": "input",
|
| 220 |
-
"semantic": "input",
|
| 221 |
-
"buffer": { "type": "read-only-storage" },
|
| 222 |
-
"elementType": "$scalar"
|
| 223 |
-
},
|
| 224 |
-
{ "name": "y0", "arg": "y0", "semantic": "Y0", "buffer": { "type": "storage" }, "elementType": "$scalar" },
|
| 225 |
-
{ "name": "y1", "arg": "y1", "semantic": "Y1", "buffer": { "type": "storage" }, "elementType": "$scalar" },
|
| 226 |
-
{ "name": "y2", "arg": "y2", "semantic": "Y2", "buffer": { "type": "storage" }, "elementType": "$scalar" },
|
| 227 |
-
{
|
| 228 |
-
"name": "params",
|
| 229 |
-
"semantic": "kernel.params",
|
| 230 |
-
"buffer": { "type": "uniform" },
|
| 231 |
-
"struct": {
|
| 232 |
-
"name": "Params",
|
| 233 |
-
"fields": [
|
| 234 |
-
{ "name": "y0Count", "type": "u32", "value": "numel(shapes.Y0)" },
|
| 235 |
-
{ "name": "y1Count", "type": "u32", "value": "numel(shapes.Y1)" },
|
| 236 |
-
{ "name": "y2Count", "type": "u32", "value": "numel(shapes.Y2)" }
|
| 237 |
-
]
|
| 238 |
-
}
|
| 239 |
-
}
|
| 240 |
-
]
|
| 241 |
},
|
| 242 |
"variants": [
|
| 243 |
{
|
|
@@ -248,9 +97,17 @@
|
|
| 248 |
{
|
| 249 |
"id": "main",
|
| 250 |
"name": "Split.copy",
|
| 251 |
-
"
|
| 252 |
-
"
|
| 253 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 254 |
"viewAlias": [{ "input": "src", "output": "dst" }]
|
| 255 |
}
|
| 256 |
]
|
|
@@ -258,54 +115,55 @@
|
|
| 258 |
{
|
| 259 |
"id": "two_outputs_block_vec4",
|
| 260 |
"priority": 15,
|
| 261 |
-
"when": ["twoBlockContract", "(dim(shapes.
|
| 262 |
-
"
|
| 263 |
"passes": [
|
| 264 |
{
|
| 265 |
"id": "main",
|
| 266 |
"name": "Split.blockVec4",
|
| 267 |
-
"
|
| 268 |
-
|
| 269 |
-
"
|
| 270 |
-
|
| 271 |
-
|
| 272 |
-
|
| 273 |
-
|
| 274 |
-
|
| 275 |
-
"outputCount": 2
|
| 276 |
-
}
|
| 277 |
},
|
| 278 |
-
"bindings": "
|
| 279 |
-
"dispatch": {
|
|
|
|
|
|
|
|
|
|
|
|
|
| 280 |
}
|
| 281 |
]
|
| 282 |
},
|
| 283 |
{
|
| 284 |
"id": "three_outputs_block_scalar_x4",
|
| 285 |
"priority": 14,
|
| 286 |
-
"when": ["threeBlockContract", "dim(shapes.
|
| 287 |
-
"
|
| 288 |
"passes": [
|
| 289 |
{
|
| 290 |
"id": "main",
|
| 291 |
"name": "Split3.blockScalarX4",
|
| 292 |
-
"
|
| 293 |
-
|
| 294 |
-
"
|
| 295 |
-
|
| 296 |
-
|
| 297 |
-
|
| 298 |
-
|
| 299 |
-
|
| 300 |
-
|
| 301 |
-
|
| 302 |
-
"scalarBoundX4": true
|
| 303 |
-
}
|
| 304 |
},
|
| 305 |
-
"bindings": "
|
| 306 |
"dispatch": {
|
| 307 |
-
"
|
| 308 |
-
"
|
|
|
|
| 309 |
}
|
| 310 |
}
|
| 311 |
]
|
|
@@ -313,28 +171,27 @@
|
|
| 313 |
{
|
| 314 |
"id": "three_outputs_block_vec4",
|
| 315 |
"priority": 15,
|
| 316 |
-
"when": ["threeBlockContract", "(dim(shapes.
|
| 317 |
-
"
|
| 318 |
"passes": [
|
| 319 |
{
|
| 320 |
"id": "main",
|
| 321 |
"name": "Split3.blockVec4",
|
| 322 |
-
"
|
| 323 |
-
|
| 324 |
-
"
|
| 325 |
-
|
| 326 |
-
|
| 327 |
-
|
| 328 |
-
|
| 329 |
-
|
| 330 |
-
|
| 331 |
-
"outputCount": 3
|
| 332 |
-
}
|
| 333 |
},
|
| 334 |
-
"bindings": "
|
| 335 |
"dispatch": {
|
| 336 |
-
"
|
| 337 |
-
"
|
|
|
|
| 338 |
}
|
| 339 |
}
|
| 340 |
]
|
|
@@ -342,29 +199,34 @@
|
|
| 342 |
{
|
| 343 |
"id": "four_outputs_block_vec4",
|
| 344 |
"priority": 25,
|
| 345 |
-
"when": ["fourBlockContract", "(dim(shapes.
|
| 346 |
-
"
|
| 347 |
"passes": [
|
| 348 |
{
|
| 349 |
"id": "main",
|
| 350 |
"name": "Split4.blockVec4",
|
| 351 |
-
"
|
| 352 |
-
|
| 353 |
-
"
|
| 354 |
-
|
| 355 |
-
|
| 356 |
-
|
| 357 |
-
|
| 358 |
-
|
| 359 |
-
|
| 360 |
-
|
| 361 |
-
"outputCount": 4
|
| 362 |
-
}
|
| 363 |
},
|
| 364 |
-
"bindings":
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 365 |
"dispatch": {
|
| 366 |
-
"
|
| 367 |
-
"
|
|
|
|
| 368 |
}
|
| 369 |
}
|
| 370 |
]
|
|
@@ -376,17 +238,19 @@
|
|
| 376 |
{
|
| 377 |
"id": "main",
|
| 378 |
"name": "Split",
|
| 379 |
-
"
|
| 380 |
-
|
| 381 |
-
"
|
| 382 |
-
|
| 383 |
-
|
| 384 |
-
|
| 385 |
-
"axis": "axis"
|
| 386 |
-
}
|
| 387 |
},
|
| 388 |
-
"bindings": "
|
| 389 |
-
"dispatch": {
|
|
|
|
|
|
|
|
|
|
|
|
|
| 390 |
}
|
| 391 |
]
|
| 392 |
},
|
|
@@ -398,19 +262,18 @@
|
|
| 398 |
{
|
| 399 |
"id": "main",
|
| 400 |
"name": "SplitN",
|
| 401 |
-
"
|
| 402 |
-
|
| 403 |
-
"
|
| 404 |
-
|
| 405 |
-
|
| 406 |
-
|
| 407 |
-
"axis": "axis"
|
| 408 |
-
}
|
| 409 |
},
|
| 410 |
-
"bindings": "
|
| 411 |
"dispatch": {
|
| 412 |
-
"
|
| 413 |
-
"
|
|
|
|
| 414 |
}
|
| 415 |
}
|
| 416 |
]
|
|
@@ -423,19 +286,18 @@
|
|
| 423 |
{
|
| 424 |
"id": "main",
|
| 425 |
"name": "Split4",
|
| 426 |
-
"
|
| 427 |
-
|
| 428 |
-
"
|
| 429 |
-
|
| 430 |
-
|
| 431 |
-
|
| 432 |
-
"axis": "axis"
|
| 433 |
-
}
|
| 434 |
},
|
| 435 |
-
"bindings": "
|
| 436 |
"dispatch": {
|
| 437 |
-
"
|
| 438 |
-
"
|
|
|
|
| 439 |
}
|
| 440 |
}
|
| 441 |
]
|
|
@@ -448,19 +310,18 @@
|
|
| 448 |
{
|
| 449 |
"id": "main",
|
| 450 |
"name": "Split3",
|
| 451 |
-
"
|
| 452 |
-
|
| 453 |
-
"
|
| 454 |
-
|
| 455 |
-
|
| 456 |
-
|
| 457 |
-
"axis": "axis"
|
| 458 |
-
}
|
| 459 |
},
|
| 460 |
-
"bindings": "
|
| 461 |
"dispatch": {
|
| 462 |
-
"
|
| 463 |
-
"
|
|
|
|
| 464 |
}
|
| 465 |
}
|
| 466 |
]
|
|
|
|
| 2 |
"domain": "ai.onnx",
|
| 3 |
"name": "Split",
|
| 4 |
"sinceVersion": 18,
|
| 5 |
+
"inputs": {
|
| 6 |
+
"input": { "dtype": "T" },
|
| 7 |
+
"split": { "dtype": "S", "rank": 1, "optional": true, "storage": "uint32", "narrowing": "checked" }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
},
|
| 9 |
+
"outputs": {
|
| 10 |
+
"y0": { "onnx": "Y0", "dtype": "T", "rank": "ranks.input" },
|
| 11 |
+
"y1": { "onnx": "Y1", "dtype": "T", "rank": "ranks.input", "optional": true },
|
| 12 |
+
"y2": { "onnx": "Y2", "dtype": "T", "rank": "ranks.input", "optional": true },
|
| 13 |
+
"y3": { "onnx": "Y3", "dtype": "T", "rank": "ranks.input", "optional": true },
|
| 14 |
+
"y4": { "onnx": "Y4", "dtype": "T", "rank": "ranks.input", "optional": true }
|
| 15 |
+
},
|
| 16 |
+
"attributes": { "axis": { "default": 0 }, "num_outputs": {} },
|
| 17 |
"typeConstraints": {
|
| 18 |
"T": ["float32", "float16", "uint32", "int32", "int16", "uint8", "int8", "bool"],
|
| 19 |
"S": ["int64"]
|
| 20 |
},
|
| 21 |
+
"tunables": { "WORKGROUP_SIZE": { "default": 256 } },
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
"derive": {
|
| 23 |
"deviceWorkgroupCap": "min(device.limits.maxComputeInvocationsPerWorkgroup, device.limits.maxComputeWorkgroupSizeX)",
|
| 24 |
"axis": "attrs.axis if attrs.axis >= 0 else attrs.axis + ranks.input",
|
|
|
|
| 26 |
"numOutputsContract": "not has(attrs, \"num_outputs\") or attrs.num_outputs == outputCount",
|
| 27 |
"workgroupSize": "min(tunables.WORKGROUP_SIZE, deviceWorkgroupCap)",
|
| 28 |
"baseContract": "ranks.input >= 1 and axis >= 0 and axis < ranks.input and numOutputsContract and f16Ok(dtypes.T)",
|
| 29 |
+
"oneOutputContract": "baseContract and not present.y1 and not present.y2 and not present.y3 and not present.y4 and sameShape(shapes.input, shapes.y0)",
|
| 30 |
+
"twoOutputContract": "baseContract and present.y1 and not present.y2 and ranks.input == ranks.y0 and ranks.input == ranks.y1 and dim(shapes.input, attrs.axis) == dim(shapes.y0, attrs.axis) + dim(shapes.y1, attrs.axis)",
|
| 31 |
+
"threeOutputContract": "baseContract and present.y1 and present.y2 and not present.y3 and ranks.input == ranks.y0 and ranks.input == ranks.y1 and ranks.input == ranks.y2 and dim(shapes.input, attrs.axis) == dim(shapes.y0, attrs.axis) + dim(shapes.y1, attrs.axis) + dim(shapes.y2, attrs.axis)",
|
| 32 |
+
"fourOutputContract": "baseContract and present.y1 and present.y2 and present.y3 and not present.y4 and ranks.input == ranks.y0 and ranks.input == ranks.y1 and ranks.input == ranks.y2 and ranks.input == ranks.y3 and dim(shapes.input, attrs.axis) == dim(shapes.y0, attrs.axis) + dim(shapes.y1, attrs.axis) + dim(shapes.y2, attrs.axis) + dim(shapes.y3, attrs.axis)",
|
| 33 |
+
"fiveOutputContract": "baseContract and present.y1 and present.y2 and present.y3 and present.y4 and ranks.input == ranks.y0 and ranks.input == ranks.y1 and ranks.input == ranks.y2 and ranks.input == ranks.y3 and ranks.input == ranks.y4 and dim(shapes.input, attrs.axis) == dim(shapes.y0, attrs.axis) + dim(shapes.y1, attrs.axis) + dim(shapes.y2, attrs.axis) + dim(shapes.y3, attrs.axis) + dim(shapes.y4, attrs.axis)",
|
| 34 |
+
"twoBlockContract": "twoOutputContract and outer(shapes.y0, attrs.axis) == outer(shapes.input, attrs.axis) and inner(shapes.y0, attrs.axis) == inner(shapes.input, attrs.axis) and outer(shapes.y1, attrs.axis) == outer(shapes.input, attrs.axis) and inner(shapes.y1, attrs.axis) == inner(shapes.input, attrs.axis)",
|
| 35 |
+
"threeBlockContract": "threeOutputContract and outer(shapes.y0, attrs.axis) == outer(shapes.input, attrs.axis) and inner(shapes.y0, attrs.axis) == inner(shapes.input, attrs.axis) and outer(shapes.y1, attrs.axis) == outer(shapes.input, attrs.axis) and inner(shapes.y1, attrs.axis) == inner(shapes.input, attrs.axis) and outer(shapes.y2, attrs.axis) == outer(shapes.input, attrs.axis) and inner(shapes.y2, attrs.axis) == inner(shapes.input, attrs.axis)",
|
| 36 |
+
"fourBlockContract": "fourOutputContract and outer(shapes.y0, attrs.axis) == outer(shapes.input, attrs.axis) and inner(shapes.y0, attrs.axis) == inner(shapes.input, attrs.axis) and outer(shapes.y1, attrs.axis) == outer(shapes.input, attrs.axis) and inner(shapes.y1, attrs.axis) == inner(shapes.input, attrs.axis) and outer(shapes.y2, attrs.axis) == outer(shapes.input, attrs.axis) and inner(shapes.y2, attrs.axis) == inner(shapes.input, attrs.axis) and outer(shapes.y3, attrs.axis) == outer(shapes.input, attrs.axis) and inner(shapes.y3, attrs.axis) == inner(shapes.input, attrs.axis)",
|
| 37 |
+
"scalar": "dtypes.T"
|
| 38 |
},
|
| 39 |
+
"bindings": {
|
| 40 |
+
"input": { "buffer": "read-only-storage", "elementType": "$vectorScalar" },
|
| 41 |
+
"y0": { "buffer": "storage", "elementType": "$vectorScalar" },
|
| 42 |
+
"y1": { "buffer": "storage", "elementType": "$vectorScalar" },
|
| 43 |
+
"input_2": { "name": "input", "buffer": "read-only-storage", "elementType": "$ioElement" },
|
| 44 |
+
"y0_2": { "name": "y0", "buffer": "storage", "elementType": "$ioElement" },
|
| 45 |
+
"y1_2": { "name": "y1", "buffer": "storage", "elementType": "$ioElement" },
|
| 46 |
+
"y2": { "buffer": "storage", "elementType": "$ioElement" },
|
| 47 |
+
"input_3": { "name": "input", "buffer": "read-only-storage", "elementType": "$scalar" },
|
| 48 |
+
"y0_3": { "name": "y0", "buffer": "storage", "elementType": "$scalar" },
|
| 49 |
+
"y1_3": { "name": "y1", "buffer": "storage", "elementType": "$scalar" },
|
| 50 |
+
"params": {
|
| 51 |
+
"buffer": "uniform",
|
| 52 |
+
"struct": [
|
| 53 |
+
{ "name": "y0Count", "type": "u32", "value": "numel(shapes.y0)" },
|
| 54 |
+
{ "name": "y1Count", "type": "u32", "value": "numel(shapes.y1)" }
|
| 55 |
+
]
|
| 56 |
+
},
|
| 57 |
+
"y2_3": { "name": "y2", "buffer": "storage", "elementType": "$scalar" },
|
| 58 |
+
"y3_2": { "name": "y3", "buffer": "storage", "elementType": "$scalar" },
|
| 59 |
+
"y4": { "buffer": "storage", "elementType": "$scalar" },
|
| 60 |
+
"params_2": {
|
| 61 |
+
"name": "params",
|
| 62 |
+
"buffer": "uniform",
|
| 63 |
+
"struct": [
|
| 64 |
+
{ "name": "y0Count", "type": "u32", "value": "numel(shapes.y0)" },
|
| 65 |
+
{ "name": "y1Count", "type": "u32", "value": "numel(shapes.y1)" },
|
| 66 |
+
{ "name": "y2Count", "type": "u32", "value": "numel(shapes.y2)" },
|
| 67 |
+
{ "name": "y3Count", "type": "u32", "value": "numel(shapes.y3)" },
|
| 68 |
+
{ "name": "y4Count", "type": "u32", "value": "numel(shapes.y4)" }
|
| 69 |
+
]
|
| 70 |
+
},
|
| 71 |
+
"params_3": {
|
| 72 |
+
"name": "params",
|
| 73 |
+
"buffer": "uniform",
|
| 74 |
+
"struct": [
|
| 75 |
+
{ "name": "y0Count", "type": "u32", "value": "numel(shapes.y0)" },
|
| 76 |
+
{ "name": "y1Count", "type": "u32", "value": "numel(shapes.y1)" },
|
| 77 |
+
{ "name": "y2Count", "type": "u32", "value": "numel(shapes.y2)" },
|
| 78 |
+
{ "name": "y3Count", "type": "u32", "value": "numel(shapes.y3)" }
|
| 79 |
+
]
|
| 80 |
+
},
|
| 81 |
+
"params_4": {
|
| 82 |
+
"name": "params",
|
| 83 |
+
"buffer": "uniform",
|
| 84 |
+
"struct": [
|
| 85 |
+
{ "name": "y0Count", "type": "u32", "value": "numel(shapes.y0)" },
|
| 86 |
+
{ "name": "y1Count", "type": "u32", "value": "numel(shapes.y1)" },
|
| 87 |
+
{ "name": "y2Count", "type": "u32", "value": "numel(shapes.y2)" }
|
| 88 |
+
]
|
| 89 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 90 |
},
|
| 91 |
"variants": [
|
| 92 |
{
|
|
|
|
| 97 |
{
|
| 98 |
"id": "main",
|
| 99 |
"name": "Split.copy",
|
| 100 |
+
"shader": "datamove-flat-copy.wgsl.jinja",
|
| 101 |
+
"derive": { "count": "numel(shapes.y0)" },
|
| 102 |
+
"bindings": [
|
| 103 |
+
{ "arg": "input", "name": "src", "elementType": "$scalar" },
|
| 104 |
+
{ "arg": "y0", "name": "dst", "elementType": "$scalar" }
|
| 105 |
+
],
|
| 106 |
+
"dispatch": {
|
| 107 |
+
"x": "min(ceilDiv((numel(shapes.y0)), (workgroupSize)), min(device.limits.maxComputeWorkgroupsPerDimension, 65535))",
|
| 108 |
+
"y": 1,
|
| 109 |
+
"z": 1
|
| 110 |
+
},
|
| 111 |
"viewAlias": [{ "input": "src", "output": "dst" }]
|
| 112 |
}
|
| 113 |
]
|
|
|
|
| 115 |
{
|
| 116 |
"id": "two_outputs_block_vec4",
|
| 117 |
"priority": 15,
|
| 118 |
+
"when": ["twoBlockContract", "(dim(shapes.y0, attrs.axis) * inner(shapes.y0, attrs.axis)) % 4 == 0", "(dim(shapes.y1, attrs.axis) * inner(shapes.y1, attrs.axis)) % 4 == 0"],
|
| 119 |
+
"derive": { "vectorScalar": "\"vec4<\" ~ dtypes.T ~ \">\"" },
|
| 120 |
"passes": [
|
| 121 |
{
|
| 122 |
"id": "main",
|
| 123 |
"name": "Split.blockVec4",
|
| 124 |
+
"shader": "datamove-split-block.wgsl.jinja",
|
| 125 |
+
"derive": {
|
| 126 |
+
"inputShape": "shapes.input",
|
| 127 |
+
"y0Shape": "shapes.y0",
|
| 128 |
+
"y1Shape": "shapes.y1",
|
| 129 |
+
"rank": "ranks.input",
|
| 130 |
+
"axisSpec": "axis",
|
| 131 |
+
"outputCountSpec": 2
|
|
|
|
|
|
|
| 132 |
},
|
| 133 |
+
"bindings": ["input", "y0", "y1"],
|
| 134 |
+
"dispatch": {
|
| 135 |
+
"x": "min(ceilDiv((max(numel(shapes.y0), numel(shapes.y1)) / 4), (workgroupSize)), min(device.limits.maxComputeWorkgroupsPerDimension, 65535))",
|
| 136 |
+
"y": 1,
|
| 137 |
+
"z": 1
|
| 138 |
+
}
|
| 139 |
}
|
| 140 |
]
|
| 141 |
},
|
| 142 |
{
|
| 143 |
"id": "three_outputs_block_scalar_x4",
|
| 144 |
"priority": 14,
|
| 145 |
+
"when": ["threeBlockContract", "dim(shapes.y0, attrs.axis) > 0", "dim(shapes.y1, attrs.axis) > 0", "dim(shapes.y2, attrs.axis) > 0", "max(numel(shapes.y0), numel(shapes.y1), numel(shapes.y2)) >= 16"],
|
| 146 |
+
"derive": { "ioElement": "dtypes.T" },
|
| 147 |
"passes": [
|
| 148 |
{
|
| 149 |
"id": "main",
|
| 150 |
"name": "Split3.blockScalarX4",
|
| 151 |
+
"shader": "datamove-split-block.wgsl.jinja",
|
| 152 |
+
"derive": {
|
| 153 |
+
"inputShape": "shapes.input",
|
| 154 |
+
"y0Shape": "shapes.y0",
|
| 155 |
+
"y1Shape": "shapes.y1",
|
| 156 |
+
"y2Shape": "shapes.y2",
|
| 157 |
+
"rank": "ranks.input",
|
| 158 |
+
"axisSpec": "axis",
|
| 159 |
+
"outputCountSpec": 3,
|
| 160 |
+
"scalarBoundX4": true
|
|
|
|
|
|
|
| 161 |
},
|
| 162 |
+
"bindings": ["input_2", "y0_2", "y1_2", "y2"],
|
| 163 |
"dispatch": {
|
| 164 |
+
"x": "min(ceilDiv((max(outer(shapes.y0, attrs.axis) * ceil(dim(shapes.y0, attrs.axis) * inner(shapes.y0, attrs.axis) / 4), outer(shapes.y1, attrs.axis) * ceil(dim(shapes.y1, attrs.axis) * inner(shapes.y1, attrs.axis) / 4), outer(shapes.y2, attrs.axis) * ceil(dim(shapes.y2, attrs.axis) * inner(shapes.y2, attrs.axis) / 4))), (workgroupSize)), min(device.limits.maxComputeWorkgroupsPerDimension, 65535))",
|
| 165 |
+
"y": 1,
|
| 166 |
+
"z": 1
|
| 167 |
}
|
| 168 |
}
|
| 169 |
]
|
|
|
|
| 171 |
{
|
| 172 |
"id": "three_outputs_block_vec4",
|
| 173 |
"priority": 15,
|
| 174 |
+
"when": ["threeBlockContract", "(dim(shapes.y0, attrs.axis) * inner(shapes.y0, attrs.axis)) % 4 == 0", "(dim(shapes.y1, attrs.axis) * inner(shapes.y1, attrs.axis)) % 4 == 0", "(dim(shapes.y2, attrs.axis) * inner(shapes.y2, attrs.axis)) % 4 == 0"],
|
| 175 |
+
"derive": { "ioElement": "\"vec4<\" ~ dtypes.T ~ \">\"", "vectorScalar": "\"vec4<\" ~ dtypes.T ~ \">\"" },
|
| 176 |
"passes": [
|
| 177 |
{
|
| 178 |
"id": "main",
|
| 179 |
"name": "Split3.blockVec4",
|
| 180 |
+
"shader": "datamove-split-block.wgsl.jinja",
|
| 181 |
+
"derive": {
|
| 182 |
+
"inputShape": "shapes.input",
|
| 183 |
+
"y0Shape": "shapes.y0",
|
| 184 |
+
"y1Shape": "shapes.y1",
|
| 185 |
+
"y2Shape": "shapes.y2",
|
| 186 |
+
"rank": "ranks.input",
|
| 187 |
+
"axisSpec": "axis",
|
| 188 |
+
"outputCountSpec": 3
|
|
|
|
|
|
|
| 189 |
},
|
| 190 |
+
"bindings": ["input_2", "y0_2", "y1_2", "y2"],
|
| 191 |
"dispatch": {
|
| 192 |
+
"x": "min(ceilDiv((max(numel(shapes.y0), numel(shapes.y1), numel(shapes.y2)) / 4), (workgroupSize)), min(device.limits.maxComputeWorkgroupsPerDimension, 65535))",
|
| 193 |
+
"y": 1,
|
| 194 |
+
"z": 1
|
| 195 |
}
|
| 196 |
}
|
| 197 |
]
|
|
|
|
| 199 |
{
|
| 200 |
"id": "four_outputs_block_vec4",
|
| 201 |
"priority": 25,
|
| 202 |
+
"when": ["fourBlockContract", "(dim(shapes.y0, attrs.axis) * inner(shapes.y0, attrs.axis)) % 4 == 0", "(dim(shapes.y1, attrs.axis) * inner(shapes.y1, attrs.axis)) % 4 == 0", "(dim(shapes.y2, attrs.axis) * inner(shapes.y2, attrs.axis)) % 4 == 0", "(dim(shapes.y3, attrs.axis) * inner(shapes.y3, attrs.axis)) % 4 == 0"],
|
| 203 |
+
"derive": { "vectorScalar": "\"vec4<\" ~ dtypes.T ~ \">\"" },
|
| 204 |
"passes": [
|
| 205 |
{
|
| 206 |
"id": "main",
|
| 207 |
"name": "Split4.blockVec4",
|
| 208 |
+
"shader": "datamove-split-block.wgsl.jinja",
|
| 209 |
+
"derive": {
|
| 210 |
+
"inputShape": "shapes.input",
|
| 211 |
+
"y0Shape": "shapes.y0",
|
| 212 |
+
"y1Shape": "shapes.y1",
|
| 213 |
+
"y2Shape": "shapes.y2",
|
| 214 |
+
"y3Shape": "shapes.y3",
|
| 215 |
+
"rank": "ranks.input",
|
| 216 |
+
"axisSpec": "axis",
|
| 217 |
+
"outputCountSpec": 4
|
|
|
|
|
|
|
| 218 |
},
|
| 219 |
+
"bindings": [
|
| 220 |
+
"input",
|
| 221 |
+
"y0",
|
| 222 |
+
"y1",
|
| 223 |
+
{ "arg": "y2", "elementType": "$vectorScalar" },
|
| 224 |
+
{ "arg": "y3", "elementType": "$vectorScalar" }
|
| 225 |
+
],
|
| 226 |
"dispatch": {
|
| 227 |
+
"x": "min(ceilDiv((max(numel(shapes.y0), numel(shapes.y1), numel(shapes.y2), numel(shapes.y3)) / 4), (workgroupSize)), min(device.limits.maxComputeWorkgroupsPerDimension, 65535))",
|
| 228 |
+
"y": 1,
|
| 229 |
+
"z": 1
|
| 230 |
}
|
| 231 |
}
|
| 232 |
]
|
|
|
|
| 238 |
{
|
| 239 |
"id": "main",
|
| 240 |
"name": "Split",
|
| 241 |
+
"shader": "split-n.wgsl.jinja",
|
| 242 |
+
"derive": {
|
| 243 |
+
"inputShape": "shapes.input",
|
| 244 |
+
"outputs": "[ {\"name\": \"y0\", \"shape\": shapes.y0}, {\"name\": \"y1\", \"shape\": shapes.y1} ]",
|
| 245 |
+
"rank": "ranks.input",
|
| 246 |
+
"axisSpec": "axis"
|
|
|
|
|
|
|
| 247 |
},
|
| 248 |
+
"bindings": ["input_3", "y0_3", "y1_3", "params"],
|
| 249 |
+
"dispatch": {
|
| 250 |
+
"x": "min(ceilDiv((max(numel(shapes.y0), numel(shapes.y1))), (workgroupSize)), 65535)",
|
| 251 |
+
"y": "ceilDiv(ceilDiv((max(numel(shapes.y0), numel(shapes.y1))), (workgroupSize)), 65535)",
|
| 252 |
+
"z": 1
|
| 253 |
+
}
|
| 254 |
}
|
| 255 |
]
|
| 256 |
},
|
|
|
|
| 262 |
{
|
| 263 |
"id": "main",
|
| 264 |
"name": "SplitN",
|
| 265 |
+
"shader": "split-n.wgsl.jinja",
|
| 266 |
+
"derive": {
|
| 267 |
+
"inputShape": "shapes.input",
|
| 268 |
+
"outputs": "[ {\"name\": \"y0\", \"shape\": shapes.y0}, {\"name\": \"y1\", \"shape\": shapes.y1}, {\"name\": \"y2\", \"shape\": shapes.y2}, {\"name\": \"y3\", \"shape\": shapes.y3}, {\"name\": \"y4\", \"shape\": shapes.y4} ]",
|
| 269 |
+
"rank": "ranks.input",
|
| 270 |
+
"axisSpec": "axis"
|
|
|
|
|
|
|
| 271 |
},
|
| 272 |
+
"bindings": ["input_3", "y0_3", "y1_3", "y2_3", "y3_2", "y4", "params_2"],
|
| 273 |
"dispatch": {
|
| 274 |
+
"x": "min(ceilDiv((max(numel(shapes.y0), numel(shapes.y1), numel(shapes.y2), numel(shapes.y3), numel(shapes.y4))), (workgroupSize)), 65535)",
|
| 275 |
+
"y": "ceilDiv(ceilDiv((max(numel(shapes.y0), numel(shapes.y1), numel(shapes.y2), numel(shapes.y3), numel(shapes.y4))), (workgroupSize)), 65535)",
|
| 276 |
+
"z": 1
|
| 277 |
}
|
| 278 |
}
|
| 279 |
]
|
|
|
|
| 286 |
{
|
| 287 |
"id": "main",
|
| 288 |
"name": "Split4",
|
| 289 |
+
"shader": "split-n.wgsl.jinja",
|
| 290 |
+
"derive": {
|
| 291 |
+
"inputShape": "shapes.input",
|
| 292 |
+
"outputs": "[ {\"name\": \"y0\", \"shape\": shapes.y0}, {\"name\": \"y1\", \"shape\": shapes.y1}, {\"name\": \"y2\", \"shape\": shapes.y2}, {\"name\": \"y3\", \"shape\": shapes.y3} ]",
|
| 293 |
+
"rank": "ranks.input",
|
| 294 |
+
"axisSpec": "axis"
|
|
|
|
|
|
|
| 295 |
},
|
| 296 |
+
"bindings": ["input_3", "y0_3", "y1_3", "y2_3", "y3_2", "params_3"],
|
| 297 |
"dispatch": {
|
| 298 |
+
"x": "min(ceilDiv((max(numel(shapes.y0), numel(shapes.y1), numel(shapes.y2), numel(shapes.y3))), (workgroupSize)), 65535)",
|
| 299 |
+
"y": "ceilDiv(ceilDiv((max(numel(shapes.y0), numel(shapes.y1), numel(shapes.y2), numel(shapes.y3))), (workgroupSize)), 65535)",
|
| 300 |
+
"z": 1
|
| 301 |
}
|
| 302 |
}
|
| 303 |
]
|
|
|
|
| 310 |
{
|
| 311 |
"id": "main",
|
| 312 |
"name": "Split3",
|
| 313 |
+
"shader": "split-n.wgsl.jinja",
|
| 314 |
+
"derive": {
|
| 315 |
+
"inputShape": "shapes.input",
|
| 316 |
+
"outputs": "[ {\"name\": \"y0\", \"shape\": shapes.y0}, {\"name\": \"y1\", \"shape\": shapes.y1}, {\"name\": \"y2\", \"shape\": shapes.y2} ]",
|
| 317 |
+
"rank": "ranks.input",
|
| 318 |
+
"axisSpec": "axis"
|
|
|
|
|
|
|
| 319 |
},
|
| 320 |
+
"bindings": ["input_3", "y0_3", "y1_3", "y2_3", "params_4"],
|
| 321 |
"dispatch": {
|
| 322 |
+
"x": "min(ceilDiv((max(numel(shapes.y0), numel(shapes.y1), numel(shapes.y2))), (workgroupSize)), 65535)",
|
| 323 |
+
"y": "ceilDiv(ceilDiv((max(numel(shapes.y0), numel(shapes.y1), numel(shapes.y2))), (workgroupSize)), 65535)",
|
| 324 |
+
"z": 1
|
| 325 |
}
|
| 326 |
}
|
| 327 |
]
|
build/webgpu/metadata.json
CHANGED
|
@@ -1,20 +1,33 @@
|
|
| 1 |
{
|
| 2 |
"name": "ai.onnx.Split",
|
| 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 |
-
"datamove-flat-copy.wgsl.jinja": "
|
| 12 |
-
"datamove-split-block.wgsl.jinja": "
|
| 13 |
-
"manifest.json": "
|
| 14 |
-
"split-n.wgsl.jinja": "
|
| 15 |
-
"test.json": "
|
| 16 |
}
|
| 17 |
},
|
| 18 |
-
"provenance": { "kernel": { "sha": "
|
| 19 |
-
"webgpu": {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
}
|
|
|
|
| 1 |
{
|
| 2 |
"name": "ai.onnx.Split",
|
| 3 |
+
"id": "_ai_onnx_split_webgpu_905cd69",
|
| 4 |
"version": 1,
|
| 5 |
"license": "Apache-2.0",
|
| 6 |
"backend": { "type": "webgpu" },
|
| 7 |
"digest": {
|
| 8 |
"algorithm": "sha256",
|
| 9 |
"files": {
|
| 10 |
+
"bench.json": "k7jAXfnplRAPstbkQGbKdFPxoWX7R9DW+MK+4NiYTLU=",
|
| 11 |
+
"datamove-flat-copy.wgsl.jinja": "g9d62mer2bmHfbScqX5CIT5Zq/Pdinac0W2dH0CD+5s=",
|
| 12 |
+
"datamove-split-block.wgsl.jinja": "shWWQMUtwoSmMEgOn2yy1spChp86zzPkm/Cb7QiAnWs=",
|
| 13 |
+
"manifest.json": "qnPxFTTkmu2fktjom8/oaTjlNXRcGD2kg+oeCsJ6RQc=",
|
| 14 |
+
"split-n.wgsl.jinja": "z574+TJ8XGpxhV0wwxRfsHXSsSu7Ry4dvhXBxHcB6Cw=",
|
| 15 |
+
"test.json": "71+a2DHyXRRHacOOABnDWrpe60/NRk7A/jP9UqPwpFE="
|
| 16 |
}
|
| 17 |
},
|
| 18 |
+
"provenance": { "kernel": { "sha": "91d990483a174128daf7673f3f37a7c890493ae1", "dirty": false } },
|
| 19 |
+
"webgpu": {
|
| 20 |
+
"manifestSpec": "2.0",
|
| 21 |
+
"variants": {
|
| 22 |
+
"one_output_copy": ["datamove-flat-copy.wgsl.jinja"],
|
| 23 |
+
"two_outputs_block_vec4": ["datamove-split-block.wgsl.jinja"],
|
| 24 |
+
"three_outputs_block_scalar_x4": ["datamove-split-block.wgsl.jinja"],
|
| 25 |
+
"three_outputs_block_vec4": ["datamove-split-block.wgsl.jinja"],
|
| 26 |
+
"four_outputs_block_vec4": ["datamove-split-block.wgsl.jinja"],
|
| 27 |
+
"two_outputs": ["split-n.wgsl.jinja"],
|
| 28 |
+
"five_outputs": ["split-n.wgsl.jinja"],
|
| 29 |
+
"four_outputs": ["split-n.wgsl.jinja"],
|
| 30 |
+
"three_outputs": ["split-n.wgsl.jinja"]
|
| 31 |
+
}
|
| 32 |
+
}
|
| 33 |
}
|
build/webgpu/split-n.wgsl.jinja
CHANGED
|
@@ -2,19 +2,16 @@
|
|
| 2 |
// adding all preceding outputs' cumulative split-axis extent. One invocation
|
| 3 |
// handles the same flat position across outputs, and each output writes only
|
| 4 |
// when that position is within its own element count.
|
| 5 |
-
{% if usesF16 %}
|
| 6 |
-
enable f16;
|
| 7 |
-
{% endif %}
|
| 8 |
{{ env.wgsl.resourceDeclarations }}
|
| 9 |
|
| 10 |
-
{% for output in
|
| 11 |
{% set out_count = namespace(value=1) %}
|
| 12 |
{% for d in output.shape %}
|
| 13 |
{% set out_count.value = out_count.value * d %}
|
| 14 |
{% endfor %}
|
| 15 |
{% set prefix = namespace(value=0) %}
|
| 16 |
-
{% for prev in
|
| 17 |
-
{% set prefix.value = prefix.value + prev.shape[
|
| 18 |
{% endfor %}
|
| 19 |
fn input_offset_{{ output.name }}({% if out_count.value > 0 %}out_index: u32{% endif %}) -> u32 {
|
| 20 |
{% if out_count.value == 0 %}
|
|
@@ -22,18 +19,18 @@ fn input_offset_{{ output.name }}({% if out_count.value > 0 %}out_index: u32{% e
|
|
| 22 |
{% else %}
|
| 23 |
var rem = out_index;
|
| 24 |
var offset = 0u;
|
| 25 |
-
{% for axis in range(
|
| 26 |
{% set out_stride = namespace(value=1) %}
|
| 27 |
-
{% for j in range(axis + 1,
|
| 28 |
{% set out_stride.value = out_stride.value * output.shape[j] %}
|
| 29 |
{% endfor %}
|
| 30 |
{% set input_stride = namespace(value=1) %}
|
| 31 |
-
{% for j in range(axis + 1,
|
| 32 |
-
{% set input_stride.value = input_stride.value *
|
| 33 |
{% endfor %}
|
| 34 |
var coord{{ axis }} = rem / {{ out_stride.value }}u;
|
| 35 |
rem = rem % {{ out_stride.value }}u;
|
| 36 |
-
{% if axis ==
|
| 37 |
coord{{ axis }} = coord{{ axis }} + {{ prefix.value }}u;
|
| 38 |
{% endif %}
|
| 39 |
offset = offset + coord{{ axis }} * {{ input_stride.value }}u;
|
|
@@ -44,11 +41,11 @@ fn input_offset_{{ output.name }}({% if out_count.value > 0 %}out_index: u32{% e
|
|
| 44 |
|
| 45 |
{% endfor %}
|
| 46 |
@compute @workgroup_size({{ workgroupSize }})
|
| 47 |
-
fn main(@builtin(global_invocation_id) gid: vec3<u32>
|
| 48 |
// 2D-folded flat index: gid.y carries the high bits past the
|
| 49 |
-
//
|
| 50 |
-
let i = gid.x + gid.y *
|
| 51 |
-
{% for output in
|
| 52 |
{% set out_count = namespace(value=1) %}
|
| 53 |
{% for d in output.shape %}
|
| 54 |
{% set out_count.value = out_count.value * d %}
|
|
|
|
| 2 |
// adding all preceding outputs' cumulative split-axis extent. One invocation
|
| 3 |
// handles the same flat position across outputs, and each output writes only
|
| 4 |
// when that position is within its own element count.
|
|
|
|
|
|
|
|
|
|
| 5 |
{{ env.wgsl.resourceDeclarations }}
|
| 6 |
|
| 7 |
+
{% for output in outputs %}
|
| 8 |
{% set out_count = namespace(value=1) %}
|
| 9 |
{% for d in output.shape %}
|
| 10 |
{% set out_count.value = out_count.value * d %}
|
| 11 |
{% endfor %}
|
| 12 |
{% set prefix = namespace(value=0) %}
|
| 13 |
+
{% for prev in outputs[:loop.index0] %}
|
| 14 |
+
{% set prefix.value = prefix.value + prev.shape[axisSpec] %}
|
| 15 |
{% endfor %}
|
| 16 |
fn input_offset_{{ output.name }}({% if out_count.value > 0 %}out_index: u32{% endif %}) -> u32 {
|
| 17 |
{% if out_count.value == 0 %}
|
|
|
|
| 19 |
{% else %}
|
| 20 |
var rem = out_index;
|
| 21 |
var offset = 0u;
|
| 22 |
+
{% for axis in range(rank) %}
|
| 23 |
{% set out_stride = namespace(value=1) %}
|
| 24 |
+
{% for j in range(axis + 1, rank) %}
|
| 25 |
{% set out_stride.value = out_stride.value * output.shape[j] %}
|
| 26 |
{% endfor %}
|
| 27 |
{% set input_stride = namespace(value=1) %}
|
| 28 |
+
{% for j in range(axis + 1, rank) %}
|
| 29 |
+
{% set input_stride.value = input_stride.value * inputShape[j] %}
|
| 30 |
{% endfor %}
|
| 31 |
var coord{{ axis }} = rem / {{ out_stride.value }}u;
|
| 32 |
rem = rem % {{ out_stride.value }}u;
|
| 33 |
+
{% if axis == axisSpec and prefix.value > 0 %}
|
| 34 |
coord{{ axis }} = coord{{ axis }} + {{ prefix.value }}u;
|
| 35 |
{% endif %}
|
| 36 |
offset = offset + coord{{ axis }} * {{ input_stride.value }}u;
|
|
|
|
| 41 |
|
| 42 |
{% endfor %}
|
| 43 |
@compute @workgroup_size({{ workgroupSize }})
|
| 44 |
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
| 45 |
// 2D-folded flat index: gid.y carries the high bits past the
|
| 46 |
+
// per-axis dispatch fold width.
|
| 47 |
+
let i = gid.x + gid.y * {{ DISPATCH_FOLD_WIDTH }}u * {{ workgroupSize }}u;
|
| 48 |
+
{% for output in outputs %}
|
| 49 |
{% set out_count = namespace(value=1) %}
|
| 50 |
{% for d in output.shape %}
|
| 51 |
{% set out_count.value = out_count.value * d %}
|
build/webgpu/test.json
CHANGED
|
@@ -1,5 +1,4 @@
|
|
| 1 |
{
|
| 2 |
-
"op": "ai.onnx.Split",
|
| 3 |
"fixtureArrays": {
|
| 4 |
"ort_axis2_equal_three_outputs_input_input": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24],
|
| 5 |
"ort_axis1_middle_dimension_unequal_input_input": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]
|
|
@@ -655,7 +654,7 @@
|
|
| 655 |
"provenance": {
|
| 656 |
"source": "onnxruntime/test/providers/cpu/tensor/split_op_test.cc",
|
| 657 |
"test": "SplitOperatorTest.Uint8NegativeAxis",
|
| 658 |
-
"notes": "Logical uint8 payload values are stored one per uint32 slot
|
| 659 |
},
|
| 660 |
"attrs": { "axis": -1 },
|
| 661 |
"inputs": {
|
|
@@ -675,7 +674,7 @@
|
|
| 675 |
"provenance": {
|
| 676 |
"source": "onnxruntime/test/providers/cpu/tensor/split_op_test.cc",
|
| 677 |
"test": "SplitOperatorTest.Uint8Axis1SplitMiddleDimensionUnequally",
|
| 678 |
-
"notes": "Logical uint8 payload values are stored one per uint32 slot
|
| 679 |
},
|
| 680 |
"attrs": { "axis": 1 },
|
| 681 |
"inputs": {
|
|
@@ -848,7 +847,7 @@
|
|
| 848 |
"outputs": { "y0": { "dtype": "float32", "shape": [2] }, "y1": { "dtype": "float32", "shape": [4] } },
|
| 849 |
"provenance": {
|
| 850 |
"source": "cmake/external/onnx/onnx/backend/test/data/node/test_split_variable_parts_1d_opset18",
|
| 851 |
-
"notes": "
|
| 852 |
}
|
| 853 |
},
|
| 854 |
{
|
|
@@ -865,7 +864,7 @@
|
|
| 865 |
"outputs": { "y0": { "dtype": "float32", "shape": [2, 2] }, "y1": { "dtype": "float32", "shape": [2, 4] } },
|
| 866 |
"provenance": {
|
| 867 |
"source": "cmake/external/onnx/onnx/backend/test/data/node/test_split_variable_parts_2d_opset18",
|
| 868 |
-
"notes": "
|
| 869 |
}
|
| 870 |
},
|
| 871 |
{
|
|
@@ -881,7 +880,7 @@
|
|
| 881 |
"outputs": { "y0": { "dtype": "float32", "shape": [2] }, "y1": { "dtype": "float32", "shape": [4] } },
|
| 882 |
"provenance": {
|
| 883 |
"source": "cmake/external/onnx/onnx/backend/test/data/node/test_split_variable_parts_default_axis_opset18",
|
| 884 |
-
"notes": "
|
| 885 |
}
|
| 886 |
},
|
| 887 |
{
|
|
@@ -897,7 +896,7 @@
|
|
| 897 |
},
|
| 898 |
"provenance": {
|
| 899 |
"source": "cmake/external/onnx/onnx/backend/test/data/node/test_split_zero_size_splits_opset18",
|
| 900 |
-
"notes": "
|
| 901 |
}
|
| 902 |
},
|
| 903 |
{
|
|
@@ -944,7 +943,7 @@
|
|
| 944 |
{
|
| 945 |
"name": "rank7_middle_axis_two_outputs",
|
| 946 |
"provenance": {
|
| 947 |
-
"notes": "
|
| 948 |
},
|
| 949 |
"attrs": { "axis": 2 },
|
| 950 |
"inputs": {
|
|
@@ -1266,7 +1265,7 @@
|
|
| 1266 |
{
|
| 1267 |
"name": "block_scalar_x4_three_outputs_y2_dominant_groups",
|
| 1268 |
"provenance": {
|
| 1269 |
-
"notes": "
|
| 1270 |
},
|
| 1271 |
"attrs": { "axis": 1 },
|
| 1272 |
"inputs": {
|
|
@@ -1296,7 +1295,7 @@
|
|
| 1296 |
{
|
| 1297 |
"name": "block_vec4_four_outputs_axis1_y3_dominant_count",
|
| 1298 |
"provenance": {
|
| 1299 |
-
"notes": "
|
| 1300 |
},
|
| 1301 |
"attrs": { "axis": 1 },
|
| 1302 |
"inputs": {
|
|
@@ -1316,7 +1315,7 @@
|
|
| 1316 |
{
|
| 1317 |
"name": "block_vec4_four_outputs_empty_y3",
|
| 1318 |
"provenance": {
|
| 1319 |
-
"notes": "
|
| 1320 |
},
|
| 1321 |
"attrs": { "axis": 1 },
|
| 1322 |
"inputs": {
|
|
|
|
| 1 |
{
|
|
|
|
| 2 |
"fixtureArrays": {
|
| 3 |
"ort_axis2_equal_three_outputs_input_input": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24],
|
| 4 |
"ort_axis1_middle_dimension_unequal_input_input": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]
|
|
|
|
| 654 |
"provenance": {
|
| 655 |
"source": "onnxruntime/test/providers/cpu/tensor/split_op_test.cc",
|
| 656 |
"test": "SplitOperatorTest.Uint8NegativeAxis",
|
| 657 |
+
"notes": "Logical uint8 payload values are stored one per uint32 slot."
|
| 658 |
},
|
| 659 |
"attrs": { "axis": -1 },
|
| 660 |
"inputs": {
|
|
|
|
| 674 |
"provenance": {
|
| 675 |
"source": "onnxruntime/test/providers/cpu/tensor/split_op_test.cc",
|
| 676 |
"test": "SplitOperatorTest.Uint8Axis1SplitMiddleDimensionUnequally",
|
| 677 |
+
"notes": "Logical uint8 payload values are stored one per uint32 slot."
|
| 678 |
},
|
| 679 |
"attrs": { "axis": 1 },
|
| 680 |
"inputs": {
|
|
|
|
| 847 |
"outputs": { "y0": { "dtype": "float32", "shape": [2] }, "y1": { "dtype": "float32", "shape": [4] } },
|
| 848 |
"provenance": {
|
| 849 |
"source": "cmake/external/onnx/onnx/backend/test/data/node/test_split_variable_parts_1d_opset18",
|
| 850 |
+
"notes": "This WebGPU package stores representable ONNX int64 tensor values in int32 slots."
|
| 851 |
}
|
| 852 |
},
|
| 853 |
{
|
|
|
|
| 864 |
"outputs": { "y0": { "dtype": "float32", "shape": [2, 2] }, "y1": { "dtype": "float32", "shape": [2, 4] } },
|
| 865 |
"provenance": {
|
| 866 |
"source": "cmake/external/onnx/onnx/backend/test/data/node/test_split_variable_parts_2d_opset18",
|
| 867 |
+
"notes": "This WebGPU package stores representable ONNX int64 tensor values in int32 slots."
|
| 868 |
}
|
| 869 |
},
|
| 870 |
{
|
|
|
|
| 880 |
"outputs": { "y0": { "dtype": "float32", "shape": [2] }, "y1": { "dtype": "float32", "shape": [4] } },
|
| 881 |
"provenance": {
|
| 882 |
"source": "cmake/external/onnx/onnx/backend/test/data/node/test_split_variable_parts_default_axis_opset18",
|
| 883 |
+
"notes": "This WebGPU package stores representable ONNX int64 tensor values in int32 slots."
|
| 884 |
}
|
| 885 |
},
|
| 886 |
{
|
|
|
|
| 896 |
},
|
| 897 |
"provenance": {
|
| 898 |
"source": "cmake/external/onnx/onnx/backend/test/data/node/test_split_zero_size_splits_opset18",
|
| 899 |
+
"notes": "This WebGPU package stores representable ONNX int64 tensor values in int32 slots."
|
| 900 |
}
|
| 901 |
},
|
| 902 |
{
|
|
|
|
| 943 |
{
|
| 944 |
"name": "rank7_middle_axis_two_outputs",
|
| 945 |
"provenance": {
|
| 946 |
+
"notes": "A rank-7 tensor split equally along middle axis 2 exercises high-rank address arithmetic."
|
| 947 |
},
|
| 948 |
"attrs": { "axis": 2 },
|
| 949 |
"inputs": {
|
|
|
|
| 1265 |
{
|
| 1266 |
"name": "block_scalar_x4_three_outputs_y2_dominant_groups",
|
| 1267 |
"provenance": {
|
| 1268 |
+
"notes": "Splitting axis 1 into runs of 2, 3, and 6 scalars selects grouped scalar copying because no run is four-aligned. The third output needs two four-scalar groups per row and therefore determines the loop bound."
|
| 1269 |
},
|
| 1270 |
"attrs": { "axis": 1 },
|
| 1271 |
"inputs": {
|
|
|
|
| 1295 |
{
|
| 1296 |
"name": "block_vec4_four_outputs_axis1_y3_dominant_count",
|
| 1297 |
"provenance": {
|
| 1298 |
+
"notes": "A four-output vec4 block split on axis 1 uses chunks 2/2/4/6 with inner=2, giving 4/4/8/12 aligned scalars per outer slice. Multiple outer slices exercise each output row stride, and the final output has the largest element count."
|
| 1299 |
},
|
| 1300 |
"attrs": { "axis": 1 },
|
| 1301 |
"inputs": {
|
|
|
|
| 1315 |
{
|
| 1316 |
"name": "block_vec4_four_outputs_empty_y3",
|
| 1317 |
"provenance": {
|
| 1318 |
+
"notes": "A four-output vectorized block split uses lengths [4,4,4,0]. ONNX permits the zero-length final chunk, which must be emitted without a copy or out-of-bounds input read. A 13-value cycle over 12-wide rows avoids alignment between values, rows, and chunk boundaries."
|
| 1319 |
},
|
| 1320 |
"attrs": { "axis": 1 },
|
| 1321 |
"inputs": {
|