2026-05-12 06:35:53 +03:00
""" HiDream-O1 two-pass attention: tokens [0, ar_len) are causal, [ar_len, T)
attend full K / V . Splitting Q at the boundary avoids the ( B , 1 , T , T ) additive
mask the general - purpose path would build ( ~ 500 MB at T ~ 16 K ) and lets the
gen half hit the user ' s preferred backend via optimized_attention.
"""
import torch
import comfy . ops
from comfy . ldm . modules . attention import optimized_attention
def make_two_pass_attention ( ar_len : int , transformer_options = None ) :
""" Build a two-pass attention callable. AR pass uses SDPA-causal directly, gen pass routes through optimized_attention.
The AR pass goes through SDPA directand bypasses wrappers , it is only ~ 1 % of T at typical edit sizes .
"""
2026-07-13 12:52:28 -07:00
def two_pass_attention ( q , k , v , heads , enable_gqa = False , * * kwargs ) :
2026-05-12 06:35:53 +03:00
B , H , T , D = q . shape
if T < k . shape [ 2 ] : # KV-cache hot path: Q is shorter than K/V (cached AR prefix is in K/V only), all fresh Q positions are in the gen region, single full-attention call
2026-07-13 12:52:28 -07:00
out = optimized_attention ( q , k , v , heads , mask = None , skip_reshape = True , skip_output_reshape = True , transformer_options = transformer_options , enable_gqa = enable_gqa )
2026-05-12 06:35:53 +03:00
elif ar_len > = T :
2026-07-13 12:52:28 -07:00
out = comfy . ops . scaled_dot_product_attention ( q , k , v , attn_mask = None , dropout_p = 0.0 , is_causal = True , enable_gqa = enable_gqa )
2026-05-12 06:35:53 +03:00
elif ar_len < = 0 :
2026-07-13 12:52:28 -07:00
out = optimized_attention ( q , k , v , heads , mask = None , skip_reshape = True , skip_output_reshape = True , transformer_options = transformer_options , enable_gqa = enable_gqa )
2026-05-12 06:35:53 +03:00
else :
out_ar = comfy . ops . scaled_dot_product_attention (
q [ : , : , : ar_len ] , k [ : , : , : ar_len ] , v [ : , : , : ar_len ] ,
2026-07-13 12:52:28 -07:00
attn_mask = None , dropout_p = 0.0 , is_causal = True , enable_gqa = enable_gqa ,
2026-05-12 06:35:53 +03:00
)
out_gen = optimized_attention (
q [ : , : , ar_len : ] , k , v , heads ,
mask = None , skip_reshape = True , skip_output_reshape = True ,
2026-07-13 12:52:28 -07:00
transformer_options = transformer_options , enable_gqa = enable_gqa ,
2026-05-12 06:35:53 +03:00
)
out = torch . cat ( [ out_ar , out_gen ] , dim = 2 )
return out . transpose ( 1 , 2 ) . reshape ( B , T , H * D )
return two_pass_attention