Xenova HF Staff commited on
Commit
2e68766
·
verified ·
1 Parent(s): 078aa71

sync 91d990483a17

Browse files
README.md CHANGED
@@ -18,19 +18,19 @@ See the [ONNX Runtime `LinearAttentionGate` contrib-operator spec](https://githu
18
 
19
  ## Inputs
20
 
21
- | Name | Bind key | Logical dtype | Rank | Shape | Description | Presence |
22
  | --- | --- | --- | --- | --- | --- | --- |
23
- | `a` | `aT` | `T` | — | — | Decay gate projection with shape `(B, T, H)`. Any rank of at least 1 is accepted; the last axis is the head count and the leading axes are folded. | required |
24
- | `dt_bias` | `dtBiasT` | `TF` | `1` | — | Per-head float32 bias added to `a`, with shape (H). | required |
25
- | `decay_scale` | `decayScaleT` | `TF` | `1` | — | Per-head float32 multiplier applied to `softplus(a + dt_bias)`, with shape `(H)`. For gated DeltaNet this is `-exp(A_log)`. | required |
26
- | `b` | `bT` | `T` | — | — | Update-rate projection with the same shape as `a` when `beta` is requested. It is accepted but unused when `beta` is omitted. | optional |
27
 
28
  ## Outputs
29
 
30
- | Name | Bind key | Logical dtype | Rank | Shape | Description | Presence |
31
  | --- | --- | --- | --- | --- | --- | --- |
32
- | `decay` | `decayT` | `T` | same as `a` | same as `a` | `decay_scale * softplus(a + dt_bias)`, with the same shape as `a`. | required |
33
- | `beta` | `betaT` | `T` | same as `a` | same as `a` | sigmoid(b), with the same shape as `a`. Requires the `b` input. | optional |
34
 
35
  ## Type constraints
36
 
@@ -41,7 +41,7 @@ See the [ONNX Runtime `LinearAttentionGate` contrib-operator spec](https://githu
41
 
42
  ## Files
43
 
44
- - [`metadata.json`](build/webgpu/metadata.json) — kernel metadata (id, digests, provenance)
45
  - [`manifest.json`](build/webgpu/manifest.json) — the op contract (source of truth)
46
  - [`test.json`](build/webgpu/test.json) — correctness cases
47
  - [`bench.json`](build/webgpu/bench.json) — benchmark + tuning cases
@@ -49,10 +49,14 @@ See the [ONNX Runtime `LinearAttentionGate` contrib-operator spec](https://githu
49
 
50
  ## Use with `@huggingface/kernels`
51
 
52
- The loader derives every required output's shape and logical dtype from the manifest contract and this call.
53
- It then allocates the result tensors automatically.
 
 
 
54
 
55
  The `version: 1` option selects the published kernel contract; it is independent of any operator opset, contrib `since_version`, or model version.
 
56
 
57
  Replace each `*Data` placeholder with a typed array containing the corresponding input data.
58
 
 
18
 
19
  ## Inputs
20
 
21
+ | Name | Upstream name | Logical dtype | Rank | Shape | Description | Presence |
22
  | --- | --- | --- | --- | --- | --- | --- |
23
+ | `aT` | `a` | `T` | — | — | Decay gate projection with shape `(B, T, H)`. Any rank of at least 1 is accepted; the last axis is the head count and the leading axes are folded. | required |
24
+ | `dtBiasT` | `dt_bias` | `TF` | `1` | — | Per-head float32 bias added to `a`, with shape (H). | required |
25
+ | `decayScaleT` | `decay_scale` | `TF` | `1` | — | Per-head float32 multiplier applied to `softplus(a + dt_bias)`, with shape `(H)`. For gated DeltaNet this is `-exp(A_log)`. | required |
26
+ | `bT` | `b` | `T` | — | — | Update-rate projection with the same shape as `a` when `beta` is requested. It is accepted but unused when `beta` is omitted. | optional |
27
 
28
  ## Outputs
29
 
30
+ | Name | Upstream name | Logical dtype | Rank | Shape | Description | Presence |
31
  | --- | --- | --- | --- | --- | --- | --- |
32
+ | `decayT` | `decay` | `T` | same as `aT` | same as `aT` | `decay_scale * softplus(a + dt_bias)`, with the same shape as `a`. | required |
33
+ | `betaT` | `beta` | `T` | same as `aT` | same as `aT` | sigmoid(b), with the same shape as `a`. Requires the `b` input. | optional |
34
 
35
  ## Type constraints
36
 
 
41
 
42
  ## Files
43
 
44
+ - [`metadata.json`](build/webgpu/metadata.json) — kernel metadata (id, digests, per-variant templates, provenance)
45
  - [`manifest.json`](build/webgpu/manifest.json) — the op contract (source of truth)
46
  - [`test.json`](build/webgpu/test.json) — correctness cases
47
  - [`bench.json`](build/webgpu/bench.json) — benchmark + tuning cases
 
49
 
50
  ## Use with `@huggingface/kernels`
51
 
52
+ ```sh
53
+ npm install --save-exact @huggingface/kernels@0.0.1-preview.2
54
+ ```
55
+
56
+ Required output shapes and logical data types are inferred from the supplied inputs and attributes; result tensors are allocated 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
+ It follows the `v1` branch as fixes land. To pin exact artifact bytes, pass a 40-character commit `revision` instead of `version`.
60
 
61
  Replace each `*Data` placeholder with a typed array containing the corresponding input data.
62
 
build/webgpu/bench.json CHANGED
@@ -1,5 +1,4 @@
1
  {
2
- "op": "com.microsoft.LinearAttentionGate",
3
  "tunableSpace": { "WORKGROUP_SIZE": [32, 64, 128, 256] },
4
  "cases": [
5
  {
 
1
  {
 
2
  "tunableSpace": { "WORKGROUP_SIZE": [32, 64, 128, 256] },
3
  "cases": [
4
  {
build/webgpu/linear-attention-gate.wgsl.jinja CHANGED
@@ -51,11 +51,10 @@ fn softplus(x: f32) -> f32 {
51
  // so the operands are widened on load and the result is narrowed only on store.
52
  @compute @workgroup_size(WORKGROUP_SIZE, 1, 1)
53
  fn main(
54
- @builtin(global_invocation_id) gid: vec3<u32>,
55
- @builtin(num_workgroups) nwg: vec3<u32>
56
  ) {
57
  // Rebuild the flat invocation index after the 2D dispatch fold.
58
- let item = gid.x + gid.y * nwg.x * WORKGROUP_SIZE;
59
  if (item >= GATE_ITEMS) {
60
  return;
61
  }
 
51
  // so the operands are widened on load and the result is narrowed only on store.
52
  @compute @workgroup_size(WORKGROUP_SIZE, 1, 1)
53
  fn main(
54
+ @builtin(global_invocation_id) gid: vec3<u32>
 
55
  ) {
56
  // Rebuild the flat invocation index after the 2D dispatch fold.
57
+ let item = gid.x + gid.y * {{ DISPATCH_FOLD_WIDTH }}u * WORKGROUP_SIZE;
58
  if (item >= GATE_ITEMS) {
59
  return;
60
  }
build/webgpu/manifest.json CHANGED
@@ -2,62 +2,21 @@
2
  "domain": "com.microsoft",
3
  "name": "LinearAttentionGate",
4
  "sinceVersion": 1,
5
- "description": "Fuses the gate projections used by `com.microsoft.LinearAttention`'s gated-delta recurrence: `decay = decay_scale * softplus(a + dt_bias)` and, when requested, `beta = sigmoid(b)`. The last input axis is the head axis; `dt_bias` and `decay_scale` are float32 per-head vectors. Gate arithmetic is performed in float32 and narrowed only on store. Requesting `beta` requires `b`; an unconsumed `b` is permitted when `beta` is omitted.",
6
- "inputs": [
7
- {
8
- "role": "a",
9
- "dtype": "T",
10
- "description": "Decay gate projection with shape `(B, T, H)`. Any rank of at least 1 is accepted; the last axis is the head count and the leading axes are folded."
11
- },
12
- {
13
- "role": "dt_bias",
14
- "dtype": "TF",
15
- "rank": 1,
16
- "description": "Per-head float32 bias added to `a`, with shape (H)."
17
- },
18
- {
19
- "role": "decay_scale",
20
- "dtype": "TF",
21
- "rank": 1,
22
- "description": "Per-head float32 multiplier applied to `softplus(a + dt_bias)`, with shape `(H)`. For gated DeltaNet this is `-exp(A_log)`."
23
- },
24
- {
25
- "role": "b",
26
- "dtype": "T",
27
- "optional": true,
28
- "description": "Update-rate projection with the same shape as `a` when `beta` is requested. It is accepted but unused when `beta` is omitted."
29
- }
30
- ],
31
- "outputs": [
32
- {
33
- "role": "decay",
34
- "dtype": "T",
35
- "rank": "ranks.aT",
36
- "shape": "shapes.aT",
37
- "description": "`decay_scale * softplus(a + dt_bias)`, with the same shape as `a`."
38
- },
39
- {
40
- "role": "beta",
41
- "dtype": "T",
42
- "rank": "ranks.aT",
43
- "optional": true,
44
- "shape": "shapes.aT",
45
- "description": "sigmoid(b), with the same shape as `a`. Requires the `b` input."
46
- }
47
- ],
48
- "typeConstraints": { "T": ["float32", "float16"], "TF": ["float32"] },
49
- "tunables": { "WORKGROUP_SIZE": 64 },
50
- "args": {
51
- "aT": { "kind": "tensor", "semantic": "a", "role": "input" },
52
- "dtBiasT": { "kind": "tensor", "semantic": "dt_bias", "role": "weights" },
53
- "decayScaleT": { "kind": "tensor", "semantic": "decay_scale", "role": "weights" },
54
- "bT": { "kind": "tensor", "semantic": "b", "role": "input", "required": false },
55
- "decayT": { "kind": "tensor", "semantic": "decay", "role": "output" },
56
- "betaT": { "kind": "tensor", "semantic": "beta", "role": "output", "required": false }
57
  },
 
 
 
 
 
 
58
  "derive": {
59
  "deviceWorkgroupCap": "min(device.limits.maxComputeInvocationsPerWorkgroup, device.limits.maxComputeWorkgroupSizeX)",
60
- "foldedDispatchCapacity": "device.limits.maxComputeWorkgroupsPerDimension * device.limits.maxComputeWorkgroupsPerDimension",
61
  "numHeads": "dim(shapes.aT, ranks.aT - 1)",
62
  "gateCount": "numel(shapes.aT)",
63
  "headsVec4": "numHeads / 4",
@@ -72,98 +31,31 @@
72
  "scalarDispatchFits": "ceilDiv(gateCount, tunables.WORKGROUP_SIZE) <= foldedDispatchCapacity",
73
  "vec4DispatchFits": "numHeads % 4 == 0 and ceilDiv(gateVec4Count, tunables.WORKGROUP_SIZE) <= foldedDispatchCapacity"
74
  },
75
- "bindingSets": {
76
- "decayOnlyIo": [
77
- {
78
- "name": "a",
79
- "arg": "aT",
80
- "semantic": "a",
81
- "buffer": { "type": "read-only-storage" },
82
- "elementType": "$gateElement",
83
- "length": "$gateItems"
84
- },
85
- {
86
- "name": "dt_bias",
87
- "arg": "dtBiasT",
88
- "semantic": "dt_bias",
89
- "buffer": { "type": "read-only-storage" },
90
- "elementType": "$paramElement",
91
- "length": "$headItems"
92
- },
93
- {
94
- "name": "decay_scale",
95
- "arg": "decayScaleT",
96
- "semantic": "decay_scale",
97
- "buffer": { "type": "read-only-storage" },
98
- "elementType": "$paramElement",
99
- "length": "$headItems"
100
- },
101
- {
102
- "name": "decay",
103
- "arg": "decayT",
104
- "semantic": "decay",
105
- "buffer": { "type": "storage" },
106
- "elementType": "$gateElement",
107
- "length": "$gateItems"
108
- }
109
- ],
110
- "withBetaIo": [
111
- {
112
- "name": "a",
113
- "arg": "aT",
114
- "semantic": "a",
115
- "buffer": { "type": "read-only-storage" },
116
- "elementType": "$gateElement",
117
- "length": "$gateItems"
118
- },
119
- {
120
- "name": "dt_bias",
121
- "arg": "dtBiasT",
122
- "semantic": "dt_bias",
123
- "buffer": { "type": "read-only-storage" },
124
- "elementType": "$paramElement",
125
- "length": "$headItems"
126
- },
127
- {
128
- "name": "decay_scale",
129
- "arg": "decayScaleT",
130
- "semantic": "decay_scale",
131
- "buffer": { "type": "read-only-storage" },
132
- "elementType": "$paramElement",
133
- "length": "$headItems"
134
- },
135
- {
136
- "name": "b",
137
- "arg": "bT",
138
- "semantic": "b",
139
- "buffer": { "type": "read-only-storage" },
140
- "elementType": "$gateElement",
141
- "length": "$gateItems"
142
- },
143
- {
144
- "name": "decay",
145
- "arg": "decayT",
146
- "semantic": "decay",
147
- "buffer": { "type": "storage" },
148
- "elementType": "$gateElement",
149
- "length": "$gateItems"
150
- },
151
- {
152
- "name": "beta",
153
- "arg": "betaT",
154
- "semantic": "beta",
155
- "buffer": { "type": "storage" },
156
- "elementType": "$gateElement",
157
- "length": "$gateItems"
158
- }
159
- ]
160
  },
161
  "variants": [
162
  {
163
  "id": "vec4_gate_beta",
164
  "priority": 30,
165
- "when": ["betaContract", "workgroupFits", "vec4DispatchFits"],
166
- "constants": {
167
  "vectorized": true,
168
  "hasBeta": true,
169
  "usesF16": "gateDtype == \"float16\"",
@@ -178,16 +70,20 @@
178
  "id": "main",
179
  "name": "LinearAttentionGate.Vec4GateBeta",
180
  "shader": "linear-attention-gate.wgsl.jinja",
181
- "bindings": "withBetaIo",
182
- "dispatch": { "threads": "gateVec4Count", "workgroupSize": "tunables.WORKGROUP_SIZE" }
 
 
 
 
183
  }
184
  ]
185
  },
186
  {
187
  "id": "vec4_gate",
188
  "priority": 20,
189
- "when": ["decayOnlyContract", "workgroupFits", "vec4DispatchFits"],
190
- "constants": {
191
  "vectorized": true,
192
  "hasBeta": false,
193
  "usesF16": "gateDtype == \"float16\"",
@@ -202,16 +98,20 @@
202
  "id": "main",
203
  "name": "LinearAttentionGate.Vec4Gate",
204
  "shader": "linear-attention-gate.wgsl.jinja",
205
- "bindings": "decayOnlyIo",
206
- "dispatch": { "threads": "gateVec4Count", "workgroupSize": "tunables.WORKGROUP_SIZE" }
 
 
 
 
207
  }
208
  ]
209
  },
210
  {
211
  "id": "scalar_gate_beta",
212
  "priority": 10,
213
- "when": ["betaContract", "workgroupFits", "scalarDispatchFits"],
214
- "constants": {
215
  "vectorized": false,
216
  "hasBeta": true,
217
  "usesF16": "gateDtype == \"float16\"",
@@ -226,16 +126,20 @@
226
  "id": "main",
227
  "name": "LinearAttentionGate.ScalarGateBeta",
228
  "shader": "linear-attention-gate.wgsl.jinja",
229
- "bindings": "withBetaIo",
230
- "dispatch": { "threads": "gateCount", "workgroupSize": "tunables.WORKGROUP_SIZE" }
 
 
 
 
231
  }
232
  ]
233
  },
234
  {
235
  "id": "scalar_gate",
236
  "priority": 0,
237
- "when": ["decayOnlyContract", "workgroupFits", "scalarDispatchFits"],
238
- "constants": {
239
  "vectorized": false,
240
  "hasBeta": false,
241
  "usesF16": "gateDtype == \"float16\"",
@@ -250,8 +154,12 @@
250
  "id": "main",
251
  "name": "LinearAttentionGate.ScalarGate",
252
  "shader": "linear-attention-gate.wgsl.jinja",
253
- "bindings": "decayOnlyIo",
254
- "dispatch": { "threads": "gateCount", "workgroupSize": "tunables.WORKGROUP_SIZE" }
 
 
 
 
255
  }
256
  ]
257
  }
 
2
  "domain": "com.microsoft",
3
  "name": "LinearAttentionGate",
4
  "sinceVersion": 1,
5
+ "inputs": {
6
+ "aT": { "onnx": "a", "dtype": "T" },
7
+ "dtBiasT": { "onnx": "dt_bias", "dtype": "TF", "rank": 1 },
8
+ "decayScaleT": { "onnx": "decay_scale", "dtype": "TF", "rank": 1 },
9
+ "bT": { "onnx": "b", "dtype": "T", "optional": true }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  },
11
+ "outputs": {
12
+ "decayT": { "onnx": "decay", "dtype": "T", "rank": "ranks.aT", "shape": "shapes.aT" },
13
+ "betaT": { "onnx": "beta", "dtype": "T", "rank": "ranks.aT", "optional": true, "shape": "shapes.aT" }
14
+ },
15
+ "typeConstraints": { "T": ["float32", "float16"], "TF": ["float32"] },
16
+ "tunables": { "WORKGROUP_SIZE": { "default": 64 } },
17
  "derive": {
18
  "deviceWorkgroupCap": "min(device.limits.maxComputeInvocationsPerWorkgroup, device.limits.maxComputeWorkgroupSizeX)",
19
+ "foldedDispatchCapacity": "min(device.limits.maxComputeWorkgroupsPerDimension, 65535) * min(device.limits.maxComputeWorkgroupsPerDimension, 65535)",
20
  "numHeads": "dim(shapes.aT, ranks.aT - 1)",
21
  "gateCount": "numel(shapes.aT)",
22
  "headsVec4": "numHeads / 4",
 
31
  "scalarDispatchFits": "ceilDiv(gateCount, tunables.WORKGROUP_SIZE) <= foldedDispatchCapacity",
32
  "vec4DispatchFits": "numHeads % 4 == 0 and ceilDiv(gateVec4Count, tunables.WORKGROUP_SIZE) <= foldedDispatchCapacity"
33
  },
34
+ "when": ["workgroupFits"],
35
+ "bindings": {
36
+ "a": { "arg": "aT", "buffer": "read-only-storage", "elementType": "$gateElement", "length": "$gateItems" },
37
+ "dt_bias": {
38
+ "arg": "dtBiasT",
39
+ "buffer": "read-only-storage",
40
+ "elementType": "$paramElement",
41
+ "length": "$headItems"
42
+ },
43
+ "decay_scale": {
44
+ "arg": "decayScaleT",
45
+ "buffer": "read-only-storage",
46
+ "elementType": "$paramElement",
47
+ "length": "$headItems"
48
+ },
49
+ "b": { "arg": "bT", "buffer": "read-only-storage", "elementType": "$gateElement", "length": "$gateItems" },
50
+ "decay": { "arg": "decayT", "buffer": "storage", "elementType": "$gateElement", "length": "$gateItems" },
51
+ "beta": { "arg": "betaT", "buffer": "storage", "elementType": "$gateElement", "length": "$gateItems" }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
  },
53
  "variants": [
54
  {
55
  "id": "vec4_gate_beta",
56
  "priority": 30,
57
+ "when": ["betaContract", "vec4DispatchFits"],
58
+ "derive": {
59
  "vectorized": true,
60
  "hasBeta": true,
61
  "usesF16": "gateDtype == \"float16\"",
 
70
  "id": "main",
71
  "name": "LinearAttentionGate.Vec4GateBeta",
72
  "shader": "linear-attention-gate.wgsl.jinja",
73
+ "bindings": ["a", "dt_bias", "decay_scale", "b", "decay", "beta"],
74
+ "dispatch": {
75
+ "x": "min(ceilDiv((gateVec4Count), (tunables.WORKGROUP_SIZE)), 65535)",
76
+ "y": "ceilDiv(ceilDiv((gateVec4Count), (tunables.WORKGROUP_SIZE)), 65535)",
77
+ "z": 1
78
+ }
79
  }
80
  ]
81
  },
82
  {
83
  "id": "vec4_gate",
84
  "priority": 20,
85
+ "when": ["decayOnlyContract", "vec4DispatchFits"],
86
+ "derive": {
87
  "vectorized": true,
88
  "hasBeta": false,
89
  "usesF16": "gateDtype == \"float16\"",
 
98
  "id": "main",
99
  "name": "LinearAttentionGate.Vec4Gate",
100
  "shader": "linear-attention-gate.wgsl.jinja",
101
+ "bindings": ["a", "dt_bias", "decay_scale", "decay"],
102
+ "dispatch": {
103
+ "x": "min(ceilDiv((gateVec4Count), (tunables.WORKGROUP_SIZE)), 65535)",
104
+ "y": "ceilDiv(ceilDiv((gateVec4Count), (tunables.WORKGROUP_SIZE)), 65535)",
105
+ "z": 1
106
+ }
107
  }
108
  ]
109
  },
110
  {
111
  "id": "scalar_gate_beta",
112
  "priority": 10,
113
+ "when": ["betaContract", "scalarDispatchFits"],
114
+ "derive": {
115
  "vectorized": false,
116
  "hasBeta": true,
117
  "usesF16": "gateDtype == \"float16\"",
 
126
  "id": "main",
127
  "name": "LinearAttentionGate.ScalarGateBeta",
128
  "shader": "linear-attention-gate.wgsl.jinja",
129
+ "bindings": ["a", "dt_bias", "decay_scale", "b", "decay", "beta"],
130
+ "dispatch": {
131
+ "x": "min(ceilDiv((gateCount), (tunables.WORKGROUP_SIZE)), 65535)",
132
+ "y": "ceilDiv(ceilDiv((gateCount), (tunables.WORKGROUP_SIZE)), 65535)",
133
+ "z": 1
134
+ }
135
  }
136
  ]
137
  },
138
  {
139
  "id": "scalar_gate",
140
  "priority": 0,
141
+ "when": ["decayOnlyContract", "scalarDispatchFits"],
142
+ "derive": {
143
  "vectorized": false,
144
  "hasBeta": false,
145
  "usesF16": "gateDtype == \"float16\"",
 
154
  "id": "main",
155
  "name": "LinearAttentionGate.ScalarGate",
156
  "shader": "linear-attention-gate.wgsl.jinja",
157
+ "bindings": ["a", "dt_bias", "decay_scale", "decay"],
158
+ "dispatch": {
159
+ "x": "min(ceilDiv((gateCount), (tunables.WORKGROUP_SIZE)), 65535)",
160
+ "y": "ceilDiv(ceilDiv((gateCount), (tunables.WORKGROUP_SIZE)), 65535)",
161
+ "z": 1
162
+ }
163
  }
164
  ]
165
  }
build/webgpu/metadata.json CHANGED
@@ -1,18 +1,26 @@
1
  {
2
  "name": "com.microsoft.LinearAttentionGate",
3
- "id": "_com_microsoft_linearattentiongate_webgpu_cfa91bb",
4
  "version": 1,
5
  "license": "Apache-2.0",
6
  "backend": { "type": "webgpu" },
7
  "digest": {
8
  "algorithm": "sha256",
9
  "files": {
10
- "bench.json": "1NTbbJYE62OsV1lkReUeXTrI7rnBiOY3HTg5ldTfPyk=",
11
- "linear-attention-gate.wgsl.jinja": "NRzrWvQ2VrRHu5YsGLn5RGMIXHePxHum+umyWdbcWJs=",
12
- "manifest.json": "s1kmQ2WU1JJPknyUoE8HJj3gUC7F44ubx+ZkAtbc8To=",
13
- "test.json": "mRMxucSUiqKh/upG/J2xGsRxpeEDFhVLOYGYRCMQd2Y="
14
  }
15
  },
16
- "provenance": { "kernel": { "sha": "2e7068faf55e7f43df740015f6d1ee49391a41c5", "dirty": false } },
17
- "webgpu": { "manifestSpec": "1.0", "specialized": true, "opPath": "ops/com.microsoft.LinearAttentionGate" }
 
 
 
 
 
 
 
 
18
  }
 
1
  {
2
  "name": "com.microsoft.LinearAttentionGate",
3
+ "id": "_com_microsoft_linearattentiongate_webgpu_4bb5397",
4
  "version": 1,
5
  "license": "Apache-2.0",
6
  "backend": { "type": "webgpu" },
7
  "digest": {
8
  "algorithm": "sha256",
9
  "files": {
10
+ "bench.json": "nSMkCE+adLNKSBkCYEFz8YeOJf6YjUsw4vEzFToXs5U=",
11
+ "linear-attention-gate.wgsl.jinja": "Gi935dqD4NLjZbH6v4gzTYZElbzpeL5mC+ZD91H5pvo=",
12
+ "manifest.json": "kEskRGoQGGG0erg57qnQc/Sa4hJq5cNnduwqwU5zuDk=",
13
+ "test.json": "rlpI/FCSMX4yxQoveUCaj13GqK8JA+dadMzKFo129I8="
14
  }
15
  },
16
+ "provenance": { "kernel": { "sha": "91d990483a174128daf7673f3f37a7c890493ae1", "dirty": false } },
17
+ "webgpu": {
18
+ "manifestSpec": "2.0",
19
+ "variants": {
20
+ "vec4_gate_beta": ["linear-attention-gate.wgsl.jinja"],
21
+ "vec4_gate": ["linear-attention-gate.wgsl.jinja"],
22
+ "scalar_gate_beta": ["linear-attention-gate.wgsl.jinja"],
23
+ "scalar_gate": ["linear-attention-gate.wgsl.jinja"]
24
+ }
25
+ }
26
  }
build/webgpu/test.json CHANGED
@@ -1,10 +1,9 @@
1
  {
2
- "op": "com.microsoft.LinearAttentionGate",
3
  "cases": [
4
  {
5
  "name": "rank3_h8_vec4_gate_beta",
6
  "provenance": {
7
- "notes": "The (B, T, H) shape the schema names, with a head count that is a multiple of four so the vectorized path runs. Covers vec4_gate_beta. Tolerance: the measured kernel-vs-reference max relative deviation over this op's fixtures is 4.4e-7, which is the f32 floor for softplus just above the log1p series crossover; 2e-6 keeps roughly four times that as device margin."
8
  },
9
  "inputs": {
10
  "aT": {
@@ -100,7 +99,7 @@
100
  {
101
  "name": "b_without_beta_is_ignored",
102
  "provenance": {
103
- "notes": "The public schema requires b only in the forward direction: requesting beta requires b. ORT CPU and WebGPU accept b when beta is omitted and do not read it; this fixture prevents the manifest from imposing the stronger, non-schema b-implies-beta rule."
104
  },
105
  "inputs": {
106
  "aT": {
@@ -125,7 +124,7 @@
125
  {
126
  "name": "rank2_h4_vec4_pinned_head_parameters",
127
  "provenance": {
128
- "notes": "Hand-computed, anchoring the op off its own reference. Row 0 is built so a + dt_bias == 0 in every head, making softplus exactly ln(2) = 0.69314718, so each head's decay is its decay_scale times that one constant -- a wrong head-to-parameter mapping cannot reproduce the column pattern. Row 1 biases to 25 in every head, above the x > 20 softplus threshold where softplus(x) == x exactly, so those four values are exact. beta pins both sigmoid branches (x >= 0 and x < 0) at 0, +/-1, +/-2 and +/-6."
129
  },
130
  "inputs": {
131
  "aT": {
 
1
  {
 
2
  "cases": [
3
  {
4
  "name": "rank3_h8_vec4_gate_beta",
5
  "provenance": {
6
+ "notes": "The schema's (B,T,H) layout uses a head count divisible by four, exercising vectorized beta gating. A 2e-6 tolerance covers f32 Softplus rounding near the log1p series crossover."
7
  },
8
  "inputs": {
9
  "aT": {
 
99
  {
100
  "name": "b_without_beta_is_ignored",
101
  "provenance": {
102
+ "notes": "The schema requires `b` when beta is requested but permits `b` when beta is omitted. This case supplies unused `b` without beta."
103
  },
104
  "inputs": {
105
  "aT": {
 
124
  {
125
  "name": "rank2_h4_vec4_pinned_head_parameters",
126
  "provenance": {
127
+ "notes": "Expected values are derived directly from the gating equation. Row 0 sets `a + dt_bias` to zero in every head, so Softplus equals ln(2) and each decay differs only by `decay_scale`. Row 1 sets the value to 25, where the guarded Softplus branch returns x exactly. Beta inputs cover both sigmoid signs at 0, +/-1, +/-2, and +/-6."
128
  },
129
  "inputs": {
130
  "aT": {