a
    hP                  	   @   s2  d dl Z d dlZd dlmZmZmZ d dlZd dlm  m	  m
  mZ d dlm  m	  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 d dlmZ dd	lmZmZ ejj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Z0eddd d!Z1d"d# Z2e2ej'ej'ej'd$d%d&Z3e2ej'ej'ej'd$d'd(Z4e2ej'ej'ej'd$d)d*Z5ee6dd+d,Z7eee)ed-d.d/Z8dS )0    N)CallableOptionalUnion)FakeQuantizeBaseObserverBase)_is_activation_post_process)getattr_from_fqn)GraphModule)Node   )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   B/var/www/auris/lib/python3.9/site-packages/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|v r`tjtjfS | j|v rvtjtjfS | j|v rtjtjfS | j|v rt| |d
}t|tsJ t	||||\}}||fS tj
tj
fS n| j dkr| j dksJ t| jtsJ t|| j t fdd|
D }t |ttfs@|rvt| |d
}t|ts\J 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&t| |d
}t|ts
J t	||||\}}|tjfS | jdkrt| |d
}t|tsNJ t	||||\}}t| |d}|tju sJ | d|tjfS | j|v rt| |d
}t|tsJ 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>N   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*   e   s   call_method
dequantizetor   z handling needs to be added)optargetr   r   r   r   get_normalized_nth_inputr$   r
   $get_node_first_input_and_output_typer   strr   anyr   r   torch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   r1   &   s    






r1   )r   r   r   r   c                    sF  t | |d}t|tsdS |d }dd }|jdkrz|jtjkrN|||ddS |jtjtj	tj
tjfv rv|||dd	S dS |jd
krBt|jtsJ 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 }|rBt*|||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   sl   t | ||}t | ||}t|tr.t|jts2J t|trHt|jtsLJ t||j}t||j}||fS r"   )r0   r$   r
   r/   r2   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>)+r0   r$   r
   r.   r/   r4   Zquantize_per_tensortoqaddZadd_relumulZmul_relur2   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_pointr3   get_node_input_qparams)r   r   r   r8   r6   r9   r7   r   r<   r   rB      sb    	
	
rB   )r   r   r   c                 C   s   | j dkrt|| j}t|rt| jdks0J t| jd tsDJ | jd } t| jts^J t|| j}t|rt| jdksJ t| jd tsJ | 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   )	r.   r   r/   r   lenargsr$   r
   r2   r   r   Znode_objr   r   r   return_first_non_observer_node   s    


rF   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   )r.   r   r/   r$   nnZLSTMrE   r   r   r   get_number_of_non_param_args  s
    
rH   )r   r   c                    sp   t  jdkrg S  jdkrj jtjtjjjtjfv sP jtj	tjjj	tj	fv rj fddt
dD }|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    c                    s"   g | ]}t  j| tkr|qS r   )typerD   r
   )r&   ir   r   r   
<listcomp>?      z4get_arg_indices_of_inputs_to_log.<locals>.<listcomp>r:   )rC   rD   r.   r/   r4   r>   ops	quantizedoperatorr?   range)r   resultr   rK   r    get_arg_indices_of_inputs_to_log,  s    
rS   c                 C   sP   d}| j dv rt| j}n0| j dkrLt| jts6J 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!   )r.   r4   typenamer/   r$   r2   r   )r   r   r'   Z
target_modr   r   r   get_target_type_strD  s    


rV   )results
model_namer   c           	      C   s|   i }|   D ]j\}}d}| D ]:}|  D ],\}}||kr,t|sHJ |d d }q,q,q,q |durn|||< 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)itemsvaluesrC   )	rW   rX   Znew_resultsZold_layer_nameresult_type_to_resultsZnew_layer_namemodel_name_to_resultsZcur_model_nameZlist_of_resultsr   r   r   'rekey_logger_info_on_node_name_of_modelS  s    

r]   )rW   r   c           	      C   s   d}|   D ]P}|  D ]>}| D ],\}}t|dkr$|d d dur$|} qRq$ qXq q^q|r|   D ]`}|  D ]R}|| }| D ]<\}}||krqtt|D ]}|| d }||| d< qqqvqjd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   rY   rC   rQ   )	rW   Zmodel_name_with_fqnsr[   r\   rX   Zmodel_resultsZref_model_resultsrJ   r^   r   r   r   maybe_add_missing_fqnsz  s(    r_   c                    s    fddS )Nc            	         s   | ^}}}t |trt |ts2t |trpt |trpg }t||D ]*\}}||g|R }||i | q@|S t |tjrt |tjr|jr| }|jr| }|j	tj
ks|j	tj
krd S ||g|R } |i |S r"   )r$   tuplelistzipappendr4   TensorZis_quantizedr,   Zdtypefloat)	rD   kwargsZa0Za1Za_otherrW   Zel0Zel1new_argsfinnerr   r   rj     s(    
zGmaybe_dequantize_first_two_tensor_args_and_handle_tuples.<locals>.innerr   )ri   r   rh   r   8maybe_dequantize_first_two_tensor_args_and_handle_tuples  s    rk   )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
       )r4   Znormlog10)rl   rm   ZPsZPnr   r   r   compute_sqnr  s    
rp   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:   )r4   sqrtsumrl   rm   r   r   r   compute_normalized_l2_error  s    rt   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reshaper4   rG   Z
functionalZcosine_similarityrs   r   r   r   compute_cosine_similarity  s    rv   c                 C   s4   | j dkr0| jtjtjtjtjtjtjfv r0dS dS )Nr    FT)r.   r/   r4   r>   r?   rP   catstackrK   r   r   r   op_type_supports_shadowing  s    
	ry   )r   r   idxr   c                 C   s4  z| j |dd}|durb|\}}t|t| |ks8J |t|k rN|| W S t| | W S nXt| jt| j |ks~J |t| jk r| j| W S |t| j }t| j | W S W nr ty.   t| jt| j |ksJ |t| jk r| j|  Y S |t| j }t| j |  Y S Y n0 dS )zu
    Given a node, gets the n'th input to that node, normalizing
    args and kwargs to the best of its ability.
    T)Znormalize_to_only_use_kwargsN)Znormalized_argumentsrC   ra   rZ   rD   rf   RuntimeError)r   r   rz   Znorm_args_and_kwargsZ	norm_argsZnorm_kwargsZ
kwargs_idxr   r   r   r0     s*    
r0   )9r   rP   typingr   r   r   r4   Ztorch.ao.nn.intrinsic.quantizedZaorG   Z	intrinsicrO   rA   Ztorch.ao.nn.quantizedr@   Ztorch.nnZtorch.ao.quantizationr   r   Ztorch.ao.quantization.observerr   Ztorch.ao.quantization.utilsr   Ztorch.fxr	   Ztorch.fx.graphr
   Zns_typesr   r   rN   r=   Enumr   dictr2   setr`   r1   rd   re   intrB   rF   rH   ra   rS   rV   r]   r_   rk   rp   rt   rv   boolry   r0   r   r   r   r   <module>   sb   
"R'"