a
    dSB                     @   s  d Z ddlZddlZddlmZmZmZmZmZm	Z	 ddl
Z
ddl
mZ ddlmZ ddlmZ ddlZddlmZmZ ddlmZ dd	lmZ erdd
lmZ nddlmZ dddeee	eef  edddZdeedddZdeee e dddZ!G dd deZ"dS )z
Quantization
^^^^^^^^^^^^

    N)AnyCallableDictOptionalSequenceUnion)Tensor)QConfig)FakeQuantizeBase)_TORCH_GREATER_EQUAL_1_11_TORCH_GREATER_EQUAL_1_12)Callback)MisconfigurationException)fuse_modules_qat)fuse_modulesQuantizationAwareTrainingpl.LightningModule)quant_cbmodelfunctrigger_conditionreturnc                    s(   t  ttd fdd}|S )zDecorator to wrap forward path as it is needed to quantize inputs and dequantize outputs for in/out
    compatibility Moreover this version has the (de)quantization conditional as it may not be needed for the
    training all the time.datar   c                    sl   t oj}tto$jk }d u p4|p4|}|rR jd7  _| }  | } |rh| } | S )N   )callabletrainer
isinstanceint_forward_callsquantdequant)r   Z_is_func_trueZ_is_count_trueZ
_quant_runr   r   r   r    q/var/www/html/stable-diffusion-webui/venv/lib/python3.9/site-packages/pytorch_lightning/callbacks/quantization.pywrapper1   s    

z)wrap_qat_forward_context.<locals>.wrapper	functoolswrapsr   )r   r   r   r   r%   r#   r"   r$   wrap_qat_forward_context'   s    
r)   )r   r   r   c                    s$   t  ttd fdd}|S )zvDecorator to wrap forward path as it is needed to quantize inputs and dequantize outputs for in/out
    compatibility.r   c                    s     | }  | } | } | S N)r    r!   )r   r   r   r#   r$   r%   G   s    

z.wrap_quantize_forward_context.<locals>.wrapperr&   )r   r   r%   r#   r+   r$   wrap_quantize_forward_contextC   s    r,   T)objattribsstater   c                 C   sF   d|v r8| dd\}}t| |r4tt| |||S dS |oDt| |S )z:recursive check if model has some layers denoted with '.'..r   F)splithasattr_recursive_hasattrgetattr)r-   r.   r/   attribr#   r#   r$   r3   Q   s    
r3   c                
   @   s  e Zd ZdZdZdZd5eeef ee	ee
ef  e	e eeee dd	d
dZdedddZeeef dddZdddddZddddZdddddZddddddZddddddZddddd d!Zddddd"d#Zddddd$d%Zddddd&d'Zddddd(d)Zddddd*d+Zddddd,d-Zddddd.d/Z eee!f dd0d1Z"deee!f dd2d3d4Z#dS )6r   a  Quantization allows speeding up inference and decreasing memory requirements by performing computations and
    storing tensors at lower bitwidths (such as INT8 or FLOAT16) than floating point precision. We use native
    PyTorch API so for more information see `PyTorch Quantization`_.

    .. warning:: ``QuantizationAwareTraining`` is in beta and subject to change.

    The ``LightningModule`` is prepared for QAT training in the ``on_fit_start`` hook. Checkpoints saved during training
    include already collected stats to perform the Quantization conversion, but it doesn't contain the quantized or
    fused model/layers. The quantization is performed in the ``on_fit_end`` hook so the model needs to be saved after
    training finishes if quantization is desired.

    Args:

        qconfig: quantization configuration:

            - 'fbgemm' for server inference.
            - 'qnnpack' for mobile inference.
            - a custom `torch.quantization.QConfig`_.

        observer_type: allows switching between ``MovingAverageMinMaxObserver`` as "average" (default)
            and ``HistogramObserver`` as "histogram" which is more computationally expensive.

        collect_quantization: count or custom function to collect quantization statistics:

            - ``None`` (default). The quantization observer is called in each module forward
                (useful for collecting extended statistic when using image/data augmentation).
            - ``int``. Use to set a fixed number of calls, starting from the beginning.
            - ``Callable``. Custom function with single trainer argument.
                See this example to trigger only the last epoch:

                .. code-block:: python

                    def custom_trigger_last(trainer):
                        return trainer.current_epoch == (trainer.max_epochs - 1)


                    QuantizationAwareTraining(collect_quantization=custom_trigger_last)

        modules_to_fuse: allows you fuse a few layers together as shown in
            `diagram <https://pytorch.org/docs/stable/quantization.html#quantization-aware-training>`_
            to find which layer types can be fused, check https://github.com/pytorch/pytorch/pull/43286.

        input_compatible: preserve quant/dequant layers. This allows to feat any input as to the original model,
            but break compatibility to torchscript and export with ``torch.save``.

        quantize_on_fit_end: perform the quantization in `on_fit_end`.
            Note that once converted, the model cannot be put in training mode again.

        observer_enabled_stages: allow fake-quantization modules' observers to do calibration during provided stages:

            - ``'train'``: the observers can do calibration during training.
            - ``'validate'``: the observers can do calibration during validating.
              Note that we don't disable observers during the sanity check as the model hasn't been calibrated with
              training data yet. After the sanity check, the fake-quantization modules are restored to initial states.
            - ``'test'``: the observers can do calibration during testing.
            - ``'predict'``: the observers can do calibration during predicting.

            Note that we only handle observers belonging to fake-quantization modules. When ``qconfig`` is a ``str`` and
            ``observer_type`` is ``'histogram'``, the observers won't belong to any fake-quantization modules and will
            not be controlled by the callback.

    .. _PyTorch Quantization: https://pytorch.org/docs/stable/quantization.html#quantization-aware-training
    .. _torch.quantization.QConfig:
        https://pytorch.org/docs/stable/generated/torch.quantization.qconfig.QConfig.html#qconfig
    )	histogramaverage)trainvalidatetestpredictfbgemmr7   NTr8   )qconfigobserver_typecollect_quantizationmodules_to_fuseinput_compatiblequantize_on_fit_endobserver_enabled_stagesr   c           
      C   s  t |to|tjjjv }t |ts@|s@td| dtjjj || _|| j	vrhtd| d| j	 d|| _
|d urt |tst|std| d|| _|| _|| _|| _t|}|t| j }	|	rtdtt|	 d| j dt| j| | _d	| _i | _i | _d
| _d S )NzUnsupported qconfig: fz.
Try one of defaults: zUnsupported observer type "z", allowed are r0   z$Unsupported `collect_quantization` "z#", allowed are `int` or `Callable`.zUnsupported stages "r   F)r   strtorchbackendsZ	quantizedZsupported_enginesr	   r   _qconfigOBSERVER_TYPES_observer_typer   r   _collect_quantization_modules_to_fuse_input_compatible_convert_on_fit_endsetOBSERVER_STAGEStuplesorted_observer_disabled_stagesr   !_fake_quant_to_initial_state_dict$_last_fake_quant_to_observer_enabled_module_prepared)
selfr>   r?   r@   rA   rB   rC   rD   Z_valid_qconf_strZunsupported_stagesr#   r#   r$   __init__   sD    


z"QuantizationAwareTraining.__init__r   )r   r   c                    s@   | j s
dS | j D ]*}t fdd|D std| dqdS )NFc                 3   s   | ]}t  |V  qd S r*   )r3   ).0mr   r#   r$   	<genexpr>       zAQuantizationAwareTraining._check_feasible_fuse.<locals>.<genexpr>zYou have requested to fuse z5 but one or more of them is not your model attributesT)rL   allr   )rW   r   groupr#   r[   r$   _check_feasible_fuse   s    

z.QuantizationAwareTraining._check_feasible_fuse)r   c                 C   s   dd | j D S )Nc                 S   s   i | ]}||j  qS r#   )observer_enabledclonerY   
fake_quantr#   r#   r$   
<dictcomp>   s   zGQuantizationAwareTraining._collect_observer_enabled.<locals>.<dictcomp>)rT   rW   r#   r#   r$   _collect_observer_enabled   s    z3QuantizationAwareTraining._collect_observer_enabled)	pl_moduler   c                 C   s   |   | _|tjj d S r*   )rg   rU   applyrF   quantizationZdisable_observer)rW   rh   r#   r#   r$   _disable_observer   s    
z+QuantizationAwareTraining._disable_observerc                 C   s$   | j  D ]\}}|j| q
d S r*   )rU   itemsra   Zcopy_)rW   rd   ra   r#   r#   r$   _restore_last_observer_enabled   s    z8QuantizationAwareTraining._restore_last_observer_enabledc                 C   s   | j r
d S tj |_tj |_|j| _t	| ||j| j
d|_t| jtr| jdkrhtj| j|_q| jdkrtjj| jtrdnd d|_nt| jtr| j|_| |rt|| jdd tjj|dd tdd	 | D }d
d |D | _d| _ d S )N)r   r   r   r   r6   r7   r   )versionTZinplacec                 s   s   | ]}t |tr|V  qd S r*   )r   r
   )rY   moduler#   r#   r$   r\   
  r]   z;QuantizationAwareTraining._prepare_model.<locals>.<genexpr>c                 S   s   i | ]}|t | qS r#   )copydeepcopy
state_dictrc   r#   r#   r$   re     s   z<QuantizationAwareTraining._prepare_model.<locals>.<dictcomp>)rV   rF   rj   Z	QuantStubr    ZDeQuantStubr!   forward*_QuantizationAwareTraining__module_forwardr)   rK   r   rH   rE   rJ   Zget_default_qconfigr>   Zget_default_qat_qconfigr   r	   r`   r   rL   Zprepare_qatrQ   modulesrT   )rW   r   Zfake_quantsr#   r#   r$   _prepare_model   s2    



z(QuantizationAwareTraining._prepare_modelz
pl.Trainer)r   rh   r   c                 C   s   |  | d S r*   )rw   rW   r   rh   r#   r#   r$   on_fit_start  s    z&QuantizationAwareTraining.on_fit_startc                 C   sN   | j s| j|_d S |  tjj|dd | jrBt|| jd|_n| j|_d S )NTro   )r   r   )	rN   ru   rt   evalrF   rj   convertrM   r,   rx   r#   r#   r$   
on_fit_end  s    
z$QuantizationAwareTraining.on_fit_endc                 C   s   d| j v r| | d S Nr8   rS   rk   rx   r#   r#   r$   on_train_start&  s    
z(QuantizationAwareTraining.on_train_startc                 C   s   d| j v r|   d S r}   rS   rm   rx   r#   r#   r$   on_train_end*  s    
z&QuantizationAwareTraining.on_train_endc                 C   s   d| j v r|js| | d S Nr9   )rS   sanity_checkingrk   rx   r#   r#   r$   on_validation_start.  s    z-QuantizationAwareTraining.on_validation_startc                 C   s<   d| j v r8|jr0| j D ]\}}|| qn|   d S r   )rS   r   rT   rl   Zload_state_dictrm   )rW   r   rh   rd   rs   r#   r#   r$   on_validation_end6  s
    
z+QuantizationAwareTraining.on_validation_endc                 C   s   d| j v r| | d S Nr:   r~   rx   r#   r#   r$   on_test_start>  s    
z'QuantizationAwareTraining.on_test_startc                 C   s   d| j v r|   d S r   r   rx   r#   r#   r$   on_test_endB  s    
z%QuantizationAwareTraining.on_test_endc                 C   s   d| j v r| | d S Nr;   r~   rx   r#   r#   r$   on_predict_startF  s    
z*QuantizationAwareTraining.on_predict_startc                 C   s   d| j v r|   d S r   r   rx   r#   r#   r$   on_predict_endJ  s    
z(QuantizationAwareTraining.on_predict_endc                    s   h d} fdd|D S )N>   rJ   rM   rL   rH   rK   c                    s   i | ]}|t  |qS r#   )r4   )rY   nrf   r#   r$   re   P  r]   z8QuantizationAwareTraining.state_dict.<locals>.<dictcomp>r#   )rW   keysr#   rf   r$   rs   N  s    z$QuantizationAwareTraining.state_dict)r   rs   r   c                 C   s,   |  D ]\}}t| || q| | dS )a  Special hook that gets called by the CheckpointConnector *before* the model gets loaded.

        This hook replaces the :meth:`on_load_checkpoint` and :meth:`load_state_dict` callback methods which get called
        after the model has already loaded the weights. For quantization, we need to convert the model first before that
        happens, assuming the previous training used quantization.
        N)rl   setattrrw   )rW   r   rs   kvr#   r#   r$   _load_before_modelR  s    z,QuantizationAwareTraining._load_before_model)r<   r7   NNTTr=   )$__name__
__module____qualname____doc__rI   rP   r   rE   r	   r   r   r   r   boolrX   r`   r   r
   r   rg   rk   rm   rw   ry   r|   r   r   r   r   r   r   r   r   r   rs   r   r#   r#   r#   r$   r   [   sJ   B       
0
()N)T)#r   rq   r'   typingr   r   r   r   r   r   rF   r   Ztorch.ao.quantization.qconfigr	   Ztorch.quantizationr
   Zpytorch_lightningplZ"lightning_fabric.utilities.importsr   r   Z$pytorch_lightning.callbacks.callbackr   Z&pytorch_lightning.utilities.exceptionsr   Ztorch.ao.quantizationr   r   r   r)   r,   rE   r   r3   r   r#   r#   r#   r$   <module>   s2     
