@@ -340,6 +340,8 @@ class _HubKernelConfig:
340340 AttentionBackendName ._FLASH_3_VARLEN_HUB : _HubKernelConfig (
341341 repo_id = "kernels-community/flash-attn3" ,
342342 function_attr = "flash_attn_varlen_func" ,
343+ wrapped_forward_attr = "flash_attn_interface._flash_attn_forward" ,
344+ wrapped_backward_attr = "flash_attn_interface._flash_attn_backward" ,
343345 version = 1 ,
344346 ),
345347 AttentionBackendName .FLASH_HUB : _HubKernelConfig (
@@ -1612,6 +1614,194 @@ def _flash_attention_3_hub_backward_op(
16121614 return grad_query , grad_key , grad_value
16131615
16141616
1617+ def _flash_attention_3_varlen_hub_forward_op (
1618+ ctx : torch .autograd .function .FunctionCtx ,
1619+ query : torch .Tensor ,
1620+ key : torch .Tensor ,
1621+ value : torch .Tensor ,
1622+ attn_mask : torch .Tensor | None = None ,
1623+ dropout_p : float = 0.0 ,
1624+ is_causal : bool = False ,
1625+ scale : float | None = None ,
1626+ enable_gqa : bool = False ,
1627+ return_lse : bool = False ,
1628+ _save_ctx : bool = True ,
1629+ _parallel_config : "ParallelConfig" | None = None ,
1630+ * ,
1631+ window_size : tuple [int , int ] = (- 1 , - 1 ),
1632+ softcap : float = 0.0 ,
1633+ num_splits : int = 1 ,
1634+ pack_gqa : bool | None = None ,
1635+ deterministic : bool = False ,
1636+ sm_margin : int = 0 ,
1637+ ):
1638+ if dropout_p != 0.0 :
1639+ raise ValueError ("`dropout_p` is not yet supported for flash-attn 3 varlen hub kernels." )
1640+ if enable_gqa :
1641+ raise ValueError ("`enable_gqa` is not yet supported for flash-attn 3 varlen hub kernels." )
1642+
1643+ config = _HUB_KERNELS_REGISTRY [AttentionBackendName ._FLASH_3_VARLEN_HUB ]
1644+ wrapped_forward_fn = config .wrapped_forward_fn
1645+ wrapped_backward_fn = config .wrapped_backward_fn
1646+ if wrapped_forward_fn is None or wrapped_backward_fn is None :
1647+ raise RuntimeError (
1648+ "Flash attention 3 varlen hub kernels must expose `flash_attn_interface._flash_attn_forward` and "
1649+ "`flash_attn_interface._flash_attn_backward` for context parallel execution."
1650+ )
1651+
1652+ if scale is None :
1653+ scale = query .shape [- 1 ] ** (- 0.5 )
1654+
1655+ batch_size , seq_len_q , num_heads , _ = query .shape
1656+ _ , seq_len_kv , _ , _ = key .shape
1657+
1658+ if attn_mask is not None :
1659+ attn_mask = _normalize_attn_mask (attn_mask , batch_size , seq_len_kv )
1660+ (_ , seqlens_k ), (cu_seqlens_q , cu_seqlens_k ), (_ , max_seqlen_k ) = (
1661+ _prepare_for_flash_attn_or_sage_varlen_with_mask (batch_size , seq_len_q , attn_mask , query .device )
1662+ )
1663+ indices_k = attn_mask .flatten ().nonzero (as_tuple = False ).flatten ()
1664+ query_packed = query .flatten (0 , 1 )
1665+ key_packed = key .reshape (- 1 , * key .shape [2 :])[indices_k ]
1666+ value_packed = value .reshape (- 1 , * value .shape [2 :])[indices_k ]
1667+ max_seqlen_q = seq_len_q
1668+ else :
1669+ (_ , seqlens_k ), (cu_seqlens_q , cu_seqlens_k ), (max_seqlen_q , max_seqlen_k ) = (
1670+ _prepare_for_flash_attn_or_sage_varlen_without_mask (batch_size , seq_len_q , seq_len_kv , query .device )
1671+ )
1672+ query_packed = query .flatten (0 , 1 )
1673+ key_packed = key .flatten (0 , 1 )
1674+ value_packed = value .flatten (0 , 1 )
1675+ seqlens_k = None
1676+
1677+ out_packed , softmax_lse , * _ = wrapped_forward_fn (
1678+ query_packed ,
1679+ key_packed ,
1680+ value_packed ,
1681+ None , # k_new
1682+ None , # v_new
1683+ None , # qv
1684+ None , # out_
1685+ cu_seqlens_q ,
1686+ cu_seqlens_k ,
1687+ None , # cu_seqlens_k_new
1688+ None , # seqused_q
1689+ None , # seqused_k
1690+ max_seqlen_q ,
1691+ max_seqlen_k ,
1692+ None , # page_table
1693+ None , # kv_batch_idx
1694+ None , # leftpad_k
1695+ None , # rotary_cos
1696+ None , # rotary_sin
1697+ None , # seqlens_rotary
1698+ None , # q_descale
1699+ None , # k_descale
1700+ None , # v_descale
1701+ scale ,
1702+ causal = is_causal ,
1703+ window_size_left = window_size [0 ],
1704+ window_size_right = window_size [1 ],
1705+ attention_chunk = 0 ,
1706+ softcap = softcap ,
1707+ rotary_interleaved = True ,
1708+ scheduler_metadata = None ,
1709+ num_splits = num_splits ,
1710+ pack_gqa = pack_gqa ,
1711+ sm_margin = sm_margin ,
1712+ )
1713+
1714+ out = out_packed .view (batch_size , seq_len_q , * out_packed .shape [1 :])
1715+
1716+ if _save_ctx :
1717+ ctx .save_for_backward (
1718+ query_packed , key_packed , value_packed , out_packed , softmax_lse , cu_seqlens_q , cu_seqlens_k
1719+ )
1720+ ctx .seqlens_k = seqlens_k # None if unmasked
1721+ ctx .indices_k = indices_k if attn_mask is not None else None
1722+ ctx .max_seqlen_q = max_seqlen_q
1723+ ctx .max_seqlen_k = max_seqlen_k
1724+ ctx .batch_size = batch_size
1725+ ctx .seq_len_q = seq_len_q
1726+ ctx .seq_len_kv = seq_len_kv
1727+ ctx .num_heads = num_heads
1728+ ctx .scale = scale
1729+ ctx .is_causal = is_causal
1730+ ctx .window_size = window_size
1731+ ctx .softcap = softcap
1732+ ctx .deterministic = deterministic
1733+ ctx .sm_margin = sm_margin
1734+
1735+ # softmax_lse in varlen mode: (num_heads, total_q) -> (batch_size, seq_len_q, num_heads)
1736+ lse_sp = softmax_lse .view (num_heads , batch_size , seq_len_q ).permute (1 , 2 , 0 ).contiguous ()
1737+
1738+ return (out , lse_sp ) if return_lse else out
1739+
1740+
1741+ def _flash_attention_3_varlen_hub_backward_op (
1742+ ctx : torch .autograd .function .FunctionCtx ,
1743+ grad_out : torch .Tensor ,
1744+ * args ,
1745+ ** kwargs ,
1746+ ):
1747+ config = _HUB_KERNELS_REGISTRY [AttentionBackendName ._FLASH_3_VARLEN_HUB ]
1748+ wrapped_backward_fn = config .wrapped_backward_fn
1749+ if wrapped_backward_fn is None :
1750+ raise RuntimeError (
1751+ "Flash attention 3 varlen hub kernels must expose `flash_attn_interface._flash_attn_backward` "
1752+ "for context parallel execution."
1753+ )
1754+
1755+ query_packed , key_packed , value_packed , out_packed , softmax_lse , cu_seqlens_q , cu_seqlens_k = ctx .saved_tensors
1756+
1757+ grad_out_packed = grad_out .flatten (0 , 1 )
1758+ grad_query , grad_key , grad_value = (
1759+ torch .empty_like (query_packed ),
1760+ torch .empty_like (key_packed ),
1761+ torch .empty_like (value_packed ),
1762+ )
1763+
1764+ wrapped_backward_fn (
1765+ grad_out_packed ,
1766+ query_packed ,
1767+ key_packed ,
1768+ value_packed ,
1769+ out_packed ,
1770+ softmax_lse ,
1771+ cu_seqlens_q ,
1772+ cu_seqlens_k ,
1773+ None ,
1774+ None , # seqused_q, seqused_k
1775+ ctx .max_seqlen_q ,
1776+ ctx .max_seqlen_k ,
1777+ grad_query ,
1778+ grad_key ,
1779+ grad_value ,
1780+ ctx .scale ,
1781+ ctx .is_causal ,
1782+ ctx .window_size [0 ],
1783+ ctx .window_size [1 ],
1784+ ctx .softcap ,
1785+ ctx .deterministic ,
1786+ ctx .sm_margin ,
1787+ )
1788+
1789+ grad_query = grad_query .view (ctx .batch_size , ctx .seq_len_q , * grad_query .shape [1 :])
1790+
1791+ if ctx .seqlens_k is not None :
1792+ grad_key = _unpad_to_padded (grad_key , ctx .indices_k , ctx .batch_size , ctx .seq_len_kv )
1793+ grad_value = _unpad_to_padded (grad_value , ctx .indices_k , ctx .batch_size , ctx .seq_len_kv )
1794+ else :
1795+ grad_key = grad_key .view (ctx .batch_size , ctx .seq_len_kv , * grad_key .shape [1 :])
1796+ grad_value = grad_value .view (ctx .batch_size , ctx .seq_len_kv , * grad_value .shape [1 :])
1797+
1798+ grad_query = grad_query [..., : grad_out .shape [- 1 ]]
1799+ grad_key = grad_key [..., : grad_out .shape [- 1 ]]
1800+ grad_value = grad_value [..., : grad_out .shape [- 1 ]]
1801+
1802+ return grad_query , grad_key , grad_value
1803+
1804+
16151805def _sage_attention_forward_op (
16161806 ctx : torch .autograd .function .FunctionCtx ,
16171807 query : torch .Tensor ,
@@ -3007,7 +3197,7 @@ def _flash_attention_3_hub(
30073197@_AttentionBackendRegistry .register (
30083198 AttentionBackendName ._FLASH_3_VARLEN_HUB ,
30093199 constraints = [_check_device , _check_qkv_dtype_bf16_or_fp16 , _check_shape ],
3010- supports_context_parallel = False ,
3200+ supports_context_parallel = True ,
30113201)
30123202def _flash_attention_3_varlen_hub (
30133203 query : torch .Tensor ,
@@ -3019,44 +3209,74 @@ def _flash_attention_3_varlen_hub(
30193209 return_lse : bool = False ,
30203210 _parallel_config : "ParallelConfig" | None = None ,
30213211) -> torch .Tensor :
3212+ if _parallel_config is not None and _parallel_config .context_parallel_config .ring_degree > 1 :
3213+ raise NotImplementedError ("`ring_degree > 1` is not yet supported for the _FLASH_3_VARLEN_HUB backend." )
3214+
30223215 batch_size , seq_len_q , _ , _ = query .shape
30233216 _ , seq_len_kv , _ , _ = key .shape
30243217
3025- if attn_mask is not None :
3026- attn_mask = _normalize_attn_mask (attn_mask , batch_size , seq_len_kv )
3027- (_ , _ ), (cu_seqlens_q , cu_seqlens_k ), (max_seqlen_q , max_seqlen_k ) = (
3028- _prepare_for_flash_attn_or_sage_varlen_with_mask (batch_size , seq_len_q , attn_mask , query .device )
3029- )
3030- indices_k = attn_mask .flatten ().nonzero (as_tuple = False ).flatten ()
3031- key_packed = key .reshape (- 1 , * key .shape [2 :])[indices_k ]
3032- value_packed = value .reshape (- 1 , * value .shape [2 :])[indices_k ]
3033- else :
3034- (_ , _ ), (cu_seqlens_q , cu_seqlens_k ), (max_seqlen_q , max_seqlen_k ) = (
3035- _prepare_for_flash_attn_or_sage_varlen_without_mask (batch_size , seq_len_q , seq_len_kv , query .device )
3036- )
3037- key_packed = key .flatten (0 , 1 )
3038- value_packed = value .flatten (0 , 1 )
3218+ if _parallel_config is None :
3219+ if attn_mask is not None :
3220+ attn_mask = _normalize_attn_mask (attn_mask , batch_size , seq_len_kv )
3221+ (_ , _ ), (cu_seqlens_q , cu_seqlens_k ), (max_seqlen_q , max_seqlen_k ) = (
3222+ _prepare_for_flash_attn_or_sage_varlen_with_mask (batch_size , seq_len_q , attn_mask , query .device )
3223+ )
3224+ indices_k = attn_mask .flatten ().nonzero (as_tuple = False ).flatten ()
3225+ key_packed = key .reshape (- 1 , * key .shape [2 :])[indices_k ]
3226+ value_packed = value .reshape (- 1 , * value .shape [2 :])[indices_k ]
3227+ else :
3228+ (_ , _ ), (cu_seqlens_q , cu_seqlens_k ), (max_seqlen_q , max_seqlen_k ) = (
3229+ _prepare_for_flash_attn_or_sage_varlen_without_mask (batch_size , seq_len_q , seq_len_kv , query .device )
3230+ )
3231+ key_packed = key .flatten (0 , 1 )
3232+ value_packed = value .flatten (0 , 1 )
30393233
3040- query_packed = query .flatten (0 , 1 )
3234+ query_packed = query .flatten (0 , 1 )
30413235
3042- func = _HUB_KERNELS_REGISTRY [AttentionBackendName ._FLASH_3_VARLEN_HUB ].kernel_fn
3043- result = func (
3044- q = query_packed ,
3045- k = key_packed ,
3046- v = value_packed ,
3047- cu_seqlens_q = cu_seqlens_q ,
3048- cu_seqlens_k = cu_seqlens_k ,
3049- max_seqlen_q = max_seqlen_q ,
3050- max_seqlen_k = max_seqlen_k ,
3051- softmax_scale = scale ,
3052- causal = is_causal ,
3053- )
3054- if isinstance (result , tuple ):
3055- out , lse , * _ = result
3236+ func = _HUB_KERNELS_REGISTRY [AttentionBackendName ._FLASH_3_VARLEN_HUB ].kernel_fn
3237+ result = func (
3238+ q = query_packed ,
3239+ k = key_packed ,
3240+ v = value_packed ,
3241+ cu_seqlens_q = cu_seqlens_q ,
3242+ cu_seqlens_k = cu_seqlens_k ,
3243+ max_seqlen_q = max_seqlen_q ,
3244+ max_seqlen_k = max_seqlen_k ,
3245+ softmax_scale = scale ,
3246+ causal = is_causal ,
3247+ )
3248+ if isinstance (result , tuple ):
3249+ out , lse , * _ = result
3250+ else :
3251+ out = result
3252+ lse = None
3253+ out = out .unflatten (0 , (batch_size , - 1 ))
30563254 else :
3057- out = result
3058- lse = None
3059- out = out .unflatten (0 , (batch_size , - 1 ))
3255+ forward_op = functools .partial (
3256+ _flash_attention_3_varlen_hub_forward_op ,
3257+ window_size = (- 1 , - 1 ),
3258+ softcap = 0.0 ,
3259+ num_splits = 1 ,
3260+ pack_gqa = None ,
3261+ deterministic = False ,
3262+ sm_margin = 0 ,
3263+ )
3264+ out = _templated_context_parallel_attention (
3265+ query ,
3266+ key ,
3267+ value ,
3268+ attn_mask ,
3269+ 0.0 ,
3270+ is_causal ,
3271+ scale ,
3272+ False ,
3273+ return_lse ,
3274+ forward_op = forward_op ,
3275+ backward_op = _flash_attention_3_varlen_hub_backward_op ,
3276+ _parallel_config = _parallel_config ,
3277+ )
3278+ if return_lse :
3279+ out , lse = out
30603280
30613281 return (out , lse ) if return_lse else out
30623282
0 commit comments