
    bi'                         d dl Z d dlmZmZmZmZ d dlZd dlmZ ddl	m
Z
mZmZmZ ddlmZ  ej                   e      Z G d d      Zy)    N)DictListTupleUnion   )	AttentionAttentionProcessor"PAGCFGIdentitySelfAttnProcessor2_0PAGIdentitySelfAttnProcessor2_0)loggingc                       e Zd ZdZd Zd Z	 ddZd Z e        e	       ffde
eee   f   deeef   fdZed	efd
       Zed	efd       Zed	efd       Zed	efd       Zed	eeef   fd       Zy)PAGMixinzZMixin class for [Pertubed Attention Guidance](https://huggingface.co/papers/2403.17377v1).c                    | j                   }|t        d      |r|d   n|d   }t        | d      r| j                  }n| j                  }dt
        j                  dt        fd}d	 }|D ]  }g }	|j                         D ]X  \  }
} ||      st        j                  ||
      & |||
      r0t        j                  d
|
        |	j                  |       Z t        |	      dk(  rt        d|       |	D ]	  }||_          y)zA
        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                 @    t        | t              xr | j                   S )zY
            Check if the module is self-attention module based on its name.
            )
isinstancer   is_cross_attention)r   s    \/home/cdr/jupyterlab/.venv/lib/python3.12/site-packages/diffusers/pipelines/pag/pag_utils.pyis_self_attnz6PAGMixin._set_pag_attn_processor.<locals>.is_self_attn5   s     fi0R9R9R5RR    c                     | j                  d      d   } |j                  d      d   }| j                         xr |j                         xr | |k(  S )N.)split	isnumeric)layer_idnames     r   is_fake_integral_matchz@PAGMixin._set_pag_attn_processor.<locals>.is_fake_integral_match;   sL    ~~c*2.H::c?2&D%%'QDNN,<QTAQ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_processorz PAGMixin._set_pag_attn_processor$   s4    #77& c  3N+A.SfghSi4 #yyE#//E	S 	St 	S	R
 + 	1HN % 3 3 5 2f !(		(D1=28TBLL#:4&!AB"))&12 >"a' #YZbYc!dee( 1#0 1+	1r   c                     | j                   r(| j                  | j                  d|z
  z  z
  }|dk  rd}|S | j                  S )z\
        Get the scale factor for the perturbed attention guidance at timestep `t`.
        i  r   )do_pag_adaptive_scaling	pag_scalepag_adaptive_scale)r1   tsignal_scales      r   _get_pag_scalezPAGMixin._get_pag_scaleX   sG    
 ''>>D,C,Ctax,PPLa >>!r   c                     | j                  |      }|r*|j                  d      \  }}}	||||z
  z  z   |||	z
  z  z   }n|j                  d      \  }}	||||	z
  z  z   }|r||fS |S )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      )r?   chunk)
r1   
noise_predr3   guidance_scaler=   return_pred_textr;   noise_pred_uncondnoise_pred_textnoise_pred_perturbs
             r   #_apply_perturbed_attention_guidancez,PAGMixin._apply_perturbed_attention_guidancee   s    " ''*	&EOEUEUVWEXB0B! O6G$GHI1CCDE  3=2B2B12E/O/(9J\8\+]]J..r   c                 r    t        j                  |gdz  d      }|rt        j                  ||gd      }|S )a  
        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.
        rA   r   )dim)torchcat)r1   conduncondr3   s       r   %_prepare_perturbed_attention_guidancez.PAGMixin._prepare_perturbed_attention_guidance   s6     yy$!+&99fd^3Dr   r2   r4   c                 N   t        | d      sd| _        t        |t              s|g}|)t        |t              rt        |      dk7  rt        d      t        t        |            D ]/  }t        ||   t              rt        dt        ||                 || _
        || _        y)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"   NrA   z,Expected a tuple of two attention processorsz:Expected either a string or a list of string but got type )r$   r"   r   listtupler/   r#   rangestrtyper2   )r1   r2   r4   is       r   set_pag_applied_layerszPAGMixin.set_pag_applied_layers   s    4 t34(,D%,d3"4!5*159SAT=UYZ=Z !OPPs-./ 	A03S9 PQUVhijVkQlPmn 	 #5$7!r   r   c                     | j                   S )z:Get the scale factor for the perturbed attention guidance.)
_pag_scaler1   s    r   r;   zPAGMixin.pag_scale   s     r   c                     | j                   S )zCGet the adaptive scale factor for the perturbed attention guidance.)_pag_adaptive_scaler[   s    r   r<   zPAGMixin.pag_adaptive_scale   s     '''r   c                 v    | j                   dkD  xr) | j                  dkD  xr t        | j                        dkD  S )zNCheck if the adaptive scaling is enabled for the perturbed attention guidance.r   )r]   rZ   r/   r2   r[   s    r   r:   z PAGMixin.do_pag_adaptive_scaling   s9     ''!+h!0ChDLcLcHdghHhhr   c                 T    | j                   dkD  xr t        | j                        dkD  S )z5Check if the perturbed attention guidance is enabled.r   )rZ   r/   r2   r[   s    r   do_perturbed_attention_guidancez(PAGMixin.do_perturbed_attention_guidance   s(     "Gs4+B+B'Ca'GGr   c                 \   | j                   i S | j                   D ch c]  }|j                   }}i }t        | d      r| j                  }n$t        | d      r| j                  }nt        d      |j                  j                         D ]  \  }}|j                  |v s|||<    |S c c}w )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)r1   xvalid_attn_processors
processorsdenoiser_moduler    procs          r   r4   zPAGMixin.pag_attn_processors   s     $$,I6:6O6O P P P
 4 "iiOT=)"..O899)99??A 	(JD$~~!66#'
4 	( ! !Qs   B)N)F)__name__
__module____qualname____doc__r8   r?   rI   rP   r
   r   r   rU   r   r   r	   rX   propertyfloatr;   r<   r(   r:   r`   r   r4    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   rL   torch.nnr&   models.attention_processorr   r	   r
   r   utilsr   
get_loggerrj   r,   r   rp   r   r   <module>rv      sE    
 + +     
		H	%R Rr   