U
    ©Ê¹jan  ã                
   @   sð  d dl Z 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Z d dlmZmZmZmZmZmZmZmZ ddlmZmZ d dl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ddddddddg
Z'ej(ej)j(ej*ej)j*iej)j(ejj(ej)j*ejj*idœZ+dd
„ Z,d6dd„Z-d7dd„Z.dd„ Z/dd„ Z0d8dd „Z1d9d!d"„Z2d#d$„ Z3d%d„ Z4d:d&d„Z5d'd(„ Z6d)d*„ Z7d;d+d„Z8dej9ddfd,d„Z:d<d-d„Z;d=d.d„Z<d>d0d„Z=d?d1d2„Z>d3d„ Z?d@d4d5„Z@dS )Aé    N)Ú_FusedModule)Ú)get_default_dynamic_quant_module_mappingsÚ(get_default_static_quant_module_mappingsÚ2get_default_static_quant_reference_module_mappingsÚget_default_qat_module_mappingsÚ$get_default_qconfig_propagation_listÚno_observer_setÚ_has_special_act_post_processÚ_get_special_act_post_processé   )Úget_qparam_dictÚ)has_no_children_ignoring_parametrizations)ÚDeQuantStubÚQuantWrapper)Ú_add_module_to_qconfig_obs_ctrÚdefault_dynamic_qconfigÚfloat16_dynamic_qconfigÚ!float_qparams_weight_only_qconfigÚ&float_qparams_weight_only_qconfig_4bitÚ_activation_is_memoryless)Útype_before_parametrizations)Ú_is_activation_post_processÚget_default_custom_config_dictÚpropagate_qconfig_Úadd_quant_dequantÚprepareÚquantizeÚquantize_dynamicÚprepare_qatÚquantize_qatÚconvertÚswap_module)Ú%float_to_observed_custom_module_classÚ)observed_to_quantized_custom_module_classc                   C   s   t S )z,Defines the default custom config dict.
    )Ú_DEFAULT_CUSTOM_CONFIG_DICT© r%   r%   ú]/var/www/html/bwave/python/venv/lib/python3.8/site-packages/torch/ao/quantization/quantize.pyr   =   s    Ú c           
      C   s®   |  t| ƒ|¡}|  ||¡}t| d|ƒ}tjjj || ¡ t|| ƒ}|| _|  	¡ D ]V\}}|rj|d | n|}	|dksš||  dg ¡ksRt
|ƒ|  dg ¡ksRt||||	ƒ qRdS )aò  This is a helper function for `propagate_qconfig_`

    Args:
        module: input module
        qconfig_dict: dictionary that maps from name of submodule to quantization
                     configuration
        qconfig_parent: quantization config of parent module, we will fallback to
                       this config when there is no specified config for current
                       module
        prefix: corresponding prefix of the current module, used as key in
                qconfig_dict
        prepare_custom_config_dict: dictionary for custom handling of modules
                                    see docs for :func:`~torch.ao.quantization.prepare_fx`

    Return:
        None, module is modified inplace with qconfig attached
    ÚqconfigÚ.NZnon_traceable_module_nameZnon_traceable_module_class)Úgetr   ÚgetattrÚtorchÚaoZquantizationr(   Z_assert_valid_qconfigr   Únamed_childrenÚtypeÚ_propagate_qconfig_helper)
ÚmoduleÚqconfig_dictZqconfig_parentÚprefixÚprepare_custom_config_dictZmodule_qconfigZqconfig_with_device_checkÚnameÚchildÚmodule_prefixr%   r%   r&   r0   B   s&    
ÿþ   ÿr0   c                 C   s*   |dkri }|dkri }t | ||d� dS )a“  Propagate qconfig through the module hierarchy and assign `qconfig`
    attribute on each leaf module

    Args:
        module: input module
        qconfig_dict: dictionary that maps from name or type of submodule to
            quantization configuration, qconfig applies to all submodules of a
            given module unless qconfig for the submodules are specified (when
            the submodule already has qconfig attribute)
        prepare_custom_config_dict: dictionary for custom handling of modules
            see docs for :func:`~torch.ao.quantization.prepare_fx`

    Return:
        None, module is modified inplace with qconfig attached
    N)r4   )r0   )r1   r2   r4   r%   r%   r&   r   j   s
    c                 C   s
   |   |¡S )z3Forward hook that calls observer on the output
    ©Úactivation_post_process)ÚselfÚinputÚoutputr%   r%   r&   Ú_observer_forward_hook€   s    r=   c                 C   s   |   |d ¡S )z7Forward pre hook that calls observer on the output
    r   r8   )r:   r;   r%   r%   r&   Ú_observer_forward_pre_hook…   s    r>   Fc                 C   s8   t | dƒstdƒ‚|r&| jtdd�}n| jtdd�}d S )Nr9   zGExpect activation_post_process attribute already attached to the moduleT)Úprepend)ÚhasattrÚAssertionErrorÚregister_forward_pre_hookr>   Úregister_forward_hookr=   )r1   Úpre_hookÚhandler%   r%   r&   Ú&_register_activation_post_process_hookŠ   s    ÿ ÿ ÿrF   c                    sÖ  |dkrt ƒ }|dkri }ˆ dkr`t| ƒ}t|ƒdksDtd|› �ƒ‚t|ƒdkr\tt|ƒƒnd‰ ddd„‰dd„ ‰d‡ ‡‡fd	d
„	}|  ¡ D �]\}}t|ƒtj	fkrªqŒqŒt|ƒt
jt
jfkrÖˆ|ƒrÔˆ|jˆ ƒ|_qŒt|tƒròˆ|ƒrð||ƒ qŒ|dk	�rt|ƒ|k�rˆ|ƒ�r ||ƒ qŒt|ƒ�r<t|ƒ}	|||	ƒ qŒˆ|ƒ�r�t|ƒ|k�r�|t|ƒ  |¡}
t| ||
ƒ |t|ƒ tƒ k�r ||
ƒ qŒt|||ˆ |ƒ qŒt| ƒ�rÒt| tjjƒ�sÒt| ƒ|k�rÒ|| ƒ dS )as  Add observer for the leaf child of the module.

    This function insert observer module to all leaf child module that
    has a valid qconfig attribute.

    Args:
        module: input module with qconfig attributes for all the leaf modules that we want to quantize
        qconfig_propagation_list: a list of quantizable modules that will have observers added to them
            if they are leaf nodes
        device: parent device, if any
        non_leaf_module_list: list of non-leaf modules we want to add observer

    Return:
        None, module is modified inplace with added observer modules and forward_hooks
    Nr   zR_add_observer_ only works with cpu or single-device CUDA modules, but got devices r   c                 S   s,   |d kr|   ¡ n|ƒ }|d k	r(| |¡ |S ©N)Ú
activationÚto)r(   ÚdeviceÚspecial_act_post_processrH   r%   r%   r&   Úget_activation_post_processµ   s    
z3_add_observer_.<locals>.get_activation_post_processc                 S   s   t | dƒo| jd k	S )Nr(   ©r@   r(   )Úmr%   r%   r&   Úneeds_observation»   s    z)_add_observer_.<locals>.needs_observationc                    s>   ˆ| ƒr:t | tƒs:|  dˆ| jˆ |ƒ¡ t| t| jƒd� dS )zn Adds an activation post process module and register
        a pre or post hook that calls the module
        r9   ©rD   N)Ú
isinstancer   Z
add_moduler(   rF   r   )rN   rK   ©rJ   rL   rO   r%   r&   Úinsert_activation_post_process¾   s      ÿz6_add_observer_.<locals>.insert_activation_post_process)N)N)r   Ú_get_unique_devices_ÚlenrA   ÚnextÚiterr.   r   ÚnnZDropoutÚnnqZFloatFunctionalZQFunctionalr(   r9   rQ   r   r	   r
   Ú
from_floatÚsetattrr   Ú_add_observer_r   r,   Z
Sequential)r1   Úqconfig_propagation_listZnon_leaf_module_listrJ   Úcustom_module_class_mappingÚdevicesrS   r5   r6   rK   Zobserved_childr%   rR   r&   r\   —   sL    ÿ







ÿr\   c                 C   s$   dd„ |   ¡ D ƒdd„ |  ¡ D ƒB S )Nc                 S   s   h | ]
}|j ’qS r%   ©rJ   ©Ú.0Úpr%   r%   r&   Ú	<setcomp>í   s     z'_get_unique_devices_.<locals>.<setcomp>c                 S   s   h | ]
}|j ’qS r%   r`   ra   r%   r%   r&   rd   î   s     )Ú
parametersÚbuffers©r1   r%   r%   r&   rT   ì   s    ÿrT   c                 C   sD   t | ƒr t| dƒr | jr t| ƒS |  ¡ D ]\}}t|ƒ| j|< q(| S )a{  Wrap the leaf child module in QuantWrapper if it has a valid qconfig
    Note that this function will modify the children of module inplace and it
    can return a new module which wraps the input module as well.

    Args:
        module: input module with qconfig attributes for all the leaf modules
        that we want to quantize

    Return:
        Either the inplace modified module with submodules wrapped in
        `QuantWrapper` based on qconfig or a new `QuantWrapper` module which
        wraps the input module, the latter case only happens when the input
        module is a leaf module and we want to quantize it.
    r(   )r   r@   r(   r   r.   r   Ú_modules)r1   r5   r6   r%   r%   r&   r   ð   s
    c                 C   s†   t j d¡ |dkrtƒ }| di ¡}|s4t | ¡} |}|dkrFtƒ }t| dd� t	dd„ |  
¡ D ƒƒsrt d¡ t| |||d� | S )	aƒ  Prepares a copy of the model for quantization calibration or quantization-aware training.

    Quantization configuration should be assigned preemptively
    to individual submodules in `.qconfig` attribute.

    The model will be attached with observer or fake quant modules, and qconfig
    will be propagated.

    Args:
        `model`: input model to be modified in-place
        `inplace`: carry out model transformations in-place, the original module is mutated
        `allow_list`: list of quantizable modules
        `observer_non_leaf_module_list`: list of non-leaf modules we want to add observer
        `prepare_custom_config_dict`: customization configuration dictionary for prepare function

    .. code-block:: python

       # Example of prepare_custom_config_dict:
       prepare_custom_config_dict = {
           # user will manually define the corresponding observed
           # module class which has a from_float class method that converts
           # float custom module to observed custom module
           "float_to_observed_custom_module_class": {
               CustomModule: ObservedCustomModule
           }
        }

    z!quantization_api.quantize.prepareNr"   ©r2   c                 s   s   | ]}t |d ƒo|jV  qdS )r(   NrM   )rb   rN   r%   r%   r&   Ú	<genexpr>4  s     zprepare.<locals>.<genexpr>z¬None of the submodule got qconfig applied. Make sure you passed correct configuration through `qconfig_dict` or by assigning the `.qconfig` attribute directly on submodules)r^   )r,   Ú_CÚ_log_api_usage_oncer   r*   ÚcopyÚdeepcopyr   r   ÚanyÚmodulesÚwarningsÚwarnr\   )ÚmodelÚinplaceZ
allow_listÚobserver_non_leaf_module_listr4   r^   r]   r%   r%   r&   r     s&    

  þc                    sD   t ˆ dƒrtˆ jƒrtˆ dƒ d‡ fdd„	}|dd� |dd� d S )Nr9   Fc                    s^   | r
ˆ j nˆ j}| rtnt}tƒ }| ¡ D ]\}}||kr*| |¡ q*|D ]}| |¡ qJd S rG   )Ú_forward_pre_hooksÚ_forward_hooksr>   r=   ÚsetÚitemsÚaddÚpop)rD   Zhook_mapZobserver_hookZhandle_ids_to_removeZ	handle_idÚhook_fnrg   r%   r&   Úremove_hooksF  s    z5_remove_activation_post_process.<locals>.remove_hooksTrP   )F)r@   r   r9   Údelattr)r1   r}   r%   rg   r&   Ú_remove_activation_post_process>  s    
ÿ


r   c                 C   s0   |   ¡ D ]}t|ƒ qt| dƒr$| `t| ƒ dS )zŠClean up the qconfig left in the module so that new qconfig can be
    propagated.

    Args:
        module: module to be cleaned up
    r(   N)ÚchildrenÚ_remove_qconfigr@   r(   r   )r1   r6   r%   r%   r&   r�   T  s
    

r�   c                 C   s\   t j d¡ |dkrtƒ }|s(t | ¡} |  ¡  t| dd� || f|žŽ  t| |dd� | S )aƒ  Quantize the input float model with post training static quantization.

    First it will prepare the model for calibration, then it calls
    `run_fn` which will run the calibration step, after that we will
    convert the model to a quantized model.

    Args:
        model: input float model
        run_fn: a calibration function for calibrating the prepared model
        run_args: positional arguments for `run_fn`
        inplace: carry out model transformations in-place, the original module is mutated
        mapping: correspondence between original module types and quantized counterparts

    Return:
        Quantized model.
    z"quantization_api.quantize.quantizeNT©rt   )	r,   rk   rl   r   rm   rn   Úevalr   r    )rs   Úrun_fnÚrun_argsÚmappingrt   r%   r%   r&   r   c  s    
c                 C   st  t j d¡ |dkrÀ|t jkrHtjttjttjttj	ttj
ttjti}nv|t jkr|tjttjttjttj	ttj
ttjti}nB|t jkr˜tjttjti}n&|t jkr®tjti}ntd|› d�ƒ‚npt|tƒ�r0|t jkrÜt}n@|t jkrìt}n0|t jkrüt}n |t jk�rt}ntdt|ƒƒ‚tt|t |¡ƒƒ}|dk�r@tƒ }|�sPt | ¡} |   ¡  t!| |ƒ t"| |dd� | S )av  Converts a float model to dynamic (i.e. weights-only) quantized model.

    Replaces specified modules with dynamic weight-only quantized versions and output the quantized model.

    For simplest usage provide `dtype` argument that can be float16 or qint8. Weight-only quantization
    by default is performed for layers with large weights size - i.e. Linear and RNN variants.

    Fine grained control is possible with `qconfig` and `mapping` that act similarly to `quantize()`.
    If `qconfig` is provided, the `dtype` argument is ignored.

    Args:
        model: input model
        qconfig_spec: Either:

            - A dictionary that maps from name or type of submodule to quantization
              configuration, qconfig applies to all submodules of a given
              module unless qconfig for the submodules are specified (when the
              submodule already has qconfig attribute). Entries in the dictionary
              need to be QConfig instances.

            - A set of types and/or submodule names to apply dynamic quantization to,
              in which case the `dtype` argument is used to specify the bit-width

        inplace: carry out model transformations in-place, the original module is mutated
        mapping: maps type of a submodule to a type of corresponding dynamically quantized version
            with which the submodule needs to be replaced

    z*quantization_api.quantize.quantize_dynamicNz5Don't know how to quantize with default settings for z. Provide full qconfig pleasez.Unknown dtype specified for quantize_dynamic: Tr‚   )#r,   rk   rl   Úqint8rX   ZLinearr   ÚLSTMZGRUZLSTMCellZRNNCellZGRUCellZfloat16r   Zquint8ZEmbeddingBagr   Z	EmbeddingZquint4x2r   Ú
ValueErrorrQ   rx   ÚRuntimeErrorÚstrÚdictÚzipÚ	itertoolsÚrepeatr   rm   rn   rƒ   r   r    )rs   Zqconfig_specZdtyper†   rt   Zdefault_qconfigr%   r%   r&   r     s|    
      ú
      ú
  þ
 ÿ
ÿ





c                 C   sl   t j d¡ | jstdƒ‚|dkr(tƒ }|s6t | ¡} t| dd� t	| |ddd� t
| t| ¡ ƒdd� | S )	a  
    Prepares a copy of the model for quantization calibration or
    quantization-aware training and converts it to quantized version.

    Quantization configuration should be assigned preemptively
    to individual submodules in `.qconfig` attribute.

    Args:
        model: input model to be modified in-place
        mapping: dictionary that maps float modules to quantized modules to be
                 replaced.
        inplace: carry out model transformations in-place, the original module
                 is mutated
    z%quantization_api.quantize.prepare_qatz1prepare_qat only works on models in training modeNri   TF)r†   rt   Úremove_qconfig)ru   rt   )r,   rk   rl   ZtrainingrA   r   rm   rn   r   r    r   rx   Úvalues)rs   r†   rt   r%   r%   r&   r   Ô  s    
c                 C   sL   t j d¡ |st | ¡} |  ¡  t| dd� || f|žŽ  t| dd� | S )ag  Do quantization aware training and output a quantized model

    Args:
        model: input model
        run_fn: a function for evaluating the prepared model, can be a
                function that simply runs the prepared model or a training
                loop
        run_args: positional arguments for `run_fn`

    Return:
        Quantized model.
    z&quantization_api.quantize.quantize_qatTr‚   )r,   rk   rl   rm   rn   Útrainr   r    )rs   r„   r…   rt   r%   r%   r&   r   ð  s    
Tc                 C   s<   t j d¡ |st | ¡} t| |d||d� |r8t| ƒ | S )ag  Converts submodules in input module to a different module according to `mapping`
    by calling `from_float` method on the target module class. And remove qconfig at the
    end if remove_qconfig is set to True.

    Args:
        `module`: prepared and calibrated module
        `mapping`: a dictionary that maps from source module type to target
                   module type, can be overwritten to allow swapping user defined
                   Modules
        `inplace`: carry out model transformations in-place, the original module
                   is mutated
        `convert_custom_config_dict`: custom configuration dictionary for convert function

    .. code-block:: python

       # Example of convert_custom_config_dict:
       convert_custom_config_dict = {
           # user will manually define the corresponding quantized
           # module class which has a from_observed class method that converts
           # observed custom module to quantized custom module
           "observed_to_quantized_custom_module_class": {
               ObservedCustomModule: QuantizedCustomModule
           }
       }

    z!quantization_api.quantize.convertT)rt   Úis_referenceÚconvert_custom_config_dict)r,   rk   rl   rm   rn   Ú_convertr�   )r1   r†   rt   r�   r“   r”   r%   r%   r&   r      s    
   þc                 C   s¬   |dkr|rt ƒ ntƒ }|dkr&tƒ }| di ¡}|s@t | ¡} i }|  ¡ D ]>\}}t|tƒszt	|ƒ|krzt
||d||ƒ t|||ƒ||< qL| ¡ D ]\}	}
|
| j|	< q”| S )a  Converts submodules in input module to a different module according to `mapping`
    by calling `from_float` method on the target module class

    Args:
        module: input module
        mapping: a dictionary that maps from source module type to target
                 module type, can be overwritten to allow swapping user defined
                 Modules
        inplace: carry out model transformations in-place, the original module
                 is mutated
        is_reference: a flag to enable quantized reference module

    Nr#   T)r   r   r   r*   rm   rn   r.   rQ   r   r   r•   r!   ry   rh   )r1   r†   rt   r“   r”   r^   Zreassignr5   ÚmodÚkeyÚvaluer%   r%   r&   r•   -  s,    
ÿ


ÿ ÿr•   c                 C   sJ  | }t | dƒ�rF| jdk	�rFd}t| ƒ|krD|t| ƒ  | ¡}d}nnt| ƒ|kr²|t| ƒ }t |dƒr¤|jr¤| jdk	szt‚| j ¡ }|| jƒ t|ƒ}| | |¡}n
| | ¡}d}|�rF| j	 
¡ D ]}| |¡ qÂ| j 
¡ D ]}	|	tk	rÜ| |	¡ qÜt| ƒ}
t|
ƒdk�std|
› �ƒ‚t|
ƒdk�r2tt|
ƒƒnd}|�rF| |¡ |S )	a	  Swaps the module if it has a quantized counterpart and it has an
    `observer` attached.

    Args:
        mod: input module
        mapping: a dictionary that maps from nn module to nnq module

    Return:
        The corresponding quantized module of `mod`
    r(   NFTÚ_IS_REFERENCEr   zOswap_module only works with cpu or single-device CUDA modules, but got devices r   )r@   r(   r   Zfrom_observedr™   rA   Úweightr   rZ   rv   r‘   rB   rw   r=   rC   rT   rU   rV   rW   rI   )r–   r†   r^   Únew_modZswappedZqmodZweight_post_processZweight_qparamsZpre_hook_fnr|   r_   rJ   r%   r%   r&   r!   U  s<    


ÿ
c                 C   sZ   dd„ }t | dƒr$| j|||ƒd < |  ¡ D ](\}}|rD||ƒ| n|}t|||ƒ q,dS )a,  Traverse the modules and save all observers into dict.
    This is mainly used for quantization accuracy debug
    Args:
        mod: the top module we want to save all observers
        prefix: the prefix for the current module
        target_dict: the dictionary used to save all the observers
    c                 S   s   | dkr| S | d S )Nr'   r)   r%   )r3   r%   r%   r&   Ú
get_prefixŽ  s    z&_get_observer_dict.<locals>.get_prefixr9   N)r@   r9   r.   Ú_get_observer_dict)r–   Útarget_dictr3   rœ   r5   r6   r7   r%   r%   r&   r�   †  s    
r�   )Nr'   N)NN)F)NNNN)FNNN)NF)NF)F)NFTFN)NFFN)r'   )Arm   rŽ   rq   r,   Ztorch.nnrX   Ztorch.ao.nn.quantizedr-   Z	quantizedrY   Ztorch.ao.nn.intrinsicr   Z+torch.ao.quantization.quantization_mappingsr   r   r   r   r   r   r	   r
   Úutilsr   r   Ztorch.ao.quantization.stubsr   r   Ztorch.ao.quantization.qconfigr   r   r   r   r   r   Ztorch.nn.utils.parametrizer   Ztorch.ao.quantization.observerr   Zis_activation_post_processÚ__all__rˆ   ZquantizableZMultiheadAttentionr$   r   r0   r   r=   r>   rF   r\   rT   r   r   r   r�   r   r‡   r   r   r   r    r•   r!   r�   r%   r%   r%   r&   Ú<module>   s’   (
 ö  þ  þû     ÿ
(


U   þ
8
 ÿ
U

        þ
(      þ
(1