Xenova HF Staff commited on
Commit
36916af
·
verified ·
1 Parent(s): 8d1ebb5

sync 2e7068faf55e

Browse files
README.md CHANGED
@@ -1,3 +1,76 @@
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.AffineGrid
10
+
11
+ `ai.onnx` · standard ONNX operator · ONNX opset ≥ 20
12
+
13
+ ## Description
14
+
15
+ Generates a 2-D or 3-D flow field (sampling grid) from a batch of affine matrices `theta`. Each affine matrix is applied to the target output's normalized coordinate grid in `[-1, 1]`, producing sample coordinates at every output position.
16
+
17
+ See the [ONNX `AffineGrid` spec](https://onnx.ai/onnx/operators/onnx__AffineGrid.html) for the reference semantics.
18
+
19
+ ## Inputs
20
+
21
+ | Name | Bind key | Logical dtype | Rank | Shape | Description | Presence |
22
+ | --- | --- | --- | --- | --- | --- | --- |
23
+ | `theta` | `theta` | `T` | `3` | — | Batch of affine matrices with shape `(N, 2, 3)` for 2-D or `(N, 3, 4)` for 3-D. | required |
24
+
25
+ ## Outputs
26
+
27
+ | Name | Bind key | Logical dtype | Rank | Shape | Description | Presence |
28
+ | --- | --- | --- | --- | --- | --- | --- |
29
+ | `grid` | `grid` | `T` | derived | — | Sampling grid of 2-D coordinates with shape `(N, H, W, 2)`, or 3-D coordinates with shape `(N, D, H, W, 3)`. | required |
30
+
31
+ ## Attributes
32
+
33
+ Default values (overridable per request):
34
+
35
+ | Attribute | Default | Description |
36
+ | --- | --- | --- |
37
+ | `align_corners` | `0` | When 1, the values -1 and 1 refer to the centers of the corner pixels; when 0 (default), they refer to the outer edges of the corner pixels. |
38
+
39
+ ## Type constraints
40
+
41
+ | Variable | Allowed dtypes |
42
+ | --- | --- |
43
+ | `T` | `float32`, `float16` |
44
+
45
+ ## Files
46
+
47
+ - [`metadata.json`](build/webgpu/metadata.json) — kernel metadata (id, digests, provenance)
48
+ - [`manifest.json`](build/webgpu/manifest.json) — the op contract (source of truth)
49
+ - [`test.json`](build/webgpu/test.json) — correctness cases
50
+ - [`bench.json`](build/webgpu/bench.json) — benchmark + tuning cases
51
+ - [`affine-grid.wgsl.jinja`](build/webgpu/affine-grid.wgsl.jinja)
52
+ - [`affine-grid3d-w4.wgsl.jinja`](build/webgpu/affine-grid3d-w4.wgsl.jinja)
53
+
54
+ ## Use with `@huggingface/kernels`
55
+
56
+ The loader automatically allocates outputs whose metadata it can derive from the manifest contract and this call.
57
+
58
+ The explicit `outputs` entries provide shape and logical dtype metadata for the results listed below:
59
+
60
+ - `grid`
61
+
62
+ Each entry either requests an optional result or supplies metadata that cannot be inferred from the inputs.
63
+
64
+ The `version: 1` option selects the published kernel contract; it is independent of any operator opset, contrib `since_version`, or model version.
65
+
66
+ Replace each `*Data` placeholder with a typed array containing the corresponding input data.
67
+
68
+ ```js
69
+ import { getKernel } from "@huggingface/kernels";
70
+
71
+ const kernel = await getKernel("webgpu-kernels/ai.onnx.AffineGrid", { version: 1 });
72
+ // Explicit destinations request optional results or supply metadata that cannot be inferred.
73
+ const { grid } = await kernel({ theta: { data: thetaData, shape: [1, 2, 3] } }, {
74
+ outputs: { grid: { shape: [1, 3, 2, 2], dtype: "float32" } },
75
+ });
76
+ ```
build/webgpu/affine-grid.wgsl.jinja ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ fn lin(coord: u32, size: u32) -> f32 {
40
+ {% if source.alignCorners %}
41
+ if (size <= 1u) { return 0.0; }
42
+ return -1.0 + 2.0 * f32(coord) / f32(size - 1u);
43
+ {% else %}
44
+ return (2.0 * f32(coord) + 1.0) / f32(size) - 1.0;
45
+ {% endif %}
46
+ }
47
+
48
+ @compute @workgroup_size({{ tunables.WORKGROUP_SIZE }})
49
+ fn main(@builtin(global_invocation_id) gid: vec3<u32>, @builtin(num_workgroups) nwg: vec3<u32>) {
50
+ {{ flat_index_2d("p", guardInline=true) }}
51
+ let w = p % params.W;
52
+ {% if source.spatialRank == 3 %}
53
+ var remaining = p / params.W;
54
+ let h = remaining % params.H;
55
+ remaining /= params.H;
56
+ let d = remaining % params.D;
57
+ let n = remaining / params.D;
58
+ {% else %}
59
+ let h = (p / params.W) % params.H;
60
+ let n = p / (params.W * params.H);
61
+ {% endif %}
62
+ let x0 = lin(w, params.W);
63
+ let y0 = lin(h, params.H);
64
+ {% if source.spatialRank == 3 %}
65
+ let z0 = lin(d, params.D);
66
+ let t = n * 12u;
67
+ grid[p * 3u] = {{ scalar }}(f32(theta[t]) * x0 + f32(theta[t + 1u]) * y0 + f32(theta[t + 2u]) * z0 + f32(theta[t + 3u]));
68
+ grid[p * 3u + 1u] = {{ scalar }}(f32(theta[t + 4u]) * x0 + f32(theta[t + 5u]) * y0 + f32(theta[t + 6u]) * z0 + f32(theta[t + 7u]));
69
+ grid[p * 3u + 2u] = {{ scalar }}(f32(theta[t + 8u]) * x0 + f32(theta[t + 9u]) * y0 + f32(theta[t + 10u]) * z0 + f32(theta[t + 11u]));
70
+ {% else %}
71
+ let t = n * 6u;
72
+ grid[p * 2u] = {{ scalar }}(f32(theta[t]) * x0 + f32(theta[t + 1u]) * y0 + f32(theta[t + 2u]));
73
+ grid[p * 2u + 1u] = {{ scalar }}(f32(theta[t + 3u]) * x0 + f32(theta[t + 4u]) * y0 + f32(theta[t + 5u]));
74
+ {% endif %}
75
+ }
build/webgpu/affine-grid3d-w4.wgsl.jinja ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% if usesF16 %}
2
+ enable f16;
3
+ {% endif %}
4
+ {% set STORE_OPEN = vectorScalar ~ "(vec4<f32>(" if usesF16 else vectorScalar ~ "(" %}
5
+ {% set STORE_CLOSE = "))" if usesF16 else ")" %}
6
+ {{ env.wgsl.resourceDeclarations }}
7
+
8
+ const COUNT4: u32 = {{ source.count4 }}u;
9
+ const D: u32 = {{ source.D }}u;
10
+ const H: u32 = {{ source.H }}u;
11
+ const W: u32 = {{ source.W }}u;
12
+ const W4: u32 = {{ source.W4 }}u;
13
+ const WG: u32 = {{ tunables.WORKGROUP_SIZE }}u;
14
+
15
+ fn lin(coord: u32, size: u32) -> f32 {
16
+ {% if source.alignCorners %}
17
+ if (size <= 1u) { return 0.0; }
18
+ return -1.0 + 2.0 * f32(coord) / f32(size - 1u);
19
+ {% else %}
20
+ return (2.0 * f32(coord) + 1.0) / f32(size) - 1.0;
21
+ {% endif %}
22
+ }
23
+
24
+ fn transform(t: u32, x0: f32, y0: f32, z0: f32) -> vec3<f32> {
25
+ return vec3<f32>(
26
+ f32(theta[t]) * x0 + f32(theta[t + 1u]) * y0 + f32(theta[t + 2u]) * z0 + f32(theta[t + 3u]),
27
+ f32(theta[t + 4u]) * x0 + f32(theta[t + 5u]) * y0 + f32(theta[t + 6u]) * z0 + f32(theta[t + 7u]),
28
+ f32(theta[t + 8u]) * x0 + f32(theta[t + 9u]) * y0 + f32(theta[t + 10u]) * z0 + f32(theta[t + 11u])
29
+ );
30
+ }
31
+
32
+ @compute @workgroup_size({{ tunables.WORKGROUP_SIZE }})
33
+ fn main(@builtin(global_invocation_id) gid: vec3<u32>, @builtin(num_workgroups) nwg: vec3<u32>) {
34
+ let q = gid.x + gid.y * nwg.x * WG;
35
+ if (q >= COUNT4) { return; }
36
+ let w4 = q % W4;
37
+ var r = q / W4;
38
+ let h = r % H;
39
+ r /= H;
40
+ let d = r % D;
41
+ let n = r / D;
42
+ let y0 = lin(h, H);
43
+ let z0 = lin(d, D);
44
+ let w0 = w4 * 4u;
45
+ let t = n * 12u;
46
+ let p0 = transform(t, lin(w0, W), y0, z0);
47
+ let p1 = transform(t, lin(w0 + 1u, W), y0, z0);
48
+ let p2 = transform(t, lin(w0 + 2u, W), y0, z0);
49
+ let p3 = transform(t, lin(w0 + 3u, W), y0, z0);
50
+ let o = q * 3u;
51
+ grid[o] = {{ STORE_OPEN }}p0.x, p0.y, p0.z, p1.x{{ STORE_CLOSE }};
52
+ grid[o + 1u] = {{ STORE_OPEN }}p1.y, p1.z, p2.x, p2.y{{ STORE_CLOSE }};
53
+ grid[o + 2u] = {{ STORE_OPEN }}p2.z, p3.x, p3.y, p3.z{{ STORE_CLOSE }};
54
+ }
build/webgpu/bench.json ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "op": "ai.onnx.AffineGrid",
3
+ "cases": [
4
+ {
5
+ "name": "1x256x256_f32",
6
+ "attrs": { "align_corners": 0 },
7
+ "inputs": {
8
+ "theta": {
9
+ "dtype": "float32",
10
+ "shape": [1, 2, 3],
11
+ "data": { "kind": "values", "values": [1.0, 0.0, 0.0, 0.0, 1.0, 0.0] }
12
+ }
13
+ },
14
+ "outputs": { "grid": { "dtype": "float32", "shape": [1, 256, 256, 2] } },
15
+ "preset": "smoke"
16
+ },
17
+ {
18
+ "name": "affine-grid3d-f32-b1-64x128x128-medical-volume",
19
+ "preset": "stress",
20
+ "vars": { "dtype": "float32", "points": 1048576 },
21
+ "attrs": { "align_corners": 0 },
22
+ "inputs": {
23
+ "theta": {
24
+ "dtype": "float32",
25
+ "shape": [1, 3, 4],
26
+ "data": { "kind": "values", "values": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0] }
27
+ }
28
+ },
29
+ "outputs": { "grid": { "dtype": "float32", "shape": [1, 64, 128, 128, 3] } },
30
+ "bench": {
31
+ "primary": true,
32
+ "metrics": [{ "type": "bandwidth", "value": "args.points * 3 * dtypeBytes(args.dtype)" }]
33
+ }
34
+ }
35
+ ]
36
+ }
build/webgpu/manifest.json ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "domain": "ai.onnx",
3
+ "name": "AffineGrid",
4
+ "sinceVersion": 20,
5
+ "description": "Generates a 2-D or 3-D flow field (sampling grid) from a batch of affine matrices `theta`. Each affine matrix is applied to the target output's normalized coordinate grid in `[-1, 1]`, producing sample coordinates at every output position.",
6
+ "inputs": [
7
+ {
8
+ "role": "theta",
9
+ "dtype": "T",
10
+ "description": "Batch of affine matrices with shape `(N, 2, 3)` for 2-D or `(N, 3, 4)` for 3-D.",
11
+ "rank": 3
12
+ }
13
+ ],
14
+ "outputs": [
15
+ {
16
+ "role": "grid",
17
+ "dtype": "T",
18
+ "rank": "4 if dim(shapes.theta, 1) == 2 else 5",
19
+ "description": "Sampling grid of 2-D coordinates with shape `(N, H, W, 2)`, or 3-D coordinates with shape `(N, D, H, W, 3)`."
20
+ }
21
+ ],
22
+ "attributes": { "align_corners": 0 },
23
+ "attributeDescriptions": {
24
+ "align_corners": "When 1, the values -1 and 1 refer to the centers of the corner pixels; when 0 (default), they refer to the outer edges of the corner pixels."
25
+ },
26
+ "attributeConstraints": { "align_corners": { "values": [0, 1] } },
27
+ "typeConstraints": { "T": ["float32", "float16"] },
28
+ "args": {
29
+ "theta": { "kind": "tensor", "semantic": "theta", "role": "input" },
30
+ "grid": { "kind": "tensor", "semantic": "grid", "role": "output" }
31
+ },
32
+ "tunables": { "WORKGROUP_SIZE": 256 },
33
+ "derive": {
34
+ "dtypeSupported": "f16Ok(dtypes.T)",
35
+ "grid2dContract": "dtypeSupported and ranks.theta == 3 and ranks.grid == 4 and dim(shapes.theta, 1) == 2 and dim(shapes.theta, 2) == 3 and dim(shapes.grid, 0) == dim(shapes.theta, 0) and dim(shapes.grid, 3) == 2",
36
+ "grid3dContract": "dtypeSupported and ranks.theta == 3 and ranks.grid == 5 and dim(shapes.theta, 1) == 3 and dim(shapes.theta, 2) == 4 and dim(shapes.grid, 0) == dim(shapes.theta, 0) and dim(shapes.grid, 4) == 3"
37
+ },
38
+ "constants": { "scalar": "dtypes.T", "usesF16": "dtypes.T == \"f16\"" },
39
+ "bindingSets": {
40
+ "grid3dVector": [
41
+ {
42
+ "name": "theta",
43
+ "arg": "theta",
44
+ "semantic": "theta",
45
+ "buffer": { "type": "read-only-storage" },
46
+ "elementType": "$scalar"
47
+ },
48
+ {
49
+ "name": "grid",
50
+ "arg": "grid",
51
+ "semantic": "grid",
52
+ "buffer": { "type": "storage" },
53
+ "elementType": "$vectorScalar"
54
+ }
55
+ ],
56
+ "grid2dScalar": [
57
+ {
58
+ "name": "theta",
59
+ "arg": "theta",
60
+ "semantic": "theta",
61
+ "buffer": { "type": "read-only-storage" },
62
+ "elementType": "$scalar"
63
+ },
64
+ { "name": "grid", "arg": "grid", "semantic": "grid", "buffer": { "type": "storage" }, "elementType": "$scalar" },
65
+ {
66
+ "name": "params",
67
+ "semantic": "kernel.params",
68
+ "buffer": { "type": "uniform" },
69
+ "struct": {
70
+ "name": "Params",
71
+ "fields": [
72
+ { "name": "count", "type": "u32", "value": "numel(shapes.grid) / 2" },
73
+ { "name": "H", "type": "u32", "value": "dim(shapes.grid, 1)" },
74
+ { "name": "W", "type": "u32", "value": "dim(shapes.grid, 2)" }
75
+ ]
76
+ }
77
+ }
78
+ ],
79
+ "grid3dScalar": [
80
+ {
81
+ "name": "theta",
82
+ "arg": "theta",
83
+ "semantic": "theta",
84
+ "buffer": { "type": "read-only-storage" },
85
+ "elementType": "$scalar"
86
+ },
87
+ { "name": "grid", "arg": "grid", "semantic": "grid", "buffer": { "type": "storage" }, "elementType": "$scalar" },
88
+ {
89
+ "name": "params",
90
+ "semantic": "kernel.params",
91
+ "buffer": { "type": "uniform" },
92
+ "struct": {
93
+ "name": "Params",
94
+ "fields": [
95
+ { "name": "count", "type": "u32", "value": "numel(shapes.grid) / 3" },
96
+ { "name": "D", "type": "u32", "value": "dim(shapes.grid, 1)" },
97
+ { "name": "H", "type": "u32", "value": "dim(shapes.grid, 2)" },
98
+ { "name": "W", "type": "u32", "value": "dim(shapes.grid, 3)" }
99
+ ]
100
+ }
101
+ }
102
+ ]
103
+ },
104
+ "variants": [
105
+ {
106
+ "id": "3d_w4",
107
+ "priority": 20,
108
+ "when": ["grid3dContract", "dim(shapes.grid, 3) > 0", "dim(shapes.grid, 3) % 4 == 0"],
109
+ "constants": { "vectorScalar": "\"vec4<\" ~ dtypes.T ~ \">\"", "usesF16": "dtypes.T == \"f16\"" },
110
+ "passes": [
111
+ {
112
+ "id": "main",
113
+ "name": "AffineGrid3D.W4",
114
+ "source": {
115
+ "shader": "affine-grid3d-w4.wgsl.jinja",
116
+ "inputs": {
117
+ "alignCorners": "attrs.align_corners != 0",
118
+ "count4": "numel(shapes.grid) / 3 / 4",
119
+ "D": "dim(shapes.grid, 1)",
120
+ "H": "dim(shapes.grid, 2)",
121
+ "W": "dim(shapes.grid, 3)",
122
+ "W4": "dim(shapes.grid, 3) / 4"
123
+ }
124
+ },
125
+ "bindings": "grid3dVector",
126
+ "dispatch": { "threads": "numel(shapes.grid) / 3 / 4", "workgroupSize": "tunables.WORKGROUP_SIZE" }
127
+ }
128
+ ]
129
+ },
130
+ {
131
+ "id": "2d",
132
+ "when": ["grid2dContract"],
133
+ "passes": [
134
+ {
135
+ "id": "main",
136
+ "name": "AffineGrid",
137
+ "source": {
138
+ "shader": "affine-grid.wgsl.jinja",
139
+ "inputs": { "alignCorners": "attrs.align_corners != 0", "spatialRank": 2 }
140
+ },
141
+ "bindings": "grid2dScalar",
142
+ "dispatch": { "threads": "numel(shapes.grid) / 2", "workgroupSize": "tunables.WORKGROUP_SIZE" }
143
+ }
144
+ ]
145
+ },
146
+ {
147
+ "id": "3d",
148
+ "priority": 10,
149
+ "when": ["grid3dContract"],
150
+ "passes": [
151
+ {
152
+ "id": "main",
153
+ "name": "AffineGrid3D",
154
+ "source": {
155
+ "shader": "affine-grid.wgsl.jinja",
156
+ "inputs": { "alignCorners": "attrs.align_corners != 0", "spatialRank": 3 }
157
+ },
158
+ "bindings": "grid3dScalar",
159
+ "dispatch": { "threads": "numel(shapes.grid) / 3", "workgroupSize": "tunables.WORKGROUP_SIZE" }
160
+ }
161
+ ]
162
+ }
163
+ ]
164
+ }
build/webgpu/metadata.json ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "ai.onnx.AffineGrid",
3
+ "id": "_ai_onnx_affinegrid_webgpu_10a1b9d",
4
+ "version": 1,
5
+ "license": "Apache-2.0",
6
+ "backend": { "type": "webgpu" },
7
+ "digest": {
8
+ "algorithm": "sha256",
9
+ "files": {
10
+ "affine-grid.wgsl.jinja": "hemLmXc03t/I3JyiZ8OneDr0uaL8q7cwVwUZPZcF7QE=",
11
+ "affine-grid3d-w4.wgsl.jinja": "pYw6LFXYyqXUgA8id761xxtP2UzQieyOpCKoegZFs5E=",
12
+ "bench.json": "x1krZetoEyoKMLV4F08UOzIemtdXC4MpoDqERBhDQhM=",
13
+ "manifest.json": "dYhH9vmmJYbl+nExkZfGUwNlgPtp4F6OJnwXwQkWeIw=",
14
+ "test.json": "eB8AkQmDzUaHcUhNazVmAXned4+KqnFEuiaOX9kL7gE="
15
+ }
16
+ },
17
+ "provenance": { "kernel": { "sha": "2e7068faf55e7f43df740015f6d1ee49391a41c5", "dirty": false } },
18
+ "webgpu": { "manifestSpec": "1.0", "specialized": true, "opPath": "ops/ai.onnx.AffineGrid" }
19
+ }
build/webgpu/test.json ADDED
@@ -0,0 +1,567 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "op": "ai.onnx.AffineGrid",
3
+ "fixtureArrays": {
4
+ "ort_generated_3d_rotation_shear_batch2_no_align_input_theta": [1.409539, 0, 0.51303, 0.3, 0.118782, 1.969615, -0.326352, -0.5, -0.168412, 0.086824, 0.462708, 1.8, 1.409539, 0, 0.51303, 0.3, 0.118782, 1.969615, -0.326352, -0.5, -0.168412, 0.086824, 0.462708, 1.8],
5
+ "ort_generated_3d_stronger_transform_batch2_no_align_input_theta": [0.259808, 0, -0.15, -0.5, -1.299038, 1.5, -2.25, -0.5, 1.375, 4.76314, 2.38157, 0.3, 0.259808, 0, -0.15, -0.5, -1.299038, 1.5, -2.25, -0.5, 1.375, 4.76314, 2.38157, 0.3],
6
+ "onnx_backend_affine_grid_3d_input_theta": [2.6830732822418213, -0.7943316102027893, 0.21829216182231903, 5, 0.622253954410553, 3.2880465984344482, -0.5303300619125366, -3.299999952316284, 0.24721935391426086, 1.7241772413253784, 0.07809311151504517, -1.100000023841858, -0.35552558302879333, 1.004422903060913, 1.3995190858840942, 2.5, 0.17578838765621185, 0.06028856709599495, -0.9240381121635437, 1.100000023841858, -1.100000023841858, -0.44999998807907104, 0.44999998807907104, 2.200000047683716]
7
+ },
8
+ "cases": [
9
+ {
10
+ "name": "affine_grid3d_w4_coarsened",
11
+ "attrs": { "align_corners": 0 },
12
+ "inputs": {
13
+ "theta": {
14
+ "dtype": "float32",
15
+ "shape": [1, 3, 4],
16
+ "data": { "kind": "values", "values": [1.0, 0.1, 0.0, 0.05, 0.0, 1.0, -0.1, -0.05, 0.1, 0.0, 1.0, 0.0] }
17
+ }
18
+ },
19
+ "outputs": { "grid": { "dtype": "float32", "shape": [1, 2, 3, 4, 3], "tolerance": 0.000001 } }
20
+ },
21
+ {
22
+ "name": "f32_subnormal_translation_2d_singleton_gpu_gap",
23
+ "skipGpu": {
24
+ "category": "permanent",
25
+ "reason": "Portable WGSL floating-point semantics do not guarantee preservation of the subnormal values required by this fixture. Backend evidence: Metal FTZ: subnormal f32 translation (1e-40) in theta flushes to zero on GPU, so the singleton grid reads 0 instead of the subnormal translation (tolerance 0)."
26
+ },
27
+ "provenance": {
28
+ "notes": "A singleton 2D output grid has normalized coordinates (0, 0), so the grid should preserve theta's subnormal translation exactly."
29
+ },
30
+ "attrs": { "align_corners": 1 },
31
+ "inputs": {
32
+ "theta": {
33
+ "dtype": "float32",
34
+ "shape": [1, 2, 3],
35
+ "data": { "kind": "values", "values": [0.0, 0.0, 1e-40, 0.0, 0.0, -1e-40] }
36
+ }
37
+ },
38
+ "outputs": { "grid": { "dtype": "float32", "shape": [1, 1, 1, 2], "tolerance": 0 } }
39
+ },
40
+ {
41
+ "name": "f32_subnormal_translation_3d_singleton_gpu_gap",
42
+ "skipGpu": {
43
+ "category": "permanent",
44
+ "reason": "Portable WGSL floating-point semantics do not guarantee preservation of the subnormal values required by this fixture. Backend evidence: Metal FTZ: subnormal f32 translation (1e-40) in theta flushes to zero on GPU, so the singleton grid reads 0 instead of the subnormal translation (tolerance 0)."
45
+ },
46
+ "provenance": {
47
+ "notes": "A singleton 3D output grid should preserve subnormal x/y/z translations without arithmetic amplification."
48
+ },
49
+ "attrs": { "align_corners": 1 },
50
+ "inputs": {
51
+ "theta": {
52
+ "dtype": "float32",
53
+ "shape": [1, 3, 4],
54
+ "data": { "kind": "values", "values": [0.0, 0.0, 0.0, 1e-40, 0.0, 0.0, 0.0, -1e-40, 0.0, 0.0, 0.0, 1e-40] }
55
+ }
56
+ },
57
+ "outputs": { "grid": { "dtype": "float32", "shape": [1, 1, 1, 1, 3], "tolerance": 0 } }
58
+ },
59
+ {
60
+ "name": "dispatch_cliff_2d_over_16m_elements",
61
+ "attrs": { "align_corners": 0 },
62
+ "inputs": {
63
+ "theta": {
64
+ "dtype": "float32",
65
+ "shape": [1, 2, 3],
66
+ "data": { "kind": "values", "values": [1.0, 0.5, 0.25, -0.5, 2.0, -1.0] }
67
+ }
68
+ },
69
+ "outputs": { "grid": { "dtype": "float32", "shape": [1, 4097, 4097, 2], "tolerance": 0.0001 } }
70
+ },
71
+ {
72
+ "name": "identity_2x2_align_corners",
73
+ "attrs": { "align_corners": 1 },
74
+ "inputs": {
75
+ "theta": {
76
+ "dtype": "float32",
77
+ "shape": [1, 2, 3],
78
+ "data": { "kind": "values", "values": [1.0, 0.0, 0.0, 0.0, 1.0, 0.0] }
79
+ }
80
+ },
81
+ "outputs": { "grid": { "dtype": "float32", "shape": [1, 2, 2, 2] } },
82
+ "tolerance": 0.000001
83
+ },
84
+ {
85
+ "name": "translate_f16",
86
+ "attrs": { "align_corners": 0 },
87
+ "inputs": {
88
+ "theta": {
89
+ "dtype": "float16",
90
+ "shape": [1, 2, 3],
91
+ "data": { "kind": "values", "values": [1.0, 0.0, 0.5, 0.0, 1.0, -0.5] }
92
+ }
93
+ },
94
+ "outputs": { "grid": { "dtype": "float16", "shape": [1, 2, 2, 2] } },
95
+ "tolerance": 0.002
96
+ },
97
+ {
98
+ "name": "identity_3x4_no_align_corners",
99
+ "attrs": { "align_corners": 0 },
100
+ "inputs": {
101
+ "theta": {
102
+ "dtype": "float32",
103
+ "shape": [1, 2, 3],
104
+ "data": { "kind": "values", "values": [1.0, 0.0, 0.0, 0.0, 1.0, 0.0] }
105
+ }
106
+ },
107
+ "outputs": { "grid": { "dtype": "float32", "shape": [1, 3, 4, 2], "tolerance": 0.000001 } }
108
+ },
109
+ {
110
+ "name": "batch2_scale_translate_align_corners",
111
+ "attrs": { "align_corners": 1 },
112
+ "inputs": {
113
+ "theta": {
114
+ "dtype": "float32",
115
+ "shape": [2, 2, 3],
116
+ "data": { "kind": "values", "values": [1.0, 0.0, 0.25, 0.0, 1.0, -0.25, 0.5, 0.0, -0.5, 0.0, 0.5, 0.5] }
117
+ }
118
+ },
119
+ "outputs": { "grid": { "dtype": "float32", "shape": [2, 2, 3, 2], "tolerance": 0.000001 } }
120
+ },
121
+ {
122
+ "name": "ort_generated_2d_rotation_shear_no_align",
123
+ "provenance": {
124
+ "source": "onnxruntime/test/providers/cpu/tensor/affine_grid_test_gen.py",
125
+ "test": "AffineGridTest.test_2d_0",
126
+ "notes": "Generated ORT fixture materialized in affine_grid_test.cc."
127
+ },
128
+ "attrs": { "align_corners": 0 },
129
+ "inputs": {
130
+ "theta": {
131
+ "dtype": "float32",
132
+ "shape": [1, 2, 3],
133
+ "data": { "kind": "values", "values": [1.477212, -0.173648, 0.3, 0.173648, 0.492404, -0.5] }
134
+ }
135
+ },
136
+ "outputs": { "grid": { "dtype": "float32", "shape": [1, 3, 2, 2], "tolerance": 0.0001 } }
137
+ },
138
+ {
139
+ "name": "ort_generated_2d_batch2_align_corners",
140
+ "provenance": {
141
+ "source": "onnxruntime/test/providers/cpu/tensor/affine_grid_test.cc",
142
+ "test": "AffineGridTest.test_2d_7"
143
+ },
144
+ "attrs": { "align_corners": 1 },
145
+ "inputs": {
146
+ "theta": {
147
+ "dtype": "float32",
148
+ "shape": [2, 2, 3],
149
+ "data": {
150
+ "kind": "values",
151
+ "values": [1.5, -0.866025, -0.5, 0.866025, 2.75, -0.5, 1.5, -0.866025, -0.5, 0.866025, 2.75, -0.5]
152
+ }
153
+ }
154
+ },
155
+ "outputs": { "grid": { "dtype": "float32", "shape": [2, 2, 3, 2], "tolerance": 0.0001 } }
156
+ },
157
+ {
158
+ "name": "ort_2d_identity_default_no_align",
159
+ "provenance": {
160
+ "source": "onnxruntime/test/providers/cpu/tensor/affine_grid_test.cc",
161
+ "test": "AffineGridTest.2d"
162
+ },
163
+ "inputs": {
164
+ "theta": {
165
+ "dtype": "float32",
166
+ "shape": [1, 2, 3],
167
+ "data": { "kind": "values", "values": [1.0, 0.0, 0.0, 0.0, 1.0, 0.0] }
168
+ }
169
+ },
170
+ "outputs": { "grid": { "dtype": "float32", "shape": [1, 2, 3, 2], "tolerance": 0.0001 } }
171
+ },
172
+ {
173
+ "name": "ort_generated_2d_batch2_no_align",
174
+ "provenance": {
175
+ "source": "onnxruntime/test/providers/cpu/tensor/affine_grid_test.cc",
176
+ "test": "AffineGridTest.test_2d_1"
177
+ },
178
+ "attrs": { "align_corners": 0 },
179
+ "inputs": {
180
+ "theta": {
181
+ "dtype": "float32",
182
+ "shape": [2, 2, 3],
183
+ "data": {
184
+ "kind": "values",
185
+ "values": [1.477212, -0.173648, 0.3, 0.173648, 0.492404, -0.5, 1.477212, -0.173648, 0.3, 0.173648, 0.492404, -0.5]
186
+ }
187
+ }
188
+ },
189
+ "outputs": { "grid": { "dtype": "float32", "shape": [2, 2, 3, 2], "tolerance": 0.0001 } }
190
+ },
191
+ {
192
+ "name": "ort_generated_2d_stronger_transform_no_align",
193
+ "provenance": {
194
+ "source": "onnxruntime/test/providers/cpu/tensor/affine_grid_test.cc",
195
+ "test": "AffineGridTest.test_2d_2"
196
+ },
197
+ "attrs": { "align_corners": 0 },
198
+ "inputs": {
199
+ "theta": {
200
+ "dtype": "float32",
201
+ "shape": [1, 2, 3],
202
+ "data": { "kind": "values", "values": [1.5, -0.866025, -0.5, 0.866025, 2.75, -0.5] }
203
+ }
204
+ },
205
+ "outputs": { "grid": { "dtype": "float32", "shape": [1, 3, 2, 2], "tolerance": 0.0001 } }
206
+ },
207
+ {
208
+ "name": "ort_generated_2d_rotation_shear_align_corners",
209
+ "provenance": {
210
+ "source": "onnxruntime/test/providers/cpu/tensor/affine_grid_test.cc",
211
+ "test": "AffineGridTest.test_2d_4"
212
+ },
213
+ "attrs": { "align_corners": 1 },
214
+ "inputs": {
215
+ "theta": {
216
+ "dtype": "float32",
217
+ "shape": [1, 2, 3],
218
+ "data": { "kind": "values", "values": [1.477212, -0.173648, 0.3, 0.173648, 0.492404, -0.5] }
219
+ }
220
+ },
221
+ "outputs": { "grid": { "dtype": "float32", "shape": [1, 3, 2, 2], "tolerance": 0.0001 } }
222
+ },
223
+ {
224
+ "name": "ort_generated_2d_stronger_transform_batch2_no_align",
225
+ "provenance": {
226
+ "source": "onnxruntime/test/providers/cpu/tensor/affine_grid_test.cc",
227
+ "test": "AffineGridTest.test_2d_3"
228
+ },
229
+ "attrs": { "align_corners": 0 },
230
+ "inputs": {
231
+ "theta": {
232
+ "dtype": "float32",
233
+ "shape": [2, 2, 3],
234
+ "data": {
235
+ "kind": "values",
236
+ "values": [1.5, -0.866025, -0.5, 0.866025, 2.75, -0.5, 1.5, -0.866025, -0.5, 0.866025, 2.75, -0.5]
237
+ }
238
+ }
239
+ },
240
+ "outputs": { "grid": { "dtype": "float32", "shape": [2, 2, 3, 2], "tolerance": 0.0001 } }
241
+ },
242
+ {
243
+ "name": "ort_generated_2d_rotation_shear_batch2_align_corners",
244
+ "provenance": {
245
+ "source": "onnxruntime/test/providers/cpu/tensor/affine_grid_test.cc",
246
+ "test": "AffineGridTest.test_2d_5"
247
+ },
248
+ "attrs": { "align_corners": 1 },
249
+ "inputs": {
250
+ "theta": {
251
+ "dtype": "float32",
252
+ "shape": [2, 2, 3],
253
+ "data": {
254
+ "kind": "values",
255
+ "values": [1.477212, -0.173648, 0.3, 0.173648, 0.492404, -0.5, 1.477212, -0.173648, 0.3, 0.173648, 0.492404, -0.5]
256
+ }
257
+ }
258
+ },
259
+ "outputs": { "grid": { "dtype": "float32", "shape": [2, 2, 3, 2], "tolerance": 0.0001 } }
260
+ },
261
+ {
262
+ "name": "ort_generated_2d_stronger_transform_align_corners",
263
+ "provenance": {
264
+ "source": "onnxruntime/test/providers/cpu/tensor/affine_grid_test.cc",
265
+ "test": "AffineGridTest.test_2d_6"
266
+ },
267
+ "attrs": { "align_corners": 1 },
268
+ "inputs": {
269
+ "theta": {
270
+ "dtype": "float32",
271
+ "shape": [1, 2, 3],
272
+ "data": { "kind": "values", "values": [1.5, -0.866025, -0.5, 0.866025, 2.75, -0.5] }
273
+ }
274
+ },
275
+ "outputs": { "grid": { "dtype": "float32", "shape": [1, 3, 2, 2], "tolerance": 0.0001 } }
276
+ },
277
+ {
278
+ "name": "ort_generated_3d_rotation_shear_no_align",
279
+ "provenance": {
280
+ "source": "onnxruntime/test/providers/cpu/tensor/affine_grid_test.cc",
281
+ "test": "AffineGridTest.test_3d_0"
282
+ },
283
+ "attrs": { "align_corners": 0 },
284
+ "inputs": {
285
+ "theta": {
286
+ "dtype": "float32",
287
+ "shape": [1, 3, 4],
288
+ "data": {
289
+ "kind": "values",
290
+ "values": [1.409539, 0.0, 0.51303, 0.3, 0.118782, 1.969615, -0.326352, -0.5, -0.168412, 0.086824, 0.462708, 1.8]
291
+ }
292
+ }
293
+ },
294
+ "outputs": { "grid": { "dtype": "float32", "shape": [1, 3, 2, 2, 3], "tolerance": 0.0001 } }
295
+ },
296
+ {
297
+ "name": "ort_generated_3d_rotation_shear_batch2_no_align",
298
+ "provenance": {
299
+ "source": "onnxruntime/test/providers/cpu/tensor/affine_grid_test.cc",
300
+ "test": "AffineGridTest.test_3d_1"
301
+ },
302
+ "attrs": { "align_corners": 0 },
303
+ "inputs": {
304
+ "theta": {
305
+ "dtype": "float32",
306
+ "shape": [2, 3, 4],
307
+ "data": {
308
+ "kind": "values",
309
+ "values": { "$ref": "#/fixtureArrays/ort_generated_3d_rotation_shear_batch2_no_align_input_theta" }
310
+ }
311
+ }
312
+ },
313
+ "outputs": { "grid": { "dtype": "float32", "shape": [2, 2, 2, 3, 3], "tolerance": 0.0001 } }
314
+ },
315
+ {
316
+ "name": "ort_generated_3d_stronger_transform_no_align",
317
+ "provenance": {
318
+ "source": "onnxruntime/test/providers/cpu/tensor/affine_grid_test.cc",
319
+ "test": "AffineGridTest.test_3d_2"
320
+ },
321
+ "attrs": { "align_corners": 0 },
322
+ "inputs": {
323
+ "theta": {
324
+ "dtype": "float32",
325
+ "shape": [1, 3, 4],
326
+ "data": {
327
+ "kind": "values",
328
+ "values": [0.259808, 0.0, -0.15, -0.5, -1.299038, 1.5, -2.25, -0.5, 1.375, 4.76314, 2.38157, 0.3]
329
+ }
330
+ }
331
+ },
332
+ "outputs": { "grid": { "dtype": "float32", "shape": [1, 3, 2, 2, 3], "tolerance": 0.0001 } }
333
+ },
334
+ {
335
+ "name": "ort_generated_3d_stronger_transform_batch2_no_align",
336
+ "provenance": {
337
+ "source": "onnxruntime/test/providers/cpu/tensor/affine_grid_test.cc",
338
+ "test": "AffineGridTest.test_3d_3"
339
+ },
340
+ "attrs": { "align_corners": 0 },
341
+ "inputs": {
342
+ "theta": {
343
+ "dtype": "float32",
344
+ "shape": [2, 3, 4],
345
+ "data": {
346
+ "kind": "values",
347
+ "values": { "$ref": "#/fixtureArrays/ort_generated_3d_stronger_transform_batch2_no_align_input_theta" }
348
+ }
349
+ }
350
+ },
351
+ "outputs": { "grid": { "dtype": "float32", "shape": [2, 2, 2, 3, 3], "tolerance": 0.0001 } }
352
+ },
353
+ {
354
+ "name": "ort_generated_3d_rotation_shear_align_corners",
355
+ "provenance": {
356
+ "source": "onnxruntime/test/providers/cpu/tensor/affine_grid_test.cc",
357
+ "test": "AffineGridTest.test_3d_4"
358
+ },
359
+ "attrs": { "align_corners": 1 },
360
+ "inputs": {
361
+ "theta": {
362
+ "dtype": "float32",
363
+ "shape": [1, 3, 4],
364
+ "data": {
365
+ "kind": "values",
366
+ "values": [1.409539, 0.0, 0.51303, 0.3, 0.118782, 1.969615, -0.326352, -0.5, -0.168412, 0.086824, 0.462708, 1.8]
367
+ }
368
+ }
369
+ },
370
+ "outputs": { "grid": { "dtype": "float32", "shape": [1, 3, 2, 2, 3], "tolerance": 0.0001 } }
371
+ },
372
+ {
373
+ "name": "ort_generated_3d_rotation_shear_batch2_align_corners",
374
+ "provenance": {
375
+ "source": "onnxruntime/test/providers/cpu/tensor/affine_grid_test.cc",
376
+ "test": "AffineGridTest.test_3d_5"
377
+ },
378
+ "attrs": { "align_corners": 1 },
379
+ "inputs": {
380
+ "theta": {
381
+ "dtype": "float32",
382
+ "shape": [2, 3, 4],
383
+ "data": {
384
+ "kind": "values",
385
+ "values": { "$ref": "#/fixtureArrays/ort_generated_3d_rotation_shear_batch2_no_align_input_theta" }
386
+ }
387
+ }
388
+ },
389
+ "outputs": { "grid": { "dtype": "float32", "shape": [2, 2, 2, 3, 3], "tolerance": 0.0001 } }
390
+ },
391
+ {
392
+ "name": "ort_generated_3d_stronger_transform_align_corners",
393
+ "provenance": {
394
+ "source": "onnxruntime/test/providers/cpu/tensor/affine_grid_test.cc",
395
+ "test": "AffineGridTest.test_3d_6"
396
+ },
397
+ "attrs": { "align_corners": 1 },
398
+ "inputs": {
399
+ "theta": {
400
+ "dtype": "float32",
401
+ "shape": [1, 3, 4],
402
+ "data": {
403
+ "kind": "values",
404
+ "values": [0.259808, 0.0, -0.15, -0.5, -1.299038, 1.5, -2.25, -0.5, 1.375, 4.76314, 2.38157, 0.3]
405
+ }
406
+ }
407
+ },
408
+ "outputs": { "grid": { "dtype": "float32", "shape": [1, 3, 2, 2, 3], "tolerance": 0.0001 } }
409
+ },
410
+ {
411
+ "name": "ort_generated_3d_stronger_transform_batch2_align_corners",
412
+ "provenance": {
413
+ "source": "onnxruntime/test/providers/cpu/tensor/affine_grid_test.cc",
414
+ "test": "AffineGridTest.test_3d_7"
415
+ },
416
+ "attrs": { "align_corners": 1 },
417
+ "inputs": {
418
+ "theta": {
419
+ "dtype": "float32",
420
+ "shape": [2, 3, 4],
421
+ "data": {
422
+ "kind": "values",
423
+ "values": { "$ref": "#/fixtureArrays/ort_generated_3d_stronger_transform_batch2_no_align_input_theta" }
424
+ }
425
+ }
426
+ },
427
+ "outputs": { "grid": { "dtype": "float32", "shape": [2, 2, 2, 3, 3], "tolerance": 0.0001 } }
428
+ },
429
+ {
430
+ "name": "onnx_backend_affine_grid_2d",
431
+ "provenance": {
432
+ "source": "cmake/external/onnx/onnx/backend/test/data/node/test_affine_grid_2d",
433
+ "notes": "Official size metadata is represented by the output grid shape in this framework."
434
+ },
435
+ "attrs": { "align_corners": 0 },
436
+ "inputs": {
437
+ "theta": {
438
+ "dtype": "float32",
439
+ "shape": [2, 2, 3],
440
+ "data": {
441
+ "kind": "values",
442
+ "values": [1.088944435119629, -3.2880465984344482, 5.0, 2.022325277328491, 1.096015453338623, -3.299999952316284, 0.835788369178772, -0.5544228553771973, 2.5, 0.7876279354095459, 0.8397114276885986, 1.100000023841858]
443
+ }
444
+ }
445
+ },
446
+ "outputs": { "grid": { "dtype": "float32", "shape": [2, 5, 6, 2], "tolerance": 0.00001 } }
447
+ },
448
+ {
449
+ "name": "onnx_backend_affine_grid_2d_align_corners",
450
+ "provenance": {
451
+ "source": "cmake/external/onnx/onnx/backend/test/data/node/test_affine_grid_2d_align_corners",
452
+ "notes": "Official size metadata is represented by the output grid shape in this framework."
453
+ },
454
+ "attrs": { "align_corners": 1 },
455
+ "inputs": {
456
+ "theta": {
457
+ "dtype": "float32",
458
+ "shape": [2, 2, 3],
459
+ "data": {
460
+ "kind": "values",
461
+ "values": [1.088944435119629, -3.2880465984344482, 5.0, 2.022325277328491, 1.096015453338623, -3.299999952316284, 0.835788369178772, -0.5544228553771973, 2.5, 0.7876279354095459, 0.8397114276885986, 1.100000023841858]
462
+ }
463
+ }
464
+ },
465
+ "outputs": { "grid": { "dtype": "float32", "shape": [2, 5, 6, 2], "tolerance": 0.00001 } }
466
+ },
467
+ {
468
+ "name": "onnx_backend_affine_grid_3d",
469
+ "provenance": {
470
+ "source": "cmake/external/onnx/onnx/backend/test/data/node/test_affine_grid_3d",
471
+ "notes": "Official size metadata is represented by the output grid shape in this framework."
472
+ },
473
+ "attrs": { "align_corners": 0 },
474
+ "inputs": {
475
+ "theta": {
476
+ "dtype": "float32",
477
+ "shape": [2, 3, 4],
478
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/onnx_backend_affine_grid_3d_input_theta" } }
479
+ }
480
+ },
481
+ "outputs": { "grid": { "dtype": "float32", "shape": [2, 4, 5, 6, 3], "tolerance": 0.00001 } }
482
+ },
483
+ {
484
+ "name": "onnx_backend_affine_grid_3d_align_corners",
485
+ "provenance": {
486
+ "source": "cmake/external/onnx/onnx/backend/test/data/node/test_affine_grid_3d_align_corners",
487
+ "notes": "Official size metadata is represented by the output grid shape in this framework."
488
+ },
489
+ "attrs": { "align_corners": 1 },
490
+ "inputs": {
491
+ "theta": {
492
+ "dtype": "float32",
493
+ "shape": [2, 3, 4],
494
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/onnx_backend_affine_grid_3d_input_theta" } }
495
+ }
496
+ },
497
+ "outputs": { "grid": { "dtype": "float32", "shape": [2, 4, 5, 6, 3], "tolerance": 0.00001 } }
498
+ },
499
+ {
500
+ "name": "empty_zero_dim",
501
+ "attrs": { "align_corners": 0 },
502
+ "inputs": { "theta": { "dtype": "float32", "shape": [0, 2, 3], "data": { "kind": "values", "values": [] } } },
503
+ "outputs": { "grid": { "dtype": "float32", "shape": [0, 2, 2, 2], "tolerance": 0 } }
504
+ },
505
+ {
506
+ "name": "empty_zero_dim_f16",
507
+ "attrs": { "align_corners": 0 },
508
+ "inputs": { "theta": { "dtype": "float16", "shape": [0, 2, 3], "data": { "kind": "values", "values": [] } } },
509
+ "outputs": { "grid": { "dtype": "float16", "shape": [0, 2, 2, 2], "tolerance": 0 } }
510
+ },
511
+ {
512
+ "name": "align_corners_1_h1_w3_identity",
513
+ "attrs": { "align_corners": 1 },
514
+ "inputs": {
515
+ "theta": {
516
+ "dtype": "float32",
517
+ "shape": [1, 2, 3],
518
+ "data": { "kind": "values", "values": [1.0, 0.0, 0.0, 0.0, 1.0, 0.0] }
519
+ }
520
+ },
521
+ "outputs": { "grid": { "dtype": "float32", "shape": [1, 1, 3, 2], "tolerance": 0.000001 } }
522
+ },
523
+ {
524
+ "name": "3d_f16_identity_no_align",
525
+ "attrs": { "align_corners": 0 },
526
+ "inputs": {
527
+ "theta": {
528
+ "dtype": "float16",
529
+ "shape": [1, 3, 4],
530
+ "data": { "kind": "values", "values": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0] }
531
+ }
532
+ },
533
+ "outputs": { "grid": { "dtype": "float16", "shape": [1, 2, 2, 2, 3] } },
534
+ "tolerance": 0.002
535
+ },
536
+ {
537
+ "name": "affine_grid3d_w4_coarsened_f16",
538
+ "provenance": {
539
+ "notes": "A float16 width-by-four 3D grid checks half-precision inputs and output on the vectorized 3D path."
540
+ },
541
+ "attrs": { "align_corners": 0 },
542
+ "inputs": {
543
+ "theta": {
544
+ "dtype": "float16",
545
+ "shape": [1, 3, 4],
546
+ "data": { "kind": "values", "values": [1.0, 0.1, 0.0, 0.05, 0.0, 1.0, -0.1, -0.05, 0.1, 0.0, 1.0, 0.0] }
547
+ }
548
+ },
549
+ "outputs": { "grid": { "dtype": "float16", "shape": [1, 2, 3, 4, 3], "tolerance": 0.002 } }
550
+ },
551
+ {
552
+ "name": "affine_grid3d_w4_align_corners",
553
+ "provenance": {
554
+ "notes": "align_corners=1 on the width-by-four 3D grid. The flag changes the normalized-coordinate step the kernel bakes in, and every case that reached this route left it at 0."
555
+ },
556
+ "attrs": { "align_corners": 1 },
557
+ "inputs": {
558
+ "theta": {
559
+ "dtype": "float32",
560
+ "shape": [1, 3, 4],
561
+ "data": { "kind": "values", "values": [1.0, 0.1, 0.0, 0.05, 0.0, 1.0, -0.1, -0.05, 0.1, 0.0, 1.0, 0.0] }
562
+ }
563
+ },
564
+ "outputs": { "grid": { "dtype": "float32", "shape": [1, 2, 3, 4, 3], "tolerance": 0.000001 } }
565
+ }
566
+ ]
567
+ }