Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
ea8791f
Extend GDN and causal convolution fused state handling
apsonawane Oct 19, 2026
c1e138f
Fix GDN empty-request state capture and WebGPU plugin compatibility
apsonawane Oct 19, 2026
62bd923
Add opt-in two-token GDN and convolution CUDA specialization
apsonawane Oct 21, 2026
e64ec07
Merge origin/main and enable default-on S<=8 GDN/CausalConv specializ…
tianleiwu Oct 22, 2026
51cd77f
[CUDA] Add S=4 prefix-state outputs (present_mid2/3) to GatedDeltaNet…
tianleiwu Oct 23, 2026
4eecd5d
Merge remote-tracking branch 'origin/main' into tlwu/pr33471-updates
tianleiwu Oct 23, 2026
bbeb06e
[CUDA] Remove unused ORT_GDN_DECODE_WARPS instantiations and duplicat…
tianleiwu Oct 24, 2026
87cc338
fix(cuda): include env_var_utils.h after cuda_common.h and sync Gated…
tianleiwu Oct 24, 2026
4439bb3
feat(cuda): support state_update_capacity in CausalConvWithState and …
tianleiwu Oct 24, 2026
bbc8741
Merge remote-tracking branch 'origin/main' into pr33471-work
tianleiwu Oct 24, 2026
fe6c41c
Remove legacy explicit mid-state outputs from CausalConvWithState and…
tianleiwu Oct 25, 2026
08f2f5a
fix(cuda): restore GatedDeltaNet packed-QKV prefill plan parity and s…
tianleiwu Oct 25, 2026
0cdb489
perf(cuda): tile 8 positions per CTA in CausalConvProjection for K=4 …
tianleiwu Oct 26, 2026
2ba61c3
fix(cuda): address review feedback on CausalConvWithState/GatedDeltaNet
tianleiwu Oct 26, 2026
7495ae5
fix(causal_conv): use plugin-compatible optional-output check
tianleiwu Oct 26, 2026
e62ab5a
Remove gate_activation 'qwen' alias from GatedDeltaNet; use 'softplus…
tianleiwu Oct 26, 2026
63ad89b
CausalConvWithState: zero unused state_update rows; fix S2 env var docs
tianleiwu Oct 26, 2026
7fa1b49
Test CausalConvWithState tiled K4 projection and state_update tail ze…
tianleiwu Oct 26, 2026
5bdeab4
Restore gate_activation 'qwen' as a legacy alias of 'softplus'
tianleiwu Oct 26, 2026
c4babd0
Document QwenS2 / CausalConvWithState S2 op-level and end-to-end benc…
tianleiwu Oct 27, 2026
f83fc02
Merge remote-tracking branch 'origin/main' into asonawane/main-ops-gd…
tianleiwu Oct 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 31 additions & 14 deletions docs/ContribOperators.md
Original file line number Diff line number Diff line change
Expand Up @@ -1025,8 +1025,18 @@ This version of the operator has been available since version 1 of the 'com.micr
<dd>When 1, input, output, past_state and present_state use a sequence-major, channels-last layout: input and output are (batch_size, sequence_length, d_1, ..., d_n) and the state tensors are (batch_size, state_length, d_1, ..., d_n), where channels = d_1 * ... * d_n. weight and bias keep their channels-first shapes. Requires ndim = 1. Default is 0 (channels-first).</dd>
<dt><tt>dilation</tt> : int</dt>
<dd>Spacing between kernel taps along the causal (last spatial) axis. The receptive field spans (k_1 - 1) * dilation positions before the current one, and past_state / present_state hold that many positions. Must be >= 1. Default is 1 (undilated).</dd>
<dt><tt>input_channel_offset</tt> : int</dt>
<dd>Starting channel of the channels-last input slice (CUDA only).</dd>
<dt><tt>input_channels</tt> : int</dt>
<dd>CUDA channels-last input channel slice width; 0 selects all channels. Nondefault extended attributes require rank-3 input and state_window=0.</dd>
<dt><tt>ndim</tt> : int</dt>
<dd>Spatial dimensionality: 1, 2, or 3. Default is 1.</dd>
<dt><tt>state_channels_last</tt> : int</dt>
<dd>State layout override (CUDA only): -1 follows channels_last, 0 uses [B,C,state_length], 1 uses [B,state_length,C].</dd>
<dt><tt>state_length</tt> : int</dt>
<dd>Carry history length (CUDA only); 0 uses (kernel_size-1)*dilation. An explicit length must cover the receptive field; convolution reads its trailing history.</dd>
<dt><tt>state_update_capacity</tt> : int</dt>
<dd>Compact speculative state-update capture capacity (CUDA extended path only, 0..8); when > 0, output 2 has shape (batch_size, state_update_capacity, channels) and records the first min(sequence_length, state_update_capacity) projected input rows and any remaining rows are zero.</dd>
<dt><tt>state_window</tt> : int</dt>
<dd>Number of trailing per-position carry states held by past_state and present_state. When 0 (default) the state tensors have no window axis and hold only the state after the last position, i.e. the backward-compatible (batch_size, channels, state_length) where state_length = (k_1 - 1) * dilation. When W > 0 both gain a LEADING axis of extent W, right-aligned: slot j is the state after position (seq_len - W + j), so slot W-1 is always the state after the last position (identical to the W = 0 tensor) and is the slot past_state is read from. The window axis leads the batch axis so that each slot is one contiguous (batch_size, channels, state_length) block. Slots below max(0, W - seq_len) hold no position from this call and are filled with zeros. A window lets a speculative decoder roll the state back to an accepted prefix without replaying the forward. Valid range is [0, 8].</dd>
</dl>
Expand All @@ -1035,22 +1045,24 @@ This version of the operator has been available since version 1 of the 'com.micr

<dl>
<dt><tt>input</tt> : T</dt>
<dd>Input tensor with shape (batch_size, channels, ...) in the default channels-first layout. Spatial dims: 1D: (L,); 2D: (H, W); 3D: (D, H, W). When channels_last = 1 the shape is (batch_size, sequence_length, d_1, ..., d_n) instead.</dd>
<dd>Input tensor with shape (batch_size, channels, ...) in the default channels-first layout. Spatial dims: 1D: (L,); 2D: (H, W); 3D: (D, H, W). When channels_last = 1 the shape is (batch_size, sequence_length, d_1, ..., d_n) instead. Extended channel selection uses rank-3 (batch_size, sequence_length, input_width).</dd>
<dt><tt>weight</tt> : T</dt>
<dd>Depthwise convolution kernel with shape (channels, 1, k_1, ...). Spatial kernel sizes: (k_1, ..., k_ndim).</dd>
<dt><tt>bias</tt> (optional) : T</dt>
<dd>Optional per-channel bias with shape (channels).</dd>
<dt><tt>past_state</tt> (optional) : T</dt>
<dd>Carry state from previous step. For ndim=1: (batch_size, channels, state_length), or (W, batch_size, channels, state_length) when state_window = W > 0, in which case only slot W-1 is read, where state_length = (k_1 - 1) * dilation. When channels_last = 1 each slot is (batch_size, state_length, d_1, ..., d_n) instead. If not provided, padding is zero.</dd>
<dd>Carry state from previous step. For ndim=1: (batch_size, channels, state_length), or (W, batch_size, channels, state_length) when state_window = W > 0, in which case only slot W-1 is read, where state_length = (k_1 - 1) * dilation. When channels_last = 1 each slot is (batch_size, state_length, d_1, ..., d_n) instead. The state_length and state_channels_last attributes may override the length and layout for the CUDA extended path. If not provided, padding is zero.</dd>
</dl>

#### Outputs
#### Outputs (2 - 3)

<dl>
<dt><tt>output</tt> : T</dt>
<dd>Convolution output with same shape as input.</dd>
<dd>Convolution output with same shape as input, except the final dimension is input_channels when extended channel selection is enabled.</dd>
<dt><tt>present_state</tt> : T</dt>
<dd>Updated carry state. For ndim=1: (batch_size, channels, state_length), or (W, batch_size, channels, state_length) when state_window = W > 0, and (batch_size, state_length, d_1, ..., d_n) per slot when channels_last = 1. Slot W-1 contains the last state_length values from the virtual input along the causal axis; slot j contains the same for the prefix ending at position (seq_len - W + j).</dd>
<dd>Updated carry state. For ndim=1: (batch_size, channels, state_length), or (W, batch_size, channels, state_length) when state_window = W > 0, and (batch_size, state_length, d_1, ..., d_n) per slot when channels_last = 1. Slot W-1 contains the last state_length values from the virtual input along the causal axis; slot j contains the same for the prefix ending at position (seq_len - W + j). Extended attributes override the state length and layout as for past_state.</dd>
<dt><tt>state_update</tt> (optional) : T</dt>
<dd>Optional compact state-update capture with shape (batch_size, state_update_capacity, channels) when state_update_capacity > 0. CUDA extended path only; requires rank-3 channels-last input and state_window=0.</dd>
</dl>

#### Type Constraints
Expand Down Expand Up @@ -2493,14 +2505,17 @@ This version of the operator has been available since version 1 of the 'com.micr
per-chunk system (I + M) is arbitrarily ill-conditioned and the recurrence diverges. Either
normalize upstream or set `qk_l2_norm=1` to have the operator do it.

Fused activations. `gate_activation='qwen'` computes the effective decay in float32 from the
Fused activations. `gate_activation='softplus'` computes the effective decay in float32 from the
raw projection carried by `decay`:

g = -exp(a_log) * Softplus(decay + dt_bias)

`beta_activation='sigmoid'` applies a sigmoid to `beta`, and `qk_l2_norm=1` L2-normalizes each
query and key head vector. Folding these in avoids materializing the intermediates and keeps
the gate arithmetic in float32 independent of the input type.
Decay and beta may be float or the query element type (both use the same type). CUDA widens
FP16/BF16 gate inputs to float before any gate arithmetic, avoiding standalone lossless casts.
State, a_log, and dt_bias remain float. WebGPU currently accepts float decay and beta only.


#### Version
Expand All @@ -2515,7 +2530,7 @@ This version of the operator has been available since version 1 of the 'com.micr
<dt><tt>chunk_size</tt> : int</dt>
<dd>Tuning hint for the chunk-parallel prefill algorithm. On CUDA, 32 pins the narrow chunk and any other value lets the implementation select the widest chunk the device can hold. On WebGPU, 16 opts into the chunkwise prefill route on supported Apple silicon; default 64 retains recurrent execution. Default 64.</dd>
<dt><tt>gate_activation</tt> : string</dt>
<dd>'none' (default) treats `decay` as the effective log-space decay. 'qwen' computes -exp(a_log) * Softplus(decay + dt_bias) in float32.</dd>
<dd>'none' (default) treats `decay` as the effective log-space decay. 'softplus' computes -exp(a_log) * Softplus(decay + dt_bias) in float32. 'qwen' is accepted as a legacy alias of 'softplus' with identical behavior.</dd>
<dt><tt>qk_l2_norm</tt> : int</dt>
<dd>When 1, L2-normalize each query and key head vector before the recurrence. Default 0.</dd>
<dt><tt>scale</tt> : float</dt>
Expand All @@ -2537,16 +2552,16 @@ This version of the operator has been available since version 1 of the 'com.micr
<dd>Value, shape (total_tokens, num_heads_v, head_size_v)</dd>
<dt><tt>cu_seqlens</tt> (optional) : TI</dt>
<dd>Exclusive prefix sums of the per-request token counts, shape (batch_size + 1). Absent means uniform packing.</dd>
<dt><tt>decay</tt> (optional) : TS</dt>
<dd>Log-space decay, shape (total_tokens, num_heads_v) for a scalar per-head decay or (total_tokens, num_heads_v, head_size_qk) for a per-key-dimension decay.</dd>
<dt><tt>beta</tt> (optional) : TS</dt>
<dd>Update rate, shape (total_tokens, num_heads_v)</dd>
<dt><tt>decay</tt> (optional) : TG</dt>
<dd>Log-space decay, shape (total_tokens, num_heads_v) for a scalar per-head decay or (total_tokens, num_heads_v, head_size_qk) for a per-key-dimension decay. Float or the query element type; converted to float before gate arithmetic.</dd>
<dt><tt>beta</tt> (optional) : TG</dt>
<dd>Update rate, shape (total_tokens, num_heads_v). Same element type as decay.</dd>
<dt><tt>initial_state</tt> (optional) : TS</dt>
<dd>Recurrent state, shape (batch_size, num_heads_v, head_size_v, head_size_qk), V-major. Required for packed QKV. May alias final_state.</dd>
<dt><tt>a_log</tt> (optional) : TS</dt>
<dd>Per-head A_log, shape (num_heads_v). Requires gate_activation=qwen.</dd>
<dd>Per-head A_log, shape (num_heads_v). Requires gate_activation=softplus.</dd>
<dt><tt>dt_bias</tt> (optional) : TS</dt>
<dd>Per-head gate bias, shape (num_heads_v). Requires gate_activation=qwen.</dd>
<dd>Per-head gate bias, shape (num_heads_v). Requires gate_activation=softplus.</dd>
<dt><tt>capture_count</tt> (optional) : TI</dt>
<dd>Number of leading local token transitions to capture for each request, shape (batch_size). Clamped on device to [0, min(state_update_capacity, sequence_length)]. Required exactly when state_update_capacity is positive.</dd>
<dt><tt>state_update_active</tt> (optional) : TI</dt>
Expand All @@ -2570,7 +2585,9 @@ This version of the operator has been available since version 1 of the 'com.micr
<dt><tt>T</tt> : tensor(float), tensor(float16), tensor(bfloat16)</dt>
<dd>Constrain query/key/value/output types.</dd>
<dt><tt>TS</tt> : tensor(float)</dt>
<dd>State, gate, beta and compact state-update tensors are always float.</dd>
<dd>State, gate parameters and compact state-update tensors are always float.</dd>
<dt><tt>TG</tt> : tensor(float), tensor(float16), tensor(bfloat16)</dt>
<dd>Decay and beta are float or match the query element type. Gate arithmetic is float.</dd>
<dt><tt>TI</tt> : tensor(int32)</dt>
<dd>Constrain index and count tensors to int32.</dd>
</dl>
Expand Down
6 changes: 3 additions & 3 deletions docs/OperatorKernels.md
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,7 @@ The **OpSet Version** column uses the following notation:
|BifurcationDetector|*in* src_tokens:**T**<br> *in* cur_tokens:**T**<br> *in* prev_suffix_match_idx:**T**<br> *in* pred_tokens:**T**<br> *out* tokens:**T**<br> *out* suffix_match_idx:**T**|1+|**T** = tensor(int64)|
|BranchwiseRMSNorm|*in* X:**T**<br> *in* scale:**M**<br> *out* Y:**T**|1+|**M** = tensor(bfloat16), tensor(float), tensor(float16)<br/> **T** = tensor(bfloat16), tensor(float), tensor(float16)|
|CDist|*in* A:**T**<br> *in* B:**T**<br> *out* C:**T**|1+|**T** = tensor(double), tensor(float)|
|CausalConvWithState|*in* input:**T**<br> *in* weight:**T**<br> *in* bias:**T**<br> *in* past_state:**T**<br> *out* output:**T**<br> *out* present_state:**T**|1+|**T** = tensor(float)|
|CausalConvWithState|*in* input:**T**<br> *in* weight:**T**<br> *in* bias:**T**<br> *in* past_state:**T**<br> *out* output:**T**<br> *out* present_state:**T**<br> *out* state_update:**T**|1+|**T** = tensor(float)|
|ConvTransposeWithDynamicPads|*in* X:**T**<br> *in* W:**T**<br> *in* Pads:**tensor(int64)**<br> *in* B:**T**<br> *out* Y:**T**|1+|**T** = tensor(float)|
|CropAndResize|*in* X:**T1**<br> *in* rois:**T1**<br> *in* batch_indices:**T2**<br> *in* crop_size:**T2**<br> *out* Y:**T1**|1+|**T1** = tensor(float)<br/> **T2** = tensor(int32)|
|DecoderMaskedMultiHeadAttention|*in* query:**T**<br> *in* key:**T**<br> *in* value:**T**<br> *in* mask_index:**M**<br> *in* attention_bias:**T**<br> *in* past_key:**T**<br> *in* past_value:**T**<br> *in* past_sequence_length:**M**<br> *in* beam_width:**M**<br> *in* cache_indirection:**M**<br> *in* bias:**T**<br> *out* output:**T**<br> *out* present_key:**T**<br> *out* present_value:**T**<br> *out* qk:**QK**|1+|**T** = tensor(float)|
Expand Down Expand Up @@ -1103,7 +1103,7 @@ The **OpSet Version** column uses the following notation:
|BitmaskBiasDropout|*in* data:**T**<br> *in* bias:**T**<br> *in* residual:**T**<br> *in* ratio:**T1**<br> *in* training_mode:**T2**<br> *out* output:**T**<br> *out* mask:**T3**|1+|**T** = tensor(bfloat16), tensor(double), tensor(float), tensor(float16)<br/> **T1** = tensor(bfloat16), tensor(double), tensor(float), tensor(float16)<br/> **T2** = tensor(bool)<br/> **T3** = tensor(uint32)|
|BitmaskDropout|*in* data:**T**<br> *in* ratio:**T1**<br> *in* training_mode:**T2**<br> *out* output:**T**<br> *out* mask:**T3**|1+|**T** = tensor(bfloat16), tensor(double), tensor(float), tensor(float16)<br/> **T1** = tensor(bfloat16), tensor(double), tensor(float), tensor(float16)<br/> **T2** = tensor(bool)<br/> **T3** = tensor(uint32)|
|BranchwiseRMSNorm|*in* X:**T**<br> *in* scale:**M**<br> *out* Y:**T**|1+|**M** = tensor(bfloat16), tensor(float), tensor(float16)<br/> **T** = tensor(bfloat16), tensor(float), tensor(float16)|
|CausalConvWithState|*in* input:**T**<br> *in* weight:**T**<br> *in* bias:**T**<br> *in* past_state:**T**<br> *out* output:**T**<br> *out* present_state:**T**|1+|**T** = tensor(bfloat16), tensor(float), tensor(float16)|
|CausalConvWithState|*in* input:**T**<br> *in* weight:**T**<br> *in* bias:**T**<br> *in* past_state:**T**<br> *out* output:**T**<br> *out* present_state:**T**<br> *out* state_update:**T**|1+|**T** = tensor(bfloat16), tensor(float), tensor(float16)|
|ComplexMul|*in* A:**T**<br> *in* B:**T**<br> *out* C:**T**|1+|**T** = tensor(float), tensor(float16)|
|ComplexMulConj|*in* A:**T**<br> *in* B:**T**<br> *out* C:**T**|1+|**T** = tensor(float), tensor(float16)|
|ConvTransposeWithDynamicPads|*in* X:**T**<br> *in* W:**T**<br> *in* Pads:**tensor(int64)**<br> *in* B:**T**<br> *out* Y:**T**|1+|**T** = tensor(float)|
Expand All @@ -1120,7 +1120,7 @@ The **OpSet Version** column uses the following notation:
|FusedConv|*in* X:**T**<br> *in* W:**T**<br> *in* B:**T**<br> *in* Z:**T**<br> *out* Y:**T**|1+|**T** = tensor(float)|
|FusedMatMul|*in* A:**T**<br> *in* B:**T**<br> *out* Y:**T**|1+|**T** = tensor(bfloat16), tensor(double), tensor(float), tensor(float16)|
|GatedAdd|*in* X:**T**<br> *in* Y:**T**<br> *in* gate:**T**<br> *out* output:**T**|1+|**T** = tensor(bfloat16), tensor(float), tensor(float16)|
|GatedDeltaNet|*in* query:**T**<br> *in* key:**T**<br> *in* value:**T**<br> *in* cu_seqlens:**TI**<br> *in* decay:**TS**<br> *in* beta:**TS**<br> *in* initial_state:**TS**<br> *in* a_log:**TS**<br> *in* dt_bias:**TS**<br> *in* capture_count:**TI**<br> *in* state_update_active:**TI**<br> *out* output:**T**<br> *out* final_state:**TS**<br> *out* state_update:**TS**|1+|**T** = tensor(bfloat16), tensor(float), tensor(float16)<br/> **TI** = tensor(int32)<br/> **TS** = tensor(float)|
|GatedDeltaNet|*in* query:**T**<br> *in* key:**T**<br> *in* value:**T**<br> *in* cu_seqlens:**TI**<br> *in* decay:**TG**<br> *in* beta:**TG**<br> *in* initial_state:**TS**<br> *in* a_log:**TS**<br> *in* dt_bias:**TS**<br> *in* capture_count:**TI**<br> *in* state_update_active:**TI**<br> *out* output:**T**<br> *out* final_state:**TS**<br> *out* state_update:**TS**|1+|**T** = tensor(bfloat16), tensor(float), tensor(float16)<br/> **TG** = tensor(bfloat16), tensor(float), tensor(float16)<br/> **TI** = tensor(int32)<br/> **TS** = tensor(float)|
|GatedRMSNorm|*in* X:**T**<br> *in* scale:**T**<br> *in* gate:**T**<br> *out* Y:**T**|1+|**T** = tensor(bfloat16), tensor(float), tensor(float16)|
|GatedRelativePositionBias|*in* query_layer:**T**<br> *in* query_bias:**T**<br> *in* rel_pos:**T**<br> *in* weight:**T**<br> *in* bias:**T**<br> *in* eco_a:**T**<br> *in* token_offset:**M**<br> *out* output:**T**|1+|**T** = tensor(float), tensor(float16)|
|GatherBlockQuantized|*in* data:**T1**<br> *in* indices:**Tind**<br> *in* scales:**T2**<br> *in* zero_points:**T1**<br> *out* output:**T2**|1+|**T1** = tensor(float4e2m1), tensor(float8e4m3fn), tensor(float8e4m3fnuz), tensor(float8e5m2), tensor(float8e5m2fnuz), tensor(int4), tensor(uint4), tensor(uint8)<br/> **T2** = tensor(bfloat16), tensor(float), tensor(float16)<br/> **Tind** = tensor(int32), tensor(int64)|
Expand Down
Loading
Loading