Xenova HF Staff commited on
Commit
c4a6897
·
verified ·
1 Parent(s): 07147ca

sync 2e7068faf55e

Browse files
README.md CHANGED
@@ -1,3 +1,67 @@
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
+ # com.microsoft.QuickGelu
10
+
11
+ `com.microsoft` · ONNX Runtime contrib operator · contrib since_version 1
12
+
13
+ ## Description
14
+
15
+ Computes `x * sigmoid(alpha * x)` elementwise, a fast approximation of GELU activation. The output has the same shape as the input. This WebGPU package implements float16 and float32; the schema-allowed double and bfloat16 types are not supported.
16
+
17
+ See the [ONNX Runtime `QuickGelu` contrib-operator spec](https://github.com/microsoft/onnxruntime/blob/main/docs/ContribOperators.md#com.microsoft.QuickGelu) for the reference semantics.
18
+
19
+ ## Inputs
20
+
21
+ | Name | Bind key | Logical dtype | Rank | Shape | Description | Presence |
22
+ | --- | --- | --- | --- | --- | --- | --- |
23
+ | `X` | `X` | `T` | — | — | Input tensor of any shape. | required |
24
+
25
+ ## Outputs
26
+
27
+ | Name | Bind key | Logical dtype | Rank | Shape | Description | Presence |
28
+ | --- | --- | --- | --- | --- | --- | --- |
29
+ | `Y` | `Y` | `T` | same as `X` | same as `X` | Output tensor; same shape as the input. | required |
30
+
31
+ ## Attributes
32
+
33
+ Default values (overridable per request):
34
+
35
+ | Attribute | Default | Description |
36
+ | --- | --- | --- |
37
+ | `alpha` | `1.702` | Scalar multiplier applied to `x` inside the sigmoid; defaults to 1.702, which approximates GELU. |
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
+ - [`quick-gelu.wgsl.jinja`](build/webgpu/quick-gelu.wgsl.jinja)
52
+
53
+ ## Use with `@huggingface/kernels`
54
+
55
+ The loader derives every required output's shape and logical dtype from the manifest contract and this call.
56
+ It then allocates the result tensors automatically.
57
+
58
+ The `version: 1` option selects the published kernel contract; it is independent of any operator opset, contrib `since_version`, or model version.
59
+
60
+ Replace each `*Data` placeholder with a typed array containing the corresponding input data.
61
+
62
+ ```js
63
+ import { getKernel } from "@huggingface/kernels";
64
+
65
+ const kernel = await getKernel("webgpu-kernels/com.microsoft.QuickGelu", { version: 1 });
66
+ const { Y } = await kernel({ X: { data: XData, shape: [2, 4] } });
67
+ ```
build/webgpu/bench.json ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "op": "com.microsoft.QuickGelu",
3
+ "tunableSpace": { "WORKGROUP_SIZE": [64, 128, 256] },
4
+ "cases": [
5
+ {
6
+ "name": "quickgelu-f32-4096x3072",
7
+ "preset": "smoke",
8
+ "vars": { "dtype": "float32" },
9
+ "inputs": { "X": { "shape": [4096, 3072], "dtype": "float32", "dist": "normal", "seed": 720, "scale": 2 } },
10
+ "outputs": { "Y": { "shape": [4096, 3072], "dtype": "float32" } },
11
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "4096 * 3072 * 2 * dtypeBytes(args.dtype)" }] }
12
+ },
13
+ {
14
+ "name": "quickgelu-f16-4096x3072",
15
+ "preset": "model",
16
+ "vars": { "dtype": "float16" },
17
+ "inputs": { "X": { "shape": [4096, 3072], "dtype": "float16", "dist": "normal", "seed": 721, "scale": 2 } },
18
+ "outputs": { "Y": { "shape": [4096, 3072], "dtype": "float16" } },
19
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "4096 * 3072 * 2 * dtypeBytes(args.dtype)" }] }
20
+ },
21
+ {
22
+ "name": "quickgelu-f32-scalar-cliff-odd-numel",
23
+ "preset": "stress",
24
+ "attrs": { "alpha": 1.702 },
25
+ "vars": { "dtype": "float32" },
26
+ "inputs": { "X": { "shape": [2049, 2047], "dtype": "float32", "dist": "normal", "seed": 7201, "scale": 2 } },
27
+ "outputs": { "Y": { "shape": [2049, 2047], "dtype": "float32" } },
28
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "2049 * 2047 * 2 * dtypeBytes(args.dtype)" }] }
29
+ }
30
+ ]
31
+ }
build/webgpu/manifest.json ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "domain": "com.microsoft",
3
+ "name": "QuickGelu",
4
+ "sinceVersion": 1,
5
+ "description": "Computes `x * sigmoid(alpha * x)` elementwise, a fast approximation of GELU activation. The output has the same shape as the input. This WebGPU package implements float16 and float32; the schema-allowed double and bfloat16 types are not supported.",
6
+ "inputs": [{ "role": "X", "dtype": "T", "description": "Input tensor of any shape." }],
7
+ "outputs": [
8
+ {
9
+ "role": "Y",
10
+ "dtype": "T",
11
+ "rank": "ranks.X",
12
+ "shape": "shapes.X",
13
+ "description": "Output tensor; same shape as the input."
14
+ }
15
+ ],
16
+ "attributes": { "alpha": 1.702 },
17
+ "attributeDescriptions": {
18
+ "alpha": "Scalar multiplier applied to `x` inside the sigmoid; defaults to 1.702, which approximates GELU."
19
+ },
20
+ "typeConstraints": { "T": ["float32", "float16"] },
21
+ "args": {
22
+ "X": { "kind": "tensor", "semantic": "X", "role": "input" },
23
+ "Y": { "kind": "tensor", "semantic": "Y", "role": "output" }
24
+ },
25
+ "tunables": { "WORKGROUP_SIZE": 256 },
26
+ "derive": {
27
+ "deviceWorkgroupCap": "min(device.limits.maxComputeInvocationsPerWorkgroup, device.limits.maxComputeWorkgroupSizeX)",
28
+ "workgroupOk": "tunables.WORKGROUP_SIZE > 0 and tunables.WORKGROUP_SIZE <= deviceWorkgroupCap",
29
+ "baseOk": "workgroupOk and numel(shapes.X) == numel(shapes.Y) and f16Ok(dtypes.T)",
30
+ "vec4Ok": "numel(shapes.X) > 0 and numel(shapes.X) % 4 == 0"
31
+ },
32
+ "bindingSets": {
33
+ "scalarTail": [
34
+ { "name": "x", "arg": "X", "semantic": "X", "buffer": { "type": "read-only-storage" }, "elementType": "$scalar" },
35
+ { "name": "y", "arg": "Y", "semantic": "Y", "buffer": { "type": "storage" }, "elementType": "$scalar" },
36
+ {
37
+ "name": "params",
38
+ "semantic": "kernel.params",
39
+ "buffer": { "type": "uniform" },
40
+ "struct": { "name": "Params", "fields": [{ "name": "count", "type": "u32", "value": "numel(shapes.X)" }] }
41
+ }
42
+ ]
43
+ },
44
+ "variants": [
45
+ {
46
+ "id": "vec4",
47
+ "priority": 20,
48
+ "when": ["baseOk", "vec4Ok"],
49
+ "constants": {
50
+ "scalar": "dtypes.T",
51
+ "usesF16": "dtypes.T == \"f16\"",
52
+ "vectorScalar": "\"vec4<\" ~ dtypes.T ~ \">\"",
53
+ "vec4": true,
54
+ "vec4Tail": false
55
+ },
56
+ "passes": [
57
+ {
58
+ "id": "main",
59
+ "name": "QuickGelu.vec4",
60
+ "source": { "shader": "quick-gelu.wgsl.jinja", "inputs": { "alpha": "attrs.alpha" } },
61
+ "bindings": [
62
+ {
63
+ "name": "x",
64
+ "arg": "X",
65
+ "semantic": "X",
66
+ "buffer": { "type": "read-only-storage" },
67
+ "elementType": "$vectorScalar"
68
+ },
69
+ {
70
+ "name": "y",
71
+ "arg": "Y",
72
+ "semantic": "Y",
73
+ "buffer": { "type": "storage" },
74
+ "elementType": "$vectorScalar"
75
+ },
76
+ {
77
+ "name": "params",
78
+ "semantic": "kernel.params",
79
+ "buffer": { "type": "uniform" },
80
+ "struct": {
81
+ "name": "Params",
82
+ "fields": [{ "name": "count", "type": "u32", "value": "numel(shapes.X) / 4" }]
83
+ }
84
+ }
85
+ ],
86
+ "dispatch": { "threads": "numel(shapes.X) / 4", "workgroupSize": "tunables.WORKGROUP_SIZE" }
87
+ }
88
+ ]
89
+ },
90
+ {
91
+ "id": "vec4_tail",
92
+ "priority": 10,
93
+ "when": ["baseOk", "numel(shapes.X) > 0"],
94
+ "constants": { "scalar": "dtypes.T", "usesF16": "dtypes.T == \"f16\"", "vec4": false, "vec4Tail": true },
95
+ "passes": [
96
+ {
97
+ "id": "main",
98
+ "name": "QuickGelu.vec4Tail",
99
+ "source": { "shader": "quick-gelu.wgsl.jinja", "inputs": { "alpha": "attrs.alpha" } },
100
+ "bindings": "scalarTail",
101
+ "dispatch": { "threads": "ceilDiv(numel(shapes.X), 4)", "workgroupSize": "tunables.WORKGROUP_SIZE" }
102
+ }
103
+ ]
104
+ },
105
+ {
106
+ "id": "scalar",
107
+ "priority": 0,
108
+ "when": ["baseOk", "true"],
109
+ "constants": { "scalar": "dtypes.T", "usesF16": "dtypes.T == \"f16\"", "vec4": false, "vec4Tail": false },
110
+ "passes": [
111
+ {
112
+ "id": "main",
113
+ "name": "QuickGelu.scalar",
114
+ "source": { "shader": "quick-gelu.wgsl.jinja", "inputs": { "alpha": "attrs.alpha" } },
115
+ "bindings": "scalarTail",
116
+ "dispatch": { "threads": "numel(shapes.X)", "workgroupSize": "tunables.WORKGROUP_SIZE" }
117
+ }
118
+ ]
119
+ }
120
+ ]
121
+ }
build/webgpu/metadata.json ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "com.microsoft.QuickGelu",
3
+ "id": "_com_microsoft_quickgelu_webgpu_75eb0ab",
4
+ "version": 1,
5
+ "license": "Apache-2.0",
6
+ "backend": { "type": "webgpu" },
7
+ "digest": {
8
+ "algorithm": "sha256",
9
+ "files": {
10
+ "bench.json": "g3U1AfptsaN7o7RQkF70XpQkOLCsBrZIr0WbKXyeZF4=",
11
+ "manifest.json": "DEC3xwPqmogreS46virRjZUF4PzWGkJwGMQ0ku4ytok=",
12
+ "quick-gelu.wgsl.jinja": "vBvqUo8P4UGy3DVJFBNcoTPinSfCxWFoIX77f9s6Zro=",
13
+ "test.json": "ErgPevOReyIn0tBPjmUMYo73FIwanLWeFzQmyXeSOak="
14
+ }
15
+ },
16
+ "provenance": { "kernel": { "sha": "2e7068faf55e7f43df740015f6d1ee49391a41c5", "dirty": false } },
17
+ "webgpu": { "manifestSpec": "1.0", "specialized": true, "opPath": "ops/com.microsoft.QuickGelu" }
18
+ }
build/webgpu/quick-gelu.wgsl.jinja ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ // com.microsoft.QuickGelu : Y = X * sigmoid(alpha * X)
40
+ // sigmoid here uses the stable two-branch form so the gate never overflows
41
+ // for extreme magnitudes (alpha*x = +/-1702 for x = -/+1000 with the default
42
+ // alpha): the naive 1/(1+exp(-alpha*x)) computes exp(+1702) = Inf and yields
43
+ // Inf/Inf = NaN, while exp(z)/(1+exp(z)) (z <= 0) and 1/(1+exp(-z)) (z >= 0)
44
+ // each only ever evaluate exp of a non-positive argument. ALPHA is compiled
45
+ // as a constant; alpha == 0 collapses to sigmoid(0) = 0.5 exactly (the
46
+ // z >= 0 branch: 1/(1+exp(0))).
47
+ const ALPHA: f32 = f32({{ source.alpha }});
48
+
49
+ fn sigmoid_stable(z: f32) -> f32 {
50
+ if (z >= 0.0) {
51
+ return 1.0 / (1.0 + exp(-z));
52
+ }
53
+ let e = exp(z);
54
+ return e / (1.0 + e);
55
+ }
56
+
57
+ fn quick_gelu(v: f32) -> f32 {
58
+ return v * sigmoid_stable(ALPHA * v);
59
+ }
60
+
61
+ @compute @workgroup_size({{ tunables.WORKGROUP_SIZE }})
62
+ fn main(@builtin(global_invocation_id) gid: vec3<u32>, @builtin(num_workgroups) nwg: vec3<u32>) {
63
+ {{ flat_index_2d() }}
64
+ {% if vec4Tail %}
65
+ let base = i * 4u;
66
+ {% for lane in range(4) %}
67
+ if (base + {{ lane }}u < params.count) {
68
+ y[base + {{ lane }}u] = {{ scalar }}(quick_gelu(f32(x[base + {{ lane }}u])));
69
+ }
70
+ {% endfor %}
71
+ {% elif vec4 %}
72
+ let fv = vec4<f32>(x[i]);
73
+ y[i] = vec4<{{ scalar }}>(vec4<f32>(quick_gelu(fv.x), quick_gelu(fv.y), quick_gelu(fv.z), quick_gelu(fv.w)));
74
+ {% else %}
75
+ y[i] = {{ scalar }}(quick_gelu(f32(x[i])));
76
+ {% endif %}
77
+ }
build/webgpu/test.json ADDED
@@ -0,0 +1,248 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "op": "com.microsoft.QuickGelu",
3
+ "cases": [
4
+ {
5
+ "name": "dispatch_cliff_scalar_over_16M",
6
+ "attrs": { "alpha": 1.702 },
7
+ "inputs": {
8
+ "X": { "dtype": "float32", "shape": [16776961], "data": { "kind": "linspace", "start": -4.0, "end": 4.0 } }
9
+ },
10
+ "outputs": { "Y": { "dtype": "float32", "shape": [16776961], "tolerance": 0.0001 } }
11
+ },
12
+ {
13
+ "name": "ort_default_alpha_extreme_safe_sigmoid",
14
+ "provenance": {
15
+ "source": "onnxruntime/test/contrib_ops/activation_op_test.cc",
16
+ "test": "ActivationOpTest.QuickGelu",
17
+ "notes": "Default alpha path over very large magnitudes; the safe sigmoid should not overflow."
18
+ },
19
+ "inputs": {
20
+ "X": {
21
+ "dtype": "float32",
22
+ "shape": [1, 9],
23
+ "data": { "kind": "values", "values": [-1000.0, -100.0, -10.0, -1.0, 0.0, 1.0, 10.0, 100.0, 1000.0] }
24
+ }
25
+ },
26
+ "outputs": {
27
+ "Y": {
28
+ "dtype": "float32",
29
+ "shape": [1, 9],
30
+ "tolerance": 0.000001,
31
+ "data": {
32
+ "kind": "values",
33
+ "values": [0.0, 0.0, -2.980232238769531e-7, -0.15420421957969666, 0.0, 0.845795750617981, 10.0, 100.0, 1000.0]
34
+ }
35
+ }
36
+ }
37
+ },
38
+ {
39
+ "name": "ort_alpha_one_matches_silu_edges",
40
+ "provenance": {
41
+ "source": "onnxruntime/test/contrib_ops/activation_op_test.cc",
42
+ "test": "ActivationOpTest.QuickGelu"
43
+ },
44
+ "attrs": { "alpha": 1 },
45
+ "inputs": {
46
+ "X": {
47
+ "dtype": "float32",
48
+ "shape": [7],
49
+ "data": { "kind": "values", "values": [-100.0, -10.0, -1.0, 0.0, 1.0, 10.0, 100.0] }
50
+ }
51
+ },
52
+ "outputs": {
53
+ "Y": {
54
+ "dtype": "float32",
55
+ "shape": [7],
56
+ "tolerance": 0.000001,
57
+ "data": {
58
+ "kind": "values",
59
+ "values": [0.0, -0.0004538893699645996, -0.2689414322376251, 0.0, 0.7310585975646973, 9.99954605102539, 100.0]
60
+ }
61
+ }
62
+ }
63
+ },
64
+ {
65
+ "name": "ort_negative_alpha_flips_gate",
66
+ "provenance": {
67
+ "source": "onnxruntime/test/contrib_ops/activation_op_test.cc",
68
+ "test": "ActivationOpTest.QuickGelu"
69
+ },
70
+ "attrs": { "alpha": -1.702 },
71
+ "inputs": {
72
+ "X": { "dtype": "float32", "shape": [5], "data": { "kind": "values", "values": [-3.0, -1.0, 0.0, 1.0, 3.0] } }
73
+ },
74
+ "outputs": {
75
+ "Y": {
76
+ "dtype": "float32",
77
+ "shape": [5],
78
+ "tolerance": 0.000001,
79
+ "data": {
80
+ "kind": "values",
81
+ "values": [-2.981928825378418, -0.845795750617981, 0.0, 0.15420421957969666, 0.018071293830871582]
82
+ }
83
+ }
84
+ }
85
+ },
86
+ {
87
+ "name": "ort_negative_alpha_extreme_safe_sigmoid",
88
+ "provenance": {
89
+ "source": "onnxruntime/test/contrib_ops/activation_op_test.cc",
90
+ "test": "ActivationOpTest.QuickGelu",
91
+ "notes": "Upstream negative-alpha branch extended over the same large magnitudes as the positive-alpha ORT vector to guard the stable sigmoid reformulation."
92
+ },
93
+ "attrs": { "alpha": -1.702 },
94
+ "inputs": {
95
+ "X": {
96
+ "dtype": "float32",
97
+ "shape": [1, 9],
98
+ "data": { "kind": "values", "values": [-1000.0, -100.0, -10.0, -1.0, 0.0, 1.0, 10.0, 100.0, 1000.0] }
99
+ }
100
+ },
101
+ "outputs": {
102
+ "Y": {
103
+ "dtype": "float32",
104
+ "shape": [1, 9],
105
+ "tolerance": 0.000001,
106
+ "data": {
107
+ "kind": "values",
108
+ "values": [-1000.0, -100.0, -10.0, -0.845795750617981, 0.0, 0.15420423448085785, 4.0579612914370955e-7, 0.0, 0.0]
109
+ }
110
+ }
111
+ }
112
+ },
113
+ {
114
+ "name": "ort_empty_rank4",
115
+ "provenance": {
116
+ "source": "onnxruntime/test/contrib_ops/activation_op_test.cc",
117
+ "notes": "Empty tensors should preserve shape and produce no values."
118
+ },
119
+ "inputs": { "X": { "dtype": "float32", "shape": [1, 0, 2, 3], "data": { "kind": "values", "values": [] } } },
120
+ "outputs": { "Y": { "dtype": "float32", "shape": [1, 0, 2, 3], "data": { "kind": "values", "values": [] } } }
121
+ },
122
+ {
123
+ "name": "vec4_default_alpha_mixed_magnitudes",
124
+ "provenance": {
125
+ "source": "onnxruntime/test/contrib_ops/activation_op_test.cc",
126
+ "test": "ActivationOpTest.QuickGelu",
127
+ "notes": "numel divisible by 4 so the vec4 variant is exercised; default alpha over a spread of signs/magnitudes."
128
+ },
129
+ "inputs": {
130
+ "X": {
131
+ "dtype": "float32",
132
+ "shape": [2, 4],
133
+ "data": { "kind": "values", "values": [-2.0, -0.5, 0.0, 0.5, 2.0, 1.0, -1.0, 4.0] }
134
+ }
135
+ },
136
+ "outputs": {
137
+ "Y": {
138
+ "dtype": "float32",
139
+ "shape": [2, 4],
140
+ "tolerance": 0.000001,
141
+ "data": {
142
+ "kind": "values",
143
+ "values": [-0.06434137374162674, -0.14961156249046326, 0.0, 0.35038843750953674, 1.935658574104309, 0.845795750617981, -0.15420423448085785, 3.9955852031707764]
144
+ }
145
+ }
146
+ }
147
+ },
148
+ {
149
+ "name": "alpha_zero_halves_input",
150
+ "provenance": {
151
+ "source": "onnxruntime/test/contrib_ops/activation_op_test.cc",
152
+ "test": "ActivationOpTest.QuickGelu",
153
+ "notes": "Additional edge: alpha=0 makes sigmoid(alpha*x)=0.5 for every finite x."
154
+ },
155
+ "attrs": { "alpha": 0 },
156
+ "inputs": {
157
+ "X": { "dtype": "float32", "shape": [5], "data": { "kind": "values", "values": [-3.0, -1.0, 0.0, 1.0, 3.0] } }
158
+ },
159
+ "outputs": {
160
+ "Y": {
161
+ "dtype": "float32",
162
+ "shape": [5],
163
+ "tolerance": 0,
164
+ "data": { "kind": "values", "values": [-1.5, -0.5, 0.0, 0.5, 1.5] }
165
+ }
166
+ }
167
+ },
168
+ {
169
+ "name": "alpha_zero_subnormal_half_input_vec4_gpu_gap",
170
+ "skipGpu": {
171
+ "category": "permanent",
172
+ "reason": "Portable WGSL floating-point semantics do not guarantee preservation of the subnormal values required by this fixture. Backend evidence: WebGPU/Metal flushes subnormals to zero (f32 and f16); the kernel cannot preserve denormal inputs/outputs bit-exactly."
173
+ },
174
+ "provenance": {
175
+ "source": "onnxruntime/test/contrib_ops/activation_op_test.cc",
176
+ "test": "ActivationOpTest.QuickGelu",
177
+ "notes": "With alpha=0, QuickGelu is exactly x/2, so signed subnormal inputs should not flush to zero in the vec4 path."
178
+ },
179
+ "attrs": { "alpha": 0 },
180
+ "inputs": {
181
+ "X": {
182
+ "dtype": "float32",
183
+ "shape": [4],
184
+ "data": { "kind": "values", "values": [1e-40, -1e-40, 1e-38, -1e-38] }
185
+ }
186
+ },
187
+ "outputs": {
188
+ "Y": {
189
+ "dtype": "float32",
190
+ "shape": [4],
191
+ "tolerance": 2e-45,
192
+ "data": {
193
+ "kind": "values",
194
+ "values": [4.99997305055738e-41, -4.99997305055738e-41, 4.999999675228202e-39, -4.999999675228202e-39]
195
+ }
196
+ }
197
+ }
198
+ },
199
+ {
200
+ "name": "alpha_zero_subnormal_half_input_scalar_gpu_gap",
201
+ "skipGpu": {
202
+ "category": "permanent",
203
+ "reason": "Portable WGSL floating-point semantics do not guarantee preservation of the subnormal values required by this fixture. Backend evidence: WebGPU/Metal flushes subnormals to zero (f32 and f16); the kernel cannot preserve denormal inputs/outputs bit-exactly."
204
+ },
205
+ "provenance": {
206
+ "source": "onnxruntime/test/contrib_ops/activation_op_test.cc",
207
+ "test": "ActivationOpTest.QuickGelu",
208
+ "notes": "Scalar-path companion for alpha=0 exact half-input subnormal behavior."
209
+ },
210
+ "attrs": { "alpha": 0 },
211
+ "inputs": {
212
+ "X": { "dtype": "float32", "shape": [3], "data": { "kind": "values", "values": [1e-40, -1e-40, 1e-38] } }
213
+ },
214
+ "outputs": {
215
+ "Y": {
216
+ "dtype": "float32",
217
+ "shape": [3],
218
+ "tolerance": 2e-45,
219
+ "data": { "kind": "values", "values": [4.99997305055738e-41, -4.99997305055738e-41, 4.999999675228202e-39] }
220
+ }
221
+ }
222
+ },
223
+ {
224
+ "name": "f16_values",
225
+ "attrs": { "alpha": 1.702 },
226
+ "inputs": {
227
+ "X": {
228
+ "dtype": "float16",
229
+ "shape": [8],
230
+ "data": { "kind": "values", "values": [-4.0, -2.0, -0.5, 0.0, 0.5, 1.0, 2.0, 4.0] }
231
+ }
232
+ },
233
+ "outputs": { "Y": { "dtype": "float16", "shape": [8], "tolerance": 0.005 } }
234
+ },
235
+ {
236
+ "name": "f16_default_alpha_extreme_stable_sigmoid",
237
+ "attrs": { "alpha": 1.702 },
238
+ "inputs": {
239
+ "X": {
240
+ "dtype": "float16",
241
+ "shape": [8],
242
+ "data": { "kind": "values", "values": [-1000.0, -100.0, -10.0, -1.0, 1.0, 10.0, 100.0, 1000.0] }
243
+ }
244
+ },
245
+ "outputs": { "Y": { "dtype": "float16", "shape": [8], "tolerance": 0.02 } }
246
+ }
247
+ ]
248
+ }