sync 2e7068faf55e
Browse files- README.md +74 -0
- build/webgpu/bench.json +25 -0
- build/webgpu/manifest.json +74 -0
- build/webgpu/metadata.json +18 -0
- build/webgpu/test.json +217 -0
- build/webgpu/window-cosine-sum.wgsl.jinja +129 -0
README.md
CHANGED
|
@@ -1,3 +1,77 @@
|
|
| 1 |
---
|
|
|
|
| 2 |
license: apache-2.0
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
---
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
+
library_name: kernels
|
| 3 |
license: apache-2.0
|
| 4 |
+
tags:
|
| 5 |
+
- kernel
|
| 6 |
+
- webgpu
|
| 7 |
+
- wgsl
|
| 8 |
---
|
| 9 |
+
# ai.onnx.HannWindow
|
| 10 |
+
|
| 11 |
+
`ai.onnx` · standard ONNX operator · ONNX opset ≥ 17
|
| 12 |
+
|
| 13 |
+
## Description
|
| 14 |
+
|
| 15 |
+
Generates a Hann window of a given length using the formula `0.5 - 0.5 * cos(2π * n / N)`, where `N` is `size` for periodic mode or `size - 1` for symmetric mode. The output is a 1-D tensor of length `size`.
|
| 16 |
+
|
| 17 |
+
See the [ONNX `HannWindow` spec](https://onnx.ai/onnx/operators/onnx__HannWindow.html) for the reference semantics.
|
| 18 |
+
|
| 19 |
+
## Inputs
|
| 20 |
+
|
| 21 |
+
| Name | Bind key | Logical dtype | Rank | Shape | Description | Presence |
|
| 22 |
+
| --- | --- | --- | --- | --- | --- | --- |
|
| 23 |
+
| `size` | `size` | `T1` | `0` | — | Scalar indicating the number of elements in the output window. | required |
|
| 24 |
+
|
| 25 |
+
## Outputs
|
| 26 |
+
|
| 27 |
+
| Name | Bind key | Logical dtype | Rank | Shape | Description | Presence |
|
| 28 |
+
| --- | --- | --- | --- | --- | --- | --- |
|
| 29 |
+
| `output` | `y` | `T2` | `1` | — | 1-D Hann window tensor of shape `[size]`. | required |
|
| 30 |
+
|
| 31 |
+
## Attributes
|
| 32 |
+
|
| 33 |
+
Default values (overridable per request):
|
| 34 |
+
|
| 35 |
+
| Attribute | Default | Description |
|
| 36 |
+
| --- | --- | --- |
|
| 37 |
+
| `output_datatype` | `1` | Data type of the output tensor, encoded as a DataType enum value from TensorProto (default `1` = FLOAT). |
|
| 38 |
+
| `periodic` | `1` | If `1` (default), returns a periodic window of length `size`; if `0`, returns a symmetric window of length `size`. |
|
| 39 |
+
|
| 40 |
+
## Type constraints
|
| 41 |
+
|
| 42 |
+
| Variable | Allowed dtypes |
|
| 43 |
+
| --- | --- |
|
| 44 |
+
| `T1` | `int32` |
|
| 45 |
+
| `T2` | `float32`, `float16`, `uint32`, `int32`, `uint8`, `int8`, `int16` |
|
| 46 |
+
|
| 47 |
+
## Files
|
| 48 |
+
|
| 49 |
+
- [`metadata.json`](build/webgpu/metadata.json) — kernel metadata (id, digests, provenance)
|
| 50 |
+
- [`manifest.json`](build/webgpu/manifest.json) — the op contract (source of truth)
|
| 51 |
+
- [`test.json`](build/webgpu/test.json) — correctness cases
|
| 52 |
+
- [`bench.json`](build/webgpu/bench.json) — benchmark + tuning cases
|
| 53 |
+
- [`window-cosine-sum.wgsl.jinja`](build/webgpu/window-cosine-sum.wgsl.jinja)
|
| 54 |
+
|
| 55 |
+
## Use with `@huggingface/kernels`
|
| 56 |
+
|
| 57 |
+
The loader automatically allocates outputs whose metadata it can derive from the manifest contract and this call.
|
| 58 |
+
|
| 59 |
+
The explicit `outputs` entries provide shape and logical dtype metadata for the results listed below:
|
| 60 |
+
|
| 61 |
+
- `y`
|
| 62 |
+
|
| 63 |
+
Each entry either requests an optional result or supplies metadata that cannot be inferred from the inputs.
|
| 64 |
+
|
| 65 |
+
The `version: 1` option selects the published kernel contract; it is independent of any operator opset, contrib `since_version`, or model version.
|
| 66 |
+
|
| 67 |
+
Replace each `*Data` placeholder with a typed array containing the corresponding input data.
|
| 68 |
+
|
| 69 |
+
```js
|
| 70 |
+
import { getKernel } from "@huggingface/kernels";
|
| 71 |
+
|
| 72 |
+
const kernel = await getKernel("webgpu-kernels/ai.onnx.HannWindow", { version: 1 });
|
| 73 |
+
// Explicit destinations request optional results or supply metadata that cannot be inferred.
|
| 74 |
+
const { y } = await kernel({ size: { data: sizeData, shape: [] } }, {
|
| 75 |
+
outputs: { y: { shape: [1], dtype: "float32" } },
|
| 76 |
+
});
|
| 77 |
+
```
|
build/webgpu/bench.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"op": "ai.onnx.HannWindow",
|
| 3 |
+
"cases": [
|
| 4 |
+
{
|
| 5 |
+
"name": "hann-f32-4096",
|
| 6 |
+
"inputs": { "size": { "dtype": "int32", "shape": [], "data": { "kind": "values", "values": [4096] } } },
|
| 7 |
+
"outputs": { "y": { "dtype": "float32", "shape": [4096] } }
|
| 8 |
+
},
|
| 9 |
+
{
|
| 10 |
+
"name": "hann-f16-1m",
|
| 11 |
+
"preset": "edge",
|
| 12 |
+
"attrs": { "output_datatype": 10 },
|
| 13 |
+
"inputs": { "size": { "dtype": "int32", "shape": [], "data": { "kind": "values", "values": [1048576] } } },
|
| 14 |
+
"outputs": { "y": { "dtype": "float16", "shape": [1048576], "dist": "empty" } },
|
| 15 |
+
"bench": { "metrics": [{ "type": "bandwidth", "value": "2 * numel(shapes.y)", "name": "write-BW" }] }
|
| 16 |
+
},
|
| 17 |
+
{
|
| 18 |
+
"name": "hann-f32-1m",
|
| 19 |
+
"preset": "smoke",
|
| 20 |
+
"inputs": { "size": { "dtype": "int32", "shape": [], "data": { "kind": "values", "values": [1048576] } } },
|
| 21 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1048576], "dist": "empty" } },
|
| 22 |
+
"bench": { "metrics": [{ "type": "bandwidth", "value": "numel(shapes.y) * 4", "name": "write-BW" }] }
|
| 23 |
+
}
|
| 24 |
+
]
|
| 25 |
+
}
|
build/webgpu/manifest.json
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"domain": "ai.onnx",
|
| 3 |
+
"name": "HannWindow",
|
| 4 |
+
"sinceVersion": 17,
|
| 5 |
+
"description": "Generates a Hann window of a given length using the formula `0.5 - 0.5 * cos(2π * n / N)`, where `N` is `size` for periodic mode or `size - 1` for symmetric mode. The output is a 1-D tensor of length `size`.",
|
| 6 |
+
"inputs": [
|
| 7 |
+
{
|
| 8 |
+
"role": "size",
|
| 9 |
+
"dtype": "T1",
|
| 10 |
+
"description": "Scalar indicating the number of elements in the output window.",
|
| 11 |
+
"rank": 0
|
| 12 |
+
}
|
| 13 |
+
],
|
| 14 |
+
"outputs": [
|
| 15 |
+
{ "role": "output", "dtype": "T2", "description": "1-D Hann window tensor of shape `[size]`.", "rank": 1 }
|
| 16 |
+
],
|
| 17 |
+
"attributes": { "output_datatype": 1, "periodic": 1 },
|
| 18 |
+
"attributeDescriptions": {
|
| 19 |
+
"output_datatype": "Data type of the output tensor, encoded as a DataType enum value from TensorProto (default `1` = FLOAT).",
|
| 20 |
+
"periodic": "If `1` (default), returns a periodic window of length `size`; if `0`, returns a symmetric window of length `size`."
|
| 21 |
+
},
|
| 22 |
+
"attributeConstraints": { "periodic": { "values": [0, 1] } },
|
| 23 |
+
"typeConstraints": { "T1": ["int32"], "T2": ["float32", "float16", "uint32", "int32", "uint8", "int8", "int16"] },
|
| 24 |
+
"args": {
|
| 25 |
+
"size": { "kind": "tensor", "semantic": "size", "role": "input" },
|
| 26 |
+
"y": { "kind": "tensor", "semantic": "output", "role": "output" }
|
| 27 |
+
},
|
| 28 |
+
"tunables": { "WORKGROUP_SIZE": 256 },
|
| 29 |
+
"derive": {},
|
| 30 |
+
"variants": [
|
| 31 |
+
{
|
| 32 |
+
"id": "generic",
|
| 33 |
+
"when": "ranks.output == 1 and attrs.output_datatype == onnxDtypeCode(logicalDtypes.T2) and f16Ok(tensorDtypes.output)",
|
| 34 |
+
"constants": {
|
| 35 |
+
"usesF16": "tensorDtypes.output == \"float16\"",
|
| 36 |
+
"integerOutput": "tensorDtypes.output != \"float32\" and tensorDtypes.output != \"float16\"",
|
| 37 |
+
"outScalar": "dtypes.T2"
|
| 38 |
+
},
|
| 39 |
+
"passes": [
|
| 40 |
+
{
|
| 41 |
+
"id": "main",
|
| 42 |
+
"name": "HannWindow",
|
| 43 |
+
"source": { "shader": "window-cosine-sum.wgsl.jinja", "inputs": { "a0": "0.5", "a1": "0.5", "a2": "0" } },
|
| 44 |
+
"bindings": [
|
| 45 |
+
{
|
| 46 |
+
"name": "y",
|
| 47 |
+
"arg": "y",
|
| 48 |
+
"semantic": "output",
|
| 49 |
+
"buffer": { "type": "storage" },
|
| 50 |
+
"elementType": "$outScalar"
|
| 51 |
+
},
|
| 52 |
+
{
|
| 53 |
+
"name": "params",
|
| 54 |
+
"semantic": "kernel.params",
|
| 55 |
+
"buffer": { "type": "uniform" },
|
| 56 |
+
"struct": {
|
| 57 |
+
"name": "Params",
|
| 58 |
+
"fields": [
|
| 59 |
+
{ "name": "count", "type": "u32", "value": "numel(shapes.output)" },
|
| 60 |
+
{
|
| 61 |
+
"name": "denom",
|
| 62 |
+
"type": "f32",
|
| 63 |
+
"value": "dim(shapes.output, 0) if attrs.periodic else dim(shapes.output, 0) - 1"
|
| 64 |
+
}
|
| 65 |
+
]
|
| 66 |
+
}
|
| 67 |
+
}
|
| 68 |
+
],
|
| 69 |
+
"dispatch": { "gridStride": "numel(shapes.output)", "workgroupSize": "tunables.WORKGROUP_SIZE" }
|
| 70 |
+
}
|
| 71 |
+
]
|
| 72 |
+
}
|
| 73 |
+
]
|
| 74 |
+
}
|
build/webgpu/metadata.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "ai.onnx.HannWindow",
|
| 3 |
+
"id": "_ai_onnx_hannwindow_webgpu_d631c24",
|
| 4 |
+
"version": 1,
|
| 5 |
+
"license": "Apache-2.0",
|
| 6 |
+
"backend": { "type": "webgpu" },
|
| 7 |
+
"digest": {
|
| 8 |
+
"algorithm": "sha256",
|
| 9 |
+
"files": {
|
| 10 |
+
"bench.json": "PEIGhBPxuOnWnbnYZ7QAl796F7fkVaYB3agt7stTl7c=",
|
| 11 |
+
"manifest.json": "pLxvdWH8iSFyF9krpRrWQGiCCJ/bAW8+ksjxaaY7D1U=",
|
| 12 |
+
"test.json": "f/qlcQHxoUOnaLhNSSG6jsdaOpn929gU3yLsEAi5XyY=",
|
| 13 |
+
"window-cosine-sum.wgsl.jinja": "T17RHnl56gmwE9BtwVPMeL6Gb+bO/QFqpqKZ9q6EiBE="
|
| 14 |
+
}
|
| 15 |
+
},
|
| 16 |
+
"provenance": { "kernel": { "sha": "2e7068faf55e7f43df740015f6d1ee49391a41c5", "dirty": false } },
|
| 17 |
+
"webgpu": { "manifestSpec": "1.0", "specialized": true, "opPath": "ops/ai.onnx.HannWindow" }
|
| 18 |
+
}
|
build/webgpu/test.json
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"op": "ai.onnx.HannWindow",
|
| 3 |
+
"cases": [
|
| 4 |
+
{
|
| 5 |
+
"name": "periodic_f32_size16",
|
| 6 |
+
"inputs": { "size": { "dtype": "int32", "shape": [], "data": { "kind": "values", "values": [16] } } },
|
| 7 |
+
"outputs": { "y": { "dtype": "float32", "shape": [16], "tolerance": 0.00001 } }
|
| 8 |
+
},
|
| 9 |
+
{
|
| 10 |
+
"name": "symmetric_f32_size16",
|
| 11 |
+
"attrs": { "periodic": 0 },
|
| 12 |
+
"inputs": { "size": { "dtype": "int32", "shape": [], "data": { "kind": "values", "values": [16] } } },
|
| 13 |
+
"outputs": { "y": { "dtype": "float32", "shape": [16], "tolerance": 0.00001 } }
|
| 14 |
+
},
|
| 15 |
+
{
|
| 16 |
+
"name": "periodic_f32_size10",
|
| 17 |
+
"provenance": { "source": "cmake/external/onnx/onnx/backend/test/data/node/test_hannwindow" },
|
| 18 |
+
"inputs": { "size": { "dtype": "int32", "shape": [], "data": { "kind": "values", "values": [10] } } },
|
| 19 |
+
"outputs": { "y": { "dtype": "float32", "shape": [10], "tolerance": 0.00001 } }
|
| 20 |
+
},
|
| 21 |
+
{
|
| 22 |
+
"name": "symmetric_f32_size10_onnx_backend",
|
| 23 |
+
"provenance": { "source": "cmake/external/onnx/onnx/backend/test/data/node/test_hannwindow_symmetric" },
|
| 24 |
+
"attrs": { "periodic": 0 },
|
| 25 |
+
"inputs": { "size": { "dtype": "int32", "shape": [], "data": { "kind": "values", "values": [10] } } },
|
| 26 |
+
"outputs": { "y": { "dtype": "float32", "shape": [10], "tolerance": 0.00001 } }
|
| 27 |
+
},
|
| 28 |
+
{
|
| 29 |
+
"name": "periodic_f32_size0_empty",
|
| 30 |
+
"inputs": { "size": { "dtype": "int32", "shape": [], "data": { "kind": "values", "values": [0] } } },
|
| 31 |
+
"outputs": { "y": { "dtype": "float32", "shape": [0], "tolerance": 0 } }
|
| 32 |
+
},
|
| 33 |
+
{
|
| 34 |
+
"name": "periodic_f32_size1_boundary",
|
| 35 |
+
"inputs": { "size": { "dtype": "int32", "shape": [], "data": { "kind": "values", "values": [1] } } },
|
| 36 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1], "tolerance": 0.00001 } }
|
| 37 |
+
},
|
| 38 |
+
{
|
| 39 |
+
"name": "symmetric_f32_size1_nan_boundary",
|
| 40 |
+
"provenance": {
|
| 41 |
+
"source": "onnxruntime/test/providers/cpu/signal/signal_ops_test.cc",
|
| 42 |
+
"test": "SignalOpsTest.HannWindowFloat",
|
| 43 |
+
"notes": "Additional ORT-validated edge: symmetric size 1 uses denominator length - 1 = 0 and produces NaN."
|
| 44 |
+
},
|
| 45 |
+
"attrs": { "periodic": 0 },
|
| 46 |
+
"inputs": { "size": { "dtype": "int32", "shape": [], "data": { "kind": "values", "values": [1] } } },
|
| 47 |
+
"outputs": {
|
| 48 |
+
"y": {
|
| 49 |
+
"dtype": "float32",
|
| 50 |
+
"shape": [1],
|
| 51 |
+
"tolerance": 0,
|
| 52 |
+
"allowNaN": true,
|
| 53 |
+
"data": { "kind": "values", "values": ["NaN"] }
|
| 54 |
+
}
|
| 55 |
+
}
|
| 56 |
+
},
|
| 57 |
+
{
|
| 58 |
+
"name": "symmetric_f32_odd_size7",
|
| 59 |
+
"attrs": { "periodic": 0 },
|
| 60 |
+
"inputs": { "size": { "dtype": "int32", "shape": [], "data": { "kind": "values", "values": [7] } } },
|
| 61 |
+
"outputs": { "y": { "dtype": "float32", "shape": [7], "tolerance": 0.00001 } }
|
| 62 |
+
},
|
| 63 |
+
{
|
| 64 |
+
"name": "periodic_f16_size32",
|
| 65 |
+
"attrs": { "output_datatype": 10 },
|
| 66 |
+
"inputs": { "size": { "dtype": "int32", "shape": [], "data": { "kind": "values", "values": [32] } } },
|
| 67 |
+
"outputs": { "y": { "dtype": "float16", "shape": [32], "tolerance": 0.002 } }
|
| 68 |
+
},
|
| 69 |
+
{
|
| 70 |
+
"name": "ort_periodic_uint32_output_size8",
|
| 71 |
+
"provenance": {
|
| 72 |
+
"source": "ONNX Runtime CPUExecutionProvider",
|
| 73 |
+
"notes": "ONNX HannWindow computes in float and applies output_datatype=UINT32 as a final cast."
|
| 74 |
+
},
|
| 75 |
+
"attrs": { "output_datatype": 12 },
|
| 76 |
+
"inputs": { "size": { "dtype": "int32", "shape": [], "data": { "kind": "values", "values": [8] } } },
|
| 77 |
+
"outputs": {
|
| 78 |
+
"y": {
|
| 79 |
+
"dtype": "uint32",
|
| 80 |
+
"shape": [8],
|
| 81 |
+
"tolerance": 0,
|
| 82 |
+
"data": { "kind": "values", "values": [0, 0, 0, 0, 1, 0, 0, 0] }
|
| 83 |
+
}
|
| 84 |
+
}
|
| 85 |
+
},
|
| 86 |
+
{
|
| 87 |
+
"name": "ort_symmetric_int32_output_size1_zero_cast",
|
| 88 |
+
"provenance": {
|
| 89 |
+
"source": "ONNX Runtime CPUExecutionProvider",
|
| 90 |
+
"notes": "The symmetric size-one formula produces NaN in float; ONNX Cast to INT32 maps that value to zero."
|
| 91 |
+
},
|
| 92 |
+
"attrs": { "output_datatype": 6, "periodic": 0 },
|
| 93 |
+
"inputs": { "size": { "dtype": "int32", "shape": [], "data": { "kind": "values", "values": [1] } } },
|
| 94 |
+
"outputs": {
|
| 95 |
+
"y": { "dtype": "int32", "shape": [1], "tolerance": 0, "data": { "kind": "values", "values": [0] } }
|
| 96 |
+
}
|
| 97 |
+
},
|
| 98 |
+
{
|
| 99 |
+
"name": "onnx_standard_periodic_int8_output_size8",
|
| 100 |
+
"attrs": { "output_datatype": 3 },
|
| 101 |
+
"inputs": { "size": { "dtype": "int32", "shape": [], "data": { "kind": "values", "values": [8] } } },
|
| 102 |
+
"outputs": {
|
| 103 |
+
"y": {
|
| 104 |
+
"dtype": "int8",
|
| 105 |
+
"shape": [8],
|
| 106 |
+
"tolerance": 0,
|
| 107 |
+
"data": { "kind": "values", "values": [0, 0, 0, 0, 1, 0, 0, 0] }
|
| 108 |
+
}
|
| 109 |
+
}
|
| 110 |
+
},
|
| 111 |
+
{
|
| 112 |
+
"name": "onnx_standard_periodic_uint8_output_size8",
|
| 113 |
+
"attrs": { "output_datatype": 2 },
|
| 114 |
+
"inputs": { "size": { "dtype": "int32", "shape": [], "data": { "kind": "values", "values": [8] } } },
|
| 115 |
+
"outputs": {
|
| 116 |
+
"y": {
|
| 117 |
+
"dtype": "uint8",
|
| 118 |
+
"shape": [8],
|
| 119 |
+
"tolerance": 0,
|
| 120 |
+
"data": { "kind": "values", "values": [0, 0, 0, 0, 1, 0, 0, 0] }
|
| 121 |
+
}
|
| 122 |
+
}
|
| 123 |
+
},
|
| 124 |
+
{
|
| 125 |
+
"name": "onnx_standard_periodic_int16_output_size8",
|
| 126 |
+
"attrs": { "output_datatype": 5 },
|
| 127 |
+
"inputs": { "size": { "dtype": "int32", "shape": [], "data": { "kind": "values", "values": [8] } } },
|
| 128 |
+
"outputs": {
|
| 129 |
+
"y": {
|
| 130 |
+
"dtype": "int16",
|
| 131 |
+
"shape": [8],
|
| 132 |
+
"tolerance": 0,
|
| 133 |
+
"data": { "kind": "values", "values": [0, 0, 0, 0, 1, 0, 0, 0] }
|
| 134 |
+
}
|
| 135 |
+
}
|
| 136 |
+
},
|
| 137 |
+
{
|
| 138 |
+
"name": "periodic_f32_size257_phase_accuracy_gpu_gap",
|
| 139 |
+
"skipGpu": {
|
| 140 |
+
"category": "todo",
|
| 141 |
+
"reason": "The current f32 cosine and range-reduction path crosses the final rounding boundary for this periodic size-257 window. A correctly rounded approximation or software-extended precision could close this implementable gap."
|
| 142 |
+
},
|
| 143 |
+
"provenance": {
|
| 144 |
+
"source": "onnxruntime/test/providers/cpu/signal/signal_ops_test.cc",
|
| 145 |
+
"test": "SignalOpsTest.HannWindowFloat",
|
| 146 |
+
"notes": "Medium odd-sized periodic window stresses f32 phase formation across many non-cardinal cosine positions; CPU and ORT agree more tightly than the current WGSL f32 cosine-sum path."
|
| 147 |
+
},
|
| 148 |
+
"inputs": { "size": { "dtype": "int32", "shape": [], "data": { "kind": "values", "values": [257] } } },
|
| 149 |
+
"outputs": { "y": { "dtype": "float32", "shape": [257], "tolerance": 6e-8, "relTolerance": 0 } }
|
| 150 |
+
},
|
| 151 |
+
{
|
| 152 |
+
"name": "symmetric_f32_size257_phase_accuracy_gpu_gap",
|
| 153 |
+
"skipGpu": {
|
| 154 |
+
"category": "todo",
|
| 155 |
+
"reason": "The current f32 cosine and range-reduction path crosses the final rounding boundary for this symmetric size-257 window. A correctly rounded approximation or software-extended precision could close this implementable gap."
|
| 156 |
+
},
|
| 157 |
+
"provenance": {
|
| 158 |
+
"source": "onnxruntime/test/providers/cpu/signal/signal_ops_test.cc",
|
| 159 |
+
"test": "SignalOpsTest.HannWindowFloat",
|
| 160 |
+
"notes": "Symmetric odd-sized companion to the periodic phase edge; the length-1 denominator shifts every non-cardinal cosine sample and exposes f32 phase drift in the WGSL path."
|
| 161 |
+
},
|
| 162 |
+
"attrs": { "periodic": 0 },
|
| 163 |
+
"inputs": { "size": { "dtype": "int32", "shape": [], "data": { "kind": "values", "values": [257] } } },
|
| 164 |
+
"outputs": { "y": { "dtype": "float32", "shape": [257], "tolerance": 6e-8, "relTolerance": 0 } }
|
| 165 |
+
},
|
| 166 |
+
{
|
| 167 |
+
"name": "ort_periodic_f32_size32",
|
| 168 |
+
"provenance": {
|
| 169 |
+
"source": "onnxruntime/test/providers/cpu/signal/signal_ops_test.cc",
|
| 170 |
+
"test": "SignalOpsTest.HannWindowFloat"
|
| 171 |
+
},
|
| 172 |
+
"inputs": { "size": { "dtype": "int32", "shape": [], "data": { "kind": "values", "values": [32] } } },
|
| 173 |
+
"outputs": {
|
| 174 |
+
"y": {
|
| 175 |
+
"dtype": "float32",
|
| 176 |
+
"shape": [32],
|
| 177 |
+
"tolerance": 0.00001,
|
| 178 |
+
"data": {
|
| 179 |
+
"kind": "values",
|
| 180 |
+
"values": [0.0, 0.009607, 0.03806, 0.084265, 0.146447, 0.222215, 0.308658, 0.402455, 0.5, 0.597545, 0.691342, 0.777785, 0.853553, 0.915735, 0.96194, 0.990393, 1.0, 0.990393, 0.96194, 0.915735, 0.853553, 0.777785, 0.691342, 0.597545, 0.5, 0.402455, 0.308658, 0.222215, 0.146447, 0.084265, 0.03806, 0.009607]
|
| 181 |
+
}
|
| 182 |
+
}
|
| 183 |
+
}
|
| 184 |
+
},
|
| 185 |
+
{
|
| 186 |
+
"name": "periodic_int32_size8",
|
| 187 |
+
"inputs": { "size": { "dtype": "int32", "shape": [], "data": { "kind": "values", "values": [8] } } },
|
| 188 |
+
"outputs": { "y": { "dtype": "float32", "shape": [8], "tolerance": 0.00001 } }
|
| 189 |
+
},
|
| 190 |
+
{
|
| 191 |
+
"name": "symmetric_f32_size2_denom1",
|
| 192 |
+
"attrs": { "periodic": 0 },
|
| 193 |
+
"inputs": { "size": { "dtype": "int32", "shape": [], "data": { "kind": "values", "values": [2] } } },
|
| 194 |
+
"outputs": {
|
| 195 |
+
"y": {
|
| 196 |
+
"dtype": "float32",
|
| 197 |
+
"shape": [2],
|
| 198 |
+
"tolerance": 0.00001,
|
| 199 |
+
"data": { "kind": "values", "values": [0.0, 0.0] }
|
| 200 |
+
}
|
| 201 |
+
}
|
| 202 |
+
},
|
| 203 |
+
{
|
| 204 |
+
"name": "symmetric_f32_size4_cardinal_verify",
|
| 205 |
+
"attrs": { "periodic": 0 },
|
| 206 |
+
"inputs": { "size": { "dtype": "int32", "shape": [], "data": { "kind": "values", "values": [4] } } },
|
| 207 |
+
"outputs": { "y": { "dtype": "float32", "shape": [4], "tolerance": 0.00001 } }
|
| 208 |
+
},
|
| 209 |
+
{
|
| 210 |
+
"name": "symmetric_f16_size16",
|
| 211 |
+
"attrs": { "output_datatype": 10, "periodic": 0 },
|
| 212 |
+
"requires": { "features": ["shader-f16"] },
|
| 213 |
+
"inputs": { "size": { "dtype": "int32", "shape": [], "data": { "kind": "values", "values": [16] } } },
|
| 214 |
+
"outputs": { "y": { "dtype": "float16", "shape": [16], "tolerance": 0.002 } }
|
| 215 |
+
}
|
| 216 |
+
]
|
| 217 |
+
}
|
build/webgpu/window-cosine-sum.wgsl.jinja
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Cosine-sum window:
|
| 2 |
+
// w = a0 - a1*cos(phase) + a2*cos(2*phase), phase = 2*pi*n/N
|
| 3 |
+
// Compiled coefficients select Hann, Hamming, or Blackman. N (params.denom) is
|
| 4 |
+
// the window length for a periodic window, or length - 1 for a symmetric window.
|
| 5 |
+
//
|
| 6 |
+
// Matching the f64-rounded target within roughly 0.5 ULP requires two
|
| 7 |
+
// details beyond a naive `a0 - a1*cos(2*pi*n/N)`: keep n/N as a rational turn and
|
| 8 |
+
// use the backend-stable unit-circle polynomial, and form a0 - a1*c with one
|
| 9 |
+
// rounding via fma(-a1, c, a0). WGSL builtin transcendental accuracy is
|
| 10 |
+
// implementation-defined, and a rounded multiply followed by subtraction would
|
| 11 |
+
// double-round. Grid strides cover large windows with a clamped dispatch.
|
| 12 |
+
{% if usesF16 %}
|
| 13 |
+
enable f16;
|
| 14 |
+
{% endif %}
|
| 15 |
+
{{ env.wgsl.resourceDeclarations }}
|
| 16 |
+
// Backend-stable unit-circle twiddles for DFT kernels. Retain the phase as a
|
| 17 |
+
// rational turn and route all polynomial evaluation through the shared precise
|
| 18 |
+
// trig core so FFT, direct DFT, STFT, and cosine windows agree exactly.
|
| 19 |
+
//
|
| 20 |
+
// phase is in [0, period). sign is -1 for a forward transform and +1 for an
|
| 21 |
+
// inverse transform. The result is (cos, sin).
|
| 22 |
+
// Backend-stable f32 sine/cosine core.
|
| 23 |
+
//
|
| 24 |
+
// Shader transcendental accuracy is implementation-defined, and some portable
|
| 25 |
+
// backends are only accurate to roughly 1e-4. Each path retains the most accurate
|
| 26 |
+
// available phase representation, reduces it to [-pi, pi], then uses these
|
| 27 |
+
// polynomials. The half-pi core is degree 13 for sine and degree 12 for cosine;
|
| 28 |
+
// truncation error is well below one f32 ULP over its documented interval.
|
| 29 |
+
const PRECISE_TRIG_PI: f32 = 3.141592653589793;
|
| 30 |
+
const PRECISE_TRIG_TWO_PI: f32 = 6.283185307179586;
|
| 31 |
+
const PRECISE_TRIG_HALF_PI: f32 = 1.5707963267948966;
|
| 32 |
+
|
| 33 |
+
// Input must be in [-pi/2, pi/2]. Returns (cos(x), sin(x)).
|
| 34 |
+
fn precise_sincos_half_pi(x: f32) -> vec2<f32> {
|
| 35 |
+
let x2 = x * x;
|
| 36 |
+
|
| 37 |
+
var sinPolynomial = 1.6059043836821613e-10;
|
| 38 |
+
sinPolynomial = fma(sinPolynomial, x2, -2.505210838544172e-8);
|
| 39 |
+
sinPolynomial = fma(sinPolynomial, x2, 2.7557319223985893e-6);
|
| 40 |
+
sinPolynomial = fma(sinPolynomial, x2, -1.984126984126984e-4);
|
| 41 |
+
sinPolynomial = fma(sinPolynomial, x2, 8.333333333333333e-3);
|
| 42 |
+
sinPolynomial = fma(sinPolynomial, x2, -1.6666666666666666e-1);
|
| 43 |
+
let sine = x * fma(sinPolynomial, x2, 1.0);
|
| 44 |
+
|
| 45 |
+
var cosPolynomial = 2.08767569878681e-9;
|
| 46 |
+
cosPolynomial = fma(cosPolynomial, x2, -2.755731922398589e-7);
|
| 47 |
+
cosPolynomial = fma(cosPolynomial, x2, 2.48015873015873e-5);
|
| 48 |
+
cosPolynomial = fma(cosPolynomial, x2, -1.388888888888889e-3);
|
| 49 |
+
cosPolynomial = fma(cosPolynomial, x2, 4.1666666666666664e-2);
|
| 50 |
+
cosPolynomial = fma(cosPolynomial, x2, -5.0e-1);
|
| 51 |
+
let cosine = fma(cosPolynomial, x2, 1.0);
|
| 52 |
+
|
| 53 |
+
return vec2<f32>(cosine, sine);
|
| 54 |
+
}
|
| 55 |
+
|
| 56 |
+
// Input must be in [-pi, pi]. Returns (cos(x), sin(x)).
|
| 57 |
+
fn precise_sincos_centered(x: f32) -> vec2<f32> {
|
| 58 |
+
var folded = x;
|
| 59 |
+
var cosineSign = 1.0;
|
| 60 |
+
if (folded > PRECISE_TRIG_HALF_PI) {
|
| 61 |
+
folded = PRECISE_TRIG_PI - folded;
|
| 62 |
+
cosineSign = -1.0;
|
| 63 |
+
} else if (folded < -PRECISE_TRIG_HALF_PI) {
|
| 64 |
+
folded = -PRECISE_TRIG_PI - folded;
|
| 65 |
+
cosineSign = -1.0;
|
| 66 |
+
}
|
| 67 |
+
let value = precise_sincos_half_pi(folded);
|
| 68 |
+
return vec2<f32>(cosineSign * value.x, value.y);
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
fn dft_precise_twiddle(phase: u32, period: u32, sign: f32) -> vec2<f32> {
|
| 73 |
+
let reducedPhase = phase % period;
|
| 74 |
+
if (reducedPhase == 0u) {
|
| 75 |
+
return vec2<f32>(1.0, sign * 0.0);
|
| 76 |
+
}
|
| 77 |
+
if (period % 4u == 0u) {
|
| 78 |
+
let quarter = period / 4u;
|
| 79 |
+
if (reducedPhase == quarter) {
|
| 80 |
+
return vec2<f32>(0.0, sign);
|
| 81 |
+
}
|
| 82 |
+
if (reducedPhase == 2u * quarter) {
|
| 83 |
+
return vec2<f32>(-1.0, sign * 0.0);
|
| 84 |
+
}
|
| 85 |
+
if (reducedPhase == 3u * quarter) {
|
| 86 |
+
return vec2<f32>(0.0, -sign);
|
| 87 |
+
}
|
| 88 |
+
}
|
| 89 |
+
// Center the rational turn before multiplying by 2*pi. This avoids the
|
| 90 |
+
// cancellation in `2*pi*(N-1)/N - 2*pi` for bins near the end of a row.
|
| 91 |
+
let turns = f32(reducedPhase) / f32(period);
|
| 92 |
+
let centeredTurns = turns - floor(turns + 0.5);
|
| 93 |
+
return precise_sincos_centered(sign * PRECISE_TRIG_TWO_PI * centeredTurns);
|
| 94 |
+
}
|
| 95 |
+
|
| 96 |
+
|
| 97 |
+
const WG: u32 = {{ tunables.WORKGROUP_SIZE }}u;
|
| 98 |
+
|
| 99 |
+
fn cos_turns(phase: u32, period: u32) -> f32 {
|
| 100 |
+
return dft_precise_twiddle(phase % period, period, 1.0).x;
|
| 101 |
+
}
|
| 102 |
+
|
| 103 |
+
@compute @workgroup_size({{ tunables.WORKGROUP_SIZE }})
|
| 104 |
+
fn main(
|
| 105 |
+
@builtin(global_invocation_id) gid: vec3<u32>,
|
| 106 |
+
@builtin(num_workgroups) nwg: vec3<u32>
|
| 107 |
+
) {
|
| 108 |
+
let stride = nwg.x * WG;
|
| 109 |
+
for (var i = gid.x; i < params.count; i += stride) {
|
| 110 |
+
if (params.denom == 0.0) {
|
| 111 |
+
{% if integerOutput %}
|
| 112 |
+
// The window is evaluated in f32 before the output cast. Spell the
|
| 113 |
+
// symmetric-size-one integer result directly instead of converting NaN.
|
| 114 |
+
y[i] = {{ outScalar }}(0);
|
| 115 |
+
{% else %}
|
| 116 |
+
// Do not synthesize NaN with 0/0: fast-math can fold identical operands to
|
| 117 |
+
// 1. Incorporating the runtime uniform also keeps
|
| 118 |
+
// WGSL validators from rejecting a compile-time non-finite constant.
|
| 119 |
+
let nan_bits = bitcast<u32>(params.denom) | 0x7fc00000u;
|
| 120 |
+
y[i] = {{ outScalar }}(bitcast<f32>(nan_bits));
|
| 121 |
+
{% endif %}
|
| 122 |
+
continue;
|
| 123 |
+
}
|
| 124 |
+
let period = u32(params.denom);
|
| 125 |
+
// w = a0 - a1*cos(2*pi*turns) [+ a2*cos(4*pi*turns)], fused single-rounding.
|
| 126 |
+
var w = fma(-({{ source.a1 }}), cos_turns(i, period), {{ source.a0 }});
|
| 127 |
+
y[i] = {{ outScalar }}(w);
|
| 128 |
+
}
|
| 129 |
+
}
|