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

sync 91d990483a17

Browse files
README.md CHANGED
@@ -18,16 +18,16 @@ See the [ONNX Runtime `FastGelu` contrib-operator spec](https://github.com/micro
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
 
@@ -37,7 +37,7 @@ See the [ONNX Runtime `FastGelu` contrib-operator spec](https://github.com/micro
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
@@ -45,10 +45,14 @@ See the [ONNX Runtime `FastGelu` contrib-operator spec](https://github.com/micro
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
 
 
18
 
19
  ## Inputs
20
 
21
+ | Name | Logical dtype | Rank | Shape | Description | Presence |
22
+ | --- | --- | --- | --- | --- | --- |
23
+ | `X` | `T` | — | — | Values transformed by FastGelu after adding the optional `bias`. | required |
24
+ | `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 | Logical dtype | Rank | Shape | Description | Presence |
29
+ | --- | --- | --- | --- | --- | --- |
30
+ | `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
 
 
37
 
38
  ## Files
39
 
40
+ - [`metadata.json`](build/webgpu/metadata.json) — kernel metadata (id, digests, per-variant templates, 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
 
45
 
46
  ## Use with `@huggingface/kernels`
47
 
48
+ ```sh
49
+ npm install --save-exact @huggingface/kernels@0.0.1-preview.2
50
+ ```
51
+
52
+ Required output shapes and logical data types are inferred from the supplied inputs and attributes; result tensors are allocated automatically.
53
 
54
  The `version: 1` option selects the published kernel contract; it is independent of any operator opset, contrib `since_version`, or model version.
55
+ It follows the `v1` branch as fixes land. To pin exact artifact bytes, pass a 40-character commit `revision` instead of `version`.
56
 
57
  Replace each `*Data` placeholder with a typed array containing the corresponding input data.
58
 
build/webgpu/bench.json CHANGED
@@ -1,5 +1,4 @@
1
  {
2
- "op": "com.microsoft.FastGelu",
3
  "tunableSpace": { "WORKGROUP_SIZE": [64, 128, 256] },
4
  "cases": [
5
  {
 
1
  {
 
2
  "tunableSpace": { "WORKGROUP_SIZE": [64, 128, 256] },
3
  "cases": [
4
  {
build/webgpu/elementwise-bias-gelu.wgsl.jinja CHANGED
@@ -1,58 +1,29 @@
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
  }
 
 
 
 
1
  {{ env.wgsl.resourceDeclarations }}
2
  {% set wg = workgroupSize if workgroupSize is defined else tunables.WORKGROUP_SIZE %}
3
 
4
+ // Computes GELU, optionally after adding a rank-1 bias broadcast over the
5
+ // innermost axis. A present bias uses element_index % hidden_extent. The `vec4`
6
+ // path requires the innermost extent and element count to be divisible by four;
7
+ // `vec4Tail` instead uses scalar bindings with four guarded lanes.
8
+ // GELU uses the tanh approximation below, with its input clamped in the tails.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  fn tanh_safe(x: f32) -> f32 {
10
  if (x > 10.0) { return 1.0; }
11
  if (x < -10.0) { return -1.0; }
12
  return tanh(x);
13
  }
 
14
  fn gelu_value(v: f32) -> f32 {
 
 
 
15
  return 0.5 * v * (1.0 + tanh_safe(0.7978845608028654 * (v + 0.044715 * v * v * v)));
 
16
  }
17
  {% if hasBias %}
18
 
19
+ const HIDDEN: u32 = {{ hidden | default(0) }}u;
20
 
21
  {% endif %}
22
  @compute @workgroup_size({{ wg }})
23
+ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
24
  // 2D-folded flat index: gid.y carries the high bits past the
25
+ // per-axis dispatch fold width (outputs > 16.7M elements).
26
+ let i = gid.x + gid.y * {{ DISPATCH_FOLD_WIDTH }}u * {{ wg }}u;
27
  if (i >= params.count) {
28
  return;
29
  }
build/webgpu/manifest.json CHANGED
@@ -2,120 +2,42 @@
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,
@@ -127,31 +49,39 @@
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,
@@ -162,31 +92,39 @@
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,
@@ -197,23 +135,31 @@
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
  }
 
2
  "domain": "com.microsoft",
3
  "name": "FastGelu",
4
  "sinceVersion": 1,
5
+ "inputs": { "X": { "dtype": "T" }, "bias": { "dtype": "T", "rank": 1, "optional": true } },
6
+ "outputs": { "Y": { "dtype": "T", "rank": "ranks.X", "shape": "shapes.X" } },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
  "typeConstraints": { "T": ["float32", "float16"] },
8
+ "tunables": { "WORKGROUP_SIZE": { "default": 256 } },
 
 
 
 
 
9
  "derive": {
10
  "deviceWorkgroupCap": "min(device.limits.maxComputeInvocationsPerWorkgroup, device.limits.maxComputeWorkgroupSizeX)",
11
  "storageBufferLimit": "min(device.limits.maxStorageBufferBindingSize, device.limits.maxBufferSize)",
12
  "workgroupSize": "min(tunables.WORKGROUP_SIZE, deviceWorkgroupCap)",
13
  "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)",
14
+ "dispatchFits": "numel(shapes.X) <= min(device.limits.maxComputeWorkgroupsPerDimension, 65535) * min(device.limits.maxComputeWorkgroupsPerDimension, 65535) * workgroupSize * 4",
15
  "baseOk": "workgroupSize > 0 and ranks.X >= 1 and numel(shapes.X) == numel(shapes.Y) and f16Ok(dtypes.T) and buffersFit and dispatchFits",
16
  "biasOk": "present.bias and ranks.bias == 1 and dim(shapes.bias, 0) == dim(shapes.X, ranks.X - 1)",
17
  "noBiasOk": "not present.bias",
18
+ "vec4Ok": "numel(shapes.X) > 0 and numel(shapes.X) % 4 == 0 and dim(shapes.X, ranks.X - 1) % 4 == 0",
19
+ "scalar": "dtypes.T",
20
+ "approximate": "\"tanh\""
21
  },
22
+ "when": ["baseOk"],
23
+ "bindings": {
24
+ "x": { "arg": "X", "buffer": "read-only-storage", "elementType": "$vectorScalar" },
25
+ "y": { "arg": "Y", "buffer": "storage", "elementType": "$vectorScalar" },
26
+ "params": { "buffer": "uniform", "struct": [{ "name": "count", "type": "u32", "value": "numel(shapes.X) / 4" }] },
27
+ "x_2": { "arg": "X", "name": "x", "buffer": "read-only-storage", "elementType": "$scalar" },
28
+ "y_2": { "arg": "Y", "name": "y", "buffer": "storage", "elementType": "$scalar" },
29
+ "params_2": {
30
+ "name": "params",
31
+ "buffer": "uniform",
32
+ "struct": [{ "name": "count", "type": "u32", "value": "numel(shapes.X)" }]
33
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  },
35
  "variants": [
36
  {
37
  "id": "vec4_bias",
38
  "priority": 30,
39
+ "when": ["biasOk", "vec4Ok"],
40
+ "derive": {
41
  "vec4": true,
42
  "vec4Tail": false,
43
  "hasBias": true,
 
49
  "id": "main",
50
  "name": "FastGelu.vec4Bias",
51
  "shader": "elementwise-bias-gelu.wgsl.jinja",
52
+ "bindings": ["x", { "arg": "bias", "elementType": "$scalar", "length": "$hidden" }, "y", "params"],
53
+ "dispatch": {
54
+ "x": "min(ceilDiv((numel(shapes.X) / 4), (workgroupSize)), 65535)",
55
+ "y": "ceilDiv(ceilDiv((numel(shapes.X) / 4), (workgroupSize)), 65535)",
56
+ "z": 1
57
+ }
58
  }
59
  ]
60
  },
61
  {
62
  "id": "vec4_no_bias",
63
  "priority": 25,
64
+ "when": ["noBiasOk", "vec4Ok"],
65
+ "derive": { "vec4": true, "vec4Tail": false, "hasBias": false, "vectorScalar": "\"vec4<\" ~ dtypes.T ~ \">\"" },
66
  "passes": [
67
  {
68
  "id": "main",
69
  "name": "FastGelu.vec4",
70
  "shader": "elementwise-bias-gelu.wgsl.jinja",
71
+ "bindings": ["x", "y", "params"],
72
+ "dispatch": {
73
+ "x": "min(ceilDiv((numel(shapes.X) / 4), (workgroupSize)), 65535)",
74
+ "y": "ceilDiv(ceilDiv((numel(shapes.X) / 4), (workgroupSize)), 65535)",
75
+ "z": 1
76
+ }
77
  }
78
  ]
79
  },
80
  {
81
  "id": "vec4_tail_bias",
82
  "priority": 20,
83
+ "when": ["biasOk", "numel(shapes.X) > 0"],
84
+ "derive": {
85
  "vec4": false,
86
  "vec4Tail": true,
87
  "hasBias": true,
 
92
  "id": "main",
93
  "name": "FastGelu.vec4TailBias",
94
  "shader": "elementwise-bias-gelu.wgsl.jinja",
95
+ "bindings": ["x_2", "bias", "y_2", "params_2"],
96
+ "dispatch": {
97
+ "x": "min(ceilDiv((ceilDiv(numel(shapes.X), 4)), (workgroupSize)), 65535)",
98
+ "y": "ceilDiv(ceilDiv((ceilDiv(numel(shapes.X), 4)), (workgroupSize)), 65535)",
99
+ "z": 1
100
+ }
101
  }
102
  ]
103
  },
104
  {
105
  "id": "vec4_tail_no_bias",
106
  "priority": 15,
107
+ "when": ["noBiasOk", "numel(shapes.X) > 0"],
108
+ "derive": { "vec4": false, "vec4Tail": true, "hasBias": false },
109
  "passes": [
110
  {
111
  "id": "main",
112
  "name": "FastGelu.vec4Tail",
113
  "shader": "elementwise-bias-gelu.wgsl.jinja",
114
+ "bindings": ["x_2", "y_2", "params_2"],
115
+ "dispatch": {
116
+ "x": "min(ceilDiv((ceilDiv(numel(shapes.X), 4)), (workgroupSize)), 65535)",
117
+ "y": "ceilDiv(ceilDiv((ceilDiv(numel(shapes.X), 4)), (workgroupSize)), 65535)",
118
+ "z": 1
119
+ }
120
  }
121
  ]
122
  },
123
  {
124
  "id": "scalar_bias",
125
  "priority": 10,
126
+ "when": ["biasOk", "true"],
127
+ "derive": {
128
  "vec4": false,
129
  "vec4Tail": false,
130
  "hasBias": true,
 
135
  "id": "main",
136
  "name": "FastGelu.scalarBias",
137
  "shader": "elementwise-bias-gelu.wgsl.jinja",
138
+ "bindings": ["x_2", "bias", "y_2", "params_2"],
139
+ "dispatch": {
140
+ "x": "min(ceilDiv((numel(shapes.X)), (workgroupSize)), 65535)",
141
+ "y": "ceilDiv(ceilDiv((numel(shapes.X)), (workgroupSize)), 65535)",
142
+ "z": 1
143
+ }
144
  }
145
  ]
146
  },
147
  {
148
  "id": "scalar_no_bias",
149
  "priority": 0,
150
+ "when": ["noBiasOk", "true"],
151
+ "derive": { "vec4": false, "vec4Tail": false, "hasBias": false },
152
  "passes": [
153
  {
154
  "id": "main",
155
  "name": "FastGelu.scalar",
156
  "shader": "elementwise-bias-gelu.wgsl.jinja",
157
+ "bindings": ["x_2", "y_2", "params_2"],
158
+ "dispatch": {
159
+ "x": "min(ceilDiv((numel(shapes.X)), (workgroupSize)), 65535)",
160
+ "y": "ceilDiv(ceilDiv((numel(shapes.X)), (workgroupSize)), 65535)",
161
+ "z": 1
162
+ }
163
  }
164
  ]
165
  }
build/webgpu/metadata.json CHANGED
@@ -1,18 +1,28 @@
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
  }
 
1
  {
2
  "name": "com.microsoft.FastGelu",
3
+ "id": "_com_microsoft_fastgelu_webgpu_da3aabd",
4
  "version": 1,
5
  "license": "Apache-2.0",
6
  "backend": { "type": "webgpu" },
7
  "digest": {
8
  "algorithm": "sha256",
9
  "files": {
10
+ "bench.json": "uob2jmkWOUzFyVqQy0sJhB7JkQGvh+5ux8/7f+O6DYA=",
11
+ "elementwise-bias-gelu.wgsl.jinja": "OW2nqbCYsSLMd8w5lKcNx4zjdkHi4i2kB+FFAKyHhFg=",
12
+ "manifest.json": "nHE7yhM3Q5obzXWntT8sXryEtqYicMVDVSqdP+kwbLs=",
13
+ "test.json": "oH8XR6itu84Ti3GZbKE8ImRXTl4N2njDh1qRw0+HhCs="
14
  }
15
  },
16
+ "provenance": { "kernel": { "sha": "91d990483a174128daf7673f3f37a7c890493ae1", "dirty": false } },
17
+ "webgpu": {
18
+ "manifestSpec": "2.0",
19
+ "variants": {
20
+ "vec4_bias": ["elementwise-bias-gelu.wgsl.jinja"],
21
+ "vec4_no_bias": ["elementwise-bias-gelu.wgsl.jinja"],
22
+ "vec4_tail_bias": ["elementwise-bias-gelu.wgsl.jinja"],
23
+ "vec4_tail_no_bias": ["elementwise-bias-gelu.wgsl.jinja"],
24
+ "scalar_bias": ["elementwise-bias-gelu.wgsl.jinja"],
25
+ "scalar_no_bias": ["elementwise-bias-gelu.wgsl.jinja"]
26
+ }
27
+ }
28
  }
build/webgpu/test.json CHANGED
@@ -1,5 +1,4 @@
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
  },
@@ -77,7 +76,7 @@
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": [] } } }
@@ -300,7 +299,7 @@
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] } }
@@ -323,7 +322,7 @@
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": {
@@ -354,7 +353,7 @@
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] } },
 
1
  {
 
2
  "fixtureArrays": {
3
  "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]
4
  },
 
76
  {
77
  "name": "f32_scalar_no_bias_zero_sequence",
78
  "provenance": {
79
+ "notes": "An empty bias-free input bypasses both vec4 routes and selects the scalar no-bias kernel."
80
  },
81
  "inputs": { "X": { "dtype": "float32", "shape": [1, 0, 4], "data": { "kind": "values", "values": [] } } },
82
  "outputs": { "Y": { "dtype": "float32", "shape": [1, 0, 4], "data": { "kind": "values", "values": [] } } }
 
299
  "provenance": {
300
  "source": "onnxruntime/test/contrib_ops/fastgelu_op_test.cc",
301
  "test": "FastGeluTest.FastGeluWithoutBiasFloat32",
302
+ "notes": "Near-zero inputs exercise FastGelu's subnormal x/2 behavior on the scalar path."
303
  },
304
  "inputs": {
305
  "X": { "dtype": "float32", "shape": [3], "data": { "kind": "values", "values": [1e-40, -1e-40, 1e-38] } }
 
322
  "provenance": {
323
  "source": "onnxruntime/test/contrib_ops/fastgelu_op_test.cc",
324
  "test": "FastGeluTest.FastGeluWithBiasFloat32",
325
+ "notes": "Zero bias isolates near-zero x/2 behavior on the vec4 bias-broadcast path."
326
  },
327
  "inputs": {
328
  "X": {
 
353
  "provenance": {
354
  "source": "onnxruntime/test/contrib_ops/fastgelu_op_test.cc",
355
  "test": "FastGeluTest.FastGeluWithBiasFloat32",
356
+ "notes": "Zero bias isolates subnormal linear-region behavior on the scalar bias-broadcast path."
357
  },
358
  "inputs": {
359
  "X": { "dtype": "float32", "shape": [1, 3], "data": { "kind": "values", "values": [1e-40, -1e-40, 1e-38] } },