U
    d3                     @   s  d Z ddlZddlZddlZddlmZmZ ddlmZm	Z	m
Z
mZ ddlmZ e
eeeef eeeeef f e	f ZG dd dZejjejjejjejjejjejjejjejjejjejjejjejjejjejjejjhZ ejj!j"ejj!j#ejj!j$ejj!j%ejj!j&ejj!j'ejj!j(ejj!j)ejj!j*ejj!j+ejj!j,ejj!j-ejj!j.ejj!j/ejj!j0ejj!j1ejj!j2ejj!j3ejj!j4ej5ej6ej4ej7ej8ej9ej:ej;ej<hZ=ej>dd	d
dddddddddddddddddddddhZ?d d! Z@d"d# ZAd$d% ZBd&d' ZCe	eDe	d(d)d*ZEd+d, ZFd-d. ZGd/d0 ZHd1d2 ZId3d4 ZJd5d6 ZKd7d8 ZLd9d: ZMd;d< ZNd=d> ZOePd?d@dAZQdBdC ZRdDdE ZSejTejTePdFdGdHZUeVeVePejWePeeVeVf dIdJdKZXdLdM ZYdNdO ZZdS )Pz?
Utils shared by different modes of quantization (eager/graph)
    N)	QuantTypequant_type_to_str)TupleAnyUnionCallable)is_parametrizedc                   @   s   e Zd ZdZdS )MatchAllNodezo A node pattern that matches all nodes, used in defining
    fusion patterns in FX Graph Mode Quantization
    N)__name__
__module____qualname____doc__ r   r   ?/tmp/pip-unpacked-wheel-ua33x9lu/torch/ao/quantization/utils.pyr	      s   r	   reluZrelu_
contiguousdetachZdetach_hardsigmoidZhardsigmoid_Zpermuterepeatrepeat_interleaveZreshapeZresize_shapesigmoidZsigmoid_sizesqueezeZsqueeze_tanhZtanh_	transpose	unsqueezeZ
unsqueeze_viewc                 C   sR   | j dko| jtk}| j dko&| jtk}| j dkoFt|t| j tk}|||fS )Ncall_functionZcall_methodZcall_module)optarget	func_listmethod_listtypestrmodule_type_list)nodemodulesZis_call_functionZis_call_methodZis_call_moduler   r   r   
check_nodeb   s     r(   c                 C   s   |   }|| |S N)copyupdate)Zdefault_dictZadditional_dictdr   r   r   get_combined_dicti   s    
r-   c                 C   s   | t jkp| t jkS r)   )torchper_tensor_affineZper_tensor_symmetricqschemer   r   r   is_per_tensorn   s    
r2   c                 C   s   | t jt jt jfkS r)   )r.   per_channel_affineZ per_channel_affine_float_qparamsper_channel_symmetricr0   r   r   r   is_per_channelr   s    r5   )objfqnreturnc                 C   s   t t|d| S )zO
    Given an obj and a fqn such as "foo.bar.baz", returns gm.foo.bar.baz.
    .)	functoolsreducegetattrsplit)r6   r7   r   r   r   getattr_from_fqnw   s    r>   c                 C   s   t | dr| jnd }| j}||d}|s,|S t|r<tj}n2t|r`|tjkrTtj}| j	|d< nt
d| ||d< |  \}}||d< ||d< |S )Nr1   )r1   dtypeZaxiszUnrecognized qscheme: scale
zero_point)hasattrr1   r?   r2   r.   r/   r5   r4   r3   Zch_axisRuntimeErrorZcalculate_qparams)Zobserver_or_fake_quantr1   r?   Zqparamsr@   rA   r   r   r   get_qparam_dict}   s"    

rD   c                 C   sH   t |}t|}||i }t| |ks<tdt| ||t|  S )a   Get the observed/quantized custom module class that we need
    to swap `custom_module` to
    Input:
        custom_module: input, can be an instance of either a float or observed custom module
        custom_module_class_mapping: the float to observed or observed to quantized custom module class mapping
        qconfig: qconfig configured for the custom module

    Output:
        corresponding observed/quantized custom module class for input custom module instance
    zFdid not find corresponding observed module class for {} in mapping: {})get_quant_typer   getr#   AssertionErrorformat)Zcustom_moduleZcustom_module_class_mappingqconfigZ
quant_typeZquant_type_strZclass_mappingr   r   r   get_swapped_custom_module_class   s     rJ   c                 C   s   | d k	st |  }|jS r)   )rG   
activationr?   )rI   rK   r   r   r   activation_dtype   s    rL   c                 C   s   | d k	st |  }|jS r)   )rG   weightr?   )rI   rM   r   r   r   weight_dtype   s    rN   c                 C   s   t | tjtjtjfkS )z Given a qconfig, decide if the activation needs to be
    quantized or not, this includes quantizing to quint8, qint8 and float16
    )rL   r.   quint8qint8float16rI   r   r   r   "activation_is_statically_quantized   s    rS   c                 C   s,   t | \}}}|tjko*|tjtjtjfkS )z Given a qconfig, decide if the activation needs to be
    dynamically quantized or not, this includes dynamically quantizing to
    quint8, qint8 and float16
    )get_qconfig_dtypesr.   floatrO   rP   rQ   )rI   rL   _activation_compute_dtyper   r   r   #activation_is_dynamically_quantized   s
    
rX   c                 C   s   t | tjtjfkS )z Given a qconfig, decide if the activation needs to be
    quantized to int8 or not, this includes quantizing to quint8, qint8
    )rL   r.   rO   rP   rR   r   r   r   activation_is_int8_quantized   s    rY   c                 C   s   t | tjkS )zY Given a qconfig, decide if the activation needs to be
    quantized to int32 or not
    )rL   r.   qint32rR   r   r   r   activation_is_int32_quantized   s    r[   c                 C   s   t | tjtjtjtjfkS )zL Given a qconfig, decide if the weight needs to be
    quantized or not
    )rN   r.   rO   rP   rQ   quint4x2rR   r   r   r   weight_is_quantized   s    r]   c                 C   s   t | tjtjfkS )zW Given a qconfig, decide if the weight needs to be statically
    quantized or not
    )rN   r.   rO   rP   rR   r   r   r   weight_is_statically_quantized   s    r^   )r8   c                 C   s,   t | \}}}|tjko*|tjko*|tjkS )zU Given a qconfig, returns True if this op is using int8 dynamic
    quantization
    )rT   r.   rU   rP   rO   )rI   rL   rN   rW   r   r   r    op_is_int8_dynamically_quantized   s    
r_   c                 C   s>   | dk	st |  }|  }t|dr,|jnd}|j|j|fS )zk returns the qconfig tuple for qconfig:
    (activation_dtype, weight_dtype, activation_compute_dtype)
    Ncompute_dtype)rG   rK   rM   rB   r`   r?   )rI   rK   rM   r`   r   r   r   rT      s
    rT   c                 C   s   | d k	st |  }|  }tjtjtjg}|j|krf|j|krFtj	S t
|dr`|j|kr`tjS tjS |jtjkr|jtjkrtjS |jtjkrtj	S td|j|jd S )Nr`   zKUnrecognized dtype combination in get_quant_type: activation({}),weight({}))rG   rK   rM   r.   rO   rP   r\   r?   r   ZSTATICrB   r`   ZDYNAMICZWEIGHT_ONLYrQ   rU   	ExceptionrH   )rI   rK   rM   Zstatic_dtypesr   r   r   rE      s&    

 rE   )min_valmax_valr8   c                 C   s   |   dks|  dkr&td dS |  dks>| dkr~| tdkrd|tdkrdtd dS | |kstd| |nt| |kstd| |dS )z Checks if the given minimum and maximum values are valid, meaning that
    they exist and the min value is less than the max value.
    r   zMmust run observer before calling calculate_qparams. Returning default values.Finfz-infz!min {} should be less than max {}T)	ZnumelwarningswarnZdimrU   rG   rH   r.   all)rb   rc   r   r   r   check_min_max_valid  s*     
rh   )	quant_min	quant_maxhas_customized_qranger?   reduce_ranger8   c           
      C   s&  |r|t jkrd\}}nd\}}| | }}|dk	rD|dk	rD|| }}|| d }	|t jkrzd|	  k rndksn tdn(|t jkrd|	  k rdksn td	|r| d
 |d
  } }nd|t jkr|rd\} }nd\} }nB|t jkr |rd\} }nd\} }n|t jkrd\} }nd\} }| |fS )ztCalculates actual qmin and qmax based on the quantization range,
    observer datatype and if range is reduced.
    )r   )r      N   r      zRquantization range should be positive and not exceed the maximum bit range (=256).l        zYquantization range should be positive and not exceed the maximum bit range (=4294967296).   )i?   )i   )r   rs   )i   rm   )r      )r.   rZ   rP   rG   rO   )
ri   rj   rk   r?   rl   Zinitial_quant_minZinitial_quant_maxZcustom_quant_minZcustom_quant_maxZ
qrange_lenr   r   r   calculate_qmin_qmax*  sP    



 

 






ru   c                 C   s8   |  dd}t|dkr$d|d fS |d |d fS dS )z,
    Turn 'foo.bar' into ['foo', 'bar']
    r9   ro    r   N)rsplitlen)r    rr   r   r   _parent_name_  s    rz   c                 C   s:   t | jdkrdS t| r2t | jdko0d| jkS dS dS )z
    Checks if module._modules is empty or
    if module is a parametrization, checks that module._modules only has
    the 'parametrizations' module
    r   Tro   ZparametrizationsFN)rx   Z_modulesr   )moduler   r   r   )has_no_children_ignoring_parametrizationsi  s
    r|   )[r   re   r:   r.   Z torch.ao.quantization.quant_typer   r   typingr   r   r   r   Ztorch.nn.utils.parametrizer   Patternr	   nnZReLUZReLU6ZAdaptiveAvgPool1dZAdaptiveAvgPool2dZAdaptiveAvgPool3dZ	AvgPool1dZ	AvgPool2dZ	AvgPool3dZ	MaxPool1dZ	MaxPool2dZ	MaxPool3dZIdentityZHardsigmoidZSigmoidZTanhr%   Z
functionalZadaptive_avg_pool1dZadaptive_avg_pool2dZadaptive_avg_pool3dZeluZ	hardswishZinstance_normZ
layer_normZ
leaky_reluZsiluZmishZdropoutZ
max_pool1dZ
max_pool2dZ
max_pool3dr   ZhardtanhZ	hardtanh_r   r   r   r   r   stacksumr   r   catr!   Zmeanr"   r(   r-   r2   r5   r$   r>   rD   rJ   rL   rN   rS   rX   rY   r[   r]   r^   boolr_   rT   rE   ZTensorrh   intr?   ru   rz   r|   r   r   r   r   <module>   s   (


 
5
