
    +h'                         S SK r S SKJrJrJrJr  S SKrS SKJr  SSK	J
r
JrJrJr  SSKJr  \R                   " \5      r " S S5      rg)    N)DictListTupleUnion   )	AttentionAttentionProcessor"PAGCFGIdentitySelfAttnProcessor2_0PAGIdentitySelfAttnProcessor2_0)loggingc                      \ rS rSrSrS rS r SS jrS r\	" 5       \
" 5       44S\\\\   4   S\\\4   4S	 jjr\S
\4S j5       r\S
\4S j5       r\S
\4S j5       r\S
\4S j5       r\S
\\\4   4S j5       rSrg)PAGMixin!   zZMixin class for [Pertubed Attention Guidance](https://huggingface.co/papers/2403.17377v1).c                 J   U R                   nUc  [        S5      eU(       a  US   OUS   n[        U S5      (       a  U R                  nOU R                  nS[
        R                  S[        4S jnS	 nU H  n/ n	UR                  5        He  u  pU" U5      (       d  M  [        R                  " X5      c  M-  U" X5      (       a  M<  [        R                  S
U
 35        U	R                  U5        Mg     [        U	5      S:X  a  [        SU 35      eU	 H	  nXKl        M     M     g)z1
Set the attention processor for the PAG layers.
NzNo PAG attention processors have been set. Set the attention processors by calling `set_pag_applied_layers` and passing the relevant parameters.r      unetmodulereturnc                 R    [        U [        5      =(       a    U R                  (       + $ )zA
Check if the module is self-attention module based on its name.
)
isinstancer   is_cross_attention)r   s    [/home/james-whalen/.local/lib/python3.13/site-packages/diffusers/pipelines/pag/pag_utils.pyis_self_attn6PAGMixin._set_pag_attn_processor.<locals>.is_self_attn5   s     fi0R9R9R5RR    c                     U R                  S5      S   n UR                  S5      S   nU R                  5       =(       a    UR                  5       =(       a    X:H  $ )N.)split	isnumeric)layer_idnames     r   is_fake_integral_match@PAGMixin._set_pag_attn_processor.<locals>.is_fake_integral_match;   sJ    ~~c*2.H::c?2&D%%'QDNN,<QAQQr   zApplying PAG to layer: z6Cannot find PAG layer to set attention processor for: )_pag_attn_processors
ValueErrorhasattrr   transformernnModuleboolnamed_modulesresearchloggerdebugappendlen	processor)selfpag_applied_layersdo_classifier_free_guidancepag_attn_processorspag_attn_procmodelr   r#   r!   target_modulesr"   r   s               r   _set_pag_attn_processor PAGMixin._set_pag_attn_processor$   s&    #77& c  3N+A.SfghSi4  #yyE#//E	S 	St 	S	R
 +HN % 3 3 5 !((		(1=28BBLL#:4&!AB"))&1 !6 >"a' #YZbYc!dee(#0  )+ +r   c                     U R                   (       a)  U R                  U R                  SU-
  -  -
  nUS:  a  SnU$ U R                  $ )zL
Get the scale factor for the perturbed attention guidance at timestep `t`.
i  r   )do_pag_adaptive_scaling	pag_scalepag_adaptive_scale)r4   tsignal_scales      r   _get_pag_scalePAGMixin._get_pag_scaleX   sG    
 ''>>D,C,Ctax,PPLa >>!r   c                     U R                  U5      nU(       a'  UR                  S5      u  pxn	UX8U-
  -  -   XhU	-
  -  -   nOUR                  S5      u  pXX-
  -  -   nU(       a  X4$ U$ )a>  
Apply perturbed attention guidance to the noise prediction.

Args:
    noise_pred (torch.Tensor): The noise prediction tensor.
    do_classifier_free_guidance (bool): Whether to apply classifier-free guidance.
    guidance_scale (float): The scale factor for the guidance term.
    t (int): The current time step.
    return_pred_text (bool): Whether to return the text noise prediction.

Returns:
    Union[torch.Tensor, Tuple[torch.Tensor, torch.Tensor]]: The updated noise prediction tensor after applying
    perturbed attention guidance and the text noise prediction.
r      )rC   chunk)
r4   
noise_predr6   guidance_scalerA   return_pred_textr?   noise_pred_uncondnoise_pred_textnoise_pred_perturbs
             r   #_apply_perturbed_attention_guidance,PAGMixin._apply_perturbed_attention_guidancee   s    " ''*	&EOEUEUVWEXB0B! 6G$GHI1CCDE  3=2B2B12E/O(8\+]]J..r   c                 r    [         R                  " U/S-  SS9nU(       a  [         R                  " X!/SS9nU$ )aj  
Prepares the perturbed attention guidance for the PAG model.

Args:
    cond (torch.Tensor): The conditional input tensor.
    uncond (torch.Tensor): The unconditional input tensor.
    do_classifier_free_guidance (bool): Flag indicating whether to perform classifier-free guidance.

Returns:
    torch.Tensor: The prepared perturbed attention guidance tensor.
rF   r   )dim)torchcat)r4   conduncondr6   s       r   %_prepare_perturbed_attention_guidance.PAGMixin._prepare_perturbed_attention_guidance   s4     yy$!+&99f^3Dr   r5   r7   c                 v   [        U S5      (       d  SU l        [        U[        5      (       d  U/nUb/  [        U[        5      (       a  [        U5      S:w  a  [        S5      e[        [        U5      5       H3  n[        X   [        5      (       a  M  [        S[        X   5       35      e   Xl
        X l        g)a  
Set the self-attention layers to apply PAG. Raise ValueError if the input is invalid.

Args:
    pag_applied_layers (`str` or `List[str]`):
        One or more strings identifying the layer names, or a simple regex for matching multiple layers, where
        PAG is to be applied. A few ways of expected usage are as follows:
          - Single layers specified as - "blocks.{layer_index}"
          - Multiple layers as a list - ["blocks.{layers_index_1}", "blocks.{layer_index_2}", ...]
          - Multiple layers as a block name - "mid"
          - Multiple layers as regex - "blocks.({layer_index_1}|{layer_index_2})"
    pag_attn_processors:
        (`Tuple[AttentionProcessor, AttentionProcessor]`, defaults to `(PAGCFGIdentitySelfAttnProcessor2_0(),
        PAGIdentitySelfAttnProcessor2_0())`): A tuple of two attention processors. The first attention
        processor is for PAG with Classifier-free guidance enabled (conditional and unconditional). The second
        attention processor is for PAG with CFG disabled (unconditional only).
r%   NrF   z,Expected a tuple of two attention processorsz:Expected either a string or a list of string but got type )r'   r%   r   listtupler2   r&   rangestrtyper5   )r4   r5   r7   is       r   set_pag_applied_layersPAGMixin.set_pag_applied_layers   s    4 t344(,D%,d33"4!5*1599SAT=UYZ=Z !OPPs-./A03S99 PQUVhVkQlPmn  0 #5$7!r   r   c                     U R                   $ )z:Get the scale factor for the perturbed attention guidance.)
_pag_scaler4   s    r   r?   PAGMixin.pag_scale   s     r   c                     U R                   $ )zCGet the adaptive scale factor for the perturbed attention guidance.)_pag_adaptive_scalerc   s    r   r@   PAGMixin.pag_adaptive_scale   s     '''r   c                     U R                   S:  =(       a.    U R                  S:  =(       a    [        U R                  5      S:  $ )zNCheck if the adaptive scaling is enabled for the perturbed attention guidance.r   )rf   rb   r2   r5   rc   s    r   r>    PAGMixin.do_pag_adaptive_scaling   s9     ''!+h!0ChDLcLcHdghHhhr   c                 ^    U R                   S:  =(       a    [        U R                  5      S:  $ )z5Check if the perturbed attention guidance is enabled.r   )rb   r2   r5   rc   s    r   do_perturbed_attention_guidance(PAGMixin.do_perturbed_attention_guidance   s(     "Gs4+B+B'Ca'GGr   c                 |   U R                   c  0 $ U R                    Vs1 s H  oR                  iM     nn0 n[        U S5      (       a  U R                  nO)[        U S5      (       a  U R                  nO[        S5      eUR                  R                  5        H  u  pVUR                  U;   d  M  XcU'   M     U$ s  snf )z
Returns:
    `dict` of PAG attention processors: A dictionary contains all PAG attention processors used in the model
    with the key as the name of the layer.
r   r(   zNo denoiser module found.)r%   	__class__r'   r   r(   r&   attn_processorsitems)r4   xvalid_attn_processors
processorsdenoiser_moduler"   procs          r   r7   PAGMixin.pag_attn_processors   s     $$,I6:6O6O P6O6O P
 4  "iiOT=))"..O899)99??AJD~~!66#'4  B ! !Qs   B9)r%   r5   N)F)__name__
__module____qualname____firstlineno____doc__r;   rC   rN   rV   r
   r   r   r\   r   r   r	   r_   propertyfloatr?   r@   r+   r>   rk   r   r7   __static_attributes__ r   r   r   r   !   s    e21h" \a@. /0+-N
*8!#tCy.1*8 ##57I#IJ*8X 5   (E ( ( i i i H H H T#/A*A%B  r   r   )r-   typingr   r   r   r   rR   torch.nnr)   models.attention_processorr   r	   r
   r   utilsr   
get_loggerrw   r/   r   r   r   r   <module>r      sC    
 + +     
		H	%R Rr   