Xenova HF Staff commited on
Commit
3aadfb1
·
verified ·
1 Parent(s): 0ef25e5

sync 2e7068faf55e

Browse files
README.md CHANGED
@@ -1,3 +1,60 @@
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.FastGelu
10
+
11
+ `com.microsoft` · ONNX Runtime contrib operator · contrib since_version 1
12
+
13
+ ## Description
14
+
15
+ Applies the GELU (Gaussian Error Linear Unit) activation using a tanh approximation: `Y = 0.5 * X * (1 + tanh(0.797885 * X + 0.035677 * X^3))`. An optional `bias` is added to `X` before the activation is computed. This WebGPU package implements float16 and float32; the schema-allowed double and bfloat16 types are not supported.
16
+
17
+ See the [ONNX Runtime `FastGelu` contrib-operator spec](https://github.com/microsoft/onnxruntime/blob/main/docs/ContribOperators.md#com.microsoft.FastGelu) for the reference semantics.
18
+
19
+ ## Inputs
20
+
21
+ | Name | Bind key | Logical dtype | Rank | Shape | Description | Presence |
22
+ | --- | --- | --- | --- | --- | --- | --- |
23
+ | `X` | `X` | `T` | — | — | Values transformed by FastGelu after adding the optional `bias`. | required |
24
+ | `bias` | `bias` | `T` | `1` | — | Optional 1-D bias added to `X` along the last dimension before the GELU activation. | optional |
25
+
26
+ ## Outputs
27
+
28
+ | Name | Bind key | Logical dtype | Rank | Shape | Description | Presence |
29
+ | --- | --- | --- | --- | --- | --- | --- |
30
+ | `Y` | `Y` | `T` | same as `X` | same as `X` | Output tensor after applying the GELU activation; same shape as `X`. | required |
31
+
32
+ ## Type constraints
33
+
34
+ | Variable | Allowed dtypes |
35
+ | --- | --- |
36
+ | `T` | `float32`, `float16` |
37
+
38
+ ## Files
39
+
40
+ - [`metadata.json`](build/webgpu/metadata.json) — kernel metadata (id, digests, provenance)
41
+ - [`manifest.json`](build/webgpu/manifest.json) — the op contract (source of truth)
42
+ - [`test.json`](build/webgpu/test.json) — correctness cases
43
+ - [`bench.json`](build/webgpu/bench.json) — benchmark + tuning cases
44
+ - [`elementwise-bias-gelu.wgsl.jinja`](build/webgpu/elementwise-bias-gelu.wgsl.jinja)
45
+
46
+ ## Use with `@huggingface/kernels`
47
+
48
+ The loader derives every required output's shape and logical dtype from the manifest contract and this call.
49
+ It then allocates the result tensors automatically.
50
+
51
+ The `version: 1` option selects the published kernel contract; it is independent of any operator opset, contrib `since_version`, or model version.
52
+
53
+ Replace each `*Data` placeholder with a typed array containing the corresponding input data.
54
+
55
+ ```js
56
+ import { getKernel } from "@huggingface/kernels";
57
+
58
+ const kernel = await getKernel("webgpu-kernels/com.microsoft.FastGelu", { version: 1 });
59
+ const { Y } = await kernel({ X: { data: XData, shape: [5] } });
60
+ ```
build/webgpu/bench.json ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "op": "com.microsoft.FastGelu",
3
+ "tunableSpace": { "WORKGROUP_SIZE": [64, 128, 256] },
4
+ "cases": [
5
+ {
6
+ "name": "fastgelu-f32-bias-4096x3072",
7
+ "preset": "smoke",
8
+ "vars": { "dtype": "float32" },
9
+ "inputs": {
10
+ "X": { "shape": [4096, 3072], "dtype": "float32", "dist": "normal", "seed": 410, "scale": 2 },
11
+ "bias": { "shape": [3072], "dtype": "float32", "dist": "normal", "seed": 411, "scale": 1 }
12
+ },
13
+ "outputs": { "Y": { "shape": [4096, 3072], "dtype": "float32" } },
14
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "4096 * 3072 * 2 * dtypeBytes(args.dtype)" }] }
15
+ },
16
+ {
17
+ "name": "fastgelu-f16-bias-4096x3072",
18
+ "preset": "model",
19
+ "vars": { "dtype": "float16" },
20
+ "inputs": {
21
+ "X": { "shape": [4096, 3072], "dtype": "float16", "dist": "normal", "seed": 412, "scale": 2 },
22
+ "bias": { "shape": [3072], "dtype": "float16", "dist": "normal", "seed": 413, "scale": 1 }
23
+ },
24
+ "outputs": { "Y": { "shape": [4096, 3072], "dtype": "float16" } },
25
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "4096 * 3072 * 2 * dtypeBytes(args.dtype)" }] }
26
+ },
27
+ {
28
+ "name": "fastgelu-f32-scalar-bias-odd-hidden",
29
+ "preset": "stress",
30
+ "vars": { "dtype": "float32" },
31
+ "inputs": {
32
+ "X": { "shape": [2097152, 3], "dtype": "float32", "dist": "normal", "seed": 440, "scale": 2 },
33
+ "bias": { "shape": [3], "dtype": "float32", "dist": "normal", "seed": 441, "scale": 1 }
34
+ },
35
+ "outputs": { "Y": { "shape": [2097152, 3], "dtype": "float32" } },
36
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "2097152 * 3 * 2 * dtypeBytes(args.dtype)" }] }
37
+ }
38
+ ]
39
+ }
build/webgpu/elementwise-bias-gelu.wgsl.jinja ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% if usesF16 %}
2
+ enable f16;
3
+ {% endif %}
4
+ {{ env.wgsl.resourceDeclarations }}
5
+ {% set wg = workgroupSize if workgroupSize is defined else tunables.WORKGROUP_SIZE %}
6
+
7
+ // Bias plus GELU, with a specialization-selected tanh or erf approximation.
8
+ // The optional bias is a rank-1 vector broadcast over the innermost (hidden)
9
+ // axis: bias index = element_index % HIDDEN. The `vec4` path requires
10
+ // HIDDEN % 4 == 0 and numel % 4 == 0 so a vec4 group never crosses the hidden
11
+ // axis (the bias slice is then contiguous). `vec4Tail` keeps scalar bindings but
12
+ // evaluates four guarded lanes per invocation, so odd hidden sizes retain the
13
+ // same parallel efficiency without crossing row/bias boundaries. Gelu math and overflow guards match
14
+ // the vectorized unary implementation: tanh saturates to +/-1 by |x|~9, and the
15
+ // erf path uses the same rational approximation as Gelu.
16
+ {% if approximate == "erf" %}
17
+ fn erf_approx(x: f32) -> f32 {
18
+ let ax = abs(x);
19
+ // The polynomial has a small nonzero floor near zero. Use erf(x) ~=
20
+ // 2/sqrt(pi)*x below 2^-20 to preserve erf(0) == 0, odd symmetry, and the
21
+ // correctly rounded f32 result. The exactly representable threshold keeps
22
+ // scalar and vector branching identical. NaN falls through to the polynomial
23
+ // and propagates.
24
+ if (ax < 9.5367431640625e-7) {
25
+ return 1.1283791670955126 * x;
26
+ }
27
+ let sign = select(-1.0, 1.0, x >= 0.0);
28
+ let t = 1.0 / (1.0 + 0.3275911 * ax);
29
+ let y = 1.0 - (((((1.061405429 * t - 1.453152027) * t) + 1.421413741) * t - 0.284496736) * t + 0.254829592) * t * exp(-(ax * ax));
30
+ return sign * y;
31
+ }
32
+ {% else %}
33
+ fn tanh_safe(x: f32) -> f32 {
34
+ if (x > 10.0) { return 1.0; }
35
+ if (x < -10.0) { return -1.0; }
36
+ return tanh(x);
37
+ }
38
+ {% endif %}
39
+ fn gelu_value(v: f32) -> f32 {
40
+ {% if approximate == "erf" %}
41
+ return 0.5 * v * (1.0 + erf_approx(v * 0.7071067811865476));
42
+ {% else %}
43
+ return 0.5 * v * (1.0 + tanh_safe(0.7978845608028654 * (v + 0.044715 * v * v * v)));
44
+ {% endif %}
45
+ }
46
+ {% if hasBias %}
47
+
48
+ const HIDDEN: u32 = {{ hidden }}u;
49
+
50
+ {% endif %}
51
+ @compute @workgroup_size({{ wg }})
52
+ fn main(@builtin(global_invocation_id) gid: vec3<u32>, @builtin(num_workgroups) nwg: vec3<u32>) {
53
+ // 2D-folded flat index: gid.y carries the high bits past the
54
+ // maxComputeWorkgroupsPerDimension dispatch limit (outputs > 16.7M elements).
55
+ let i = gid.x + gid.y * nwg.x * {{ wg }}u;
56
+ if (i >= params.count) {
57
+ return;
58
+ }
59
+ {% if vec4Tail %}
60
+ let base = i * 4u;
61
+ {% for lane in range(4) %}
62
+ if (base + {{ lane }}u < params.count) {
63
+ let xv{{ lane }} = f32(x[base + {{ lane }}u]);
64
+ {% if hasBias %}
65
+ let v{{ lane }} = xv{{ lane }} + f32(bias[(base + {{ lane }}u) % HIDDEN]);
66
+ {% else %}
67
+ let v{{ lane }} = xv{{ lane }};
68
+ {% endif %}
69
+ y[base + {{ lane }}u] = {{ scalar }}(gelu_value(v{{ lane }}));
70
+ }
71
+ {% endfor %}
72
+ {% elif vec4 %}
73
+ let xv = vec4<f32>(x[i]);
74
+ {% if hasBias %}
75
+ let bcol = (i * 4u) % HIDDEN;
76
+ let v = xv + vec4<f32>(f32(bias[bcol]), f32(bias[bcol + 1u]), f32(bias[bcol + 2u]), f32(bias[bcol + 3u]));
77
+ {% else %}
78
+ let v = xv;
79
+ {% endif %}
80
+ y[i] = vec4<{{ scalar }}>(vec4<f32>(gelu_value(v.x), gelu_value(v.y), gelu_value(v.z), gelu_value(v.w)));
81
+ {% else %}
82
+ let xv = f32(x[i]);
83
+ {% if hasBias %}
84
+ let v = xv + f32(bias[i % HIDDEN]);
85
+ {% else %}
86
+ let v = xv;
87
+ {% endif %}
88
+ y[i] = {{ scalar }}(gelu_value(v));
89
+ {% endif %}
90
+ }
build/webgpu/manifest.json ADDED
@@ -0,0 +1,221 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "domain": "com.microsoft",
3
+ "name": "FastGelu",
4
+ "sinceVersion": 1,
5
+ "description": "Applies the GELU (Gaussian Error Linear Unit) activation using a tanh approximation: `Y = 0.5 * X * (1 + tanh(0.797885 * X + 0.035677 * X^3))`. An optional `bias` is added to `X` before the activation is computed. This WebGPU package implements float16 and float32; the schema-allowed double and bfloat16 types are not supported.",
6
+ "inputs": [
7
+ { "role": "X", "dtype": "T", "description": "Values transformed by FastGelu after adding the optional `bias`." },
8
+ {
9
+ "role": "bias",
10
+ "dtype": "T",
11
+ "rank": 1,
12
+ "optional": true,
13
+ "description": "Optional 1-D bias added to `X` along the last dimension before the GELU activation."
14
+ }
15
+ ],
16
+ "outputs": [
17
+ {
18
+ "role": "Y",
19
+ "dtype": "T",
20
+ "rank": "ranks.X",
21
+ "shape": "shapes.X",
22
+ "description": "Output tensor after applying the GELU activation; same shape as `X`."
23
+ }
24
+ ],
25
+ "typeConstraints": { "T": ["float32", "float16"] },
26
+ "args": {
27
+ "X": { "kind": "tensor", "semantic": "X", "role": "input" },
28
+ "bias": { "kind": "tensor", "semantic": "bias", "role": "input", "required": false },
29
+ "Y": { "kind": "tensor", "semantic": "Y", "role": "output" }
30
+ },
31
+ "tunables": { "WORKGROUP_SIZE": 256 },
32
+ "derive": {
33
+ "deviceWorkgroupCap": "min(device.limits.maxComputeInvocationsPerWorkgroup, device.limits.maxComputeWorkgroupSizeX)",
34
+ "storageBufferLimit": "min(device.limits.maxStorageBufferBindingSize, device.limits.maxBufferSize)",
35
+ "workgroupSize": "min(tunables.WORKGROUP_SIZE, deviceWorkgroupCap)",
36
+ "buffersFit": "numel(shapes.X) * dtypeBytes(dtypes.T) <= storageBufferLimit and numel(shapes.Y) * dtypeBytes(dtypes.T) <= storageBufferLimit and (not present.bias or numel(shapes.bias) * dtypeBytes(dtypes.T) <= storageBufferLimit)",
37
+ "dispatchFits": "numel(shapes.X) <= device.limits.maxComputeWorkgroupsPerDimension * device.limits.maxComputeWorkgroupsPerDimension * workgroupSize * 4",
38
+ "baseOk": "workgroupSize > 0 and ranks.X >= 1 and numel(shapes.X) == numel(shapes.Y) and f16Ok(dtypes.T) and buffersFit and dispatchFits",
39
+ "biasOk": "present.bias and ranks.bias == 1 and dim(shapes.bias, 0) == dim(shapes.X, ranks.X - 1)",
40
+ "noBiasOk": "not present.bias",
41
+ "vec4Ok": "numel(shapes.X) > 0 and numel(shapes.X) % 4 == 0 and dim(shapes.X, ranks.X - 1) % 4 == 0"
42
+ },
43
+ "constants": { "scalar": "dtypes.T", "usesF16": "dtypes.T == \"f16\"", "approximate": "\"tanh\"" },
44
+ "bindingSets": {
45
+ "vec4Bias": [
46
+ {
47
+ "name": "x",
48
+ "arg": "X",
49
+ "semantic": "X",
50
+ "buffer": { "type": "read-only-storage" },
51
+ "elementType": "$vectorScalar"
52
+ },
53
+ {
54
+ "name": "bias",
55
+ "arg": "bias",
56
+ "semantic": "bias",
57
+ "buffer": { "type": "read-only-storage" },
58
+ "elementType": "$scalar",
59
+ "length": "$hidden"
60
+ },
61
+ { "name": "y", "arg": "Y", "semantic": "Y", "buffer": { "type": "storage" }, "elementType": "$vectorScalar" },
62
+ {
63
+ "name": "params",
64
+ "semantic": "kernel.params",
65
+ "buffer": { "type": "uniform" },
66
+ "struct": { "name": "Params", "fields": [{ "name": "count", "type": "u32", "value": "numel(shapes.X) / 4" }] }
67
+ }
68
+ ],
69
+ "vec4": [
70
+ {
71
+ "name": "x",
72
+ "arg": "X",
73
+ "semantic": "X",
74
+ "buffer": { "type": "read-only-storage" },
75
+ "elementType": "$vectorScalar"
76
+ },
77
+ { "name": "y", "arg": "Y", "semantic": "Y", "buffer": { "type": "storage" }, "elementType": "$vectorScalar" },
78
+ {
79
+ "name": "params",
80
+ "semantic": "kernel.params",
81
+ "buffer": { "type": "uniform" },
82
+ "struct": { "name": "Params", "fields": [{ "name": "count", "type": "u32", "value": "numel(shapes.X) / 4" }] }
83
+ }
84
+ ],
85
+ "scalarBias": [
86
+ { "name": "x", "arg": "X", "semantic": "X", "buffer": { "type": "read-only-storage" }, "elementType": "$scalar" },
87
+ {
88
+ "name": "bias",
89
+ "arg": "bias",
90
+ "semantic": "bias",
91
+ "buffer": { "type": "read-only-storage" },
92
+ "elementType": "$scalar"
93
+ },
94
+ { "name": "y", "arg": "Y", "semantic": "Y", "buffer": { "type": "storage" }, "elementType": "$scalar" },
95
+ {
96
+ "name": "params",
97
+ "semantic": "kernel.params",
98
+ "buffer": { "type": "uniform" },
99
+ "struct": { "name": "Params", "fields": [{ "name": "count", "type": "u32", "value": "numel(shapes.X)" }] }
100
+ }
101
+ ],
102
+ "scalar": [
103
+ { "name": "x", "arg": "X", "semantic": "X", "buffer": { "type": "read-only-storage" }, "elementType": "$scalar" },
104
+ { "name": "y", "arg": "Y", "semantic": "Y", "buffer": { "type": "storage" }, "elementType": "$scalar" },
105
+ {
106
+ "name": "params",
107
+ "semantic": "kernel.params",
108
+ "buffer": { "type": "uniform" },
109
+ "struct": { "name": "Params", "fields": [{ "name": "count", "type": "u32", "value": "numel(shapes.X)" }] }
110
+ }
111
+ ]
112
+ },
113
+ "variants": [
114
+ {
115
+ "id": "vec4_bias",
116
+ "priority": 30,
117
+ "when": ["baseOk", "biasOk", "vec4Ok"],
118
+ "constants": {
119
+ "vec4": true,
120
+ "vec4Tail": false,
121
+ "hasBias": true,
122
+ "vectorScalar": "\"vec4<\" ~ dtypes.T ~ \">\"",
123
+ "hidden": "dim(shapes.X, ranks.X - 1) if dim(shapes.X, ranks.X - 1) > 0 else 1"
124
+ },
125
+ "passes": [
126
+ {
127
+ "id": "main",
128
+ "name": "FastGelu.vec4Bias",
129
+ "shader": "elementwise-bias-gelu.wgsl.jinja",
130
+ "bindings": "vec4Bias",
131
+ "dispatch": { "threads": "numel(shapes.X) / 4", "workgroupSize": "workgroupSize" }
132
+ }
133
+ ]
134
+ },
135
+ {
136
+ "id": "vec4_no_bias",
137
+ "priority": 25,
138
+ "when": ["baseOk", "noBiasOk", "vec4Ok"],
139
+ "constants": { "vec4": true, "vec4Tail": false, "hasBias": false, "vectorScalar": "\"vec4<\" ~ dtypes.T ~ \">\"" },
140
+ "passes": [
141
+ {
142
+ "id": "main",
143
+ "name": "FastGelu.vec4",
144
+ "shader": "elementwise-bias-gelu.wgsl.jinja",
145
+ "bindings": "vec4",
146
+ "dispatch": { "threads": "numel(shapes.X) / 4", "workgroupSize": "workgroupSize" }
147
+ }
148
+ ]
149
+ },
150
+ {
151
+ "id": "vec4_tail_bias",
152
+ "priority": 20,
153
+ "when": ["baseOk", "biasOk", "numel(shapes.X) > 0"],
154
+ "constants": {
155
+ "vec4": false,
156
+ "vec4Tail": true,
157
+ "hasBias": true,
158
+ "hidden": "dim(shapes.X, ranks.X - 1) if dim(shapes.X, ranks.X - 1) > 0 else 1"
159
+ },
160
+ "passes": [
161
+ {
162
+ "id": "main",
163
+ "name": "FastGelu.vec4TailBias",
164
+ "shader": "elementwise-bias-gelu.wgsl.jinja",
165
+ "bindings": "scalarBias",
166
+ "dispatch": { "threads": "ceilDiv(numel(shapes.X), 4)", "workgroupSize": "workgroupSize" }
167
+ }
168
+ ]
169
+ },
170
+ {
171
+ "id": "vec4_tail_no_bias",
172
+ "priority": 15,
173
+ "when": ["baseOk", "noBiasOk", "numel(shapes.X) > 0"],
174
+ "constants": { "vec4": false, "vec4Tail": true, "hasBias": false },
175
+ "passes": [
176
+ {
177
+ "id": "main",
178
+ "name": "FastGelu.vec4Tail",
179
+ "shader": "elementwise-bias-gelu.wgsl.jinja",
180
+ "bindings": "scalar",
181
+ "dispatch": { "threads": "ceilDiv(numel(shapes.X), 4)", "workgroupSize": "workgroupSize" }
182
+ }
183
+ ]
184
+ },
185
+ {
186
+ "id": "scalar_bias",
187
+ "priority": 10,
188
+ "when": ["baseOk", "biasOk", "true"],
189
+ "constants": {
190
+ "vec4": false,
191
+ "vec4Tail": false,
192
+ "hasBias": true,
193
+ "hidden": "dim(shapes.X, ranks.X - 1) if dim(shapes.X, ranks.X - 1) > 0 else 1"
194
+ },
195
+ "passes": [
196
+ {
197
+ "id": "main",
198
+ "name": "FastGelu.scalarBias",
199
+ "shader": "elementwise-bias-gelu.wgsl.jinja",
200
+ "bindings": "scalarBias",
201
+ "dispatch": { "threads": "numel(shapes.X)", "workgroupSize": "workgroupSize" }
202
+ }
203
+ ]
204
+ },
205
+ {
206
+ "id": "scalar_no_bias",
207
+ "priority": 0,
208
+ "when": ["baseOk", "noBiasOk", "true"],
209
+ "constants": { "vec4": false, "vec4Tail": false, "hasBias": false },
210
+ "passes": [
211
+ {
212
+ "id": "main",
213
+ "name": "FastGelu.scalar",
214
+ "shader": "elementwise-bias-gelu.wgsl.jinja",
215
+ "bindings": "scalar",
216
+ "dispatch": { "threads": "numel(shapes.X)", "workgroupSize": "workgroupSize" }
217
+ }
218
+ ]
219
+ }
220
+ ]
221
+ }
build/webgpu/metadata.json ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "com.microsoft.FastGelu",
3
+ "id": "_com_microsoft_fastgelu_webgpu_efaff66",
4
+ "version": 1,
5
+ "license": "Apache-2.0",
6
+ "backend": { "type": "webgpu" },
7
+ "digest": {
8
+ "algorithm": "sha256",
9
+ "files": {
10
+ "bench.json": "m93bKUUMLGZxG/F5G6AFYMyDIKSE1Pk4hOyYNKrO+y0=",
11
+ "elementwise-bias-gelu.wgsl.jinja": "Eg8N2jJCMce+IsYNcCzuxvs8CSv7yTQXdorvv+c0L58=",
12
+ "manifest.json": "WckeD7rVTEJ1Lb6FDdpYC9n//UUq4+QWwd7vyAGc5m8=",
13
+ "test.json": "shIb34pVGz4K2kmzCn/yOmL6OuRbXD+UaRJ/PADEFtM="
14
+ }
15
+ },
16
+ "provenance": { "kernel": { "sha": "2e7068faf55e7f43df740015f6d1ee49391a41c5", "dirty": false } },
17
+ "webgpu": { "manifestSpec": "1.0", "specialized": true, "opPath": "ops/com.microsoft.FastGelu" }
18
+ }
build/webgpu/test.json ADDED
@@ -0,0 +1,448 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "op": "com.microsoft.FastGelu",
3
+ "fixtureArrays": {
4
+ "ort_float16_hidden8_with_bias_input_X": [0.8, -0.5, 0, 1, 1.3, 2.1, -0.2, 1.1, 0.5, 0.2, 0.3, -0.6, 3.1, 2.2, -1.1, 0]
5
+ },
6
+ "cases": [
7
+ {
8
+ "name": "dispatch_cliff_scalar_no_bias",
9
+ "inputs": {
10
+ "X": { "dtype": "float32", "shape": [16777, 1001], "data": { "kind": "linspace", "start": -3.0, "end": 3.0 } }
11
+ },
12
+ "outputs": { "Y": { "dtype": "float32", "shape": [16777, 1001], "tolerance": 0.0001 } }
13
+ },
14
+ {
15
+ "name": "ort_float32_with_bias",
16
+ "provenance": {
17
+ "source": "onnxruntime/test/contrib_ops/fastgelu_op_test.cc",
18
+ "test": "FastGeluTest.FastGeluWithBiasFloat32"
19
+ },
20
+ "inputs": {
21
+ "X": {
22
+ "dtype": "float32",
23
+ "shape": [1, 2, 4],
24
+ "data": { "kind": "values", "values": [0.8, -0.5, 0.0, 1.0, 0.5, 0.2, 0.3, -0.6] }
25
+ },
26
+ "bias": { "dtype": "float32", "shape": [4], "data": { "kind": "values", "values": [-0.5, 0.6, 1.2, 2.1] } }
27
+ },
28
+ "outputs": {
29
+ "Y": {
30
+ "dtype": "float32",
31
+ "shape": [1, 2, 4],
32
+ "tolerance": 0.000001,
33
+ "data": {
34
+ "kind": "values",
35
+ "values": [0.18537092, 0.05398276, 1.0617028, 3.0973732, 0.0, 0.6304317, 1.3995715, 1.3995714]
36
+ }
37
+ }
38
+ }
39
+ },
40
+ {
41
+ "name": "ort_float32_without_bias",
42
+ "provenance": {
43
+ "source": "onnxruntime/test/contrib_ops/fastgelu_op_test.cc",
44
+ "test": "FastGeluTest.FastGeluWithoutBiasFloat32"
45
+ },
46
+ "inputs": {
47
+ "X": {
48
+ "dtype": "float32",
49
+ "shape": [1, 2, 4],
50
+ "data": { "kind": "values", "values": [0.8, -0.5, 0.0, 1.0, 0.5, 0.2, 0.3, -0.6] }
51
+ }
52
+ },
53
+ "outputs": {
54
+ "Y": {
55
+ "dtype": "float32",
56
+ "shape": [1, 2, 4],
57
+ "tolerance": 0.000001,
58
+ "data": {
59
+ "kind": "values",
60
+ "values": [0.6304317, -0.154286, 0.0, 0.841192, 0.345714, 0.11585142, 0.18537092, -0.16458479]
61
+ }
62
+ }
63
+ }
64
+ },
65
+ {
66
+ "name": "ort_float32_zero_sequence_with_bias",
67
+ "provenance": {
68
+ "source": "onnxruntime/test/contrib_ops/fastgelu_op_test.cc",
69
+ "test": "FastGeluTest.FastGeluWithNullInput"
70
+ },
71
+ "inputs": {
72
+ "X": { "dtype": "float32", "shape": [1, 0, 4], "data": { "kind": "values", "values": [] } },
73
+ "bias": { "dtype": "float32", "shape": [4], "data": { "kind": "values", "values": [-0.5, 0.6, 1.2, 2.1] } }
74
+ },
75
+ "outputs": { "Y": { "dtype": "float32", "shape": [1, 0, 4], "data": { "kind": "values", "values": [] } } }
76
+ },
77
+ {
78
+ "name": "f32_scalar_no_bias_zero_sequence",
79
+ "provenance": {
80
+ "notes": "Bias-free twin of ort_float32_zero_sequence_with_bias. An empty X fails the numel > 0 guard both vec4 routes carry, so the plain scalar no-bias kernel is the only one left."
81
+ },
82
+ "inputs": { "X": { "dtype": "float32", "shape": [1, 0, 4], "data": { "kind": "values", "values": [] } } },
83
+ "outputs": { "Y": { "dtype": "float32", "shape": [1, 0, 4], "data": { "kind": "values", "values": [] } } }
84
+ },
85
+ {
86
+ "name": "empty_zero_hidden",
87
+ "provenance": {
88
+ "notes": "Zero-length last (bias-broadcast) axis: the bias vector itself is empty, so no kernel may size a binding from the hidden extent."
89
+ },
90
+ "inputs": {
91
+ "X": { "dtype": "float32", "shape": [2, 0], "data": { "kind": "values", "values": [] } },
92
+ "bias": { "dtype": "float32", "shape": [0], "data": { "kind": "values", "values": [] } }
93
+ },
94
+ "outputs": { "Y": { "dtype": "float32", "shape": [2, 0], "data": { "kind": "values", "values": [] } } }
95
+ },
96
+ {
97
+ "name": "ort_float16_hidden2_with_bias",
98
+ "provenance": {
99
+ "source": "onnxruntime/test/contrib_ops/fastgelu_op_test.cc",
100
+ "test": "FastGeluTest.FastGeluWithBiasFloat16_2"
101
+ },
102
+ "inputs": {
103
+ "X": { "dtype": "float16", "shape": [1, 2, 2], "data": { "kind": "values", "values": [0.8, -0.5, 0.5, 0.2] } },
104
+ "bias": { "dtype": "float16", "shape": [2], "data": { "kind": "values", "values": [-0.5, 0.6] } }
105
+ },
106
+ "outputs": {
107
+ "Y": {
108
+ "dtype": "float16",
109
+ "shape": [1, 2, 2],
110
+ "tolerance": 0.001,
111
+ "data": { "kind": "values", "values": [0.1851806640625, 0.054046630859375, 0.0, 0.63037109375] }
112
+ }
113
+ }
114
+ },
115
+ {
116
+ "name": "ort_float16_hidden2_without_bias",
117
+ "provenance": {
118
+ "source": "onnxruntime/test/contrib_ops/fastgelu_op_test.cc",
119
+ "test": "FastGeluTest.FastGeluWithoutBiasFloat16_2"
120
+ },
121
+ "inputs": {
122
+ "X": { "dtype": "float16", "shape": [1, 2, 2], "data": { "kind": "values", "values": [0.8, -0.5, 0.5, 0.2] } }
123
+ },
124
+ "outputs": {
125
+ "Y": {
126
+ "dtype": "float16",
127
+ "shape": [1, 2, 2],
128
+ "tolerance": 0.001,
129
+ "data": { "kind": "values", "values": [0.63037109375, -0.154296875, 0.345703125, 0.11578369140625] }
130
+ }
131
+ }
132
+ },
133
+ {
134
+ "name": "ort_float16_hidden4_with_bias",
135
+ "provenance": {
136
+ "source": "onnxruntime/test/contrib_ops/fastgelu_op_test.cc",
137
+ "test": "FastGeluTest.FastGeluWithBiasFloat16_4"
138
+ },
139
+ "inputs": {
140
+ "X": {
141
+ "dtype": "float16",
142
+ "shape": [1, 2, 4],
143
+ "data": { "kind": "values", "values": [0.8, -0.5, 0.0, 1.0, 0.5, 0.2, 0.3, -0.6] }
144
+ },
145
+ "bias": { "dtype": "float16", "shape": [4], "data": { "kind": "values", "values": [-0.5, 0.6, 1.2, 2.1] } }
146
+ },
147
+ "outputs": {
148
+ "Y": {
149
+ "dtype": "float16",
150
+ "shape": [1, 2, 4],
151
+ "tolerance": 0.001,
152
+ "data": {
153
+ "kind": "values",
154
+ "values": [0.1851806640625, 0.054046630859375, 1.0615234375, 3.09765625, 0.0, 0.63037109375, 1.3994140625, 1.3994140625]
155
+ }
156
+ }
157
+ }
158
+ },
159
+ {
160
+ "name": "ort_float16_hidden4_without_bias",
161
+ "provenance": {
162
+ "source": "onnxruntime/test/contrib_ops/fastgelu_op_test.cc",
163
+ "test": "FastGeluTest.FastGeluWithoutBiasFloat16_4"
164
+ },
165
+ "inputs": {
166
+ "X": {
167
+ "dtype": "float16",
168
+ "shape": [1, 2, 4],
169
+ "data": { "kind": "values", "values": [0.8, -0.5, 0.0, 1.0, 0.5, 0.2, 0.3, -0.6] }
170
+ }
171
+ },
172
+ "outputs": {
173
+ "Y": {
174
+ "dtype": "float16",
175
+ "shape": [1, 2, 4],
176
+ "tolerance": 0.001,
177
+ "data": {
178
+ "kind": "values",
179
+ "values": [0.63037109375, -0.154296875, 0.0, 0.84130859375, 0.345703125, 0.1158447265625, 0.1854248046875, -0.16455078125]
180
+ }
181
+ }
182
+ }
183
+ },
184
+ {
185
+ "name": "ort_float16_hidden8_with_bias",
186
+ "provenance": {
187
+ "source": "onnxruntime/test/contrib_ops/fastgelu_op_test.cc",
188
+ "test": "FastGeluTest.FastGeluWithBiasFloat16_8"
189
+ },
190
+ "inputs": {
191
+ "X": {
192
+ "dtype": "float16",
193
+ "shape": [1, 2, 8],
194
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/ort_float16_hidden8_with_bias_input_X" } }
195
+ },
196
+ "bias": {
197
+ "dtype": "float16",
198
+ "shape": [8],
199
+ "data": { "kind": "values", "values": [-0.5, 0.6, 1.2, 2.1, 1.3, -1.0, 0.0, 3.1] }
200
+ }
201
+ },
202
+ "outputs": {
203
+ "Y": {
204
+ "dtype": "float16",
205
+ "shape": [1, 2, 8],
206
+ "tolerance": 0.001,
207
+ "data": {
208
+ "kind": "values",
209
+ "values": [0.1851806640625, 0.054046630859375, 1.0615234375, 3.09765625, 2.587890625, 0.9501953125, -0.0841064453125, 4.19921875, 0.0, 0.63037109375, 1.3994140625, 1.3994140625, 4.3984375, 1.060546875, -0.1494140625, 3.09765625]
210
+ }
211
+ }
212
+ }
213
+ },
214
+ {
215
+ "name": "ort_float16_hidden8_without_bias",
216
+ "provenance": {
217
+ "source": "onnxruntime/test/contrib_ops/fastgelu_op_test.cc",
218
+ "test": "FastGeluTest.FastGeluWithoutBiasFloat16_8"
219
+ },
220
+ "inputs": {
221
+ "X": {
222
+ "dtype": "float16",
223
+ "shape": [1, 2, 8],
224
+ "data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/ort_float16_hidden8_with_bias_input_X" } }
225
+ }
226
+ },
227
+ "outputs": {
228
+ "Y": {
229
+ "dtype": "float16",
230
+ "shape": [1, 2, 8],
231
+ "tolerance": 0.001,
232
+ "data": {
233
+ "kind": "values",
234
+ "values": [0.63037109375, -0.154296875, 0.0, 0.84130859375, 1.173828125, 2.0625, -0.0841064453125, 0.9501953125, 0.345703125, 0.1158447265625, 0.1854248046875, -0.16455078125, 3.09765625, 2.16796875, -0.1494140625, 0.0]
235
+ }
236
+ }
237
+ }
238
+ },
239
+ {
240
+ "name": "float32_extreme_saturation_edges",
241
+ "provenance": {
242
+ "source": "onnxruntime/test/contrib_ops/fastgelu_op_test.cc",
243
+ "notes": "Extra edge case for the tanh approximation: large negative values saturate to signed-zero-ish outputs while large positives pass through."
244
+ },
245
+ "inputs": {
246
+ "X": {
247
+ "dtype": "float32",
248
+ "shape": [1, 9],
249
+ "data": { "kind": "values", "values": [-20.0, -10.0, -5.0, -2.0, 0.0, 2.0, 5.0, 10.0, 20.0] }
250
+ }
251
+ },
252
+ "outputs": {
253
+ "Y": {
254
+ "dtype": "float32",
255
+ "shape": [1, 9],
256
+ "tolerance": 0.000001,
257
+ "data": {
258
+ "kind": "values",
259
+ "values": [0.0, 0.0, -2.9802322e-7, -0.045402348, 0.0, 1.9545977, 4.9999995, 10.0, 20.0]
260
+ }
261
+ }
262
+ }
263
+ },
264
+ {
265
+ "name": "f32_subnormal_linear_region_no_bias_vec4_gpu_gap",
266
+ "skipGpu": {
267
+ "category": "permanent",
268
+ "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."
269
+ },
270
+ "provenance": {
271
+ "source": "onnxruntime/test/contrib_ops/fastgelu_op_test.cc",
272
+ "test": "FastGeluTest.FastGeluWithoutBiasFloat32",
273
+ "notes": "Near zero, tanh-approx FastGelu is approximately x/2; finite subnormal tails should survive the vec4 no-bias path."
274
+ },
275
+ "inputs": {
276
+ "X": {
277
+ "dtype": "float32",
278
+ "shape": [4],
279
+ "data": { "kind": "values", "values": [1e-40, -1e-40, 1e-38, -1e-38] }
280
+ }
281
+ },
282
+ "outputs": {
283
+ "Y": {
284
+ "dtype": "float32",
285
+ "shape": [4],
286
+ "tolerance": 2e-45,
287
+ "data": {
288
+ "kind": "values",
289
+ "values": [4.99997305055738e-41, -4.99997305055738e-41, 4.999999675228202e-39, -4.999999675228202e-39]
290
+ }
291
+ }
292
+ }
293
+ },
294
+ {
295
+ "name": "f32_subnormal_linear_region_no_bias_scalar_gpu_gap",
296
+ "skipGpu": {
297
+ "category": "permanent",
298
+ "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."
299
+ },
300
+ "provenance": {
301
+ "source": "onnxruntime/test/contrib_ops/fastgelu_op_test.cc",
302
+ "test": "FastGeluTest.FastGeluWithoutBiasFloat32",
303
+ "notes": "Scalar-path companion for FastGelu's near-zero x/2 subnormal behavior."
304
+ },
305
+ "inputs": {
306
+ "X": { "dtype": "float32", "shape": [3], "data": { "kind": "values", "values": [1e-40, -1e-40, 1e-38] } }
307
+ },
308
+ "outputs": {
309
+ "Y": {
310
+ "dtype": "float32",
311
+ "shape": [3],
312
+ "tolerance": 2e-45,
313
+ "data": { "kind": "values", "values": [4.99997305055738e-41, -4.99997305055738e-41, 4.999999675228202e-39] }
314
+ }
315
+ }
316
+ },
317
+ {
318
+ "name": "f32_subnormal_linear_region_zero_bias_vec4_gpu_gap",
319
+ "skipGpu": {
320
+ "category": "permanent",
321
+ "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."
322
+ },
323
+ "provenance": {
324
+ "source": "onnxruntime/test/contrib_ops/fastgelu_op_test.cc",
325
+ "test": "FastGeluTest.FastGeluWithBiasFloat32",
326
+ "notes": "Bias-path companion: zero bias reduces FastGelu to the same near-zero x/2 behavior, but exercises the vec4 bias-broadcast kernel variant."
327
+ },
328
+ "inputs": {
329
+ "X": {
330
+ "dtype": "float32",
331
+ "shape": [1, 4],
332
+ "data": { "kind": "values", "values": [1e-40, -1e-40, 1e-38, -1e-38] }
333
+ },
334
+ "bias": { "dtype": "float32", "shape": [4], "data": { "kind": "values", "values": [0.0, 0.0, 0.0, 0.0] } }
335
+ },
336
+ "outputs": {
337
+ "Y": {
338
+ "dtype": "float32",
339
+ "shape": [1, 4],
340
+ "tolerance": 2e-45,
341
+ "data": {
342
+ "kind": "values",
343
+ "values": [4.99997305055738e-41, -4.99997305055738e-41, 4.999999675228202e-39, -4.999999675228202e-39]
344
+ }
345
+ }
346
+ }
347
+ },
348
+ {
349
+ "name": "f32_subnormal_linear_region_zero_bias_scalar_gpu_gap",
350
+ "skipGpu": {
351
+ "category": "permanent",
352
+ "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."
353
+ },
354
+ "provenance": {
355
+ "source": "onnxruntime/test/contrib_ops/fastgelu_op_test.cc",
356
+ "test": "FastGeluTest.FastGeluWithBiasFloat32",
357
+ "notes": "Scalar bias-broadcast companion for FastGelu subnormal linear-region behavior with zero bias."
358
+ },
359
+ "inputs": {
360
+ "X": { "dtype": "float32", "shape": [1, 3], "data": { "kind": "values", "values": [1e-40, -1e-40, 1e-38] } },
361
+ "bias": { "dtype": "float32", "shape": [3], "data": { "kind": "values", "values": [0.0, 0.0, 0.0] } }
362
+ },
363
+ "outputs": {
364
+ "Y": {
365
+ "dtype": "float32",
366
+ "shape": [1, 3],
367
+ "tolerance": 2e-45,
368
+ "data": { "kind": "values", "values": [4.99997305055738e-41, -4.99997305055738e-41, 4.999999675228202e-39] }
369
+ }
370
+ }
371
+ },
372
+ {
373
+ "name": "rank4_last_dim_bias_broadcast",
374
+ "provenance": {
375
+ "source": "onnxruntime/test/contrib_ops/fastgelu_op_test.cc",
376
+ "test": "FastGeluTest.FastGeluWithBiasFloat32",
377
+ "notes": "Compact rank-4 projection of ORT's last-dimension bias behavior."
378
+ },
379
+ "inputs": {
380
+ "X": {
381
+ "dtype": "float32",
382
+ "shape": [1, 1, 2, 3],
383
+ "data": { "kind": "values", "values": [-2.0, -1.0, 0.0, 1.0, 2.0, 3.0] }
384
+ },
385
+ "bias": { "dtype": "float32", "shape": [3], "data": { "kind": "values", "values": [0.5, -0.25, 1.0] } }
386
+ },
387
+ "outputs": {
388
+ "Y": {
389
+ "dtype": "float32",
390
+ "shape": [1, 1, 2, 3],
391
+ "tolerance": 0.000001,
392
+ "data": { "kind": "values", "values": [-0.10042842, -0.1322858, 0.841192, 1.3995715, 1.6797954, 3.9999297] }
393
+ }
394
+ }
395
+ },
396
+ {
397
+ "name": "f32_scalar_bias_odd_hidden",
398
+ "inputs": {
399
+ "X": {
400
+ "dtype": "float32",
401
+ "shape": [2, 3],
402
+ "data": { "kind": "values", "values": [0.8, -0.5, 0.0, 0.5, 0.2, 0.3] }
403
+ },
404
+ "bias": { "dtype": "float32", "shape": [3], "data": { "kind": "values", "values": [-0.5, 0.6, 1.2] } }
405
+ },
406
+ "outputs": {
407
+ "Y": {
408
+ "dtype": "float32",
409
+ "shape": [2, 3],
410
+ "tolerance": 0.000001,
411
+ "data": { "kind": "values", "values": [0.18537092, 0.05398275, 1.06170277, 0.0, 0.63043169, 1.39957158] }
412
+ }
413
+ }
414
+ },
415
+ {
416
+ "name": "f32_scalar_no_bias_numel_not_div4",
417
+ "inputs": {
418
+ "X": { "dtype": "float32", "shape": [5], "data": { "kind": "values", "values": [0.8, -0.5, 0.0, 1.0, -2.0] } }
419
+ },
420
+ "outputs": {
421
+ "Y": {
422
+ "dtype": "float32",
423
+ "shape": [5],
424
+ "tolerance": 0.000001,
425
+ "data": { "kind": "values", "values": [0.63043169, -0.15428599, 0.0, 0.84119199, -0.04540231] }
426
+ }
427
+ }
428
+ },
429
+ {
430
+ "name": "f32_tanh_vs_erf_distinguisher",
431
+ "inputs": {
432
+ "X": {
433
+ "dtype": "float32",
434
+ "shape": [1, 5],
435
+ "data": { "kind": "values", "values": [-2.0, -1.0, 0.0, 1.0, 2.0] }
436
+ }
437
+ },
438
+ "outputs": {
439
+ "Y": {
440
+ "dtype": "float32",
441
+ "shape": [1, 5],
442
+ "tolerance": 0.0001,
443
+ "data": { "kind": "values", "values": [-0.04540231, -0.15880801, 0.0, 0.84119199, 1.95459769] }
444
+ }
445
+ }
446
+ }
447
+ ]
448
+ }