a
    d)                     @   s   d dl Z d dlZd dlmZmZmZmZmZ ddlm	Z	 ddl
mZmZ e jeeef eedf ddd	Zee jj ee jj d
ddZee jj ee jj d
ddZe jjdddZde jjeeeeeeeed	ddZe jjdddZdS )    N)TypeDictAnyTupleCallable   )merge)isinstance_strinit_generator.)x	tome_inforeturnc              
   C   s  |d \}}|| }t tt|| jd  }|d }||d krt t|| }t t|| }t | jd |d  }	|d d u rt| j|d< n&|d j| jkrt| j|d d|d< | jd d	 dkrd
n|d }
tj| |||d |d |	|
 |d d\}}ntj	tj	 }}|d r0||fn
tj	tj	f\}}|d rR||fn
tj	tj	f\}}|d rt||fn
tj	tj	f\}}||||||fS )Nsizer   argsmax_downsampleratio	generator)fallbackr      Fuse_randsxsy)Zno_randr   
merge_attnmerge_crossattn	merge_mlp)
intmathceilsqrtshaper
   Zdevicer   Z bipartite_soft_matching_random2dZ
do_nothing)r   r   Z
original_hZ
original_wZoriginal_tokensZ
downsampler   whrr   mum_au_am_cu_cm_mu_m r+   U/var/www/html/stable-diffusion-webui/venv/lib/python3.9/site-packages/tomesd/patch.pycompute_merge
   s*    
"""r-   )block_classr   c                    s   G  fddd }|S )z
    Make a patched class on the fly so we don't have to import any specific modules.
    This patch applies ToMe to the forward function of the block.
    c                       s*   e Zd Z ZdejejejdddZdS )z"make_tome_block.<locals>.ToMeBlockN)r   contextr   c           	      S   s   t || j\}}}}}}|| j|| || jr4|nd d| }|| j|| ||d| }|| || || }|S )N)r/   )	r-   
_tome_infoattn1norm1disable_self_attnattn2norm2ffnorm3)	selfr   r/   r%   r'   r)   r&   r(   r*   r+   r+   r,   _forward:   s
    * z+make_tome_block.<locals>.ToMeBlock._forward)N)__name__
__module____qualname___parenttorchTensorr9   r+   r.   r+   r,   	ToMeBlock6   s   rA   r+   r.   rA   r+   r@   r,   make_tome_block0   s    rC   c                    s   G  fddd }|S )zw
    Make a patched class for a diffusers model.
    This patch applies ToMe to the forward function of the block.
    c                       s"   e Zd Z ZdejdddZdS )z,make_diffusers_tome_block.<locals>.ToMeBlockN)r   c                 S   s|  t || j\}}	}
}}}| jr,| ||}n0| jrR| j||||jd\}}}}}n
| |}||}|d urp|ni }| j|f| jr|nd |d|}| jr|d| }||| }| j	d ur
| jr| 
||n| 
|}|	|}| j	|f||d|}||| }| |}| jrD|d|d d d f   |d d d f  }|
|}| |}| jrl|d| }||| }|S )N)Zhidden_dtype)encoder_hidden_statesattention_maskr   )r-   r0   use_ada_layer_normr2   use_ada_layer_norm_zeroZdtyper1   Zonly_cross_attentionZ	unsqueezer4   r5   r7   r6   )r8   Zhidden_statesrE   rD   Zencoder_attention_maskZtimestepZcross_attention_kwargsZclass_labelsr%   r'   r)   r&   r(   r*   Znorm_hidden_statesZgate_msaZ	shift_mlpZ	scale_mlpZgate_mlpZattn_outputZ	ff_outputr+   r+   r,   forwardT   sV    


(
z4make_diffusers_tome_block.<locals>.ToMeBlock.forward)NNNNNN)r:   r;   r<   r=   r>   r?   rH   r+   r@   r+   r,   rA   P   s         	rA   r+   rB   r+   r@   r,   make_diffusers_tome_blockK   s    OrI   )modelc                 C   s"   dd }| j d | | dS )z\ Adds a forward pre hook to get the image size. This hook can be removed with remove_patch. c                 S   s&   |d j d |d j d f| jd< d S )Nr   r      r   )r   r0   )moduler   r+   r+   r,   hook   s    "zhook_tome_model.<locals>.hookhooksN)r0   appendZregister_forward_pre_hook)rJ   rM   r+   r+   r,   hook_tome_model   s    rP         ?r   TF)	rJ   r   r   r   r   r   r   r   r   c	                 C   s   t |  t| dpt| d}	|	sHt| dr6t| jds>td| jj}
nt| drX| jn| }
dg |||||d|||d	d	|
_t|
 |
	 D ]`\}}t|d
r|	rt
nt}||j|_|
j|_t|ds|	sd|_t|ds|	rd|_d|_q| S )af  
    Patches a stable diffusion model with ToMe.
    Apply this to the highest level stable diffusion object (i.e., it should have a .model.diffusion_model).

    Important Args:
     - model: A top level Stable Diffusion module to patch in place. Should have a ".model.diffusion_model"
     - ratio: The ratio of tokens to merge. I.e., 0.4 would reduce the total number of tokens by 40%.
              The maximum value for this is 1-(1/(sx*sy)). By default, the max is 0.75 (I recommend <= 0.5 though).
              Higher values result in more speed-up, but with more visual quality loss.
    
    Args to tinker with if you want:
     - max_downsample [1, 2, 4, or 8]: Apply ToMe to layers with at most this amount of downsampling.
                                       E.g., 1 only applies to layers with no downsampling (4/15) while
                                       8 applies to all layers (15/15). I recommend a value of 1 or 2.
     - sx, sy: The stride for computing dst sets (see paper). A higher stride means you can merge more tokens,
               but the default of (2, 2) works well in most cases. Doesn't have to divide image size.
     - use_rand: Whether or not to allow random perturbations when computing dst sets (see paper). Usually
                 you'd want to leave this on, but if you're having weird artifacts try turning this off.
     - merge_attn: Whether or not to merge tokens for attention (recommended).
     - merge_crossattn: Whether or not to merge tokens for cross attention (not recommended).
     - merge_mlp: Whether or not to merge tokens for the mlp layers (very not recommended).
    ZDiffusionPipelineZ
ModelMixinrJ   diffusion_modelzPProvided model was not a Stable Diffusion / Latent Diffusion model, as expected.unetN)	r   r   r   r   r   r   r   r   r   )r   rN   r   ZBasicTransformerBlockr3   FrG   )remove_patchr	   hasattrrJ   RuntimeErrorrR   rS   r0   rP   named_modulesrI   rC   	__class__r3   rF   rG   )rJ   r   r   r   r   r   r   r   r   Zis_diffusersrR   _rL   Zmake_tome_block_fnr+   r+   r,   apply_patch   s>    !

rZ   c                 C   sn   t | dr| jn| } |  D ]L\}}t |drT|jd D ]}|  q8|jd   |jjdkr|j|_q| S )zI Removes a patch from a ToMe Diffusion module if it was already patched. rS   r0   rN   rA   )	rU   rS   rW   r0   removeclearrX   r:   r=   )rJ   rY   rL   rM   r+   r+   r,   rT   	  s    


rT   )rQ   r   r   r   TTFF)r>   r   typingr   r   r   r   r    r   utilsr	   r
   r?   strr-   nnModulerC   rI   rP   floatr   boolrZ   rT   r+   r+   r+   r,   <module>   s4   $&  [       T