88from typing import List , Optional
99
1010import torch
11+ import torch .nn as nn
1112from diffusers .models .attention import FeedForward
1213from diffusers .models .attention_processor import Attention
1314from diffusers .models .transformers .transformer_z_image import FeedForward as ZImageFeedForward
1617
1718from nunchaku .models .unets .unet_sdxl import NunchakuSDXLFeedForward
1819
19- from ...utils import get_precision
20+ from ...utils import get_precision , pad_tensor
2021from ..attention import NunchakuBaseAttention
2122from ..attention_processors .zimage import NunchakuZSingleStreamAttnProcessor
23+ from ..embeddings import pack_rotemb
2224from ..linear import SVDQW4A4Linear
2325from ..utils import fuse_linears
2426from .utils import NunchakuModelLoaderMixin , patch_scale_key
2527
2628
29+ class NunchakuZImageRopeHook :
30+
31+ def __init__ (self ):
32+ self .packed_cache = {}
33+
34+ def __call__ (self , module : nn .Module , input_args : tuple , input_kwargs : dict ):
35+ freqs_cis : torch .Tensor = input_kwargs .get ("freqs_cis" , None )
36+ if freqs_cis is None :
37+ return None
38+ cache_key = freqs_cis .data_ptr ()
39+ packed_freqs_cis = self .packed_cache .get (cache_key , None )
40+ if packed_freqs_cis is None :
41+ packed_freqs_cis = torch .view_as_real (freqs_cis ).unsqueeze (3 )
42+ packed_freqs_cis = torch .flip (packed_freqs_cis , dims = [- 1 ])
43+ packed_freqs_cis = pack_rotemb (pad_tensor (packed_freqs_cis , 256 , 1 ))
44+ self .packed_cache [cache_key ] = packed_freqs_cis
45+ new_input_kwargs = input_kwargs .copy ()
46+ new_input_kwargs ["freqs_cis" ] = packed_freqs_cis
47+ return input_args , new_input_kwargs
48+
49+
2750class NunchakuZImageAttention (NunchakuBaseAttention ):
2851 """
2952 Nunchaku-optimized Attention module for ZImage with quantized and fused QKV projections.
@@ -198,6 +221,7 @@ def _convert_feed_forward(block_list: List[ZImageTransformerBlock]):
198221 for _ , block in enumerate (block_list ):
199222 block .feed_forward = _convert_z_image_ff (block .feed_forward )
200223
224+ self .skip_refiners = skip_refiners
201225 _patch_transformer_block (self .layers )
202226 if skip_refiners :
203227 _convert_feed_forward (self .noise_refiner )
@@ -207,6 +231,38 @@ def _convert_feed_forward(block_list: List[ZImageTransformerBlock]):
207231 _patch_transformer_block (self .context_refiner )
208232 return self
209233
234+ def register_rope_hook (self , rope_hook : NunchakuZImageRopeHook ):
235+ self .rope_hook_handles = []
236+ for _ , ly in enumerate (self .layers ):
237+ self .rope_hook_handles .append (ly .attention .register_forward_pre_hook (rope_hook , with_kwargs = True ))
238+ if not self .skip_refiners :
239+ for _ , nr in enumerate (self .noise_refiner ):
240+ self .rope_hook_handles .append (nr .attention .register_forward_pre_hook (rope_hook , with_kwargs = True ))
241+ for _ , cr in enumerate (self .context_refiner ):
242+ self .rope_hook_handles .append (cr .attention .register_forward_pre_hook (rope_hook , with_kwargs = True ))
243+
244+ def unregister_rope_hook (self ):
245+ for h in self .rope_hook_handles :
246+ h .remove ()
247+ self .rope_hook_handles .clear ()
248+
249+ def forward (
250+ self ,
251+ x : List [torch .Tensor ],
252+ t ,
253+ cap_feats : List [torch .Tensor ],
254+ patch_size = 2 ,
255+ f_patch_size = 1 ,
256+ return_dict : bool = True ,
257+ ):
258+ rope_hook = NunchakuZImageRopeHook ()
259+ self .register_rope_hook (rope_hook )
260+ try :
261+ return super ().forward (x , t , cap_feats , patch_size , f_patch_size , return_dict )
262+ finally :
263+ self .unregister_rope_hook ()
264+ del rope_hook
265+
210266 @classmethod
211267 @utils .validate_hf_hub_args
212268 def from_pretrained (cls , pretrained_model_name_or_path : str | os .PathLike [str ], ** kwargs ):
0 commit comments