@@ -74,7 +74,8 @@ def fused_recurrent_gated_delta_rule_fwd_kernel(
7474
7575 b_h = tl .zeros ([BK , BV ], dtype = tl .float32 )
7676 if USE_INITIAL_STATE :
77- p_h0 = h0 + i_nh * K * V + o_k [:, None ] * V + o_v [None , :]
77+ # Pool layout [N, HV, V, K] with K innermost: offset v*K + k.
78+ p_h0 = h0 + i_nh * V * K + o_k [:, None ] + o_v [None , :] * K
7879 b_h += tl .load (p_h0 , mask = mask_h , other = 0 ).to (tl .float32 )
7980
8081 for _ in range (0 , T ):
@@ -110,7 +111,8 @@ def fused_recurrent_gated_delta_rule_fwd_kernel(
110111 p_beta += HV * (V if IS_BETA_HEADWISE else 1 )
111112
112113 if STORE_FINAL_STATE :
113- p_ht = ht + i_nh * K * V + o_k [:, None ] * V + o_v [None , :]
114+ # Pool layout [N, HV, V, K].
115+ p_ht = ht + i_nh * V * K + o_k [:, None ] + o_v [None , :] * K
114116 tl .store (p_ht , b_h .to (p_ht .dtype .element_ty ), mask = mask_h )
115117
116118
@@ -137,7 +139,8 @@ def fused_recurrent_gated_delta_rule_fwd(
137139
138140 o = q .new_empty (NK , * v .shape )
139141 if output_final_state :
140- final_state = q .new_empty (N , HV , K , V , dtype = torch .float32 )
142+ # Pool layout: [N, HV, V, K] (K innermost).
143+ final_state = q .new_empty (N , HV , V , K , dtype = torch .float32 )
141144 else :
142145 final_state = None
143146
@@ -240,19 +243,19 @@ def fused_recurrent_gated_delta_rule(
240243 Scale factor for the RetNet attention scores.
241244 If not provided, it will default to `1 / sqrt(K)`. Default: `None`.
242245 initial_state (Optional[torch.Tensor]):
243- Initial state of shape `[N, HV, K, V ]` for `N` input sequences.
246+ Initial state of shape `[N, HV, V, K ]` for `N` input sequences.
244247 For equal-length input sequences, `N` equals the batch size `B`.
245248 Default: `None`.
246249 output_final_state (Optional[bool]):
247- Whether to output the final state of shape `[N, HV, K, V ]`. Default: `False`.
250+ Whether to output the final state of shape `[N, HV, V, K ]`. Default: `False`.
248251 cu_seqlens (torch.LongTensor):
249252 Cumulative sequence lengths of shape `[N+1]` used for variable-length training,
250253 consistent with the FlashAttention API.
251254 Returns:
252255 o (torch.Tensor):
253256 Outputs of shape `[B, T, HV, V]`.
254257 final_state (torch.Tensor):
255- Final state of shape `[N, HV, K, V ]` if `output_final_state=True` else `None`.
258+ Final state of shape `[N, HV, V, K ]` if `output_final_state=True` else `None`.
256259 Examples::
257260 >>> import torch
258261 >>> import torch.nn.functional as F
@@ -265,7 +268,7 @@ def fused_recurrent_gated_delta_rule(
265268 >>> v = torch.randn(B, T, HV, V, device='cuda')
266269 >>> g = F.logsigmoid(torch.rand(B, T, HV, device='cuda'))
267270 >>> beta = torch.rand(B, T, HV, device='cuda').sigmoid()
268- >>> h0 = torch.randn(B, HV, K, V , device='cuda')
271+ >>> h0 = torch.randn(B, HV, V, K , device='cuda')
269272 >>> o, ht = fused_gated_recurrent_delta_rule(
270273 q, k, v, g, beta,
271274 initial_state=h0,
@@ -387,8 +390,9 @@ def fused_recurrent_gated_delta_rule_update_fwd_kernel(
387390 idx = tl .load (h0_indices + i_n )
388391 # Add bounds checking for idx
389392 if idx >= 0 : # Assuming negative indices are invalid
390- p_h0 = (h0_source + idx * HV * K * V + i_hv * K * V +
391- o_k [:, None ] * V + o_v [None , :])
393+ # Pool layout [slots, HV, V, K], K innermost (stride 1).
394+ p_h0 = (h0_source + idx * HV * V * K + i_hv * V * K + o_k [:, None ] +
395+ o_v [None , :] * K )
392396 b_h += tl .load (p_h0 , mask = mask_h , other = 0 ).to (tl .float32 )
393397
394398 # Prepare intermediate state cache variables if enabled
@@ -427,12 +431,12 @@ def fused_recurrent_gated_delta_rule_update_fwd_kernel(
427431 # store intermediate states if enabled
428432 if CACHE_INTERMEDIATE_STATES :
429433 if cache_idx >= 0 :
430- # Compute cache pointer for this step
431- step_offset = step_idx * HV * K * V
434+ # Match the SSM pool layout [slots, HV, V, K] with K innermost.
435+ step_offset = step_idx * HV * V * K
432436 cache_ptr = (intermediate_states_buffer +
433- cache_idx * cache_steps * HV * K * V +
434- step_offset + i_hv * K * V + o_k [:, None ] * V +
435- o_v [None , :])
437+ cache_idx * cache_steps * HV * V * K +
438+ step_offset + i_hv * V * K + o_k [:, None ] +
439+ o_v [None , :] * K )
436440 tl .store (cache_ptr ,
437441 b_h .to (cache_ptr .dtype .element_ty ),
438442 mask = mask_h )
@@ -447,12 +451,12 @@ def fused_recurrent_gated_delta_rule_update_fwd_kernel(
447451 p_beta += HV * (V if IS_BETA_HEADWISE else 1 )
448452
449453 # Store final state back to h0_source with bounds checking
450- # ssm states
454+ # ssm states (pool layout [slots, HV, V, K], K innermost).
451455 if not DISABLE_STATE_UPDATE :
452456 idx = tl .load (h0_indices + i_n )
453457 if idx >= 0 : # Add bounds checking
454- p_h0 = (h0_source + idx * HV * K * V + i_hv * K * V +
455- o_k [:, None ] * V + o_v [None , :])
458+ p_h0 = (h0_source + idx * HV * V * K + i_hv * V * K + o_k [:, None ] +
459+ o_v [None , :] * K )
456460 tl .store (p_h0 , b_h .to (p_h0 .dtype .element_ty ), mask = mask_h )
457461
458462
0 commit comments