sync 2e7068faf55e
Browse files- README.md +93 -0
- build/webgpu/bench.json +452 -0
- build/webgpu/conv-1x1-gemm-tiled-reg.wgsl.jinja +402 -0
- build/webgpu/conv-1x1-gemm-tiled.wgsl.jinja +121 -0
- build/webgpu/conv-1x1-subgroup-matrix.wgsl.jinja +306 -0
- build/webgpu/conv-transpose-empty-input.wgsl.jinja +57 -0
- build/webgpu/conv-transpose1d-ncl.wgsl.jinja +102 -0
- build/webgpu/conv-transpose1d-phase-tiled.wgsl.jinja +102 -0
- build/webgpu/conv-transpose2d-col2im.wgsl.jinja +96 -0
- build/webgpu/conv-transpose2d-grouped-stride-phase.wgsl.jinja +70 -0
- build/webgpu/conv-transpose2d-nchw.wgsl.jinja +124 -0
- build/webgpu/conv-transpose2d-phase-gemm-tiled.wgsl.jinja +155 -0
- build/webgpu/conv-transpose2d-weight-reorder.wgsl.jinja +57 -0
- build/webgpu/conv-transpose3d-col2im.wgsl.jinja +88 -0
- build/webgpu/conv-transpose3d-ncdhw.wgsl.jinja +73 -0
- build/webgpu/conv-transpose3d-weight-reorder.wgsl.jinja +56 -0
- build/webgpu/manifest.json +0 -0
- build/webgpu/metadata.json +31 -0
- build/webgpu/test.json +1856 -0
README.md
CHANGED
|
@@ -1,3 +1,96 @@
|
|
| 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.ConvTranspose
|
| 10 |
+
|
| 11 |
+
`ai.onnx` · standard ONNX operator · ONNX opset ≥ 11
|
| 12 |
+
|
| 13 |
+
## Description
|
| 14 |
+
|
| 15 |
+
Computes the transpose of a convolution, also known as a fractionally strided convolution or deconvolution, from input tensor `X`, filter weights `W`, and an optional bias `B`. Output spatial dimensions follow the stride, dilation, padding, and optional `output_padding` attributes. Supports grouped convolution through `group`.
|
| 16 |
+
|
| 17 |
+
See the [ONNX `ConvTranspose` spec](https://onnx.ai/onnx/operators/onnx__ConvTranspose.html) for the reference semantics.
|
| 18 |
+
|
| 19 |
+
## Inputs
|
| 20 |
+
|
| 21 |
+
| Name | Bind key | Logical dtype | Rank | Shape | Description | Presence |
|
| 22 |
+
| --- | --- | --- | --- | --- | --- | --- |
|
| 23 |
+
| `X` | `x` | `T` | — | — | Input data tensor of shape `(N x C x D1 x ... x Dn)`, where `N` is batch size and `C` is the number of input channels. | required |
|
| 24 |
+
| `W` | `w` | `T` | — | — | Filter weight tensor of shape `(C x M/group x k1 x ... x kn)`, where `M` is the number of output feature maps. | required |
|
| 25 |
+
| `B` | `bias` | `T` | `1` | — | Optional 1-D bias of length M added to each output channel. | optional |
|
| 26 |
+
|
| 27 |
+
## Outputs
|
| 28 |
+
|
| 29 |
+
| Name | Bind key | Logical dtype | Rank | Shape | Description | Presence |
|
| 30 |
+
| --- | --- | --- | --- | --- | --- | --- |
|
| 31 |
+
| `Y` | `y` | `T` | same as `X` | derived; see description | Output tensor whose spatial dimensions are computed from the input size, kernel shape, strides, dilations, and padding. | required |
|
| 32 |
+
|
| 33 |
+
## Attributes
|
| 34 |
+
|
| 35 |
+
Attributes and default values (overridable per request):
|
| 36 |
+
|
| 37 |
+
| Attribute | Default | Description |
|
| 38 |
+
| --- | --- | --- |
|
| 39 |
+
| `auto_pad` | `"NOTSET"` | Padding mode: `NOTSET` uses explicit pads; `SAME_UPPER` and `SAME_LOWER` make output spatial size equal input size times stride, with any odd extra padding added at the end or beginning respectively; `VALID` applies no padding. |
|
| 40 |
+
| `group` | `1` | Number of groups that input and output channels are divided into for grouped (depthwise) convolution. |
|
| 41 |
+
| `dilations` | — | Dilation factors for each spatial axis; defaults to one on every axis. |
|
| 42 |
+
| `kernel_shape` | — | Kernel dimensions for each spatial axis. When omitted, they are inferred from the spatial dimensions of `W`. |
|
| 43 |
+
| `output_padding` | — | Additional size on the high-index end of each output spatial axis; each value must be smaller than the corresponding stride or dilation. |
|
| 44 |
+
| `output_shape` | — | Requested output spatial dimensions. When present, it must match the declared spatial shape of `Y`. |
|
| 45 |
+
| `pads` | — | Padding at the beginning of every spatial axis followed by padding at the end of every spatial axis; defaults to zeros. |
|
| 46 |
+
| `strides` | — | Stride factors for each spatial axis; defaults to one on every axis. |
|
| 47 |
+
|
| 48 |
+
## Type constraints
|
| 49 |
+
|
| 50 |
+
| Variable | Allowed dtypes |
|
| 51 |
+
| --- | --- |
|
| 52 |
+
| `T` | `float32`, `float16` |
|
| 53 |
+
|
| 54 |
+
## Device requirements
|
| 55 |
+
|
| 56 |
+
Some implementation variants require `subgroup-matrix`, `shader-f16`, and `subgroups`. These are route-specific capabilities, not package-wide requirements; availability also depends on the request shape and dtype.
|
| 57 |
+
|
| 58 |
+
## Files
|
| 59 |
+
|
| 60 |
+
- [`metadata.json`](build/webgpu/metadata.json) — kernel metadata (id, digests, provenance)
|
| 61 |
+
- [`manifest.json`](build/webgpu/manifest.json) — the op contract (source of truth)
|
| 62 |
+
- [`test.json`](build/webgpu/test.json) — correctness cases
|
| 63 |
+
- [`bench.json`](build/webgpu/bench.json) — benchmark + tuning cases
|
| 64 |
+
- [`conv-1x1-gemm-tiled-reg.wgsl.jinja`](build/webgpu/conv-1x1-gemm-tiled-reg.wgsl.jinja)
|
| 65 |
+
- [`conv-1x1-gemm-tiled.wgsl.jinja`](build/webgpu/conv-1x1-gemm-tiled.wgsl.jinja)
|
| 66 |
+
- [`conv-1x1-subgroup-matrix.wgsl.jinja`](build/webgpu/conv-1x1-subgroup-matrix.wgsl.jinja)
|
| 67 |
+
- [`conv-transpose-empty-input.wgsl.jinja`](build/webgpu/conv-transpose-empty-input.wgsl.jinja)
|
| 68 |
+
- [`conv-transpose1d-ncl.wgsl.jinja`](build/webgpu/conv-transpose1d-ncl.wgsl.jinja)
|
| 69 |
+
- [`conv-transpose1d-phase-tiled.wgsl.jinja`](build/webgpu/conv-transpose1d-phase-tiled.wgsl.jinja)
|
| 70 |
+
- [`conv-transpose2d-col2im.wgsl.jinja`](build/webgpu/conv-transpose2d-col2im.wgsl.jinja)
|
| 71 |
+
- [`conv-transpose2d-grouped-stride-phase.wgsl.jinja`](build/webgpu/conv-transpose2d-grouped-stride-phase.wgsl.jinja)
|
| 72 |
+
- [`conv-transpose2d-nchw.wgsl.jinja`](build/webgpu/conv-transpose2d-nchw.wgsl.jinja)
|
| 73 |
+
- [`conv-transpose2d-phase-gemm-tiled.wgsl.jinja`](build/webgpu/conv-transpose2d-phase-gemm-tiled.wgsl.jinja)
|
| 74 |
+
- [`conv-transpose2d-weight-reorder.wgsl.jinja`](build/webgpu/conv-transpose2d-weight-reorder.wgsl.jinja)
|
| 75 |
+
- [`conv-transpose3d-col2im.wgsl.jinja`](build/webgpu/conv-transpose3d-col2im.wgsl.jinja)
|
| 76 |
+
- [`conv-transpose3d-ncdhw.wgsl.jinja`](build/webgpu/conv-transpose3d-ncdhw.wgsl.jinja)
|
| 77 |
+
- [`conv-transpose3d-weight-reorder.wgsl.jinja`](build/webgpu/conv-transpose3d-weight-reorder.wgsl.jinja)
|
| 78 |
+
|
| 79 |
+
## Use with `@huggingface/kernels`
|
| 80 |
+
|
| 81 |
+
The loader derives every required output's shape and logical dtype from the manifest contract and this call.
|
| 82 |
+
It then allocates the result tensors automatically.
|
| 83 |
+
|
| 84 |
+
The `version: 1` option selects the published kernel contract; it is independent of any operator opset, contrib `since_version`, or model version.
|
| 85 |
+
|
| 86 |
+
Replace each `*Data` placeholder with a typed array containing the corresponding input data.
|
| 87 |
+
|
| 88 |
+
```js
|
| 89 |
+
import { getKernel } from "@huggingface/kernels";
|
| 90 |
+
|
| 91 |
+
const kernel = await getKernel("webgpu-kernels/ai.onnx.ConvTranspose", { version: 1 });
|
| 92 |
+
const { y } = await kernel({
|
| 93 |
+
x: { data: xData, shape: [1, 1, 3] },
|
| 94 |
+
w: { data: wData, shape: [1, 2, 2] },
|
| 95 |
+
});
|
| 96 |
+
```
|
build/webgpu/bench.json
ADDED
|
@@ -0,0 +1,452 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"op": "ai.onnx.ConvTranspose",
|
| 3 |
+
"tunableSpace": { "WORKGROUP_SIZE": [64, 128, 256] },
|
| 4 |
+
"cases": [
|
| 5 |
+
{
|
| 6 |
+
"name": "conv-transpose-f32-b1c16m16-16x16-k3s2",
|
| 7 |
+
"preset": "smoke",
|
| 8 |
+
"vars": {
|
| 9 |
+
"batch": 1,
|
| 10 |
+
"inChannels": 16,
|
| 11 |
+
"outChannels": 16,
|
| 12 |
+
"inH": 16,
|
| 13 |
+
"inW": 16,
|
| 14 |
+
"kernelH": 3,
|
| 15 |
+
"kernelW": 3,
|
| 16 |
+
"strideH": 2,
|
| 17 |
+
"strideW": 2,
|
| 18 |
+
"padH": 1,
|
| 19 |
+
"padW": 1
|
| 20 |
+
},
|
| 21 |
+
"attrs": { "strides": [2, 2], "pads": [1, 1, 1, 1] },
|
| 22 |
+
"inputs": {
|
| 23 |
+
"x": { "shape": [1, 16, 16, 16], "dtype": "float32", "dist": "normal", "seed": 114, "scale": 0.2 },
|
| 24 |
+
"w": { "shape": [16, 16, 3, 3], "dtype": "float32", "dist": "normal", "seed": 115, "scale": 0.1 }
|
| 25 |
+
},
|
| 26 |
+
"outputs": { "y": { "shape": [1, 16, 31, 31], "dtype": "float32" } },
|
| 27 |
+
"bench": {
|
| 28 |
+
"primary": true,
|
| 29 |
+
"metrics": [
|
| 30 |
+
{
|
| 31 |
+
"type": "gflops",
|
| 32 |
+
"value": "2 * args.batch * args.outChannels * args.inH * args.inW * args.inChannels * args.kernelH * args.kernelW"
|
| 33 |
+
}
|
| 34 |
+
]
|
| 35 |
+
}
|
| 36 |
+
},
|
| 37 |
+
{
|
| 38 |
+
"name": "conv-transpose-f32-non-vector-bias-b1c3m5-32x32-k3s2",
|
| 39 |
+
"preset": "edge",
|
| 40 |
+
"vars": {
|
| 41 |
+
"batch": 1,
|
| 42 |
+
"inChannels": 3,
|
| 43 |
+
"outChannels": 5,
|
| 44 |
+
"inH": 32,
|
| 45 |
+
"inW": 32,
|
| 46 |
+
"kernelH": 3,
|
| 47 |
+
"kernelW": 3,
|
| 48 |
+
"strideH": 2,
|
| 49 |
+
"strideW": 2,
|
| 50 |
+
"padH": 1,
|
| 51 |
+
"padW": 1
|
| 52 |
+
},
|
| 53 |
+
"attrs": { "strides": [2, 2], "pads": [1, 1, 1, 1] },
|
| 54 |
+
"inputs": {
|
| 55 |
+
"x": { "shape": [1, 3, 32, 32], "dtype": "float32", "dist": "normal", "seed": 116, "scale": 0.2 },
|
| 56 |
+
"w": { "shape": [3, 5, 3, 3], "dtype": "float32", "dist": "normal", "seed": 117, "scale": 0.1 },
|
| 57 |
+
"bias": { "shape": [5], "dtype": "float32", "dist": "normal", "seed": 118, "scale": 0.1 }
|
| 58 |
+
},
|
| 59 |
+
"outputs": { "y": { "shape": [1, 5, 63, 63], "dtype": "float32" } },
|
| 60 |
+
"bench": {
|
| 61 |
+
"metrics": [
|
| 62 |
+
{
|
| 63 |
+
"type": "gflops",
|
| 64 |
+
"value": "2 * args.batch * args.outChannels * args.inH * args.inW * args.inChannels * args.kernelH * args.kernelW"
|
| 65 |
+
}
|
| 66 |
+
]
|
| 67 |
+
}
|
| 68 |
+
},
|
| 69 |
+
{
|
| 70 |
+
"name": "conv-transpose-f16-b1c64m64-32x32-k3s2",
|
| 71 |
+
"preset": "smoke",
|
| 72 |
+
"vars": {
|
| 73 |
+
"batch": 1,
|
| 74 |
+
"inChannels": 64,
|
| 75 |
+
"outChannels": 64,
|
| 76 |
+
"inH": 32,
|
| 77 |
+
"inW": 32,
|
| 78 |
+
"kernelH": 3,
|
| 79 |
+
"kernelW": 3,
|
| 80 |
+
"strideH": 2,
|
| 81 |
+
"strideW": 2,
|
| 82 |
+
"padH": 1,
|
| 83 |
+
"padW": 1
|
| 84 |
+
},
|
| 85 |
+
"attrs": { "strides": [2, 2], "pads": [1, 1, 1, 1] },
|
| 86 |
+
"inputs": {
|
| 87 |
+
"x": { "shape": [1, 64, 32, 32], "dtype": "float16", "dist": "normal", "seed": 211, "scale": 0.2 },
|
| 88 |
+
"w": { "shape": [64, 64, 3, 3], "dtype": "float16", "dist": "normal", "seed": 212, "scale": 0.1 }
|
| 89 |
+
},
|
| 90 |
+
"outputs": { "y": { "shape": [1, 64, 63, 63], "dtype": "float16" } },
|
| 91 |
+
"bench": {
|
| 92 |
+
"metrics": [
|
| 93 |
+
{
|
| 94 |
+
"type": "gflops",
|
| 95 |
+
"value": "2 * args.batch * args.outChannels * args.inH * args.inW * args.inChannels * args.kernelH * args.kernelW"
|
| 96 |
+
}
|
| 97 |
+
]
|
| 98 |
+
}
|
| 99 |
+
},
|
| 100 |
+
{
|
| 101 |
+
"name": "conv-transpose-f32-b1c64m64-32x32-k3s2",
|
| 102 |
+
"preset": "smoke",
|
| 103 |
+
"vars": {
|
| 104 |
+
"batch": 1,
|
| 105 |
+
"inChannels": 64,
|
| 106 |
+
"outChannels": 64,
|
| 107 |
+
"inH": 32,
|
| 108 |
+
"inW": 32,
|
| 109 |
+
"kernelH": 3,
|
| 110 |
+
"kernelW": 3,
|
| 111 |
+
"strideH": 2,
|
| 112 |
+
"strideW": 2,
|
| 113 |
+
"padH": 1,
|
| 114 |
+
"padW": 1
|
| 115 |
+
},
|
| 116 |
+
"attrs": { "strides": [2, 2], "pads": [1, 1, 1, 1] },
|
| 117 |
+
"inputs": {
|
| 118 |
+
"x": { "shape": [1, 64, 32, 32], "dtype": "float32", "dist": "normal", "seed": 211, "scale": 0.2 },
|
| 119 |
+
"w": { "shape": [64, 64, 3, 3], "dtype": "float32", "dist": "normal", "seed": 212, "scale": 0.1 }
|
| 120 |
+
},
|
| 121 |
+
"outputs": { "y": { "shape": [1, 64, 63, 63], "dtype": "float32" } },
|
| 122 |
+
"bench": {
|
| 123 |
+
"metrics": [
|
| 124 |
+
{
|
| 125 |
+
"type": "gflops",
|
| 126 |
+
"value": "2 * args.batch * args.outChannels * args.inH * args.inW * args.inChannels * args.kernelH * args.kernelW"
|
| 127 |
+
}
|
| 128 |
+
]
|
| 129 |
+
}
|
| 130 |
+
},
|
| 131 |
+
{
|
| 132 |
+
"name": "conv-transpose-f16-large-upsampler-b1c128m128-64x64-k4s2",
|
| 133 |
+
"preset": "smoke",
|
| 134 |
+
"vars": {
|
| 135 |
+
"batch": 1,
|
| 136 |
+
"inChannels": 128,
|
| 137 |
+
"outChannels": 128,
|
| 138 |
+
"inH": 64,
|
| 139 |
+
"inW": 64,
|
| 140 |
+
"kernelH": 4,
|
| 141 |
+
"kernelW": 4,
|
| 142 |
+
"strideH": 2,
|
| 143 |
+
"strideW": 2,
|
| 144 |
+
"padH": 1,
|
| 145 |
+
"padW": 1
|
| 146 |
+
},
|
| 147 |
+
"attrs": { "strides": [2, 2], "pads": [1, 1, 1, 1] },
|
| 148 |
+
"inputs": {
|
| 149 |
+
"x": { "shape": [1, 128, 64, 64], "dtype": "float16", "dist": "normal", "seed": 213, "scale": 0.2 },
|
| 150 |
+
"w": { "shape": [128, 128, 4, 4], "dtype": "float16", "dist": "normal", "seed": 214, "scale": 0.05 }
|
| 151 |
+
},
|
| 152 |
+
"outputs": { "y": { "shape": [1, 128, 128, 128], "dtype": "float16" } },
|
| 153 |
+
"bench": {
|
| 154 |
+
"metrics": [
|
| 155 |
+
{
|
| 156 |
+
"type": "gflops",
|
| 157 |
+
"value": "2 * args.batch * args.outChannels * args.inH * args.inW * args.inChannels * args.kernelH * args.kernelW"
|
| 158 |
+
}
|
| 159 |
+
]
|
| 160 |
+
}
|
| 161 |
+
},
|
| 162 |
+
{
|
| 163 |
+
"name": "conv-transpose-f32-depthwise-g64-32x32-k4s2",
|
| 164 |
+
"preset": "smoke",
|
| 165 |
+
"vars": {
|
| 166 |
+
"batch": 1,
|
| 167 |
+
"inChannels": 64,
|
| 168 |
+
"outChannels": 64,
|
| 169 |
+
"inChannelsPerGroup": 1,
|
| 170 |
+
"inH": 32,
|
| 171 |
+
"inW": 32,
|
| 172 |
+
"kernelH": 4,
|
| 173 |
+
"kernelW": 4,
|
| 174 |
+
"strideH": 2,
|
| 175 |
+
"strideW": 2,
|
| 176 |
+
"padH": 1,
|
| 177 |
+
"padW": 1,
|
| 178 |
+
"group": 64
|
| 179 |
+
},
|
| 180 |
+
"attrs": { "group": 64, "strides": [2, 2], "pads": [1, 1, 1, 1] },
|
| 181 |
+
"inputs": {
|
| 182 |
+
"x": { "shape": [1, 64, 32, 32], "dtype": "float32", "dist": "normal", "seed": 215, "scale": 0.2 },
|
| 183 |
+
"w": { "shape": [64, 1, 4, 4], "dtype": "float32", "dist": "normal", "seed": 216, "scale": 0.1 }
|
| 184 |
+
},
|
| 185 |
+
"outputs": { "y": { "shape": [1, 64, 64, 64], "dtype": "float32" } },
|
| 186 |
+
"bench": {
|
| 187 |
+
"metrics": [
|
| 188 |
+
{
|
| 189 |
+
"type": "gflops",
|
| 190 |
+
"value": "2 * args.batch * args.outChannels * args.inH * args.inW * args.inChannelsPerGroup * args.kernelH * args.kernelW"
|
| 191 |
+
}
|
| 192 |
+
]
|
| 193 |
+
}
|
| 194 |
+
},
|
| 195 |
+
{
|
| 196 |
+
"name": "conv-transpose-f32-depthwise-pointwise-g64-512x512-dispatch-fold",
|
| 197 |
+
"preset": "edge",
|
| 198 |
+
"provenance": {
|
| 199 |
+
"notes": "Realistic depthwise pointwise projection at 16,777,216 outputs. Exercises the two-dimensional dispatch fold while exposing scalar coordinate/division overhead in the generic grouped kernel."
|
| 200 |
+
},
|
| 201 |
+
"vars": { "count": 16777216 },
|
| 202 |
+
"attrs": { "group": 64 },
|
| 203 |
+
"inputs": {
|
| 204 |
+
"x": { "shape": [1, 64, 512, 512], "dtype": "float32", "dist": "normal", "seed": 221, "scale": 0.2 },
|
| 205 |
+
"w": { "shape": [64, 1, 1, 1], "dtype": "float32", "dist": "normal", "seed": 222, "scale": 0.1 }
|
| 206 |
+
},
|
| 207 |
+
"outputs": { "y": { "shape": [1, 64, 512, 512], "dtype": "float32" } },
|
| 208 |
+
"bench": { "metrics": [{ "type": "bandwidth", "value": "(2 * args.count + 64) * 4" }] }
|
| 209 |
+
},
|
| 210 |
+
{
|
| 211 |
+
"name": "conv-transpose-f32-1d-b1c128m128-256-k4s2",
|
| 212 |
+
"preset": "smoke",
|
| 213 |
+
"vars": { "batch": 1, "inChannels": 128, "outChannels": 128, "inW": 256, "kernelW": 4, "strideW": 2, "padW": 1 },
|
| 214 |
+
"attrs": { "strides": [2], "pads": [1, 1] },
|
| 215 |
+
"inputs": {
|
| 216 |
+
"x": { "shape": [1, 128, 256], "dtype": "float32", "dist": "normal", "seed": 217, "scale": 0.2 },
|
| 217 |
+
"w": { "shape": [128, 128, 4], "dtype": "float32", "dist": "normal", "seed": 218, "scale": 0.1 }
|
| 218 |
+
},
|
| 219 |
+
"outputs": { "y": { "shape": [1, 128, 512], "dtype": "float32" } },
|
| 220 |
+
"bench": {
|
| 221 |
+
"metrics": [
|
| 222 |
+
{ "type": "gflops", "value": "2 * args.batch * args.outChannels * args.inW * args.inChannels * args.kernelW" }
|
| 223 |
+
]
|
| 224 |
+
}
|
| 225 |
+
},
|
| 226 |
+
{
|
| 227 |
+
"name": "neural-audio-1d-f32-b1c256m256-w1024-k4s2-pathology",
|
| 228 |
+
"preset": "stress",
|
| 229 |
+
"provenance": {
|
| 230 |
+
"source": "authored for performance coverage",
|
| 231 |
+
"notes": "Realistic neural-audio upsampling stage for the direct NCW fallback. Every output sample serially scans 256 input channels and four kernel taps."
|
| 232 |
+
},
|
| 233 |
+
"vars": { "batch": 1, "inChannels": 256, "outChannels": 256, "inW": 1024, "kernelW": 4, "strideW": 2, "padW": 1 },
|
| 234 |
+
"attrs": { "strides": [2], "pads": [1, 1] },
|
| 235 |
+
"inputs": {
|
| 236 |
+
"x": { "shape": [1, 256, 1024], "dtype": "float32", "dist": "normal", "seed": 219, "scale": 0.2 },
|
| 237 |
+
"w": { "shape": [256, 256, 4], "dtype": "float32", "dist": "normal", "seed": 220, "scale": 0.05 }
|
| 238 |
+
},
|
| 239 |
+
"outputs": { "y": { "shape": [1, 256, 2048], "dtype": "float32" } },
|
| 240 |
+
"bench": {
|
| 241 |
+
"metrics": [
|
| 242 |
+
{ "type": "gflops", "value": "2 * args.batch * args.outChannels * args.inW * args.inChannels * args.kernelW" }
|
| 243 |
+
]
|
| 244 |
+
}
|
| 245 |
+
},
|
| 246 |
+
{
|
| 247 |
+
"name": "conv-transpose-f32-3d-naive-b1c16m16-16x16x16-k3",
|
| 248 |
+
"preset": "stress",
|
| 249 |
+
"vars": {
|
| 250 |
+
"batch": 1,
|
| 251 |
+
"inChannels": 16,
|
| 252 |
+
"outChannels": 16,
|
| 253 |
+
"inD": 16,
|
| 254 |
+
"inH": 16,
|
| 255 |
+
"inW": 16,
|
| 256 |
+
"kernelD": 3,
|
| 257 |
+
"kernelH": 3,
|
| 258 |
+
"kernelW": 3
|
| 259 |
+
},
|
| 260 |
+
"attrs": {},
|
| 261 |
+
"inputs": {
|
| 262 |
+
"x": { "shape": [1, 16, 16, 16, 16], "dtype": "float32", "dist": "normal", "seed": 331, "scale": 0.2 },
|
| 263 |
+
"w": { "shape": [16, 16, 3, 3, 3], "dtype": "float32", "dist": "normal", "seed": 332, "scale": 0.05 }
|
| 264 |
+
},
|
| 265 |
+
"outputs": { "y": { "shape": [1, 16, 18, 18, 18], "dtype": "float32" } },
|
| 266 |
+
"bench": {
|
| 267 |
+
"metrics": [
|
| 268 |
+
{
|
| 269 |
+
"type": "gflops",
|
| 270 |
+
"value": "2 * args.batch * args.outChannels * args.inD * args.inH * args.inW * args.inChannels * args.kernelD * args.kernelH * args.kernelW"
|
| 271 |
+
}
|
| 272 |
+
]
|
| 273 |
+
}
|
| 274 |
+
},
|
| 275 |
+
{
|
| 276 |
+
"name": "medical-decoder-3d-f32-b1c32m32-32x32x32-k3-pathology",
|
| 277 |
+
"preset": "stress",
|
| 278 |
+
"provenance": {
|
| 279 |
+
"source": "authored for performance coverage",
|
| 280 |
+
"notes": "Realistic 3D decoder stage for the direct NCDHW fallback. Each output voxel serially scans all 32 input channels and the 3x3x3 kernel."
|
| 281 |
+
},
|
| 282 |
+
"vars": {
|
| 283 |
+
"batch": 1,
|
| 284 |
+
"inChannels": 32,
|
| 285 |
+
"outChannels": 32,
|
| 286 |
+
"inD": 32,
|
| 287 |
+
"inH": 32,
|
| 288 |
+
"inW": 32,
|
| 289 |
+
"kernelD": 3,
|
| 290 |
+
"kernelH": 3,
|
| 291 |
+
"kernelW": 3
|
| 292 |
+
},
|
| 293 |
+
"attrs": { "pads": [1, 1, 1, 1, 1, 1] },
|
| 294 |
+
"inputs": {
|
| 295 |
+
"x": { "shape": [1, 32, 32, 32, 32], "dtype": "float32", "dist": "normal", "seed": 333, "scale": 0.2 },
|
| 296 |
+
"w": { "shape": [32, 32, 3, 3, 3], "dtype": "float32", "dist": "normal", "seed": 334, "scale": 0.05 }
|
| 297 |
+
},
|
| 298 |
+
"outputs": { "y": { "shape": [1, 32, 32, 32, 32], "dtype": "float32" } },
|
| 299 |
+
"bench": {
|
| 300 |
+
"metrics": [
|
| 301 |
+
{
|
| 302 |
+
"type": "gflops",
|
| 303 |
+
"value": "2 * args.batch * args.outChannels * args.inD * args.inH * args.inW * args.inChannels * args.kernelD * args.kernelH * args.kernelW"
|
| 304 |
+
}
|
| 305 |
+
]
|
| 306 |
+
}
|
| 307 |
+
},
|
| 308 |
+
{
|
| 309 |
+
"name": "conv-transpose-f32-grouped-naive-g4-c32m64-48x48-k4s2",
|
| 310 |
+
"preset": "stress",
|
| 311 |
+
"vars": {
|
| 312 |
+
"batch": 1,
|
| 313 |
+
"inChannels": 32,
|
| 314 |
+
"outChannels": 64,
|
| 315 |
+
"inChannelsPerGroup": 8,
|
| 316 |
+
"inH": 48,
|
| 317 |
+
"inW": 48,
|
| 318 |
+
"kernelH": 4,
|
| 319 |
+
"kernelW": 4,
|
| 320 |
+
"strideH": 2,
|
| 321 |
+
"strideW": 2,
|
| 322 |
+
"padH": 1,
|
| 323 |
+
"padW": 1,
|
| 324 |
+
"group": 4
|
| 325 |
+
},
|
| 326 |
+
"attrs": { "group": 4, "strides": [2, 2], "pads": [1, 1, 1, 1] },
|
| 327 |
+
"inputs": {
|
| 328 |
+
"x": { "shape": [1, 32, 48, 48], "dtype": "float32", "dist": "normal", "seed": 341, "scale": 0.2 },
|
| 329 |
+
"w": { "shape": [32, 16, 4, 4], "dtype": "float32", "dist": "normal", "seed": 342, "scale": 0.05 }
|
| 330 |
+
},
|
| 331 |
+
"outputs": { "y": { "shape": [1, 64, 96, 96], "dtype": "float32" } },
|
| 332 |
+
"bench": {
|
| 333 |
+
"metrics": [
|
| 334 |
+
{
|
| 335 |
+
"type": "gflops",
|
| 336 |
+
"value": "2 * args.batch * args.outChannels * args.inH * args.inW * args.inChannelsPerGroup * args.kernelH * args.kernelW"
|
| 337 |
+
}
|
| 338 |
+
]
|
| 339 |
+
}
|
| 340 |
+
},
|
| 341 |
+
{
|
| 342 |
+
"name": "grouped-bias-g4-c32m64-48x48-k4s2-generic-pathology",
|
| 343 |
+
"preset": "stress",
|
| 344 |
+
"provenance": {
|
| 345 |
+
"source": "authored for variant coverage",
|
| 346 |
+
"notes": "Adding channel bias excludes nchw2d_grouped_stride_phase and selects nchw2d_grouped_bias; the paired no-bias case isolates this optional-input route boundary."
|
| 347 |
+
},
|
| 348 |
+
"vars": {
|
| 349 |
+
"batch": 1,
|
| 350 |
+
"inChannels": 32,
|
| 351 |
+
"outChannels": 64,
|
| 352 |
+
"inChannelsPerGroup": 8,
|
| 353 |
+
"inH": 48,
|
| 354 |
+
"inW": 48,
|
| 355 |
+
"kernelH": 4,
|
| 356 |
+
"kernelW": 4,
|
| 357 |
+
"strideH": 2,
|
| 358 |
+
"strideW": 2,
|
| 359 |
+
"padH": 1,
|
| 360 |
+
"padW": 1,
|
| 361 |
+
"group": 4
|
| 362 |
+
},
|
| 363 |
+
"attrs": { "group": 4, "strides": [2, 2], "pads": [1, 1, 1, 1] },
|
| 364 |
+
"inputs": {
|
| 365 |
+
"x": { "shape": [1, 32, 48, 48], "dtype": "float32", "dist": "normal", "seed": 5104, "scale": 0.2 },
|
| 366 |
+
"w": { "shape": [32, 16, 4, 4], "dtype": "float32", "dist": "normal", "seed": 5105, "scale": 0.05 },
|
| 367 |
+
"bias": { "shape": [64], "dtype": "float32", "dist": "normal", "seed": 5106, "scale": 0.05 }
|
| 368 |
+
},
|
| 369 |
+
"outputs": { "y": { "shape": [1, 64, 96, 96], "dtype": "float32" } },
|
| 370 |
+
"bench": {
|
| 371 |
+
"metrics": [
|
| 372 |
+
{
|
| 373 |
+
"type": "gflops",
|
| 374 |
+
"value": "2 * args.batch * args.outChannels * args.inH * args.inW * args.inChannelsPerGroup * args.kernelH * args.kernelW"
|
| 375 |
+
}
|
| 376 |
+
]
|
| 377 |
+
}
|
| 378 |
+
},
|
| 379 |
+
{
|
| 380 |
+
"name": "conv-transpose-f32-dpt-reassemble-48ch-37x49-k4s4",
|
| 381 |
+
"preset": "all",
|
| 382 |
+
"provenance": {
|
| 383 |
+
"source": "Depth Anything V2 Small neck reassemble",
|
| 384 |
+
"notes": "Depth Anything V2 Small's factor-4 reassemble at 518x686. ConvTranspose contracts the projected neck width (48), not the backbone width."
|
| 385 |
+
},
|
| 386 |
+
"vars": {
|
| 387 |
+
"batch": 1,
|
| 388 |
+
"inChannels": 48,
|
| 389 |
+
"outChannels": 48,
|
| 390 |
+
"inH": 37,
|
| 391 |
+
"inW": 49,
|
| 392 |
+
"kernelH": 4,
|
| 393 |
+
"kernelW": 4,
|
| 394 |
+
"strideH": 4,
|
| 395 |
+
"strideW": 4,
|
| 396 |
+
"padH": 0,
|
| 397 |
+
"padW": 0
|
| 398 |
+
},
|
| 399 |
+
"attrs": { "strides": [4, 4] },
|
| 400 |
+
"inputs": {
|
| 401 |
+
"x": { "shape": [1, 48, 37, 49], "dtype": "float32", "dist": "normal", "seed": 9421, "scale": 0.2 },
|
| 402 |
+
"w": { "shape": [48, 48, 4, 4], "dtype": "float32", "dist": "normal", "seed": 9422, "scale": 0.1 },
|
| 403 |
+
"bias": { "shape": [48], "dtype": "float32", "dist": "normal", "seed": 9423, "scale": 0.1 }
|
| 404 |
+
},
|
| 405 |
+
"outputs": { "y": { "shape": [1, 48, 148, 196], "dtype": "float32" } },
|
| 406 |
+
"bench": {
|
| 407 |
+
"metrics": [
|
| 408 |
+
{
|
| 409 |
+
"type": "gflops",
|
| 410 |
+
"value": "2 * args.batch * args.outChannels * args.inH * args.inW * args.inChannels * args.kernelH * args.kernelW"
|
| 411 |
+
}
|
| 412 |
+
]
|
| 413 |
+
}
|
| 414 |
+
},
|
| 415 |
+
{
|
| 416 |
+
"name": "conv-transpose-f32-dpt-reassemble-96ch-37x49-k2s2",
|
| 417 |
+
"preset": "all",
|
| 418 |
+
"provenance": {
|
| 419 |
+
"source": "Depth Anything V2 Small neck reassemble",
|
| 420 |
+
"notes": "The factor-2 reassemble of the same model, likewise contracting over the neck width (96). Four taps per output element, one of them real."
|
| 421 |
+
},
|
| 422 |
+
"vars": {
|
| 423 |
+
"batch": 1,
|
| 424 |
+
"inChannels": 96,
|
| 425 |
+
"outChannels": 96,
|
| 426 |
+
"inH": 37,
|
| 427 |
+
"inW": 49,
|
| 428 |
+
"kernelH": 2,
|
| 429 |
+
"kernelW": 2,
|
| 430 |
+
"strideH": 2,
|
| 431 |
+
"strideW": 2,
|
| 432 |
+
"padH": 0,
|
| 433 |
+
"padW": 0
|
| 434 |
+
},
|
| 435 |
+
"attrs": { "strides": [2, 2] },
|
| 436 |
+
"inputs": {
|
| 437 |
+
"x": { "shape": [1, 96, 37, 49], "dtype": "float32", "dist": "normal", "seed": 9431, "scale": 0.2 },
|
| 438 |
+
"w": { "shape": [96, 96, 2, 2], "dtype": "float32", "dist": "normal", "seed": 9432, "scale": 0.1 },
|
| 439 |
+
"bias": { "shape": [96], "dtype": "float32", "dist": "normal", "seed": 9433, "scale": 0.1 }
|
| 440 |
+
},
|
| 441 |
+
"outputs": { "y": { "shape": [1, 96, 74, 98], "dtype": "float32" } },
|
| 442 |
+
"bench": {
|
| 443 |
+
"metrics": [
|
| 444 |
+
{
|
| 445 |
+
"type": "gflops",
|
| 446 |
+
"value": "2 * args.batch * args.outChannels * args.inH * args.inW * args.inChannels * args.kernelH * args.kernelW"
|
| 447 |
+
}
|
| 448 |
+
]
|
| 449 |
+
}
|
| 450 |
+
}
|
| 451 |
+
]
|
| 452 |
+
}
|
build/webgpu/conv-1x1-gemm-tiled-reg.wgsl.jinja
ADDED
|
@@ -0,0 +1,402 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// 1x1 / im2col Conv routed as a batched GEMM:
|
| 2 |
+
// Y[b] (M x N) = W (M x K) * X[b] (K x N), with M = outChannels,
|
| 3 |
+
// K = inChannels * kh * kw after im2col, and N = H * W. Register-blocked
|
| 4 |
+
// workgroup lanes compute TM x TN micro-tiles. The defaults use 16x16 lanes with
|
| 5 |
+
// an 8x4 micro-tile over a 64x64 output tile. Weight A is shared across the batch;
|
| 6 |
+
// input B and the output use the dispatch.z batch offset. Accumulation is f32;
|
| 7 |
+
// the optional epilogue applies bias, residual Z, and activation in the
|
| 8 |
+
// accumulator domain on store. Every dimension is bounds-checked.
|
| 9 |
+
// f16 operands remain packed in workgroup memory and widen only at the FMA site;
|
| 10 |
+
// the f32 accumulation order is retained while shared traffic is halved.
|
| 11 |
+
//
|
| 12 |
+
// Both shared tiles are stored as vec4 groups along the axis each lane consumes
|
| 13 |
+
// contiguously: tileA groups four K values for one output row, tileB groups four
|
| 14 |
+
// N columns for one K. One micro-tile step therefore reads TM + 4 vector words
|
| 15 |
+
// instead of 4 * (TM + TN) scalars, so a shared word feeds four times as many
|
| 16 |
+
// FMAs and the K loop runs four accumulation steps per iteration.
|
| 17 |
+
{% if usesF16 %}
|
| 18 |
+
enable f16;
|
| 19 |
+
{% endif %}
|
| 20 |
+
{{ env.wgsl.resourceDeclarations }}
|
| 21 |
+
{% set hasActivation = hasActivation is defined and hasActivation %}
|
| 22 |
+
{% if hasActivation %}
|
| 23 |
+
// Apply the fused activation in the f32 accumulator before the single output
|
| 24 |
+
// cast, avoiding an intermediate convolution tensor.
|
| 25 |
+
fn fused_act(v: f32) -> f32 {
|
| 26 |
+
return v * clamp(v * 0.16666666666666666 + 0.5, 0.0, 1.0);
|
| 27 |
+
}
|
| 28 |
+
{% endif %}
|
| 29 |
+
|
| 30 |
+
{% set tileT = "f16" if usesF16 else "f32" -%}
|
| 31 |
+
{%- set GEMM_BK = gemmKTile if gemmKTile is defined else 16 %}
|
| 32 |
+
{% set GEMM_TM = gemmThreadRows if gemmThreadRows is defined else 8 %}
|
| 33 |
+
{% set GEMM_WG_X = gemmWorkgroupX if gemmWorkgroupX is defined else 16 %}
|
| 34 |
+
{% set GEMM_BM = gemmMTile if gemmMTile is defined else 64 %}
|
| 35 |
+
{% set GEMM_BN = gemmNTile if gemmNTile is defined else GEMM_WG_X * 4 %}
|
| 36 |
+
{% set GEMM_TN = gemmThreadColumns if gemmThreadColumns is defined else (GEMM_BN / GEMM_WG_X)|int %}
|
| 37 |
+
{% set GEMM_WG_Y = gemmWorkgroupY if gemmWorkgroupY is defined else (GEMM_BM / GEMM_TM)|int %}
|
| 38 |
+
{% set components = ["x", "y", "z", "w"] %}
|
| 39 |
+
const BK: u32 = {{ GEMM_BK }}u;
|
| 40 |
+
const BM: u32 = {{ GEMM_BM }}u;
|
| 41 |
+
const BN: u32 = {{ GEMM_BN }}u;
|
| 42 |
+
const TM: u32 = {{ GEMM_TM }}u;
|
| 43 |
+
const TN: u32 = {{ GEMM_TN }}u;
|
| 44 |
+
const WG_X: u32 = {{ GEMM_WG_X }}u;
|
| 45 |
+
const WG_SIZE: u32 = {{ GEMM_WG_X * GEMM_WG_Y }}u;
|
| 46 |
+
// Vector words per tile row: A groups K, B groups N.
|
| 47 |
+
const AK_VECS: u32 = BK / 4u;
|
| 48 |
+
const BN_VECS: u32 = BN / 4u;
|
| 49 |
+
|
| 50 |
+
// implicitIm2col leaves B unmaterialized. While staging a tile, the kernel
|
| 51 |
+
// decodes each (k, n) column-matrix coordinate into a raw NCHW input address.
|
| 52 |
+
// Overlapping windows may reread input values, trading address arithmetic and
|
| 53 |
+
// cache traffic for the storage and bandwidth of the expanded column matrix.
|
| 54 |
+
{% set implicitIm2col = implicitIm2col is defined and implicitIm2col %}
|
| 55 |
+
{% set fusedNarrowProjection = fusedNarrowProjection is defined and fusedNarrowProjection %}
|
| 56 |
+
{% if fusedNarrowProjection %}
|
| 57 |
+
{% set projectionChannels = projectionOutChannels %}
|
| 58 |
+
{% set projectionInputAct = inputActivation %}
|
| 59 |
+
{% set projectionOutputAct = outputActivation %}
|
| 60 |
+
{% set projectionScaled = hasOutputScale %}
|
| 61 |
+
{% set projectionBiased = hasProjectionBias %}
|
| 62 |
+
{% endif %}
|
| 63 |
+
{% set narrowProjectionTile = "tileB" if GEMM_BK >= GEMM_BM else "projectionTile" %}
|
| 64 |
+
{% set splitKValue = splitK if splitK is defined else 1 %}
|
| 65 |
+
{% set splitKPartial = splitKValue > 1 %}
|
| 66 |
+
{% set gemmKLimit = "kEnd" if splitKPartial else "K" %}
|
| 67 |
+
{% set implicitGatherMode = tunables.IMPLICIT_TILED_GATHER_MODE if tunables.IMPLICIT_TILED_GATHER_MODE is defined else 0 %}
|
| 68 |
+
{% set implicitGatherWgSize = GEMM_WG_X * GEMM_WG_Y %}
|
| 69 |
+
{% set implicitGatherColumnVecs = (GEMM_BN / 4)|int %}
|
| 70 |
+
{% set implicitGatherKChunks = (implicitGatherWgSize / implicitGatherColumnVecs)|int %}
|
| 71 |
+
{% set implicitGatherDivides = implicitGatherWgSize % implicitGatherColumnVecs == 0 and implicitGatherKChunks > 0 and GEMM_BK % implicitGatherKChunks == 0 %}
|
| 72 |
+
{% set useCarriedImplicitGather = implicitIm2col and implicitGatherMode == 1 and implicitGatherDivides %}
|
| 73 |
+
{% if useCarriedImplicitGather %}
|
| 74 |
+
{% set implicitGatherLoadWidth = (GEMM_BK / implicitGatherKChunks)|int %}
|
| 75 |
+
{% endif %}
|
| 76 |
+
{% if implicitIm2col %}
|
| 77 |
+
const CONV_KERNEL_H: u32 = {{ convKernelH }}u;
|
| 78 |
+
const CONV_KERNEL_W: u32 = {{ convKernelW }}u;
|
| 79 |
+
const CONV_KSIZE: u32 = CONV_KERNEL_H * CONV_KERNEL_W;
|
| 80 |
+
const CONV_STRIDE_H: u32 = {{ convStrideH }}u;
|
| 81 |
+
const CONV_STRIDE_W: u32 = {{ convStrideW }}u;
|
| 82 |
+
const CONV_DILATION_H: u32 = {{ convDilationH }}u;
|
| 83 |
+
const CONV_DILATION_W: u32 = {{ convDilationW }}u;
|
| 84 |
+
const CONV_PAD_TOP: i32 = {{ convPadTop }};
|
| 85 |
+
const CONV_PAD_LEFT: i32 = {{ convPadLeft }};
|
| 86 |
+
const CONV_IN_H: u32 = {{ convInH }}u;
|
| 87 |
+
const CONV_IN_W: u32 = {{ convInW }}u;
|
| 88 |
+
const CONV_OUT_W: u32 = {{ convOutW }}u;
|
| 89 |
+
const CONV_IN_CHANNELS: u32 = {{ convInChannels }}u;
|
| 90 |
+
{% endif %}
|
| 91 |
+
|
| 92 |
+
{% if fusedNarrowProjection %}
|
| 93 |
+
|
| 94 |
+
const PROJECTION_OUT_C: u32 = {{ projectionChannels }}u;
|
| 95 |
+
{% else %}{% set emitConvStoreOut = not splitKPartial %}{% if emitConvStoreOut | default(true) %}fn store_out(m: u32, n: u32, yBase: u32, raw: f32) {
|
| 96 |
+
if (m >= params.M || n >= params.N) {
|
| 97 |
+
return;
|
| 98 |
+
}
|
| 99 |
+
var v = raw;
|
| 100 |
+
{% if hasBias %}
|
| 101 |
+
v = v + f32(bias[m]);
|
| 102 |
+
{% endif %}
|
| 103 |
+
{% if hasActivation %}
|
| 104 |
+
v = fused_act(v);
|
| 105 |
+
{% endif %}
|
| 106 |
+
y[yBase + m * params.N + n] = {{ T }}(v);
|
| 107 |
+
}
|
| 108 |
+
{% endif %}
|
| 109 |
+
{% endif %}
|
| 110 |
+
|
| 111 |
+
var<workgroup> tileA: array<array<vec4<{{ tileT }}>, AK_VECS>, BM>;
|
| 112 |
+
var<workgroup> tileB: array<array<vec4<{{ tileT }}>, BN_VECS>, BK>;
|
| 113 |
+
{% if fusedNarrowProjection and GEMM_BK < GEMM_BM %}
|
| 114 |
+
// BK16 cannot reuse the 16-row input tile to publish a BM32 intermediate.
|
| 115 |
+
// The extra 32x64 f32 tile keeps the total at 14 KiB, below WebGPU's
|
| 116 |
+
// guaranteed 16 KiB workgroup-storage floor.
|
| 117 |
+
var<workgroup> projectionTile: array<array<vec4<f32>, BN_VECS>, BM>;
|
| 118 |
+
{% endif %}
|
| 119 |
+
{% macro publish_projection_input(localRow, localVec, component, globalRow, globalColumn, raw) %}
|
| 120 |
+
if ({{ globalRow }} < M && {{ globalColumn }} < N) {
|
| 121 |
+
var projectionInput = {{ raw }};
|
| 122 |
+
{% if hasBias %}
|
| 123 |
+
projectionInput = projectionInput + f32(bias[{{ globalRow }}]);
|
| 124 |
+
{% endif %}
|
| 125 |
+
{% if projectionInputAct == "relu" %}
|
| 126 |
+
projectionInput = projection_relu(projectionInput);
|
| 127 |
+
{% endif %}
|
| 128 |
+
{{ narrowProjectionTile }}[{{ localRow }}][{{ localVec }}].{{ component }} = projectionInput;
|
| 129 |
+
} else {
|
| 130 |
+
{{ narrowProjectionTile }}[{{ localRow }}][{{ localVec }}].{{ component }} = 0.0;
|
| 131 |
+
}
|
| 132 |
+
{%- endmacro %}
|
| 133 |
+
{% macro load_a_vec4(rowBase, columnBase, rowLimit, columnLimit) %}
|
| 134 |
+
for (var linear = li; linear < BM * AK_VECS; linear += WG_SIZE) {
|
| 135 |
+
let ar = linear / AK_VECS;
|
| 136 |
+
let ac4 = linear % AK_VECS;
|
| 137 |
+
let am = {{ rowBase }} + ar;
|
| 138 |
+
let ak = {{ columnBase }} + ac4 * 4u;
|
| 139 |
+
var av = vec4<{{ tileT }}>({{ tileT }}(0.0));
|
| 140 |
+
if (am < {{ rowLimit }}) {
|
| 141 |
+
let aBase = am * K + ak;
|
| 142 |
+
if (ak + 3u < {{ columnLimit }}) {
|
| 143 |
+
av = vec4<{{ tileT }}>({{ tileT }}(w[aBase]), {{ tileT }}(w[aBase + 1u]), {{ tileT }}(w[aBase + 2u]), {{ tileT }}(w[aBase + 3u]));
|
| 144 |
+
} else {
|
| 145 |
+
for (var t = 0u; t < 4u; t = t + 1u) {
|
| 146 |
+
if (ak + t < {{ columnLimit }}) {
|
| 147 |
+
av[t] = {{ tileT }}(w[aBase + t]);
|
| 148 |
+
}
|
| 149 |
+
}
|
| 150 |
+
}
|
| 151 |
+
}
|
| 152 |
+
tileA[ar][ac4] = av;
|
| 153 |
+
}
|
| 154 |
+
{%- endmacro %}
|
| 155 |
+
{% macro load_b_vec4(rowBase, columnBase, rowLimit, columnLimit) %}
|
| 156 |
+
for (var linear = li; linear < BK * BN_VECS; linear += WG_SIZE) {
|
| 157 |
+
let br = linear / BN_VECS;
|
| 158 |
+
let bc4 = linear % BN_VECS;
|
| 159 |
+
let bk = {{ rowBase }} + br;
|
| 160 |
+
let bn = {{ columnBase }} + bc4 * 4u;
|
| 161 |
+
var bvec = vec4<{{ tileT }}>({{ tileT }}(0.0));
|
| 162 |
+
if (bk < {{ rowLimit }}) {
|
| 163 |
+
let bBase = xBatchBase + bk * N + bn;
|
| 164 |
+
if (bn + 3u < {{ columnLimit }}) {
|
| 165 |
+
bvec = vec4<{{ tileT }}>({{ tileT }}(xm[bBase]), {{ tileT }}(xm[bBase + 1u]), {{ tileT }}(xm[bBase + 2u]), {{ tileT }}(xm[bBase + 3u]));
|
| 166 |
+
} else {
|
| 167 |
+
for (var t = 0u; t < 4u; t = t + 1u) {
|
| 168 |
+
if (bn + t < {{ columnLimit }}) {
|
| 169 |
+
bvec[t] = {{ tileT }}(xm[bBase + t]);
|
| 170 |
+
}
|
| 171 |
+
}
|
| 172 |
+
}
|
| 173 |
+
}
|
| 174 |
+
tileB[br][bc4] = bvec;
|
| 175 |
+
}
|
| 176 |
+
{%- endmacro %}
|
| 177 |
+
{% macro load_b_implicit_vec4(rowBase, columnBase, rowLimit, columnLimit) %}
|
| 178 |
+
for (var linear = li; linear < BK * BN_VECS; linear += WG_SIZE) {
|
| 179 |
+
let br = linear / BN_VECS;
|
| 180 |
+
let bc4 = linear % BN_VECS;
|
| 181 |
+
let bk = {{ rowBase }} + br;
|
| 182 |
+
var bvec = vec4<{{ tileT }}>({{ tileT }}(0.0));
|
| 183 |
+
if (bk < {{ rowLimit }}) {
|
| 184 |
+
// k is the OIHW weight flattening (ic * KH + kh) * KW + kw; n is the output position.
|
| 185 |
+
let ic = bk / CONV_KSIZE;
|
| 186 |
+
let kq = bk % CONV_KSIZE;
|
| 187 |
+
let kh = kq / CONV_KERNEL_W;
|
| 188 |
+
let kw = kq % CONV_KERNEL_W;
|
| 189 |
+
let planeBase = (batch * CONV_IN_CHANNELS + ic) * CONV_IN_H;
|
| 190 |
+
for (var t = 0u; t < 4u; t = t + 1u) {
|
| 191 |
+
let bn = {{ columnBase }} + bc4 * 4u + t;
|
| 192 |
+
if (bn < {{ columnLimit }}) {
|
| 193 |
+
let oh = bn / CONV_OUT_W;
|
| 194 |
+
let ow = bn % CONV_OUT_W;
|
| 195 |
+
let ih = i32(oh * CONV_STRIDE_H + kh * CONV_DILATION_H) - CONV_PAD_TOP;
|
| 196 |
+
let iw = i32(ow * CONV_STRIDE_W + kw * CONV_DILATION_W) - CONV_PAD_LEFT;
|
| 197 |
+
if (ih >= 0 && ih < i32(CONV_IN_H) && iw >= 0 && iw < i32(CONV_IN_W)) {
|
| 198 |
+
bvec[t] = {{ tileT }}(xm[(planeBase + u32(ih)) * CONV_IN_W + u32(iw)]);
|
| 199 |
+
}
|
| 200 |
+
}
|
| 201 |
+
}
|
| 202 |
+
}
|
| 203 |
+
tileB[br][bc4] = bvec;
|
| 204 |
+
}
|
| 205 |
+
{%- endmacro %}
|
| 206 |
+
{% macro load_b_implicit_carried(rowBase, columnBase, rowLimit, columnLimit) %}
|
| 207 |
+
let bColVec = li / {{ implicitGatherKChunks }}u;
|
| 208 |
+
let bChunk = li % {{ implicitGatherKChunks }}u;
|
| 209 |
+
let bLocalK = bChunk * {{ implicitGatherLoadWidth }}u;
|
| 210 |
+
let bStartK = {{ rowBase }} + bLocalK;
|
| 211 |
+
let bCol0 = {{ columnBase }} + bColVec * 4u;
|
| 212 |
+
let bCols = vec4<u32>(bCol0, bCol0 + 1u, bCol0 + 2u, bCol0 + 3u);
|
| 213 |
+
let inColumn = bCols < vec4<u32>({{ columnLimit }});
|
| 214 |
+
let ih0 = vec4<i32>((bCols / vec4<u32>(CONV_OUT_W)) * CONV_STRIDE_H) - vec4<i32>(CONV_PAD_TOP);
|
| 215 |
+
let iw0 = vec4<i32>((bCols % vec4<u32>(CONV_OUT_W)) * CONV_STRIDE_W) - vec4<i32>(CONV_PAD_LEFT);
|
| 216 |
+
var carriedK = bStartK;
|
| 217 |
+
var carriedIc = carriedK / CONV_KSIZE;
|
| 218 |
+
let carriedKq = carriedK % CONV_KSIZE;
|
| 219 |
+
var carriedKh = carriedKq / CONV_KERNEL_W;
|
| 220 |
+
var carriedKw = carriedKq % CONV_KERNEL_W;
|
| 221 |
+
var carriedIh = ih0 + vec4<i32>(i32(carriedKh * CONV_DILATION_H));
|
| 222 |
+
var carriedIw = iw0 + vec4<i32>(i32(carriedKw * CONV_DILATION_W));
|
| 223 |
+
|
| 224 |
+
// Interior words can carry four addresses. Padding, the N tail, and the
|
| 225 |
+
// final K tile retain the coordinate-checked loop below and publish exact
|
| 226 |
+
// zeros.
|
| 227 |
+
let interior = all(inColumn)
|
| 228 |
+
&& bStartK + {{ implicitGatherLoadWidth }}u <= {{ rowLimit }}
|
| 229 |
+
&& all(ih0 >= vec4<i32>(0))
|
| 230 |
+
&& all(ih0 + vec4<i32>(i32((CONV_KERNEL_H - 1u) * CONV_DILATION_H)) < vec4<i32>(i32(CONV_IN_H)))
|
| 231 |
+
&& all(iw0 >= vec4<i32>(0))
|
| 232 |
+
&& all(iw0 + vec4<i32>(i32((CONV_KERNEL_W - 1u) * CONV_DILATION_W)) < vec4<i32>(i32(CONV_IN_W)));
|
| 233 |
+
if (interior) {
|
| 234 |
+
let batchBase = batch * CONV_IN_CHANNELS * CONV_IN_H * CONV_IN_W;
|
| 235 |
+
let colStep = i32(CONV_DILATION_W);
|
| 236 |
+
let rowStep = i32(CONV_DILATION_H * CONV_IN_W);
|
| 237 |
+
let planeStep = i32(CONV_IN_H * CONV_IN_W);
|
| 238 |
+
let kwWrap = colStep * i32(CONV_KERNEL_W) - rowStep;
|
| 239 |
+
let khWrap = rowStep * i32(CONV_KERNEL_H) - planeStep;
|
| 240 |
+
var carriedAddress = vec4<i32>(i32(carriedIc) * planeStep) + carriedIh * vec4<i32>(i32(CONV_IN_W)) + carriedIw;
|
| 241 |
+
for (var i = 0u; i < {{ implicitGatherLoadWidth }}u; i = i + 1u) {
|
| 242 |
+
tileB[bLocalK + i][bColVec] = vec4<{{ tileT }}>(
|
| 243 |
+
{% for component in components %}
|
| 244 |
+
{{ tileT }}(xm[batchBase + u32(carriedAddress.{{ component }})]){% if not loop.last %},{% endif %}
|
| 245 |
+
{% endfor %}
|
| 246 |
+
);
|
| 247 |
+
carriedAddress = carriedAddress + vec4<i32>(colStep);
|
| 248 |
+
carriedKw = carriedKw + 1u;
|
| 249 |
+
if (carriedKw == CONV_KERNEL_W) {
|
| 250 |
+
carriedKw = 0u;
|
| 251 |
+
carriedAddress = carriedAddress - vec4<i32>(kwWrap);
|
| 252 |
+
carriedKh = carriedKh + 1u;
|
| 253 |
+
if (carriedKh == CONV_KERNEL_H) {
|
| 254 |
+
carriedKh = 0u;
|
| 255 |
+
carriedAddress = carriedAddress - vec4<i32>(khWrap);
|
| 256 |
+
}
|
| 257 |
+
}
|
| 258 |
+
}
|
| 259 |
+
} else {
|
| 260 |
+
for (var i = 0u; i < {{ implicitGatherLoadWidth }}u; i = i + 1u) {
|
| 261 |
+
var carriedValue = vec4<{{ tileT }}>({{ tileT }}(0.0));
|
| 262 |
+
let carriedRow = (batch * CONV_IN_CHANNELS + carriedIc) * CONV_IN_H;
|
| 263 |
+
let carriedOk = inColumn
|
| 264 |
+
& (carriedIh >= vec4<i32>(0)) & (carriedIh < vec4<i32>(i32(CONV_IN_H)))
|
| 265 |
+
& (carriedIw >= vec4<i32>(0)) & (carriedIw < vec4<i32>(i32(CONV_IN_W)));
|
| 266 |
+
if (carriedK < {{ rowLimit }}) {
|
| 267 |
+
{% for component in components %}
|
| 268 |
+
if (carriedOk.{{ component }}) {
|
| 269 |
+
carriedValue.{{ component }} = {{ tileT }}(xm[(carriedRow + u32(carriedIh.{{ component }})) * CONV_IN_W + u32(carriedIw.{{ component }})]);
|
| 270 |
+
}
|
| 271 |
+
{% endfor %}
|
| 272 |
+
}
|
| 273 |
+
tileB[bLocalK + i][bColVec] = carriedValue;
|
| 274 |
+
carriedK = carriedK + 1u;
|
| 275 |
+
carriedKw = carriedKw + 1u;
|
| 276 |
+
carriedIw = carriedIw + vec4<i32>(i32(CONV_DILATION_W));
|
| 277 |
+
if (carriedKw == CONV_KERNEL_W) {
|
| 278 |
+
carriedKw = 0u;
|
| 279 |
+
carriedIw = iw0;
|
| 280 |
+
carriedKh = carriedKh + 1u;
|
| 281 |
+
carriedIh = carriedIh + vec4<i32>(i32(CONV_DILATION_H));
|
| 282 |
+
if (carriedKh == CONV_KERNEL_H) {
|
| 283 |
+
carriedKh = 0u;
|
| 284 |
+
carriedIh = ih0;
|
| 285 |
+
carriedIc = carriedIc + 1u;
|
| 286 |
+
}
|
| 287 |
+
}
|
| 288 |
+
}
|
| 289 |
+
}
|
| 290 |
+
{%- endmacro %}
|
| 291 |
+
|
| 292 |
+
@compute @workgroup_size({{ GEMM_WG_X }}, {{ GEMM_WG_Y }}, 1)
|
| 293 |
+
fn main(
|
| 294 |
+
@builtin(workgroup_id) wg: vec3<u32>,
|
| 295 |
+
@builtin(local_invocation_id) lid: vec3<u32>
|
| 296 |
+
) {
|
| 297 |
+
let M = params.M;
|
| 298 |
+
let K = params.K;
|
| 299 |
+
let N = params.N;
|
| 300 |
+
let mBase = wg.y * BM;
|
| 301 |
+
let nBase = wg.x * BN;
|
| 302 |
+
let batch = wg.z;
|
| 303 |
+
{% if not implicitIm2col %}
|
| 304 |
+
let xBatchBase = batch * K * N;
|
| 305 |
+
{% endif %}
|
| 306 |
+
let li = lid.y * WG_X + lid.x;
|
| 307 |
+
|
| 308 |
+
// Explicit vectors give the backend fixed register indices and expose TM
|
| 309 |
+
// independent FMA chains.
|
| 310 |
+
{% for row in range(GEMM_TM) %}
|
| 311 |
+
var acc{{ row }} = vec{{ GEMM_TN }}<f32>(0.0);
|
| 312 |
+
{% endfor %}
|
| 313 |
+
|
| 314 |
+
let numTiles = (K + BK - 1u) / BK;
|
| 315 |
+
for (var kt: u32 = 0u; kt < numTiles; kt = kt + 1u) {
|
| 316 |
+
let kBase = kt * BK;
|
| 317 |
+
{{ load_a_vec4("mBase", "kBase", "M", gemmKLimit) }}
|
| 318 |
+
{% if useCarriedImplicitGather %}
|
| 319 |
+
{{ load_b_implicit_carried("kBase", "nBase", gemmKLimit, "N") }}
|
| 320 |
+
{% elif implicitIm2col %}
|
| 321 |
+
{{ load_b_implicit_vec4("kBase", "nBase", gemmKLimit, "N") }}
|
| 322 |
+
{% else %}
|
| 323 |
+
{{ load_b_vec4("kBase", "nBase", gemmKLimit, "N") }}
|
| 324 |
+
{% endif %}
|
| 325 |
+
workgroupBarrier();
|
| 326 |
+
// One iteration consumes four K steps: TM vector words of A and four of B
|
| 327 |
+
// cover TM x TN x 4 FMAs.
|
| 328 |
+
let aRow = lid.y * TM;
|
| 329 |
+
for (var kv: u32 = 0u; kv < AK_VECS; kv = kv + 1u) {
|
| 330 |
+
{% for row in range(GEMM_TM) %}
|
| 331 |
+
let av{{ row }} = vec4<f32>(tileA[aRow + {{ row }}u][kv]);
|
| 332 |
+
{% endfor %}
|
| 333 |
+
{% for sub in range(4) %}
|
| 334 |
+
let bv{{ sub }} = vec{{ GEMM_TN }}<f32>(tileB[kv * 4u + {{ sub }}u][lid.x]);
|
| 335 |
+
{% for row in range(GEMM_TM) %}
|
| 336 |
+
acc{{ row }} += vec{{ GEMM_TN }}<f32>(av{{ row }}.{{ components[sub] }}) * bv{{ sub }};
|
| 337 |
+
{% endfor %}
|
| 338 |
+
{% endfor %}
|
| 339 |
+
}
|
| 340 |
+
workgroupBarrier();
|
| 341 |
+
}
|
| 342 |
+
|
| 343 |
+
{% if not fusedNarrowProjection %}
|
| 344 |
+
let yBatchBase = batch * M * N;
|
| 345 |
+
{% endif %}
|
| 346 |
+
let m0 = mBase + lid.y * TM;
|
| 347 |
+
let n0 = nBase + lid.x * TN;
|
| 348 |
+
{% for row in range(GEMM_TM) %}
|
| 349 |
+
{% for column in range(GEMM_TN) %}
|
| 350 |
+
{% if fusedNarrowProjection %}
|
| 351 |
+
{{ publish_projection_input("lid.y * TM + " ~ row ~ "u", "lid.x * " ~ ((GEMM_TN / 4)|int) ~ "u + " ~ ((column / 4)|int) ~ "u", components[column % 4], "m0 + " ~ row ~ "u", "n0 + " ~ column ~ "u", "acc" ~ row ~ "." ~ components[column]) }}
|
| 352 |
+
{% else %}
|
| 353 |
+
store_out(m0 + {{ row }}u, n0 + {{ column }}u, yBatchBase, acc{{ row }}.{{ components[column] }});
|
| 354 |
+
{% endif %}
|
| 355 |
+
{% endfor %}
|
| 356 |
+
{% endfor %}{% if fusedNarrowProjection %}
|
| 357 |
+
|
| 358 |
+
// Conv's final K-tile barrier makes tileB dead before it becomes the
|
| 359 |
+
// intermediate tile. Every lane publishes its unique micro-tile, then one
|
| 360 |
+
// lane per spatial vector word consumes all logical M rows in increasing
|
| 361 |
+
// order, four adjacent columns at a time. Invalid M/N-tail cells are
|
| 362 |
+
// initialized above, so the barrier is uniform and no lane can observe a
|
| 363 |
+
// stale input-tile value.
|
| 364 |
+
workgroupBarrier();
|
| 365 |
+
if (li < BN_VECS) {
|
| 366 |
+
let projectionNBase = nBase + li * 4u;
|
| 367 |
+
{% for oc in range(projectionChannels) %}
|
| 368 |
+
var projectionAcc{{ oc }} = vec4<f32>(0.0);
|
| 369 |
+
{% endfor %}
|
| 370 |
+
for (var channel = 0u; channel < M; channel = channel + 1u) {
|
| 371 |
+
let projectionValues = vec4<f32>({{ narrowProjectionTile }}[channel][li]);
|
| 372 |
+
{% for oc in range(projectionChannels) %}
|
| 373 |
+
projectionAcc{{ oc }} = projectionAcc{{ oc }} + projectionValues * f32(projectionW[{{ oc }}u * M + channel]);
|
| 374 |
+
{% endfor %}
|
| 375 |
+
}
|
| 376 |
+
|
| 377 |
+
let projectionYBase = batch * PROJECTION_OUT_C * N;
|
| 378 |
+
{% for oc in range(projectionChannels) %}
|
| 379 |
+
let projected{{ oc }} = projectionAcc{{ oc }}{% if projectionBiased %} + vec4<f32>(f32(projectionBias[{{ oc }}u])){% endif %};
|
| 380 |
+
{% endfor %}
|
| 381 |
+
{% for column in range(4) %}
|
| 382 |
+
let projectionN{{ column }} = projectionNBase + {{ column }}u;
|
| 383 |
+
if (projectionN{{ column }} < N) {
|
| 384 |
+
{% for oc in range(projectionChannels) %}
|
| 385 |
+
{% if projectionOutputAct == "relu" %}
|
| 386 |
+
let activated{{ oc }}_{{ column }} = projection_relu(projected{{ oc }}.{{ components[column] }});
|
| 387 |
+
{% elif projectionOutputAct == "sigmoid" %}
|
| 388 |
+
let activated{{ oc }}_{{ column }} = sigmoid_safe(projected{{ oc }}.{{ components[column] }});
|
| 389 |
+
{% else %}
|
| 390 |
+
let activated{{ oc }}_{{ column }} = projected{{ oc }}.{{ components[column] }};
|
| 391 |
+
{% endif %}
|
| 392 |
+
{% if projectionScaled %}
|
| 393 |
+
y[projectionYBase + {{ oc }}u * N + projectionN{{ column }}] = activated{{ oc }}_{{ column }} * params.outputScale;
|
| 394 |
+
{% else %}
|
| 395 |
+
y[projectionYBase + {{ oc }}u * N + projectionN{{ column }}] = activated{{ oc }}_{{ column }};
|
| 396 |
+
{% endif %}
|
| 397 |
+
{% endfor %}
|
| 398 |
+
}
|
| 399 |
+
{% endfor %}
|
| 400 |
+
}
|
| 401 |
+
{% endif %}
|
| 402 |
+
}
|
build/webgpu/conv-1x1-gemm-tiled.wgsl.jinja
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// 1x1 Conv routed as a batched GEMM: Y[b] (M x N) = W (M x K) * X[b] (K x N)
|
| 2 |
+
// with M = outChannels, K = inChannels, N = H*W. For a 1x1 kernel with
|
| 3 |
+
// group == 1, stride 1, no padding, and dilation 1, the NCHW input is already
|
| 4 |
+
// the [K, N] matrix and the OIHW weight is already the [M, K] matrix — no
|
| 5 |
+
// data movement, only index arithmetic.
|
| 6 |
+
//
|
| 7 |
+
// Register-blocked 32x32 shared-memory tile (16x16 threads, each computes a 2x2
|
| 8 |
+
// micro-tile, with a selectable K tile (16 by default), the same structure as
|
| 9 |
+
// the general tiled matmul path — each shared element feeds 2 FMAs
|
| 10 |
+
// and a 32-wide column tile is staged once instead of re-reading W per output
|
| 11 |
+
// column. The weight matrix (A) is shared across the batch (no batch stride);
|
| 12 |
+
// the input (B) and output carry the batch offset via dispatch.z. f32
|
| 13 |
+
// accumulation, cast to the output element type on store; the optional bias is
|
| 14 |
+
// per output channel (M row), added after the full K accumulation per ONNX Conv
|
| 15 |
+
// semantics. f16 operands stay packed in workgroup memory and widen only when
|
| 16 |
+
// consumed. Fully bounds-checked (any M/N/K).
|
| 17 |
+
{% if usesF16 %}
|
| 18 |
+
enable f16;
|
| 19 |
+
{% endif %}
|
| 20 |
+
{{ env.wgsl.resourceDeclarations }}
|
| 21 |
+
{% set hasActivation = hasActivation is defined and hasActivation %}
|
| 22 |
+
{% if hasActivation %}
|
| 23 |
+
// Apply the fused activation in the f32 accumulator before the single output
|
| 24 |
+
// cast, avoiding an intermediate convolution tensor.
|
| 25 |
+
fn fused_act(v: f32) -> f32 {
|
| 26 |
+
return v * clamp(v * 0.16666666666666666 + 0.5, 0.0, 1.0);
|
| 27 |
+
}
|
| 28 |
+
{% endif %}
|
| 29 |
+
|
| 30 |
+
{% set tileT = "f16" if usesF16 else "f32" -%}
|
| 31 |
+
const BK: u32 = 16u;
|
| 32 |
+
const BM: u32 = 32u;
|
| 33 |
+
const BN: u32 = 32u;
|
| 34 |
+
|
| 35 |
+
// Store one output element with the optional bias/residual/activation epilogue in the
|
| 36 |
+
// f32 accumulator domain: Y = activation(conv + bias + Z).
|
| 37 |
+
fn store_out(m: u32, n: u32, yBase: u32, raw: f32) {
|
| 38 |
+
if (m >= params.M || n >= params.N) {
|
| 39 |
+
return;
|
| 40 |
+
}
|
| 41 |
+
var v = raw;
|
| 42 |
+
{% if hasBias %}
|
| 43 |
+
v = v + f32(bias[m]);
|
| 44 |
+
{% endif %}
|
| 45 |
+
{% if hasActivation %}
|
| 46 |
+
v = fused_act(v);
|
| 47 |
+
{% endif %}
|
| 48 |
+
y[yBase + m * params.N + n] = {{ T }}(v);
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
var<workgroup> tileA: array<array<{{ tileT }}, BK>, BM>;
|
| 53 |
+
var<workgroup> tileB: array<array<{{ tileT }}, BN>, BK>;
|
| 54 |
+
|
| 55 |
+
@compute @workgroup_size(16, 16, 1)
|
| 56 |
+
fn main(
|
| 57 |
+
@builtin(workgroup_id) wg: vec3<u32>,
|
| 58 |
+
@builtin(local_invocation_id) lid: vec3<u32>
|
| 59 |
+
) {
|
| 60 |
+
let M = params.M;
|
| 61 |
+
let K = params.K;
|
| 62 |
+
let N = params.N;
|
| 63 |
+
let mBase = wg.y * BM;
|
| 64 |
+
let nBase = wg.x * BN;
|
| 65 |
+
let batch = wg.z;
|
| 66 |
+
let xBatchBase = batch * K * N;
|
| 67 |
+
let li = lid.y * 16u + lid.x;
|
| 68 |
+
|
| 69 |
+
var acc00: f32 = 0.0;
|
| 70 |
+
var acc01: f32 = 0.0;
|
| 71 |
+
var acc10: f32 = 0.0;
|
| 72 |
+
var acc11: f32 = 0.0;
|
| 73 |
+
let numTiles = (K + BK - 1u) / BK;
|
| 74 |
+
for (var kt: u32 = 0u; kt < numTiles; kt = kt + 1u) {
|
| 75 |
+
let kBase = kt * BK;
|
| 76 |
+
// Cooperative load: 32x16 A(=W) tile + 16x32 B(=X[batch]) tile, 256 threads x 2 each.
|
| 77 |
+
for (var e: u32 = 0u; e < (BM * BK) / 256u; e = e + 1u) {
|
| 78 |
+
let idx = li + e * 256u;
|
| 79 |
+
let ar = idx / BK;
|
| 80 |
+
let ac = idx % BK;
|
| 81 |
+
let am = mBase + ar;
|
| 82 |
+
let ak = kBase + ac;
|
| 83 |
+
if (am < M && ak < K) {
|
| 84 |
+
tileA[ar][ac] = {{ tileT }}(w[am * K + ak]);
|
| 85 |
+
} else {
|
| 86 |
+
tileA[ar][ac] = {{ tileT }}(0.0);
|
| 87 |
+
}
|
| 88 |
+
let br = idx / BN;
|
| 89 |
+
let bc = idx % BN;
|
| 90 |
+
let bk = kBase + br;
|
| 91 |
+
let bn = nBase + bc;
|
| 92 |
+
if (bk < K && bn < N) {
|
| 93 |
+
tileB[br][bc] = {{ tileT }}(xm[xBatchBase + bk * N + bn]);
|
| 94 |
+
} else {
|
| 95 |
+
tileB[br][bc] = {{ tileT }}(0.0);
|
| 96 |
+
}
|
| 97 |
+
}
|
| 98 |
+
workgroupBarrier();
|
| 99 |
+
for (var kk: u32 = 0u; kk < BK; kk = kk + 1u) {
|
| 100 |
+
let a0 = f32(tileA[lid.y * 2u][kk]);
|
| 101 |
+
let a1 = f32(tileA[lid.y * 2u + 1u][kk]);
|
| 102 |
+
let b0 = f32(tileB[kk][lid.x * 2u]);
|
| 103 |
+
let b1 = f32(tileB[kk][lid.x * 2u + 1u]);
|
| 104 |
+
acc00 = acc00 + a0 * b0;
|
| 105 |
+
acc01 = acc01 + a0 * b1;
|
| 106 |
+
acc10 = acc10 + a1 * b0;
|
| 107 |
+
acc11 = acc11 + a1 * b1;
|
| 108 |
+
}
|
| 109 |
+
workgroupBarrier();
|
| 110 |
+
}
|
| 111 |
+
|
| 112 |
+
let m0 = mBase + lid.y * 2u;
|
| 113 |
+
let m1 = m0 + 1u;
|
| 114 |
+
let n0 = nBase + lid.x * 2u;
|
| 115 |
+
let n1 = n0 + 1u;
|
| 116 |
+
let yBatchBase = batch * M * N;
|
| 117 |
+
store_out(m0, n0, yBatchBase, acc00);
|
| 118 |
+
store_out(m0, n1, yBatchBase, acc01);
|
| 119 |
+
store_out(m1, n0, yBatchBase, acc10);
|
| 120 |
+
store_out(m1, n1, yBatchBase, acc11);
|
| 121 |
+
}
|
build/webgpu/conv-1x1-subgroup-matrix.wgsl.jinja
ADDED
|
@@ -0,0 +1,306 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Convolution as subgroup-matrix GEMM. OIHW weights form row-major [M,K]; `xm`
|
| 2 |
+
// is either an NCHW 1x1 view [K,N] or a materialized im2col matrix. Bias is
|
| 3 |
+
// applied per output channel after the full f32 accumulation.
|
| 4 |
+
//
|
| 5 |
+
// Full 8x8 matrix loads require complete K/N tiles. The aligned path enforces
|
| 6 |
+
// that geometry; `padded` zero-fills tails, and `implicitIm2col` gathers and
|
| 7 |
+
// zero-fills directly from NCHW without materializing the column matrix.
|
| 8 |
+
//
|
| 9 |
+
// `splitK` assigns disjoint K ranges to workgroup_id.z. Each slice writes raw
|
| 10 |
+
// sums to tile-padded [splitK,batch,M_PAD,N_PAD] scratch; a later pass combines
|
| 11 |
+
// the slices and applies bias or an epilogue. Padded tail cells remain zero and
|
| 12 |
+
// are never copied to the logical output.
|
| 13 |
+
{% set fusedNarrowProjection = fusedNarrowProjection if fusedNarrowProjection is defined else false %}
|
| 14 |
+
{% set polyphase = polyphaseConvTranspose is defined and polyphaseConvTranspose %}
|
| 15 |
+
{% set splitKValue = splitK if splitK is defined else 1 %}
|
| 16 |
+
{% set splitKPartial = splitKValue > 1 %}
|
| 17 |
+
{% set kLoopVar = "K_LOOP" if padded else "K" %}
|
| 18 |
+
{% set nColsVar = "N_COLS" if padded else "N" %}
|
| 19 |
+
{% if usesF16 %}
|
| 20 |
+
enable f16;
|
| 21 |
+
{% endif %}
|
| 22 |
+
enable subgroups;
|
| 23 |
+
{% if pinSubgroupSize32 %}
|
| 24 |
+
enable subgroup_size_control;
|
| 25 |
+
{% endif %}
|
| 26 |
+
enable chromium_experimental_subgroup_matrix;
|
| 27 |
+
diagnostic(off, chromium.subgroup_matrix_uniformity);
|
| 28 |
+
|
| 29 |
+
{{ env.wgsl.resourceDeclarations }}
|
| 30 |
+
|
| 31 |
+
{% set operandScalar = fScalar %}
|
| 32 |
+
{% set accScalar = "f32" %}
|
| 33 |
+
{% set useDirectMatrixStore = directMatrixStore is defined and directMatrixStore %}
|
| 34 |
+
{% set tileRowsValue = tileRows if tileRows is defined else 32 %}
|
| 35 |
+
{% set tileColsValue = tileCols if tileCols is defined else 64 %}
|
| 36 |
+
{% set workgroupThreadsValue = workgroupThreads if workgroupThreads is defined else 128 %}
|
| 37 |
+
{% set subgroupRowsValue = subgroupRows if subgroupRows is defined else 2 %}
|
| 38 |
+
{% set subgroupColsValue = subgroupCols if subgroupCols is defined else 2 %}
|
| 39 |
+
{% set subRowsValue = (tileRowsValue / subgroupRowsValue)|int %}
|
| 40 |
+
{% set subColsValue = (tileColsValue / subgroupColsValue)|int %}
|
| 41 |
+
{% set bLoadWidth = (tileColsValue * 32 / workgroupThreadsValue)|int %}
|
| 42 |
+
{% set bKChunks = (32 / bLoadWidth)|int %}
|
| 43 |
+
|
| 44 |
+
const M: u32 = {{ M }}u;
|
| 45 |
+
const K: u32 = {{ K }}u;
|
| 46 |
+
const N: u32 = {{ N }}u;
|
| 47 |
+
const B_BATCH_STRIDE: u32 = {{ kLoopVar }} * {{ nColsVar }};
|
| 48 |
+
{% if not splitKPartial and not polyphase and not fusedNarrowProjection %}
|
| 49 |
+
const C_BATCH_STRIDE: u32 = M * N;
|
| 50 |
+
{% endif %}
|
| 51 |
+
const TILE_COLS: u32 = {{ tileColsValue }}u;
|
| 52 |
+
const TILE_ROWS: u32 = {{ tileRowsValue }}u;
|
| 53 |
+
const TILE_K: u32 = 32u;
|
| 54 |
+
const SUB_COLS: u32 = {{ subColsValue }}u;
|
| 55 |
+
const SUB_ROWS: u32 = {{ subRowsValue }}u;
|
| 56 |
+
|
| 57 |
+
var<workgroup> tile_A: array<{{ operandScalar }}, {{ tileRowsValue }} * 32>;
|
| 58 |
+
var<workgroup> tile_B: array<{{ operandScalar }}, {{ tileColsValue }} * 32>;
|
| 59 |
+
{% if (not useDirectMatrixStore or padded) and not splitKPartial and not fusedNarrowProjection %}
|
| 60 |
+
var<workgroup> scratch: array<array<array<{{ accScalar }}, 64>, 4>, {{ (workgroupThreadsValue / 32)|int }}>;
|
| 61 |
+
|
| 62 |
+
{% endif %}
|
| 63 |
+
fn loadSHMA(tile_base: u32, k_idx: u32, row: u32, c_idx: u32) {
|
| 64 |
+
let a_global = tile_base + row;
|
| 65 |
+
let col = c_idx * 8u;
|
| 66 |
+
for (var col_offset = 0u; col_offset < 8u; col_offset = col_offset + 1u) {
|
| 67 |
+
let k = k_idx + col + col_offset;
|
| 68 |
+
if (a_global < M) {
|
| 69 |
+
{% set A_PHASE = "phase_base + " if polyphase else "" %}
|
| 70 |
+
{% if operandScalar == "f16" %}
|
| 71 |
+
tile_A[row * TILE_K + col + col_offset] = f16(w[{{ A_PHASE }}a_global * K + k]);
|
| 72 |
+
{% else %}
|
| 73 |
+
tile_A[row * TILE_K + col + col_offset] = f32(w[{{ A_PHASE }}a_global * K + k]);
|
| 74 |
+
{% endif %}
|
| 75 |
+
} else {
|
| 76 |
+
{% if operandScalar == "f16" %}
|
| 77 |
+
tile_A[row * TILE_K + col + col_offset] = 0.0h;
|
| 78 |
+
{% else %}
|
| 79 |
+
tile_A[row * TILE_K + col + col_offset] = 0.0;
|
| 80 |
+
{% endif %}
|
| 81 |
+
}
|
| 82 |
+
}
|
| 83 |
+
}
|
| 84 |
+
|
| 85 |
+
fn loadSHMB(b_base: u32, tile_base: u32, k_idx: u32, row: u32, c_idx: u32) {
|
| 86 |
+
let b_col = tile_base + row;
|
| 87 |
+
let col = c_idx * {{ bLoadWidth }}u;
|
| 88 |
+
for (var i = 0u; i < {{ bLoadWidth }}u; i = i + 1u) {
|
| 89 |
+
let k = k_idx + col + i;
|
| 90 |
+
{% if operandScalar == "f16" %}
|
| 91 |
+
tile_B[row * TILE_K + col + i] = f16(xm[b_base + k * {{ nColsVar }} + b_col]);
|
| 92 |
+
{% else %}
|
| 93 |
+
tile_B[row * TILE_K + col + i] = f32(xm[b_base + k * {{ nColsVar }} + b_col]);
|
| 94 |
+
{% endif %}
|
| 95 |
+
}
|
| 96 |
+
}
|
| 97 |
+
|
| 98 |
+
{% set hasActivation = hasActivation is defined and hasActivation %}
|
| 99 |
+
{% if hasActivation %}
|
| 100 |
+
// Apply the fused activation in the f32 accumulator before the single output
|
| 101 |
+
// cast, avoiding an intermediate convolution tensor.
|
| 102 |
+
fn fused_act(v: f32) -> f32 {
|
| 103 |
+
return v * clamp(v * 0.16666666666666666 + 0.5, 0.0, 1.0);
|
| 104 |
+
}
|
| 105 |
+
{% endif %}
|
| 106 |
+
|
| 107 |
+
{% set biasAdd = " + bv" if hasBias else "" %}
|
| 108 |
+
{% if hasActivation or hasZ %}
|
| 109 |
+
// Fused epilogue: Y = activation(conv + bias + Z), applied at the output store.
|
| 110 |
+
// `raw` is the f32 convolution-plus-bias accumulator; Z shares Y's NCHW layout.
|
| 111 |
+
fn epi(raw: f32) -> {{ T }} {
|
| 112 |
+
var r = raw;
|
| 113 |
+
{% if hasActivation %}
|
| 114 |
+
r = fused_act(r);
|
| 115 |
+
{% endif %}
|
| 116 |
+
return {{ T }}(r);
|
| 117 |
+
}
|
| 118 |
+
{% endif %}
|
| 119 |
+
{% macro store_val(valExpr, idxExpr) %}
|
| 120 |
+
{% if hasActivation or hasZ %}epi({{ valExpr }})
|
| 121 |
+
{%- else %}{{ T }}({{ valExpr }})
|
| 122 |
+
{%- endif %}
|
| 123 |
+
{% endmacro %}
|
| 124 |
+
|
| 125 |
+
{% if (not useDirectMatrixStore or padded) and not splitKPartial and not fusedNarrowProjection %}
|
| 126 |
+
fn storeOutput(offset: u32, {% if hasBias or polyphase %}row_base: u32, {% endif %}row: u32, col: u32, src_slot: u32, row_limit: i32) {
|
| 127 |
+
if (row_limit > 0 && row < u32(row_limit)) {
|
| 128 |
+
let col2 = col + 1u;
|
| 129 |
+
{% if hasBias %}
|
| 130 |
+
let bv = {{ accScalar }}(bias[row_base + row]);
|
| 131 |
+
{% endif %}
|
| 132 |
+
y[offset + row * N + col] = {{ store_val("scratch[src_slot][0][row * 8u + col]" ~ biasAdd, "offset + row * N + col") }};
|
| 133 |
+
y[offset + row * N + col + 8u] = {{ store_val("scratch[src_slot][1][row * 8u + col]" ~ biasAdd, "offset + row * N + col + 8u") }};
|
| 134 |
+
y[offset + row * N + col + 16u] = {{ store_val("scratch[src_slot][2][row * 8u + col]" ~ biasAdd, "offset + row * N + col + 16u") }};
|
| 135 |
+
y[offset + row * N + col + 24u] = {{ store_val("scratch[src_slot][3][row * 8u + col]" ~ biasAdd, "offset + row * N + col + 24u") }};
|
| 136 |
+
|
| 137 |
+
y[offset + row * N + col2] = {{ store_val("scratch[src_slot][0][row * 8u + col2]" ~ biasAdd, "offset + row * N + col2") }};
|
| 138 |
+
y[offset + row * N + col2 + 8u] = {{ store_val("scratch[src_slot][1][row * 8u + col2]" ~ biasAdd, "offset + row * N + col2 + 8u") }};
|
| 139 |
+
y[offset + row * N + col2 + 16u] = {{ store_val("scratch[src_slot][2][row * 8u + col2]" ~ biasAdd, "offset + row * N + col2 + 16u") }};
|
| 140 |
+
y[offset + row * N + col2 + 24u] = {{ store_val("scratch[src_slot][3][row * 8u + col2]" ~ biasAdd, "offset + row * N + col2 + 24u") }};
|
| 141 |
+
}
|
| 142 |
+
}
|
| 143 |
+
|
| 144 |
+
{% endif %}
|
| 145 |
+
@compute @workgroup_size({{ workgroupThreadsValue }}, 1, 1){{ " @subgroup_size(32)" if pinSubgroupSize32 else "" }}
|
| 146 |
+
fn main(
|
| 147 |
+
@builtin(workgroup_id) workgroup_id: vec3<u32>,
|
| 148 |
+
@builtin(local_invocation_index) local_idx: u32,
|
| 149 |
+
{% if (not useDirectMatrixStore or padded) and not splitKPartial and not fusedNarrowProjection %}
|
| 150 |
+
@builtin(subgroup_invocation_id) sg_id: u32,
|
| 151 |
+
{% endif %}
|
| 152 |
+
@builtin(subgroup_size) sg_size: u32
|
| 153 |
+
) {
|
| 154 |
+
let batch = workgroup_id.z;
|
| 155 |
+
let b_base = batch * B_BATCH_STRIDE;
|
| 156 |
+
{% if not fusedNarrowProjection %}
|
| 157 |
+
let c_base = batch * C_BATCH_STRIDE;
|
| 158 |
+
{% endif %}
|
| 159 |
+
let a_global_base = workgroup_id.y * TILE_ROWS;
|
| 160 |
+
let b_global_base = workgroup_id.x * TILE_COLS;
|
| 161 |
+
let subtile_id = local_idx / sg_size;
|
| 162 |
+
let subtile_idx = subtile_id / {{ subgroupRowsValue }}u;
|
| 163 |
+
let subtile_idy = subtile_id % {{ subgroupRowsValue }}u;
|
| 164 |
+
let base_A = subtile_idy * SUB_ROWS;
|
| 165 |
+
let base_B = subtile_idx * SUB_COLS;
|
| 166 |
+
|
| 167 |
+
var matC00: subgroup_matrix_result<{{ accScalar }}, 8, 8>;
|
| 168 |
+
var matC01: subgroup_matrix_result<{{ accScalar }}, 8, 8>;
|
| 169 |
+
var matC02: subgroup_matrix_result<{{ accScalar }}, 8, 8>;
|
| 170 |
+
var matC03: subgroup_matrix_result<{{ accScalar }}, 8, 8>;
|
| 171 |
+
var matC10: subgroup_matrix_result<{{ accScalar }}, 8, 8>;
|
| 172 |
+
var matC11: subgroup_matrix_result<{{ accScalar }}, 8, 8>;
|
| 173 |
+
var matC12: subgroup_matrix_result<{{ accScalar }}, 8, 8>;
|
| 174 |
+
var matC13: subgroup_matrix_result<{{ accScalar }}, 8, 8>;
|
| 175 |
+
|
| 176 |
+
for (var kidx = 0u; kidx < {{ kLoopVar }}; kidx = kidx + TILE_K) {
|
| 177 |
+
loadSHMA(a_global_base, kidx, local_idx / 4u, local_idx % 4u);
|
| 178 |
+
loadSHMB(b_base, b_global_base, kidx, local_idx / {{ bKChunks }}u, local_idx % {{ bKChunks }}u);
|
| 179 |
+
workgroupBarrier();
|
| 180 |
+
|
| 181 |
+
for (var step = 0u; step < TILE_K; step = step + 8u) {
|
| 182 |
+
let matrix_a_offset = subtile_idy * SUB_ROWS * TILE_K + step;
|
| 183 |
+
var matA0: subgroup_matrix_left<{{ operandScalar }}, 8, 8> = subgroupMatrixLoad<subgroup_matrix_left<{{ operandScalar }}, 8, 8>>(&tile_A, matrix_a_offset, false, TILE_K);
|
| 184 |
+
var matA1: subgroup_matrix_left<{{ operandScalar }}, 8, 8> = subgroupMatrixLoad<subgroup_matrix_left<{{ operandScalar }}, 8, 8>>(&tile_A, matrix_a_offset + 8u * TILE_K, false, TILE_K);
|
| 185 |
+
|
| 186 |
+
let matrix_b_offset = subtile_idx * SUB_COLS * TILE_K + step;
|
| 187 |
+
var matB0: subgroup_matrix_right<{{ operandScalar }}, 8, 8> = subgroupMatrixLoad<subgroup_matrix_right<{{ operandScalar }}, 8, 8>>(&tile_B, matrix_b_offset, true, TILE_K);
|
| 188 |
+
var matB1: subgroup_matrix_right<{{ operandScalar }}, 8, 8> = subgroupMatrixLoad<subgroup_matrix_right<{{ operandScalar }}, 8, 8>>(&tile_B, matrix_b_offset + 8u * TILE_K, true, TILE_K);
|
| 189 |
+
var matB2: subgroup_matrix_right<{{ operandScalar }}, 8, 8> = subgroupMatrixLoad<subgroup_matrix_right<{{ operandScalar }}, 8, 8>>(&tile_B, matrix_b_offset + 16u * TILE_K, true, TILE_K);
|
| 190 |
+
var matB3: subgroup_matrix_right<{{ operandScalar }}, 8, 8> = subgroupMatrixLoad<subgroup_matrix_right<{{ operandScalar }}, 8, 8>>(&tile_B, matrix_b_offset + 24u * TILE_K, true, TILE_K);
|
| 191 |
+
|
| 192 |
+
matC00 = subgroupMatrixMultiplyAccumulate(matA0, matB0, matC00);
|
| 193 |
+
matC01 = subgroupMatrixMultiplyAccumulate(matA0, matB1, matC01);
|
| 194 |
+
matC02 = subgroupMatrixMultiplyAccumulate(matA0, matB2, matC02);
|
| 195 |
+
matC03 = subgroupMatrixMultiplyAccumulate(matA0, matB3, matC03);
|
| 196 |
+
matC10 = subgroupMatrixMultiplyAccumulate(matA1, matB0, matC10);
|
| 197 |
+
matC11 = subgroupMatrixMultiplyAccumulate(matA1, matB1, matC11);
|
| 198 |
+
matC12 = subgroupMatrixMultiplyAccumulate(matA1, matB2, matC12);
|
| 199 |
+
matC13 = subgroupMatrixMultiplyAccumulate(matA1, matB3, matC13);
|
| 200 |
+
}
|
| 201 |
+
workgroupBarrier();
|
| 202 |
+
}
|
| 203 |
+
|
| 204 |
+
{% if fusedNarrowProjection %}
|
| 205 |
+
// The Conv producer owns exactly one 32-row tile. Its input tile is dead after
|
| 206 |
+
// the final K iteration, so reuse those 32x64 f32 cells as the only
|
| 207 |
+
// cross-subgroup handoff into the narrow projection. All collective stores
|
| 208 |
+
// remain subgroup-uniform, and every fragment has a disjoint destination.
|
| 209 |
+
let fused_tile_offset = base_A * TILE_COLS + base_B;
|
| 210 |
+
subgroupMatrixStore(&tile_B, fused_tile_offset + 0u * TILE_COLS + 0u, matC00, false, TILE_COLS);
|
| 211 |
+
subgroupMatrixStore(&tile_B, fused_tile_offset + 0u * TILE_COLS + 8u, matC01, false, TILE_COLS);
|
| 212 |
+
subgroupMatrixStore(&tile_B, fused_tile_offset + 0u * TILE_COLS + 16u, matC02, false, TILE_COLS);
|
| 213 |
+
subgroupMatrixStore(&tile_B, fused_tile_offset + 0u * TILE_COLS + 24u, matC03, false, TILE_COLS);
|
| 214 |
+
subgroupMatrixStore(&tile_B, fused_tile_offset + 8u * TILE_COLS + 0u, matC10, false, TILE_COLS);
|
| 215 |
+
subgroupMatrixStore(&tile_B, fused_tile_offset + 8u * TILE_COLS + 8u, matC11, false, TILE_COLS);
|
| 216 |
+
subgroupMatrixStore(&tile_B, fused_tile_offset + 8u * TILE_COLS + 16u, matC12, false, TILE_COLS);
|
| 217 |
+
subgroupMatrixStore(&tile_B, fused_tile_offset + 8u * TILE_COLS + 24u, matC13, false, TILE_COLS);
|
| 218 |
+
workgroupBarrier();
|
| 219 |
+
|
| 220 |
+
// One invocation owns one spatial column and walks the producer channels in
|
| 221 |
+
// increasing order to preserve the scalar projection's accumulation order.
|
| 222 |
+
// The inactive half of the workgroup has no remaining collective operation
|
| 223 |
+
// to reach.
|
| 224 |
+
let fused_global_col = b_global_base + local_idx;
|
| 225 |
+
if (local_idx < TILE_COLS && fused_global_col < N) {
|
| 226 |
+
{% for oc in range(projectionOutChannels) %}
|
| 227 |
+
var projected_acc{{ oc }} = f32(0.0);
|
| 228 |
+
{% endfor %}
|
| 229 |
+
for (var channel = 0u; channel < M; channel = channel + 1u) {
|
| 230 |
+
let producer_value = tile_B[channel * TILE_COLS + local_idx]{% if hasBias %} + f32(bias[channel]){% endif %};
|
| 231 |
+
let activated_value = producer_value;
|
| 232 |
+
{% for oc in range(projectionOutChannels) %}
|
| 233 |
+
projected_acc{{ oc }} = projected_acc{{ oc }} + activated_value * f32(projectionW[{{ oc }}u * M + channel]);
|
| 234 |
+
{% endfor %}
|
| 235 |
+
}
|
| 236 |
+
|
| 237 |
+
let fused_y_base = batch * {{ projectionOutChannels }}u * N + fused_global_col;
|
| 238 |
+
{% for oc in range(projectionOutChannels) %}
|
| 239 |
+
let projected{{ oc }} = projected_acc{{ oc }};
|
| 240 |
+
let activated{{ oc }} = projected{{ oc }};
|
| 241 |
+
y[fused_y_base + {{ oc }}u * N] = activated{{ oc }};
|
| 242 |
+
{% endfor %}
|
| 243 |
+
}
|
| 244 |
+
{% elif useDirectMatrixStore %}
|
| 245 |
+
// Full f32 output tiles can be published by the subgroup-matrix collectives
|
| 246 |
+
// directly. With no epilogue this removes scratch traffic and three barriers.
|
| 247 |
+
// When an epilogue is present, publish the raw accumulators first, then apply
|
| 248 |
+
// bias, residual Z, and activation cooperatively after one storage barrier.
|
| 249 |
+
let matrix_c_offset = c_base + (a_global_base + base_A) * N + b_global_base + base_B;
|
| 250 |
+
subgroupMatrixStore(&y, matrix_c_offset + 0u * N + 0u, matC00, false, N);
|
| 251 |
+
subgroupMatrixStore(&y, matrix_c_offset + 0u * N + 8u, matC01, false, N);
|
| 252 |
+
subgroupMatrixStore(&y, matrix_c_offset + 0u * N + 16u, matC02, false, N);
|
| 253 |
+
subgroupMatrixStore(&y, matrix_c_offset + 0u * N + 24u, matC03, false, N);
|
| 254 |
+
subgroupMatrixStore(&y, matrix_c_offset + 8u * N + 0u, matC10, false, N);
|
| 255 |
+
subgroupMatrixStore(&y, matrix_c_offset + 8u * N + 8u, matC11, false, N);
|
| 256 |
+
subgroupMatrixStore(&y, matrix_c_offset + 8u * N + 16u, matC12, false, N);
|
| 257 |
+
subgroupMatrixStore(&y, matrix_c_offset + 8u * N + 24u, matC13, false, N);
|
| 258 |
+
{% if hasBias or hasActivation or hasZ %}
|
| 259 |
+
storageBarrier();
|
| 260 |
+
for (var tile_idx = local_idx; tile_idx < TILE_ROWS * TILE_COLS; tile_idx += {{ workgroupThreadsValue }}u) {
|
| 261 |
+
let local_row = tile_idx / TILE_COLS;
|
| 262 |
+
let local_col = tile_idx % TILE_COLS;
|
| 263 |
+
let global_row = a_global_base + local_row;
|
| 264 |
+
let global_col = b_global_base + local_col;
|
| 265 |
+
let y_index = c_base + global_row * N + global_col;
|
| 266 |
+
var raw = f32(y[y_index]);
|
| 267 |
+
{% if hasBias %}
|
| 268 |
+
raw += f32(bias[global_row]);
|
| 269 |
+
{% endif %}
|
| 270 |
+
{% if hasActivation or hasZ %}
|
| 271 |
+
y[y_index] = epi(raw);
|
| 272 |
+
{% else %}
|
| 273 |
+
y[y_index] = {{ T }}(raw);
|
| 274 |
+
{% endif %}
|
| 275 |
+
}
|
| 276 |
+
{% endif %}
|
| 277 |
+
{% endif %}
|
| 278 |
+
{% if (not useDirectMatrixStore or padded) and not splitKPartial and not fusedNarrowProjection %}
|
| 279 |
+
// The four scratch banks are reused across the two row-groups, and each is written
|
| 280 |
+
// by a collective subgroupMatrixStore then read CROSS-LANE by storeOutput. Barriers
|
| 281 |
+
// give the reads visibility of the store AND stop the second row-group's store from
|
| 282 |
+
// clobbering the first's still-in-flight readback when a partial final M-tile
|
| 283 |
+
// diverges storeOutput's guard. Without both barriers the last valid row can be corrupted.
|
| 284 |
+
subgroupMatrixStore(&scratch[subtile_id][0], 0u, matC00, false, 8u);
|
| 285 |
+
subgroupMatrixStore(&scratch[subtile_id][1], 0u, matC01, false, 8u);
|
| 286 |
+
subgroupMatrixStore(&scratch[subtile_id][2], 0u, matC02, false, 8u);
|
| 287 |
+
subgroupMatrixStore(&scratch[subtile_id][3], 0u, matC03, false, 8u);
|
| 288 |
+
workgroupBarrier();
|
| 289 |
+
let row = sg_id / 4u;
|
| 290 |
+
let col = (sg_id % 4u) * 2u;
|
| 291 |
+
let row_base = a_global_base + base_A;
|
| 292 |
+
var matrix_c_offset = c_base + row_base * N + b_global_base + base_B;
|
| 293 |
+
var row_limit = i32(M) - i32(row_base);
|
| 294 |
+
storeOutput(matrix_c_offset, {% if hasBias or polyphase %}row_base, {% endif %}row, col, subtile_id, row_limit);
|
| 295 |
+
workgroupBarrier();
|
| 296 |
+
|
| 297 |
+
subgroupMatrixStore(&scratch[subtile_id][0], 0u, matC10, false, 8u);
|
| 298 |
+
subgroupMatrixStore(&scratch[subtile_id][1], 0u, matC11, false, 8u);
|
| 299 |
+
subgroupMatrixStore(&scratch[subtile_id][2], 0u, matC12, false, 8u);
|
| 300 |
+
subgroupMatrixStore(&scratch[subtile_id][3], 0u, matC13, false, 8u);
|
| 301 |
+
workgroupBarrier();
|
| 302 |
+
matrix_c_offset = matrix_c_offset + 8u * N;
|
| 303 |
+
row_limit = i32(M) - i32(row_base + 8u);
|
| 304 |
+
storeOutput(matrix_c_offset, {% if hasBias or polyphase %}row_base + 8u, {% endif %}row, col, subtile_id, row_limit);
|
| 305 |
+
{% endif %}
|
| 306 |
+
}
|
build/webgpu/conv-transpose-empty-input.wgsl.jinja
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{% macro flat_index_2d(name="i", bound="params.count", guardInline=false, note="dispatch-limit") %}
|
| 2 |
+
{% if note == "dispatch-limit" %}
|
| 3 |
+
// 2D-folded flat index: gid.y carries the high bits past the
|
| 4 |
+
// maxComputeWorkgroupsPerDimension dispatch limit (outputs > 16.7M elements).
|
| 5 |
+
{% elif note == "limit" %}
|
| 6 |
+
// 2D-folded flat index: gid.y carries the high bits past the
|
| 7 |
+
// maxComputeWorkgroupsPerDimension limit.
|
| 8 |
+
{% elif note == "device-axis" %}
|
| 9 |
+
// The flat dispatch is folded across x/y at the device's per-axis workgroup
|
| 10 |
+
// limit; gid.y carries the high portion of the output index.
|
| 11 |
+
{% elif note == "vec4-limit" %}
|
| 12 |
+
// 2D-folded flat vec4 index: gid.y carries the high bits past the
|
| 13 |
+
// maxComputeWorkgroupsPerDimension limit (the dispatch caps x and spills into y).
|
| 14 |
+
{% elif note == "element-limit" %}
|
| 15 |
+
// 2D-folded flat element index: gid.y carries the high bits past the
|
| 16 |
+
// maxComputeWorkgroupsPerDimension limit.
|
| 17 |
+
{% elif note == "dispatch" %}
|
| 18 |
+
// 2D-folded flat index: gid.y carries the high bits past the
|
| 19 |
+
// maxComputeWorkgroupsPerDimension dispatch limit.
|
| 20 |
+
{% endif %}
|
| 21 |
+
{% if bound == "" %}
|
| 22 |
+
let {{ name }} = gid.x + gid.y * nwg.x * {{ tunables.WORKGROUP_SIZE }}u;
|
| 23 |
+
{%- elif guardInline %}
|
| 24 |
+
let {{ name }} = gid.x + gid.y * nwg.x * {{ tunables.WORKGROUP_SIZE }}u;
|
| 25 |
+
if ({{ name }} >= {{ bound }}) { return; }
|
| 26 |
+
{%- else %}
|
| 27 |
+
let {{ name }} = gid.x + gid.y * nwg.x * {{ tunables.WORKGROUP_SIZE }}u;
|
| 28 |
+
if ({{ name }} >= {{ bound }}) {
|
| 29 |
+
return;
|
| 30 |
+
}
|
| 31 |
+
{%- endif %}
|
| 32 |
+
{% endmacro %}
|
| 33 |
+
|
| 34 |
+
{% if usesF16 %}
|
| 35 |
+
enable f16;
|
| 36 |
+
{% endif %}
|
| 37 |
+
{{ env.wgsl.resourceDeclarations }}
|
| 38 |
+
|
| 39 |
+
const COUNT: u32 = {{ source.count }}u;
|
| 40 |
+
{% if hasBias %}
|
| 41 |
+
const OUT_CHANNELS: u32 = {{ source.outChannels }}u;
|
| 42 |
+
const OUTPUT_SPATIAL: u32 = {{ source.outputSpatial }}u;
|
| 43 |
+
|
| 44 |
+
{% endif %}
|
| 45 |
+
// An empty contraction contributes the additive identity at every output
|
| 46 |
+
// coordinate. The optional ConvTranspose bias is applied after that reduction.
|
| 47 |
+
@compute @workgroup_size({{ tunables.WORKGROUP_SIZE }})
|
| 48 |
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>,
|
| 49 |
+
@builtin(num_workgroups) nwg: vec3<u32>) {
|
| 50 |
+
{{ flat_index_2d("index", "COUNT", note="device-axis") }}
|
| 51 |
+
{% if hasBias %}
|
| 52 |
+
let output_channel = (index / OUTPUT_SPATIAL) % OUT_CHANNELS;
|
| 53 |
+
y[index] = bias[output_channel];
|
| 54 |
+
{% else %}
|
| 55 |
+
y[index] = {{ T }}(0.0);
|
| 56 |
+
{% endif %}
|
| 57 |
+
}
|
build/webgpu/conv-transpose1d-ncl.wgsl.jinja
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{% macro flat_index_2d(name="i", bound="params.count", guardInline=false, note="dispatch-limit") %}
|
| 2 |
+
{% if note == "dispatch-limit" %}
|
| 3 |
+
// 2D-folded flat index: gid.y carries the high bits past the
|
| 4 |
+
// maxComputeWorkgroupsPerDimension dispatch limit (outputs > 16.7M elements).
|
| 5 |
+
{% elif note == "limit" %}
|
| 6 |
+
// 2D-folded flat index: gid.y carries the high bits past the
|
| 7 |
+
// maxComputeWorkgroupsPerDimension limit.
|
| 8 |
+
{% elif note == "device-axis" %}
|
| 9 |
+
// The flat dispatch is folded across x/y at the device's per-axis workgroup
|
| 10 |
+
// limit; gid.y carries the high portion of the output index.
|
| 11 |
+
{% elif note == "vec4-limit" %}
|
| 12 |
+
// 2D-folded flat vec4 index: gid.y carries the high bits past the
|
| 13 |
+
// maxComputeWorkgroupsPerDimension limit (the dispatch caps x and spills into y).
|
| 14 |
+
{% elif note == "element-limit" %}
|
| 15 |
+
// 2D-folded flat element index: gid.y carries the high bits past the
|
| 16 |
+
// maxComputeWorkgroupsPerDimension limit.
|
| 17 |
+
{% elif note == "dispatch" %}
|
| 18 |
+
// 2D-folded flat index: gid.y carries the high bits past the
|
| 19 |
+
// maxComputeWorkgroupsPerDimension dispatch limit.
|
| 20 |
+
{% endif %}
|
| 21 |
+
{% if bound == "" %}
|
| 22 |
+
let {{ name }} = gid.x + gid.y * nwg.x * {{ tunables.WORKGROUP_SIZE }}u;
|
| 23 |
+
{%- elif guardInline %}
|
| 24 |
+
let {{ name }} = gid.x + gid.y * nwg.x * {{ tunables.WORKGROUP_SIZE }}u;
|
| 25 |
+
if ({{ name }} >= {{ bound }}) { return; }
|
| 26 |
+
{%- else %}
|
| 27 |
+
let {{ name }} = gid.x + gid.y * nwg.x * {{ tunables.WORKGROUP_SIZE }}u;
|
| 28 |
+
if ({{ name }} >= {{ bound }}) {
|
| 29 |
+
return;
|
| 30 |
+
}
|
| 31 |
+
{%- endif %}
|
| 32 |
+
{% endmacro %}
|
| 33 |
+
|
| 34 |
+
{% macro tap(raw, coord, out, kernel, axis, indent) %}
|
| 35 |
+
{{ indent }}let {{ raw }} = i32({{ out }}) + params.pad{{ axis }} - i32({{ kernel }} * params.dilation{{ axis }});
|
| 36 |
+
{{ indent }}if ({{ raw }} < 0 || {{ raw }} % i32(params.stride{{ axis }}) != 0) { continue; }
|
| 37 |
+
{{ indent }}let {{ coord }} = {{ raw }} / i32(params.stride{{ axis }});
|
| 38 |
+
{{ indent }}if ({{ coord }} < 0 || {{ coord }} >= i32(params.in{{ axis }})) { continue; }
|
| 39 |
+
{%- endmacro -%}
|
| 40 |
+
{% if usesF16 %}
|
| 41 |
+
// Preserve f32 accumulation for the deep channel-by-kernel sum: widen each
|
| 42 |
+
// f16 product and narrow only once at the output store.
|
| 43 |
+
enable f16;
|
| 44 |
+
{% endif %}
|
| 45 |
+
{{ env.wgsl.resourceDeclarations }}
|
| 46 |
+
@compute @workgroup_size({{ tunables.WORKGROUP_SIZE }})
|
| 47 |
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>, @builtin(num_workgroups) nwg: vec3<u32>) {
|
| 48 |
+
{{ flat_index_2d("index", note="device-axis") }}
|
| 49 |
+
|
| 50 |
+
let ow = index % params.outW;
|
| 51 |
+
var t = index / params.outW;
|
| 52 |
+
let oc = t % params.outChannels;
|
| 53 |
+
let batch = t / params.outChannels;
|
| 54 |
+
{% if grouped %}
|
| 55 |
+
|
| 56 |
+
let groupIndex = oc / params.outChannelsPerGroup;
|
| 57 |
+
let localOc = oc - groupIndex * params.outChannelsPerGroup;
|
| 58 |
+
let inputStart = groupIndex * params.inChannelsPerGroup;
|
| 59 |
+
|
| 60 |
+
{% endif %}
|
| 61 |
+
var acc = 0.0;
|
| 62 |
+
{% if hasBias %}
|
| 63 |
+
{% if usesF16 %}
|
| 64 |
+
acc = f32(bias[oc]);
|
| 65 |
+
{% else %}
|
| 66 |
+
acc = bias[oc];
|
| 67 |
+
{% endif %}
|
| 68 |
+
{% endif %}
|
| 69 |
+
{% if grouped %}
|
| 70 |
+
for (var localIc = 0u; localIc < params.inChannelsPerGroup; localIc = localIc + 1u) {
|
| 71 |
+
let ic = inputStart + localIc;
|
| 72 |
+
for (var kw = 0u; kw < params.kernelW; kw = kw + 1u) {
|
| 73 |
+
{{ tap("rawW", "iw", "ow", "kw", "W", " ") }}
|
| 74 |
+
let xIndex = (batch * params.inChannels + ic) * params.inW + u32(iw);
|
| 75 |
+
let wIndex = (ic * params.outChannelsPerGroup + localOc) * params.kernelW + kw;
|
| 76 |
+
{% if usesF16 %}
|
| 77 |
+
acc = acc + f32(x[xIndex]) * f32(w[wIndex]);
|
| 78 |
+
{% else %}
|
| 79 |
+
acc = acc + x[xIndex] * w[wIndex];
|
| 80 |
+
{% endif %}
|
| 81 |
+
}
|
| 82 |
+
}
|
| 83 |
+
{% else %}
|
| 84 |
+
for (var ic = 0u; ic < params.inChannels; ic = ic + 1u) {
|
| 85 |
+
for (var kw = 0u; kw < params.kernelW; kw = kw + 1u) {
|
| 86 |
+
{{ tap("rawW", "iw", "ow", "kw", "W", " ") }}
|
| 87 |
+
let xIndex = (batch * params.inChannels + ic) * params.inW + u32(iw);
|
| 88 |
+
let wIndex = (ic * params.outChannels + oc) * params.kernelW + kw;
|
| 89 |
+
{% if usesF16 %}
|
| 90 |
+
acc = acc + f32(x[xIndex]) * f32(w[wIndex]);
|
| 91 |
+
{% else %}
|
| 92 |
+
acc = acc + x[xIndex] * w[wIndex];
|
| 93 |
+
{% endif %}
|
| 94 |
+
}
|
| 95 |
+
}
|
| 96 |
+
{% endif %}
|
| 97 |
+
{% if usesF16 %}
|
| 98 |
+
y[index] = f16(acc);
|
| 99 |
+
{% else %}
|
| 100 |
+
y[index] = acc;
|
| 101 |
+
{% endif %}
|
| 102 |
+
}
|
build/webgpu/conv-transpose1d-phase-tiled.wgsl.jinja
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{{ env.wgsl.resourceDeclarations }}
|
| 2 |
+
|
| 3 |
+
// Stride-2, k=4 transposed convolution decomposes into two dense phases per
|
| 4 |
+
// input position:
|
| 5 |
+
// y[2j] = x[j] W1 + x[j-1] W3
|
| 6 |
+
// y[2j+1] = x[j+1] W0 + x[j] W2
|
| 7 |
+
// A workgroup computes both phases for a tile of positions and output channels.
|
| 8 |
+
// Input samples and four-tap weight vectors are staged once per input-channel
|
| 9 |
+
// tile, so every staged value is reused across the tile's dot products.
|
| 10 |
+
const IN_CHANNELS: u32 = {{ source.inChannels }}u;
|
| 11 |
+
const IN_WIDTH: u32 = {{ source.inWidth }}u;
|
| 12 |
+
const OUT_CHANNELS: u32 = {{ source.outChannels }}u;
|
| 13 |
+
const POSITION_TILE: u32 = {{ source.positionTile }}u;
|
| 14 |
+
const OUTPUT_TILE: u32 = {{ source.outputTile }}u;
|
| 15 |
+
const OUTPUTS_PER_THREAD: u32 = {{ source.outputsPerThread }}u;
|
| 16 |
+
const OUTPUT_GROUPS: u32 = OUTPUT_TILE / OUTPUTS_PER_THREAD;
|
| 17 |
+
const K_TILE: u32 = {{ source.kTile }}u;
|
| 18 |
+
const WORKGROUP_SIZE: u32 = {{ source.workgroupSize }}u;
|
| 19 |
+
const INPUT_TILE_STRIDE: u32 = POSITION_TILE + 2u;
|
| 20 |
+
|
| 21 |
+
var<workgroup> tile_x: array<f32, {{ source.xTileElements }}>;
|
| 22 |
+
var<workgroup> tile_w: array<vec4<f32>, {{ source.weightTileElements }}>;
|
| 23 |
+
|
| 24 |
+
@compute @workgroup_size({{ source.workgroupSize }})
|
| 25 |
+
fn main(
|
| 26 |
+
@builtin(local_invocation_index) lane: u32,
|
| 27 |
+
@builtin(workgroup_id) wid: vec3<u32>
|
| 28 |
+
) {
|
| 29 |
+
let position_base = wid.x * POSITION_TILE;
|
| 30 |
+
let output_base = wid.y * OUTPUT_TILE;
|
| 31 |
+
let batch = wid.z;
|
| 32 |
+
let local_position = lane % POSITION_TILE;
|
| 33 |
+
let local_output_group = lane / POSITION_TILE;
|
| 34 |
+
let position = position_base + local_position;
|
| 35 |
+
{% for slot in range(source.outputsPerThread) %}
|
| 36 |
+
let output_channel_{{ slot }} = output_base + local_output_group + {{ slot }}u * OUTPUT_GROUPS;
|
| 37 |
+
let output_valid_{{ slot }} = position < IN_WIDTH && output_channel_{{ slot }} < OUT_CHANNELS;
|
| 38 |
+
var even_{{ slot }} = 0.0;
|
| 39 |
+
var odd_{{ slot }} = 0.0;
|
| 40 |
+
{% if hasBias %}
|
| 41 |
+
if (output_channel_{{ slot }} < OUT_CHANNELS) {
|
| 42 |
+
even_{{ slot }} = bias[output_channel_{{ slot }}];
|
| 43 |
+
odd_{{ slot }} = even_{{ slot }};
|
| 44 |
+
}
|
| 45 |
+
{% endif %}
|
| 46 |
+
{% endfor %}
|
| 47 |
+
|
| 48 |
+
for (var k_base = 0u; k_base < IN_CHANNELS; k_base += K_TILE) {
|
| 49 |
+
for (var load_index = lane; load_index < {{ source.xTileElements }}u; load_index += WORKGROUP_SIZE) {
|
| 50 |
+
let local_k = load_index / INPUT_TILE_STRIDE;
|
| 51 |
+
let halo_position = load_index - local_k * INPUT_TILE_STRIDE;
|
| 52 |
+
let input_channel = k_base + local_k;
|
| 53 |
+
let input_position = i32(position_base + halo_position) - 1;
|
| 54 |
+
var value = 0.0;
|
| 55 |
+
if (input_channel < IN_CHANNELS && input_position >= 0 && input_position < i32(IN_WIDTH)) {
|
| 56 |
+
let input_index = (batch * IN_CHANNELS + input_channel) * IN_WIDTH + u32(input_position);
|
| 57 |
+
value = x[input_index];
|
| 58 |
+
}
|
| 59 |
+
tile_x[load_index] = value;
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
for (var load_index = lane; load_index < {{ source.weightTileElements }}u; load_index += WORKGROUP_SIZE) {
|
| 63 |
+
let local_k = load_index / OUTPUT_TILE;
|
| 64 |
+
let local_oc = load_index - local_k * OUTPUT_TILE;
|
| 65 |
+
let input_channel = k_base + local_k;
|
| 66 |
+
let oc = output_base + local_oc;
|
| 67 |
+
var value = vec4<f32>(0.0);
|
| 68 |
+
if (input_channel < IN_CHANNELS && oc < OUT_CHANNELS) {
|
| 69 |
+
value = w[input_channel * OUT_CHANNELS + oc];
|
| 70 |
+
}
|
| 71 |
+
tile_w[load_index] = value;
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
workgroupBarrier();
|
| 75 |
+
if (position < IN_WIDTH) {
|
| 76 |
+
for (var local_k = 0u; local_k < K_TILE; local_k += 1u) {
|
| 77 |
+
let x_base = local_k * INPUT_TILE_STRIDE + local_position;
|
| 78 |
+
let previous = tile_x[x_base];
|
| 79 |
+
let center = tile_x[x_base + 1u];
|
| 80 |
+
let next = tile_x[x_base + 2u];
|
| 81 |
+
{% for slot in range(source.outputsPerThread) %}
|
| 82 |
+
if (output_channel_{{ slot }} < OUT_CHANNELS) {
|
| 83 |
+
let weights_{{ slot }} = tile_w[local_k * OUTPUT_TILE + local_output_group + {{ slot }}u * OUTPUT_GROUPS];
|
| 84 |
+
even_{{ slot }} = fma(center, weights_{{ slot }}.y, even_{{ slot }});
|
| 85 |
+
even_{{ slot }} = fma(previous, weights_{{ slot }}.w, even_{{ slot }});
|
| 86 |
+
odd_{{ slot }} = fma(next, weights_{{ slot }}.x, odd_{{ slot }});
|
| 87 |
+
odd_{{ slot }} = fma(center, weights_{{ slot }}.z, odd_{{ slot }});
|
| 88 |
+
}
|
| 89 |
+
{% endfor %}
|
| 90 |
+
}
|
| 91 |
+
}
|
| 92 |
+
workgroupBarrier();
|
| 93 |
+
}
|
| 94 |
+
|
| 95 |
+
{% for slot in range(source.outputsPerThread) %}
|
| 96 |
+
if (output_valid_{{ slot }}) {
|
| 97 |
+
// The output width is exactly 2*IN_WIDTH, so one vec2 owns both phases.
|
| 98 |
+
let output_index_{{ slot }} = (batch * OUT_CHANNELS + output_channel_{{ slot }}) * IN_WIDTH + position;
|
| 99 |
+
y[output_index_{{ slot }}] = vec2<f32>(even_{{ slot }}, odd_{{ slot }});
|
| 100 |
+
}
|
| 101 |
+
{% endfor %}
|
| 102 |
+
}
|
build/webgpu/conv-transpose2d-col2im.wgsl.jinja
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{% macro flat_index_2d(name="i", bound="params.count", guardInline=false, note="dispatch-limit") %}
|
| 2 |
+
{% if note == "dispatch-limit" %}
|
| 3 |
+
// 2D-folded flat index: gid.y carries the high bits past the
|
| 4 |
+
// maxComputeWorkgroupsPerDimension dispatch limit (outputs > 16.7M elements).
|
| 5 |
+
{% elif note == "limit" %}
|
| 6 |
+
// 2D-folded flat index: gid.y carries the high bits past the
|
| 7 |
+
// maxComputeWorkgroupsPerDimension limit.
|
| 8 |
+
{% elif note == "device-axis" %}
|
| 9 |
+
// The flat dispatch is folded across x/y at the device's per-axis workgroup
|
| 10 |
+
// limit; gid.y carries the high portion of the output index.
|
| 11 |
+
{% elif note == "vec4-limit" %}
|
| 12 |
+
// 2D-folded flat vec4 index: gid.y carries the high bits past the
|
| 13 |
+
// maxComputeWorkgroupsPerDimension limit (the dispatch caps x and spills into y).
|
| 14 |
+
{% elif note == "element-limit" %}
|
| 15 |
+
// 2D-folded flat element index: gid.y carries the high bits past the
|
| 16 |
+
// maxComputeWorkgroupsPerDimension limit.
|
| 17 |
+
{% elif note == "dispatch" %}
|
| 18 |
+
// 2D-folded flat index: gid.y carries the high bits past the
|
| 19 |
+
// maxComputeWorkgroupsPerDimension dispatch limit.
|
| 20 |
+
{% endif %}
|
| 21 |
+
{% if bound == "" %}
|
| 22 |
+
let {{ name }} = gid.x + gid.y * nwg.x * {{ tunables.WORKGROUP_SIZE }}u;
|
| 23 |
+
{%- elif guardInline %}
|
| 24 |
+
let {{ name }} = gid.x + gid.y * nwg.x * {{ tunables.WORKGROUP_SIZE }}u;
|
| 25 |
+
if ({{ name }} >= {{ bound }}) { return; }
|
| 26 |
+
{%- else %}
|
| 27 |
+
let {{ name }} = gid.x + gid.y * nwg.x * {{ tunables.WORKGROUP_SIZE }}u;
|
| 28 |
+
if ({{ name }} >= {{ bound }}) {
|
| 29 |
+
return;
|
| 30 |
+
}
|
| 31 |
+
{%- endif %}
|
| 32 |
+
{% endmacro %}
|
| 33 |
+
|
| 34 |
+
{% macro tap(raw, coord, out, kernel, axis, indent) %}
|
| 35 |
+
{{ indent }}let {{ raw }} = i32({{ out }}) + params.pad{{ axis }} - i32({{ kernel }} * params.dilation{{ axis }});
|
| 36 |
+
{{ indent }}if ({{ raw }} < 0 || {{ raw }} % i32(params.stride{{ axis }}) != 0) { continue; }
|
| 37 |
+
{{ indent }}let {{ coord }} = {{ raw }} / i32(params.stride{{ axis }});
|
| 38 |
+
{{ indent }}if ({{ coord }} < 0 || {{ coord }} >= i32(params.in{{ axis }})) { continue; }
|
| 39 |
+
{%- endmacro -%}
|
| 40 |
+
// ConvTranspose col2im scatter (output-stationary) for the im2col-GEMM path.
|
| 41 |
+
//
|
| 42 |
+
// The GEMM pass produced cols[m = (oc*KH+kh)*KW+kw, n = ih*IW+iw] = sum_ic
|
| 43 |
+
// Wt[m, ic] * X[ic, n], i.e. the per-tap partial products with the IC contraction
|
| 44 |
+
// already folded in. This pass reconstructs each output element by gathering the
|
| 45 |
+
// KH*KW taps that land on it — exactly the (oh,ow) -> (ih,iw) mapping the direct
|
| 46 |
+
// kernel uses, but reading the precomputed cols instead of re-running the IC sum.
|
| 47 |
+
// One thread per output element, f32 accumulation, deterministic (no atomics).
|
| 48 |
+
{% if usesF16 %}
|
| 49 |
+
enable f16;
|
| 50 |
+
|
| 51 |
+
{% endif %}
|
| 52 |
+
{{ env.wgsl.resourceDeclarations }}
|
| 53 |
+
@compute @workgroup_size({{ tunables.WORKGROUP_SIZE }})
|
| 54 |
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>, @builtin(num_workgroups) nwg: vec3<u32>) {
|
| 55 |
+
{{ flat_index_2d("index", note="") }}
|
| 56 |
+
|
| 57 |
+
let ow = index % params.outW;
|
| 58 |
+
var t = index / params.outW;
|
| 59 |
+
let oh = t % params.outH;
|
| 60 |
+
t = t / params.outH;
|
| 61 |
+
let oc = t % params.outChannels;
|
| 62 |
+
let batch = t / params.outChannels;
|
| 63 |
+
|
| 64 |
+
// cols is [M = OC*KH*KW, N = IH*IW] per batch image.
|
| 65 |
+
let cols_row_stride = params.inH * params.inW;
|
| 66 |
+
let cols_batch_stride = params.outChannels * params.kernelH * params.kernelW * cols_row_stride;
|
| 67 |
+
let b_base = batch * cols_batch_stride;
|
| 68 |
+
|
| 69 |
+
var acc = 0.0;
|
| 70 |
+
{% if hasBias %}
|
| 71 |
+
acc = f32(bias[oc]);
|
| 72 |
+
{% endif %}
|
| 73 |
+
{% if exactTiling is defined and exactTiling %}
|
| 74 |
+
// When kernel equals stride with no padding or dilation, the taps tile the
|
| 75 |
+
// output and exactly one (kh, kw) contributes to each element. Derive that
|
| 76 |
+
// tap directly; the output-shape contract keeps ih and iw in range.
|
| 77 |
+
let kh = oh % params.kernelH;
|
| 78 |
+
let ih = oh / params.kernelH;
|
| 79 |
+
let kw = ow % params.kernelW;
|
| 80 |
+
let iw = ow / params.kernelW;
|
| 81 |
+
let m = (oc * params.kernelH + kh) * params.kernelW + kw;
|
| 82 |
+
let n = ih * params.inW + iw;
|
| 83 |
+
acc = acc + f32(cols[b_base + m * cols_row_stride + n]);
|
| 84 |
+
{% else %}
|
| 85 |
+
for (var kh = 0u; kh < params.kernelH; kh = kh + 1u) {
|
| 86 |
+
{{ tap("raw_h", "ih", "oh", "kh", "H", " ") }}
|
| 87 |
+
for (var kw = 0u; kw < params.kernelW; kw = kw + 1u) {
|
| 88 |
+
{{ tap("raw_w", "iw", "ow", "kw", "W", " ") }}
|
| 89 |
+
let m = (oc * params.kernelH + kh) * params.kernelW + kw;
|
| 90 |
+
let n = u32(ih) * params.inW + u32(iw);
|
| 91 |
+
acc = acc + f32(cols[b_base + m * cols_row_stride + n]);
|
| 92 |
+
}
|
| 93 |
+
}
|
| 94 |
+
{% endif %}
|
| 95 |
+
y[index] = {{ T }}(acc);
|
| 96 |
+
}
|
build/webgpu/conv-transpose2d-grouped-stride-phase.wgsl.jinja
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{% if usesF16 %}
|
| 2 |
+
enable f16;
|
| 3 |
+
{% endif %}
|
| 4 |
+
{{ env.wgsl.resourceDeclarations }}
|
| 5 |
+
|
| 6 |
+
// With stride > 1 only one kernel phase contributes to a given output pixel.
|
| 7 |
+
// Start each kernel loop at that phase and advance by stride so it visits only
|
| 8 |
+
// contributing taps and needs no per-tap modulo or divisibility test.
|
| 9 |
+
const COUNT: u32 = {{ source.count }}u;
|
| 10 |
+
const OUT_C: u32 = {{ source.outC }}u;
|
| 11 |
+
const OUT_CPG: u32 = {{ source.outCPerGroup }}u;
|
| 12 |
+
const OUT_H: u32 = {{ source.outH }}u;
|
| 13 |
+
const OUT_W: u32 = {{ source.outW }}u;
|
| 14 |
+
const IN_C: u32 = {{ source.inC }}u;
|
| 15 |
+
const IN_CPG: u32 = {{ source.inCPerGroup }}u;
|
| 16 |
+
const IN_H: i32 = {{ source.inH }};
|
| 17 |
+
const IN_W: i32 = {{ source.inW }};
|
| 18 |
+
const IN_H_U: u32 = {{ source.inH }}u;
|
| 19 |
+
const IN_W_U: u32 = {{ source.inW }}u;
|
| 20 |
+
const KH: i32 = {{ source.kernelH }};
|
| 21 |
+
const KW: i32 = {{ source.kernelW }};
|
| 22 |
+
const STRIDE_H: i32 = {{ source.strideH }};
|
| 23 |
+
const STRIDE_W: i32 = {{ source.strideW }};
|
| 24 |
+
const PAD_H: i32 = {{ source.padH }};
|
| 25 |
+
const PAD_W: i32 = {{ source.padW }};
|
| 26 |
+
const WG: u32 = {{ tunables.WORKGROUP_SIZE }}u;
|
| 27 |
+
|
| 28 |
+
@compute @workgroup_size({{ tunables.WORKGROUP_SIZE }})
|
| 29 |
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>, @builtin(num_workgroups) nwg: vec3<u32>) {
|
| 30 |
+
let index = gid.x + gid.y * nwg.x * WG;
|
| 31 |
+
if (index >= COUNT) { return; }
|
| 32 |
+
let ow = index % OUT_W;
|
| 33 |
+
var t = index / OUT_W;
|
| 34 |
+
let oh = t % OUT_H;
|
| 35 |
+
t /= OUT_H;
|
| 36 |
+
let oc = t % OUT_C;
|
| 37 |
+
let batch = t / OUT_C;
|
| 38 |
+
let group = oc / OUT_CPG;
|
| 39 |
+
let localOc = oc - group * OUT_CPG;
|
| 40 |
+
let inputStart = group * IN_CPG;
|
| 41 |
+
let rawHBase = i32(oh) + PAD_H;
|
| 42 |
+
let rawWBase = i32(ow) + PAD_W;
|
| 43 |
+
let khPhase = rawHBase % STRIDE_H;
|
| 44 |
+
let kwPhase = rawWBase % STRIDE_W;
|
| 45 |
+
{% if source.hasBias %}
|
| 46 |
+
var acc = f32(bias[oc]);
|
| 47 |
+
{% else %}
|
| 48 |
+
var acc = 0.0;
|
| 49 |
+
{% endif %}
|
| 50 |
+
|
| 51 |
+
for (var localIc = 0u; localIc < IN_CPG; localIc++) {
|
| 52 |
+
let ic = inputStart + localIc;
|
| 53 |
+
for (var kh = khPhase; kh < KH; kh += STRIDE_H) {
|
| 54 |
+
let rawH = rawHBase - kh;
|
| 55 |
+
if (rawH < 0) { continue; }
|
| 56 |
+
let ih = rawH / STRIDE_H;
|
| 57 |
+
if (ih >= IN_H) { continue; }
|
| 58 |
+
for (var kw = kwPhase; kw < KW; kw += STRIDE_W) {
|
| 59 |
+
let rawW = rawWBase - kw;
|
| 60 |
+
if (rawW < 0) { continue; }
|
| 61 |
+
let iw = rawW / STRIDE_W;
|
| 62 |
+
if (iw >= IN_W) { continue; }
|
| 63 |
+
let xIndex = ((batch * IN_C + ic) * IN_H_U + u32(ih)) * IN_W_U + u32(iw);
|
| 64 |
+
let wIndex = ((ic * OUT_CPG + localOc) * u32(KH) + u32(kh)) * u32(KW) + u32(kw);
|
| 65 |
+
acc += f32(x[xIndex]) * f32(w[wIndex]);
|
| 66 |
+
}
|
| 67 |
+
}
|
| 68 |
+
}
|
| 69 |
+
y[index] = {{ scalar }}(acc);
|
| 70 |
+
}
|
build/webgpu/conv-transpose2d-nchw.wgsl.jinja
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{% macro flat_index_2d(name="i", bound="params.count", guardInline=false, note="dispatch-limit") %}
|
| 2 |
+
{% if note == "dispatch-limit" %}
|
| 3 |
+
// 2D-folded flat index: gid.y carries the high bits past the
|
| 4 |
+
// maxComputeWorkgroupsPerDimension dispatch limit (outputs > 16.7M elements).
|
| 5 |
+
{% elif note == "limit" %}
|
| 6 |
+
// 2D-folded flat index: gid.y carries the high bits past the
|
| 7 |
+
// maxComputeWorkgroupsPerDimension limit.
|
| 8 |
+
{% elif note == "device-axis" %}
|
| 9 |
+
// The flat dispatch is folded across x/y at the device's per-axis workgroup
|
| 10 |
+
// limit; gid.y carries the high portion of the output index.
|
| 11 |
+
{% elif note == "vec4-limit" %}
|
| 12 |
+
// 2D-folded flat vec4 index: gid.y carries the high bits past the
|
| 13 |
+
// maxComputeWorkgroupsPerDimension limit (the dispatch caps x and spills into y).
|
| 14 |
+
{% elif note == "element-limit" %}
|
| 15 |
+
// 2D-folded flat element index: gid.y carries the high bits past the
|
| 16 |
+
// maxComputeWorkgroupsPerDimension limit.
|
| 17 |
+
{% elif note == "dispatch" %}
|
| 18 |
+
// 2D-folded flat index: gid.y carries the high bits past the
|
| 19 |
+
// maxComputeWorkgroupsPerDimension dispatch limit.
|
| 20 |
+
{% endif %}
|
| 21 |
+
{% if bound == "" %}
|
| 22 |
+
let {{ name }} = gid.x + gid.y * nwg.x * {{ tunables.WORKGROUP_SIZE }}u;
|
| 23 |
+
{%- elif guardInline %}
|
| 24 |
+
let {{ name }} = gid.x + gid.y * nwg.x * {{ tunables.WORKGROUP_SIZE }}u;
|
| 25 |
+
if ({{ name }} >= {{ bound }}) { return; }
|
| 26 |
+
{%- else %}
|
| 27 |
+
let {{ name }} = gid.x + gid.y * nwg.x * {{ tunables.WORKGROUP_SIZE }}u;
|
| 28 |
+
if ({{ name }} >= {{ bound }}) {
|
| 29 |
+
return;
|
| 30 |
+
}
|
| 31 |
+
{%- endif %}
|
| 32 |
+
{% endmacro %}
|
| 33 |
+
|
| 34 |
+
{% macro tap(raw, coord, out, kernel, axis, indent) %}
|
| 35 |
+
{{ indent }}let {{ raw }} = i32({{ out }}) + params.pad{{ axis }} - i32({{ kernel }} * params.dilation{{ axis }});
|
| 36 |
+
{{ indent }}if ({{ raw }} < 0 || {{ raw }} % i32(params.stride{{ axis }}) != 0) { continue; }
|
| 37 |
+
{{ indent }}let {{ coord }} = {{ raw }} / i32(params.stride{{ axis }});
|
| 38 |
+
{{ indent }}if ({{ coord }} < 0 || {{ coord }} >= i32(params.in{{ axis }})) { continue; }
|
| 39 |
+
{%- endmacro -%}
|
| 40 |
+
{% if usesF16 %}
|
| 41 |
+
// Preserve f32 accumulation for the deep channel-by-kernel sum: widen each
|
| 42 |
+
// f16 product and narrow only once at the output store.
|
| 43 |
+
enable f16;
|
| 44 |
+
{% endif %}
|
| 45 |
+
{{ env.wgsl.resourceDeclarations }}
|
| 46 |
+
{% if depthwisePointwiseVec4 %}
|
| 47 |
+
@compute @workgroup_size({{ tunables.WORKGROUP_SIZE }})
|
| 48 |
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>, @builtin(num_workgroups) nwg: vec3<u32>) {
|
| 49 |
+
{{ flat_index_2d("vector_index", "", note="") }}
|
| 50 |
+
let base = vector_index * 4u;
|
| 51 |
+
if (base >= params.count) {
|
| 52 |
+
return;
|
| 53 |
+
}
|
| 54 |
+
|
| 55 |
+
// The contract guarantees a whole number of vec4s per NCHW channel plane,
|
| 56 |
+
// so these four adjacent values share one depthwise weight and never cross
|
| 57 |
+
// a channel boundary. This removes four copies of the generic coordinate,
|
| 58 |
+
// stride, padding, and kernel-loop arithmetic from the pointwise case.
|
| 59 |
+
let plane = params.outH * params.outW;
|
| 60 |
+
let oc = (base / plane) % params.outChannels;
|
| 61 |
+
let xv = vec4<f32>(x[base], x[base + 1u], x[base + 2u], x[base + 3u]);
|
| 62 |
+
let result = vec4<f32>(0.0) + xv * vec4<f32>(w[oc]);
|
| 63 |
+
y[base] = result.x;
|
| 64 |
+
y[base + 1u] = result.y;
|
| 65 |
+
y[base + 2u] = result.z;
|
| 66 |
+
y[base + 3u] = result.w;
|
| 67 |
+
}
|
| 68 |
+
{% else %}
|
| 69 |
+
@compute @workgroup_size({{ tunables.WORKGROUP_SIZE }})
|
| 70 |
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>, @builtin(num_workgroups) nwg: vec3<u32>) {
|
| 71 |
+
{{ flat_index_2d("index", note="device-axis") }}
|
| 72 |
+
|
| 73 |
+
let ow = index % params.outW;
|
| 74 |
+
var t = index / params.outW;
|
| 75 |
+
let oh = t % params.outH;
|
| 76 |
+
t = t / params.outH;
|
| 77 |
+
let oc = t % params.outChannels;
|
| 78 |
+
let batch = t / params.outChannels;
|
| 79 |
+
{% if grouped %}
|
| 80 |
+
|
| 81 |
+
let group_index = oc / params.outChannelsPerGroup;
|
| 82 |
+
let local_oc = oc - group_index * params.outChannelsPerGroup;
|
| 83 |
+
let input_start = group_index * params.inChannelsPerGroup;
|
| 84 |
+
|
| 85 |
+
{% endif %}
|
| 86 |
+
var acc = 0.0;
|
| 87 |
+
{% if hasBias %}
|
| 88 |
+
{% if usesF16 %}
|
| 89 |
+
acc = f32(bias[oc]);
|
| 90 |
+
{% else %}
|
| 91 |
+
acc = bias[oc];
|
| 92 |
+
{% endif %}
|
| 93 |
+
{% endif %}
|
| 94 |
+
{% if grouped %}
|
| 95 |
+
for (var local_ic = 0u; local_ic < params.inChannelsPerGroup; local_ic = local_ic + 1u) {
|
| 96 |
+
let ic = input_start + local_ic;
|
| 97 |
+
{% else %}
|
| 98 |
+
for (var ic = 0u; ic < params.inChannels; ic = ic + 1u) {
|
| 99 |
+
{% endif %}
|
| 100 |
+
for (var kh = 0u; kh < params.kernelH; kh = kh + 1u) {
|
| 101 |
+
{{ tap("raw_h", "ih", "oh", "kh", "H", " ") }}
|
| 102 |
+
for (var kw = 0u; kw < params.kernelW; kw = kw + 1u) {
|
| 103 |
+
{{ tap("raw_w", "iw", "ow", "kw", "W", " ") }}
|
| 104 |
+
let x_index = ((batch * params.inChannels + ic) * params.inH + u32(ih)) * params.inW + u32(iw);
|
| 105 |
+
{% if grouped %}
|
| 106 |
+
let w_index = ((ic * params.outChannelsPerGroup + local_oc) * params.kernelH + kh) * params.kernelW + kw;
|
| 107 |
+
{% else %}
|
| 108 |
+
let w_index = ((ic * params.outChannels + oc) * params.kernelH + kh) * params.kernelW + kw;
|
| 109 |
+
{% endif %}
|
| 110 |
+
{% if usesF16 %}
|
| 111 |
+
acc = acc + f32(x[x_index]) * f32(w[w_index]);
|
| 112 |
+
{% else %}
|
| 113 |
+
acc = acc + x[x_index] * w[w_index];
|
| 114 |
+
{% endif %}
|
| 115 |
+
}
|
| 116 |
+
}
|
| 117 |
+
}
|
| 118 |
+
{% if usesF16 %}
|
| 119 |
+
y[index] = f16(acc);
|
| 120 |
+
{% else %}
|
| 121 |
+
y[index] = acc;
|
| 122 |
+
{% endif %}
|
| 123 |
+
}
|
| 124 |
+
{% endif %}
|
build/webgpu/conv-transpose2d-phase-gemm-tiled.wgsl.jinja
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Fused k4s2 ConvTranspose for the common exact-2x upsampling geometry.
|
| 2 |
+
//
|
| 3 |
+
// A stride-two output has four independent parity phases. Within one phase,
|
| 4 |
+
// each output pixel receives exactly four kernel taps per input channel, so the
|
| 5 |
+
// operation is an implicit GEMM:
|
| 6 |
+
//
|
| 7 |
+
// Y_phase[OC, IH*IW] = W_phase[OC, IC*4] * X_neighborhood[IC*4, IH*IW]
|
| 8 |
+
//
|
| 9 |
+
// Materializing the conventional [OC*16, IH*IW] columns tensor costs one large
|
| 10 |
+
// scratch write, one large scratch read, and a second col2im dispatch. This
|
| 11 |
+
// kernel gathers the four shifted input samples while cooperatively loading the
|
| 12 |
+
// GEMM B tile, then stores each register tile directly to its interleaved output
|
| 13 |
+
// phase. Boundary samples are represented by zero in shared memory.
|
| 14 |
+
enable f16;
|
| 15 |
+
|
| 16 |
+
{{ env.wgsl.resourceDeclarations }}
|
| 17 |
+
|
| 18 |
+
const IN_C: u32 = {{ source.inChannels }}u;
|
| 19 |
+
const IN_H: u32 = {{ source.inHeight }}u;
|
| 20 |
+
const IN_W: u32 = {{ source.inWidth }}u;
|
| 21 |
+
const OUT_C: u32 = {{ source.outChannels }}u;
|
| 22 |
+
const OUT_H: u32 = {{ source.outHeight }}u;
|
| 23 |
+
const OUT_W: u32 = {{ source.outWidth }}u;
|
| 24 |
+
const BATCH: u32 = {{ source.batch }}u;
|
| 25 |
+
const PAD_H: u32 = {{ source.padH }}u;
|
| 26 |
+
const PAD_W: u32 = {{ source.padW }}u;
|
| 27 |
+
|
| 28 |
+
const PHASES: u32 = 4u;
|
| 29 |
+
const TAPS_PER_PHASE: u32 = 4u;
|
| 30 |
+
const PHASE_EDGE: u32 = 2u;
|
| 31 |
+
const N: u32 = IN_H * IN_W;
|
| 32 |
+
const K: u32 = IN_C * TAPS_PER_PHASE;
|
| 33 |
+
|
| 34 |
+
const M_TILE: u32 = {{ source.mTile }}u;
|
| 35 |
+
const N_TILE: u32 = {{ source.nTile }}u;
|
| 36 |
+
const BK: u32 = {{ source.kTile }}u;
|
| 37 |
+
const THREAD_ROWS: u32 = {{ source.threadRows }}u;
|
| 38 |
+
const THREAD_COLUMNS: u32 = {{ source.threadColumns }}u;
|
| 39 |
+
const WG_EDGE: u32 = {{ source.workgroupEdge }}u;
|
| 40 |
+
const WG_SIZE: u32 = WG_EDGE * WG_EDGE;
|
| 41 |
+
|
| 42 |
+
var<workgroup> tileA: array<array<f16, BK>, M_TILE>;
|
| 43 |
+
var<workgroup> tileB: array<array<f16, N_TILE>, BK>;
|
| 44 |
+
|
| 45 |
+
fn store_output(batch: u32, phase: u32, oc: u32, n: u32, value: f32) {
|
| 46 |
+
if (oc >= OUT_C || n >= N) {
|
| 47 |
+
return;
|
| 48 |
+
}
|
| 49 |
+
let phaseH = phase / PHASE_EDGE;
|
| 50 |
+
let phaseW = phase % PHASE_EDGE;
|
| 51 |
+
let oh = (n / IN_W) * PHASE_EDGE + phaseH;
|
| 52 |
+
let ow = (n % IN_W) * PHASE_EDGE + phaseW;
|
| 53 |
+
{% if source.hasBias %}
|
| 54 |
+
let result = value + f32(bias[oc]);
|
| 55 |
+
{% else %}
|
| 56 |
+
let result = value;
|
| 57 |
+
{% endif %}
|
| 58 |
+
y[((batch * OUT_C + oc) * OUT_H + oh) * OUT_W + ow] = f16(result);
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
@compute @workgroup_size({{ source.workgroupEdge }}, {{ source.workgroupEdge }}, 1)
|
| 62 |
+
fn main(
|
| 63 |
+
@builtin(workgroup_id) wg: vec3<u32>,
|
| 64 |
+
@builtin(local_invocation_id) lid: vec3<u32>
|
| 65 |
+
) {
|
| 66 |
+
let phase = wg.z % PHASES;
|
| 67 |
+
let batch = wg.z / PHASES;
|
| 68 |
+
if (batch >= BATCH) {
|
| 69 |
+
return;
|
| 70 |
+
}
|
| 71 |
+
|
| 72 |
+
let phaseH = phase / PHASE_EDGE;
|
| 73 |
+
let phaseW = phase % PHASE_EDGE;
|
| 74 |
+
let kernelPhaseH = (phaseH + PAD_H) % PHASE_EDGE;
|
| 75 |
+
let kernelPhaseW = (phaseW + PAD_W) % PHASE_EDGE;
|
| 76 |
+
let inputShiftH = (phaseH + PAD_H - kernelPhaseH) / PHASE_EDGE;
|
| 77 |
+
let inputShiftW = (phaseW + PAD_W - kernelPhaseW) / PHASE_EDGE;
|
| 78 |
+
|
| 79 |
+
let mBase = wg.y * M_TILE;
|
| 80 |
+
let nBase = wg.x * N_TILE;
|
| 81 |
+
let lane = lid.y * WG_EDGE + lid.x;
|
| 82 |
+
let aRow = lid.y * THREAD_ROWS;
|
| 83 |
+
let bCol = lid.x * THREAD_COLUMNS;
|
| 84 |
+
|
| 85 |
+
{% for r in range(source.threadRows) %}
|
| 86 |
+
var acc{{ r }} = vec4<f32>(0.0);
|
| 87 |
+
{% endfor %}
|
| 88 |
+
|
| 89 |
+
for (var kBase = 0u; kBase < K; kBase += BK) {
|
| 90 |
+
// The square A/B tiles contain the same number of values, so one loop
|
| 91 |
+
// publishes a coalesced share of both operands per lane.
|
| 92 |
+
for (var linear = lane; linear < M_TILE * BK; linear += WG_SIZE) {
|
| 93 |
+
let ar = linear / BK;
|
| 94 |
+
let ac = linear % BK;
|
| 95 |
+
let oc = mBase + ar;
|
| 96 |
+
let k = kBase + ac;
|
| 97 |
+
if (oc < OUT_C && k < K) {
|
| 98 |
+
let ic = k / TAPS_PER_PHASE;
|
| 99 |
+
let tap = k % TAPS_PER_PHASE;
|
| 100 |
+
let tapH = tap / PHASE_EDGE;
|
| 101 |
+
let tapW = tap % PHASE_EDGE;
|
| 102 |
+
let kh = kernelPhaseH + tapH * PHASE_EDGE;
|
| 103 |
+
let kw = kernelPhaseW + tapW * PHASE_EDGE;
|
| 104 |
+
let wIndex = ((ic * OUT_C + oc) * 4u + kh) * 4u + kw;
|
| 105 |
+
tileA[ar][ac] = w[wIndex];
|
| 106 |
+
} else {
|
| 107 |
+
tileA[ar][ac] = f16(0.0);
|
| 108 |
+
}
|
| 109 |
+
|
| 110 |
+
let br = linear / N_TILE;
|
| 111 |
+
let bc = linear % N_TILE;
|
| 112 |
+
let bk = kBase + br;
|
| 113 |
+
let n = nBase + bc;
|
| 114 |
+
if (bk < K && n < N) {
|
| 115 |
+
let ic = bk / TAPS_PER_PHASE;
|
| 116 |
+
let tap = bk % TAPS_PER_PHASE;
|
| 117 |
+
let tapH = tap / PHASE_EDGE;
|
| 118 |
+
let tapW = tap % PHASE_EDGE;
|
| 119 |
+
let ih = i32(n / IN_W) + i32(inputShiftH) - i32(tapH);
|
| 120 |
+
let iw = i32(n % IN_W) + i32(inputShiftW) - i32(tapW);
|
| 121 |
+
if (ih >= 0 && ih < i32(IN_H) && iw >= 0 && iw < i32(IN_W)) {
|
| 122 |
+
let xIndex = ((batch * IN_C + ic) * IN_H + u32(ih)) * IN_W + u32(iw);
|
| 123 |
+
tileB[br][bc] = x[xIndex];
|
| 124 |
+
} else {
|
| 125 |
+
tileB[br][bc] = f16(0.0);
|
| 126 |
+
}
|
| 127 |
+
} else {
|
| 128 |
+
tileB[br][bc] = f16(0.0);
|
| 129 |
+
}
|
| 130 |
+
}
|
| 131 |
+
workgroupBarrier();
|
| 132 |
+
|
| 133 |
+
for (var kk = 0u; kk < BK; kk++) {
|
| 134 |
+
let bv = vec4<f32>(
|
| 135 |
+
f32(tileB[kk][bCol]),
|
| 136 |
+
f32(tileB[kk][bCol + 1u]),
|
| 137 |
+
f32(tileB[kk][bCol + 2u]),
|
| 138 |
+
f32(tileB[kk][bCol + 3u])
|
| 139 |
+
);
|
| 140 |
+
{% for r in range(source.threadRows) %}
|
| 141 |
+
acc{{ r }} += vec4<f32>(f32(tileA[aRow + {{ r }}u][kk])) * bv;
|
| 142 |
+
{% endfor %}
|
| 143 |
+
}
|
| 144 |
+
workgroupBarrier();
|
| 145 |
+
}
|
| 146 |
+
|
| 147 |
+
let oc0 = mBase + aRow;
|
| 148 |
+
let n0 = nBase + bCol;
|
| 149 |
+
{% for r in range(source.threadRows) %}
|
| 150 |
+
store_output(batch, phase, oc0 + {{ r }}u, n0, acc{{ r }}.x);
|
| 151 |
+
store_output(batch, phase, oc0 + {{ r }}u, n0 + 1u, acc{{ r }}.y);
|
| 152 |
+
store_output(batch, phase, oc0 + {{ r }}u, n0 + 2u, acc{{ r }}.z);
|
| 153 |
+
store_output(batch, phase, oc0 + {{ r }}u, n0 + 3u, acc{{ r }}.w);
|
| 154 |
+
{% endfor %}
|
| 155 |
+
}
|
build/webgpu/conv-transpose2d-weight-reorder.wgsl.jinja
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{% macro flat_index_2d(name="i", bound="params.count", guardInline=false, note="dispatch-limit") %}
|
| 2 |
+
{% if note == "dispatch-limit" %}
|
| 3 |
+
// 2D-folded flat index: gid.y carries the high bits past the
|
| 4 |
+
// maxComputeWorkgroupsPerDimension dispatch limit (outputs > 16.7M elements).
|
| 5 |
+
{% elif note == "limit" %}
|
| 6 |
+
// 2D-folded flat index: gid.y carries the high bits past the
|
| 7 |
+
// maxComputeWorkgroupsPerDimension limit.
|
| 8 |
+
{% elif note == "device-axis" %}
|
| 9 |
+
// The flat dispatch is folded across x/y at the device's per-axis workgroup
|
| 10 |
+
// limit; gid.y carries the high portion of the output index.
|
| 11 |
+
{% elif note == "vec4-limit" %}
|
| 12 |
+
// 2D-folded flat vec4 index: gid.y carries the high bits past the
|
| 13 |
+
// maxComputeWorkgroupsPerDimension limit (the dispatch caps x and spills into y).
|
| 14 |
+
{% elif note == "element-limit" %}
|
| 15 |
+
// 2D-folded flat element index: gid.y carries the high bits past the
|
| 16 |
+
// maxComputeWorkgroupsPerDimension limit.
|
| 17 |
+
{% elif note == "dispatch" %}
|
| 18 |
+
// 2D-folded flat index: gid.y carries the high bits past the
|
| 19 |
+
// maxComputeWorkgroupsPerDimension dispatch limit.
|
| 20 |
+
{% endif %}
|
| 21 |
+
{% if bound == "" %}
|
| 22 |
+
let {{ name }} = gid.x + gid.y * nwg.x * {{ tunables.WORKGROUP_SIZE }}u;
|
| 23 |
+
{%- elif guardInline %}
|
| 24 |
+
let {{ name }} = gid.x + gid.y * nwg.x * {{ tunables.WORKGROUP_SIZE }}u;
|
| 25 |
+
if ({{ name }} >= {{ bound }}) { return; }
|
| 26 |
+
{%- else %}
|
| 27 |
+
let {{ name }} = gid.x + gid.y * nwg.x * {{ tunables.WORKGROUP_SIZE }}u;
|
| 28 |
+
if ({{ name }} >= {{ bound }}) {
|
| 29 |
+
return;
|
| 30 |
+
}
|
| 31 |
+
{%- endif %}
|
| 32 |
+
{% endmacro %}
|
| 33 |
+
|
| 34 |
+
// ConvTranspose weight reorder for the im2col-GEMM path.
|
| 35 |
+
//
|
| 36 |
+
// The ONNX ConvTranspose weight is laid out [IC, OC, KH, KW]. The GEMM that
|
| 37 |
+
// produces the cols matrix (cols[OC*KH*KW, IH*IW] = Wt @ X) needs its A operand
|
| 38 |
+
// as a row-major [M = OC*KH*KW, K = IC] matrix, i.e. the IC dimension contracted
|
| 39 |
+
// to the inner (column) axis. This pass gathers W into that transposed layout.
|
| 40 |
+
{% if usesF16 %}
|
| 41 |
+
enable f16;
|
| 42 |
+
|
| 43 |
+
{% endif %}
|
| 44 |
+
{{ env.wgsl.resourceDeclarations }}
|
| 45 |
+
@compute @workgroup_size({{ tunables.WORKGROUP_SIZE }})
|
| 46 |
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>, @builtin(num_workgroups) nwg: vec3<u32>) {
|
| 47 |
+
{{ flat_index_2d("index", note="") }}
|
| 48 |
+
// Wt[m, ic] with m = (oc * KH + kh) * KW + kw, contracted dim ic.
|
| 49 |
+
let ic = index % params.inChannels;
|
| 50 |
+
var m = index / params.inChannels;
|
| 51 |
+
let kw = m % params.kernelW;
|
| 52 |
+
m = m / params.kernelW;
|
| 53 |
+
let kh = m % params.kernelH;
|
| 54 |
+
let oc = m / params.kernelH;
|
| 55 |
+
let w_index = ((ic * params.outChannels + oc) * params.kernelH + kh) * params.kernelW + kw;
|
| 56 |
+
wt[index] = wsrc[w_index];
|
| 57 |
+
}
|
build/webgpu/conv-transpose3d-col2im.wgsl.jinja
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{% macro flat_index_2d(name="i", bound="params.count", guardInline=false, note="dispatch-limit") %}
|
| 2 |
+
{% if note == "dispatch-limit" %}
|
| 3 |
+
// 2D-folded flat index: gid.y carries the high bits past the
|
| 4 |
+
// maxComputeWorkgroupsPerDimension dispatch limit (outputs > 16.7M elements).
|
| 5 |
+
{% elif note == "limit" %}
|
| 6 |
+
// 2D-folded flat index: gid.y carries the high bits past the
|
| 7 |
+
// maxComputeWorkgroupsPerDimension limit.
|
| 8 |
+
{% elif note == "device-axis" %}
|
| 9 |
+
// The flat dispatch is folded across x/y at the device's per-axis workgroup
|
| 10 |
+
// limit; gid.y carries the high portion of the output index.
|
| 11 |
+
{% elif note == "vec4-limit" %}
|
| 12 |
+
// 2D-folded flat vec4 index: gid.y carries the high bits past the
|
| 13 |
+
// maxComputeWorkgroupsPerDimension limit (the dispatch caps x and spills into y).
|
| 14 |
+
{% elif note == "element-limit" %}
|
| 15 |
+
// 2D-folded flat element index: gid.y carries the high bits past the
|
| 16 |
+
// maxComputeWorkgroupsPerDimension limit.
|
| 17 |
+
{% elif note == "dispatch" %}
|
| 18 |
+
// 2D-folded flat index: gid.y carries the high bits past the
|
| 19 |
+
// maxComputeWorkgroupsPerDimension dispatch limit.
|
| 20 |
+
{% endif %}
|
| 21 |
+
{% if bound == "" %}
|
| 22 |
+
let {{ name }} = gid.x + gid.y * nwg.x * {{ tunables.WORKGROUP_SIZE }}u;
|
| 23 |
+
{%- elif guardInline %}
|
| 24 |
+
let {{ name }} = gid.x + gid.y * nwg.x * {{ tunables.WORKGROUP_SIZE }}u;
|
| 25 |
+
if ({{ name }} >= {{ bound }}) { return; }
|
| 26 |
+
{%- else %}
|
| 27 |
+
let {{ name }} = gid.x + gid.y * nwg.x * {{ tunables.WORKGROUP_SIZE }}u;
|
| 28 |
+
if ({{ name }} >= {{ bound }}) {
|
| 29 |
+
return;
|
| 30 |
+
}
|
| 31 |
+
{%- endif %}
|
| 32 |
+
{% endmacro %}
|
| 33 |
+
|
| 34 |
+
{% macro tap(raw, coord, out, kernel, axis, indent) %}
|
| 35 |
+
{{ indent }}let {{ raw }} = i32({{ out }}) + params.pad{{ axis }} - i32({{ kernel }} * params.dilation{{ axis }});
|
| 36 |
+
{{ indent }}if ({{ raw }} < 0 || {{ raw }} % i32(params.stride{{ axis }}) != 0) { continue; }
|
| 37 |
+
{{ indent }}let {{ coord }} = {{ raw }} / i32(params.stride{{ axis }});
|
| 38 |
+
{{ indent }}if ({{ coord }} < 0 || {{ coord }} >= i32(params.in{{ axis }})) { continue; }
|
| 39 |
+
{%- endmacro -%}
|
| 40 |
+
// Output-stationary rank-5 col2im gather for ConvTranspose-as-GEMM.
|
| 41 |
+
//
|
| 42 |
+
// GEMM has already contracted input channels into
|
| 43 |
+
// cols[oc,kd,kh,kw,id,ih,iw]. This pass gathers only the spatial taps that land
|
| 44 |
+
// on each output coordinate, retaining deterministic f32 accumulation and the
|
| 45 |
+
// full stride/dilation/padding contract without atomics.
|
| 46 |
+
{{ env.wgsl.resourceDeclarations }}
|
| 47 |
+
|
| 48 |
+
@compute @workgroup_size({{ tunables.WORKGROUP_SIZE }})
|
| 49 |
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>,
|
| 50 |
+
@builtin(num_workgroups) nwg: vec3<u32>) {
|
| 51 |
+
{{ flat_index_2d("index", note="device-axis") }}
|
| 52 |
+
|
| 53 |
+
let ow = index % params.outW;
|
| 54 |
+
var t = index / params.outW;
|
| 55 |
+
let oh = t % params.outH;
|
| 56 |
+
t /= params.outH;
|
| 57 |
+
let od = t % params.outD;
|
| 58 |
+
t /= params.outD;
|
| 59 |
+
let oc = t % params.outChannels;
|
| 60 |
+
let batch = t / params.outChannels;
|
| 61 |
+
|
| 62 |
+
let inputPlane = params.inH * params.inW;
|
| 63 |
+
let inputVolume = params.inD * inputPlane;
|
| 64 |
+
let kernelPlane = params.kernelH * params.kernelW;
|
| 65 |
+
let kernelVolume = params.kernelD * kernelPlane;
|
| 66 |
+
let colsBatchStride = params.outChannels * kernelVolume * inputVolume;
|
| 67 |
+
let batchBase = batch * colsBatchStride;
|
| 68 |
+
|
| 69 |
+
var acc = 0.0;
|
| 70 |
+
{% if hasBias %}
|
| 71 |
+
acc = f32(bias[oc]);
|
| 72 |
+
{% endif %}
|
| 73 |
+
for (var kd = 0u; kd < params.kernelD; kd += 1u) {
|
| 74 |
+
{{ tap("rawD", "id", "od", "kd", "D", " ") }}
|
| 75 |
+
for (var kh = 0u; kh < params.kernelH; kh += 1u) {
|
| 76 |
+
{{ tap("rawH", "ih", "oh", "kh", "H", " ") }}
|
| 77 |
+
for (var kw = 0u; kw < params.kernelW; kw += 1u) {
|
| 78 |
+
{{ tap("rawW", "iw", "ow", "kw", "W", " ") }}
|
| 79 |
+
let matrixRow = ((oc * params.kernelD + kd) * params.kernelH + kh) *
|
| 80 |
+
params.kernelW + kw;
|
| 81 |
+
let matrixColumn = (u32(id) * params.inH + u32(ih)) * params.inW +
|
| 82 |
+
u32(iw);
|
| 83 |
+
acc += f32(cols[batchBase + matrixRow * inputVolume + matrixColumn]);
|
| 84 |
+
}
|
| 85 |
+
}
|
| 86 |
+
}
|
| 87 |
+
y[index] = {{ T }}(acc);
|
| 88 |
+
}
|
build/webgpu/conv-transpose3d-ncdhw.wgsl.jinja
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{% macro flat_index_2d(name="i", bound="params.count", guardInline=false, note="dispatch-limit") %}
|
| 2 |
+
{% if note == "dispatch-limit" %}
|
| 3 |
+
// 2D-folded flat index: gid.y carries the high bits past the
|
| 4 |
+
// maxComputeWorkgroupsPerDimension dispatch limit (outputs > 16.7M elements).
|
| 5 |
+
{% elif note == "limit" %}
|
| 6 |
+
// 2D-folded flat index: gid.y carries the high bits past the
|
| 7 |
+
// maxComputeWorkgroupsPerDimension limit.
|
| 8 |
+
{% elif note == "device-axis" %}
|
| 9 |
+
// The flat dispatch is folded across x/y at the device's per-axis workgroup
|
| 10 |
+
// limit; gid.y carries the high portion of the output index.
|
| 11 |
+
{% elif note == "vec4-limit" %}
|
| 12 |
+
// 2D-folded flat vec4 index: gid.y carries the high bits past the
|
| 13 |
+
// maxComputeWorkgroupsPerDimension limit (the dispatch caps x and spills into y).
|
| 14 |
+
{% elif note == "element-limit" %}
|
| 15 |
+
// 2D-folded flat element index: gid.y carries the high bits past the
|
| 16 |
+
// maxComputeWorkgroupsPerDimension limit.
|
| 17 |
+
{% elif note == "dispatch" %}
|
| 18 |
+
// 2D-folded flat index: gid.y carries the high bits past the
|
| 19 |
+
// maxComputeWorkgroupsPerDimension dispatch limit.
|
| 20 |
+
{% endif %}
|
| 21 |
+
{% if bound == "" %}
|
| 22 |
+
let {{ name }} = gid.x + gid.y * nwg.x * {{ tunables.WORKGROUP_SIZE }}u;
|
| 23 |
+
{%- elif guardInline %}
|
| 24 |
+
let {{ name }} = gid.x + gid.y * nwg.x * {{ tunables.WORKGROUP_SIZE }}u;
|
| 25 |
+
if ({{ name }} >= {{ bound }}) { return; }
|
| 26 |
+
{%- else %}
|
| 27 |
+
let {{ name }} = gid.x + gid.y * nwg.x * {{ tunables.WORKGROUP_SIZE }}u;
|
| 28 |
+
if ({{ name }} >= {{ bound }}) {
|
| 29 |
+
return;
|
| 30 |
+
}
|
| 31 |
+
{%- endif %}
|
| 32 |
+
{% endmacro %}
|
| 33 |
+
|
| 34 |
+
{% macro tap(raw, coord, out, kernel, axis, indent) %}
|
| 35 |
+
{{ indent }}let {{ raw }} = i32({{ out }}) + params.pad{{ axis }} - i32({{ kernel }} * params.dilation{{ axis }});
|
| 36 |
+
{{ indent }}if ({{ raw }} < 0 || {{ raw }} % i32(params.stride{{ axis }}) != 0) { continue; }
|
| 37 |
+
{{ indent }}let {{ coord }} = {{ raw }} / i32(params.stride{{ axis }});
|
| 38 |
+
{{ indent }}if ({{ coord }} < 0 || {{ coord }} >= i32(params.in{{ axis }})) { continue; }
|
| 39 |
+
{%- endmacro -%}
|
| 40 |
+
{{ env.wgsl.resourceDeclarations }}
|
| 41 |
+
@compute @workgroup_size({{ tunables.WORKGROUP_SIZE }})
|
| 42 |
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>, @builtin(num_workgroups) nwg: vec3<u32>) {
|
| 43 |
+
{{ flat_index_2d("index", note="device-axis") }}
|
| 44 |
+
|
| 45 |
+
let ow = index % params.outW;
|
| 46 |
+
var t = index / params.outW;
|
| 47 |
+
let oh = t % params.outH;
|
| 48 |
+
t = t / params.outH;
|
| 49 |
+
let od = t % params.outD;
|
| 50 |
+
t = t / params.outD;
|
| 51 |
+
let oc = t % params.outChannels;
|
| 52 |
+
let batch = t / params.outChannels;
|
| 53 |
+
|
| 54 |
+
var acc = 0.0;
|
| 55 |
+
{% if hasBias %}
|
| 56 |
+
acc = bias[oc];
|
| 57 |
+
{% endif %}
|
| 58 |
+
for (var ic = 0u; ic < params.inChannels; ic = ic + 1u) {
|
| 59 |
+
for (var kd = 0u; kd < params.kernelD; kd = kd + 1u) {
|
| 60 |
+
{{ tap("raw_d", "id", "od", "kd", "D", " ") }}
|
| 61 |
+
for (var kh = 0u; kh < params.kernelH; kh = kh + 1u) {
|
| 62 |
+
{{ tap("raw_h", "ih", "oh", "kh", "H", " ") }}
|
| 63 |
+
for (var kw = 0u; kw < params.kernelW; kw = kw + 1u) {
|
| 64 |
+
{{ tap("raw_w", "iw", "ow", "kw", "W", " ") }}
|
| 65 |
+
let x_index = (((batch * params.inChannels + ic) * params.inD + u32(id)) * params.inH + u32(ih)) * params.inW + u32(iw);
|
| 66 |
+
let w_index = (((ic * params.outChannels + oc) * params.kernelD + kd) * params.kernelH + kh) * params.kernelW + kw;
|
| 67 |
+
acc = acc + x[x_index] * w[w_index];
|
| 68 |
+
}
|
| 69 |
+
}
|
| 70 |
+
}
|
| 71 |
+
}
|
| 72 |
+
y[index] = acc;
|
| 73 |
+
}
|
build/webgpu/conv-transpose3d-weight-reorder.wgsl.jinja
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{% macro flat_index_2d(name="i", bound="params.count", guardInline=false, note="dispatch-limit") %}
|
| 2 |
+
{% if note == "dispatch-limit" %}
|
| 3 |
+
// 2D-folded flat index: gid.y carries the high bits past the
|
| 4 |
+
// maxComputeWorkgroupsPerDimension dispatch limit (outputs > 16.7M elements).
|
| 5 |
+
{% elif note == "limit" %}
|
| 6 |
+
// 2D-folded flat index: gid.y carries the high bits past the
|
| 7 |
+
// maxComputeWorkgroupsPerDimension limit.
|
| 8 |
+
{% elif note == "device-axis" %}
|
| 9 |
+
// The flat dispatch is folded across x/y at the device's per-axis workgroup
|
| 10 |
+
// limit; gid.y carries the high portion of the output index.
|
| 11 |
+
{% elif note == "vec4-limit" %}
|
| 12 |
+
// 2D-folded flat vec4 index: gid.y carries the high bits past the
|
| 13 |
+
// maxComputeWorkgroupsPerDimension limit (the dispatch caps x and spills into y).
|
| 14 |
+
{% elif note == "element-limit" %}
|
| 15 |
+
// 2D-folded flat element index: gid.y carries the high bits past the
|
| 16 |
+
// maxComputeWorkgroupsPerDimension limit.
|
| 17 |
+
{% elif note == "dispatch" %}
|
| 18 |
+
// 2D-folded flat index: gid.y carries the high bits past the
|
| 19 |
+
// maxComputeWorkgroupsPerDimension dispatch limit.
|
| 20 |
+
{% endif %}
|
| 21 |
+
{% if bound == "" %}
|
| 22 |
+
let {{ name }} = gid.x + gid.y * nwg.x * {{ tunables.WORKGROUP_SIZE }}u;
|
| 23 |
+
{%- elif guardInline %}
|
| 24 |
+
let {{ name }} = gid.x + gid.y * nwg.x * {{ tunables.WORKGROUP_SIZE }}u;
|
| 25 |
+
if ({{ name }} >= {{ bound }}) { return; }
|
| 26 |
+
{%- else %}
|
| 27 |
+
let {{ name }} = gid.x + gid.y * nwg.x * {{ tunables.WORKGROUP_SIZE }}u;
|
| 28 |
+
if ({{ name }} >= {{ bound }}) {
|
| 29 |
+
return;
|
| 30 |
+
}
|
| 31 |
+
{%- endif %}
|
| 32 |
+
{% endmacro %}
|
| 33 |
+
|
| 34 |
+
// Reorder ONNX ConvTranspose weights from [IC, OC, KD, KH, KW] into the
|
| 35 |
+
// row-major GEMM operand [OC*KD*KH*KW, IC]. All extents come from the rank-5
|
| 36 |
+
// tensor contract through the uniform parameters.
|
| 37 |
+
{{ env.wgsl.resourceDeclarations }}
|
| 38 |
+
|
| 39 |
+
@compute @workgroup_size({{ tunables.WORKGROUP_SIZE }})
|
| 40 |
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>,
|
| 41 |
+
@builtin(num_workgroups) nwg: vec3<u32>) {
|
| 42 |
+
{{ flat_index_2d("index", note="device-axis") }}
|
| 43 |
+
|
| 44 |
+
let ic = index % params.inChannels;
|
| 45 |
+
var m = index / params.inChannels;
|
| 46 |
+
let kw = m % params.kernelW;
|
| 47 |
+
m /= params.kernelW;
|
| 48 |
+
let kh = m % params.kernelH;
|
| 49 |
+
m /= params.kernelH;
|
| 50 |
+
let kd = m % params.kernelD;
|
| 51 |
+
let oc = m / params.kernelD;
|
| 52 |
+
|
| 53 |
+
let sourceIndex = (((ic * params.outChannels + oc) * params.kernelD + kd) *
|
| 54 |
+
params.kernelH + kh) * params.kernelW + kw;
|
| 55 |
+
wt[index] = wsrc[sourceIndex];
|
| 56 |
+
}
|
build/webgpu/manifest.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
build/webgpu/metadata.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "ai.onnx.ConvTranspose",
|
| 3 |
+
"id": "_ai_onnx_convtranspose_webgpu_a7764a8",
|
| 4 |
+
"version": 1,
|
| 5 |
+
"license": "Apache-2.0",
|
| 6 |
+
"backend": { "type": "webgpu" },
|
| 7 |
+
"digest": {
|
| 8 |
+
"algorithm": "sha256",
|
| 9 |
+
"files": {
|
| 10 |
+
"bench.json": "K/3QCWt4Y0n8hE7RNLjJqIdqSDzkpSnjvOzP4cYpsgU=",
|
| 11 |
+
"conv-1x1-gemm-tiled-reg.wgsl.jinja": "hwyCsCvuGx3JXDj/OC0mVEhBqvrqpR5KqTWdUUdInZY=",
|
| 12 |
+
"conv-1x1-gemm-tiled.wgsl.jinja": "VeRKrzHV+9CvWm0Lrsgpt5C98Gkz5MubGVEnYApQhdk=",
|
| 13 |
+
"conv-1x1-subgroup-matrix.wgsl.jinja": "unfOK0d/deJ/p0Mzv12Z49OZHoZ89yHE8tQvQGTpOhI=",
|
| 14 |
+
"conv-transpose-empty-input.wgsl.jinja": "242WjbMQKXP51v/XyR8R/FORSaUohUJy0qMTCgcyd7Y=",
|
| 15 |
+
"conv-transpose1d-ncl.wgsl.jinja": "QV+rvtffoKy5nFid4T0vKcLbiRGeCVef87otPiRZs3Q=",
|
| 16 |
+
"conv-transpose1d-phase-tiled.wgsl.jinja": "nN+V8lCFxP3Omu1vLhUqZMpCt7Gb/LLQAVhPGntzcxk=",
|
| 17 |
+
"conv-transpose2d-col2im.wgsl.jinja": "TlUk+O29OeiRgVi+sCzFtm/pvJjQ4Pxs727+pS7Fg4c=",
|
| 18 |
+
"conv-transpose2d-grouped-stride-phase.wgsl.jinja": "VW/769KFvrA4NywQuNw9uawTGodB/iKUJdAE9vszJx8=",
|
| 19 |
+
"conv-transpose2d-nchw.wgsl.jinja": "VB/VsdNoFh6eVJJ9x1rHjIJYG1INTVMGO145elCU7ow=",
|
| 20 |
+
"conv-transpose2d-phase-gemm-tiled.wgsl.jinja": "uF07bIUt+NQdzc5Jq6IDLUDn51h6GASE++9HYbPGZms=",
|
| 21 |
+
"conv-transpose2d-weight-reorder.wgsl.jinja": "Gt8Qw4oUFXATVT33pGW7hvEIZ+VaYPrN70sFkFPNfGs=",
|
| 22 |
+
"conv-transpose3d-col2im.wgsl.jinja": "hKL2pQTqi81DFVEVuUZd5KNoikhK5Fcq+e6xPSBpM60=",
|
| 23 |
+
"conv-transpose3d-ncdhw.wgsl.jinja": "F9SYKafHOobKRTCa9yE/dUD4SCU/Fzgo+EdQdiAssCg=",
|
| 24 |
+
"conv-transpose3d-weight-reorder.wgsl.jinja": "CghFqX1j85v2ZY6DjTGhO2B+Es/lERkUB+QR+KoTzNA=",
|
| 25 |
+
"manifest.json": "X8AIY7imVWPKlvjr6NpBMaBGsONv+0kH68l2z0fwYZM=",
|
| 26 |
+
"test.json": "xRSBVV55KeohZ8pTZbAS5n3B0wwxBev9MxJbaE6/wF4="
|
| 27 |
+
}
|
| 28 |
+
},
|
| 29 |
+
"provenance": { "kernel": { "sha": "2e7068faf55e7f43df740015f6d1ee49391a41c5", "dirty": false } },
|
| 30 |
+
"webgpu": { "manifestSpec": "1.0", "specialized": true, "opPath": "ops/ai.onnx.ConvTranspose" }
|
| 31 |
+
}
|
build/webgpu/test.json
ADDED
|
@@ -0,0 +1,1856 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"op": "ai.onnx.ConvTranspose",
|
| 3 |
+
"fixtureArrays": {
|
| 4 |
+
"grouped_two_groups_no_bias_input_x": [1, 2, 3, 4, -1, -2, 0.5, 1.5, 2, -3, 4, -5, 0.25, -0.5, 0.75, -1],
|
| 5 |
+
"grouped_two_groups_no_bias_input_w": [1, 0, 0.5, -1, -0.25, 0.75, 1.5, 0, 0.5, -0.5, 1, 0.25, 1.25, 0, -0.75, 0.5, -1, 0.5, 0.25, 1, 0.75, -1.25, 0, 0.5, 0.25, 1.5, -0.5, 0, -0.75, 0.5, 1, -1],
|
| 6 |
+
"ort_default_strides_dilations_multi_channel_input_x": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17],
|
| 7 |
+
"onnx_backend_convtranspose_input_w": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
| 8 |
+
"f16_1d_nobias_input_x": [0.1, 0.5, -0.25, 0.75, 1, -0.5, 0.25, -1, 0.5, -0.75, 1.25, -0.25, 0, 0.5, -1, 0.75],
|
| 9 |
+
"f16_1d_nobias_input_w": [0.5, -0.25, 1, 0.75, -0.5, 0.25, -1, 0.5, 0.125, 1, -0.5, 0.25, 0.5, 0.75, -0.25, -0.75, 0.5, 1]
|
| 10 |
+
},
|
| 11 |
+
"cases": [
|
| 12 |
+
{
|
| 13 |
+
"name": "f32_subnormal_times_large_scale_1d_gpu_gap",
|
| 14 |
+
"provenance": {
|
| 15 |
+
"source": "onnxruntime/test/providers/cpu/nn/conv_transpose_op_test.cc",
|
| 16 |
+
"test": "ConvTransposeTest",
|
| 17 |
+
"notes": "A 1D transposed convolution with a pointwise large finite weight should preserve subnormal input signal as normal finite output."
|
| 18 |
+
},
|
| 19 |
+
"attrs": {},
|
| 20 |
+
"inputs": {
|
| 21 |
+
"x": {
|
| 22 |
+
"dtype": "float32",
|
| 23 |
+
"shape": [1, 1, 4],
|
| 24 |
+
"data": { "kind": "values", "values": [1e-39, -1e-39, 1e-38, -1e-38] }
|
| 25 |
+
},
|
| 26 |
+
"w": { "dtype": "float32", "shape": [1, 1, 1], "data": { "kind": "constant", "value": 1e+38 } }
|
| 27 |
+
},
|
| 28 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 1, 4], "tolerance": 0.000001 } },
|
| 29 |
+
"skipGpu": {
|
| 30 |
+
"category": "permanent",
|
| 31 |
+
"reason": "Portable WGSL floating-point semantics do not guarantee preservation of the subnormal values required by this fixture. Backend evidence: Metal flushes f32 subnormals to zero (FTZ); subnormal-magnitude values cannot survive the GPU arithmetic path."
|
| 32 |
+
}
|
| 33 |
+
},
|
| 34 |
+
{
|
| 35 |
+
"name": "f32_subnormal_times_large_scale_2d_gpu_gap",
|
| 36 |
+
"provenance": {
|
| 37 |
+
"source": "onnxruntime/test/providers/cpu/nn/conv_transpose_op_test.cc",
|
| 38 |
+
"test": "ConvTransposeTest",
|
| 39 |
+
"notes": "A 2D transposed convolution with a pointwise large finite weight should preserve subnormal input signal as normal finite output."
|
| 40 |
+
},
|
| 41 |
+
"attrs": {},
|
| 42 |
+
"inputs": {
|
| 43 |
+
"x": {
|
| 44 |
+
"dtype": "float32",
|
| 45 |
+
"shape": [1, 1, 2, 2],
|
| 46 |
+
"data": { "kind": "values", "values": [1e-39, -1e-39, 1e-38, -1e-38] }
|
| 47 |
+
},
|
| 48 |
+
"w": { "dtype": "float32", "shape": [1, 1, 1, 1], "data": { "kind": "constant", "value": 1e+38 } }
|
| 49 |
+
},
|
| 50 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 1, 2, 2], "tolerance": 0.000001 } },
|
| 51 |
+
"skipGpu": {
|
| 52 |
+
"category": "permanent",
|
| 53 |
+
"reason": "Portable WGSL floating-point semantics do not guarantee preservation of the subnormal values required by this fixture. Backend evidence: Metal flushes f32 subnormals to zero (FTZ); subnormal-magnitude values cannot survive the GPU arithmetic path."
|
| 54 |
+
}
|
| 55 |
+
},
|
| 56 |
+
{
|
| 57 |
+
"name": "f32_subnormal_times_large_scale_3d_gpu_gap",
|
| 58 |
+
"provenance": {
|
| 59 |
+
"source": "onnxruntime/test/providers/cpu/nn/conv_transpose_op_test.cc",
|
| 60 |
+
"test": "ConvTransposeTest",
|
| 61 |
+
"notes": "A 3D transposed convolution with a pointwise large finite weight should preserve subnormal input signal as normal finite output."
|
| 62 |
+
},
|
| 63 |
+
"attrs": {},
|
| 64 |
+
"inputs": {
|
| 65 |
+
"x": {
|
| 66 |
+
"dtype": "float32",
|
| 67 |
+
"shape": [1, 1, 2, 2, 2],
|
| 68 |
+
"data": { "kind": "values", "values": [1e-39, -1e-39, 2e-39, -2e-39, 5e-39, -5e-39, 1e-38, -1e-38] }
|
| 69 |
+
},
|
| 70 |
+
"w": { "dtype": "float32", "shape": [1, 1, 1, 1, 1], "data": { "kind": "constant", "value": 1e+38 } }
|
| 71 |
+
},
|
| 72 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 1, 2, 2, 2], "tolerance": 0.000001 } },
|
| 73 |
+
"skipGpu": {
|
| 74 |
+
"category": "permanent",
|
| 75 |
+
"reason": "Portable WGSL floating-point semantics do not guarantee preservation of the subnormal values required by this fixture. Backend evidence: Metal flushes f32 subnormals to zero (FTZ); subnormal-magnitude values cannot survive the GPU arithmetic path."
|
| 76 |
+
}
|
| 77 |
+
},
|
| 78 |
+
{
|
| 79 |
+
"name": "dispatch_cliff_ncl1d",
|
| 80 |
+
"attrs": {},
|
| 81 |
+
"inputs": {
|
| 82 |
+
"x": {
|
| 83 |
+
"dtype": "float32",
|
| 84 |
+
"shape": [1, 1, 16776961],
|
| 85 |
+
"data": { "kind": "cycle", "values": [0.5, -0.25, 1.0, -0.75] }
|
| 86 |
+
},
|
| 87 |
+
"w": { "dtype": "float32", "shape": [1, 1, 1], "data": { "kind": "constant", "value": 2.0 } }
|
| 88 |
+
},
|
| 89 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 1, 16776961], "tolerance": 0.00001 } }
|
| 90 |
+
},
|
| 91 |
+
{
|
| 92 |
+
"name": "phase_tiled_1d_k4s2_batch_channel_position_tails",
|
| 93 |
+
"provenance": {
|
| 94 |
+
"notes": "Exercises the neural-audio stride-2 phase decomposition with non-tile-aligned input channels, output channels, positions, and batch > 1."
|
| 95 |
+
},
|
| 96 |
+
"attrs": { "strides": [2], "pads": [1, 1] },
|
| 97 |
+
"inputs": {
|
| 98 |
+
"x": {
|
| 99 |
+
"dtype": "float32",
|
| 100 |
+
"shape": [2, 37, 35],
|
| 101 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.11, "cosStep": 0.17, "scale": 0.2 }
|
| 102 |
+
},
|
| 103 |
+
"w": {
|
| 104 |
+
"dtype": "float32",
|
| 105 |
+
"shape": [37, 13, 4],
|
| 106 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.19, "cosStep": 0.13, "scale": 0.1 }
|
| 107 |
+
}
|
| 108 |
+
},
|
| 109 |
+
"outputs": { "y": { "dtype": "float32", "shape": [2, 13, 70], "tolerance": 0.00002 } }
|
| 110 |
+
},
|
| 111 |
+
{
|
| 112 |
+
"name": "phase_tiled_1d_k4s2_bias_tails",
|
| 113 |
+
"provenance": { "notes": "Bias companion for the phase-tiled neural-audio path with channel and position tails." },
|
| 114 |
+
"attrs": { "strides": [2], "pads": [1, 1] },
|
| 115 |
+
"inputs": {
|
| 116 |
+
"x": {
|
| 117 |
+
"dtype": "float32",
|
| 118 |
+
"shape": [1, 17, 33],
|
| 119 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.23, "scale": 0.2 }
|
| 120 |
+
},
|
| 121 |
+
"w": {
|
| 122 |
+
"dtype": "float32",
|
| 123 |
+
"shape": [17, 19, 4],
|
| 124 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.17, "cosStep": 0.29, "scale": 0.1 }
|
| 125 |
+
},
|
| 126 |
+
"bias": {
|
| 127 |
+
"dtype": "float32",
|
| 128 |
+
"shape": [19],
|
| 129 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.05, "cosStep": 0.31, "scale": 0.05 }
|
| 130 |
+
}
|
| 131 |
+
},
|
| 132 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 19, 66], "tolerance": 0.00002 } }
|
| 133 |
+
},
|
| 134 |
+
{
|
| 135 |
+
"name": "phase_tiled_1d_register_tile_channel_position_tails",
|
| 136 |
+
"provenance": {
|
| 137 |
+
"notes": "Crosses the occupancy-derived two-output register-tile threshold while retaining input-channel, output-channel, and position tails."
|
| 138 |
+
},
|
| 139 |
+
"attrs": { "strides": [2], "pads": [1, 1] },
|
| 140 |
+
"inputs": {
|
| 141 |
+
"x": {
|
| 142 |
+
"dtype": "float32",
|
| 143 |
+
"shape": [1, 17, 1025],
|
| 144 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.09, "cosStep": 0.21, "scale": 0.2 }
|
| 145 |
+
},
|
| 146 |
+
"w": {
|
| 147 |
+
"dtype": "float32",
|
| 148 |
+
"shape": [17, 65, 4],
|
| 149 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.15, "cosStep": 0.27, "scale": 0.1 }
|
| 150 |
+
}
|
| 151 |
+
},
|
| 152 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 65, 2050], "tolerance": 0.00002 } }
|
| 153 |
+
},
|
| 154 |
+
{
|
| 155 |
+
"name": "nchw_no_bias",
|
| 156 |
+
"attrs": { "strides": [2, 1], "pads": [1, 0, 1, 0] },
|
| 157 |
+
"inputs": {
|
| 158 |
+
"x": {
|
| 159 |
+
"dtype": "float32",
|
| 160 |
+
"shape": [1, 2, 3, 4],
|
| 161 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.11, "cosStep": 0.17 }
|
| 162 |
+
},
|
| 163 |
+
"w": {
|
| 164 |
+
"dtype": "float32",
|
| 165 |
+
"shape": [2, 2, 3, 2],
|
| 166 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.19, "cosStep": 0.13 }
|
| 167 |
+
}
|
| 168 |
+
},
|
| 169 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 2, 5, 5], "tolerance": 0.00001 } }
|
| 170 |
+
},
|
| 171 |
+
{
|
| 172 |
+
"name": "nchw_bias",
|
| 173 |
+
"attrs": { "strides": [2, 1], "pads": [1, 0, 1, 0] },
|
| 174 |
+
"inputs": {
|
| 175 |
+
"x": {
|
| 176 |
+
"dtype": "float32",
|
| 177 |
+
"shape": [1, 2, 3, 4],
|
| 178 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.11, "cosStep": 0.17 }
|
| 179 |
+
},
|
| 180 |
+
"w": {
|
| 181 |
+
"dtype": "float32",
|
| 182 |
+
"shape": [2, 2, 3, 2],
|
| 183 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.19, "cosStep": 0.13 }
|
| 184 |
+
},
|
| 185 |
+
"bias": {
|
| 186 |
+
"dtype": "float32",
|
| 187 |
+
"shape": [2],
|
| 188 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.29 }
|
| 189 |
+
}
|
| 190 |
+
},
|
| 191 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 2, 5, 5], "tolerance": 0.00001 } }
|
| 192 |
+
},
|
| 193 |
+
{
|
| 194 |
+
"name": "non_vector_channels_no_bias",
|
| 195 |
+
"attrs": {},
|
| 196 |
+
"inputs": {
|
| 197 |
+
"x": {
|
| 198 |
+
"dtype": "float32",
|
| 199 |
+
"shape": [1, 3, 2, 2],
|
| 200 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.13, "cosStep": 0.17 }
|
| 201 |
+
},
|
| 202 |
+
"w": {
|
| 203 |
+
"dtype": "float32",
|
| 204 |
+
"shape": [3, 5, 2, 2],
|
| 205 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.19, "cosStep": 0.23 }
|
| 206 |
+
}
|
| 207 |
+
},
|
| 208 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 5, 3, 3], "tolerance": 0.00001 } }
|
| 209 |
+
},
|
| 210 |
+
{
|
| 211 |
+
"name": "non_vector_channels_bias",
|
| 212 |
+
"attrs": {},
|
| 213 |
+
"inputs": {
|
| 214 |
+
"x": {
|
| 215 |
+
"dtype": "float32",
|
| 216 |
+
"shape": [1, 3, 2, 2],
|
| 217 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.13, "cosStep": 0.17 }
|
| 218 |
+
},
|
| 219 |
+
"w": {
|
| 220 |
+
"dtype": "float32",
|
| 221 |
+
"shape": [3, 5, 2, 2],
|
| 222 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.19, "cosStep": 0.23 }
|
| 223 |
+
},
|
| 224 |
+
"bias": {
|
| 225 |
+
"dtype": "float32",
|
| 226 |
+
"shape": [5],
|
| 227 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.29 }
|
| 228 |
+
}
|
| 229 |
+
},
|
| 230 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 5, 3, 3], "tolerance": 0.00001 } }
|
| 231 |
+
},
|
| 232 |
+
{
|
| 233 |
+
"name": "non_vector_channels_bias_stride2_compact",
|
| 234 |
+
"provenance": {
|
| 235 |
+
"notes": "Compact companion for bench case conv-transpose-f32-non-vector-bias-b1c3m5-32x32-k3s2, preserving non-vec channel counts, bias, stride=2, and padded k3 output geometry."
|
| 236 |
+
},
|
| 237 |
+
"attrs": { "strides": [2, 2], "pads": [1, 1, 1, 1] },
|
| 238 |
+
"inputs": {
|
| 239 |
+
"x": {
|
| 240 |
+
"dtype": "float32",
|
| 241 |
+
"shape": [1, 3, 8, 8],
|
| 242 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.13, "cosStep": 0.17, "scale": 0.2 }
|
| 243 |
+
},
|
| 244 |
+
"w": {
|
| 245 |
+
"dtype": "float32",
|
| 246 |
+
"shape": [3, 5, 3, 3],
|
| 247 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.19, "cosStep": 0.23, "scale": 0.12 }
|
| 248 |
+
},
|
| 249 |
+
"bias": {
|
| 250 |
+
"dtype": "float32",
|
| 251 |
+
"shape": [5],
|
| 252 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.29, "scale": 0.1 }
|
| 253 |
+
}
|
| 254 |
+
},
|
| 255 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 5, 15, 15], "tolerance": 0.00001 } }
|
| 256 |
+
},
|
| 257 |
+
{
|
| 258 |
+
"name": "output_padding_extends_shape",
|
| 259 |
+
"attrs": { "strides": [2, 2], "output_padding": [1, 1] },
|
| 260 |
+
"inputs": {
|
| 261 |
+
"x": { "dtype": "float32", "shape": [1, 1, 2, 2], "data": { "kind": "values", "values": [1.0, 2.0, 3.0, 4.0] } },
|
| 262 |
+
"w": {
|
| 263 |
+
"dtype": "float32",
|
| 264 |
+
"shape": [1, 1, 2, 2],
|
| 265 |
+
"data": { "kind": "values", "values": [1.0, -1.0, 2.0, 0.5] }
|
| 266 |
+
}
|
| 267 |
+
},
|
| 268 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 1, 5, 5], "tolerance": 0.000001 } }
|
| 269 |
+
},
|
| 270 |
+
{
|
| 271 |
+
"name": "dilated_kernel_spreads_taps",
|
| 272 |
+
"attrs": { "dilations": [2, 2] },
|
| 273 |
+
"inputs": {
|
| 274 |
+
"x": {
|
| 275 |
+
"dtype": "float32",
|
| 276 |
+
"shape": [1, 1, 3, 3],
|
| 277 |
+
"data": { "kind": "values", "values": [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0] }
|
| 278 |
+
},
|
| 279 |
+
"w": {
|
| 280 |
+
"dtype": "float32",
|
| 281 |
+
"shape": [1, 1, 2, 2],
|
| 282 |
+
"data": { "kind": "values", "values": [1.0, -2.0, 0.5, 3.0] }
|
| 283 |
+
}
|
| 284 |
+
},
|
| 285 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 1, 5, 5], "tolerance": 0.000001 } }
|
| 286 |
+
},
|
| 287 |
+
{
|
| 288 |
+
"name": "grouped_two_groups_no_bias",
|
| 289 |
+
"attrs": { "group": 2 },
|
| 290 |
+
"inputs": {
|
| 291 |
+
"x": {
|
| 292 |
+
"dtype": "float32",
|
| 293 |
+
"shape": [1, 4, 2, 2],
|
| 294 |
+
"data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/grouped_two_groups_no_bias_input_x" } }
|
| 295 |
+
},
|
| 296 |
+
"w": {
|
| 297 |
+
"dtype": "float32",
|
| 298 |
+
"shape": [4, 2, 2, 2],
|
| 299 |
+
"data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/grouped_two_groups_no_bias_input_w" } }
|
| 300 |
+
}
|
| 301 |
+
},
|
| 302 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 4, 3, 3], "tolerance": 0.000001 } }
|
| 303 |
+
},
|
| 304 |
+
{
|
| 305 |
+
"name": "f32_grouped2d_stride2_phase",
|
| 306 |
+
"provenance": {
|
| 307 |
+
"notes": "Compact grouped stride-2 fixture that exercises the phase-decomposed nchw2d_grouped_stride_phase fallback on every feature tier."
|
| 308 |
+
},
|
| 309 |
+
"attrs": { "group": 2, "strides": [2, 2], "pads": [1, 1, 1, 1] },
|
| 310 |
+
"inputs": {
|
| 311 |
+
"x": {
|
| 312 |
+
"dtype": "float32",
|
| 313 |
+
"shape": [1, 4, 3, 4],
|
| 314 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.11, "cosStep": 0.17, "scale": 0.25 }
|
| 315 |
+
},
|
| 316 |
+
"w": {
|
| 317 |
+
"dtype": "float32",
|
| 318 |
+
"shape": [4, 3, 3, 3],
|
| 319 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.19, "cosStep": 0.13, "scale": 0.2 }
|
| 320 |
+
}
|
| 321 |
+
},
|
| 322 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 6, 5, 7], "tolerance": 0.00001 } }
|
| 323 |
+
},
|
| 324 |
+
{
|
| 325 |
+
"name": "grouped_two_groups_bias",
|
| 326 |
+
"attrs": { "group": 2 },
|
| 327 |
+
"inputs": {
|
| 328 |
+
"x": {
|
| 329 |
+
"dtype": "float32",
|
| 330 |
+
"shape": [1, 4, 2, 2],
|
| 331 |
+
"data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/grouped_two_groups_no_bias_input_x" } }
|
| 332 |
+
},
|
| 333 |
+
"w": {
|
| 334 |
+
"dtype": "float32",
|
| 335 |
+
"shape": [4, 2, 2, 2],
|
| 336 |
+
"data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/grouped_two_groups_no_bias_input_w" } }
|
| 337 |
+
},
|
| 338 |
+
"bias": { "dtype": "float32", "shape": [4], "data": { "kind": "values", "values": [0.5, -1.0, 1.5, -0.25] } }
|
| 339 |
+
},
|
| 340 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 4, 3, 3], "tolerance": 0.000001 } }
|
| 341 |
+
},
|
| 342 |
+
{
|
| 343 |
+
"name": "ort_zero_batch_dim",
|
| 344 |
+
"provenance": {
|
| 345 |
+
"source": "onnxruntime/test/providers/cpu/nn/conv_transpose_op_test.cc",
|
| 346 |
+
"test": "ConvTransposeTest.DimWithZero"
|
| 347 |
+
},
|
| 348 |
+
"attrs": { "strides": [2, 2], "pads": [1, 1, 1, 1], "output_padding": [1, 1] },
|
| 349 |
+
"inputs": {
|
| 350 |
+
"x": { "dtype": "float32", "shape": [0, 1, 3, 3], "data": { "kind": "values", "values": [] } },
|
| 351 |
+
"w": {
|
| 352 |
+
"dtype": "float32",
|
| 353 |
+
"shape": [1, 1, 3, 3],
|
| 354 |
+
"data": {
|
| 355 |
+
"kind": "values",
|
| 356 |
+
"values": [-0.06230065, 0.37932432, -0.25388849, 0.33878803, 0.43709868, -0.22477469, 0.04118127, -0.44696793, 0.06373066]
|
| 357 |
+
}
|
| 358 |
+
}
|
| 359 |
+
},
|
| 360 |
+
"outputs": { "y": { "dtype": "float32", "shape": [0, 1, 6, 6], "tolerance": 0 } }
|
| 361 |
+
},
|
| 362 |
+
{
|
| 363 |
+
"name": "ort_outputpadding_strides2",
|
| 364 |
+
"provenance": {
|
| 365 |
+
"source": "onnxruntime/test/providers/cpu/nn/conv_transpose_op_test.cc",
|
| 366 |
+
"test": "ConvTransposeTest.ConvTranspose_2D_outputpadding_strides2"
|
| 367 |
+
},
|
| 368 |
+
"attrs": { "strides": [2, 2], "pads": [1, 1, 1, 1], "output_padding": [1, 1] },
|
| 369 |
+
"inputs": {
|
| 370 |
+
"x": {
|
| 371 |
+
"dtype": "float32",
|
| 372 |
+
"shape": [1, 1, 3, 3],
|
| 373 |
+
"data": {
|
| 374 |
+
"kind": "values",
|
| 375 |
+
"values": [0.16857791, -0.15161794, 0.08540368, 0.1820628, -0.21746576, 0.08245695, 0.1431433, -0.43156421, 0.30591947]
|
| 376 |
+
}
|
| 377 |
+
},
|
| 378 |
+
"w": {
|
| 379 |
+
"dtype": "float32",
|
| 380 |
+
"shape": [1, 1, 3, 3],
|
| 381 |
+
"data": {
|
| 382 |
+
"kind": "values",
|
| 383 |
+
"values": [-0.06230065, 0.37932432, -0.25388849, 0.33878803, 0.43709868, -0.22477469, 0.04118127, -0.44696793, 0.06373066]
|
| 384 |
+
}
|
| 385 |
+
}
|
| 386 |
+
},
|
| 387 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 1, 6, 6], "tolerance": 0.000001 } }
|
| 388 |
+
},
|
| 389 |
+
{
|
| 390 |
+
"name": "ort_outputpadding_strides2_f16",
|
| 391 |
+
"provenance": {
|
| 392 |
+
"source": "onnxruntime/test/providers/cpu/nn/conv_transpose_op_test.cc",
|
| 393 |
+
"test": "ConvTransposeTest.ConvTranspose_2D_outputpadding_strides2"
|
| 394 |
+
},
|
| 395 |
+
"attrs": { "strides": [2, 2], "pads": [1, 1, 1, 1], "output_padding": [1, 1] },
|
| 396 |
+
"inputs": {
|
| 397 |
+
"x": {
|
| 398 |
+
"dtype": "float16",
|
| 399 |
+
"shape": [1, 1, 3, 3],
|
| 400 |
+
"data": {
|
| 401 |
+
"kind": "values",
|
| 402 |
+
"values": [0.16857791, -0.15161794, 0.08540368, 0.1820628, -0.21746576, 0.08245695, 0.1431433, -0.43156421, 0.30591947]
|
| 403 |
+
}
|
| 404 |
+
},
|
| 405 |
+
"w": {
|
| 406 |
+
"dtype": "float16",
|
| 407 |
+
"shape": [1, 1, 3, 3],
|
| 408 |
+
"data": {
|
| 409 |
+
"kind": "values",
|
| 410 |
+
"values": [-0.06230065, 0.37932432, -0.25388849, 0.33878803, 0.43709868, -0.22477469, 0.04118127, -0.44696793, 0.06373066]
|
| 411 |
+
}
|
| 412 |
+
}
|
| 413 |
+
},
|
| 414 |
+
"outputs": { "y": { "dtype": "float16", "shape": [1, 1, 6, 6], "tolerance": 0.001 } }
|
| 415 |
+
},
|
| 416 |
+
{
|
| 417 |
+
"name": "ort_2d_c2_single_output_channel",
|
| 418 |
+
"provenance": {
|
| 419 |
+
"source": "onnxruntime/test/providers/cpu/nn/conv_transpose_op_test.cc",
|
| 420 |
+
"test": "ConvTransposeTest.ConvTranspose_2D_C2"
|
| 421 |
+
},
|
| 422 |
+
"attrs": {},
|
| 423 |
+
"inputs": {
|
| 424 |
+
"x": {
|
| 425 |
+
"dtype": "float32",
|
| 426 |
+
"shape": [1, 2, 3, 3],
|
| 427 |
+
"data": {
|
| 428 |
+
"kind": "values",
|
| 429 |
+
"values": [0.43, 0.42871707, 0.29552766, 0.17258859, 0.68087016, 0.7090254, 0.60937387, 0.58646585, 0.84525721, 0.47011843, 0.95854213, 0.3972888, 0.0585452, 0.1206734, 0.76727852, 0.46040912, 0.83495316, 0.02409773]
|
| 430 |
+
}
|
| 431 |
+
},
|
| 432 |
+
"w": {
|
| 433 |
+
"dtype": "float32",
|
| 434 |
+
"shape": [2, 1, 2, 2],
|
| 435 |
+
"data": {
|
| 436 |
+
"kind": "values",
|
| 437 |
+
"values": [0.25616416, 0.10246604, 0.08771133, 0.30770606, 0.84369617, 0.3010619, 0.44524362, 0.6056068]
|
| 438 |
+
}
|
| 439 |
+
}
|
| 440 |
+
},
|
| 441 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 1, 4, 4], "tolerance": 0.000001 } }
|
| 442 |
+
},
|
| 443 |
+
{
|
| 444 |
+
"name": "ort_dilation2_kernel2_simple",
|
| 445 |
+
"provenance": {
|
| 446 |
+
"source": "onnxruntime/test/providers/cpu/nn/conv_transpose_op_test.cc",
|
| 447 |
+
"test": "ConvTransposeTest.ConvTranspose_2D_Dilation_1"
|
| 448 |
+
},
|
| 449 |
+
"attrs": { "dilations": [2, 2] },
|
| 450 |
+
"inputs": {
|
| 451 |
+
"x": {
|
| 452 |
+
"dtype": "float32",
|
| 453 |
+
"shape": [1, 1, 2, 2],
|
| 454 |
+
"data": { "kind": "values", "values": [11.0, 12.0, 21.0, 22.0] }
|
| 455 |
+
},
|
| 456 |
+
"w": { "dtype": "float32", "shape": [1, 1, 2, 2], "data": { "kind": "values", "values": [1.0, 1.0, 1.0, 1.0] } }
|
| 457 |
+
},
|
| 458 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 1, 4, 4], "tolerance": 0.000001 } }
|
| 459 |
+
},
|
| 460 |
+
{
|
| 461 |
+
"name": "ort_dilation3_kernel2_mixed_values",
|
| 462 |
+
"provenance": {
|
| 463 |
+
"source": "onnxruntime/test/providers/cpu/nn/conv_transpose_op_test.cc",
|
| 464 |
+
"test": "ConvTransposeTest.ConvTranspose_2D_Dilation_4"
|
| 465 |
+
},
|
| 466 |
+
"attrs": { "dilations": [3, 3] },
|
| 467 |
+
"inputs": {
|
| 468 |
+
"x": {
|
| 469 |
+
"dtype": "float32",
|
| 470 |
+
"shape": [1, 1, 3, 3],
|
| 471 |
+
"data": { "kind": "values", "values": [3.0, 8.0, 1.0, 9.0, 5.0, 7.0, 3.0, 2.0, 6.0] }
|
| 472 |
+
},
|
| 473 |
+
"w": { "dtype": "float32", "shape": [1, 1, 2, 2], "data": { "kind": "values", "values": [7.0, 2.0, 1.0, 9.0] } }
|
| 474 |
+
},
|
| 475 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 1, 6, 6], "tolerance": 0.000001 } }
|
| 476 |
+
},
|
| 477 |
+
{
|
| 478 |
+
"name": "ort_dilation3_asymmetric_pads_top_left",
|
| 479 |
+
"provenance": {
|
| 480 |
+
"source": "onnxruntime/test/providers/cpu/nn/conv_transpose_op_test.cc",
|
| 481 |
+
"test": "ConvTransposeTest.ConvTranspose_2D_Dilation_AsymmetricPads_1"
|
| 482 |
+
},
|
| 483 |
+
"attrs": { "pads": [2, 2, 1, 1], "dilations": [3, 3] },
|
| 484 |
+
"inputs": {
|
| 485 |
+
"x": {
|
| 486 |
+
"dtype": "float32",
|
| 487 |
+
"shape": [1, 1, 3, 3],
|
| 488 |
+
"data": { "kind": "values", "values": [3.0, 8.0, 1.0, 9.0, 5.0, 7.0, 3.0, 2.0, 6.0] }
|
| 489 |
+
},
|
| 490 |
+
"w": { "dtype": "float32", "shape": [1, 1, 2, 2], "data": { "kind": "values", "values": [7.0, 2.0, 1.0, 9.0] } }
|
| 491 |
+
},
|
| 492 |
+
"outputs": {
|
| 493 |
+
"y": {
|
| 494 |
+
"dtype": "float32",
|
| 495 |
+
"shape": [1, 1, 3, 3],
|
| 496 |
+
"tolerance": 0.000001,
|
| 497 |
+
"data": { "kind": "values", "values": [42.0, 6.0, 4.0, 1.0, 27.0, 72.0, 7.0, 81.0, 45.0] }
|
| 498 |
+
}
|
| 499 |
+
}
|
| 500 |
+
},
|
| 501 |
+
{
|
| 502 |
+
"name": "ort_dilation3_asymmetric_pads_bottom_right",
|
| 503 |
+
"provenance": {
|
| 504 |
+
"source": "onnxruntime/test/providers/cpu/nn/conv_transpose_op_test.cc",
|
| 505 |
+
"test": "ConvTransposeTest.ConvTranspose_2D_Dilation_AsymmetricPads_2"
|
| 506 |
+
},
|
| 507 |
+
"attrs": { "pads": [1, 1, 2, 2], "dilations": [3, 3] },
|
| 508 |
+
"inputs": {
|
| 509 |
+
"x": {
|
| 510 |
+
"dtype": "float32",
|
| 511 |
+
"shape": [1, 1, 3, 3],
|
| 512 |
+
"data": { "kind": "values", "values": [3.0, 8.0, 1.0, 9.0, 5.0, 7.0, 3.0, 2.0, 6.0] }
|
| 513 |
+
},
|
| 514 |
+
"w": { "dtype": "float32", "shape": [1, 1, 2, 2], "data": { "kind": "values", "values": [7.0, 2.0, 1.0, 9.0] } }
|
| 515 |
+
},
|
| 516 |
+
"outputs": {
|
| 517 |
+
"y": {
|
| 518 |
+
"dtype": "float32",
|
| 519 |
+
"shape": [1, 1, 3, 3],
|
| 520 |
+
"tolerance": 0.000001,
|
| 521 |
+
"data": { "kind": "values", "values": [35.0, 49.0, 18.0, 14.0, 42.0, 6.0, 8.0, 1.0, 27.0] }
|
| 522 |
+
}
|
| 523 |
+
}
|
| 524 |
+
},
|
| 525 |
+
{
|
| 526 |
+
"name": "ort_dilation3_asymmetric_pads_crop_top_left",
|
| 527 |
+
"provenance": {
|
| 528 |
+
"source": "onnxruntime/test/providers/cpu/nn/conv_transpose_op_test.cc",
|
| 529 |
+
"test": "ConvTransposeTest.ConvTranspose_2D_Dilation_AsymmetricPads_3"
|
| 530 |
+
},
|
| 531 |
+
"attrs": { "pads": [2, 2, 0, 0], "dilations": [3, 3] },
|
| 532 |
+
"inputs": {
|
| 533 |
+
"x": {
|
| 534 |
+
"dtype": "float32",
|
| 535 |
+
"shape": [1, 1, 3, 3],
|
| 536 |
+
"data": { "kind": "values", "values": [3.0, 8.0, 1.0, 9.0, 5.0, 7.0, 3.0, 2.0, 6.0] }
|
| 537 |
+
},
|
| 538 |
+
"w": { "dtype": "float32", "shape": [1, 1, 2, 2], "data": { "kind": "values", "values": [7.0, 2.0, 1.0, 9.0] } }
|
| 539 |
+
},
|
| 540 |
+
"outputs": {
|
| 541 |
+
"y": {
|
| 542 |
+
"dtype": "float32",
|
| 543 |
+
"shape": [1, 1, 4, 4],
|
| 544 |
+
"tolerance": 0.000001,
|
| 545 |
+
"data": {
|
| 546 |
+
"kind": "values",
|
| 547 |
+
"values": [42.0, 6.0, 4.0, 12.0, 1.0, 27.0, 72.0, 9.0, 7.0, 81.0, 45.0, 63.0, 6.0, 27.0, 18.0, 54.0]
|
| 548 |
+
}
|
| 549 |
+
}
|
| 550 |
+
}
|
| 551 |
+
},
|
| 552 |
+
{
|
| 553 |
+
"name": "ort_dilation3_asymmetric_pads_crop_bottom_right",
|
| 554 |
+
"provenance": {
|
| 555 |
+
"source": "onnxruntime/test/providers/cpu/nn/conv_transpose_op_test.cc",
|
| 556 |
+
"test": "ConvTransposeTest.ConvTranspose_2D_Dilation_AsymmetricPads_4"
|
| 557 |
+
},
|
| 558 |
+
"attrs": { "pads": [0, 0, 2, 2], "dilations": [3, 3] },
|
| 559 |
+
"inputs": {
|
| 560 |
+
"x": {
|
| 561 |
+
"dtype": "float32",
|
| 562 |
+
"shape": [1, 1, 3, 3],
|
| 563 |
+
"data": { "kind": "values", "values": [3.0, 8.0, 1.0, 9.0, 5.0, 7.0, 3.0, 2.0, 6.0] }
|
| 564 |
+
},
|
| 565 |
+
"w": { "dtype": "float32", "shape": [1, 1, 2, 2], "data": { "kind": "values", "values": [7.0, 2.0, 1.0, 9.0] } }
|
| 566 |
+
},
|
| 567 |
+
"outputs": {
|
| 568 |
+
"y": {
|
| 569 |
+
"dtype": "float32",
|
| 570 |
+
"shape": [1, 1, 4, 4],
|
| 571 |
+
"tolerance": 0.000001,
|
| 572 |
+
"data": {
|
| 573 |
+
"kind": "values",
|
| 574 |
+
"values": [21.0, 56.0, 7.0, 6.0, 63.0, 35.0, 49.0, 18.0, 21.0, 14.0, 42.0, 6.0, 3.0, 8.0, 1.0, 27.0]
|
| 575 |
+
}
|
| 576 |
+
}
|
| 577 |
+
}
|
| 578 |
+
},
|
| 579 |
+
{
|
| 580 |
+
"name": "ort_default_strides_dilations_multi_channel",
|
| 581 |
+
"provenance": {
|
| 582 |
+
"source": "onnxruntime/test/providers/cpu/nn/conv_transpose_op_test.cc",
|
| 583 |
+
"test": "ConvTransposeTest.ConvTranspose_DefaultStridesAndDilations"
|
| 584 |
+
},
|
| 585 |
+
"attrs": {},
|
| 586 |
+
"inputs": {
|
| 587 |
+
"x": {
|
| 588 |
+
"dtype": "float32",
|
| 589 |
+
"shape": [1, 2, 3, 3],
|
| 590 |
+
"data": {
|
| 591 |
+
"kind": "values",
|
| 592 |
+
"values": { "$ref": "#/fixtureArrays/ort_default_strides_dilations_multi_channel_input_x" }
|
| 593 |
+
}
|
| 594 |
+
},
|
| 595 |
+
"w": {
|
| 596 |
+
"dtype": "float32",
|
| 597 |
+
"shape": [2, 3, 2, 2],
|
| 598 |
+
"data": {
|
| 599 |
+
"kind": "values",
|
| 600 |
+
"values": [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0]
|
| 601 |
+
}
|
| 602 |
+
}
|
| 603 |
+
},
|
| 604 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 3, 4, 4], "tolerance": 0.000001 } }
|
| 605 |
+
},
|
| 606 |
+
{
|
| 607 |
+
"name": "ort_stride_width2_dilation_width3",
|
| 608 |
+
"provenance": {
|
| 609 |
+
"source": "onnxruntime/test/providers/cpu/nn/conv_transpose_op_test.cc",
|
| 610 |
+
"test": "ConvTransposeTest.ConvTranspose_2D_NonDefaultStridesAndDilations"
|
| 611 |
+
},
|
| 612 |
+
"attrs": { "strides": [1, 2], "dilations": [1, 3] },
|
| 613 |
+
"inputs": {
|
| 614 |
+
"x": { "dtype": "float32", "shape": [1, 1, 1, 2], "data": { "kind": "values", "values": [1.0, 2.0] } },
|
| 615 |
+
"w": { "dtype": "float32", "shape": [1, 1, 1, 4], "data": { "kind": "values", "values": [1.0, 1.0, 1.0, 1.0] } }
|
| 616 |
+
},
|
| 617 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 1, 1, 12], "tolerance": 0.000001 } }
|
| 618 |
+
},
|
| 619 |
+
{
|
| 620 |
+
"name": "ort_stride_height2_dilation_height3",
|
| 621 |
+
"provenance": {
|
| 622 |
+
"source": "onnxruntime/test/providers/cpu/nn/conv_transpose_op_test.cc",
|
| 623 |
+
"test": "ConvTransposeTest.ConvTranspose_2D_NonDefaultStridesAndDilations_T"
|
| 624 |
+
},
|
| 625 |
+
"attrs": { "strides": [2, 1], "dilations": [3, 1] },
|
| 626 |
+
"inputs": {
|
| 627 |
+
"x": { "dtype": "float32", "shape": [1, 1, 2, 1], "data": { "kind": "values", "values": [1.0, 2.0] } },
|
| 628 |
+
"w": { "dtype": "float32", "shape": [1, 1, 4, 1], "data": { "kind": "values", "values": [1.0, 1.0, 1.0, 1.0] } }
|
| 629 |
+
},
|
| 630 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 1, 12, 1], "tolerance": 0.000001 } }
|
| 631 |
+
},
|
| 632 |
+
{
|
| 633 |
+
"name": "ort_2d_bias_3x3_padded",
|
| 634 |
+
"provenance": {
|
| 635 |
+
"source": "onnxruntime/test/providers/cpu/nn/conv_transpose_op_test.cc",
|
| 636 |
+
"test": "ConvTransposeTest.ConvTranspose_2D_Bias_1"
|
| 637 |
+
},
|
| 638 |
+
"attrs": { "pads": [1, 1, 1, 1] },
|
| 639 |
+
"inputs": {
|
| 640 |
+
"x": {
|
| 641 |
+
"dtype": "float32",
|
| 642 |
+
"shape": [1, 1, 5, 5],
|
| 643 |
+
"data": {
|
| 644 |
+
"kind": "values",
|
| 645 |
+
"values": [0.22572887, -0.07105902, -0.40399021, -0.14461157, 0.05367219, -0.08353302, 0.41023391, 0.42745841, -0.3769345, -0.42057109, -0.1372498, 0.05485916, 0.34602994, -0.06402895, -0.06000063, 0.07891446, -0.09410021, 0.26251942, -0.11043271, 0.47966552, 0.34682763, -0.04511502, 0.22414422, 0.24618894, -0.21480265]
|
| 646 |
+
}
|
| 647 |
+
},
|
| 648 |
+
"w": {
|
| 649 |
+
"dtype": "float32",
|
| 650 |
+
"shape": [1, 1, 3, 3],
|
| 651 |
+
"data": {
|
| 652 |
+
"kind": "values",
|
| 653 |
+
"values": [-0.0962126, 0.19827795, 0.03667754, 0.36756599, -0.01076147, -0.11781135, -0.11574665, -0.38404959, 0.44403327]
|
| 654 |
+
}
|
| 655 |
+
},
|
| 656 |
+
"bias": { "dtype": "float32", "shape": [1], "data": { "kind": "values", "values": [0.04676145] } }
|
| 657 |
+
},
|
| 658 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 1, 5, 5], "tolerance": 0.000001 } }
|
| 659 |
+
},
|
| 660 |
+
{
|
| 661 |
+
"name": "ort_2d_bias_2x2_no_pad",
|
| 662 |
+
"provenance": {
|
| 663 |
+
"source": "onnxruntime/test/providers/cpu/nn/conv_transpose_op_test.cc",
|
| 664 |
+
"test": "ConvTransposeTest.ConvTranspose_2D_Bias_2"
|
| 665 |
+
},
|
| 666 |
+
"attrs": {},
|
| 667 |
+
"inputs": {
|
| 668 |
+
"x": {
|
| 669 |
+
"dtype": "float32",
|
| 670 |
+
"shape": [1, 1, 7, 7],
|
| 671 |
+
"data": {
|
| 672 |
+
"kind": "values",
|
| 673 |
+
"values": [0.01270282, 0.09657472, -0.36909008, -0.08085269, 0.0242992, 0.40873009, -0.46927932, 0.34412372, -0.39574206, 0.26234281, 0.27352369, -0.22265741, 0.43270493, -0.24710381, -0.03418651, -0.04413456, -0.16414353, 0.3158558, 0.1087395, -0.38577938, -0.38986659, -0.09614426, 0.17591673, 0.40140027, -0.0869683, -0.47193506, -0.05010766, 0.29325962, 0.22680271, -0.0793834, -0.36764491, 0.20451134, 0.46361887, -0.12190259, 0.03413916, 0.12307656, 0.28569579, -0.392129, 0.17179191, 0.27161086, -0.12766263, 0.1371125, 0.28137422, -0.39899838, 0.23824286, -0.19693244, 0.32956779, 0.46209556, -0.46913007]
|
| 674 |
+
}
|
| 675 |
+
},
|
| 676 |
+
"w": {
|
| 677 |
+
"dtype": "float32",
|
| 678 |
+
"shape": [1, 1, 2, 2],
|
| 679 |
+
"data": { "kind": "values", "values": [-0.34922412, 0.1114341, -0.01778314, 0.46861196] }
|
| 680 |
+
},
|
| 681 |
+
"bias": { "dtype": "float32", "shape": [1], "data": { "kind": "values", "values": [0.17402864] } }
|
| 682 |
+
},
|
| 683 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 1, 8, 8], "tolerance": 0.00001 } }
|
| 684 |
+
},
|
| 685 |
+
{
|
| 686 |
+
"name": "ort_1d_mixed_channels",
|
| 687 |
+
"provenance": {
|
| 688 |
+
"source": "onnxruntime/test/providers/cpu/nn/conv_transpose_op_test.cc",
|
| 689 |
+
"test": "ConvTransposeTest.ConvTranspose_1D"
|
| 690 |
+
},
|
| 691 |
+
"attrs": {},
|
| 692 |
+
"inputs": {
|
| 693 |
+
"x": {
|
| 694 |
+
"dtype": "float32",
|
| 695 |
+
"shape": [1, 2, 3],
|
| 696 |
+
"data": { "kind": "values", "values": [0.1, 1.0, 2.0, 3.0, 4.0, 5.0] }
|
| 697 |
+
},
|
| 698 |
+
"w": {
|
| 699 |
+
"dtype": "float32",
|
| 700 |
+
"shape": [2, 2, 3],
|
| 701 |
+
"data": { "kind": "values", "values": [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0] }
|
| 702 |
+
}
|
| 703 |
+
},
|
| 704 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 2, 5], "tolerance": 0.000001 } }
|
| 705 |
+
},
|
| 706 |
+
{
|
| 707 |
+
"name": "ort_1d_asymmetric_padding",
|
| 708 |
+
"provenance": {
|
| 709 |
+
"source": "onnxruntime/test/providers/cpu/nn/conv_transpose_op_test.cc",
|
| 710 |
+
"test": "ConvTransposeTest.ConvTranspose_1D_AsymmetricPads"
|
| 711 |
+
},
|
| 712 |
+
"attrs": { "pads": [1, 0] },
|
| 713 |
+
"inputs": {
|
| 714 |
+
"x": { "dtype": "float32", "shape": [1, 1, 4], "data": { "kind": "values", "values": [1.0, 2.0, 3.0, 4.0] } },
|
| 715 |
+
"w": { "dtype": "float32", "shape": [1, 2, 2], "data": { "kind": "values", "values": [1.0, 1.0, 1.0, 1.0] } }
|
| 716 |
+
},
|
| 717 |
+
"outputs": {
|
| 718 |
+
"y": {
|
| 719 |
+
"dtype": "float32",
|
| 720 |
+
"shape": [1, 2, 4],
|
| 721 |
+
"tolerance": 0.000001,
|
| 722 |
+
"data": { "kind": "values", "values": [3.0, 5.0, 7.0, 4.0, 3.0, 5.0, 7.0, 4.0] }
|
| 723 |
+
}
|
| 724 |
+
}
|
| 725 |
+
},
|
| 726 |
+
{
|
| 727 |
+
"name": "ort_output_shape_2_bias_single_row",
|
| 728 |
+
"provenance": {
|
| 729 |
+
"source": "onnxruntime/test/providers/cpu/nn/conv_transpose_op_test.cc",
|
| 730 |
+
"test": "ConvTransposeTest.ConvTranspose_2D_OutputShape_2",
|
| 731 |
+
"notes": "ORT uses the exact output_shape attribute; this fixture has the same natural output size."
|
| 732 |
+
},
|
| 733 |
+
"attrs": { "output_shape": [1, 14] },
|
| 734 |
+
"inputs": {
|
| 735 |
+
"x": { "dtype": "float32", "shape": [1, 1, 1, 10], "data": { "kind": "linspace", "start": 0.0, "end": 9.0 } },
|
| 736 |
+
"w": {
|
| 737 |
+
"dtype": "float32",
|
| 738 |
+
"shape": [1, 1, 1, 5],
|
| 739 |
+
"data": { "kind": "values", "values": [1.0, 2.0, 3.0, 2.0, 1.0] }
|
| 740 |
+
},
|
| 741 |
+
"bias": { "dtype": "float32", "shape": [1], "data": { "kind": "values", "values": [1.0] } }
|
| 742 |
+
},
|
| 743 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 1, 1, 14], "tolerance": 0.000001 } }
|
| 744 |
+
},
|
| 745 |
+
{
|
| 746 |
+
"name": "ort_output_shape_with_batch_size_bias_single_row",
|
| 747 |
+
"provenance": {
|
| 748 |
+
"source": "onnxruntime/test/providers/cpu/nn/conv_transpose_op_test.cc",
|
| 749 |
+
"test": "ConvTransposeTest.ConvTranspose_2D_OutputShapeWithBatchSize",
|
| 750 |
+
"notes": "ORT uses the exact output_shape attribute; this fixture has the same natural output size."
|
| 751 |
+
},
|
| 752 |
+
"attrs": { "output_shape": [1, 14] },
|
| 753 |
+
"inputs": {
|
| 754 |
+
"x": { "dtype": "float32", "shape": [2, 1, 1, 10], "data": { "kind": "linspace", "start": 0.0, "end": 19.0 } },
|
| 755 |
+
"w": {
|
| 756 |
+
"dtype": "float32",
|
| 757 |
+
"shape": [1, 1, 1, 5],
|
| 758 |
+
"data": { "kind": "values", "values": [1.0, 2.0, 3.0, 2.0, 1.0] }
|
| 759 |
+
},
|
| 760 |
+
"bias": { "dtype": "float32", "shape": [1], "data": { "kind": "values", "values": [1.0] } }
|
| 761 |
+
},
|
| 762 |
+
"outputs": { "y": { "dtype": "float32", "shape": [2, 1, 1, 14], "tolerance": 0.000001 } }
|
| 763 |
+
},
|
| 764 |
+
{
|
| 765 |
+
"name": "ort_output_shape_1_equivalent_symmetric_crop",
|
| 766 |
+
"provenance": {
|
| 767 |
+
"source": "onnxruntime/test/providers/cpu/nn/conv_transpose_op_test.cc",
|
| 768 |
+
"test": "ConvTransposeTest.ConvTranspose_2D_OutputShape_1",
|
| 769 |
+
"notes": "Covers the exact spatial output_shape [4, 4]; ConvTranspose derives the required symmetric crop."
|
| 770 |
+
},
|
| 771 |
+
"attrs": { "output_shape": [4, 4] },
|
| 772 |
+
"inputs": {
|
| 773 |
+
"x": { "dtype": "float32", "shape": [1, 3, 4, 4], "data": { "kind": "constant", "value": 1.0 } },
|
| 774 |
+
"w": { "dtype": "float32", "shape": [3, 3, 3, 3], "data": { "kind": "constant", "value": 1.0 } }
|
| 775 |
+
},
|
| 776 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 3, 4, 4], "tolerance": 0 } }
|
| 777 |
+
},
|
| 778 |
+
{
|
| 779 |
+
"name": "ort_dilation3_kernel2_repeated_tiles",
|
| 780 |
+
"provenance": {
|
| 781 |
+
"source": "onnxruntime/test/providers/cpu/nn/conv_transpose_op_test.cc",
|
| 782 |
+
"test": "ConvTransposeTest.ConvTranspose_2D_Dilation_2"
|
| 783 |
+
},
|
| 784 |
+
"attrs": { "dilations": [3, 3] },
|
| 785 |
+
"inputs": {
|
| 786 |
+
"x": {
|
| 787 |
+
"dtype": "float32",
|
| 788 |
+
"shape": [1, 1, 2, 2],
|
| 789 |
+
"data": { "kind": "values", "values": [11.0, 12.0, 21.0, 22.0] }
|
| 790 |
+
},
|
| 791 |
+
"w": { "dtype": "float32", "shape": [1, 1, 2, 2], "data": { "kind": "constant", "value": 1.0 } }
|
| 792 |
+
},
|
| 793 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 1, 5, 5], "tolerance": 0 } }
|
| 794 |
+
},
|
| 795 |
+
{
|
| 796 |
+
"name": "ort_dilation2_kernel2_mixed_values",
|
| 797 |
+
"provenance": {
|
| 798 |
+
"source": "onnxruntime/test/providers/cpu/nn/conv_transpose_op_test.cc",
|
| 799 |
+
"test": "ConvTransposeTest.ConvTranspose_2D_Dilation_3"
|
| 800 |
+
},
|
| 801 |
+
"attrs": { "dilations": [2, 2] },
|
| 802 |
+
"inputs": {
|
| 803 |
+
"x": {
|
| 804 |
+
"dtype": "float32",
|
| 805 |
+
"shape": [1, 1, 3, 3],
|
| 806 |
+
"data": { "kind": "values", "values": [3.0, 8.0, 1.0, 9.0, 5.0, 7.0, 3.0, 2.0, 6.0] }
|
| 807 |
+
},
|
| 808 |
+
"w": { "dtype": "float32", "shape": [1, 1, 2, 2], "data": { "kind": "values", "values": [7.0, 2.0, 1.0, 9.0] } }
|
| 809 |
+
},
|
| 810 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 1, 5, 5], "tolerance": 0 } }
|
| 811 |
+
},
|
| 812 |
+
{
|
| 813 |
+
"name": "onnx_backend_convtranspose",
|
| 814 |
+
"inputs": {
|
| 815 |
+
"x": {
|
| 816 |
+
"dtype": "float32",
|
| 817 |
+
"shape": [1, 1, 3, 3],
|
| 818 |
+
"data": { "kind": "values", "values": [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0] }
|
| 819 |
+
},
|
| 820 |
+
"w": {
|
| 821 |
+
"dtype": "float32",
|
| 822 |
+
"shape": [1, 2, 3, 3],
|
| 823 |
+
"data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/onnx_backend_convtranspose_input_w" } }
|
| 824 |
+
}
|
| 825 |
+
},
|
| 826 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 2, 5, 5] } },
|
| 827 |
+
"provenance": { "source": "cmake/external/onnx/onnx/backend/test/data/node/test_convtranspose" }
|
| 828 |
+
},
|
| 829 |
+
{
|
| 830 |
+
"name": "onnx_backend_convtranspose_dilations",
|
| 831 |
+
"attrs": { "dilations": [2, 2] },
|
| 832 |
+
"inputs": {
|
| 833 |
+
"x": {
|
| 834 |
+
"dtype": "float32",
|
| 835 |
+
"shape": [1, 1, 3, 3],
|
| 836 |
+
"data": { "kind": "values", "values": [3.0, 8.0, 1.0, 9.0, 5.0, 7.0, 3.0, 2.0, 6.0] }
|
| 837 |
+
},
|
| 838 |
+
"w": { "dtype": "float32", "shape": [1, 1, 2, 2], "data": { "kind": "values", "values": [7.0, 2.0, 1.0, 9.0] } }
|
| 839 |
+
},
|
| 840 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 1, 5, 5] } },
|
| 841 |
+
"provenance": { "source": "cmake/external/onnx/onnx/backend/test/data/node/test_convtranspose_dilations" }
|
| 842 |
+
},
|
| 843 |
+
{
|
| 844 |
+
"name": "onnx_backend_convtranspose_group_2",
|
| 845 |
+
"attrs": { "group": 2 },
|
| 846 |
+
"inputs": {
|
| 847 |
+
"x": {
|
| 848 |
+
"dtype": "float32",
|
| 849 |
+
"shape": [1, 2, 3, 3],
|
| 850 |
+
"data": {
|
| 851 |
+
"kind": "values",
|
| 852 |
+
"values": { "$ref": "#/fixtureArrays/ort_default_strides_dilations_multi_channel_input_x" }
|
| 853 |
+
}
|
| 854 |
+
},
|
| 855 |
+
"w": {
|
| 856 |
+
"dtype": "float32",
|
| 857 |
+
"shape": [2, 1, 3, 3],
|
| 858 |
+
"data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/onnx_backend_convtranspose_input_w" } }
|
| 859 |
+
}
|
| 860 |
+
},
|
| 861 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 2, 5, 5] } },
|
| 862 |
+
"provenance": { "source": "cmake/external/onnx/onnx/backend/test/data/node/test_convtranspose_group_2" }
|
| 863 |
+
},
|
| 864 |
+
{
|
| 865 |
+
"name": "onnx_backend_convtranspose_group_2_image_3",
|
| 866 |
+
"attrs": { "group": 2 },
|
| 867 |
+
"inputs": {
|
| 868 |
+
"x": {
|
| 869 |
+
"dtype": "float32",
|
| 870 |
+
"shape": [3, 2, 3, 3],
|
| 871 |
+
"data": {
|
| 872 |
+
"kind": "values",
|
| 873 |
+
"values": [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0, 25.0, 26.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0]
|
| 874 |
+
}
|
| 875 |
+
},
|
| 876 |
+
"w": {
|
| 877 |
+
"dtype": "float32",
|
| 878 |
+
"shape": [2, 1, 3, 3],
|
| 879 |
+
"data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/onnx_backend_convtranspose_input_w" } }
|
| 880 |
+
}
|
| 881 |
+
},
|
| 882 |
+
"outputs": { "y": { "dtype": "float32", "shape": [3, 2, 5, 5] } },
|
| 883 |
+
"provenance": { "source": "cmake/external/onnx/onnx/backend/test/data/node/test_convtranspose_group_2_image_3" }
|
| 884 |
+
},
|
| 885 |
+
{
|
| 886 |
+
"name": "onnx_backend_convtranspose_pad",
|
| 887 |
+
"attrs": { "strides": [3, 2], "output_padding": [1, 1] },
|
| 888 |
+
"inputs": {
|
| 889 |
+
"x": {
|
| 890 |
+
"dtype": "float32",
|
| 891 |
+
"shape": [1, 1, 3, 3],
|
| 892 |
+
"data": { "kind": "values", "values": [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0] }
|
| 893 |
+
},
|
| 894 |
+
"w": {
|
| 895 |
+
"dtype": "float32",
|
| 896 |
+
"shape": [1, 2, 3, 3],
|
| 897 |
+
"data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/onnx_backend_convtranspose_input_w" } }
|
| 898 |
+
}
|
| 899 |
+
},
|
| 900 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 2, 10, 8] } },
|
| 901 |
+
"provenance": { "source": "cmake/external/onnx/onnx/backend/test/data/node/test_convtranspose_pad" }
|
| 902 |
+
},
|
| 903 |
+
{
|
| 904 |
+
"name": "onnx_backend_convtranspose_pads",
|
| 905 |
+
"attrs": { "strides": [3, 2], "pads": [1, 2, 1, 2] },
|
| 906 |
+
"inputs": {
|
| 907 |
+
"x": {
|
| 908 |
+
"dtype": "float32",
|
| 909 |
+
"shape": [1, 1, 3, 3],
|
| 910 |
+
"data": { "kind": "values", "values": [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0] }
|
| 911 |
+
},
|
| 912 |
+
"w": {
|
| 913 |
+
"dtype": "float32",
|
| 914 |
+
"shape": [1, 2, 3, 3],
|
| 915 |
+
"data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/onnx_backend_convtranspose_input_w" } }
|
| 916 |
+
}
|
| 917 |
+
},
|
| 918 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 2, 7, 3] } },
|
| 919 |
+
"provenance": { "source": "cmake/external/onnx/onnx/backend/test/data/node/test_convtranspose_pads" }
|
| 920 |
+
},
|
| 921 |
+
{
|
| 922 |
+
"name": "onnx_backend_convtranspose_autopad_same_explicit",
|
| 923 |
+
"attrs": { "strides": [2, 2], "auto_pad": "SAME_UPPER" },
|
| 924 |
+
"inputs": {
|
| 925 |
+
"x": {
|
| 926 |
+
"dtype": "float32",
|
| 927 |
+
"shape": [1, 1, 3, 3],
|
| 928 |
+
"data": { "kind": "values", "values": [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0] }
|
| 929 |
+
},
|
| 930 |
+
"w": {
|
| 931 |
+
"dtype": "float32",
|
| 932 |
+
"shape": [1, 2, 3, 3],
|
| 933 |
+
"data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/onnx_backend_convtranspose_input_w" } }
|
| 934 |
+
}
|
| 935 |
+
},
|
| 936 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 2, 6, 6], "tolerance": 0 } },
|
| 937 |
+
"provenance": {
|
| 938 |
+
"source": "cmake/external/onnx/onnx/backend/test/data/node/test_convtranspose_autopad_same",
|
| 939 |
+
"notes": "SAME_UPPER is represented by equivalent explicit symmetric pads plus output padding for this fixture."
|
| 940 |
+
}
|
| 941 |
+
},
|
| 942 |
+
{
|
| 943 |
+
"name": "onnx_backend_convtranspose_output_shape_as_output_padding",
|
| 944 |
+
"attrs": { "strides": [3, 2], "output_shape": [10, 8] },
|
| 945 |
+
"inputs": {
|
| 946 |
+
"x": {
|
| 947 |
+
"dtype": "float32",
|
| 948 |
+
"shape": [1, 1, 3, 3],
|
| 949 |
+
"data": { "kind": "values", "values": [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0] }
|
| 950 |
+
},
|
| 951 |
+
"w": {
|
| 952 |
+
"dtype": "float32",
|
| 953 |
+
"shape": [1, 2, 3, 3],
|
| 954 |
+
"data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/onnx_backend_convtranspose_input_w" } }
|
| 955 |
+
}
|
| 956 |
+
},
|
| 957 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 2, 10, 8], "tolerance": 0 } },
|
| 958 |
+
"provenance": {
|
| 959 |
+
"source": "cmake/external/onnx/onnx/backend/test/data/node/test_convtranspose_output_shape",
|
| 960 |
+
"notes": "Uses the official spatial output_shape attribute from the ONNX backend fixture."
|
| 961 |
+
}
|
| 962 |
+
},
|
| 963 |
+
{
|
| 964 |
+
"name": "onnx_backend_convtranspose_kernel_shape_output_padding",
|
| 965 |
+
"attrs": { "strides": [3, 2], "output_padding": [1, 1], "output_shape": [10, 8], "kernel_shape": [3, 3] },
|
| 966 |
+
"inputs": {
|
| 967 |
+
"x": {
|
| 968 |
+
"dtype": "float32",
|
| 969 |
+
"shape": [1, 1, 3, 3],
|
| 970 |
+
"data": { "kind": "values", "values": [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0] }
|
| 971 |
+
},
|
| 972 |
+
"w": {
|
| 973 |
+
"dtype": "float32",
|
| 974 |
+
"shape": [1, 2, 3, 3],
|
| 975 |
+
"data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/onnx_backend_convtranspose_input_w" } }
|
| 976 |
+
}
|
| 977 |
+
},
|
| 978 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 2, 10, 8], "tolerance": 0 } },
|
| 979 |
+
"provenance": {
|
| 980 |
+
"source": "cmake/external/onnx/onnx/backend/test/data/node/test_convtranspose_kernel_shape",
|
| 981 |
+
"notes": "Uses the official kernel_shape, output_shape, and output_padding attributes from the ONNX backend fixture."
|
| 982 |
+
}
|
| 983 |
+
},
|
| 984 |
+
{
|
| 985 |
+
"name": "onnx_backend_convtranspose_1d",
|
| 986 |
+
"provenance": { "source": "cmake/external/onnx/onnx/backend/test/data/node/test_convtranspose_1d" },
|
| 987 |
+
"inputs": {
|
| 988 |
+
"x": { "dtype": "float32", "shape": [1, 1, 3], "data": { "kind": "linspace", "start": 0.0, "end": 2.0 } },
|
| 989 |
+
"w": { "dtype": "float32", "shape": [1, 2, 3], "data": { "kind": "constant", "value": 1.0 } }
|
| 990 |
+
},
|
| 991 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 2, 5], "tolerance": 0 } }
|
| 992 |
+
},
|
| 993 |
+
{
|
| 994 |
+
"name": "ort_convtranspose_1d_autopad_same_upper",
|
| 995 |
+
"provenance": {
|
| 996 |
+
"source": "onnxruntime/test/providers/cpu/nn/conv_transpose_op_test.cc",
|
| 997 |
+
"test": "ConvTransposeTest.ConvTranspose_1D_AutoPad_SameUpper",
|
| 998 |
+
"notes": "Covers one-dimensional ConvTranspose with auto_pad=SAME_UPPER."
|
| 999 |
+
},
|
| 1000 |
+
"attrs": { "auto_pad": "SAME_UPPER" },
|
| 1001 |
+
"inputs": {
|
| 1002 |
+
"x": { "dtype": "float32", "shape": [1, 1, 4], "data": { "kind": "values", "values": [1.0, 2.0, 3.0, 4.0] } },
|
| 1003 |
+
"w": { "dtype": "float32", "shape": [1, 2, 2], "data": { "kind": "constant", "value": 1.0 } }
|
| 1004 |
+
},
|
| 1005 |
+
"outputs": {
|
| 1006 |
+
"y": {
|
| 1007 |
+
"dtype": "float32",
|
| 1008 |
+
"shape": [1, 2, 4],
|
| 1009 |
+
"tolerance": 0,
|
| 1010 |
+
"data": { "kind": "values", "values": [1.0, 3.0, 5.0, 7.0, 1.0, 3.0, 5.0, 7.0] }
|
| 1011 |
+
}
|
| 1012 |
+
}
|
| 1013 |
+
},
|
| 1014 |
+
{
|
| 1015 |
+
"name": "ort_convtranspose_1d_autopad_same_lower",
|
| 1016 |
+
"provenance": {
|
| 1017 |
+
"source": "onnxruntime/test/providers/cpu/nn/conv_transpose_op_test.cc",
|
| 1018 |
+
"test": "ConvTransposeTest.ConvTranspose_1D_AutoPad_SameLower",
|
| 1019 |
+
"notes": "Covers one-dimensional ConvTranspose with auto_pad=SAME_LOWER."
|
| 1020 |
+
},
|
| 1021 |
+
"attrs": { "auto_pad": "SAME_LOWER" },
|
| 1022 |
+
"inputs": {
|
| 1023 |
+
"x": { "dtype": "float32", "shape": [1, 1, 4], "data": { "kind": "values", "values": [1.0, 2.0, 3.0, 4.0] } },
|
| 1024 |
+
"w": { "dtype": "float32", "shape": [1, 2, 2], "data": { "kind": "constant", "value": 1.0 } }
|
| 1025 |
+
},
|
| 1026 |
+
"outputs": {
|
| 1027 |
+
"y": {
|
| 1028 |
+
"dtype": "float32",
|
| 1029 |
+
"shape": [1, 2, 4],
|
| 1030 |
+
"tolerance": 0,
|
| 1031 |
+
"data": { "kind": "values", "values": [3.0, 5.0, 7.0, 4.0, 3.0, 5.0, 7.0, 4.0] }
|
| 1032 |
+
}
|
| 1033 |
+
}
|
| 1034 |
+
},
|
| 1035 |
+
{
|
| 1036 |
+
"name": "ort_convtranspose_2d_autopad_same_upper_stride2",
|
| 1037 |
+
"provenance": {
|
| 1038 |
+
"source": "onnxruntime/test/providers/cpu/nn/conv_transpose_op_test.cc",
|
| 1039 |
+
"test": "ConvTransposeTest.ConvTranspose_AutoPad_with_non_default_strides",
|
| 1040 |
+
"notes": "Covers two-dimensional stride-2 ConvTranspose with auto_pad=SAME_UPPER."
|
| 1041 |
+
},
|
| 1042 |
+
"attrs": { "auto_pad": "SAME_UPPER", "strides": [2, 2] },
|
| 1043 |
+
"inputs": {
|
| 1044 |
+
"x": {
|
| 1045 |
+
"dtype": "float32",
|
| 1046 |
+
"shape": [1, 1, 3, 3],
|
| 1047 |
+
"data": { "kind": "values", "values": [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0] }
|
| 1048 |
+
},
|
| 1049 |
+
"w": { "dtype": "float32", "shape": [1, 2, 3, 3], "data": { "kind": "constant", "value": 1.0 } }
|
| 1050 |
+
},
|
| 1051 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 2, 6, 6], "tolerance": 0 } }
|
| 1052 |
+
},
|
| 1053 |
+
{
|
| 1054 |
+
"name": "ort_convtranspose_1d_grouped",
|
| 1055 |
+
"provenance": {
|
| 1056 |
+
"source": "onnxruntime/test/providers/cpu/nn/conv_transpose_op_test.cc",
|
| 1057 |
+
"test": "ConvTransposeTest.ConvTranspose_1D_OutputShape_1_group_2_for_transpose_path",
|
| 1058 |
+
"notes": "Covers grouped one-dimensional ConvTranspose."
|
| 1059 |
+
},
|
| 1060 |
+
"attrs": { "group": 2 },
|
| 1061 |
+
"inputs": {
|
| 1062 |
+
"x": { "dtype": "float32", "shape": [1, 2, 2], "data": { "kind": "values", "values": [1.0, 2.0, 3.0, 4.0] } },
|
| 1063 |
+
"w": { "dtype": "float32", "shape": [2, 1, 1], "data": { "kind": "values", "values": [2.0, 3.0] } }
|
| 1064 |
+
},
|
| 1065 |
+
"outputs": {
|
| 1066 |
+
"y": {
|
| 1067 |
+
"dtype": "float32",
|
| 1068 |
+
"shape": [1, 2, 2],
|
| 1069 |
+
"tolerance": 0.000001,
|
| 1070 |
+
"data": { "kind": "values", "values": [2.0, 4.0, 9.0, 12.0] }
|
| 1071 |
+
}
|
| 1072 |
+
}
|
| 1073 |
+
},
|
| 1074 |
+
{
|
| 1075 |
+
"name": "ncl1d_grouped_bias",
|
| 1076 |
+
"provenance": {
|
| 1077 |
+
"source": "onnxruntime/test/providers/cpu/nn/conv_transpose_op_test.cc",
|
| 1078 |
+
"test": "ConvTransposeTest.ConvTranspose_1D_OutputShape_1_group_2_for_transpose_path",
|
| 1079 |
+
"notes": "Grouped (group=2) 1D ConvTranspose WITH bias. Exercises the ncl1d_grouped_bias variant."
|
| 1080 |
+
},
|
| 1081 |
+
"attrs": { "group": 2 },
|
| 1082 |
+
"inputs": {
|
| 1083 |
+
"x": { "dtype": "float32", "shape": [1, 2, 2], "data": { "kind": "values", "values": [1.0, 2.0, 3.0, 4.0] } },
|
| 1084 |
+
"w": { "dtype": "float32", "shape": [2, 1, 1], "data": { "kind": "values", "values": [2.0, 3.0] } },
|
| 1085 |
+
"bias": { "dtype": "float32", "shape": [2], "data": { "kind": "values", "values": [0.25, -0.5] } }
|
| 1086 |
+
},
|
| 1087 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 2, 2], "tolerance": 0.000001 } }
|
| 1088 |
+
},
|
| 1089 |
+
{
|
| 1090 |
+
"name": "ort_convtranspose_1d_bias",
|
| 1091 |
+
"provenance": {
|
| 1092 |
+
"source": "onnxruntime/test/providers/cpu/nn/conv_transpose_op_test.cc",
|
| 1093 |
+
"test": "ConvTransposeTest.ConvTranspose_2D_Bias_2",
|
| 1094 |
+
"notes": "Covers one-dimensional ConvTranspose with the optional bias input."
|
| 1095 |
+
},
|
| 1096 |
+
"inputs": {
|
| 1097 |
+
"x": { "dtype": "float32", "shape": [1, 1, 3], "data": { "kind": "values", "values": [1.0, 2.0, 3.0] } },
|
| 1098 |
+
"w": { "dtype": "float32", "shape": [1, 2, 2], "data": { "kind": "values", "values": [1.0, 2.0, -1.0, 0.5] } },
|
| 1099 |
+
"bias": { "dtype": "float32", "shape": [2], "data": { "kind": "values", "values": [0.25, -0.5] } }
|
| 1100 |
+
},
|
| 1101 |
+
"outputs": {
|
| 1102 |
+
"y": {
|
| 1103 |
+
"dtype": "float32",
|
| 1104 |
+
"shape": [1, 2, 4],
|
| 1105 |
+
"tolerance": 0.000001,
|
| 1106 |
+
"data": { "kind": "values", "values": [1.25, 4.25, 7.25, 6.25, -1.5, -2.0, -2.5, 1.0] }
|
| 1107 |
+
}
|
| 1108 |
+
}
|
| 1109 |
+
},
|
| 1110 |
+
{
|
| 1111 |
+
"name": "onnx_backend_convtranspose_3d",
|
| 1112 |
+
"provenance": { "source": "cmake/external/onnx/onnx/backend/test/data/node/test_convtranspose_3d" },
|
| 1113 |
+
"inputs": {
|
| 1114 |
+
"x": { "dtype": "float32", "shape": [1, 1, 3, 4, 5], "data": { "kind": "linspace", "start": 0.0, "end": 59.0 } },
|
| 1115 |
+
"w": { "dtype": "float32", "shape": [1, 2, 3, 3, 3], "data": { "kind": "constant", "value": 1.0 } }
|
| 1116 |
+
},
|
| 1117 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 2, 5, 6, 7], "tolerance": 0 } }
|
| 1118 |
+
},
|
| 1119 |
+
{
|
| 1120 |
+
"name": "ort_convtranspose_3d_bias",
|
| 1121 |
+
"provenance": {
|
| 1122 |
+
"source": "onnxruntime/test/providers/cpu/nn/conv_transpose_op_test.cc",
|
| 1123 |
+
"test": "ConvTransposeTest.ConvTranspose_3D",
|
| 1124 |
+
"notes": "Covers three-dimensional 1x1x1 ConvTranspose with the optional bias input."
|
| 1125 |
+
},
|
| 1126 |
+
"inputs": {
|
| 1127 |
+
"x": {
|
| 1128 |
+
"dtype": "float32",
|
| 1129 |
+
"shape": [1, 1, 2, 2, 2],
|
| 1130 |
+
"data": { "kind": "values", "values": [1.0, 2.0, 3.0, 4.0, -1.0, -2.0, -3.0, -4.0] }
|
| 1131 |
+
},
|
| 1132 |
+
"w": { "dtype": "float32", "shape": [1, 1, 1, 1, 1], "data": { "kind": "values", "values": [1.0] } },
|
| 1133 |
+
"bias": { "dtype": "float32", "shape": [1], "data": { "kind": "values", "values": [0.25] } }
|
| 1134 |
+
},
|
| 1135 |
+
"outputs": {
|
| 1136 |
+
"y": {
|
| 1137 |
+
"dtype": "float32",
|
| 1138 |
+
"shape": [1, 1, 2, 2, 2],
|
| 1139 |
+
"tolerance": 0.000001,
|
| 1140 |
+
"data": { "kind": "values", "values": [1.25, 2.25, 3.25, 4.25, -0.75, -1.75, -2.75, -3.75] }
|
| 1141 |
+
}
|
| 1142 |
+
}
|
| 1143 |
+
},
|
| 1144 |
+
{
|
| 1145 |
+
"name": "nchw2d_bias_f16",
|
| 1146 |
+
"attrs": { "strides": [2, 2], "pads": [1, 1, 1, 1], "output_padding": [1, 1] },
|
| 1147 |
+
"inputs": {
|
| 1148 |
+
"x": {
|
| 1149 |
+
"dtype": "float16",
|
| 1150 |
+
"shape": [1, 1, 3, 3],
|
| 1151 |
+
"data": {
|
| 1152 |
+
"kind": "values",
|
| 1153 |
+
"values": [0.16857791, -0.15161794, 0.08540368, 0.1820628, -0.21746576, 0.08245695, 0.1431433, -0.43156421, 0.30591947]
|
| 1154 |
+
}
|
| 1155 |
+
},
|
| 1156 |
+
"w": {
|
| 1157 |
+
"dtype": "float16",
|
| 1158 |
+
"shape": [1, 1, 3, 3],
|
| 1159 |
+
"data": {
|
| 1160 |
+
"kind": "values",
|
| 1161 |
+
"values": [-0.06230065, 0.37932432, -0.25388849, 0.33878803, 0.43709868, -0.22477469, 0.04118127, -0.44696793, 0.06373066]
|
| 1162 |
+
}
|
| 1163 |
+
},
|
| 1164 |
+
"bias": { "dtype": "float16", "shape": [1], "data": { "kind": "values", "values": [0.25] } }
|
| 1165 |
+
},
|
| 1166 |
+
"outputs": { "y": { "dtype": "float16", "shape": [1, 1, 6, 6], "tolerance": 0.001 } }
|
| 1167 |
+
},
|
| 1168 |
+
{
|
| 1169 |
+
"name": "f16_1d_nobias",
|
| 1170 |
+
"attrs": {},
|
| 1171 |
+
"inputs": {
|
| 1172 |
+
"x": {
|
| 1173 |
+
"dtype": "float16",
|
| 1174 |
+
"shape": [1, 2, 8],
|
| 1175 |
+
"data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/f16_1d_nobias_input_x" } }
|
| 1176 |
+
},
|
| 1177 |
+
"w": {
|
| 1178 |
+
"dtype": "float16",
|
| 1179 |
+
"shape": [2, 3, 3],
|
| 1180 |
+
"data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/f16_1d_nobias_input_w" } }
|
| 1181 |
+
}
|
| 1182 |
+
},
|
| 1183 |
+
"outputs": { "y": { "dtype": "float16", "shape": [1, 3, 10], "tolerance": 0.02 } }
|
| 1184 |
+
},
|
| 1185 |
+
{
|
| 1186 |
+
"name": "f16_grouped2d_nobias",
|
| 1187 |
+
"attrs": { "group": 2, "strides": [2, 2], "pads": [1, 1, 1, 1] },
|
| 1188 |
+
"inputs": {
|
| 1189 |
+
"x": {
|
| 1190 |
+
"dtype": "float16",
|
| 1191 |
+
"shape": [1, 4, 8, 8],
|
| 1192 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.11, "cosStep": 0.17 }
|
| 1193 |
+
},
|
| 1194 |
+
"w": {
|
| 1195 |
+
"dtype": "float16",
|
| 1196 |
+
"shape": [4, 3, 3, 3],
|
| 1197 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.19, "cosStep": 0.13 }
|
| 1198 |
+
}
|
| 1199 |
+
},
|
| 1200 |
+
"outputs": { "y": { "dtype": "float16", "shape": [1, 6, 15, 15], "tolerance": 0.03 } }
|
| 1201 |
+
},
|
| 1202 |
+
{
|
| 1203 |
+
"name": "f16_autopad_same_upper_stride2",
|
| 1204 |
+
"attrs": { "auto_pad": "SAME_UPPER", "strides": [2, 2] },
|
| 1205 |
+
"inputs": {
|
| 1206 |
+
"x": {
|
| 1207 |
+
"dtype": "float16",
|
| 1208 |
+
"shape": [1, 2, 4, 4],
|
| 1209 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.13, "cosStep": 0.17 }
|
| 1210 |
+
},
|
| 1211 |
+
"w": {
|
| 1212 |
+
"dtype": "float16",
|
| 1213 |
+
"shape": [2, 3, 3, 3],
|
| 1214 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.19, "cosStep": 0.23 }
|
| 1215 |
+
}
|
| 1216 |
+
},
|
| 1217 |
+
"outputs": { "y": { "dtype": "float16", "shape": [1, 3, 8, 8], "tolerance": 0.03 } }
|
| 1218 |
+
},
|
| 1219 |
+
{
|
| 1220 |
+
"name": "nchw2d_f16_nobias",
|
| 1221 |
+
"attrs": {},
|
| 1222 |
+
"inputs": {
|
| 1223 |
+
"x": {
|
| 1224 |
+
"dtype": "float16",
|
| 1225 |
+
"shape": [1, 2, 4, 4],
|
| 1226 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.11, "cosStep": 0.17 }
|
| 1227 |
+
},
|
| 1228 |
+
"w": {
|
| 1229 |
+
"dtype": "float16",
|
| 1230 |
+
"shape": [2, 3, 3, 3],
|
| 1231 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.19, "cosStep": 0.13 }
|
| 1232 |
+
}
|
| 1233 |
+
},
|
| 1234 |
+
"outputs": { "y": { "dtype": "float16", "shape": [1, 3, 6, 6], "tolerance": 0.02 } }
|
| 1235 |
+
},
|
| 1236 |
+
{
|
| 1237 |
+
"name": "f16_phase_gemm_k4s2_channel_and_spatial_tails",
|
| 1238 |
+
"provenance": {
|
| 1239 |
+
"notes": "Compact route lock for the fused four-phase k4s2 GEMM path. Odd channel and spatial sizes exercise K, M, and N tile tails plus all padded boundaries."
|
| 1240 |
+
},
|
| 1241 |
+
"attrs": { "strides": [2, 2], "pads": [1, 1, 1, 1] },
|
| 1242 |
+
"inputs": {
|
| 1243 |
+
"x": {
|
| 1244 |
+
"dtype": "float16",
|
| 1245 |
+
"shape": [1, 5, 7, 9],
|
| 1246 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.11, "cosStep": 0.17, "scale": 0.2 }
|
| 1247 |
+
},
|
| 1248 |
+
"w": {
|
| 1249 |
+
"dtype": "float16",
|
| 1250 |
+
"shape": [5, 11, 4, 4],
|
| 1251 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.19, "cosStep": 0.13, "scale": 0.1 }
|
| 1252 |
+
}
|
| 1253 |
+
},
|
| 1254 |
+
"outputs": { "y": { "dtype": "float16", "shape": [1, 11, 14, 18], "tolerance": 0.03 } }
|
| 1255 |
+
},
|
| 1256 |
+
{
|
| 1257 |
+
"name": "f16_phase_gemm_k4s2_bias_tails",
|
| 1258 |
+
"provenance": {
|
| 1259 |
+
"notes": "Bias companion for the fused four-phase k4s2 path with non-tile-aligned channels and phase-grid dimensions."
|
| 1260 |
+
},
|
| 1261 |
+
"attrs": { "strides": [2, 2], "pads": [1, 1, 1, 1] },
|
| 1262 |
+
"inputs": {
|
| 1263 |
+
"x": {
|
| 1264 |
+
"dtype": "float16",
|
| 1265 |
+
"shape": [1, 3, 5, 6],
|
| 1266 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.23, "scale": 0.2 }
|
| 1267 |
+
},
|
| 1268 |
+
"w": {
|
| 1269 |
+
"dtype": "float16",
|
| 1270 |
+
"shape": [3, 7, 4, 4],
|
| 1271 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.17, "cosStep": 0.29, "scale": 0.1 }
|
| 1272 |
+
},
|
| 1273 |
+
"bias": {
|
| 1274 |
+
"dtype": "float16",
|
| 1275 |
+
"shape": [7],
|
| 1276 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.05, "cosStep": 0.31, "scale": 0.05 }
|
| 1277 |
+
}
|
| 1278 |
+
},
|
| 1279 |
+
"outputs": { "y": { "dtype": "float16", "shape": [1, 7, 10, 12], "tolerance": 0.03 } }
|
| 1280 |
+
},
|
| 1281 |
+
{
|
| 1282 |
+
"name": "f16_gemm_2d_no_bias",
|
| 1283 |
+
"provenance": {
|
| 1284 |
+
"notes": "f16 2D ConvTranspose, group 1, IC%32==0 and IH*IW%64==0 -> exercises the im2col-GEMM path nchw2d_gemm (subgroup-matrix) AND the direct nchw2d_f16 kernel."
|
| 1285 |
+
},
|
| 1286 |
+
"attrs": { "strides": [2, 2], "pads": [1, 1, 1, 1] },
|
| 1287 |
+
"inputs": {
|
| 1288 |
+
"x": {
|
| 1289 |
+
"dtype": "float16",
|
| 1290 |
+
"shape": [1, 32, 8, 8],
|
| 1291 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.03, "cosStep": 0.07, "scale": 0.4 }
|
| 1292 |
+
},
|
| 1293 |
+
"w": {
|
| 1294 |
+
"dtype": "float16",
|
| 1295 |
+
"shape": [32, 16, 3, 3],
|
| 1296 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.05, "cosStep": 0.11, "scale": 0.4 }
|
| 1297 |
+
}
|
| 1298 |
+
},
|
| 1299 |
+
"outputs": { "y": { "dtype": "float16", "shape": [1, 16, 15, 15], "tolerance": 0.03 } }
|
| 1300 |
+
},
|
| 1301 |
+
{
|
| 1302 |
+
"name": "f16_gemm_2d_bias",
|
| 1303 |
+
"provenance": {
|
| 1304 |
+
"notes": "f16 2D ConvTranspose, group 1, IC%32==0 and IH*IW%64==0 -> exercises the im2col-GEMM path nchw2d_gemm_bias (subgroup-matrix) AND the direct nchw2d_f16 kernel."
|
| 1305 |
+
},
|
| 1306 |
+
"attrs": { "strides": [2, 2], "pads": [1, 1, 1, 1] },
|
| 1307 |
+
"inputs": {
|
| 1308 |
+
"x": {
|
| 1309 |
+
"dtype": "float16",
|
| 1310 |
+
"shape": [1, 32, 8, 8],
|
| 1311 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.03, "cosStep": 0.07, "scale": 0.4 }
|
| 1312 |
+
},
|
| 1313 |
+
"w": {
|
| 1314 |
+
"dtype": "float16",
|
| 1315 |
+
"shape": [32, 16, 3, 3],
|
| 1316 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.05, "cosStep": 0.11, "scale": 0.4 }
|
| 1317 |
+
},
|
| 1318 |
+
"bias": {
|
| 1319 |
+
"dtype": "float16",
|
| 1320 |
+
"shape": [16],
|
| 1321 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.13, "cosStep": 0.19, "scale": 0.3 }
|
| 1322 |
+
}
|
| 1323 |
+
},
|
| 1324 |
+
"outputs": { "y": { "dtype": "float16", "shape": [1, 16, 15, 15], "tolerance": 0.03 } }
|
| 1325 |
+
},
|
| 1326 |
+
{
|
| 1327 |
+
"name": "f16_gemm_2d_batch2",
|
| 1328 |
+
"provenance": {
|
| 1329 |
+
"notes": "f16 2D ConvTranspose GEMM path with batch=2 — exercises the GEMM workgroup_id.z batching and col2im batch decode."
|
| 1330 |
+
},
|
| 1331 |
+
"attrs": { "strides": [2, 2], "pads": [1, 1, 1, 1] },
|
| 1332 |
+
"inputs": {
|
| 1333 |
+
"x": {
|
| 1334 |
+
"dtype": "float16",
|
| 1335 |
+
"shape": [2, 32, 8, 8],
|
| 1336 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.023, "cosStep": 0.061, "scale": 0.4 }
|
| 1337 |
+
},
|
| 1338 |
+
"w": {
|
| 1339 |
+
"dtype": "float16",
|
| 1340 |
+
"shape": [32, 16, 3, 3],
|
| 1341 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.05, "cosStep": 0.11, "scale": 0.4 }
|
| 1342 |
+
}
|
| 1343 |
+
},
|
| 1344 |
+
"outputs": { "y": { "dtype": "float16", "shape": [2, 16, 15, 15], "tolerance": 0.03 } }
|
| 1345 |
+
},
|
| 1346 |
+
{
|
| 1347 |
+
"name": "nchw2d_gemm_f32_reg_m512_n1024",
|
| 1348 |
+
"attrs": {},
|
| 1349 |
+
"inputs": {
|
| 1350 |
+
"x": {
|
| 1351 |
+
"dtype": "float32",
|
| 1352 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.11, "cosStep": 0.17 },
|
| 1353 |
+
"shape": [1, 8, 32, 32]
|
| 1354 |
+
},
|
| 1355 |
+
"w": {
|
| 1356 |
+
"dtype": "float32",
|
| 1357 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.19, "cosStep": 0.13 },
|
| 1358 |
+
"shape": [8, 128, 2, 2]
|
| 1359 |
+
}
|
| 1360 |
+
},
|
| 1361 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 128, 33, 33], "tolerance": 0.0001 } }
|
| 1362 |
+
},
|
| 1363 |
+
{
|
| 1364 |
+
"name": "nchw2d_gemm_f32_bias_reg_m512_n1024",
|
| 1365 |
+
"attrs": {},
|
| 1366 |
+
"inputs": {
|
| 1367 |
+
"x": {
|
| 1368 |
+
"dtype": "float32",
|
| 1369 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.11, "cosStep": 0.17 },
|
| 1370 |
+
"shape": [1, 8, 32, 32]
|
| 1371 |
+
},
|
| 1372 |
+
"w": {
|
| 1373 |
+
"dtype": "float32",
|
| 1374 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.19, "cosStep": 0.13 },
|
| 1375 |
+
"shape": [8, 128, 2, 2]
|
| 1376 |
+
},
|
| 1377 |
+
"bias": {
|
| 1378 |
+
"dtype": "float32",
|
| 1379 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.23 },
|
| 1380 |
+
"shape": [128]
|
| 1381 |
+
}
|
| 1382 |
+
},
|
| 1383 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 128, 33, 33], "tolerance": 0.0001 } }
|
| 1384 |
+
},
|
| 1385 |
+
{
|
| 1386 |
+
"name": "empty_input_spatial_dim_3d_nonempty_output",
|
| 1387 |
+
"provenance": {
|
| 1388 |
+
"notes": "A zero-depth input leaves a nonempty rank-5 output because the kernel is wider than the empty spatial extent. The contraction is empty, so every output is the additive identity."
|
| 1389 |
+
},
|
| 1390 |
+
"attrs": {},
|
| 1391 |
+
"inputs": {
|
| 1392 |
+
"x": { "dtype": "float32", "shape": [1, 1, 0, 3, 3] },
|
| 1393 |
+
"w": { "dtype": "float32", "shape": [1, 1, 3, 3, 3], "data": { "kind": "constant", "value": 1.0 } }
|
| 1394 |
+
},
|
| 1395 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 1, 2, 5, 5], "data": { "kind": "constant", "value": 0.0 } } }
|
| 1396 |
+
},
|
| 1397 |
+
{
|
| 1398 |
+
"name": "empty_input_spatial_dim_3d_nonempty_output_bias",
|
| 1399 |
+
"provenance": {
|
| 1400 |
+
"notes": "Bias is applied after an empty rank-5 contraction, so each nonempty output channel is exactly its bias value without reading X or W."
|
| 1401 |
+
},
|
| 1402 |
+
"attrs": {},
|
| 1403 |
+
"inputs": {
|
| 1404 |
+
"x": { "dtype": "float32", "shape": [1, 1, 0, 1, 1] },
|
| 1405 |
+
"w": { "dtype": "float32", "shape": [1, 2, 2, 1, 1], "data": { "kind": "constant", "value": 1.0 } },
|
| 1406 |
+
"bias": { "dtype": "float32", "shape": [2], "data": { "kind": "values", "values": [1.25, -2.5] } }
|
| 1407 |
+
},
|
| 1408 |
+
"outputs": {
|
| 1409 |
+
"y": {
|
| 1410 |
+
"dtype": "float32",
|
| 1411 |
+
"shape": [1, 2, 1, 1, 1],
|
| 1412 |
+
"data": { "kind": "values", "values": [1.25, -2.5] },
|
| 1413 |
+
"tolerance": 0
|
| 1414 |
+
}
|
| 1415 |
+
}
|
| 1416 |
+
},
|
| 1417 |
+
{
|
| 1418 |
+
"name": "empty_input_spatial_dim_2d_grouped_f16_nonempty_output",
|
| 1419 |
+
"provenance": {
|
| 1420 |
+
"notes": "The empty-reduction fill route also covers grouped rank-4 float16 without allocating or reading an im2col scratch buffer."
|
| 1421 |
+
},
|
| 1422 |
+
"attrs": { "group": 2 },
|
| 1423 |
+
"inputs": {
|
| 1424 |
+
"x": { "dtype": "float16", "shape": [1, 2, 0, 1] },
|
| 1425 |
+
"w": { "dtype": "float16", "shape": [2, 1, 2, 1], "data": { "kind": "constant", "value": 1.0 } }
|
| 1426 |
+
},
|
| 1427 |
+
"outputs": {
|
| 1428 |
+
"y": { "dtype": "float16", "shape": [1, 2, 1, 1], "data": { "kind": "constant", "value": 0.0 }, "tolerance": 0 }
|
| 1429 |
+
}
|
| 1430 |
+
},
|
| 1431 |
+
{
|
| 1432 |
+
"name": "empty_input_spatial_dim_1d_f16_nonempty_output_bias",
|
| 1433 |
+
"provenance": {
|
| 1434 |
+
"notes": "The float16 bias-broadcast source is rendered explicitly: a zero-width rank-3 reduction returns one output position per channel containing only bias."
|
| 1435 |
+
},
|
| 1436 |
+
"attrs": {},
|
| 1437 |
+
"inputs": {
|
| 1438 |
+
"x": { "dtype": "float16", "shape": [1, 1, 0] },
|
| 1439 |
+
"w": { "dtype": "float16", "shape": [1, 2, 2], "data": { "kind": "constant", "value": 1.0 } },
|
| 1440 |
+
"bias": { "dtype": "float16", "shape": [2], "data": { "kind": "values", "values": [0.5, -0.75] } }
|
| 1441 |
+
},
|
| 1442 |
+
"outputs": {
|
| 1443 |
+
"y": {
|
| 1444 |
+
"dtype": "float16",
|
| 1445 |
+
"shape": [1, 2, 1],
|
| 1446 |
+
"data": { "kind": "values", "values": [0.5, -0.75] },
|
| 1447 |
+
"tolerance": 0
|
| 1448 |
+
}
|
| 1449 |
+
}
|
| 1450 |
+
},
|
| 1451 |
+
{
|
| 1452 |
+
"name": "zero_batch_dim_3d_empty_output",
|
| 1453 |
+
"attrs": {},
|
| 1454 |
+
"inputs": {
|
| 1455 |
+
"x": { "dtype": "float32", "shape": [0, 1, 3, 3, 3] },
|
| 1456 |
+
"w": { "dtype": "float32", "shape": [1, 2, 3, 3, 3] }
|
| 1457 |
+
},
|
| 1458 |
+
"outputs": { "y": { "dtype": "float32", "shape": [0, 2, 5, 5, 5] } }
|
| 1459 |
+
},
|
| 1460 |
+
{
|
| 1461 |
+
"name": "zero_batch_dim_grouped_empty_output",
|
| 1462 |
+
"attrs": { "group": 2 },
|
| 1463 |
+
"inputs": {
|
| 1464 |
+
"x": { "dtype": "float32", "shape": [0, 4, 4, 4] },
|
| 1465 |
+
"w": { "dtype": "float32", "shape": [4, 2, 2, 2] }
|
| 1466 |
+
},
|
| 1467 |
+
"outputs": { "y": { "dtype": "float32", "shape": [0, 4, 5, 5] } }
|
| 1468 |
+
},
|
| 1469 |
+
{
|
| 1470 |
+
"name": "grouped_dispatch_fold_depthwise_1x1_over_16m",
|
| 1471 |
+
"attrs": { "group": 64 },
|
| 1472 |
+
"inputs": {
|
| 1473 |
+
"x": { "dtype": "float32", "shape": [1, 64, 512, 512] },
|
| 1474 |
+
"w": { "dtype": "float32", "shape": [64, 1, 1, 1], "data": { "kind": "constant", "value": 1.0 } }
|
| 1475 |
+
},
|
| 1476 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 64, 512, 512] } }
|
| 1477 |
+
},
|
| 1478 |
+
{
|
| 1479 |
+
"name": "grouped_2d_f16_bias_routing_gap",
|
| 1480 |
+
"attrs": { "group": 2, "strides": [2, 2], "pads": [1, 1, 1, 1] },
|
| 1481 |
+
"inputs": {
|
| 1482 |
+
"x": { "dtype": "float16", "shape": [1, 4, 8, 8] },
|
| 1483 |
+
"w": { "dtype": "float16", "shape": [4, 3, 3, 3] },
|
| 1484 |
+
"bias": { "dtype": "float16", "shape": [6] }
|
| 1485 |
+
},
|
| 1486 |
+
"outputs": { "y": { "dtype": "float16", "shape": [1, 6, 15, 15], "tolerance": 0.03 } }
|
| 1487 |
+
},
|
| 1488 |
+
{
|
| 1489 |
+
"name": "convtranspose3d_depth_output_padding1_compact",
|
| 1490 |
+
"provenance": {
|
| 1491 |
+
"source": "ONNX ConvTranspose-22 volumetric output_padding semantics",
|
| 1492 |
+
"notes": "Covers a non-default depth entry in the exact output_padding list attribute."
|
| 1493 |
+
},
|
| 1494 |
+
"attrs": { "strides": [2, 1, 1], "output_padding": [1, 0, 0] },
|
| 1495 |
+
"inputs": {
|
| 1496 |
+
"x": { "dtype": "float32", "shape": [1, 1, 2, 1, 1], "data": { "kind": "values", "values": [1.0, 2.0] } },
|
| 1497 |
+
"w": { "dtype": "float32", "shape": [1, 1, 2, 1, 1], "data": { "kind": "values", "values": [3.0, 4.0] } }
|
| 1498 |
+
},
|
| 1499 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 1, 5, 1, 1], "tolerance": 0.000001 } }
|
| 1500 |
+
},
|
| 1501 |
+
{
|
| 1502 |
+
"name": "dispatch_cliff_batch_over_65535_bias_forces_nchw_scalar",
|
| 1503 |
+
"provenance": {
|
| 1504 |
+
"notes": "Batch 65536 exceeds maxComputeWorkgroupsPerDimension, so gemmDispatchFits is false and every col2im GEMM variant drops out; the scalar NCHW kernel with its bias epilogue is the only remaining f32 dense path."
|
| 1505 |
+
},
|
| 1506 |
+
"attrs": {},
|
| 1507 |
+
"inputs": {
|
| 1508 |
+
"x": {
|
| 1509 |
+
"dtype": "float32",
|
| 1510 |
+
"shape": [65536, 1, 1, 1],
|
| 1511 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.0009, "cosStep": 0.0007 }
|
| 1512 |
+
},
|
| 1513 |
+
"w": { "dtype": "float32", "shape": [1, 1, 1, 1], "data": { "kind": "constant", "value": 1.25 } },
|
| 1514 |
+
"bias": { "dtype": "float32", "shape": [1], "data": { "kind": "constant", "value": 0.5 } }
|
| 1515 |
+
},
|
| 1516 |
+
"outputs": { "y": { "dtype": "float32", "shape": [65536, 1, 1, 1], "tolerance": 0.00001 } }
|
| 1517 |
+
},
|
| 1518 |
+
{
|
| 1519 |
+
"name": "dispatch_cliff_batch_over_65535_bias_f16_forces_nchw_scalar",
|
| 1520 |
+
"provenance": {
|
| 1521 |
+
"notes": "f16 companion of the batch dispatch cliff: with gemmDispatchFits false the tiled and subgroup-matrix col2im GEMMs are ineligible, and the stride-2 phase GEMM geometry does not apply, leaving the scalar f16 NCHW bias kernel."
|
| 1522 |
+
},
|
| 1523 |
+
"attrs": {},
|
| 1524 |
+
"inputs": {
|
| 1525 |
+
"x": {
|
| 1526 |
+
"dtype": "float16",
|
| 1527 |
+
"shape": [65536, 1, 1, 1],
|
| 1528 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.0009, "cosStep": 0.0007 }
|
| 1529 |
+
},
|
| 1530 |
+
"w": { "dtype": "float16", "shape": [1, 1, 1, 1], "data": { "kind": "constant", "value": 1.25 } },
|
| 1531 |
+
"bias": { "dtype": "float16", "shape": [1], "data": { "kind": "constant", "value": 0.5 } }
|
| 1532 |
+
},
|
| 1533 |
+
"outputs": { "y": { "dtype": "float16", "shape": [65536, 1, 1, 1], "tolerance": 0.002, "relTolerance": 0.01 } }
|
| 1534 |
+
},
|
| 1535 |
+
{
|
| 1536 |
+
"name": "f16_grouped2d_stride1_no_bias",
|
| 1537 |
+
"provenance": {
|
| 1538 |
+
"notes": "Grouped f16 ConvTranspose at stride 1: the grouped stride-phase kernel requires strideH/strideW >= 2, so unit stride is what routes a grouped f16 request to the scalar grouped NCHW kernel."
|
| 1539 |
+
},
|
| 1540 |
+
"attrs": { "group": 2 },
|
| 1541 |
+
"inputs": {
|
| 1542 |
+
"x": {
|
| 1543 |
+
"dtype": "float16",
|
| 1544 |
+
"shape": [1, 2, 2, 2],
|
| 1545 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.11, "cosStep": 0.17 }
|
| 1546 |
+
},
|
| 1547 |
+
"w": {
|
| 1548 |
+
"dtype": "float16",
|
| 1549 |
+
"shape": [2, 1, 2, 2],
|
| 1550 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.19, "cosStep": 0.13 }
|
| 1551 |
+
}
|
| 1552 |
+
},
|
| 1553 |
+
"outputs": { "y": { "dtype": "float16", "shape": [1, 2, 3, 3], "tolerance": 0.01 } }
|
| 1554 |
+
},
|
| 1555 |
+
{
|
| 1556 |
+
"name": "f16_grouped2d_stride1_bias",
|
| 1557 |
+
"provenance": {
|
| 1558 |
+
"notes": "Bias companion of the unit-stride grouped f16 case: the grouped stride-phase bias kernel is gated on stride >= 2, so the bias epilogue of the scalar grouped f16 NCHW kernel is only reachable at stride 1."
|
| 1559 |
+
},
|
| 1560 |
+
"attrs": { "group": 2 },
|
| 1561 |
+
"inputs": {
|
| 1562 |
+
"x": {
|
| 1563 |
+
"dtype": "float16",
|
| 1564 |
+
"shape": [1, 2, 2, 2],
|
| 1565 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.13, "cosStep": 0.19 }
|
| 1566 |
+
},
|
| 1567 |
+
"w": {
|
| 1568 |
+
"dtype": "float16",
|
| 1569 |
+
"shape": [2, 1, 2, 2],
|
| 1570 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.17, "cosStep": 0.11 }
|
| 1571 |
+
},
|
| 1572 |
+
"bias": {
|
| 1573 |
+
"dtype": "float16",
|
| 1574 |
+
"shape": [2],
|
| 1575 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.29 }
|
| 1576 |
+
}
|
| 1577 |
+
},
|
| 1578 |
+
"outputs": { "y": { "dtype": "float16", "shape": [1, 2, 3, 3], "tolerance": 0.01 } }
|
| 1579 |
+
},
|
| 1580 |
+
{
|
| 1581 |
+
"name": "convtranspose3d_subgroup_matrix_col2im_overlap_f32",
|
| 1582 |
+
"provenance": {
|
| 1583 |
+
"notes": "General rank-5 matrix-path coverage with K=IC=32, N=ID*IH*IW=64, and M=OC*KD*KH*KW=32. Constant operands make the complete 2x2x2 overlap multiplicity explicit while exercising weight reorder, subgroup-matrix contraction, and 3D col2im."
|
| 1584 |
+
},
|
| 1585 |
+
"attrs": {},
|
| 1586 |
+
"inputs": {
|
| 1587 |
+
"x": { "dtype": "float32", "shape": [1, 32, 4, 4, 4], "data": { "kind": "constant", "value": 1.0 } },
|
| 1588 |
+
"w": { "dtype": "float32", "shape": [32, 4, 2, 2, 2], "data": { "kind": "constant", "value": 0.125 } }
|
| 1589 |
+
},
|
| 1590 |
+
"outputs": {
|
| 1591 |
+
"y": {
|
| 1592 |
+
"dtype": "float32",
|
| 1593 |
+
"shape": [1, 4, 5, 5, 5],
|
| 1594 |
+
"tolerance": 0.0002,
|
| 1595 |
+
"relTolerance": 0.0002,
|
| 1596 |
+
"data": {
|
| 1597 |
+
"kind": "cycle",
|
| 1598 |
+
"values": [4.0, 8.0, 8.0, 8.0, 4.0, 8.0, 16.0, 16.0, 16.0, 8.0, 8.0, 16.0, 16.0, 16.0, 8.0, 8.0, 16.0, 16.0, 16.0, 8.0, 4.0, 8.0, 8.0, 8.0, 4.0, 8.0, 16.0, 16.0, 16.0, 8.0, 16.0, 32.0, 32.0, 32.0, 16.0, 16.0, 32.0, 32.0, 32.0, 16.0, 16.0, 32.0, 32.0, 32.0, 16.0, 8.0, 16.0, 16.0, 16.0, 8.0, 8.0, 16.0, 16.0, 16.0, 8.0, 16.0, 32.0, 32.0, 32.0, 16.0, 16.0, 32.0, 32.0, 32.0, 16.0, 16.0, 32.0, 32.0, 32.0, 16.0, 8.0, 16.0, 16.0, 16.0, 8.0, 8.0, 16.0, 16.0, 16.0, 8.0, 16.0, 32.0, 32.0, 32.0, 16.0, 16.0, 32.0, 32.0, 32.0, 16.0, 16.0, 32.0, 32.0, 32.0, 16.0, 8.0, 16.0, 16.0, 16.0, 8.0, 4.0, 8.0, 8.0, 8.0, 4.0, 8.0, 16.0, 16.0, 16.0, 8.0, 8.0, 16.0, 16.0, 16.0, 8.0, 8.0, 16.0, 16.0, 16.0, 8.0, 4.0, 8.0, 8.0, 8.0, 4.0]
|
| 1599 |
+
}
|
| 1600 |
+
}
|
| 1601 |
+
}
|
| 1602 |
+
},
|
| 1603 |
+
{
|
| 1604 |
+
"name": "convtranspose3d_subgroup_matrix_bias_f32",
|
| 1605 |
+
"provenance": {
|
| 1606 |
+
"notes": "Bias companion for the aligned rank-5 matrix path. A pointwise volumetric kernel isolates the bias epilogue while preserving context-derived M/K/N eligibility."
|
| 1607 |
+
},
|
| 1608 |
+
"attrs": {},
|
| 1609 |
+
"inputs": {
|
| 1610 |
+
"x": { "dtype": "float32", "shape": [1, 32, 4, 4, 4], "data": { "kind": "constant", "value": 1.0 } },
|
| 1611 |
+
"w": { "dtype": "float32", "shape": [32, 32, 1, 1, 1], "data": { "kind": "constant", "value": 0.125 } },
|
| 1612 |
+
"bias": { "dtype": "float32", "shape": [32], "data": { "kind": "constant", "value": 0.5 } }
|
| 1613 |
+
},
|
| 1614 |
+
"outputs": {
|
| 1615 |
+
"y": {
|
| 1616 |
+
"dtype": "float32",
|
| 1617 |
+
"shape": [1, 32, 4, 4, 4],
|
| 1618 |
+
"tolerance": 0.0002,
|
| 1619 |
+
"relTolerance": 0.0002,
|
| 1620 |
+
"data": { "kind": "constant", "value": 4.5 }
|
| 1621 |
+
}
|
| 1622 |
+
}
|
| 1623 |
+
},
|
| 1624 |
+
{
|
| 1625 |
+
"name": "convtranspose3d_tiled_reg_large_spatial_f32",
|
| 1626 |
+
"provenance": {
|
| 1627 |
+
"notes": "Portable register-tiled rank-5 coverage with N=8*32*32 and M=32. Pointwise weights isolate the large matrix path and 3D tensor plumbing while tile eligibility remains manifest-derived."
|
| 1628 |
+
},
|
| 1629 |
+
"attrs": {},
|
| 1630 |
+
"inputs": {
|
| 1631 |
+
"x": { "dtype": "float32", "shape": [1, 32, 8, 32, 32], "data": { "kind": "constant", "value": 1.0 } },
|
| 1632 |
+
"w": { "dtype": "float32", "shape": [32, 32, 1, 1, 1], "data": { "kind": "constant", "value": 0.03125 } }
|
| 1633 |
+
},
|
| 1634 |
+
"outputs": {
|
| 1635 |
+
"y": {
|
| 1636 |
+
"dtype": "float32",
|
| 1637 |
+
"shape": [1, 32, 8, 32, 32],
|
| 1638 |
+
"tolerance": 0.0002,
|
| 1639 |
+
"relTolerance": 0.0002,
|
| 1640 |
+
"data": { "kind": "constant", "value": 1.0 }
|
| 1641 |
+
}
|
| 1642 |
+
}
|
| 1643 |
+
},
|
| 1644 |
+
{
|
| 1645 |
+
"name": "convtranspose3d_tiled_bias_reg_large_spatial_f32",
|
| 1646 |
+
"provenance": {
|
| 1647 |
+
"notes": "Bias companion for the portable register-tiled rank-5 path, validating that bias stays in the output-stationary col2im epilogue rather than the intermediate GEMM."
|
| 1648 |
+
},
|
| 1649 |
+
"attrs": {},
|
| 1650 |
+
"inputs": {
|
| 1651 |
+
"x": { "dtype": "float32", "shape": [1, 32, 8, 32, 32], "data": { "kind": "constant", "value": 1.0 } },
|
| 1652 |
+
"w": { "dtype": "float32", "shape": [32, 32, 1, 1, 1], "data": { "kind": "constant", "value": 0.03125 } },
|
| 1653 |
+
"bias": { "dtype": "float32", "shape": [32], "data": { "kind": "constant", "value": 0.5 } }
|
| 1654 |
+
},
|
| 1655 |
+
"outputs": {
|
| 1656 |
+
"y": {
|
| 1657 |
+
"dtype": "float32",
|
| 1658 |
+
"shape": [1, 32, 8, 32, 32],
|
| 1659 |
+
"tolerance": 0.0002,
|
| 1660 |
+
"relTolerance": 0.0002,
|
| 1661 |
+
"data": { "kind": "constant", "value": 1.5 }
|
| 1662 |
+
}
|
| 1663 |
+
}
|
| 1664 |
+
},
|
| 1665 |
+
{
|
| 1666 |
+
"name": "exact_tiling_stride4_kernel4_gemm_bias",
|
| 1667 |
+
"provenance": {
|
| 1668 |
+
"notes": "Kernel == stride with no padding, no dilation and no output padding: the taps TILE the output rather than overlapping it, so col2im takes its collapsed single-tap path instead of the KH*KW gather. Shaped after Depth Anything V2's factor-4 reassemble (x [1,384,37,49], w [384,48,4,4]). Without a case in this quadrant the collapsed branch had zero coverage: poisoning it left all 163 ConvTranspose tests green."
|
| 1669 |
+
},
|
| 1670 |
+
"attrs": { "strides": [4, 4] },
|
| 1671 |
+
"inputs": {
|
| 1672 |
+
"x": {
|
| 1673 |
+
"dtype": "float32",
|
| 1674 |
+
"shape": [1, 16, 5, 7],
|
| 1675 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.03, "cosStep": 0.07, "scale": 0.4 }
|
| 1676 |
+
},
|
| 1677 |
+
"w": {
|
| 1678 |
+
"dtype": "float32",
|
| 1679 |
+
"shape": [16, 8, 4, 4],
|
| 1680 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.05, "cosStep": 0.11, "scale": 0.4 }
|
| 1681 |
+
},
|
| 1682 |
+
"bias": {
|
| 1683 |
+
"dtype": "float32",
|
| 1684 |
+
"shape": [8],
|
| 1685 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.13, "cosStep": 0.19, "scale": 0.3 }
|
| 1686 |
+
}
|
| 1687 |
+
},
|
| 1688 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 8, 20, 28], "tolerance": 0.0005 } }
|
| 1689 |
+
},
|
| 1690 |
+
{
|
| 1691 |
+
"name": "exact_tiling_nonsquare_stride2x3_no_bias",
|
| 1692 |
+
"provenance": {
|
| 1693 |
+
"notes": "Kernel == stride on BOTH axes but with different strides per axis (2 x 3), so a kh/kw or inW/outW swap in the collapsed col2im tap cannot cancel out the way it would on a square kernel."
|
| 1694 |
+
},
|
| 1695 |
+
"attrs": { "strides": [2, 3] },
|
| 1696 |
+
"inputs": {
|
| 1697 |
+
"x": {
|
| 1698 |
+
"dtype": "float32",
|
| 1699 |
+
"shape": [1, 8, 4, 5],
|
| 1700 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.023, "cosStep": 0.061, "scale": 0.4 }
|
| 1701 |
+
},
|
| 1702 |
+
"w": {
|
| 1703 |
+
"dtype": "float32",
|
| 1704 |
+
"shape": [8, 6, 2, 3],
|
| 1705 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.047, "cosStep": 0.089, "scale": 0.4 }
|
| 1706 |
+
}
|
| 1707 |
+
},
|
| 1708 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 6, 8, 15], "tolerance": 0.0005 } }
|
| 1709 |
+
},
|
| 1710 |
+
{
|
| 1711 |
+
"name": "exact_tiling_stride2_kernel2_f16_bias",
|
| 1712 |
+
"provenance": {
|
| 1713 |
+
"notes": "The f16 im2col-GEMM family shares the same col2im shader, so the collapsed tap needs a case on that side of the dtype split too. Shaped after Depth Anything V2's factor-2 reassemble."
|
| 1714 |
+
},
|
| 1715 |
+
"attrs": { "strides": [2, 2] },
|
| 1716 |
+
"inputs": {
|
| 1717 |
+
"x": {
|
| 1718 |
+
"dtype": "float16",
|
| 1719 |
+
"shape": [1, 32, 8, 8],
|
| 1720 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.03, "cosStep": 0.07, "scale": 0.4 }
|
| 1721 |
+
},
|
| 1722 |
+
"w": {
|
| 1723 |
+
"dtype": "float16",
|
| 1724 |
+
"shape": [32, 16, 2, 2],
|
| 1725 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.05, "cosStep": 0.11, "scale": 0.4 }
|
| 1726 |
+
},
|
| 1727 |
+
"bias": {
|
| 1728 |
+
"dtype": "float16",
|
| 1729 |
+
"shape": [16],
|
| 1730 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.13, "cosStep": 0.19, "scale": 0.3 }
|
| 1731 |
+
}
|
| 1732 |
+
},
|
| 1733 |
+
"outputs": { "y": { "dtype": "float16", "shape": [1, 16, 16, 16], "tolerance": 0.03 } }
|
| 1734 |
+
},
|
| 1735 |
+
{
|
| 1736 |
+
"name": "cols_gemm_2d_bias_m_and_n_tail",
|
| 1737 |
+
"provenance": {
|
| 1738 |
+
"notes": "An f32 rank-4 im2col-GEMM whose channel count is a multiple of 32 and whose BOTH gemm axes are ragged: gemmM = 12*3*3 = 108 tails a 32-row tile and gemmN = 9*11 = 99 tails a 64-column tile. Written to cover a subgroup-matrix 2D path that was then reverted, and kept because it is the shape that CAUGHT it: the shared sgmat kernel's materialized B load has no N guard, so this case read maxAbs 6.6 wrong while the same shape at N = 64 was exact."
|
| 1739 |
+
},
|
| 1740 |
+
"attrs": { "strides": [2, 2], "pads": [1, 1, 1, 1] },
|
| 1741 |
+
"inputs": {
|
| 1742 |
+
"x": {
|
| 1743 |
+
"dtype": "float32",
|
| 1744 |
+
"shape": [1, 32, 9, 11],
|
| 1745 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.031, "cosStep": 0.067, "scale": 0.4 }
|
| 1746 |
+
},
|
| 1747 |
+
"w": {
|
| 1748 |
+
"dtype": "float32",
|
| 1749 |
+
"shape": [32, 12, 3, 3],
|
| 1750 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.053, "cosStep": 0.089, "scale": 0.4 }
|
| 1751 |
+
},
|
| 1752 |
+
"bias": {
|
| 1753 |
+
"dtype": "float32",
|
| 1754 |
+
"shape": [12],
|
| 1755 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.131, "cosStep": 0.197, "scale": 0.3 }
|
| 1756 |
+
}
|
| 1757 |
+
},
|
| 1758 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 12, 17, 21], "tolerance": 0.0005 } }
|
| 1759 |
+
},
|
| 1760 |
+
{
|
| 1761 |
+
"name": "cols_gemm_2d_no_bias_m_aligned_n_below_tile",
|
| 1762 |
+
"provenance": {
|
| 1763 |
+
"notes": "The companion: gemmM = 16*4*4 = 256 is tile-aligned and gemmN = 5*6 = 30 is BELOW one column tile, the narrowest an N tail gets. Same provenance — it is half of the pair that showed a ragged N is not safe on the shared subgroup-matrix kernel."
|
| 1764 |
+
},
|
| 1765 |
+
"attrs": { "strides": [4, 4] },
|
| 1766 |
+
"inputs": {
|
| 1767 |
+
"x": {
|
| 1768 |
+
"dtype": "float32",
|
| 1769 |
+
"shape": [1, 64, 5, 6],
|
| 1770 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.023, "cosStep": 0.061, "scale": 0.4 }
|
| 1771 |
+
},
|
| 1772 |
+
"w": {
|
| 1773 |
+
"dtype": "float32",
|
| 1774 |
+
"shape": [64, 16, 4, 4],
|
| 1775 |
+
"data": { "kind": "fillFloat32", "sinStep": 0.047, "cosStep": 0.083, "scale": 0.4 }
|
| 1776 |
+
}
|
| 1777 |
+
},
|
| 1778 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 16, 20, 24], "tolerance": 0.0005 } }
|
| 1779 |
+
},
|
| 1780 |
+
{
|
| 1781 |
+
"name": "f16_1d_bias",
|
| 1782 |
+
"provenance": {
|
| 1783 |
+
"notes": "Covers rank-3 f16 ConvTranspose with bias. Exact half-valued inputs keep bias-indexing errors observable without f16 rounding ambiguity."
|
| 1784 |
+
},
|
| 1785 |
+
"attrs": {},
|
| 1786 |
+
"inputs": {
|
| 1787 |
+
"x": {
|
| 1788 |
+
"dtype": "float16",
|
| 1789 |
+
"shape": [1, 2, 8],
|
| 1790 |
+
"data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/f16_1d_nobias_input_x" } }
|
| 1791 |
+
},
|
| 1792 |
+
"w": {
|
| 1793 |
+
"dtype": "float16",
|
| 1794 |
+
"shape": [2, 3, 3],
|
| 1795 |
+
"data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/f16_1d_nobias_input_w" } }
|
| 1796 |
+
},
|
| 1797 |
+
"bias": { "dtype": "float16", "shape": [3], "data": { "kind": "values", "values": [0.25, -0.5, 1.5] } }
|
| 1798 |
+
},
|
| 1799 |
+
"outputs": { "y": { "dtype": "float16", "shape": [1, 3, 10], "tolerance": 0.02 } }
|
| 1800 |
+
},
|
| 1801 |
+
{
|
| 1802 |
+
"name": "f16_1d_grouped_nobias",
|
| 1803 |
+
"provenance": {
|
| 1804 |
+
"source": "onnxruntime/test/providers/cpu/nn/conv_transpose_op_test.cc",
|
| 1805 |
+
"test": "ConvTransposeTest.ConvTranspose_1D_OutputShape_1_group_2_for_transpose_path",
|
| 1806 |
+
"notes": "Covers grouped rank-3 f16 ConvTranspose without bias. Distinct per-group weights 2 and 3 make group-indexing errors observable."
|
| 1807 |
+
},
|
| 1808 |
+
"attrs": { "group": 2 },
|
| 1809 |
+
"inputs": {
|
| 1810 |
+
"x": { "dtype": "float16", "shape": [1, 2, 2], "data": { "kind": "values", "values": [1.0, 2.0, 3.0, 4.0] } },
|
| 1811 |
+
"w": { "dtype": "float16", "shape": [2, 1, 1], "data": { "kind": "values", "values": [2.0, 3.0] } }
|
| 1812 |
+
},
|
| 1813 |
+
"outputs": { "y": { "dtype": "float16", "shape": [1, 2, 2], "tolerance": 0.01 } }
|
| 1814 |
+
},
|
| 1815 |
+
{
|
| 1816 |
+
"name": "f16_1d_grouped_bias",
|
| 1817 |
+
"provenance": {
|
| 1818 |
+
"source": "onnxruntime/test/providers/cpu/nn/conv_transpose_op_test.cc",
|
| 1819 |
+
"test": "ConvTransposeTest.ConvTranspose_1D_OutputShape_1_group_2_for_transpose_path",
|
| 1820 |
+
"notes": "Covers grouped rank-3 f16 ConvTranspose with per-output-channel bias. The two bias entries differ in sign and magnitude, making a wrong channel index observable."
|
| 1821 |
+
},
|
| 1822 |
+
"attrs": { "group": 2 },
|
| 1823 |
+
"inputs": {
|
| 1824 |
+
"x": { "dtype": "float16", "shape": [1, 2, 2], "data": { "kind": "values", "values": [1.0, 2.0, 3.0, 4.0] } },
|
| 1825 |
+
"w": { "dtype": "float16", "shape": [2, 1, 1], "data": { "kind": "values", "values": [2.0, 3.0] } },
|
| 1826 |
+
"bias": { "dtype": "float16", "shape": [2], "data": { "kind": "values", "values": [0.25, -0.5] } }
|
| 1827 |
+
},
|
| 1828 |
+
"outputs": { "y": { "dtype": "float16", "shape": [1, 2, 2], "tolerance": 0.01 } }
|
| 1829 |
+
},
|
| 1830 |
+
{
|
| 1831 |
+
"name": "zero_input_spatial_dim_3d_empty_output",
|
| 1832 |
+
"provenance": {
|
| 1833 |
+
"notes": "A zero input-depth dimension with a unit kernel produces a zero output-depth dimension. This exercises the direct rank-5 fallback when the GEMM column dimension is zero and the nonempty-output reduction does not apply."
|
| 1834 |
+
},
|
| 1835 |
+
"attrs": {},
|
| 1836 |
+
"inputs": {
|
| 1837 |
+
"x": { "dtype": "float32", "shape": [1, 1, 0, 2, 2], "data": { "kind": "values", "values": [] } },
|
| 1838 |
+
"w": { "dtype": "float32", "shape": [1, 1, 1, 1, 1], "data": { "kind": "values", "values": [2.0] } }
|
| 1839 |
+
},
|
| 1840 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 1, 0, 2, 2], "tolerance": 0 } }
|
| 1841 |
+
},
|
| 1842 |
+
{
|
| 1843 |
+
"name": "zero_input_spatial_dim_3d_empty_output_bias",
|
| 1844 |
+
"provenance": {
|
| 1845 |
+
"notes": "Bias does not make an output tensor with a zero spatial dimension nonempty. This is the bias-bearing sibling for the direct rank-5 zero-column fallback."
|
| 1846 |
+
},
|
| 1847 |
+
"attrs": {},
|
| 1848 |
+
"inputs": {
|
| 1849 |
+
"x": { "dtype": "float32", "shape": [1, 1, 0, 2, 2], "data": { "kind": "values", "values": [] } },
|
| 1850 |
+
"w": { "dtype": "float32", "shape": [1, 1, 1, 1, 1], "data": { "kind": "values", "values": [2.0] } },
|
| 1851 |
+
"bias": { "dtype": "float32", "shape": [1], "data": { "kind": "values", "values": [0.75] } }
|
| 1852 |
+
},
|
| 1853 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 1, 0, 2, 2], "tolerance": 0 } }
|
| 1854 |
+
}
|
| 1855 |
+
]
|
| 1856 |
+
}
|