o
    #ji                     @   s   d dl Z d dlZd dlmZ ddlmZ G dd dejZdd Zdd
dZdd Z	dd Z
dd Zdd Zdd Zdd Zdd Zdd ZejejfeejejfeiZdS )    N)nn   )utilsc                       s(   e Zd ZdZ fddZdd Z  ZS )Identityz$a layer to replace bn or relu layersc                    s   t    d S N)super__init__)selfargskwargs	__class__ j/var/www/html/Deteccion_Ine/venv/lib/python3.10/site-packages/paddle/quantization/imperative/fuse_utils.pyr      s   zIdentity.__init__c                 C   s   |S r   r   )r	   inputr   r   r   forward   s   zIdentity.forward)__name__
__module____qualname____doc__r   r   __classcell__r   r   r   r   r      s    r   c                 C   s   d}| j r|   d}g }d d g}|  D ]/\}}t|tjr#||d< t|tjr-||d< |d rD|d rDt|dkrD|| d d g}qt	| |} |rR| 
  d S d S )NFTr   r      )trainingevalZnamed_sublayers
isinstancer   Conv2DBatchNorm2Dlenappendfuse_layerstrain)modelZis_trainZ	fuse_listZtmp_pairnamelayerr   r   r   fuse_conv_bn!   s&   

r$   Fc                 C   s*   |du r	t | } |D ]}t| | q| S )a1  
    fuse layers in layers_to_fuse

    Args:
        model(paddle.nn.Layer): The model to be fused.
        layers_to_fuse(list): The layers' names to be fused. For
            example,"fuse_list = [["conv1", "bn1"], ["conv2", "bn2"]]".
            A TypeError would be raised if "fuse" was set as
            True but "fuse_list" was None.
                              Default: None.
        inplace(bool): Whether apply fusing to the input model.
                       Default: False.

    Return
        fused_model(paddle.nn.Layer): The fused model.
    F)copydeepcopy_fuse_layers)r!   Zlayers_to_fuseZinplaceZlayersr   r   r   r   6   s
   
r   c           	      C   sl   g }|D ]}t | |\}}|t|| qt|}t|D ]\}}t | |\}}t||||  qdS )z"fuse all the layers in layers_listN)r   Zfind_parent_layer_and_sub_namer   getattr
_fuse_func	enumeratesetattr)	r!   Zlayers_list
layer_listZ
layer_nameZparent_layerZsub_name
new_layersiitemr   r   r   r'   N   s   r'   c           
      C   s   t dd | D }t|d}dgt|  }||  }| d j D ]\}}|| | d j|= q!| d j D ]\}}|| | d j|= q8||d< t	dt| D ]}t
 }	| d j|	_|	||< qS|S )z'choose the fuser method and fuse layersc                 s   s    | ]}t |V  qd S r   )type).0mr   r   r   	<genexpr>`   s    z_fuse_func.<locals>.<genexpr>Nr   r   )tupletypes_to_fusion_methodgetr   Z_forward_pre_hooksitemsZregister_forward_pre_hookZ_forward_post_hooksZregister_forward_post_hookranger   r   )
r,   typesZfusion_methodr-   Zfused_layerZ	handle_idZpre_hook_fnZhook_fnr.   identityr   r   r   r)   ^   s    


r)   c                 C   s<   | j |j ks
J d| j r|j| jksJ dtt| |S )z"fuse conv and bn for train or evalz:Conv and BN both must be in the same mode (train or eval).z?Output channel of Conv2d must match num_features of BatchNorm2d)r   _num_features_out_channelsNotImplementedError_fuse_conv_bn_eval)convbnr   r   r   _fuse_conv_bnr   s   
rB   c                 C   s   | j s|j r
J dt| }t|j|j|j|j|j|j|j\}}|j	| |jdu r:t
j|jgd|jjd|_|j	| |S )zfuse conv and bn for evalFusion only for eval!NTshapeZis_biasdtype)r   r%   r&   _fuse_conv_bn_weightsweightbias_mean	_variance_epsilon	set_valuepaddlecreate_parameterr=   rF   )r@   rA   Z
fused_convfused_weight
fused_biasr   r   r   r?      s$   
	
r?   c                 C   s   |du r	t |}|du rt |}|du rt |}t || }| || dgdgt| jd    } || | | | }| |fS )z$fuse weights and bias of conv and bnNr4   r   )rN   
zeros_likeZ	ones_likersqrtZreshaper   rE   )Zconv_wZconv_bbn_rmbn_rvbn_epsbn_wbn_bZbn_var_rsqrtr   r   r   rG      s   



rG   c                 C   sB   | j |j ks
J d| j r|j| jjd ksJ dtt| |S )zfuse linear and bnz<Linear and BN both must be in the same mode (train or eval).r   z=Output channel of Linear must match num_features of BatchNorm)r   r<   rH   rE   r>   _fuse_linear_bn_eval)linearrA   r   r   r   _fuse_linear_bn   s   
r[   c                 C   s   | j s|j r
J dt| }t|j|j|j|j|j|j|j\}}|j	| |jdu r=t
j|jjd gd|jjd|_|j	| |S )zfuse linear and bn for evalrC   Nr   TrD   )r   r%   r&   _fuse_linear_bn_weightsrH   rI   rJ   rK   rL   rM   rN   rO   rE   rF   )rZ   rA   Zfused_linearrP   rQ   r   r   r   rY      s(   
	
rY   c           
      C   sJ   |du r	t |}|t ||  }| |d }|| | | }	||	fS )z&fuse weights and bias of linear and bnNr4   )rN   rR   rS   Z	unsqueeze)
Zlinear_wZlinear_brT   rU   rV   rW   rX   Zbn_scaleZfused_wZfused_br   r   r   r\      s   
r\   )F)r%   rN   r    r   ZLayerr   r$   r   r'   r)   rB   r?   rG   r[   rY   r\   r   r   ZLinearZBatchNorm1Dr6   r   r   r   r   <module>   s$   

