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+ Hook class for caching and substition of packed `freqs_cis` tensor.
32+ """
33+
34+ def __init__ (self ):
35+ self .packed_cache = {}
36+
37+ def __call__ (self , module : nn .Module , input_args : tuple , input_kwargs : dict ):
38+ freqs_cis : torch .Tensor = input_kwargs .get ("freqs_cis" , None )
39+ if freqs_cis is None :
40+ return None
41+ cache_key = freqs_cis .data_ptr ()
42+ packed_freqs_cis = self .packed_cache .get (cache_key , None )
43+ if packed_freqs_cis is None :
44+ packed_freqs_cis = torch .view_as_real (freqs_cis ).unsqueeze (3 )
45+ packed_freqs_cis = torch .flip (packed_freqs_cis , dims = [- 1 ])
46+ packed_freqs_cis = pack_rotemb (pad_tensor (packed_freqs_cis , 256 , 1 ))
47+ self .packed_cache [cache_key ] = packed_freqs_cis
48+ new_input_kwargs = input_kwargs .copy ()
49+ new_input_kwargs ["freqs_cis" ] = packed_freqs_cis
50+ return input_args , new_input_kwargs
51+
52+
2753class NunchakuZImageAttention (NunchakuBaseAttention ):
2854 """
2955 Nunchaku-optimized Attention module for ZImage with quantized and fused QKV projections.
@@ -198,6 +224,7 @@ def _convert_feed_forward(block_list: List[ZImageTransformerBlock]):
198224 for _ , block in enumerate (block_list ):
199225 block .feed_forward = _convert_z_image_ff (block .feed_forward )
200226
227+ self .skip_refiners = skip_refiners
201228 _patch_transformer_block (self .layers )
202229 if skip_refiners :
203230 _convert_feed_forward (self .noise_refiner )
@@ -207,6 +234,43 @@ def _convert_feed_forward(block_list: List[ZImageTransformerBlock]):
207234 _patch_transformer_block (self .context_refiner )
208235 return self
209236
237+ def register_rope_hook (self , rope_hook : NunchakuZImageRopeHook ):
238+ self .rope_hook_handles = []
239+ for _ , ly in enumerate (self .layers ):
240+ self .rope_hook_handles .append (ly .attention .register_forward_pre_hook (rope_hook , with_kwargs = True ))
241+ if not self .skip_refiners :
242+ for _ , nr in enumerate (self .noise_refiner ):
243+ self .rope_hook_handles .append (nr .attention .register_forward_pre_hook (rope_hook , with_kwargs = True ))
244+ for _ , cr in enumerate (self .context_refiner ):
245+ self .rope_hook_handles .append (cr .attention .register_forward_pre_hook (rope_hook , with_kwargs = True ))
246+
247+ def unregister_rope_hook (self ):
248+ for h in self .rope_hook_handles :
249+ h .remove ()
250+ self .rope_hook_handles .clear ()
251+
252+ def forward (
253+ self ,
254+ x : List [torch .Tensor ],
255+ t ,
256+ cap_feats : List [torch .Tensor ],
257+ patch_size = 2 ,
258+ f_patch_size = 1 ,
259+ return_dict : bool = True ,
260+ ):
261+ """
262+ Adapted from diffusers.models.transformers.transformer_z_image.ZImageTransformer2DModel#forward
263+
264+ Register pre-forward hooks for caching and substitution of packed `freqs_cis` tensor for all attention submodules and unregister after forwarding is done.
265+ """
266+ rope_hook = NunchakuZImageRopeHook ()
267+ self .register_rope_hook (rope_hook )
268+ try :
269+ return super ().forward (x , t , cap_feats , patch_size , f_patch_size , return_dict )
270+ finally :
271+ self .unregister_rope_hook ()
272+ del rope_hook
273+
210274 @classmethod
211275 @utils .validate_hf_hub_args
212276 def from_pretrained (cls , pretrained_model_name_or_path : str | os .PathLike [str ], ** kwargs ):
0 commit comments