Xenova HF Staff commited on
Commit
a5f52d3
·
verified ·
1 Parent(s): 1afe052

sync 91d990483a17

Browse files
README.md CHANGED
@@ -18,22 +18,22 @@ See the [ONNX Runtime `VarlenCausalConvWithState` contrib-operator spec](https:/
18
 
19
  ## Inputs
20
 
21
- | Name | Bind key | Logical dtype | WebGPU storage | Rank | Shape | Description | Presence |
22
  | --- | --- | --- | --- | --- | --- | --- | --- |
23
- | `input` | `inputT` | `T` | same as logical dtype | `2` | — | Token-major packed input with shape `(total_tokens, channels)`. | required |
24
- | `weight` | `weightT` | `T` | same as logical dtype | `3` | — | Depthwise kernel with shape `(channels, 1, kernel_size)`. | required |
25
- | `cumulative_sequence_length` | `cumulativeSequenceLengthT` | `M` | `int32` | `1` | — | Exclusive prefix sums with shape `(batch_size + 1)`; sequence `i` owns tokens `[cum[i], cum[i + 1])`. | required |
26
- | `bias` | `biasT` | `T` | same as logical dtype | `1` | — | Optional per-channel bias with shape `(channels,)`. In an ONNX graph an omitted bias must still occupy input index 3 as an empty name so `initial_state` stays at index 4. | optional |
27
- | `initial_state` | `initialStateT` | `T` | same as logical dtype | `3` | — | Required committed carry state with shape `(batch_size, channels, kernel_size - 1)`, holding the raw samples immediately preceding this call. | required |
28
- | `capture_count` | `captureCountT` | `M` | `int32` | `1` | — | Optional int32 vector with shape `(batch_size)`. Required exactly when `state_update_capacity` is positive; each value is clamped to `[0, min(state_update_capacity, sequence_length)]`. | optional |
29
 
30
  ## Outputs
31
 
32
- | Name | Bind key | Logical dtype | Rank | Shape | Description | Presence |
33
  | --- | --- | --- | --- | --- | --- | --- |
34
- | `output` | `outputT` | `T` | same as `input` | same as `input` | Convolution output with the same shape as `input`. | required |
35
- | `final_state` | `finalStateT` | `T` | `3` | derived; see description | State after each sequence's final token, shape `(batch_size, channels, kernel_size - 1)`. Always fully written. | required |
36
- | `state_update` | `stateUpdateT` | `T` | `3` | derived; see description | Optional compact transition values with shape `(batch_size, state_update_capacity, channels)`. Active slots contain the original local input tokens and all other slots are zero. | optional |
37
 
38
  ## Attributes
39
 
@@ -53,7 +53,7 @@ Default values (overridable per request):
53
 
54
  ## Files
55
 
56
- - [`metadata.json`](build/webgpu/metadata.json) — kernel metadata (id, digests, provenance)
57
  - [`manifest.json`](build/webgpu/manifest.json) — the op contract (source of truth)
58
  - [`test.json`](build/webgpu/test.json) — correctness cases
59
  - [`bench.json`](build/webgpu/bench.json) — benchmark + tuning cases
@@ -63,10 +63,14 @@ Default values (overridable per request):
63
 
64
  ## Use with `@huggingface/kernels`
65
 
66
- The loader derives every required output's shape and logical dtype from the manifest contract and this call.
67
- It then allocates the result tensors automatically.
 
 
 
68
 
69
  The `version: 1` option selects the published kernel contract; it is independent of any operator opset, contrib `since_version`, or model version.
 
70
 
71
  Replace each `*Data` placeholder with a typed array containing the corresponding input data.
72
 
 
18
 
19
  ## Inputs
20
 
21
+ | Name | Upstream name | Logical dtype | WebGPU storage | Rank | Shape | Description | Presence |
22
  | --- | --- | --- | --- | --- | --- | --- | --- |
23
+ | `inputT` | `input` | `T` | same as logical dtype | `2` | — | Token-major packed input with shape `(total_tokens, channels)`. | required |
24
+ | `weightT` | `weight` | `T` | same as logical dtype | `3` | — | Depthwise kernel with shape `(channels, 1, kernel_size)`. | required |
25
+ | `cumulativeSequenceLengthT` | `cumulative_sequence_length` | `M` | `int32` | `1` | — | Exclusive prefix sums with shape `(batch_size + 1)`, starting at 0, ending at `total_tokens`, and strictly increasing so every sequence is non-empty. Sequence `i` owns tokens `[cum[i], cum[i + 1])`. Outputs are unspecified for a malformed schedule. | required |
26
+ | `biasT` | `bias` | `T` | same as logical dtype | `1` | — | Optional per-channel bias with shape `(channels,)`. In an ONNX graph an omitted bias must still occupy input index 3 as an empty name so `initial_state` stays at index 4. | optional |
27
+ | `initialStateT` | `initial_state` | `T` | same as logical dtype | `3` | — | Required committed carry state with shape `(batch_size, channels, kernel_size - 1)`, holding the raw samples immediately preceding this call. | required |
28
+ | `captureCountT` | `capture_count` | `M` | `int32` | `1` | — | Optional int32 vector with shape `(batch_size)`. Required exactly when `state_update_capacity` is positive; each value is clamped to `[0, min(state_update_capacity, sequence_length)]`. | optional |
29
 
30
  ## Outputs
31
 
32
+ | Name | Upstream name | Logical dtype | Rank | Shape | Description | Presence |
33
  | --- | --- | --- | --- | --- | --- | --- |
34
+ | `outputT` | `output` | `T` | same as `inputT` | same as `inputT` | Convolution output with the same shape as `input`. | required |
35
+ | `finalStateT` | `final_state` | `T` | `3` | derived | State after each sequence's final token, shape `(batch_size, channels, kernel_size - 1)`. Always fully written. | required |
36
+ | `stateUpdateT` | `state_update` | `T` | `3` | derived | Optional compact transition values with shape `(batch_size, state_update_capacity, channels)`. Active slots contain the original local input tokens and all other slots are zero. | optional |
37
 
38
  ## Attributes
39
 
 
53
 
54
  ## Files
55
 
56
+ - [`metadata.json`](build/webgpu/metadata.json) — kernel metadata (id, digests, per-variant templates, provenance)
57
  - [`manifest.json`](build/webgpu/manifest.json) — the op contract (source of truth)
58
  - [`test.json`](build/webgpu/test.json) — correctness cases
59
  - [`bench.json`](build/webgpu/bench.json) — benchmark + tuning cases
 
63
 
64
  ## Use with `@huggingface/kernels`
65
 
66
+ ```sh
67
+ npm install --save-exact @huggingface/kernels@0.0.1-preview.2
68
+ ```
69
+
70
+ Required output shapes and logical data types are inferred from the supplied inputs and attributes; result tensors are allocated automatically.
71
 
72
  The `version: 1` option selects the published kernel contract; it is independent of any operator opset, contrib `since_version`, or model version.
73
+ It follows the `v1` branch as fixes land. To pin exact artifact bytes, pass a 40-character commit `revision` instead of `version`.
74
 
75
  Replace each `*Data` placeholder with a typed array containing the corresponding input data.
76
 
build/webgpu/bench.json CHANGED
@@ -1,5 +1,4 @@
1
  {
2
- "op": "com.microsoft.VarlenCausalConvWithState",
3
  "tunableSpace": {
4
  "workgroupSize": [64, 128, 256],
5
  "streamWorkgroupSize": [64, 128, 256],
 
1
  {
 
2
  "tunableSpace": {
3
  "workgroupSize": [64, 128, 256],
4
  "streamWorkgroupSize": [64, 128, 256],
build/webgpu/manifest.json CHANGED
@@ -2,101 +2,33 @@
2
  "domain": "com.microsoft",
3
  "name": "VarlenCausalConvWithState",
4
  "sinceVersion": 1,
5
- "description": "Stateful causal depthwise convolution over packed token-major variable-length sequences, without reads across sequence boundaries. `initial_state` carries preceding raw samples and `final_state` is fully written. At positive `state_update_capacity`, `capture_count` selects a clamped prefix of raw input tokens for compact `state_update`; inactive slots are zero. SiLU and Swish are aliases. This implementation supports float16 and float32 with float32 accumulation; bfloat16 is not implemented.",
6
- "inputs": [
7
- {
8
- "role": "input",
9
- "dtype": "T",
10
- "rank": 2,
11
- "description": "Token-major packed input with shape `(total_tokens, channels)`."
12
- },
13
- {
14
- "role": "weight",
15
- "dtype": "T",
16
- "rank": 3,
17
- "description": "Depthwise kernel with shape `(channels, 1, kernel_size)`."
18
- },
19
- {
20
- "role": "cumulative_sequence_length",
21
- "dtype": "M",
22
- "rank": 1,
23
- "description": "Exclusive prefix sums with shape `(batch_size + 1)`; sequence `i` owns tokens `[cum[i], cum[i + 1])`."
24
- },
25
- {
26
- "role": "bias",
27
- "dtype": "T",
28
- "rank": 1,
29
- "optional": true,
30
- "description": "Optional per-channel bias with shape `(channels,)`. In an ONNX graph an omitted bias must still occupy input index 3 as an empty name so `initial_state` stays at index 4."
31
- },
32
- {
33
- "role": "initial_state",
34
- "dtype": "T",
35
- "rank": 3,
36
- "description": "Required committed carry state with shape `(batch_size, channels, kernel_size - 1)`, holding the raw samples immediately preceding this call."
37
- },
38
- {
39
- "role": "capture_count",
40
- "dtype": "M",
41
- "rank": 1,
42
- "optional": true,
43
- "description": "Optional int32 vector with shape `(batch_size)`. Required exactly when `state_update_capacity` is positive; each value is clamped to `[0, min(state_update_capacity, sequence_length)]`."
44
- }
45
- ],
46
- "outputs": [
47
- {
48
- "role": "output",
49
- "dtype": "T",
50
- "rank": "ranks.inputT",
51
- "shape": "shapes.inputT",
52
- "description": "Convolution output with the same shape as `input`."
53
- },
54
- {
55
- "role": "final_state",
56
- "dtype": "T",
57
- "rank": 3,
58
- "shape": "[batchSize, channels, stateLength]",
59
- "description": "State after each sequence's final token, shape `(batch_size, channels, kernel_size - 1)`. Always fully written."
60
- },
61
- {
62
- "role": "state_update",
63
  "dtype": "T",
64
  "rank": 3,
65
  "optional": true,
66
- "shape": "[batchSize, stateUpdateCapacity, channels]",
67
- "description": "Optional compact transition values with shape `(batch_size, state_update_capacity, channels)`. Active slots contain the original local input tokens and all other slots are zero."
68
  }
69
- ],
70
- "typeConstraints": { "T": ["float32", "float16"], "M": ["int32"] },
71
- "attributes": { "activation": "none", "state_update_capacity": 0 },
72
- "attributeDescriptions": {
73
- "activation": "Fused activation applied after convolution and bias. One of `none`, `silu`, or `swish`; the standard default is `none`.",
74
- "state_update_capacity": "Static number of compact per-request prefix transition values to expose, in `[0, 8]`. The standard default is 0."
75
  },
 
76
  "attributeConstraints": { "activation": { "values": ["none", "silu", "swish"] } },
77
- "args": {
78
- "inputT": { "kind": "tensor", "semantic": "input", "role": "input" },
79
- "weightT": { "kind": "tensor", "semantic": "weight", "role": "input" },
80
- "cumulativeSequenceLengthT": {
81
- "kind": "tensor",
82
- "semantic": "cumulative_sequence_length",
83
- "role": "input",
84
- "dtype": "int32"
85
- },
86
- "biasT": { "kind": "tensor", "semantic": "bias", "role": "input", "required": false },
87
- "initialStateT": { "kind": "tensor", "semantic": "initial_state", "role": "input" },
88
- "captureCountT": {
89
- "kind": "tensor",
90
- "semantic": "capture_count",
91
- "role": "input",
92
- "dtype": "int32",
93
- "required": false
94
- },
95
- "outputT": { "kind": "tensor", "semantic": "output", "role": "output" },
96
- "finalStateT": { "kind": "tensor", "semantic": "final_state", "role": "output" },
97
- "stateUpdateT": { "kind": "tensor", "semantic": "state_update", "role": "output", "required": false }
98
  },
99
- "tunables": { "workgroupSize": 256, "streamWorkgroupSize": 64, "streamChunk": 16 },
100
  "derive": {
101
  "totalTokens": "dim(shapes.inputT, 0)",
102
  "channels": "dim(shapes.inputT, 1)",
@@ -117,188 +49,51 @@
117
  "stateUpdateContract": "commonContract and not present.biasT and present.stateUpdateT and stateUpdateCapacity > 0",
118
  "biasStateUpdateContract": "commonContract and present.biasT and biasOk and present.stateUpdateT and stateUpdateCapacity > 0"
119
  },
120
- "bindingSets": {
121
- "plain": [
122
- {
123
- "name": "input",
124
- "arg": "inputT",
125
- "semantic": "input",
126
- "buffer": { "type": "read-only-storage" },
127
- "elementType": "$inputScalar"
128
- },
129
- {
130
- "name": "weight",
131
- "arg": "weightT",
132
- "semantic": "weight",
133
- "buffer": { "type": "read-only-storage" },
134
- "elementType": "$inputScalar"
135
- },
136
- {
137
- "name": "cumulative_sequence_length",
138
- "arg": "cumulativeSequenceLengthT",
139
- "semantic": "cumulative_sequence_length",
140
- "buffer": { "type": "read-only-storage" },
141
- "elementType": "i32"
142
- },
143
- {
144
- "name": "initial_state",
145
- "arg": "initialStateT",
146
- "semantic": "initial_state",
147
- "buffer": { "type": "read-only-storage" },
148
- "elementType": "$inputScalar"
149
- },
150
- {
151
- "name": "output",
152
- "arg": "outputT",
153
- "semantic": "output",
154
- "buffer": { "type": "storage" },
155
- "elementType": "$outputScalar"
156
- },
157
- {
158
- "name": "final_state",
159
- "arg": "finalStateT",
160
- "semantic": "final_state",
161
- "buffer": { "type": "storage" },
162
- "elementType": "$outputScalar"
163
- },
164
- {
165
- "name": "params",
166
- "semantic": "kernel.params",
167
- "buffer": { "type": "uniform" },
168
- "struct": {
169
- "name": "Params",
170
- "fields": [
171
- { "name": "batchSize", "type": "u32", "value": "batchSize" },
172
- { "name": "channels", "type": "u32", "value": "channels" },
173
- { "name": "totalTokens", "type": "u32", "value": "totalTokens" },
174
- { "name": "kernelSize", "type": "u32", "value": "kernelSize" }
175
- ]
176
- }
177
- }
178
- ],
179
- "bias": [
180
- {
181
- "name": "input",
182
- "arg": "inputT",
183
- "semantic": "input",
184
- "buffer": { "type": "read-only-storage" },
185
- "elementType": "$inputScalar"
186
- },
187
- {
188
- "name": "weight",
189
- "arg": "weightT",
190
- "semantic": "weight",
191
- "buffer": { "type": "read-only-storage" },
192
- "elementType": "$inputScalar"
193
- },
194
- {
195
- "name": "cumulative_sequence_length",
196
- "arg": "cumulativeSequenceLengthT",
197
- "semantic": "cumulative_sequence_length",
198
- "buffer": { "type": "read-only-storage" },
199
- "elementType": "i32"
200
- },
201
- {
202
- "name": "initial_state",
203
- "arg": "initialStateT",
204
- "semantic": "initial_state",
205
- "buffer": { "type": "read-only-storage" },
206
- "elementType": "$inputScalar"
207
- },
208
- {
209
- "name": "bias",
210
- "arg": "biasT",
211
- "semantic": "bias",
212
- "buffer": { "type": "read-only-storage" },
213
- "elementType": "$inputScalar"
214
- },
215
- {
216
- "name": "output",
217
- "arg": "outputT",
218
- "semantic": "output",
219
- "buffer": { "type": "storage" },
220
- "elementType": "$outputScalar"
221
- },
222
- {
223
- "name": "final_state",
224
- "arg": "finalStateT",
225
- "semantic": "final_state",
226
- "buffer": { "type": "storage" },
227
- "elementType": "$outputScalar"
228
- },
229
- {
230
- "name": "params",
231
- "semantic": "kernel.params",
232
- "buffer": { "type": "uniform" },
233
- "struct": {
234
- "name": "Params",
235
- "fields": [
236
- { "name": "batchSize", "type": "u32", "value": "batchSize" },
237
- { "name": "channels", "type": "u32", "value": "channels" },
238
- { "name": "totalTokens", "type": "u32", "value": "totalTokens" },
239
- { "name": "kernelSize", "type": "u32", "value": "kernelSize" }
240
- ]
241
- }
242
- }
243
- ],
244
- "state_update": [
245
- {
246
- "name": "input",
247
- "arg": "inputT",
248
- "semantic": "input",
249
- "buffer": { "type": "read-only-storage" },
250
- "elementType": "$inputScalar"
251
- },
252
- {
253
- "name": "cumulative_sequence_length",
254
- "arg": "cumulativeSequenceLengthT",
255
- "semantic": "cumulative_sequence_length",
256
- "buffer": { "type": "read-only-storage" },
257
- "elementType": "i32"
258
- },
259
- {
260
- "name": "capture_count",
261
- "arg": "captureCountT",
262
- "semantic": "capture_count",
263
- "buffer": { "type": "read-only-storage" },
264
- "elementType": "i32"
265
- },
266
- {
267
- "name": "state_update",
268
- "arg": "stateUpdateT",
269
- "semantic": "state_update",
270
- "buffer": { "type": "storage" },
271
- "elementType": "$outputScalar"
272
- },
273
- {
274
- "name": "params",
275
- "semantic": "kernel.state_update_params",
276
- "buffer": { "type": "uniform" },
277
- "struct": {
278
- "name": "Params",
279
- "fields": [
280
- { "name": "batchSize", "type": "u32", "value": "batchSize" },
281
- { "name": "channels", "type": "u32", "value": "channels" },
282
- { "name": "totalTokens", "type": "u32", "value": "totalTokens" },
283
- { "name": "stateUpdateCapacity", "type": "u32", "value": "stateUpdateCapacity" }
284
- ]
285
- }
286
- }
287
- ]
288
  },
289
  "variants": [
290
  {
291
  "id": "plain_stream",
292
  "priority": 20,
293
  "when": ["plainContract", "kernelSize >= 2", "kernelSize <= 8", "tunables.streamChunk >= 1", "floor(tunables.streamChunk) == tunables.streamChunk", "tunables.streamWorkgroupSize >= 1", "floor(tunables.streamWorkgroupSize) == tunables.streamWorkgroupSize", "tunables.streamWorkgroupSize <= device.limits.maxComputeInvocationsPerWorkgroup", "tunables.streamWorkgroupSize <= device.limits.maxComputeWorkgroupSizeX"],
294
- "constants": {
295
  "hasBias": false,
296
  "useSilu": "attrs.activation != \"none\"",
297
  "inputScalar": "dtypes.T",
298
  "outputScalar": "dtypes.T",
299
- "usesF16": "tensorDtypes.inputT == \"float16\"",
300
  "workgroupSize": "tunables.streamWorkgroupSize",
301
- "kernelSize": "kernelSize",
302
  "chunkSize": "min(tunables.streamChunk, ceilDiv(totalTokens, batchSize))"
303
  },
304
  "passes": [
@@ -306,10 +101,11 @@
306
  "id": "main",
307
  "name": "VarlenCausalConvWithState.Stream",
308
  "shader": "varlen-causal-conv-stream.wgsl.jinja",
309
- "bindings": "plain",
310
  "dispatch": {
311
- "threads": "ceilDiv(totalTokens, constants.chunkSize) * channels",
312
- "workgroupSize": "constants.workgroupSize"
 
313
  }
314
  }
315
  ]
@@ -318,14 +114,12 @@
318
  "id": "bias_stream",
319
  "priority": 20,
320
  "when": ["biasContract", "kernelSize >= 2", "kernelSize <= 8", "tunables.streamChunk >= 1", "floor(tunables.streamChunk) == tunables.streamChunk", "tunables.streamWorkgroupSize >= 1", "floor(tunables.streamWorkgroupSize) == tunables.streamWorkgroupSize", "tunables.streamWorkgroupSize <= device.limits.maxComputeInvocationsPerWorkgroup", "tunables.streamWorkgroupSize <= device.limits.maxComputeWorkgroupSizeX"],
321
- "constants": {
322
  "hasBias": true,
323
  "useSilu": "attrs.activation != \"none\"",
324
  "inputScalar": "dtypes.T",
325
  "outputScalar": "dtypes.T",
326
- "usesF16": "tensorDtypes.inputT == \"float16\"",
327
  "workgroupSize": "tunables.streamWorkgroupSize",
328
- "kernelSize": "kernelSize",
329
  "chunkSize": "min(tunables.streamChunk, ceilDiv(totalTokens, batchSize))"
330
  },
331
  "passes": [
@@ -333,10 +127,11 @@
333
  "id": "main",
334
  "name": "VarlenCausalConvWithState.Stream",
335
  "shader": "varlen-causal-conv-stream.wgsl.jinja",
336
- "bindings": "bias",
337
  "dispatch": {
338
- "threads": "ceilDiv(totalTokens, constants.chunkSize) * channels",
339
- "workgroupSize": "constants.workgroupSize"
 
340
  }
341
  }
342
  ]
@@ -345,14 +140,12 @@
345
  "id": "state_update_stream",
346
  "priority": 20,
347
  "when": ["stateUpdateContract", "kernelSize >= 2", "kernelSize <= 8", "tunables.streamChunk >= 1", "floor(tunables.streamChunk) == tunables.streamChunk", "tunables.streamWorkgroupSize >= 1", "floor(tunables.streamWorkgroupSize) == tunables.streamWorkgroupSize", "tunables.streamWorkgroupSize <= device.limits.maxComputeInvocationsPerWorkgroup", "tunables.streamWorkgroupSize <= device.limits.maxComputeWorkgroupSizeX"],
348
- "constants": {
349
  "hasBias": false,
350
  "useSilu": "attrs.activation != \"none\"",
351
  "inputScalar": "dtypes.T",
352
  "outputScalar": "dtypes.T",
353
- "usesF16": "tensorDtypes.inputT == \"float16\"",
354
  "workgroupSize": "tunables.streamWorkgroupSize",
355
- "kernelSize": "kernelSize",
356
  "chunkSize": "min(tunables.streamChunk, ceilDiv(totalTokens, batchSize))"
357
  },
358
  "passes": [
@@ -360,20 +153,22 @@
360
  "id": "state_update",
361
  "name": "VarlenCausalConvWithState.StateUpdate",
362
  "shader": "varlen-state-update.wgsl.jinja",
363
- "bindings": "state_update",
364
  "dispatch": {
365
- "threads": "batchSize * stateUpdateCapacity * channels",
366
- "workgroupSize": "constants.workgroupSize"
 
367
  }
368
  },
369
  {
370
  "id": "main",
371
  "name": "VarlenCausalConvWithState.Stream",
372
  "shader": "varlen-causal-conv-stream.wgsl.jinja",
373
- "bindings": "plain",
374
  "dispatch": {
375
- "threads": "ceilDiv(totalTokens, constants.chunkSize) * channels",
376
- "workgroupSize": "constants.workgroupSize"
 
377
  }
378
  }
379
  ]
@@ -382,14 +177,12 @@
382
  "id": "bias_state_update_stream",
383
  "priority": 20,
384
  "when": ["biasStateUpdateContract", "kernelSize >= 2", "kernelSize <= 8", "tunables.streamChunk >= 1", "floor(tunables.streamChunk) == tunables.streamChunk", "tunables.streamWorkgroupSize >= 1", "floor(tunables.streamWorkgroupSize) == tunables.streamWorkgroupSize", "tunables.streamWorkgroupSize <= device.limits.maxComputeInvocationsPerWorkgroup", "tunables.streamWorkgroupSize <= device.limits.maxComputeWorkgroupSizeX"],
385
- "constants": {
386
  "hasBias": true,
387
  "useSilu": "attrs.activation != \"none\"",
388
  "inputScalar": "dtypes.T",
389
  "outputScalar": "dtypes.T",
390
- "usesF16": "tensorDtypes.inputT == \"float16\"",
391
  "workgroupSize": "tunables.streamWorkgroupSize",
392
- "kernelSize": "kernelSize",
393
  "chunkSize": "min(tunables.streamChunk, ceilDiv(totalTokens, batchSize))"
394
  },
395
  "passes": [
@@ -397,20 +190,22 @@
397
  "id": "state_update",
398
  "name": "VarlenCausalConvWithState.StateUpdate",
399
  "shader": "varlen-state-update.wgsl.jinja",
400
- "bindings": "state_update",
401
  "dispatch": {
402
- "threads": "batchSize * stateUpdateCapacity * channels",
403
- "workgroupSize": "constants.workgroupSize"
 
404
  }
405
  },
406
  {
407
  "id": "main",
408
  "name": "VarlenCausalConvWithState.Stream",
409
  "shader": "varlen-causal-conv-stream.wgsl.jinja",
410
- "bindings": "bias",
411
  "dispatch": {
412
- "threads": "ceilDiv(totalTokens, constants.chunkSize) * channels",
413
- "workgroupSize": "constants.workgroupSize"
 
414
  }
415
  }
416
  ]
@@ -419,12 +214,11 @@
419
  "id": "plain",
420
  "priority": 0,
421
  "when": ["plainContract", "tunables.workgroupSize >= 1", "floor(tunables.workgroupSize) == tunables.workgroupSize", "tunables.workgroupSize <= device.limits.maxComputeInvocationsPerWorkgroup", "tunables.workgroupSize <= device.limits.maxComputeWorkgroupSizeX"],
422
- "constants": {
423
  "hasBias": false,
424
  "useSilu": "attrs.activation != \"none\"",
425
  "inputScalar": "dtypes.T",
426
  "outputScalar": "dtypes.T",
427
- "usesF16": "tensorDtypes.inputT == \"float16\"",
428
  "workgroupSize": "tunables.workgroupSize"
429
  },
430
  "passes": [
@@ -432,8 +226,12 @@
432
  "id": "main",
433
  "name": "VarlenCausalConvWithState",
434
  "shader": "varlen-causal-conv.wgsl.jinja",
435
- "bindings": "plain",
436
- "dispatch": { "threads": "totalTokens * channels", "workgroupSize": "constants.workgroupSize" }
 
 
 
 
437
  }
438
  ]
439
  },
@@ -441,12 +239,11 @@
441
  "id": "bias",
442
  "priority": 0,
443
  "when": ["biasContract", "tunables.workgroupSize >= 1", "floor(tunables.workgroupSize) == tunables.workgroupSize", "tunables.workgroupSize <= device.limits.maxComputeInvocationsPerWorkgroup", "tunables.workgroupSize <= device.limits.maxComputeWorkgroupSizeX"],
444
- "constants": {
445
  "hasBias": true,
446
  "useSilu": "attrs.activation != \"none\"",
447
  "inputScalar": "dtypes.T",
448
  "outputScalar": "dtypes.T",
449
- "usesF16": "tensorDtypes.inputT == \"float16\"",
450
  "workgroupSize": "tunables.workgroupSize"
451
  },
452
  "passes": [
@@ -454,8 +251,12 @@
454
  "id": "main",
455
  "name": "VarlenCausalConvWithState",
456
  "shader": "varlen-causal-conv.wgsl.jinja",
457
- "bindings": "bias",
458
- "dispatch": { "threads": "totalTokens * channels", "workgroupSize": "constants.workgroupSize" }
 
 
 
 
459
  }
460
  ]
461
  },
@@ -463,12 +264,11 @@
463
  "id": "state_update",
464
  "priority": 0,
465
  "when": ["stateUpdateContract", "tunables.workgroupSize >= 1", "floor(tunables.workgroupSize) == tunables.workgroupSize", "tunables.workgroupSize <= device.limits.maxComputeInvocationsPerWorkgroup", "tunables.workgroupSize <= device.limits.maxComputeWorkgroupSizeX"],
466
- "constants": {
467
  "hasBias": false,
468
  "useSilu": "attrs.activation != \"none\"",
469
  "inputScalar": "dtypes.T",
470
  "outputScalar": "dtypes.T",
471
- "usesF16": "tensorDtypes.inputT == \"float16\"",
472
  "workgroupSize": "tunables.workgroupSize"
473
  },
474
  "passes": [
@@ -476,18 +276,23 @@
476
  "id": "state_update",
477
  "name": "VarlenCausalConvWithState.StateUpdate",
478
  "shader": "varlen-state-update.wgsl.jinja",
479
- "bindings": "state_update",
480
  "dispatch": {
481
- "threads": "batchSize * stateUpdateCapacity * channels",
482
- "workgroupSize": "constants.workgroupSize"
 
483
  }
484
  },
485
  {
486
  "id": "main",
487
  "name": "VarlenCausalConvWithState",
488
  "shader": "varlen-causal-conv.wgsl.jinja",
489
- "bindings": "plain",
490
- "dispatch": { "threads": "totalTokens * channels", "workgroupSize": "constants.workgroupSize" }
 
 
 
 
491
  }
492
  ]
493
  },
@@ -495,12 +300,11 @@
495
  "id": "bias_state_update",
496
  "priority": 0,
497
  "when": ["biasStateUpdateContract", "tunables.workgroupSize >= 1", "floor(tunables.workgroupSize) == tunables.workgroupSize", "tunables.workgroupSize <= device.limits.maxComputeInvocationsPerWorkgroup", "tunables.workgroupSize <= device.limits.maxComputeWorkgroupSizeX"],
498
- "constants": {
499
  "hasBias": true,
500
  "useSilu": "attrs.activation != \"none\"",
501
  "inputScalar": "dtypes.T",
502
  "outputScalar": "dtypes.T",
503
- "usesF16": "tensorDtypes.inputT == \"float16\"",
504
  "workgroupSize": "tunables.workgroupSize"
505
  },
506
  "passes": [
@@ -508,18 +312,23 @@
508
  "id": "state_update",
509
  "name": "VarlenCausalConvWithState.StateUpdate",
510
  "shader": "varlen-state-update.wgsl.jinja",
511
- "bindings": "state_update",
512
  "dispatch": {
513
- "threads": "batchSize * stateUpdateCapacity * channels",
514
- "workgroupSize": "constants.workgroupSize"
 
515
  }
516
  },
517
  {
518
  "id": "main",
519
  "name": "VarlenCausalConvWithState",
520
  "shader": "varlen-causal-conv.wgsl.jinja",
521
- "bindings": "bias",
522
- "dispatch": { "threads": "totalTokens * channels", "workgroupSize": "constants.workgroupSize" }
 
 
 
 
523
  }
524
  ]
525
  }
 
2
  "domain": "com.microsoft",
3
  "name": "VarlenCausalConvWithState",
4
  "sinceVersion": 1,
5
+ "inputs": {
6
+ "inputT": { "onnx": "input", "dtype": "T", "rank": 2 },
7
+ "weightT": { "onnx": "weight", "dtype": "T", "rank": 3 },
8
+ "cumulativeSequenceLengthT": { "onnx": "cumulative_sequence_length", "dtype": "M", "rank": 1, "storage": "int32" },
9
+ "biasT": { "onnx": "bias", "dtype": "T", "rank": 1, "optional": true },
10
+ "initialStateT": { "onnx": "initial_state", "dtype": "T", "rank": 3 },
11
+ "captureCountT": { "onnx": "capture_count", "dtype": "M", "rank": 1, "optional": true, "storage": "int32" }
12
+ },
13
+ "outputs": {
14
+ "outputT": { "onnx": "output", "dtype": "T", "rank": "ranks.inputT", "shape": "shapes.inputT" },
15
+ "finalStateT": { "onnx": "final_state", "dtype": "T", "rank": 3, "shape": "[batchSize, channels, stateLength]" },
16
+ "stateUpdateT": {
17
+ "onnx": "state_update",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  "dtype": "T",
19
  "rank": 3,
20
  "optional": true,
21
+ "shape": "[batchSize, stateUpdateCapacity, channels]"
 
22
  }
 
 
 
 
 
 
23
  },
24
+ "attributes": { "activation": { "default": "none" }, "state_update_capacity": { "default": 0 } },
25
  "attributeConstraints": { "activation": { "values": ["none", "silu", "swish"] } },
26
+ "typeConstraints": { "T": ["float32", "float16"], "M": ["int32"] },
27
+ "tunables": {
28
+ "workgroupSize": { "default": 256 },
29
+ "streamWorkgroupSize": { "default": 64 },
30
+ "streamChunk": { "default": 16 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  },
 
32
  "derive": {
33
  "totalTokens": "dim(shapes.inputT, 0)",
34
  "channels": "dim(shapes.inputT, 1)",
 
49
  "stateUpdateContract": "commonContract and not present.biasT and present.stateUpdateT and stateUpdateCapacity > 0",
50
  "biasStateUpdateContract": "commonContract and present.biasT and biasOk and present.stateUpdateT and stateUpdateCapacity > 0"
51
  },
52
+ "bindings": {
53
+ "input": { "arg": "inputT", "buffer": "read-only-storage", "elementType": "$inputScalar" },
54
+ "weight": { "arg": "weightT", "buffer": "read-only-storage", "elementType": "$inputScalar" },
55
+ "cumulative_sequence_length": {
56
+ "arg": "cumulativeSequenceLengthT",
57
+ "buffer": "read-only-storage",
58
+ "elementType": "i32"
59
+ },
60
+ "initial_state": { "arg": "initialStateT", "buffer": "read-only-storage", "elementType": "$inputScalar" },
61
+ "output": { "arg": "outputT", "buffer": "storage", "elementType": "$outputScalar" },
62
+ "final_state": { "arg": "finalStateT", "buffer": "storage", "elementType": "$outputScalar" },
63
+ "params": {
64
+ "buffer": "uniform",
65
+ "struct": [
66
+ { "name": "batchSize", "type": "u32", "value": "batchSize" },
67
+ { "name": "channels", "type": "u32", "value": "channels" },
68
+ { "name": "totalTokens", "type": "u32", "value": "totalTokens" },
69
+ { "name": "kernelSize", "type": "u32", "value": "kernelSize" }
70
+ ]
71
+ },
72
+ "bias": { "arg": "biasT", "buffer": "read-only-storage", "elementType": "$inputScalar" },
73
+ "capture_count": { "arg": "captureCountT", "buffer": "read-only-storage", "elementType": "i32" },
74
+ "state_update": { "arg": "stateUpdateT", "buffer": "storage", "elementType": "$outputScalar" },
75
+ "params_2": {
76
+ "name": "params",
77
+ "buffer": "uniform",
78
+ "struct": [
79
+ { "name": "batchSize", "type": "u32", "value": "batchSize" },
80
+ { "name": "channels", "type": "u32", "value": "channels" },
81
+ { "name": "totalTokens", "type": "u32", "value": "totalTokens" },
82
+ { "name": "stateUpdateCapacity", "type": "u32", "value": "stateUpdateCapacity" }
83
+ ]
84
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
  },
86
  "variants": [
87
  {
88
  "id": "plain_stream",
89
  "priority": 20,
90
  "when": ["plainContract", "kernelSize >= 2", "kernelSize <= 8", "tunables.streamChunk >= 1", "floor(tunables.streamChunk) == tunables.streamChunk", "tunables.streamWorkgroupSize >= 1", "floor(tunables.streamWorkgroupSize) == tunables.streamWorkgroupSize", "tunables.streamWorkgroupSize <= device.limits.maxComputeInvocationsPerWorkgroup", "tunables.streamWorkgroupSize <= device.limits.maxComputeWorkgroupSizeX"],
91
+ "derive": {
92
  "hasBias": false,
93
  "useSilu": "attrs.activation != \"none\"",
94
  "inputScalar": "dtypes.T",
95
  "outputScalar": "dtypes.T",
 
96
  "workgroupSize": "tunables.streamWorkgroupSize",
 
97
  "chunkSize": "min(tunables.streamChunk, ceilDiv(totalTokens, batchSize))"
98
  },
99
  "passes": [
 
101
  "id": "main",
102
  "name": "VarlenCausalConvWithState.Stream",
103
  "shader": "varlen-causal-conv-stream.wgsl.jinja",
104
+ "bindings": ["input", "weight", "cumulative_sequence_length", "initial_state", "output", "final_state", "params"],
105
  "dispatch": {
106
+ "x": "min(ceilDiv((ceilDiv(totalTokens, chunkSize) * channels), (workgroupSize)), 65535)",
107
+ "y": "ceilDiv(ceilDiv((ceilDiv(totalTokens, chunkSize) * channels), (workgroupSize)), 65535)",
108
+ "z": 1
109
  }
110
  }
111
  ]
 
114
  "id": "bias_stream",
115
  "priority": 20,
116
  "when": ["biasContract", "kernelSize >= 2", "kernelSize <= 8", "tunables.streamChunk >= 1", "floor(tunables.streamChunk) == tunables.streamChunk", "tunables.streamWorkgroupSize >= 1", "floor(tunables.streamWorkgroupSize) == tunables.streamWorkgroupSize", "tunables.streamWorkgroupSize <= device.limits.maxComputeInvocationsPerWorkgroup", "tunables.streamWorkgroupSize <= device.limits.maxComputeWorkgroupSizeX"],
117
+ "derive": {
118
  "hasBias": true,
119
  "useSilu": "attrs.activation != \"none\"",
120
  "inputScalar": "dtypes.T",
121
  "outputScalar": "dtypes.T",
 
122
  "workgroupSize": "tunables.streamWorkgroupSize",
 
123
  "chunkSize": "min(tunables.streamChunk, ceilDiv(totalTokens, batchSize))"
124
  },
125
  "passes": [
 
127
  "id": "main",
128
  "name": "VarlenCausalConvWithState.Stream",
129
  "shader": "varlen-causal-conv-stream.wgsl.jinja",
130
+ "bindings": ["input", "weight", "cumulative_sequence_length", "initial_state", "bias", "output", "final_state", "params"],
131
  "dispatch": {
132
+ "x": "min(ceilDiv((ceilDiv(totalTokens, chunkSize) * channels), (workgroupSize)), 65535)",
133
+ "y": "ceilDiv(ceilDiv((ceilDiv(totalTokens, chunkSize) * channels), (workgroupSize)), 65535)",
134
+ "z": 1
135
  }
136
  }
137
  ]
 
140
  "id": "state_update_stream",
141
  "priority": 20,
142
  "when": ["stateUpdateContract", "kernelSize >= 2", "kernelSize <= 8", "tunables.streamChunk >= 1", "floor(tunables.streamChunk) == tunables.streamChunk", "tunables.streamWorkgroupSize >= 1", "floor(tunables.streamWorkgroupSize) == tunables.streamWorkgroupSize", "tunables.streamWorkgroupSize <= device.limits.maxComputeInvocationsPerWorkgroup", "tunables.streamWorkgroupSize <= device.limits.maxComputeWorkgroupSizeX"],
143
+ "derive": {
144
  "hasBias": false,
145
  "useSilu": "attrs.activation != \"none\"",
146
  "inputScalar": "dtypes.T",
147
  "outputScalar": "dtypes.T",
 
148
  "workgroupSize": "tunables.streamWorkgroupSize",
 
149
  "chunkSize": "min(tunables.streamChunk, ceilDiv(totalTokens, batchSize))"
150
  },
151
  "passes": [
 
153
  "id": "state_update",
154
  "name": "VarlenCausalConvWithState.StateUpdate",
155
  "shader": "varlen-state-update.wgsl.jinja",
156
+ "bindings": ["input", "cumulative_sequence_length", "capture_count", "state_update", "params_2"],
157
  "dispatch": {
158
+ "x": "min(ceilDiv((batchSize * stateUpdateCapacity * channels), (workgroupSize)), 65535)",
159
+ "y": "ceilDiv(ceilDiv((batchSize * stateUpdateCapacity * channels), (workgroupSize)), 65535)",
160
+ "z": 1
161
  }
162
  },
163
  {
164
  "id": "main",
165
  "name": "VarlenCausalConvWithState.Stream",
166
  "shader": "varlen-causal-conv-stream.wgsl.jinja",
167
+ "bindings": ["input", "weight", "cumulative_sequence_length", "initial_state", "output", "final_state", "params"],
168
  "dispatch": {
169
+ "x": "min(ceilDiv((ceilDiv(totalTokens, chunkSize) * channels), (workgroupSize)), 65535)",
170
+ "y": "ceilDiv(ceilDiv((ceilDiv(totalTokens, chunkSize) * channels), (workgroupSize)), 65535)",
171
+ "z": 1
172
  }
173
  }
174
  ]
 
177
  "id": "bias_state_update_stream",
178
  "priority": 20,
179
  "when": ["biasStateUpdateContract", "kernelSize >= 2", "kernelSize <= 8", "tunables.streamChunk >= 1", "floor(tunables.streamChunk) == tunables.streamChunk", "tunables.streamWorkgroupSize >= 1", "floor(tunables.streamWorkgroupSize) == tunables.streamWorkgroupSize", "tunables.streamWorkgroupSize <= device.limits.maxComputeInvocationsPerWorkgroup", "tunables.streamWorkgroupSize <= device.limits.maxComputeWorkgroupSizeX"],
180
+ "derive": {
181
  "hasBias": true,
182
  "useSilu": "attrs.activation != \"none\"",
183
  "inputScalar": "dtypes.T",
184
  "outputScalar": "dtypes.T",
 
185
  "workgroupSize": "tunables.streamWorkgroupSize",
 
186
  "chunkSize": "min(tunables.streamChunk, ceilDiv(totalTokens, batchSize))"
187
  },
188
  "passes": [
 
190
  "id": "state_update",
191
  "name": "VarlenCausalConvWithState.StateUpdate",
192
  "shader": "varlen-state-update.wgsl.jinja",
193
+ "bindings": ["input", "cumulative_sequence_length", "capture_count", "state_update", "params_2"],
194
  "dispatch": {
195
+ "x": "min(ceilDiv((batchSize * stateUpdateCapacity * channels), (workgroupSize)), 65535)",
196
+ "y": "ceilDiv(ceilDiv((batchSize * stateUpdateCapacity * channels), (workgroupSize)), 65535)",
197
+ "z": 1
198
  }
199
  },
200
  {
201
  "id": "main",
202
  "name": "VarlenCausalConvWithState.Stream",
203
  "shader": "varlen-causal-conv-stream.wgsl.jinja",
204
+ "bindings": ["input", "weight", "cumulative_sequence_length", "initial_state", "bias", "output", "final_state", "params"],
205
  "dispatch": {
206
+ "x": "min(ceilDiv((ceilDiv(totalTokens, chunkSize) * channels), (workgroupSize)), 65535)",
207
+ "y": "ceilDiv(ceilDiv((ceilDiv(totalTokens, chunkSize) * channels), (workgroupSize)), 65535)",
208
+ "z": 1
209
  }
210
  }
211
  ]
 
214
  "id": "plain",
215
  "priority": 0,
216
  "when": ["plainContract", "tunables.workgroupSize >= 1", "floor(tunables.workgroupSize) == tunables.workgroupSize", "tunables.workgroupSize <= device.limits.maxComputeInvocationsPerWorkgroup", "tunables.workgroupSize <= device.limits.maxComputeWorkgroupSizeX"],
217
+ "derive": {
218
  "hasBias": false,
219
  "useSilu": "attrs.activation != \"none\"",
220
  "inputScalar": "dtypes.T",
221
  "outputScalar": "dtypes.T",
 
222
  "workgroupSize": "tunables.workgroupSize"
223
  },
224
  "passes": [
 
226
  "id": "main",
227
  "name": "VarlenCausalConvWithState",
228
  "shader": "varlen-causal-conv.wgsl.jinja",
229
+ "bindings": ["input", "weight", "cumulative_sequence_length", "initial_state", "output", "final_state", "params"],
230
+ "dispatch": {
231
+ "x": "min(ceilDiv((totalTokens * channels), (workgroupSize)), 65535)",
232
+ "y": "ceilDiv(ceilDiv((totalTokens * channels), (workgroupSize)), 65535)",
233
+ "z": 1
234
+ }
235
  }
236
  ]
237
  },
 
239
  "id": "bias",
240
  "priority": 0,
241
  "when": ["biasContract", "tunables.workgroupSize >= 1", "floor(tunables.workgroupSize) == tunables.workgroupSize", "tunables.workgroupSize <= device.limits.maxComputeInvocationsPerWorkgroup", "tunables.workgroupSize <= device.limits.maxComputeWorkgroupSizeX"],
242
+ "derive": {
243
  "hasBias": true,
244
  "useSilu": "attrs.activation != \"none\"",
245
  "inputScalar": "dtypes.T",
246
  "outputScalar": "dtypes.T",
 
247
  "workgroupSize": "tunables.workgroupSize"
248
  },
249
  "passes": [
 
251
  "id": "main",
252
  "name": "VarlenCausalConvWithState",
253
  "shader": "varlen-causal-conv.wgsl.jinja",
254
+ "bindings": ["input", "weight", "cumulative_sequence_length", "initial_state", "bias", "output", "final_state", "params"],
255
+ "dispatch": {
256
+ "x": "min(ceilDiv((totalTokens * channels), (workgroupSize)), 65535)",
257
+ "y": "ceilDiv(ceilDiv((totalTokens * channels), (workgroupSize)), 65535)",
258
+ "z": 1
259
+ }
260
  }
261
  ]
262
  },
 
264
  "id": "state_update",
265
  "priority": 0,
266
  "when": ["stateUpdateContract", "tunables.workgroupSize >= 1", "floor(tunables.workgroupSize) == tunables.workgroupSize", "tunables.workgroupSize <= device.limits.maxComputeInvocationsPerWorkgroup", "tunables.workgroupSize <= device.limits.maxComputeWorkgroupSizeX"],
267
+ "derive": {
268
  "hasBias": false,
269
  "useSilu": "attrs.activation != \"none\"",
270
  "inputScalar": "dtypes.T",
271
  "outputScalar": "dtypes.T",
 
272
  "workgroupSize": "tunables.workgroupSize"
273
  },
274
  "passes": [
 
276
  "id": "state_update",
277
  "name": "VarlenCausalConvWithState.StateUpdate",
278
  "shader": "varlen-state-update.wgsl.jinja",
279
+ "bindings": ["input", "cumulative_sequence_length", "capture_count", "state_update", "params_2"],
280
  "dispatch": {
281
+ "x": "min(ceilDiv((batchSize * stateUpdateCapacity * channels), (workgroupSize)), 65535)",
282
+ "y": "ceilDiv(ceilDiv((batchSize * stateUpdateCapacity * channels), (workgroupSize)), 65535)",
283
+ "z": 1
284
  }
285
  },
286
  {
287
  "id": "main",
288
  "name": "VarlenCausalConvWithState",
289
  "shader": "varlen-causal-conv.wgsl.jinja",
290
+ "bindings": ["input", "weight", "cumulative_sequence_length", "initial_state", "output", "final_state", "params"],
291
+ "dispatch": {
292
+ "x": "min(ceilDiv((totalTokens * channels), (workgroupSize)), 65535)",
293
+ "y": "ceilDiv(ceilDiv((totalTokens * channels), (workgroupSize)), 65535)",
294
+ "z": 1
295
+ }
296
  }
297
  ]
298
  },
 
300
  "id": "bias_state_update",
301
  "priority": 0,
302
  "when": ["biasStateUpdateContract", "tunables.workgroupSize >= 1", "floor(tunables.workgroupSize) == tunables.workgroupSize", "tunables.workgroupSize <= device.limits.maxComputeInvocationsPerWorkgroup", "tunables.workgroupSize <= device.limits.maxComputeWorkgroupSizeX"],
303
+ "derive": {
304
  "hasBias": true,
305
  "useSilu": "attrs.activation != \"none\"",
306
  "inputScalar": "dtypes.T",
307
  "outputScalar": "dtypes.T",
 
308
  "workgroupSize": "tunables.workgroupSize"
309
  },
310
  "passes": [
 
312
  "id": "state_update",
313
  "name": "VarlenCausalConvWithState.StateUpdate",
314
  "shader": "varlen-state-update.wgsl.jinja",
315
+ "bindings": ["input", "cumulative_sequence_length", "capture_count", "state_update", "params_2"],
316
  "dispatch": {
317
+ "x": "min(ceilDiv((batchSize * stateUpdateCapacity * channels), (workgroupSize)), 65535)",
318
+ "y": "ceilDiv(ceilDiv((batchSize * stateUpdateCapacity * channels), (workgroupSize)), 65535)",
319
+ "z": 1
320
  }
321
  },
322
  {
323
  "id": "main",
324
  "name": "VarlenCausalConvWithState",
325
  "shader": "varlen-causal-conv.wgsl.jinja",
326
+ "bindings": ["input", "weight", "cumulative_sequence_length", "initial_state", "bias", "output", "final_state", "params"],
327
+ "dispatch": {
328
+ "x": "min(ceilDiv((totalTokens * channels), (workgroupSize)), 65535)",
329
+ "y": "ceilDiv(ceilDiv((totalTokens * channels), (workgroupSize)), 65535)",
330
+ "z": 1
331
+ }
332
  }
333
  ]
334
  }
build/webgpu/metadata.json CHANGED
@@ -1,20 +1,32 @@
1
  {
2
  "name": "com.microsoft.VarlenCausalConvWithState",
3
- "id": "_com_microsoft_varlencausalconvwithstate_webgpu_9c4b81e",
4
  "version": 1,
5
  "license": "Apache-2.0",
6
  "backend": { "type": "webgpu" },
7
  "digest": {
8
  "algorithm": "sha256",
9
  "files": {
10
- "bench.json": "z/PVF6DFL2GAEJzuVOeObMuyIEskbcAJRlEve4V0LNo=",
11
- "manifest.json": "nToIgIEAIC9CFMInjTS/RJQFVy0mUbtVqoNZeTxYLcU=",
12
- "test.json": "c7BMrgBYnFuFqXjL+U+ZbNZoDMfq9O/jhQRWxP8wdk4=",
13
- "varlen-causal-conv-stream.wgsl.jinja": "HFjAOPhuaBvGbATRz/a85lgoLzZJobT3aHhw6Ao0BBc=",
14
- "varlen-causal-conv.wgsl.jinja": "KURdzm1/gZYSl8q//HtKsQ2F8ymw3T4Uge/4kDDrQZI=",
15
- "varlen-state-update.wgsl.jinja": "SDAR9CKpClXi5LZR1G3z2QxBw6Fbbey6N3XuSuTeWvs="
16
  }
17
  },
18
- "provenance": { "kernel": { "sha": "2e7068faf55e7f43df740015f6d1ee49391a41c5", "dirty": false } },
19
- "webgpu": { "manifestSpec": "1.0", "specialized": true, "opPath": "ops/com.microsoft.VarlenCausalConvWithState" }
 
 
 
 
 
 
 
 
 
 
 
 
20
  }
 
1
  {
2
  "name": "com.microsoft.VarlenCausalConvWithState",
3
+ "id": "_com_microsoft_varlencausalconvwithstate_webgpu_7c6635e",
4
  "version": 1,
5
  "license": "Apache-2.0",
6
  "backend": { "type": "webgpu" },
7
  "digest": {
8
  "algorithm": "sha256",
9
  "files": {
10
+ "bench.json": "y4qlCvMEobqusx4BHjuqJFrTxWGJfwFiE3ck+AejJQw=",
11
+ "manifest.json": "lcISl3PiMOgRa2gUETuiKNwm2RcbERhUNsPKM4yAfbc=",
12
+ "test.json": "66AJhdzvoC4y/XYc3VfVW0rgbaNmqskI834QnP591ng=",
13
+ "varlen-causal-conv-stream.wgsl.jinja": "0FWRyGR35U5ZB7Fb4Q1MFQHx90PALdOSNk1JoyeQCdQ=",
14
+ "varlen-causal-conv.wgsl.jinja": "OhLAVTlZId7AFw0Hfp8DWRcNZsgoMZgxpWdKxGdp4Ks=",
15
+ "varlen-state-update.wgsl.jinja": "aTGir5h/LQkg5ami41pKaH4EG8ybaltnnM0oJSJ6Neg="
16
  }
17
  },
18
+ "provenance": { "kernel": { "sha": "91d990483a174128daf7673f3f37a7c890493ae1", "dirty": false } },
19
+ "webgpu": {
20
+ "manifestSpec": "2.0",
21
+ "variants": {
22
+ "plain_stream": ["varlen-causal-conv-stream.wgsl.jinja"],
23
+ "bias_stream": ["varlen-causal-conv-stream.wgsl.jinja"],
24
+ "state_update_stream": ["varlen-causal-conv-stream.wgsl.jinja", "varlen-state-update.wgsl.jinja"],
25
+ "bias_state_update_stream": ["varlen-causal-conv-stream.wgsl.jinja", "varlen-state-update.wgsl.jinja"],
26
+ "plain": ["varlen-causal-conv.wgsl.jinja"],
27
+ "bias": ["varlen-causal-conv.wgsl.jinja"],
28
+ "state_update": ["varlen-causal-conv.wgsl.jinja", "varlen-state-update.wgsl.jinja"],
29
+ "bias_state_update": ["varlen-causal-conv.wgsl.jinja", "varlen-state-update.wgsl.jinja"]
30
+ }
31
+ }
32
  }
build/webgpu/test.json CHANGED
@@ -1,5 +1,4 @@
1
  {
2
- "op": "com.microsoft.VarlenCausalConvWithState",
3
  "cases": [
4
  {
5
  "name": "k4_varlen_plain",
 
1
  {
 
2
  "cases": [
3
  {
4
  "name": "k4_varlen_plain",
build/webgpu/varlen-causal-conv-stream.wgsl.jinja CHANGED
@@ -30,9 +30,6 @@ fn activate(value: f32) -> f32 {
30
  }
31
  {%- endmacro %}
32
  {% set stateLength = kernelSize - 1 %}
33
- {% if usesF16 %}
34
- enable f16;
35
- {% endif %}
36
  {{ env.wgsl.resourceDeclarations }}
37
 
38
  // com.microsoft.VarlenCausalConvWithState, streaming pass.
@@ -51,11 +48,10 @@ const STATE_LENGTH: u32 = {{ stateLength }}u;
51
  {{ varlen_conv_helpers(useSilu) }}
52
 
53
  @compute @workgroup_size(WG, 1, 1)
54
- fn main(@builtin(global_invocation_id) gid: vec3<u32>,
55
- @builtin(num_workgroups) nwg: vec3<u32>) {
56
  // 2D-folded flat index: gid.y carries the high bits past the
57
- // maxComputeWorkgroupsPerDimension limit. Reduces to gid.x when nwg.y == 1.
58
- let index = gid.x + gid.y * nwg.x * WG;
59
  let blocks = (params.totalTokens + CHUNK - 1u) / CHUNK;
60
  if (index >= blocks * params.channels) {
61
  return;
 
30
  }
31
  {%- endmacro %}
32
  {% set stateLength = kernelSize - 1 %}
 
 
 
33
  {{ env.wgsl.resourceDeclarations }}
34
 
35
  // com.microsoft.VarlenCausalConvWithState, streaming pass.
 
48
  {{ varlen_conv_helpers(useSilu) }}
49
 
50
  @compute @workgroup_size(WG, 1, 1)
51
+ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
 
52
  // 2D-folded flat index: gid.y carries the high bits past the
53
+ // per-axis dispatch fold width. Reduces to gid.x when the dispatch does not fold.
54
+ let index = gid.x + gid.y * {{ DISPATCH_FOLD_WIDTH }}u * WG;
55
  let blocks = (params.totalTokens + CHUNK - 1u) / CHUNK;
56
  if (index >= blocks * params.channels) {
57
  return;
build/webgpu/varlen-causal-conv.wgsl.jinja CHANGED
@@ -29,18 +29,14 @@ fn activate(value: f32) -> f32 {
29
  {% endif %}
30
  }
31
  {%- endmacro %}
32
- {% if usesF16 %}
33
- enable f16;
34
- {% endif %}
35
  {{ env.wgsl.resourceDeclarations }}
36
 
37
  // com.microsoft.VarlenCausalConvWithState, portable pass.
38
  // One invocation per (token, channel) output element, for any kernel extent.
39
  // `channels` is the contiguous axis of the token-major layout, so consecutive
40
- // lanes read consecutive addresses and every load coalesces. Each element
41
- // re-reads its kernel window, but the reuse distance is kernelSize token rows,
42
- // which stays cache-resident; the streaming form removes the reread where
43
- // the kernel extent is known.
44
  const WG: u32 = {{ workgroupSize }}u;
45
 
46
  {{ varlen_sequence_of_token() }}
@@ -48,11 +44,10 @@ const WG: u32 = {{ workgroupSize }}u;
48
  {{ varlen_conv_helpers(useSilu) }}
49
 
50
  @compute @workgroup_size(WG, 1, 1)
51
- fn main(@builtin(global_invocation_id) gid: vec3<u32>,
52
- @builtin(num_workgroups) nwg: vec3<u32>) {
53
  // 2D-folded flat index: gid.y carries the high bits past the
54
- // maxComputeWorkgroupsPerDimension limit. Reduces to gid.x when nwg.y == 1.
55
- let index = gid.x + gid.y * nwg.x * WG;
56
  if (index >= params.totalTokens * params.channels) {
57
  return;
58
  }
 
29
  {% endif %}
30
  }
31
  {%- endmacro %}
 
 
 
32
  {{ env.wgsl.resourceDeclarations }}
33
 
34
  // com.microsoft.VarlenCausalConvWithState, portable pass.
35
  // One invocation per (token, channel) output element, for any kernel extent.
36
  // `channels` is the contiguous axis of the token-major layout, so consecutive
37
+ // lanes address consecutive channel values. Each element reads its kernel
38
+ // window; specializations with a fixed kernel extent use the streaming form to
39
+ // avoid rereading window values.
 
40
  const WG: u32 = {{ workgroupSize }}u;
41
 
42
  {{ varlen_sequence_of_token() }}
 
44
  {{ varlen_conv_helpers(useSilu) }}
45
 
46
  @compute @workgroup_size(WG, 1, 1)
47
+ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
 
48
  // 2D-folded flat index: gid.y carries the high bits past the
49
+ // per-axis dispatch fold width. Reduces to gid.x when the dispatch does not fold.
50
+ let index = gid.x + gid.y * {{ DISPATCH_FOLD_WIDTH }}u * WG;
51
  if (index >= params.totalTokens * params.channels) {
52
  return;
53
  }
build/webgpu/varlen-state-update.wgsl.jinja CHANGED
@@ -1,6 +1,3 @@
1
- {% if usesF16 %}
2
- enable f16;
3
- {% endif %}
4
  {{ env.wgsl.resourceDeclarations }}
5
 
6
  // Emit the compact transition payload defined by the contrib schema. One
@@ -9,9 +6,8 @@ enable f16;
9
  const WG: u32 = {{ workgroupSize }}u;
10
 
11
  @compute @workgroup_size(WG, 1, 1)
12
- fn main(@builtin(global_invocation_id) gid: vec3<u32>,
13
- @builtin(num_workgroups) nwg: vec3<u32>) {
14
- let index = gid.x + gid.y * nwg.x * WG;
15
  let count = params.batchSize * params.stateUpdateCapacity * params.channels;
16
  if (index >= count) {
17
  return;
 
 
 
 
1
  {{ env.wgsl.resourceDeclarations }}
2
 
3
  // Emit the compact transition payload defined by the contrib schema. One
 
6
  const WG: u32 = {{ workgroupSize }}u;
7
 
8
  @compute @workgroup_size(WG, 1, 1)
9
+ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
10
+ let index = gid.x + gid.y * {{ DISPATCH_FOLD_WIDTH }}u * WG;
 
11
  let count = params.batchSize * params.stateUpdateCapacity * params.channels;
12
  if (index >= count) {
13
  return;