o
    *ѹg@                     @   s  U d dl Z d dlmZ d dlmZmZmZ d dlmZm	Z	m
Z
mZmZmZ d dlmZ d dlmZ d dlmZ d dlmZ d dlmZ d d	lmZ d
dgZe jjZdd Zi Ze
e	e	f ed< dd Z d?ddZ!e!ej"ddde#fddZ$e!ej%d@de#fddZ&e!ej'd@de#fddZ(e!ej)d@de#fddZ*	d?dee# dee# dee# d e+de#f
d!d"Z,e!ej-ej.gddde#fd#d$Z/d%d& Z0e!ej1de#fd'd(Z2d)d* Z3e!ej4ej5gddde#fd+d,Z6d-d. Z7e!ej8ej9gddde#fd/d0Z:ej"e$ej%e&ej'e(ej)e*ej-e/ej.e/ej1e2ej4e6ej5e6ej8e:ej9e:iZd1d2 Z;g d3Z<d4d5 Z=d6d7 Z>d8d9 Z?d:d; Z@G d<d
 d
eZAG d=d> d>eZBdS )A    N)tree_maptree_flattentree_unflatten)ListAnyDictOptionalUnion
NamedTuple)defaultdict)TorchDispatchMode)RemovableHandle)register_decompositionprodwrapsFlopCounterModeregister_flop_formulac                 C   s   t | tjr	| jS | S N)
isinstancetorchTensorshape)i r   \/Users/admin/.pyenv/versions/3.10.0/lib/python3.10/site-packages/torch/utils/flop_counter.py	get_shape   s   r   flop_registryc                    s   t  d d fdd
}|S )N)outc                    s(   t t||| f\}}} |d|i|S )N	out_shape)r   r   )r   argskwargsr    fr   r   nf   s   zshape_wrapper.<locals>.nfr   r$   r%   r   r#   r   shape_wrapper   s   r'   Fc                        fdd}|S )Nc                    s"    st | } ttdd|  | S )NT)registryunsafe)r'   r   r   )Zflop_formulaget_rawtargetsr   r   register_fun!   s   z+register_flop_formula.<locals>.register_funr   )r-   r,   r.   r   r+   r   r       s   )r    returnc          	      O   s,   | \}}|\}}||ksJ || d | S )zCount flops for matmul.   Nr   )	a_shapeb_shaper    r!   r"   mkk2nr   r   r   mm_flop)   s   r7   c                 K   
   t ||S )zCount flops for addmm.N)r7   Z
self_shaper1   r2   r    r"   r   r   r   
addmm_flop4   s   
r:   c                 K   sD   | \}}}|\}}}	||ksJ ||ksJ || |	 d | }
|
S )z"Count flops for the bmm operation.r0   Nr   )r1   r2   r    r"   br3   r4   b2r5   r6   flopr   r   r   bmm_flop9   s   

r>   c                 K   r8   )z&Count flops for the baddbmm operation.Nr>   r9   r   r   r   baddbmm_flopF   s   
r@   x_shapew_shaper    
transposedc           
      C   sJ   | d }|r| n|dd }|^}}}|t | | t | d | }	|	S )a  Count flops for convolution.

    Note only multiplication is
    counted. Computation for bias are ignored.
    Flops for a transposed convolution are calculated as
    flops = (x_shape[2:] * prod(w_shape) * batch_size).
    Args:
        x_shape (list(int)): The input shape before convolution.
        w_shape (list(int)): The filter shape.
        out_shape (list(int)): The output shape after convolution.
        transposed (bool): is the convolution transposed
    Returns:
        int: the number of flops
    r   r0   Nr   )
rA   rB   r    rC   Z
batch_sizeZ
conv_shapeZc_outZc_indimsr=   r   r   r   conv_flop_countN   s
   
 rE   c          
      O   s   t | |||dS )zCount flops for convolution.)rC   N)rE   )
rA   rB   _bias_stride_padding	_dilationrC   r    r!   r"   r   r   r   	conv_flopk   s   rJ   c                 C   s    | d | d gt | dd   S )N   r   r0   )list)r   r   r   r   transpose_shapep   s    rM   c                 C   sZ   d}|
d rt |d }|t| ||| 7 }|
d r+t |d }|tt|| ||7 }|S Nr   rK   )r   rE   rM   )grad_out_shaperA   rB   rF   rG   rH   rI   rC   Z_output_paddingZ_groupsZoutput_maskr    
flop_countZgrad_input_shapeZgrad_weight_shaper   r   r   conv_backward_flops   s   rQ   c                 C   s   | \}}}}|\}}}	}
|\}}}}||  kr|kr8n J ||  kr)|kr8n J ||
kr8|	|kr8||
ks:J d}|t || ||f|| ||	f7 }|t || ||	f|| |	|f7 }|S )z^
    Count flops for self-attention.

    NB: We can assume that value_shape == key_shape
    r   Nr?   )query_shape	key_shapevalue_shaper;   hs_qd_q_b2_h2s_k_d2_b3_h3_s3d_vtotal_flopsr   r   r   sdpa_flop_count   s   P""ra   c                O   s   t | ||S )zCount flops for self-attention.N)ra   )rR   rS   rT   r    r!   r"   r   r   r   	sdpa_flop   s   rb   c                 C   sV  d}|\}}}}|\}	}
}}|\}}}}| \}}}}||	  kr)|  kr)|krBn J ||
  kr;|  kr;|krBn J ||ksDJ ||krP||krP||ksRJ d}|t || ||f|| ||f7 }|t || ||f|| ||f7 }|t || ||f|| ||f7 }|t || ||f|| ||f7 }|t || ||f|| ||f7 }|S )Nr   r?   )rO   rR   rS   rT   r`   r;   rU   rV   rW   rX   rY   rZ   r[   r\   r]   r^   r_   Z_b4Z_h4Z_s4Z_d4r   r   r   sdpa_backward_flop_count   s   T"""""rc   c                O   s   t | |||S )z(Count flops for self-attention backward.N)rc   )rO   rR   rS   rT   r    r!   r"   r   r   r   sdpa_backward_flop   s   rd   c                 C   s   t | ts| fS | S r   )r   tuplexr   r   r   normalize_tuple   s   
rh   ) KMBTc                 C   s0   t dtttd tt| d d }t| S )Nr   rK      )maxminlensuffixesstr)numberindexr   r   r   get_suffix_str   s   (rv   c                 C   s&   t |}| d|  d}|t |  S )Ni  z.3f)rr   ru   )rt   suffixru   valuer   r   r   convert_num_with_suffix   s   
ry   c                 C   s   |dkrdS | | dS )Nr   0%z.2%r   )numZdenomr   r   r   convert_to_percent_str   s   r|   c                    s   t   fdd}|S )Nc                    s   t | \}} | }t||S r   )r   r   )r!   Z	flat_argsspecr   r#   r   r   r%      s   
z)_pytreeify_preserve_structure.<locals>.nfr   r&   r   r#   r   _pytreeify_preserve_structure   s   r~   c                       s   e Zd ZdZ				d%deeejje	ejj f  de
dedeeeef  fd	d
Zdd Zdd Zdd Zdd Zdd Zdd Zde
fddZdeeeee
f f fddZd&ddZ fddZ fd d!Zd'd#d$Z  ZS )(r   a  
    ``FlopCounterMode`` is a context manager that counts the number of flops within its context.

    It does this using a ``TorchDispatchMode``.

    It also supports hierarchical output by passing a module (or list of
    modules) to FlopCounterMode on construction. If you do not need hierarchical
    output, you do not need to use it with a module.

    Example usage

    .. code-block:: python

        mod = ...
        flop_counter = FlopCounterMode(mod)
        with flop_counter:
            mod.sum().backward()

    Nr0   Tmodsdepthdisplaycustom_mappingc                 C   sn   t dd | _|| _dg| _|| _|d u ri }t|tjjr!|g}|| _	i | _
i tdd | D | _d S )Nc                   S   s   t tS r   )r   intr   r   r   r   <lambda>  s    z*FlopCounterMode.__init__.<locals>.<lambda>Globalc                 S   s*   i | ]\}}|t |d dr|nt|qS )Z_get_rawF)getattrr'   ).0r4   vr   r   r   
<dictcomp>!  s   * z,FlopCounterMode.__init__.<locals>.<dictcomp>)r   flop_countsr   parentsr   r   r   nnModuler   _module_to_forward_hook_handlesr   items)selfr   r   r   r   r   r   r   __init__  s   
zFlopCounterMode.__init__c                 C   s   | j d u rd S | j D ]:}t|j}t|  D ]*\}}|dkr$|}nd||g}|| |}|	| 
|}t||| j|< qq
d S )Nri   .)r   type__name__dictZnamed_modulesr   joinZregister_forward_pre_hook_enter_moduleZregister_forward_hook_exit_module_ForwardHookHandlesr   )r   modprefixnamemoduleforward_pre_hook_handleforward_hook_handler   r   r   _register_forward_hooks$  s   


z'FlopCounterMode._register_forward_hooksc                 C   s6   | j  D ]}|d   |d   q| j   d S rN   )r   valuesremoveclear)r   Zforward_hook_handlesr   r   r   _deregister_forward_hooks5  s   z)FlopCounterMode._deregister_forward_hooksc                    r(   )Nc                    s   t  |}|S r   )r~   _create_pre_module)r   inputsr   r   r   r   r   r$   <     z(FlopCounterMode._enter_module.<locals>.fr   r   r   r$   r   r   r   r   ;  s   zFlopCounterMode._enter_modulec                    r(   )Nc                    s   t  |}|S r   )r~   _create_post_module)r   r   outputsr   r   r   r$   C  r   z'FlopCounterMode._exit_module.<locals>.fr   r   r   r   r   r   B  s   zFlopCounterMode._exit_modulec                        G  fdddt jj}|jS )Nc                       0   e Zd Ze fddZe fddZdS )z6FlopCounterMode._create_post_module.<locals>.PushStatec                    s.   j d  ks	J j   tdd |}|S )Nc                 S      t | tjr
|  S | S r   r   r   r   clonerf   r   r   r   r   N      zPFlopCounterMode._create_post_module.<locals>.PushState.forward.<locals>.<lambda>)r   popr   ctxr!   r   r   r   forwardJ  s   
z>FlopCounterMode._create_post_module.<locals>.PushState.forwardc                    s   j   |S r   )r   appendr   Z	grad_outsr   r   r   backwardQ  s   z?FlopCounterMode._create_post_module.<locals>.PushState.backwardNr   
__module____qualname__staticmethodr   r   r   r   r   r   	PushStateI  s
    r   r   ZautogradZFunctionapply)r   r   r   r   r   r   r   H     z#FlopCounterMode._create_post_modulec                    r   )Nc                       r   )z4FlopCounterMode._create_pre_module.<locals>.PopStatec                    s   j   tdd |}|S )Nc                 S   r   r   r   rf   r   r   r   r   ]  r   zNFlopCounterMode._create_pre_module.<locals>.PopState.forward.<locals>.<lambda>)r   r   r   r   r   r   r   r   Z  s   z<FlopCounterMode._create_pre_module.<locals>.PopState.forwardc                    s    j d  ks	J j   |S )Nr   )r   r   r   r   r   r   r   `  s   
z=FlopCounterMode._create_pre_module.<locals>.PopState.backwardNr   r   r   r   r   PopStateY  s
    r   r   )r   r   r   r   r   r   r   X  r   z"FlopCounterMode._create_pre_moduler/   c                 C   s   t | jd  S )Nr   )sumr   r   r   r   r   r   get_total_flopsh  s   zFlopCounterMode.get_total_flopsc                 C   s
   t | jS )a  Return the flop counts as a dictionary of dictionaries.

        The outer
        dictionary is keyed by module name, and the inner dictionary is keyed by
        operation name.

        Returns:
            Dict[str, Dict[Any, int]]: The flop counts as a dictionary.
        N)r   r   r   r   r   r   get_flop_countsk  s   

zFlopCounterMode.get_flop_countsc                    s  |d u rj }|d u rd}dd l}d|_g d}g }  t d fdd}j D ]$}|dkr9q2|d	d
 }||krEq2|||d
 }|D ]}	||	 qNq2djv rzszt	|D ]\}
}	d||
 d  ||
 d< qb|dd| }t
|dkrg dg}|j||ddS )Ni?B r   T)r   ZFLOPz% TotalFc                    s   t j|   }| kO d| }g }|||  t|t| g j|   D ]\}}||d t| t|t| g q,|S )N z - )r   r   r   r   ry   r|   r   rs   )mod_namer   r`   paddingr   r4   r   Zglobal_flopsZglobal_suffixZis_global_subsumedr   r   r   process_mod  s    z.FlopCounterMode.get_table.<locals>.process_modr   r   rK   r   )r   0rz   )leftrightr   )headersZcolalign)r   tabulateZPRESERVE_WHITESPACEr   rv   r   keyscountr   	enumeraterq   )r   r   r   headerr   r   r   Z	mod_depthZ
cur_valuesrx   idxr   r   r   	get_tablew  s:   
zFlopCounterMode.get_tablec                    s    | j   |   t   | S r   )r   r   r   super	__enter__r   	__class__r   r   r     s   

zFlopCounterMode.__enter__c                    s.   | j rt| | j |   t j|  d S r   )r   printr   r   r   r   __exit__)r   r!   r   r   r   r     s   zFlopCounterMode.__exit__r   c           
      C   sp   |r|ni }||i |}|j }|| jv r6| j| }||i |d|i}| jD ]}	| j|	 |  |7  < q(|S )Nr   )Z_overloadpacketr   r   r   )
r   functypesr!   r"   r   Zfunc_packetZflop_count_funcrP   parr   r   r   __torch_dispatch__  s   


z"FlopCounterMode.__torch_dispatch__)Nr0   TNr   )r   N)r   r   r   __doc__r   r	   r   r   r   r   r   boolr   r   r   r   r   r   r   r   r   r   rs   r   r   r   r   r   __classcell__r   r   r   r   r      s6    

=c                   @   s   e Zd ZU eed< eed< dS )r   r   r   N)r   r   r   r   __annotations__r   r   r   r   r     s   
 r   )Fr   )Cr   Ztorch.nnr   Ztorch.utils._pytreer   r   r   typingr   r   r   r   r	   r
   collectionsr   Ztorch.utils._python_dispatchr   Ztorch.utils.hooksr   Ztorch._decompr   mathr   	functoolsr   __all__opsZatenr   r   r   r'   r   mmr   r7   Zaddmmr:   Zbmmr>   Zbaddbmmr@   r   rE   ZconvolutionZ_convolutionrJ   rM   Zconvolution_backwardrQ   ra   Z'_scaled_dot_product_efficient_attentionZ#_scaled_dot_product_flash_attentionrb   rc   Z0_scaled_dot_product_efficient_attention_backwardZ,_scaled_dot_product_flash_attention_backwardrd   rh   rr   rv   ry   r|   r~   r   r   r   r   r   r   <module>   s   
  
	


 T