U
    dgI                  	   @   s"  d dl Z d dlZd dlZd dlmZ d dlm  m  mZ d dl	m  mZ
 ejjZd dlmZ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mZ d dlmZ d dlmZ dd	l m!Z!m"Z" G d
d de j#Z$eeeee%ee! f ee$e$f dddZ&eeee%ee! f eeeej'e(f eej'e)f f  dddZ*eeedddZ+eee)dddZ,eee) dddZ-eee%dddZ.e"e%e"dddZ/e"ddd d!Z0d"d# Z1e1ej'ej'ej'd$d%d&Z2e1ej'ej'ej'd$d'd(Z3e1ej'ej'ej'd$d)d*Z4ee5dd+d,Z6dS )-    N)TupleCallableDictSetListOptionalUnion)GraphModule)Node)ObserverBaseFakeQuantizeBase)getattr_from_fqn)is_activation_post_process   )NSNodeTargetTypeNSResultsTypec                   @   s4   e Zd Ze Ze Ze Ze Ze Z	dS )NodeInputOrOutputTypeN)
__name__
__module____qualname__enumautoFP32INT8FP16UNKNOWNZFP32_OR_INT8 r   r   8/tmp/pip-unpacked-wheel-ua33x9lu/torch/ao/ns/fx/utils.pyr      s
   r   )nodegm
logger_clsnode_type_to_io_type_mapreturnc                    s  |d }|d }|d }|d }|d }|d }	|d }
|d }| j d	kr| j|kr`tjtjfS | j|krvtjtjfS | j|krtjtjfS | j|kr| jd
 }t|tst	t
||||\}}||fS tjtjfS n| j dkr| j dkst	t| jtst	t|| j t fdd|
D }t |ttfs>|rr| jd
 }t|tsXt	t
||||\}}||fS t fdd|D }t fdd|	D }|rtjtjfS |rtjtjfS tjtjfS n| j dkr| jdkr | jd
 }t|tst	t
||||\}}|tjfS | jdkr| jd
 }t|tsFt	t
||||\}}| jd }|tjks|t	| d|tjfS | j|kr| jd
 }t|tst	t
||||\}}||fS tjtjfS tjtjfS d S )NZfuns_io_type_fp32Zfuns_io_type_fp16Zfuns_io_type_int8Zfuns_io_type_fp32_or_int8Zmods_io_type_fp32Zmods_io_type_int8mods_io_type_fp32_or_int8Zmeths_io_type_fp32_or_int8call_functionr   call_modulec                 3   s   | ]}t  |V  qd S N
isinstance.0target_typemodr   r   	<genexpr>O   s    z7get_node_first_input_and_output_type.<locals>.<genexpr>c                 3   s   | ]}t  |V  qd S r&   r'   r)   r,   r   r   r.   a   s    c                 3   s   | ]}t  |V  qd S r&   r'   r)   r,   r   r   r.   d   s    call_method
dequantizetor   z handling needs to be added)optargetr   r   r   r   argsr(   r
   AssertionError$get_node_first_input_and_output_typer   strr   anyr   r   torchZfloat16)r   r   r    r!   ZFUNS_IO_TYPE_FP32ZFUNS_IO_TYPE_FP16ZFUNS_IO_TYPE_INT8ZFUNS_IO_TYPE_FP32_OR_INT8ZMODS_IO_TYPE_FP32ZMODS_IO_TYPE_INT8MODS_IO_TYPE_FP32_OR_INT8ZMETHS_IO_TYPE_FP32_OR_INT8Z	first_argZ_prev_node_input_typeZprev_node_output_type"is_known_fp32_or_int8_input_moduleZis_known_fp32_input_moduleZis_known_int8_input_module	prev_nodeZcur_node_dtype_targetr   r,   r   r6   &   s    





   
   
   

   


   r6   )r   r   r!   r"   c                    sD  | j d }t|tsdS |d }dd }|jdkrx|jtjkrL|||ddS |jtjtj	tj
tjfkrt|||dd	S dS |jd
kr@t|jtstt||j t tjtjtjtjtjtjtjtjtjtjtjtjtjtjtjtj tj!tj"tj#tj$tj%tjtj&tj'fr j( j)fS t* fdd|D }|r@t+|||S dS )z{
    Returns the qparams (scale, zero_point) of the first input to `node`,
    if they can be inferred from the graph.
    r   Nr#   c                 S   sj   | j | | j |  }}t|tr,t|jts0tt|trFt|jtsJtt||j}t||j}||fS r&   )r4   r(   r
   r3   r7   r5   r   )r   r   Zscale_arg_idxZ
zp_arg_idxZ
scale_nodeZzp_nodeZ	scale_objZzp_objr   r   r    _get_scale_zp_from_function_args   s    z@get_node_input_qparams.<locals>._get_scale_zp_from_function_argsr$   r         r%   c                 3   s   | ]}t  |V  qd S r&   r'   r)   Z
module_objr   r   r.      s    z)get_node_input_qparams.<locals>.<genexpr>),r4   r(   r
   r2   r3   r9   Zquantize_per_tensortoqaddZadd_relumulZmul_relur7   r5   r   nnqZLinearZConv1dZConv2dnniqZ
ConvReLU2dZConv3dZBatchNorm2dZBatchNorm3dZConvTranspose1dZConvTranspose2dZELUZ	GroupNormZInstanceNorm1dZInstanceNorm2dZInstanceNorm3dZ	LayerNormZ	HardswishZ	LeakyReLUZReLU6ZBNReLU2dZBNReLU3dZ
ConvReLU1dZ
ConvReLU3dZ
LinearReLUZscaleZ
zero_pointr8   get_node_input_qparams)r   r   r!   r<   r:   r=   r;   r   r@   r   rF      sb    	


rF   )r   r   r"   c                 C   s   | j dkrt|| j}t|rt| jdks0tt| jd tsDt| jd } t| jt	s^tt|| j}t|rt| jdkstt| jd tst| jd } | S )a  
    If node is not an observer, returns it.  If node is an observer,
    navigates up the graph and returns the first parent which is not an
    observer.  For example,

    graph: (node_non_obs), node = node_non_obs : returns node_non_obs
    graph: (node_non_obs -> obs0), node = obs0 : returns node_non_obs
    graph: (node_non_obs -> obs0 -> fq0), node = fq0 : returns node_non_obs
    r%   r   r   )
r2   r   r3   r   lenr4   r5   r(   r
   r7   r   r   Znode_objr   r   r   return_first_non_observer_node   s    


rI   c                 C   s*   | j dkr&t|| j}t|tjr&dS dS )aO  
    Assumes that all non-param args occur first. Returns the number of
    non-param args expected for a node.  For example, for

      F.linear(x, weight, bias)

    Returns 1, because x is a non-param arg and weight and bias are params.
    For

      lstm_mod(x, hid)

    Returns 2, because both x and hid are non-param args.
    r%   r>   r   )r2   r   r3   r(   nnZLSTMrH   r   r   r   get_number_of_non_param_args  s
    
rK   )r   r"   c                 C   s   t | jdkrg S | jdkr| jtjtjjjtjfksP| jtj	tjjj	tj	fkrg }t
dD ] }t| j| tkr\|| q\|S dgS )a-  
    Returns the indices of args of the node which we should attach
    loggers to, if input logging is enabled.

    For example,
    * for (x + y), returns [0, 1]
    * for (1 + y), returns [1]
    * for (x + 1), returns [0]
    * for (linear(x, w, b)) returns [0]
    * by default, returns [0]
    r   r$   r>   )rG   r4   r2   r3   r9   rB   ops	quantizedoperatorrC   rangetyper
   append)r   resultir   r   r    get_arg_indices_of_inputs_to_log*  s    
rT   c                 C   sP   d}| j dkrt| j}n0| j dkrLt| jts6tt|| j}t|}|S )z
    Returns a string representation of the type of the function or module
    pointed to by this node, or '' for other node types.
     )r$   r/   r%   )r2   r9   typenamer3   r(   r7   r5   r   )r   r   r+   Z
target_modr   r   r   get_target_type_strE  s    


rW   )results
model_namer"   c           
      C   s   i }|   D ]n\}}d}|  D ]>\}}|  D ],\}}	||kr0t|	sLt|	d d }q0q0q0q |dk	rr|||< q|||< q|S )a	  
    Rekeys the layer name of a results dictionary to use node names
    from `model_name`.

    For example, transforms

        {'base_op_1_0': {'node_output': {'model_a':
          [{'ref_node_name': 'linear1', ...}]}}}

    into

        {'linear1': {'node_output': {'model_a':
          [{'ref_node_name': 'linear1', ...}]}}}

    Note: we cannot use these node names directly because they are not
    guaranteed to be consistent across models. This is why we extract
    the results first and rekey afterwards.
    Nr   Zref_node_name)itemsrG   r5   )
rX   rY   Znew_resultsZold_layer_nameresult_type_to_resultsZnew_layer_nameZ_result_typemodel_name_to_resultsZcur_model_nameZlist_of_resultsr   r   r   'rekey_logger_info_on_node_name_of_modelT  s    

r]   )rX   r"   c                 C   s   d}|   D ]X\}}|  D ]B\}}|  D ],\}}t|dkr,|d d dk	r,|} qZq, q`q qfq|r|   D ]h\}}|  D ]V\}}|| }|  D ]<\}}||krqtt|D ]}	||	 d }
|
||	 d< qqqqrdS )ay  
    If `fqn` entries are filled in for one of the models in `results`, copies
    them over to any models which do not have them filled out.

    A common use case benefitting from this is comparing a model prepared by
    quantization to a quantized model. In this case, the model prepared by
    quantization would have `fqn` entries, and the quantized model would not.
    Nr   fqn)rZ   rG   rO   )rX   Zmodel_name_with_fqnsZ
layer_namer[   Zresult_typer\   rY   Zmodel_resultsZref_model_resultsrS   r^   r   r   r   maybe_add_missing_fqns{  s(    r_   c                    s    fddS )Nc            	         s   | ^}}}t |trt |ts2t |trjt |trjg }t||D ]$\}}||f|}||| q@|S t |tjrt |tjr|jr| }|jr| }|j	tj
ks|j	tj
krd S ||f|} ||S r&   )r(   tuplelistziprQ   r9   TensorZis_quantizedr0   Zdtypefloat)	r4   kwargsZa0Za1Za_otherrX   Zel0Zel1new_argsfinnerr   r   ri     s(    
zGmaybe_dequantize_first_two_tensor_args_and_handle_tuples.<locals>.innerr   )rh   r   rg   r   8maybe_dequantize_first_two_tensor_args_and_handle_tuples  s    rj   )xyr"   c                 C   s*   t | }t | | }dt ||  S )z
    Computes the SQNR between `x` and `y`.

    Args:
        x: Tensor or tuple of tensors
        y: Tensor or tuple of tensors

    Return:
        float or tuple of floats
       )r9   Znormlog10)rk   rl   ZPsZPnr   r   r   compute_sqnr  s    
ro   c                 C   s"   t | | d  | d   S )z
    Computes the normalized L2 error between `x` and `y`.

    Args:
        x: Tensor or tuple of tensors
        y: Tensor or tuple of tensors

    Return:
        float or tuple of floats
    r>   )r9   sqrtsumrk   rl   r   r   r   compute_normalized_l2_error  s    rs   c                 C   s(   |  dd} | dd}tjj| |S )z
    Computes the cosine similarity between `x` and `y`.

    Args:
        x: Tensor or tuple of tensors
        y: Tensor or tuple of tensors

    Return:
        float or tuple of floats
    r   )Zreshaper9   rJ   Z
functionalZcosine_similarityrr   r   r   r   compute_cosine_similarity  s    ru   c                 C   s4   | j dkr0| jtjtjtjtjtjtjfkr0dS dS )Nr$   FT)r2   r3   r9   rB   rC   rN   catstack)r   r   r   r   op_type_supports_shadowing  s    
"rx   )7r   rN   r9   Ztorch.nnrJ   Ztorch.nn.intrinsic.quantizedZ	intrinsicrM   rE   Ztorch.nn.quantizedrD   rL   rA   typingr   r   r   r   r   r   r   Ztorch.fxr	   Ztorch.fx.graphr
   Ztorch.ao.quantizationr   r   Ztorch.ao.quantization.utilsr   Ztorch.ao.quantization.quantizer   Zns_typesr   r   Enumr   r7   r6   rc   rd   intrF   rI   rK   rT   rW   r]   r_   rj   ro   rs   ru   boolrx   r   r   r   r   <module>   s`   $
}"R'"