Xenova HF Staff commited on
Commit
e82d8e1
·
verified ·
1 Parent(s): 0fe2ba4

sync 2e7068faf55e

Browse files
README.md CHANGED
@@ -1,3 +1,76 @@
1
  ---
 
2
  license: apache-2.0
 
 
 
 
3
  ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ library_name: kernels
3
  license: apache-2.0
4
+ tags:
5
+ - kernel
6
+ - webgpu
7
+ - wgsl
8
  ---
9
+ # ai.onnx.CausalConvWithState
10
+
11
+ `ai.onnx` · standard ONNX operator · ONNX opset ≥ 27
12
+
13
+ ## Description
14
+
15
+ Stateful causal 1-D depthwise convolution. It left-pads each channel with `past_state` (or zeros), applies a `(channels, 1, kernel_size)` depthwise convolution and optional SiLU/Swish activation, and returns both the output and the last `kernel_size - 1` values as `present_state`. This inference implementation supports float16 and float32 tensors; bfloat16 is not yet implemented.
16
+
17
+ See the [ONNX `CausalConvWithState` spec](https://onnx.ai/onnx/operators/onnx__CausalConvWithState.html) for the reference semantics.
18
+
19
+ ## Inputs
20
+
21
+ | Name | Bind key | Logical dtype | Rank | Shape | Description | Presence |
22
+ | --- | --- | --- | --- | --- | --- | --- |
23
+ | `input` | `inputT` | `T` | `3` | — | Input tensor with shape `(batch_size, channels, length)` in channels-first layout. | required |
24
+ | `weight` | `weightT` | `T` | `3` | — | Depthwise convolution kernel with shape `(channels, 1, kernel_size)`, matching the ONNX Conv weight layout for `group = channels`. | required |
25
+ | `bias` | `biasT` | `T` | `1` | — | Optional per-channel bias with shape `(channels)`. | optional |
26
+ | `past_state` | `pastStateT` | `T` | `3` | — | Carry state from the previous step with shape `(batch_size, channels, kernel_size - 1)`. If omitted, the left padding is zero. | optional |
27
+
28
+ ## Outputs
29
+
30
+ | Name | Bind key | Logical dtype | Rank | Shape | Description | Presence |
31
+ | --- | --- | --- | --- | --- | --- | --- |
32
+ | `output` | `outputT` | `T` | `3` | same as `input` | Convolution output with the same shape as `input`. | required |
33
+ | `present_state` | `presentStateT` | `T` | `3` | derived; see description | Updated carry state with shape `(batch_size, channels, kernel_size - 1)`, including prior state or zero-padding when the current input is shorter than the state. | required |
34
+
35
+ ## Attributes
36
+
37
+ Default values (overridable per request):
38
+
39
+ | Attribute | Default | Description |
40
+ | --- | --- | --- |
41
+ | `activation` | `"none"` | Optional fused activation. `silu` and `swish` are aliases; `none` leaves the convolution result unchanged. |
42
+
43
+ ## Type constraints
44
+
45
+ | Variable | Allowed dtypes |
46
+ | --- | --- |
47
+ | `T` | `float32`, `float16` |
48
+
49
+ ## Files
50
+
51
+ - [`metadata.json`](build/webgpu/metadata.json) — kernel metadata (id, digests, provenance)
52
+ - [`manifest.json`](build/webgpu/manifest.json) — the op contract (source of truth)
53
+ - [`test.json`](build/webgpu/test.json) — correctness cases
54
+ - [`bench.json`](build/webgpu/bench.json) — benchmark + tuning cases
55
+ - [`causal-conv-with-state-tiled.wgsl.jinja`](build/webgpu/causal-conv-with-state-tiled.wgsl.jinja)
56
+ - [`causal-conv-with-state-vec4.wgsl.jinja`](build/webgpu/causal-conv-with-state-vec4.wgsl.jinja)
57
+ - [`causal-conv-with-state.wgsl.jinja`](build/webgpu/causal-conv-with-state.wgsl.jinja)
58
+
59
+ ## Use with `@huggingface/kernels`
60
+
61
+ The loader derives every required output's shape and logical dtype from the manifest contract and this call.
62
+ It then allocates the result tensors automatically.
63
+
64
+ The `version: 1` option selects the published kernel contract; it is independent of any operator opset, contrib `since_version`, or model version.
65
+
66
+ Replace each `*Data` placeholder with a typed array containing the corresponding input data.
67
+
68
+ ```js
69
+ import { getKernel } from "@huggingface/kernels";
70
+
71
+ const kernel = await getKernel("webgpu-kernels/ai.onnx.CausalConvWithState", { version: 1 });
72
+ const { outputT, presentStateT } = await kernel({
73
+ inputT: { data: inputTData, shape: [1, 1, 2] },
74
+ weightT: { data: weightTData, shape: [1, 1, 5] },
75
+ });
76
+ ```
build/webgpu/bench.json ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "op": "ai.onnx.CausalConvWithState",
3
+ "tunableSpace": { "workgroupSize": [64, 128, 256] },
4
+ "cases": [
5
+ {
6
+ "name": "decode-f16-b1c1024t1k4",
7
+ "preset": "smoke",
8
+ "attrs": { "activation": "silu" },
9
+ "inputs": {
10
+ "inputT": { "shape": [1, 1024, 1], "dtype": "float16", "dist": "normal", "seed": 2751, "scale": 0.2 },
11
+ "weightT": { "shape": [1024, 1, 4], "dtype": "float16", "dist": "normal", "seed": 2752, "scale": 0.1 },
12
+ "biasT": { "shape": [1024], "dtype": "float16", "dist": "normal", "seed": 2753, "scale": 0.05 },
13
+ "pastStateT": { "shape": [1, 1024, 3], "dtype": "float16", "dist": "normal", "seed": 2754, "scale": 0.2 }
14
+ },
15
+ "outputs": {
16
+ "outputT": { "shape": [1, 1024, 1], "dtype": "float16" },
17
+ "presentStateT": { "shape": [1, 1024, 3], "dtype": "float16" }
18
+ },
19
+ "bench": {
20
+ "primary": true,
21
+ "metrics": [
22
+ { "type": "gflops", "value": "2 * numel(shapes.outputT) * dim(shapes.weightT, 2)" },
23
+ {
24
+ "type": "bandwidth",
25
+ "value": "(numel(shapes.inputT) + numel(shapes.weightT) + numel(shapes.biasT) + numel(shapes.pastStateT) + numel(shapes.outputT) + numel(shapes.presentStateT)) * 2"
26
+ }
27
+ ]
28
+ }
29
+ },
30
+ {
31
+ "name": "prefill-f32-b2c32t256k4",
32
+ "preset": "smoke",
33
+ "attrs": { "activation": "none" },
34
+ "inputs": {
35
+ "inputT": { "shape": [2, 32, 256], "dtype": "float32", "dist": "normal", "seed": 2755, "scale": 0.2 },
36
+ "weightT": { "shape": [32, 1, 4], "dtype": "float32", "dist": "normal", "seed": 2756, "scale": 0.1 }
37
+ },
38
+ "outputs": {
39
+ "outputT": { "shape": [2, 32, 256], "dtype": "float32" },
40
+ "presentStateT": { "shape": [2, 32, 3], "dtype": "float32" }
41
+ },
42
+ "bench": {
43
+ "primary": true,
44
+ "metrics": [
45
+ { "type": "gflops", "value": "2 * numel(shapes.outputT) * dim(shapes.weightT, 2)" },
46
+ {
47
+ "type": "bandwidth",
48
+ "value": "(numel(shapes.inputT) + numel(shapes.weightT) + numel(shapes.outputT) + numel(shapes.presentStateT)) * 4"
49
+ }
50
+ ]
51
+ }
52
+ },
53
+ {
54
+ "name": "large-kernel-f32-b2c1024t512k128",
55
+ "preset": "stress",
56
+ "tunableSpace": { "tiledWorkgroupSize": [64, 128, 256] },
57
+ "attrs": { "activation": "none" },
58
+ "inputs": {
59
+ "inputT": { "shape": [2, 1024, 512], "dtype": "float32", "dist": "normal", "seed": 2757, "scale": 0.2 },
60
+ "weightT": { "shape": [1024, 1, 128], "dtype": "float32", "dist": "normal", "seed": 2758, "scale": 0.05 }
61
+ },
62
+ "outputs": {
63
+ "outputT": { "shape": [2, 1024, 512], "dtype": "float32", "dist": "empty" },
64
+ "presentStateT": { "shape": [2, 1024, 127], "dtype": "float32", "dist": "empty" }
65
+ },
66
+ "bench": {
67
+ "primary": true,
68
+ "metrics": [
69
+ { "type": "gflops", "value": "2 * numel(shapes.outputT) * dim(shapes.weightT, 2)" },
70
+ {
71
+ "type": "bandwidth",
72
+ "value": "(numel(shapes.inputT) + numel(shapes.weightT) + numel(shapes.outputT) + numel(shapes.presentStateT)) * 4"
73
+ }
74
+ ]
75
+ }
76
+ }
77
+ ]
78
+ }
build/webgpu/causal-conv-with-state-tiled.wgsl.jinja ADDED
@@ -0,0 +1,177 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% set pastSlot = "(params.stateWindow - 1u) * params.stateSlotStride + " if hasStateWindow else "" %}
2
+ {% if usesF16 %}
3
+ enable f16;
4
+ {% endif -%}
5
+ {{ env.wgsl.resourceDeclarations }}
6
+
7
+ const WG: u32 = {{ workgroupSize }}u;
8
+ const TILE: u32 = {{ tileSize }}u;
9
+ const OUTPUTS_PER_THREAD: u32 = 8u;
10
+ const KERNEL_SIZE: u32 = {{ kernelSize }}u;
11
+ // The tap loop consumes four weights per iteration. Rounding the weight tile up
12
+ // to a multiple of four and zero-filling the tail lets a kernel of any length
13
+ // use it: the phantom taps contribute nothing. The input tile grows to match,
14
+ // because the last lane reads TILE + KERNEL_PADDED - 2.
15
+ const KERNEL_PADDED: u32 = {{ kernelSizePadded }}u;
16
+ const STATE_LENGTH: u32 = KERNEL_SIZE - 1u;
17
+ const INPUT_TILE_SIZE: u32 = TILE + KERNEL_PADDED - 1u;
18
+
19
+ var<workgroup> input_tile: array<f32, {{ inputTileSize }}>;
20
+ var<workgroup> weight_tile: array<f32, {{ kernelSizePadded }}>;
21
+
22
+ fn activate(value: f32) -> f32 {
23
+ {% if useSilu %}
24
+ // Materialize the convolution result in T before the f32 SiLU epilogue.
25
+ let convolution_output = f32({{ outputScalar }}(value));
26
+ let sigmoid = 1.0 / (1.0 + exp(-convolution_output));
27
+ return convolution_output * sigmoid;
28
+ {% else %}
29
+ return value;
30
+ {% endif %}
31
+ }
32
+
33
+ @compute @workgroup_size(WG, 1, 1)
34
+ fn main(@builtin(local_invocation_id) lid3: vec3<u32>,
35
+ @builtin(workgroup_id) wid: vec3<u32>,
36
+ @builtin(num_workgroups) nwg: vec3<u32>) {
37
+ let lane = lid3.x;
38
+ let tiles_per_row = (params.length + TILE - 1u) / TILE;
39
+ // Recover the logical workgroup index after an oversized grid folds into y.
40
+ let flat_wg = wid.x + wid.y * nwg.x;
41
+ let total_wg = params.batchSize * params.channels * tiles_per_row;
42
+ if (flat_wg >= total_wg) {
43
+ return;
44
+ }
45
+
46
+ let tile_index = flat_wg % tiles_per_row;
47
+ let bc = flat_wg / tiles_per_row;
48
+ let channel = bc % params.channels;
49
+ let tile_start = tile_index * TILE;
50
+
51
+ var i = lane;
52
+ while (i < INPUT_TILE_SIZE) {
53
+ // input_tile[i] is the concatenated state/input sample needed at output
54
+ // tile_start + i and kernel tap zero.
55
+ let virtual_pos = tile_start + i;
56
+ var value = 0.0;
57
+ if (virtual_pos >= STATE_LENGTH) {
58
+ let input_pos = virtual_pos - STATE_LENGTH;
59
+ if (input_pos < params.length) {
60
+ value = f32(input[bc * params.length + input_pos]);
61
+ }
62
+ } else {
63
+ {% if hasState %}
64
+ value = f32(past_state[{{ pastSlot }}bc * STATE_LENGTH + virtual_pos]);
65
+ {% endif %}
66
+ }
67
+ input_tile[i] = value;
68
+ i = i + WG;
69
+ }
70
+
71
+ i = lane;
72
+ while (i < KERNEL_PADDED) {
73
+ var weight_value = 0.0;
74
+ if (i < KERNEL_SIZE) {
75
+ weight_value = f32(weight[channel * KERNEL_SIZE + i]);
76
+ }
77
+ weight_tile[i] = weight_value;
78
+ i = i + WG;
79
+ }
80
+ workgroupBarrier();
81
+
82
+ let pos = tile_start + lane * OUTPUTS_PER_THREAD;
83
+ if (pos < params.length) {
84
+ {% if hasBias %}
85
+ var acc0 = vec4<f32>(f32(bias[channel]));
86
+ var acc1 = acc0;
87
+ {% else %}
88
+ var acc0 = vec4<f32>(0.0);
89
+ var acc1 = vec4<f32>(0.0);
90
+ {% endif %}
91
+ // Each lane computes eight adjacent outputs and reuses a weight across them.
92
+ var k = 0u;
93
+ while (k < KERNEL_PADDED) {
94
+ let w = vec4<f32>(
95
+ weight_tile[k],
96
+ weight_tile[k + 1u],
97
+ weight_tile[k + 2u],
98
+ weight_tile[k + 3u]
99
+ );
100
+ let base0 = lane * OUTPUTS_PER_THREAD + k;
101
+ let base1 = base0 + 4u;
102
+ let x00 = vec4<f32>(input_tile[base0], input_tile[base0 + 1u], input_tile[base0 + 2u], input_tile[base0 + 3u]);
103
+ let x01 = vec4<f32>(input_tile[base0 + 1u], input_tile[base0 + 2u], input_tile[base0 + 3u], input_tile[base0 + 4u]);
104
+ let x02 = vec4<f32>(input_tile[base0 + 2u], input_tile[base0 + 3u], input_tile[base0 + 4u], input_tile[base0 + 5u]);
105
+ let x03 = vec4<f32>(input_tile[base0 + 3u], input_tile[base0 + 4u], input_tile[base0 + 5u], input_tile[base0 + 6u]);
106
+ let x10 = vec4<f32>(input_tile[base1], input_tile[base1 + 1u], input_tile[base1 + 2u], input_tile[base1 + 3u]);
107
+ let x11 = vec4<f32>(input_tile[base1 + 1u], input_tile[base1 + 2u], input_tile[base1 + 3u], input_tile[base1 + 4u]);
108
+ let x12 = vec4<f32>(input_tile[base1 + 2u], input_tile[base1 + 3u], input_tile[base1 + 4u], input_tile[base1 + 5u]);
109
+ let x13 = vec4<f32>(input_tile[base1 + 3u], input_tile[base1 + 4u], input_tile[base1 + 5u], input_tile[base1 + 6u]);
110
+ acc0 = fma(x00, vec4<f32>(w.x), acc0);
111
+ acc0 = fma(x01, vec4<f32>(w.y), acc0);
112
+ acc0 = fma(x02, vec4<f32>(w.z), acc0);
113
+ acc0 = fma(x03, vec4<f32>(w.w), acc0);
114
+ acc1 = fma(x10, vec4<f32>(w.x), acc1);
115
+ acc1 = fma(x11, vec4<f32>(w.y), acc1);
116
+ acc1 = fma(x12, vec4<f32>(w.z), acc1);
117
+ acc1 = fma(x13, vec4<f32>(w.w), acc1);
118
+ k = k + 4u;
119
+ }
120
+ let output_base = bc * params.length + pos;
121
+ output[output_base] = {{ outputScalar }}(activate(acc0.x));
122
+ output[output_base + 1u] = {{ outputScalar }}(activate(acc0.y));
123
+ output[output_base + 2u] = {{ outputScalar }}(activate(acc0.z));
124
+ output[output_base + 3u] = {{ outputScalar }}(activate(acc0.w));
125
+ output[output_base + 4u] = {{ outputScalar }}(activate(acc1.x));
126
+ output[output_base + 5u] = {{ outputScalar }}(activate(acc1.y));
127
+ output[output_base + 6u] = {{ outputScalar }}(activate(acc1.z));
128
+ output[output_base + 7u] = {{ outputScalar }}(activate(acc1.w));
129
+ }
130
+
131
+ // Exactly one tile per (batch, channel) updates the carry state, with all
132
+ // lanes sharing the copy.
133
+ if (tile_index == 0u) {
134
+ {% if hasStateWindow %}
135
+ // Windowed state slot j follows position (length - stateWindow + j), so the
136
+ // final slot is the after-last state. A slot whose prefix
137
+ // ends before position 0 holds no position from this call and stays zero. Lanes stride over
138
+ // the flattened (slot, element) grid so a narrow workgroup still covers every slot.
139
+ var e = lane;
140
+ let state_elems = params.stateWindow * STATE_LENGTH;
141
+ while (e < state_elems) {
142
+ let slot = e / STATE_LENGTH;
143
+ let s = e % STATE_LENGTH;
144
+ var state_value = 0.0;
145
+ if (slot + params.length >= params.stateWindow) {
146
+ let virtual_pos = params.length + slot + 1u - params.stateWindow + s;
147
+ if (virtual_pos >= STATE_LENGTH) {
148
+ let input_pos = virtual_pos - STATE_LENGTH;
149
+ state_value = f32(input[bc * params.length + input_pos]);
150
+ } else {
151
+ {% if hasState %}
152
+ state_value = f32(past_state[{{ pastSlot }}bc * STATE_LENGTH + virtual_pos]);
153
+ {% endif %}
154
+ }
155
+ }
156
+ present_state[slot * params.stateSlotStride + bc * STATE_LENGTH + s] = {{ outputScalar }}(state_value);
157
+ e = e + WG;
158
+ }
159
+ {% else %}
160
+ var s = lane;
161
+ while (s < STATE_LENGTH) {
162
+ let virtual_pos = params.length + s;
163
+ var state_value = 0.0;
164
+ if (virtual_pos >= STATE_LENGTH) {
165
+ let input_pos = virtual_pos - STATE_LENGTH;
166
+ state_value = f32(input[bc * params.length + input_pos]);
167
+ } else {
168
+ {% if hasState %}
169
+ state_value = f32(past_state[bc * STATE_LENGTH + virtual_pos]);
170
+ {% endif %}
171
+ }
172
+ present_state[bc * STATE_LENGTH + s] = {{ outputScalar }}(state_value);
173
+ s = s + WG;
174
+ }
175
+ {% endif %}
176
+ }
177
+ }
build/webgpu/causal-conv-with-state-vec4.wgsl.jinja ADDED
@@ -0,0 +1,112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% set pastSlot = "(params.stateWindow - 1u) * params.stateSlotStride + " if hasStateWindow else "" %}
2
+ {% if usesF16 %}
3
+ enable f16;
4
+ {% endif -%}
5
+ {{ env.wgsl.resourceDeclarations }}
6
+
7
+ // Four outputs per invocation for a kernel narrow enough that every tap of a
8
+ // four-wide output lands in this vector or the one before it -- kernel size 2 to
9
+ // 4. The taps are unrolled swizzles of two loaded vectors rather than a
10
+ // runtime-bounded loop.
11
+ const WG: u32 = {{ workgroupSize }}u;
12
+ {% set S = kernelSize - 1 %}
13
+ const STATE_LENGTH: u32 = {{ S }}u;
14
+
15
+ fn activate4(value: vec4<f32>) -> vec4<f32> {
16
+ {% if useSilu %}
17
+ // Materialize the convolution result in T before the f32 SiLU epilogue.
18
+ let convolution_output = vec4<f32>({{ outputVec4 }}(value));
19
+ let sigmoid = vec4<f32>(1.0) / (vec4<f32>(1.0) + exp(-convolution_output));
20
+ return convolution_output * sigmoid;
21
+ {% else %}
22
+ return value;
23
+ {% endif %}
24
+ }
25
+
26
+ @compute @workgroup_size(WG, 1, 1)
27
+ fn main(@builtin(global_invocation_id) gid: vec3<u32>,
28
+ @builtin(num_workgroups) nwg: vec3<u32>) {
29
+ let row_vecs = params.length / 4u;
30
+ let work_size = params.batchSize * params.channels * row_vecs;
31
+ // Recover the logical 1D index after an oversized dispatch is folded into y.
32
+ let index = gid.x + gid.y * nwg.x * WG;
33
+ if (index >= work_size) {
34
+ return;
35
+ }
36
+
37
+ let pos4 = index % row_vecs;
38
+ let bc = index / row_vecs;
39
+ let channel = bc % params.channels;
40
+ // Widen on load and narrow on store so every tap and accumulation stays f32,
41
+ // independent of the tensor type.
42
+ let current = vec4<f32>(input[index]);
43
+ var previous = vec4<f32>(0.0);
44
+ if (pos4 != 0u) {
45
+ previous = vec4<f32>(input[index - 1u]);
46
+ {% if hasState %}
47
+ } else {
48
+ // The first vector of a row continues the previous call: its taps come from
49
+ // the carried state, in the same trailing lanes the interior case reads.
50
+ let sb = {{ pastSlot }}bc * STATE_LENGTH;
51
+ previous = vec4<f32>({% for i in range(4 - S) %}0.0, {% endfor %}{% for i in range(S) %}f32(past_state[sb{{ " + " ~ i ~ "u" if i else "" }}]){{ ", " if not loop.last else "" }}{% endfor %});
52
+ {% endif %}
53
+ }
54
+
55
+ {% if kernelSize == 4 %}
56
+ let w = vec4<f32>(weight[channel]);
57
+ {% else %}
58
+ {% for k in range(kernelSize) %}
59
+ let w{{ k }} = f32(weight[channel * {{ kernelSize }}u + {{ k }}u]);
60
+ {% endfor %}
61
+ {% endif %}
62
+ {% for k in range(kernelSize) %}
63
+ {% set wk = ("w." ~ ["x", "y", "z", "w"][k]) if kernelSize == 4 else ("w" ~ k) %}
64
+ {% if loop.first and hasBias %}
65
+ var value = vec4<f32>(f32(bias[channel])) + {{ wk }} * vec4<f32>(
66
+ {%- for j in range(4) %}{{ ("current." ~ ["x", "y", "z", "w"][j - S + k]) if j - S + k >= 0 else ("previous." ~ ["x", "y", "z", "w"][4 + j - S + k]) }}{{ ", " if not loop.last else "" }}{% endfor -%}
67
+ );
68
+ {% elif loop.first %}
69
+ var value = {{ wk }} * vec4<f32>(
70
+ {%- for j in range(4) %}{{ ("current." ~ ["x", "y", "z", "w"][j - S + k]) if j - S + k >= 0 else ("previous." ~ ["x", "y", "z", "w"][4 + j - S + k]) }}{{ ", " if not loop.last else "" }}{% endfor -%}
71
+ );
72
+ {% else %}
73
+ value = value + {{ wk }} * vec4<f32>(
74
+ {%- for j in range(4) %}{{ ("current." ~ ["x", "y", "z", "w"][j - S + k]) if j - S + k >= 0 else ("previous." ~ ["x", "y", "z", "w"][4 + j - S + k]) }}{{ ", " if not loop.last else "" }}{% endfor -%}
75
+ );
76
+ {% endif %}
77
+ {% endfor %}
78
+ output[index] = {{ outputVec4 }}(activate4(value));
79
+
80
+ if (pos4 == 0u) {
81
+ {% if hasStateWindow %}
82
+ // Windowed state: slot j holds the carry state after position (length - stateWindow + j).
83
+ // A slot whose prefix ends before position 0 holds no position from this call and stays
84
+ // zero; a slot that reaches back before position 0 continues the carried state.
85
+ // present_state is scalar-typed here while input is vec4, hence the lane split.
86
+ for (var slot = 0u; slot < params.stateWindow; slot = slot + 1u) {
87
+ let in_window = slot + params.length >= params.stateWindow;
88
+ for (var s = 0u; s < STATE_LENGTH; s = s + 1u) {
89
+ var state_value = 0.0;
90
+ if (in_window) {
91
+ let virtual_pos = params.length + slot + 1u - params.stateWindow + s;
92
+ if (virtual_pos >= STATE_LENGTH) {
93
+ let input_pos = virtual_pos - STATE_LENGTH;
94
+ state_value = f32(input[bc * row_vecs + input_pos / 4u][input_pos % 4u]);
95
+ } else {
96
+ {% if hasState %}
97
+ state_value = f32(past_state[{{ pastSlot }}bc * STATE_LENGTH + virtual_pos]);
98
+ {% endif %}
99
+ }
100
+ }
101
+ present_state[slot * params.stateSlotStride + bc * STATE_LENGTH + s] = {{ outputScalar }}(state_value);
102
+ }
103
+ }
104
+ {% else %}
105
+ let tail = vec4<f32>(input[bc * row_vecs + row_vecs - 1u]);
106
+ let state_base = bc * STATE_LENGTH;
107
+ {% for i in range(S) %}
108
+ present_state[state_base{{ " + " ~ i ~ "u" if i else "" }}] = {{ outputScalar }}(tail.{{ "xyzw"[4 - S + i] }});
109
+ {% endfor %}
110
+ {% endif %}
111
+ }
112
+ }
build/webgpu/causal-conv-with-state.wgsl.jinja ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% set pastSlot = "(params.stateWindow - 1u) * params.stateSlotStride + " if hasStateWindow else "" %}
2
+ {% if usesF16 %}
3
+ enable f16;
4
+ {% endif -%}
5
+ {{ env.wgsl.resourceDeclarations }}
6
+
7
+ const WG: u32 = {{ workgroupSize }}u;
8
+
9
+ fn activate(value: f32) -> f32 {
10
+ {% if useSilu %}
11
+ // Materialize the convolution result in T before the f32 SiLU epilogue.
12
+ let convolution_output = f32({{ outputScalar }}(value));
13
+ let sigmoid = 1.0 / (1.0 + exp(-convolution_output));
14
+ return convolution_output * sigmoid;
15
+ {% else %}
16
+ return value;
17
+ {% endif %}
18
+ }
19
+
20
+ @compute @workgroup_size(WG, 1, 1)
21
+ fn main(@builtin(global_invocation_id) gid: vec3<u32>,
22
+ @builtin(num_workgroups) nwg: vec3<u32>) {
23
+ // length == 0 still writes the present_state carryover. The nonzero grid keeps
24
+ // one state-writing thread per (batch, channel) even when there is no output.
25
+ let len_nz = max(1u, params.length);
26
+ let work_size = params.batchSize * params.channels * len_nz;
27
+ // gid.y carries the high bits past the per-dimension dispatch limit.
28
+ let index = gid.x + gid.y * nwg.x * WG;
29
+ if (index >= work_size) {
30
+ return;
31
+ }
32
+
33
+ let pos = index % len_nz;
34
+ let bc = index / len_nz;
35
+ let batch = bc / params.channels;
36
+ let channel = bc % params.channels;
37
+ let state_length = params.kernelSize - 1u;
38
+
39
+ // Output exists only for real positions. At length zero this thread performs
40
+ // only the present_state carryover below.
41
+ if (pos < params.length) {
42
+ var acc = 0.0;
43
+ {% if hasBias %}
44
+ acc = acc + f32(bias[channel]);
45
+
46
+ {% endif %}
47
+ for (var k: u32 = 0u; k < params.kernelSize; k = k + 1u) {
48
+ var value = 0.0;
49
+ let virtual_pos = pos + k;
50
+ if (virtual_pos >= state_length) {
51
+ let input_pos = virtual_pos - state_length;
52
+ let input_index = (batch * params.channels + channel) * params.length + input_pos;
53
+ value = f32(input[input_index]);
54
+ } else {
55
+ {% if hasState %}
56
+ let state_index = {{ pastSlot }}(batch * params.channels + channel) * state_length + virtual_pos;
57
+ value = f32(past_state[state_index]);
58
+ {% endif %}
59
+ }
60
+ acc = acc + value * f32(weight[channel * params.kernelSize + k]);
61
+ }
62
+ output[index] = {{ outputScalar }}(activate(acc));
63
+ }
64
+
65
+ if (pos == 0u) {
66
+ {% if hasStateWindow %}
67
+ // Windowed state slot j follows position (length - stateWindow + j), so the
68
+ // final slot is the after-last state. A slot whose prefix
69
+ // ends before position 0 holds no position from this call and stays zero.
70
+ for (var slot: u32 = 0u; slot < params.stateWindow; slot = slot + 1u) {
71
+ let in_window = slot + params.length >= params.stateWindow;
72
+ for (var s: u32 = 0u; s < state_length; s = s + 1u) {
73
+ var state_value = 0.0;
74
+ if (in_window) {
75
+ let virtual_pos = params.length + slot + 1u - params.stateWindow + s;
76
+ if (virtual_pos >= state_length) {
77
+ let input_pos = virtual_pos - state_length;
78
+ let input_index = (batch * params.channels + channel) * params.length + input_pos;
79
+ state_value = f32(input[input_index]);
80
+ } else {
81
+ {% if hasState %}
82
+ let state_index = {{ pastSlot }}(batch * params.channels + channel) * state_length + virtual_pos;
83
+ state_value = f32(past_state[state_index]);
84
+ {% endif %}
85
+ }
86
+ }
87
+ present_state[slot * params.stateSlotStride + (batch * params.channels + channel) * state_length + s] = {{ outputScalar }}(state_value);
88
+ }
89
+ }
90
+ {% else %}
91
+ for (var s: u32 = 0u; s < state_length; s = s + 1u) {
92
+ var state_value = 0.0;
93
+ let virtual_pos = params.length + s;
94
+ if (virtual_pos >= state_length) {
95
+ let input_pos = virtual_pos - state_length;
96
+ let input_index = (batch * params.channels + channel) * params.length + input_pos;
97
+ state_value = f32(input[input_index]);
98
+ } else {
99
+ {% if hasState %}
100
+ let state_index = (batch * params.channels + channel) * state_length + virtual_pos;
101
+ state_value = f32(past_state[state_index]);
102
+ {% endif %}
103
+ }
104
+ present_state[(batch * params.channels + channel) * state_length + s] = {{ outputScalar }}(state_value);
105
+ }
106
+ {% endif %}
107
+ }
108
+ }
build/webgpu/manifest.json ADDED
@@ -0,0 +1,1077 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "domain": "ai.onnx",
3
+ "name": "CausalConvWithState",
4
+ "sinceVersion": 27,
5
+ "description": "Stateful causal 1-D depthwise convolution. It left-pads each channel with `past_state` (or zeros), applies a `(channels, 1, kernel_size)` depthwise convolution and optional SiLU/Swish activation, and returns both the output and the last `kernel_size - 1` values as `present_state`. This inference implementation supports float16 and float32 tensors; bfloat16 is not yet implemented.",
6
+ "inputs": [
7
+ {
8
+ "role": "input",
9
+ "dtype": "T",
10
+ "rank": 3,
11
+ "description": "Input tensor with shape `(batch_size, channels, length)` in channels-first layout."
12
+ },
13
+ {
14
+ "role": "weight",
15
+ "dtype": "T",
16
+ "rank": 3,
17
+ "description": "Depthwise convolution kernel with shape `(channels, 1, kernel_size)`, matching the ONNX Conv weight layout for `group = channels`."
18
+ },
19
+ {
20
+ "role": "bias",
21
+ "dtype": "T",
22
+ "rank": 1,
23
+ "optional": true,
24
+ "description": "Optional per-channel bias with shape `(channels)`."
25
+ },
26
+ {
27
+ "role": "past_state",
28
+ "dtype": "T",
29
+ "rank": 3,
30
+ "optional": true,
31
+ "description": "Carry state from the previous step with shape `(batch_size, channels, kernel_size - 1)`. If omitted, the left padding is zero."
32
+ }
33
+ ],
34
+ "outputs": [
35
+ {
36
+ "role": "output",
37
+ "dtype": "T",
38
+ "rank": 3,
39
+ "shape": "shapes.input",
40
+ "description": "Convolution output with the same shape as `input`."
41
+ },
42
+ {
43
+ "role": "present_state",
44
+ "dtype": "T",
45
+ "rank": 3,
46
+ "shape": "[dim(shapes.input, 0), dim(shapes.input, 1), dim(shapes.weight, 2) - 1]",
47
+ "description": "Updated carry state with shape `(batch_size, channels, kernel_size - 1)`, including prior state or zero-padding when the current input is shorter than the state."
48
+ }
49
+ ],
50
+ "attributes": { "activation": "none" },
51
+ "attributeConstraints": { "activation": { "values": ["none", "silu", "swish"] } },
52
+ "attributeDescriptions": {
53
+ "activation": "Optional fused activation. `silu` and `swish` are aliases; `none` leaves the convolution result unchanged."
54
+ },
55
+ "typeConstraints": { "T": ["float32", "float16"] },
56
+ "args": {
57
+ "inputT": { "kind": "tensor", "semantic": "input", "role": "input" },
58
+ "weightT": { "kind": "tensor", "semantic": "weight", "role": "input" },
59
+ "biasT": { "kind": "tensor", "semantic": "bias", "role": "input", "required": false },
60
+ "pastStateT": { "kind": "tensor", "semantic": "past_state", "role": "input", "required": false },
61
+ "outputT": { "kind": "tensor", "semantic": "output", "role": "output" },
62
+ "presentStateT": { "kind": "tensor", "semantic": "present_state", "role": "output" }
63
+ },
64
+ "tunables": { "workgroupSize": 256, "tiledWorkgroupSize": 128 },
65
+ "derive": {
66
+ "kernelSize": "dim(shapes.weightT, 2)",
67
+ "kernelSizePadded": "ceilDiv(kernelSize, 4) * 4",
68
+ "stateLength": "kernelSize - 1",
69
+ "presentStateOk": "ranks.presentStateT == 3 and dim(shapes.presentStateT, 0) == dim(shapes.inputT, 0) and dim(shapes.presentStateT, 1) == dim(shapes.inputT, 1) and dim(shapes.presentStateT, 2) == stateLength",
70
+ "pastStateShapeOk": "present.pastStateT and ranks.pastStateT == 3 and dim(shapes.pastStateT, 0) == dim(shapes.inputT, 0) and dim(shapes.pastStateT, 1) == dim(shapes.inputT, 1) and dim(shapes.pastStateT, 2) == stateLength",
71
+ "commonContract": "ranks.inputT == 3 and ranks.weightT == 3 and ranks.outputT == 3 and kernelSize >= 1 and dim(shapes.weightT, 0) == dim(shapes.inputT, 1) and dim(shapes.weightT, 1) == 1 and sameShape(shapes.outputT, shapes.inputT) and presentStateOk and f16Ok(dtypes.T)",
72
+ "zeroStateContract": "commonContract and not present.pastStateT and not present.biasT",
73
+ "biasNoStateContract": "commonContract and not present.pastStateT and present.biasT and ranks.biasT == 1 and dim(shapes.biasT, 0) == dim(shapes.inputT, 1)",
74
+ "stateNoBiasContract": "commonContract and present.pastStateT and not present.biasT and pastStateShapeOk",
75
+ "stateBiasContract": "commonContract and present.pastStateT and present.biasT and ranks.biasT == 1 and dim(shapes.biasT, 0) == dim(shapes.inputT, 1) and pastStateShapeOk"
76
+ },
77
+ "bindingSets": {
78
+ "zeroScalar": [
79
+ {
80
+ "name": "input",
81
+ "arg": "inputT",
82
+ "semantic": "input",
83
+ "buffer": { "type": "read-only-storage" },
84
+ "elementType": "$inputScalar"
85
+ },
86
+ {
87
+ "name": "weight",
88
+ "arg": "weightT",
89
+ "semantic": "weight",
90
+ "buffer": { "type": "read-only-storage" },
91
+ "elementType": "$inputScalar"
92
+ },
93
+ {
94
+ "name": "output",
95
+ "arg": "outputT",
96
+ "semantic": "output",
97
+ "buffer": { "type": "storage" },
98
+ "elementType": "$outputScalar"
99
+ },
100
+ {
101
+ "name": "present_state",
102
+ "arg": "presentStateT",
103
+ "semantic": "present_state",
104
+ "buffer": { "type": "storage" },
105
+ "elementType": "$outputScalar"
106
+ },
107
+ {
108
+ "name": "params",
109
+ "semantic": "kernel.params",
110
+ "buffer": { "type": "uniform" },
111
+ "struct": {
112
+ "name": "Params",
113
+ "fields": [
114
+ { "name": "batchSize", "type": "u32", "value": "dim(shapes.inputT, 0)" },
115
+ { "name": "channels", "type": "u32", "value": "dim(shapes.inputT, 1)" },
116
+ { "name": "length", "type": "u32", "value": "dim(shapes.inputT, 2)" },
117
+ { "name": "kernelSize", "type": "u32", "value": "kernelSize" }
118
+ ]
119
+ }
120
+ }
121
+ ],
122
+ "biasNoStateScalar": [
123
+ {
124
+ "name": "input",
125
+ "arg": "inputT",
126
+ "semantic": "input",
127
+ "buffer": { "type": "read-only-storage" },
128
+ "elementType": "$inputScalar"
129
+ },
130
+ {
131
+ "name": "weight",
132
+ "arg": "weightT",
133
+ "semantic": "weight",
134
+ "buffer": { "type": "read-only-storage" },
135
+ "elementType": "$inputScalar"
136
+ },
137
+ {
138
+ "name": "bias",
139
+ "arg": "biasT",
140
+ "semantic": "bias",
141
+ "buffer": { "type": "read-only-storage" },
142
+ "elementType": "$inputScalar"
143
+ },
144
+ {
145
+ "name": "output",
146
+ "arg": "outputT",
147
+ "semantic": "output",
148
+ "buffer": { "type": "storage" },
149
+ "elementType": "$outputScalar"
150
+ },
151
+ {
152
+ "name": "present_state",
153
+ "arg": "presentStateT",
154
+ "semantic": "present_state",
155
+ "buffer": { "type": "storage" },
156
+ "elementType": "$outputScalar"
157
+ },
158
+ {
159
+ "name": "params",
160
+ "semantic": "kernel.params",
161
+ "buffer": { "type": "uniform" },
162
+ "struct": {
163
+ "name": "Params",
164
+ "fields": [
165
+ { "name": "batchSize", "type": "u32", "value": "dim(shapes.inputT, 0)" },
166
+ { "name": "channels", "type": "u32", "value": "dim(shapes.inputT, 1)" },
167
+ { "name": "length", "type": "u32", "value": "dim(shapes.inputT, 2)" },
168
+ { "name": "kernelSize", "type": "u32", "value": "kernelSize" }
169
+ ]
170
+ }
171
+ }
172
+ ],
173
+ "stateNoBiasScalar": [
174
+ {
175
+ "name": "input",
176
+ "arg": "inputT",
177
+ "semantic": "input",
178
+ "buffer": { "type": "read-only-storage" },
179
+ "elementType": "$inputScalar"
180
+ },
181
+ {
182
+ "name": "weight",
183
+ "arg": "weightT",
184
+ "semantic": "weight",
185
+ "buffer": { "type": "read-only-storage" },
186
+ "elementType": "$inputScalar"
187
+ },
188
+ {
189
+ "name": "past_state",
190
+ "arg": "pastStateT",
191
+ "semantic": "past_state",
192
+ "buffer": { "type": "read-only-storage" },
193
+ "elementType": "$inputScalar"
194
+ },
195
+ {
196
+ "name": "output",
197
+ "arg": "outputT",
198
+ "semantic": "output",
199
+ "buffer": { "type": "storage" },
200
+ "elementType": "$outputScalar"
201
+ },
202
+ {
203
+ "name": "present_state",
204
+ "arg": "presentStateT",
205
+ "semantic": "present_state",
206
+ "buffer": { "type": "storage" },
207
+ "elementType": "$outputScalar"
208
+ },
209
+ {
210
+ "name": "params",
211
+ "semantic": "kernel.params",
212
+ "buffer": { "type": "uniform" },
213
+ "struct": {
214
+ "name": "Params",
215
+ "fields": [
216
+ { "name": "batchSize", "type": "u32", "value": "dim(shapes.inputT, 0)" },
217
+ { "name": "channels", "type": "u32", "value": "dim(shapes.inputT, 1)" },
218
+ { "name": "length", "type": "u32", "value": "dim(shapes.inputT, 2)" },
219
+ { "name": "kernelSize", "type": "u32", "value": "kernelSize" }
220
+ ]
221
+ }
222
+ }
223
+ ],
224
+ "stateBiasScalar": [
225
+ {
226
+ "name": "input",
227
+ "arg": "inputT",
228
+ "semantic": "input",
229
+ "buffer": { "type": "read-only-storage" },
230
+ "elementType": "$inputScalar"
231
+ },
232
+ {
233
+ "name": "weight",
234
+ "arg": "weightT",
235
+ "semantic": "weight",
236
+ "buffer": { "type": "read-only-storage" },
237
+ "elementType": "$inputScalar"
238
+ },
239
+ {
240
+ "name": "bias",
241
+ "arg": "biasT",
242
+ "semantic": "bias",
243
+ "buffer": { "type": "read-only-storage" },
244
+ "elementType": "$inputScalar"
245
+ },
246
+ {
247
+ "name": "past_state",
248
+ "arg": "pastStateT",
249
+ "semantic": "past_state",
250
+ "buffer": { "type": "read-only-storage" },
251
+ "elementType": "$inputScalar"
252
+ },
253
+ {
254
+ "name": "output",
255
+ "arg": "outputT",
256
+ "semantic": "output",
257
+ "buffer": { "type": "storage" },
258
+ "elementType": "$outputScalar"
259
+ },
260
+ {
261
+ "name": "present_state",
262
+ "arg": "presentStateT",
263
+ "semantic": "present_state",
264
+ "buffer": { "type": "storage" },
265
+ "elementType": "$outputScalar"
266
+ },
267
+ {
268
+ "name": "params",
269
+ "semantic": "kernel.params",
270
+ "buffer": { "type": "uniform" },
271
+ "struct": {
272
+ "name": "Params",
273
+ "fields": [
274
+ { "name": "batchSize", "type": "u32", "value": "dim(shapes.inputT, 0)" },
275
+ { "name": "channels", "type": "u32", "value": "dim(shapes.inputT, 1)" },
276
+ { "name": "length", "type": "u32", "value": "dim(shapes.inputT, 2)" },
277
+ { "name": "kernelSize", "type": "u32", "value": "kernelSize" }
278
+ ]
279
+ }
280
+ }
281
+ ],
282
+ "zeroVec4": [
283
+ {
284
+ "name": "input",
285
+ "arg": "inputT",
286
+ "semantic": "input",
287
+ "buffer": { "type": "read-only-storage" },
288
+ "elementType": "$inputVec4"
289
+ },
290
+ {
291
+ "name": "weight",
292
+ "arg": "weightT",
293
+ "semantic": "weight",
294
+ "buffer": { "type": "read-only-storage" },
295
+ "elementType": "$weightElem"
296
+ },
297
+ {
298
+ "name": "output",
299
+ "arg": "outputT",
300
+ "semantic": "output",
301
+ "buffer": { "type": "storage" },
302
+ "elementType": "$outputVec4"
303
+ },
304
+ {
305
+ "name": "present_state",
306
+ "arg": "presentStateT",
307
+ "semantic": "present_state",
308
+ "buffer": { "type": "storage" },
309
+ "elementType": "$outputScalar"
310
+ },
311
+ {
312
+ "name": "params",
313
+ "semantic": "kernel.params",
314
+ "buffer": { "type": "uniform" },
315
+ "struct": {
316
+ "name": "Params",
317
+ "fields": [
318
+ { "name": "batchSize", "type": "u32", "value": "dim(shapes.inputT, 0)" },
319
+ { "name": "channels", "type": "u32", "value": "dim(shapes.inputT, 1)" },
320
+ { "name": "length", "type": "u32", "value": "dim(shapes.inputT, 2)" }
321
+ ]
322
+ }
323
+ }
324
+ ],
325
+ "biasNoStateVec4": [
326
+ {
327
+ "name": "input",
328
+ "arg": "inputT",
329
+ "semantic": "input",
330
+ "buffer": { "type": "read-only-storage" },
331
+ "elementType": "$inputVec4"
332
+ },
333
+ {
334
+ "name": "weight",
335
+ "arg": "weightT",
336
+ "semantic": "weight",
337
+ "buffer": { "type": "read-only-storage" },
338
+ "elementType": "$weightElem"
339
+ },
340
+ {
341
+ "name": "bias",
342
+ "arg": "biasT",
343
+ "semantic": "bias",
344
+ "buffer": { "type": "read-only-storage" },
345
+ "elementType": "$inputScalar"
346
+ },
347
+ {
348
+ "name": "output",
349
+ "arg": "outputT",
350
+ "semantic": "output",
351
+ "buffer": { "type": "storage" },
352
+ "elementType": "$outputVec4"
353
+ },
354
+ {
355
+ "name": "present_state",
356
+ "arg": "presentStateT",
357
+ "semantic": "present_state",
358
+ "buffer": { "type": "storage" },
359
+ "elementType": "$outputScalar"
360
+ },
361
+ {
362
+ "name": "params",
363
+ "semantic": "kernel.params",
364
+ "buffer": { "type": "uniform" },
365
+ "struct": {
366
+ "name": "Params",
367
+ "fields": [
368
+ { "name": "batchSize", "type": "u32", "value": "dim(shapes.inputT, 0)" },
369
+ { "name": "channels", "type": "u32", "value": "dim(shapes.inputT, 1)" },
370
+ { "name": "length", "type": "u32", "value": "dim(shapes.inputT, 2)" }
371
+ ]
372
+ }
373
+ }
374
+ ],
375
+ "stateNoBiasVec4": [
376
+ {
377
+ "name": "input",
378
+ "arg": "inputT",
379
+ "semantic": "input",
380
+ "buffer": { "type": "read-only-storage" },
381
+ "elementType": "$inputVec4"
382
+ },
383
+ {
384
+ "name": "weight",
385
+ "arg": "weightT",
386
+ "semantic": "weight",
387
+ "buffer": { "type": "read-only-storage" },
388
+ "elementType": "$weightElem"
389
+ },
390
+ {
391
+ "name": "past_state",
392
+ "arg": "pastStateT",
393
+ "semantic": "past_state",
394
+ "buffer": { "type": "read-only-storage" },
395
+ "elementType": "$inputScalar"
396
+ },
397
+ {
398
+ "name": "output",
399
+ "arg": "outputT",
400
+ "semantic": "output",
401
+ "buffer": { "type": "storage" },
402
+ "elementType": "$outputVec4"
403
+ },
404
+ {
405
+ "name": "present_state",
406
+ "arg": "presentStateT",
407
+ "semantic": "present_state",
408
+ "buffer": { "type": "storage" },
409
+ "elementType": "$outputScalar"
410
+ },
411
+ {
412
+ "name": "params",
413
+ "semantic": "kernel.params",
414
+ "buffer": { "type": "uniform" },
415
+ "struct": {
416
+ "name": "Params",
417
+ "fields": [
418
+ { "name": "batchSize", "type": "u32", "value": "dim(shapes.inputT, 0)" },
419
+ { "name": "channels", "type": "u32", "value": "dim(shapes.inputT, 1)" },
420
+ { "name": "length", "type": "u32", "value": "dim(shapes.inputT, 2)" }
421
+ ]
422
+ }
423
+ }
424
+ ],
425
+ "stateBiasVec4": [
426
+ {
427
+ "name": "input",
428
+ "arg": "inputT",
429
+ "semantic": "input",
430
+ "buffer": { "type": "read-only-storage" },
431
+ "elementType": "$inputVec4"
432
+ },
433
+ {
434
+ "name": "weight",
435
+ "arg": "weightT",
436
+ "semantic": "weight",
437
+ "buffer": { "type": "read-only-storage" },
438
+ "elementType": "$weightElem"
439
+ },
440
+ {
441
+ "name": "bias",
442
+ "arg": "biasT",
443
+ "semantic": "bias",
444
+ "buffer": { "type": "read-only-storage" },
445
+ "elementType": "$inputScalar"
446
+ },
447
+ {
448
+ "name": "past_state",
449
+ "arg": "pastStateT",
450
+ "semantic": "past_state",
451
+ "buffer": { "type": "read-only-storage" },
452
+ "elementType": "$inputScalar"
453
+ },
454
+ {
455
+ "name": "output",
456
+ "arg": "outputT",
457
+ "semantic": "output",
458
+ "buffer": { "type": "storage" },
459
+ "elementType": "$outputVec4"
460
+ },
461
+ {
462
+ "name": "present_state",
463
+ "arg": "presentStateT",
464
+ "semantic": "present_state",
465
+ "buffer": { "type": "storage" },
466
+ "elementType": "$outputScalar"
467
+ },
468
+ {
469
+ "name": "params",
470
+ "semantic": "kernel.params",
471
+ "buffer": { "type": "uniform" },
472
+ "struct": {
473
+ "name": "Params",
474
+ "fields": [
475
+ { "name": "batchSize", "type": "u32", "value": "dim(shapes.inputT, 0)" },
476
+ { "name": "channels", "type": "u32", "value": "dim(shapes.inputT, 1)" },
477
+ { "name": "length", "type": "u32", "value": "dim(shapes.inputT, 2)" }
478
+ ]
479
+ }
480
+ }
481
+ ],
482
+ "zeroTiled": [
483
+ {
484
+ "name": "input",
485
+ "arg": "inputT",
486
+ "semantic": "input",
487
+ "buffer": { "type": "read-only-storage" },
488
+ "elementType": "$inputScalar"
489
+ },
490
+ {
491
+ "name": "weight",
492
+ "arg": "weightT",
493
+ "semantic": "weight",
494
+ "buffer": { "type": "read-only-storage" },
495
+ "elementType": "$inputScalar"
496
+ },
497
+ {
498
+ "name": "output",
499
+ "arg": "outputT",
500
+ "semantic": "output",
501
+ "buffer": { "type": "storage" },
502
+ "elementType": "$outputScalar"
503
+ },
504
+ {
505
+ "name": "present_state",
506
+ "arg": "presentStateT",
507
+ "semantic": "present_state",
508
+ "buffer": { "type": "storage" },
509
+ "elementType": "$outputScalar"
510
+ },
511
+ {
512
+ "name": "params",
513
+ "semantic": "kernel.params",
514
+ "buffer": { "type": "uniform" },
515
+ "struct": {
516
+ "name": "Params",
517
+ "fields": [
518
+ { "name": "batchSize", "type": "u32", "value": "dim(shapes.inputT, 0)" },
519
+ { "name": "channels", "type": "u32", "value": "dim(shapes.inputT, 1)" },
520
+ { "name": "length", "type": "u32", "value": "dim(shapes.inputT, 2)" }
521
+ ]
522
+ }
523
+ }
524
+ ],
525
+ "biasNoStateTiled": [
526
+ {
527
+ "name": "input",
528
+ "arg": "inputT",
529
+ "semantic": "input",
530
+ "buffer": { "type": "read-only-storage" },
531
+ "elementType": "$inputScalar"
532
+ },
533
+ {
534
+ "name": "weight",
535
+ "arg": "weightT",
536
+ "semantic": "weight",
537
+ "buffer": { "type": "read-only-storage" },
538
+ "elementType": "$inputScalar"
539
+ },
540
+ {
541
+ "name": "bias",
542
+ "arg": "biasT",
543
+ "semantic": "bias",
544
+ "buffer": { "type": "read-only-storage" },
545
+ "elementType": "$inputScalar"
546
+ },
547
+ {
548
+ "name": "output",
549
+ "arg": "outputT",
550
+ "semantic": "output",
551
+ "buffer": { "type": "storage" },
552
+ "elementType": "$outputScalar"
553
+ },
554
+ {
555
+ "name": "present_state",
556
+ "arg": "presentStateT",
557
+ "semantic": "present_state",
558
+ "buffer": { "type": "storage" },
559
+ "elementType": "$outputScalar"
560
+ },
561
+ {
562
+ "name": "params",
563
+ "semantic": "kernel.params",
564
+ "buffer": { "type": "uniform" },
565
+ "struct": {
566
+ "name": "Params",
567
+ "fields": [
568
+ { "name": "batchSize", "type": "u32", "value": "dim(shapes.inputT, 0)" },
569
+ { "name": "channels", "type": "u32", "value": "dim(shapes.inputT, 1)" },
570
+ { "name": "length", "type": "u32", "value": "dim(shapes.inputT, 2)" }
571
+ ]
572
+ }
573
+ }
574
+ ],
575
+ "stateNoBiasTiled": [
576
+ {
577
+ "name": "input",
578
+ "arg": "inputT",
579
+ "semantic": "input",
580
+ "buffer": { "type": "read-only-storage" },
581
+ "elementType": "$inputScalar"
582
+ },
583
+ {
584
+ "name": "weight",
585
+ "arg": "weightT",
586
+ "semantic": "weight",
587
+ "buffer": { "type": "read-only-storage" },
588
+ "elementType": "$inputScalar"
589
+ },
590
+ {
591
+ "name": "past_state",
592
+ "arg": "pastStateT",
593
+ "semantic": "past_state",
594
+ "buffer": { "type": "read-only-storage" },
595
+ "elementType": "$inputScalar"
596
+ },
597
+ {
598
+ "name": "output",
599
+ "arg": "outputT",
600
+ "semantic": "output",
601
+ "buffer": { "type": "storage" },
602
+ "elementType": "$outputScalar"
603
+ },
604
+ {
605
+ "name": "present_state",
606
+ "arg": "presentStateT",
607
+ "semantic": "present_state",
608
+ "buffer": { "type": "storage" },
609
+ "elementType": "$outputScalar"
610
+ },
611
+ {
612
+ "name": "params",
613
+ "semantic": "kernel.params",
614
+ "buffer": { "type": "uniform" },
615
+ "struct": {
616
+ "name": "Params",
617
+ "fields": [
618
+ { "name": "batchSize", "type": "u32", "value": "dim(shapes.inputT, 0)" },
619
+ { "name": "channels", "type": "u32", "value": "dim(shapes.inputT, 1)" },
620
+ { "name": "length", "type": "u32", "value": "dim(shapes.inputT, 2)" }
621
+ ]
622
+ }
623
+ }
624
+ ],
625
+ "stateBiasTiled": [
626
+ {
627
+ "name": "input",
628
+ "arg": "inputT",
629
+ "semantic": "input",
630
+ "buffer": { "type": "read-only-storage" },
631
+ "elementType": "$inputScalar"
632
+ },
633
+ {
634
+ "name": "weight",
635
+ "arg": "weightT",
636
+ "semantic": "weight",
637
+ "buffer": { "type": "read-only-storage" },
638
+ "elementType": "$inputScalar"
639
+ },
640
+ {
641
+ "name": "bias",
642
+ "arg": "biasT",
643
+ "semantic": "bias",
644
+ "buffer": { "type": "read-only-storage" },
645
+ "elementType": "$inputScalar"
646
+ },
647
+ {
648
+ "name": "past_state",
649
+ "arg": "pastStateT",
650
+ "semantic": "past_state",
651
+ "buffer": { "type": "read-only-storage" },
652
+ "elementType": "$inputScalar"
653
+ },
654
+ {
655
+ "name": "output",
656
+ "arg": "outputT",
657
+ "semantic": "output",
658
+ "buffer": { "type": "storage" },
659
+ "elementType": "$outputScalar"
660
+ },
661
+ {
662
+ "name": "present_state",
663
+ "arg": "presentStateT",
664
+ "semantic": "present_state",
665
+ "buffer": { "type": "storage" },
666
+ "elementType": "$outputScalar"
667
+ },
668
+ {
669
+ "name": "params",
670
+ "semantic": "kernel.params",
671
+ "buffer": { "type": "uniform" },
672
+ "struct": {
673
+ "name": "Params",
674
+ "fields": [
675
+ { "name": "batchSize", "type": "u32", "value": "dim(shapes.inputT, 0)" },
676
+ { "name": "channels", "type": "u32", "value": "dim(shapes.inputT, 1)" },
677
+ { "name": "length", "type": "u32", "value": "dim(shapes.inputT, 2)" }
678
+ ]
679
+ }
680
+ }
681
+ ]
682
+ },
683
+ "variants": [
684
+ {
685
+ "id": "zero_state_vec4",
686
+ "priority": 20,
687
+ "when": ["zeroStateContract", "kernelSize >= 2", "kernelSize <= 4", "dim(shapes.inputT, 2) >= 4", "dim(shapes.inputT, 2) % 4 == 0"],
688
+ "constants": {
689
+ "useSilu": "attrs.activation == \"silu\" or attrs.activation == \"swish\"",
690
+ "workgroupSize": 256,
691
+ "hasStateWindow": false,
692
+ "usesF16": "tensorDtypes.inputT == \"float16\"",
693
+ "inputScalar": "dtypes.T",
694
+ "outputScalar": "dtypes.T",
695
+ "inputVec4": "\"vec4<f16>\" if tensorDtypes.inputT == \"float16\" else \"vec4<f32>\"",
696
+ "outputVec4": "\"vec4<f16>\" if tensorDtypes.inputT == \"float16\" else \"vec4<f32>\"",
697
+ "hasBias": false,
698
+ "hasState": false,
699
+ "kernelSize": "kernelSize",
700
+ "kernelSizePadded": "kernelSizePadded",
701
+ "weightElem": "(\"vec4<f16>\" if tensorDtypes.inputT == \"float16\" else \"vec4<f32>\") if kernelSize == 4 else dtypes.T"
702
+ },
703
+ "passes": [
704
+ {
705
+ "id": "main",
706
+ "name": "CausalConvWithState.Vec4",
707
+ "source": {
708
+ "shader": "causal-conv-with-state-vec4.wgsl.jinja",
709
+ "inputs": { "materializeConvBeforeActivation": true }
710
+ },
711
+ "bindings": "zeroVec4",
712
+ "dispatch": {
713
+ "threads": "dim(shapes.outputT, 0) * dim(shapes.outputT, 1) * (dim(shapes.outputT, 2) / 4)",
714
+ "workgroupSize": "constants.workgroupSize"
715
+ }
716
+ }
717
+ ]
718
+ },
719
+ {
720
+ "id": "bias_no_state_vec4",
721
+ "priority": 20,
722
+ "when": ["biasNoStateContract", "kernelSize >= 2", "kernelSize <= 4", "dim(shapes.inputT, 2) >= 4", "dim(shapes.inputT, 2) % 4 == 0"],
723
+ "constants": {
724
+ "useSilu": "attrs.activation == \"silu\" or attrs.activation == \"swish\"",
725
+ "workgroupSize": 256,
726
+ "hasStateWindow": false,
727
+ "usesF16": "tensorDtypes.inputT == \"float16\"",
728
+ "inputScalar": "dtypes.T",
729
+ "outputScalar": "dtypes.T",
730
+ "inputVec4": "\"vec4<f16>\" if tensorDtypes.inputT == \"float16\" else \"vec4<f32>\"",
731
+ "outputVec4": "\"vec4<f16>\" if tensorDtypes.inputT == \"float16\" else \"vec4<f32>\"",
732
+ "hasBias": true,
733
+ "hasState": false,
734
+ "kernelSize": "kernelSize",
735
+ "kernelSizePadded": "kernelSizePadded",
736
+ "weightElem": "(\"vec4<f16>\" if tensorDtypes.inputT == \"float16\" else \"vec4<f32>\") if kernelSize == 4 else dtypes.T"
737
+ },
738
+ "passes": [
739
+ {
740
+ "id": "main",
741
+ "name": "CausalConvWithState.Vec4",
742
+ "source": {
743
+ "shader": "causal-conv-with-state-vec4.wgsl.jinja",
744
+ "inputs": { "materializeConvBeforeActivation": true }
745
+ },
746
+ "bindings": "biasNoStateVec4",
747
+ "dispatch": {
748
+ "threads": "dim(shapes.outputT, 0) * dim(shapes.outputT, 1) * (dim(shapes.outputT, 2) / 4)",
749
+ "workgroupSize": "constants.workgroupSize"
750
+ }
751
+ }
752
+ ]
753
+ },
754
+ {
755
+ "id": "state_no_bias_vec4",
756
+ "priority": 20,
757
+ "when": ["stateNoBiasContract", "kernelSize >= 2", "kernelSize <= 4", "dim(shapes.inputT, 2) >= 4", "dim(shapes.inputT, 2) % 4 == 0"],
758
+ "constants": {
759
+ "useSilu": "attrs.activation == \"silu\" or attrs.activation == \"swish\"",
760
+ "workgroupSize": 256,
761
+ "hasStateWindow": false,
762
+ "usesF16": "tensorDtypes.inputT == \"float16\"",
763
+ "inputScalar": "dtypes.T",
764
+ "outputScalar": "dtypes.T",
765
+ "inputVec4": "\"vec4<f16>\" if tensorDtypes.inputT == \"float16\" else \"vec4<f32>\"",
766
+ "outputVec4": "\"vec4<f16>\" if tensorDtypes.inputT == \"float16\" else \"vec4<f32>\"",
767
+ "hasBias": false,
768
+ "hasState": true,
769
+ "kernelSize": "kernelSize",
770
+ "kernelSizePadded": "kernelSizePadded",
771
+ "weightElem": "(\"vec4<f16>\" if tensorDtypes.inputT == \"float16\" else \"vec4<f32>\") if kernelSize == 4 else dtypes.T"
772
+ },
773
+ "passes": [
774
+ {
775
+ "id": "main",
776
+ "name": "CausalConvWithState.Vec4",
777
+ "source": {
778
+ "shader": "causal-conv-with-state-vec4.wgsl.jinja",
779
+ "inputs": { "materializeConvBeforeActivation": true }
780
+ },
781
+ "bindings": "stateNoBiasVec4",
782
+ "dispatch": {
783
+ "threads": "dim(shapes.outputT, 0) * dim(shapes.outputT, 1) * (dim(shapes.outputT, 2) / 4)",
784
+ "workgroupSize": "constants.workgroupSize"
785
+ }
786
+ }
787
+ ]
788
+ },
789
+ {
790
+ "id": "state_bias_vec4",
791
+ "priority": 20,
792
+ "when": ["stateBiasContract", "kernelSize >= 2", "kernelSize <= 4", "dim(shapes.inputT, 2) >= 4", "dim(shapes.inputT, 2) % 4 == 0"],
793
+ "constants": {
794
+ "useSilu": "attrs.activation == \"silu\" or attrs.activation == \"swish\"",
795
+ "workgroupSize": 256,
796
+ "hasStateWindow": false,
797
+ "usesF16": "tensorDtypes.inputT == \"float16\"",
798
+ "inputScalar": "dtypes.T",
799
+ "outputScalar": "dtypes.T",
800
+ "inputVec4": "\"vec4<f16>\" if tensorDtypes.inputT == \"float16\" else \"vec4<f32>\"",
801
+ "outputVec4": "\"vec4<f16>\" if tensorDtypes.inputT == \"float16\" else \"vec4<f32>\"",
802
+ "hasBias": true,
803
+ "hasState": true,
804
+ "kernelSize": "kernelSize",
805
+ "kernelSizePadded": "kernelSizePadded",
806
+ "weightElem": "(\"vec4<f16>\" if tensorDtypes.inputT == \"float16\" else \"vec4<f32>\") if kernelSize == 4 else dtypes.T"
807
+ },
808
+ "passes": [
809
+ {
810
+ "id": "main",
811
+ "name": "CausalConvWithState.Vec4",
812
+ "source": {
813
+ "shader": "causal-conv-with-state-vec4.wgsl.jinja",
814
+ "inputs": { "materializeConvBeforeActivation": true }
815
+ },
816
+ "bindings": "stateBiasVec4",
817
+ "dispatch": {
818
+ "threads": "dim(shapes.outputT, 0) * dim(shapes.outputT, 1) * (dim(shapes.outputT, 2) / 4)",
819
+ "workgroupSize": "constants.workgroupSize"
820
+ }
821
+ }
822
+ ]
823
+ },
824
+ {
825
+ "id": "zero_state_tiled_large_kernel",
826
+ "priority": 10,
827
+ "when": ["zeroStateContract", "kernelSize >= 32", "dim(shapes.inputT, 2) >= 256", "dim(shapes.inputT, 2) % 8 == 0", "tunables.tiledWorkgroupSize >= 1", "floor(tunables.tiledWorkgroupSize) == tunables.tiledWorkgroupSize", "tunables.tiledWorkgroupSize <= device.limits.maxComputeInvocationsPerWorkgroup", "tunables.tiledWorkgroupSize <= device.limits.maxComputeWorkgroupSizeX", "(tunables.tiledWorkgroupSize * 8 + 2 * kernelSizePadded - 1) * 4 <= device.limits.maxComputeWorkgroupStorageSize"],
828
+ "constants": {
829
+ "hasBias": false,
830
+ "hasState": false,
831
+ "useSilu": "attrs.activation == \"silu\" or attrs.activation == \"swish\"",
832
+ "inputScalar": "dtypes.T",
833
+ "outputScalar": "dtypes.T",
834
+ "workgroupSize": "tunables.tiledWorkgroupSize",
835
+ "tileSize": "tunables.tiledWorkgroupSize * 8",
836
+ "kernelSize": "kernelSize",
837
+ "kernelSizePadded": "kernelSizePadded",
838
+ "inputTileSize": "tunables.tiledWorkgroupSize * 8 + kernelSizePadded - 1",
839
+ "hasStateWindow": false,
840
+ "usesF16": "tensorDtypes.inputT == \"float16\""
841
+ },
842
+ "passes": [
843
+ {
844
+ "id": "main",
845
+ "name": "CausalConvWithState.TiledLargeKernel",
846
+ "source": {
847
+ "shader": "causal-conv-with-state-tiled.wgsl.jinja",
848
+ "inputs": { "materializeConvBeforeActivation": true }
849
+ },
850
+ "bindings": "zeroTiled",
851
+ "dispatch": {
852
+ "workgroups": "dim(shapes.outputT, 0) * dim(shapes.outputT, 1) * ceilDiv(dim(shapes.outputT, 2), constants.tileSize)"
853
+ }
854
+ }
855
+ ]
856
+ },
857
+ {
858
+ "id": "bias_no_state_tiled_large_kernel",
859
+ "priority": 10,
860
+ "when": ["biasNoStateContract", "kernelSize >= 32", "dim(shapes.inputT, 2) >= 256", "dim(shapes.inputT, 2) % 8 == 0", "tunables.tiledWorkgroupSize >= 1", "floor(tunables.tiledWorkgroupSize) == tunables.tiledWorkgroupSize", "tunables.tiledWorkgroupSize <= device.limits.maxComputeInvocationsPerWorkgroup", "tunables.tiledWorkgroupSize <= device.limits.maxComputeWorkgroupSizeX", "(tunables.tiledWorkgroupSize * 8 + 2 * kernelSizePadded - 1) * 4 <= device.limits.maxComputeWorkgroupStorageSize"],
861
+ "constants": {
862
+ "hasBias": true,
863
+ "hasState": false,
864
+ "useSilu": "attrs.activation == \"silu\" or attrs.activation == \"swish\"",
865
+ "inputScalar": "dtypes.T",
866
+ "outputScalar": "dtypes.T",
867
+ "workgroupSize": "tunables.tiledWorkgroupSize",
868
+ "tileSize": "tunables.tiledWorkgroupSize * 8",
869
+ "kernelSize": "kernelSize",
870
+ "kernelSizePadded": "kernelSizePadded",
871
+ "inputTileSize": "tunables.tiledWorkgroupSize * 8 + kernelSizePadded - 1",
872
+ "hasStateWindow": false,
873
+ "usesF16": "tensorDtypes.inputT == \"float16\""
874
+ },
875
+ "passes": [
876
+ {
877
+ "id": "main",
878
+ "name": "CausalConvWithState.TiledLargeKernel",
879
+ "source": {
880
+ "shader": "causal-conv-with-state-tiled.wgsl.jinja",
881
+ "inputs": { "materializeConvBeforeActivation": true }
882
+ },
883
+ "bindings": "biasNoStateTiled",
884
+ "dispatch": {
885
+ "workgroups": "dim(shapes.outputT, 0) * dim(shapes.outputT, 1) * ceilDiv(dim(shapes.outputT, 2), constants.tileSize)"
886
+ }
887
+ }
888
+ ]
889
+ },
890
+ {
891
+ "id": "state_no_bias_tiled_large_kernel",
892
+ "priority": 10,
893
+ "when": ["stateNoBiasContract", "kernelSize >= 32", "dim(shapes.inputT, 2) >= 256", "dim(shapes.inputT, 2) % 8 == 0", "tunables.tiledWorkgroupSize >= 1", "floor(tunables.tiledWorkgroupSize) == tunables.tiledWorkgroupSize", "tunables.tiledWorkgroupSize <= device.limits.maxComputeInvocationsPerWorkgroup", "tunables.tiledWorkgroupSize <= device.limits.maxComputeWorkgroupSizeX", "(tunables.tiledWorkgroupSize * 8 + 2 * kernelSizePadded - 1) * 4 <= device.limits.maxComputeWorkgroupStorageSize"],
894
+ "constants": {
895
+ "hasBias": false,
896
+ "hasState": true,
897
+ "useSilu": "attrs.activation == \"silu\" or attrs.activation == \"swish\"",
898
+ "inputScalar": "dtypes.T",
899
+ "outputScalar": "dtypes.T",
900
+ "workgroupSize": "tunables.tiledWorkgroupSize",
901
+ "tileSize": "tunables.tiledWorkgroupSize * 8",
902
+ "kernelSize": "kernelSize",
903
+ "kernelSizePadded": "kernelSizePadded",
904
+ "inputTileSize": "tunables.tiledWorkgroupSize * 8 + kernelSizePadded - 1",
905
+ "hasStateWindow": false,
906
+ "usesF16": "tensorDtypes.inputT == \"float16\""
907
+ },
908
+ "passes": [
909
+ {
910
+ "id": "main",
911
+ "name": "CausalConvWithState.TiledLargeKernel",
912
+ "source": {
913
+ "shader": "causal-conv-with-state-tiled.wgsl.jinja",
914
+ "inputs": { "materializeConvBeforeActivation": true }
915
+ },
916
+ "bindings": "stateNoBiasTiled",
917
+ "dispatch": {
918
+ "workgroups": "dim(shapes.outputT, 0) * dim(shapes.outputT, 1) * ceilDiv(dim(shapes.outputT, 2), constants.tileSize)"
919
+ }
920
+ }
921
+ ]
922
+ },
923
+ {
924
+ "id": "state_bias_tiled_large_kernel",
925
+ "priority": 10,
926
+ "when": ["stateBiasContract", "kernelSize >= 32", "dim(shapes.inputT, 2) >= 256", "dim(shapes.inputT, 2) % 8 == 0", "tunables.tiledWorkgroupSize >= 1", "floor(tunables.tiledWorkgroupSize) == tunables.tiledWorkgroupSize", "tunables.tiledWorkgroupSize <= device.limits.maxComputeInvocationsPerWorkgroup", "tunables.tiledWorkgroupSize <= device.limits.maxComputeWorkgroupSizeX", "(tunables.tiledWorkgroupSize * 8 + 2 * kernelSizePadded - 1) * 4 <= device.limits.maxComputeWorkgroupStorageSize"],
927
+ "constants": {
928
+ "hasBias": true,
929
+ "hasState": true,
930
+ "useSilu": "attrs.activation == \"silu\" or attrs.activation == \"swish\"",
931
+ "inputScalar": "dtypes.T",
932
+ "outputScalar": "dtypes.T",
933
+ "workgroupSize": "tunables.tiledWorkgroupSize",
934
+ "tileSize": "tunables.tiledWorkgroupSize * 8",
935
+ "kernelSize": "kernelSize",
936
+ "kernelSizePadded": "kernelSizePadded",
937
+ "inputTileSize": "tunables.tiledWorkgroupSize * 8 + kernelSizePadded - 1",
938
+ "hasStateWindow": false,
939
+ "usesF16": "tensorDtypes.inputT == \"float16\""
940
+ },
941
+ "passes": [
942
+ {
943
+ "id": "main",
944
+ "name": "CausalConvWithState.TiledLargeKernel",
945
+ "source": {
946
+ "shader": "causal-conv-with-state-tiled.wgsl.jinja",
947
+ "inputs": { "materializeConvBeforeActivation": true }
948
+ },
949
+ "bindings": "stateBiasTiled",
950
+ "dispatch": {
951
+ "workgroups": "dim(shapes.outputT, 0) * dim(shapes.outputT, 1) * ceilDiv(dim(shapes.outputT, 2), constants.tileSize)"
952
+ }
953
+ }
954
+ ]
955
+ },
956
+ {
957
+ "id": "zero_state",
958
+ "priority": 0,
959
+ "when": ["zeroStateContract"],
960
+ "constants": {
961
+ "hasBias": false,
962
+ "hasState": false,
963
+ "useSilu": "attrs.activation == \"silu\" or attrs.activation == \"swish\"",
964
+ "inputScalar": "dtypes.T",
965
+ "outputScalar": "dtypes.T",
966
+ "workgroupSize": "tunables.workgroupSize",
967
+ "hasStateWindow": false,
968
+ "usesF16": "tensorDtypes.inputT == \"float16\""
969
+ },
970
+ "passes": [
971
+ {
972
+ "id": "main",
973
+ "name": "CausalConvWithState",
974
+ "source": {
975
+ "shader": "causal-conv-with-state.wgsl.jinja",
976
+ "inputs": { "materializeConvBeforeActivation": true }
977
+ },
978
+ "bindings": "zeroScalar",
979
+ "dispatch": {
980
+ "threads": "dim(shapes.outputT, 0) * dim(shapes.outputT, 1) * max(1, dim(shapes.outputT, 2))",
981
+ "workgroupSize": "constants.workgroupSize"
982
+ }
983
+ }
984
+ ]
985
+ },
986
+ {
987
+ "id": "bias_no_state",
988
+ "priority": 0,
989
+ "when": ["biasNoStateContract"],
990
+ "constants": {
991
+ "hasBias": true,
992
+ "hasState": false,
993
+ "useSilu": "attrs.activation == \"silu\" or attrs.activation == \"swish\"",
994
+ "inputScalar": "dtypes.T",
995
+ "outputScalar": "dtypes.T",
996
+ "workgroupSize": "tunables.workgroupSize",
997
+ "hasStateWindow": false,
998
+ "usesF16": "tensorDtypes.inputT == \"float16\""
999
+ },
1000
+ "passes": [
1001
+ {
1002
+ "id": "main",
1003
+ "name": "CausalConvWithState",
1004
+ "source": {
1005
+ "shader": "causal-conv-with-state.wgsl.jinja",
1006
+ "inputs": { "materializeConvBeforeActivation": true }
1007
+ },
1008
+ "bindings": "biasNoStateScalar",
1009
+ "dispatch": {
1010
+ "threads": "dim(shapes.outputT, 0) * dim(shapes.outputT, 1) * max(1, dim(shapes.outputT, 2))",
1011
+ "workgroupSize": "constants.workgroupSize"
1012
+ }
1013
+ }
1014
+ ]
1015
+ },
1016
+ {
1017
+ "id": "state_no_bias",
1018
+ "priority": 0,
1019
+ "when": ["stateNoBiasContract"],
1020
+ "constants": {
1021
+ "hasBias": false,
1022
+ "hasState": true,
1023
+ "useSilu": "attrs.activation == \"silu\" or attrs.activation == \"swish\"",
1024
+ "inputScalar": "dtypes.T",
1025
+ "outputScalar": "dtypes.T",
1026
+ "workgroupSize": "tunables.workgroupSize",
1027
+ "hasStateWindow": false,
1028
+ "usesF16": "tensorDtypes.inputT == \"float16\""
1029
+ },
1030
+ "passes": [
1031
+ {
1032
+ "id": "main",
1033
+ "name": "CausalConvWithState",
1034
+ "source": {
1035
+ "shader": "causal-conv-with-state.wgsl.jinja",
1036
+ "inputs": { "materializeConvBeforeActivation": true }
1037
+ },
1038
+ "bindings": "stateNoBiasScalar",
1039
+ "dispatch": {
1040
+ "threads": "dim(shapes.outputT, 0) * dim(shapes.outputT, 1) * max(1, dim(shapes.outputT, 2))",
1041
+ "workgroupSize": "constants.workgroupSize"
1042
+ }
1043
+ }
1044
+ ]
1045
+ },
1046
+ {
1047
+ "id": "state_bias",
1048
+ "priority": 0,
1049
+ "when": ["stateBiasContract"],
1050
+ "constants": {
1051
+ "hasBias": true,
1052
+ "hasState": true,
1053
+ "useSilu": "attrs.activation == \"silu\" or attrs.activation == \"swish\"",
1054
+ "inputScalar": "dtypes.T",
1055
+ "outputScalar": "dtypes.T",
1056
+ "workgroupSize": "tunables.workgroupSize",
1057
+ "hasStateWindow": false,
1058
+ "usesF16": "tensorDtypes.inputT == \"float16\""
1059
+ },
1060
+ "passes": [
1061
+ {
1062
+ "id": "main",
1063
+ "name": "CausalConvWithState",
1064
+ "source": {
1065
+ "shader": "causal-conv-with-state.wgsl.jinja",
1066
+ "inputs": { "materializeConvBeforeActivation": true }
1067
+ },
1068
+ "bindings": "stateBiasScalar",
1069
+ "dispatch": {
1070
+ "threads": "dim(shapes.outputT, 0) * dim(shapes.outputT, 1) * max(1, dim(shapes.outputT, 2))",
1071
+ "workgroupSize": "constants.workgroupSize"
1072
+ }
1073
+ }
1074
+ ]
1075
+ }
1076
+ ]
1077
+ }
build/webgpu/metadata.json ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "ai.onnx.CausalConvWithState",
3
+ "id": "_ai_onnx_causalconvwithstate_webgpu_0d9e334",
4
+ "version": 1,
5
+ "license": "Apache-2.0",
6
+ "backend": { "type": "webgpu" },
7
+ "digest": {
8
+ "algorithm": "sha256",
9
+ "files": {
10
+ "bench.json": "fCrdgbJNyH7TGMSVJ0qqqadgttfP8Aab9dv/haLYRZM=",
11
+ "causal-conv-with-state-tiled.wgsl.jinja": "X/uUVtlr1/PhjaCIQI7Z6EyqZzcldbk6agI1eX2UGqY=",
12
+ "causal-conv-with-state-vec4.wgsl.jinja": "BMP+FWcwzs8ig4DN9gh7PdEe/jTVZKSZah48B9WvTZM=",
13
+ "causal-conv-with-state.wgsl.jinja": "jf0H+njpBJ0uBPp3hWfdn+dyWkjSTIeM5H357XyeaN0=",
14
+ "manifest.json": "Y+eFrTwuYgJYldZPqxz/xEgCwYLiOg3A/X/Ni6/aj/E=",
15
+ "test.json": "yhv3pfQudb0pD6fFnYnV7jLeNKkxCRkzvg90AXG7Cy4="
16
+ }
17
+ },
18
+ "provenance": { "kernel": { "sha": "2e7068faf55e7f43df740015f6d1ee49391a41c5", "dirty": false } },
19
+ "webgpu": { "manifestSpec": "1.0", "specialized": true, "opPath": "ops/ai.onnx.CausalConvWithState" }
20
+ }
build/webgpu/test.json ADDED
@@ -0,0 +1,358 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "op": "ai.onnx.CausalConvWithState",
3
+ "cases": [
4
+ {
5
+ "name": "scalar_zero_state",
6
+ "attrs": { "activation": "none" },
7
+ "inputs": {
8
+ "inputT": {
9
+ "shape": [1, 2, 3],
10
+ "dtype": "float32",
11
+ "data": { "kind": "fillFloat32", "sinStep": 0.17, "cosStep": 0.29, "scale": 0.25 }
12
+ },
13
+ "weightT": {
14
+ "shape": [2, 1, 3],
15
+ "dtype": "float32",
16
+ "data": { "kind": "fillFloat32", "sinStep": 0.23, "cosStep": 0.11, "scale": 0.2 }
17
+ }
18
+ },
19
+ "outputs": {
20
+ "outputT": { "shape": [1, 2, 3], "dtype": "float32" },
21
+ "presentStateT": { "shape": [1, 2, 2], "dtype": "float32" }
22
+ }
23
+ },
24
+ {
25
+ "name": "scalar_bias_no_state",
26
+ "attrs": { "activation": "none" },
27
+ "inputs": {
28
+ "inputT": {
29
+ "shape": [1, 2, 5],
30
+ "dtype": "float32",
31
+ "data": { "kind": "fillFloat32", "sinStep": 0.19, "cosStep": 0.31, "scale": 0.25 }
32
+ },
33
+ "weightT": {
34
+ "shape": [2, 1, 5],
35
+ "dtype": "float32",
36
+ "data": { "kind": "fillFloat32", "sinStep": 0.13, "cosStep": 0.27, "scale": 0.2 }
37
+ },
38
+ "biasT": {
39
+ "shape": [2],
40
+ "dtype": "float32",
41
+ "data": { "kind": "fillFloat32", "sinStep": 0.37, "cosStep": 0.07, "scale": 0.1 }
42
+ }
43
+ },
44
+ "outputs": {
45
+ "outputT": { "shape": [1, 2, 5], "dtype": "float32" },
46
+ "presentStateT": { "shape": [1, 2, 4], "dtype": "float32" }
47
+ }
48
+ },
49
+ {
50
+ "name": "scalar_state_no_bias_swish",
51
+ "attrs": { "activation": "swish" },
52
+ "inputs": {
53
+ "inputT": {
54
+ "shape": [1, 2, 1],
55
+ "dtype": "float32",
56
+ "data": { "kind": "fillFloat32", "sinStep": 0.11, "cosStep": 0.33, "scale": 0.25 }
57
+ },
58
+ "weightT": {
59
+ "shape": [2, 1, 4],
60
+ "dtype": "float32",
61
+ "data": { "kind": "fillFloat32", "sinStep": 0.29, "cosStep": 0.17, "scale": 0.2 }
62
+ },
63
+ "pastStateT": {
64
+ "shape": [1, 2, 3],
65
+ "dtype": "float32",
66
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.21, "scale": 0.25 }
67
+ }
68
+ },
69
+ "outputs": {
70
+ "outputT": { "shape": [1, 2, 1], "dtype": "float32" },
71
+ "presentStateT": { "shape": [1, 2, 3], "dtype": "float32" }
72
+ }
73
+ },
74
+ {
75
+ "name": "scalar_f16_state_bias_silu_cast_boundary",
76
+ "attrs": { "activation": "silu" },
77
+ "inputs": {
78
+ "inputT": {
79
+ "shape": [1, 1, 3],
80
+ "dtype": "float16",
81
+ "data": { "kind": "values", "values": [1.001, -0.731, 0.287] }
82
+ },
83
+ "weightT": {
84
+ "shape": [1, 1, 3],
85
+ "dtype": "float16",
86
+ "data": { "kind": "values", "values": [0.619, -1.127, 0.443] }
87
+ },
88
+ "biasT": { "shape": [1], "dtype": "float16", "data": { "kind": "values", "values": [0.037] } },
89
+ "pastStateT": {
90
+ "shape": [1, 1, 2],
91
+ "dtype": "float16",
92
+ "data": { "kind": "values", "values": [-0.219, 0.887] }
93
+ }
94
+ },
95
+ "outputs": {
96
+ "outputT": { "shape": [1, 1, 3], "dtype": "float16" },
97
+ "presentStateT": { "shape": [1, 1, 2], "dtype": "float16" }
98
+ }
99
+ },
100
+ {
101
+ "name": "kernel_size_one",
102
+ "inputs": {
103
+ "inputT": {
104
+ "shape": [2, 2, 3],
105
+ "dtype": "float32",
106
+ "data": { "kind": "fillFloat32", "sinStep": 0.13, "cosStep": 0.19, "scale": 0.25 }
107
+ },
108
+ "weightT": {
109
+ "shape": [2, 1, 1],
110
+ "dtype": "float32",
111
+ "data": { "kind": "fillFloat32", "sinStep": 0.31, "cosStep": 0.09, "scale": 0.2 }
112
+ }
113
+ },
114
+ "outputs": {
115
+ "outputT": { "shape": [2, 2, 3], "dtype": "float32" },
116
+ "presentStateT": { "shape": [2, 2, 0], "dtype": "float32" }
117
+ }
118
+ },
119
+ {
120
+ "name": "input_shorter_than_state_zero_padding",
121
+ "inputs": {
122
+ "inputT": { "shape": [1, 1, 2], "dtype": "float32", "data": { "kind": "values", "values": [2.0, 3.0] } },
123
+ "weightT": {
124
+ "shape": [1, 1, 5],
125
+ "dtype": "float32",
126
+ "data": { "kind": "values", "values": [1.0, 1.0, 1.0, 1.0, 1.0] }
127
+ }
128
+ },
129
+ "outputs": {
130
+ "outputT": { "shape": [1, 1, 2], "dtype": "float32" },
131
+ "presentStateT": { "shape": [1, 1, 4], "dtype": "float32" }
132
+ }
133
+ },
134
+ {
135
+ "name": "zero_length_reemits_past_state",
136
+ "inputs": {
137
+ "inputT": { "shape": [1, 1, 0], "dtype": "float32", "data": { "kind": "values", "values": [] } },
138
+ "weightT": { "shape": [1, 1, 3], "dtype": "float32", "data": { "kind": "values", "values": [1.0, 1.0, 1.0] } },
139
+ "pastStateT": { "shape": [1, 1, 2], "dtype": "float32", "data": { "kind": "values", "values": [4.0, 5.0] } }
140
+ },
141
+ "outputs": {
142
+ "outputT": { "shape": [1, 1, 0], "dtype": "float32" },
143
+ "presentStateT": { "shape": [1, 1, 2], "dtype": "float32" }
144
+ }
145
+ },
146
+ {
147
+ "name": "vec4_zero_state_f16_silu",
148
+ "attrs": { "activation": "silu" },
149
+ "inputs": {
150
+ "inputT": {
151
+ "shape": [2, 3, 8],
152
+ "dtype": "float16",
153
+ "data": { "kind": "fillFloat32", "sinStep": 0.17, "cosStep": 0.23, "scale": 0.25 }
154
+ },
155
+ "weightT": {
156
+ "shape": [3, 1, 4],
157
+ "dtype": "float16",
158
+ "data": { "kind": "fillFloat32", "sinStep": 0.27, "cosStep": 0.11, "scale": 0.2 }
159
+ }
160
+ },
161
+ "outputs": {
162
+ "outputT": { "shape": [2, 3, 8], "dtype": "float16" },
163
+ "presentStateT": { "shape": [2, 3, 3], "dtype": "float16" }
164
+ }
165
+ },
166
+ {
167
+ "name": "vec4_bias_no_state_swish",
168
+ "attrs": { "activation": "swish" },
169
+ "inputs": {
170
+ "inputT": {
171
+ "shape": [1, 2, 8],
172
+ "dtype": "float32",
173
+ "data": { "kind": "fillFloat32", "sinStep": 0.21, "cosStep": 0.13, "scale": 0.25 }
174
+ },
175
+ "weightT": {
176
+ "shape": [2, 1, 3],
177
+ "dtype": "float32",
178
+ "data": { "kind": "fillFloat32", "sinStep": 0.09, "cosStep": 0.31, "scale": 0.2 }
179
+ },
180
+ "biasT": {
181
+ "shape": [2],
182
+ "dtype": "float32",
183
+ "data": { "kind": "fillFloat32", "sinStep": 0.33, "cosStep": 0.07, "scale": 0.1 }
184
+ }
185
+ },
186
+ "outputs": {
187
+ "outputT": { "shape": [1, 2, 8], "dtype": "float32" },
188
+ "presentStateT": { "shape": [1, 2, 2], "dtype": "float32" }
189
+ }
190
+ },
191
+ {
192
+ "name": "vec4_state_no_bias",
193
+ "inputs": {
194
+ "inputT": {
195
+ "shape": [1, 2, 4],
196
+ "dtype": "float32",
197
+ "data": { "kind": "fillFloat32", "sinStep": 0.15, "cosStep": 0.25, "scale": 0.25 }
198
+ },
199
+ "weightT": {
200
+ "shape": [2, 1, 2],
201
+ "dtype": "float32",
202
+ "data": { "kind": "fillFloat32", "sinStep": 0.35, "cosStep": 0.05, "scale": 0.2 }
203
+ },
204
+ "pastStateT": {
205
+ "shape": [1, 2, 1],
206
+ "dtype": "float32",
207
+ "data": { "kind": "fillFloat32", "sinStep": 0.11, "cosStep": 0.29, "scale": 0.25 }
208
+ }
209
+ },
210
+ "outputs": {
211
+ "outputT": { "shape": [1, 2, 4], "dtype": "float32" },
212
+ "presentStateT": { "shape": [1, 2, 1], "dtype": "float32" }
213
+ }
214
+ },
215
+ {
216
+ "name": "vec4_state_bias_silu",
217
+ "attrs": { "activation": "silu" },
218
+ "inputs": {
219
+ "inputT": {
220
+ "shape": [1, 2, 8],
221
+ "dtype": "float32",
222
+ "data": { "kind": "fillFloat32", "sinStep": 0.17, "cosStep": 0.27, "scale": 0.25 }
223
+ },
224
+ "weightT": {
225
+ "shape": [2, 1, 4],
226
+ "dtype": "float32",
227
+ "data": { "kind": "fillFloat32", "sinStep": 0.25, "cosStep": 0.13, "scale": 0.2 }
228
+ },
229
+ "biasT": {
230
+ "shape": [2],
231
+ "dtype": "float32",
232
+ "data": { "kind": "fillFloat32", "sinStep": 0.39, "cosStep": 0.05, "scale": 0.1 }
233
+ },
234
+ "pastStateT": {
235
+ "shape": [1, 2, 3],
236
+ "dtype": "float32",
237
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.33, "scale": 0.25 }
238
+ }
239
+ },
240
+ "outputs": {
241
+ "outputT": { "shape": [1, 2, 8], "dtype": "float32" },
242
+ "presentStateT": { "shape": [1, 2, 3], "dtype": "float32" }
243
+ }
244
+ },
245
+ {
246
+ "name": "tiled_zero_state",
247
+ "inputs": {
248
+ "inputT": {
249
+ "shape": [1, 1, 256],
250
+ "dtype": "float32",
251
+ "data": { "kind": "fillFloat32", "sinStep": 0.03, "cosStep": 0.05, "scale": 0.25 }
252
+ },
253
+ "weightT": {
254
+ "shape": [1, 1, 32],
255
+ "dtype": "float32",
256
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.09, "scale": 0.1 }
257
+ }
258
+ },
259
+ "outputs": {
260
+ "outputT": { "shape": [1, 1, 256], "dtype": "float32" },
261
+ "presentStateT": { "shape": [1, 1, 31], "dtype": "float32" }
262
+ }
263
+ },
264
+ {
265
+ "name": "tiled_bias_no_state_silu",
266
+ "attrs": { "activation": "silu" },
267
+ "inputs": {
268
+ "inputT": {
269
+ "shape": [1, 1, 256],
270
+ "dtype": "float32",
271
+ "data": { "kind": "fillFloat32", "sinStep": 0.04, "cosStep": 0.06, "scale": 0.25 }
272
+ },
273
+ "weightT": {
274
+ "shape": [1, 1, 32],
275
+ "dtype": "float32",
276
+ "data": { "kind": "fillFloat32", "sinStep": 0.08, "cosStep": 0.1, "scale": 0.1 }
277
+ },
278
+ "biasT": { "shape": [1], "dtype": "float32", "data": { "kind": "constant", "value": 0.05 } }
279
+ },
280
+ "outputs": {
281
+ "outputT": { "shape": [1, 1, 256], "dtype": "float32" },
282
+ "presentStateT": { "shape": [1, 1, 31], "dtype": "float32" }
283
+ }
284
+ },
285
+ {
286
+ "name": "tiled_state_no_bias",
287
+ "inputs": {
288
+ "inputT": {
289
+ "shape": [1, 1, 256],
290
+ "dtype": "float32",
291
+ "data": { "kind": "fillFloat32", "sinStep": 0.05, "cosStep": 0.07, "scale": 0.25 }
292
+ },
293
+ "weightT": {
294
+ "shape": [1, 1, 32],
295
+ "dtype": "float32",
296
+ "data": { "kind": "fillFloat32", "sinStep": 0.09, "cosStep": 0.11, "scale": 0.1 }
297
+ },
298
+ "pastStateT": {
299
+ "shape": [1, 1, 31],
300
+ "dtype": "float32",
301
+ "data": { "kind": "fillFloat32", "sinStep": 0.13, "cosStep": 0.17, "scale": 0.25 }
302
+ }
303
+ },
304
+ "outputs": {
305
+ "outputT": { "shape": [1, 1, 256], "dtype": "float32" },
306
+ "presentStateT": { "shape": [1, 1, 31], "dtype": "float32" }
307
+ }
308
+ },
309
+ {
310
+ "name": "tiled_state_bias_f16_swish",
311
+ "attrs": { "activation": "swish" },
312
+ "inputs": {
313
+ "inputT": {
314
+ "shape": [1, 1, 256],
315
+ "dtype": "float16",
316
+ "data": { "kind": "fillFloat32", "sinStep": 0.06, "cosStep": 0.08, "scale": 0.25 }
317
+ },
318
+ "weightT": {
319
+ "shape": [1, 1, 32],
320
+ "dtype": "float16",
321
+ "data": { "kind": "fillFloat32", "sinStep": 0.1, "cosStep": 0.12, "scale": 0.1 }
322
+ },
323
+ "biasT": { "shape": [1], "dtype": "float16", "data": { "kind": "constant", "value": -0.05 } },
324
+ "pastStateT": {
325
+ "shape": [1, 1, 31],
326
+ "dtype": "float16",
327
+ "data": { "kind": "fillFloat32", "sinStep": 0.14, "cosStep": 0.18, "scale": 0.25 }
328
+ }
329
+ },
330
+ "outputs": {
331
+ "outputT": { "shape": [1, 1, 256], "dtype": "float16" },
332
+ "presentStateT": { "shape": [1, 1, 31], "dtype": "float16" }
333
+ }
334
+ },
335
+ {
336
+ "name": "tiled_zero_state_unaligned_k35_weight_tile_pad",
337
+ "inputs": {
338
+ "inputT": {
339
+ "shape": [1, 1, 256],
340
+ "dtype": "float32",
341
+ "data": { "kind": "fillFloat32", "sinStep": 0.03, "cosStep": 0.05, "scale": 0.25 }
342
+ },
343
+ "weightT": {
344
+ "shape": [1, 1, 35],
345
+ "dtype": "float32",
346
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.09, "scale": 0.1 }
347
+ }
348
+ },
349
+ "outputs": {
350
+ "outputT": { "shape": [1, 1, 256], "dtype": "float32" },
351
+ "presentStateT": { "shape": [1, 1, 34], "dtype": "float32" }
352
+ },
353
+ "provenance": {
354
+ "notes": "Kernel length 3 mod 4. The shared tiled kernel consumes four taps per iteration, so this shape reaches it only through the zero-padded weight tile; ai.onnx carries its own copy of that gate, so it needs its own lock."
355
+ }
356
+ }
357
+ ]
358
+ }