U
    Kºct-  ã                   @   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Z d dlmZm	Z	 ddl
mZmZmZmZ d dlmZmZmZ d dlmZ d	gZejejejhZejhZG d
d	„ d	eƒZdS )é    N)Únn)Úparametrize)Ú
ModuleDictÚ
ModuleListé   )ÚPruningParametrizationÚZeroesParametrizationÚActivationReconstructionÚBiasHook)ÚBaseSparsifierÚmodule_to_fqnÚfqn_to_module)Úget_arg_info_from_tensor_fqnÚ
BasePrunerc                       sv   e Zd ZdZd‡ fdd„	Zdd„ Zddd	„Zeefd
d„Z	dd„ Z
ddd„Zddd„Zddd„Zejdd„ ƒZ‡  ZS )r   a  Base class for all pruners.

    Abstract methods that need to be implemented:

    - update_mask: Function to compute a new mask for all keys in the
        `groups` attribute.

    Args:
        - defaults [dict]: default configurations will be attached to the
            configuration. Only the keys that don't exist in the `config` will
            be updated.
        - also_prune_bias [bool]: whether to prune bias in addition to weights (to prune full output channel)
            or not; default=True.

    Tc                    s   t ƒ  |¡ || _d S ©N)ÚsuperÚ__init__Ú
prune_bias)ÚselfÚdefaultsZalso_prune_bias©Ú	__class__© úV/tmp/pip-unpacked-wheel-gikjz4vx/torch/ao/sparsity/_experimental/pruner/base_pruner.pyr   -   s    zBasePruner.__init__c                 C   sö   g }g }|rˆt |d ƒtkrZt|d |d ƒD ](\}}t| j|ƒ}| |¡ | |¡ q.qît| j|d ƒ}| |¡ |d }| |¡ nft |d ƒtkrÊt|d |d ƒD ]\}}| |¡ | |¡ qªn$|d }| |¡ |d }| |¡ ||fS )NÚmoduleÚ
module_fqnÚtensor_name)ÚtypeÚtupleÚzipr   ÚmodelÚappend)r   ÚconfigÚuse_pathÚmodulesÚtensor_namesr   r   r   r   r   r   Ú_get_modules_and_tensor_names1   s*    




z(BasePruner._get_modules_and_tensor_namesFc           
   
   O   sÎ  g | _ g | _| jD ]´}|  ||¡\}}t||ƒD ]f\}}t|ttƒƒsút|ddƒdkrx| 	dt
 t||ƒjd ¡¡ | dt¡}	tj|||	|jƒdd t|jtƒs¬t‚t|jjtƒs¾t‚t|ttƒƒrð| j  | tt|j|ƒd ƒ¡¡ ntdƒ‚nTt|ddƒdkr*| 	dt
 t||ƒjd ¡¡ | dt¡}	tj|||	|jƒdd |jdk	rx| dt  |j !¡ ¡¡ d|_| j | t"|jjd | j#ƒ¡¡ q2t$|ƒd	kr|d jjd j%|d
 jjd _%qdS )z6Adds mask parametrization to the layer weight
        ÚmaskNr   ÚparametrizationT)Zunsafez&This module type is not supported yet.Z_biasé   r   )&Zactivation_handlesZbias_handlesÚgroupsr&   r   Ú
isinstancer   ÚNEEDS_ZEROSÚgetattrZregister_bufferÚtorchZtensorÚshapeÚgetr   r   Zregister_parametrizationr'   Úparametrizationsr   ÚAssertionErrorÚweightr   ÚSUPPORTED_MODULESr!   Zregister_forward_hookr	   ÚNotImplementedErrorr   ZbiasZregister_parameterr   Ú	ParameterÚdetachr
   r   ÚlenÚpruned_outputs)
r   r#   ÚargsÚkwargsr"   r$   r%   r   r   Úparamr   r   r   Ú_prepareL   s6    
ÿ
$zBasePruner._preparec           	      C   s®   g | _ |g}|rª| ¡ }| ¡ D ]†\}}t|ƒ|krbt||ƒ}t|tƒsLt‚| j  d|d i¡ q |d k	rœt|ƒ|krœt	| dƒrœ| j
rœt dt|ƒ› d¡ | |¡ q qd S )NÚ
tensor_fqnú.weightr   zModels with z% layers have config provided by user.)r"   ÚpopZnamed_childrenr   r   r+   Ústrr2   r!   Úhasattrr   ÚwarningsÚwarn)	r   r    r4   r,   Ústackr   ÚnameÚchildZ	child_fqnr   r   r   Úmake_config_from_modelu   s    
$z!BasePruner.make_config_from_modelc                 C   s@  || _ || _| jdkr"|  | j ¡ | jD ]}t|ƒtkr|\}}t|tjƒr\t|tjƒs`t	‚t|tƒsnt	‚d|i}t
 | j¡}| |¡ g }g }g }	|d D ]X}
t||
ƒ}|dkrºd}|rÖ|d dkrÖ|dd… }| |¡ | |d ¡ |	 d¡ q ||d	< ||d
< |	|d< nt|tjƒr,d|i}t
 | j¡}| |¡ | d
d¡dk	rÈ| d
¡}t|tƒsnt	‚t||ƒ}| ¡ D ]:}||kr€|d
ks€|| || ks€t	d |¡ƒ‚q€| |¡ n^|d }
t||
ƒ}|rú|d dkrú|dd… }||d	< d|d< t|tƒst	‚|d |d
< | j |¡ q(|  ¡  dS )aU  Prepares a model, by adding the parametrizations and forward post-hooks.
        Note::
            The model is modified inplace. If you need to preserve the original
            model, use copy.deepcopy.

        Args:
        - model [nn.Module]: model to configure. The model itself is not saved
            but used for the state_dict saving / loading.
        - config [list]: configuration elements could either be instances of
            tuples of dict maps or dict maps. The dicts must have a key 'tensor_fqn' with the
            value being the fqn of the tensor to be pruned.
        Nr   Ú r   Ú.r   r?   r3   r   r>   r   z?Given both `{}` and `tensor_fqn`, it is expected them to agree!)r    r"   rH   r   r   r+   r   ÚConv2dÚBatchNorm2dr2   ÚcopyÚdeepcopyr   Úupdater   r!   ÚModuler0   rA   r   ÚkeysÚformatr*   r=   )r   r    r"   Zmodule_configZfirst_layerZ
next_layerZ
local_argsZmodule_fqn_listZtensor_fqn_listZtensor_name_listr   r   r>   Zinfo_from_tensor_fqnÚkeyr   r   r   Úprepare…   sj    







ÿÿ
zBasePruner.preparec           	      O   s|   | j D ]p}|  ||¡\}}t||ƒD ]P\}}tj||dd t|jdd ƒrT|jd= nt|jdd ƒrj|jd= t|dƒ q$qd S )NT)Zleave_parametrizedr'   )	r*   r&   r   r   Zremove_parametrizationsr-   Ú_parametersÚ_buffersÚdelattr)	r   r#   r:   r;   r"   r$   r%   r   r   r   r   r   Úsquash_maskÔ   s    
ÿ
zBasePruner.squash_maskr3   c                 C   s    t  |¡st‚t|j|ƒd jS )z+Returns the set of pruned indices of moduler   )r   Zis_parametrizedr2   r-   r1   r9   )r   r   r   r   r   r   Úget_module_pruned_outputsá   s    z$BasePruner.get_module_pruned_outputsc              	   C   sn   | j s
d S t ¡ R | jD ]D}|  ||¡\}}i }| ¡  |d |d< |d |d< | jf |Ž qW 5 Q R X d S )Nr   r   r   )Zenable_mask_updater.   Zno_gradr*   r&   rO   Úupdate_mask)r   r#   r"   r$   r%   Zuntupled_argsr   r   r   Ústepæ   s    

zBasePruner.stepc                 K   s   d S r   r   )r   r   r   r;   r   r   r   rZ   õ   s    zBasePruner.update_mask)T)F)F)r3   )F)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r&   r=   r4   r,   rH   rT   rX   rY   r[   ÚabcÚabstractmethodrZ   Ú__classcell__r   r   r   r   r      s   
)O


)rM   rC   r`   r.   r   Ztorch.nn.utilsr   Ztorch.nn.modules.containerr   r   r(   r   r   r	   r
   Ztorch.ao.sparsityr   r   r   Z"torch.ao.sparsity.sparsifier.utilsr   Ú__all__ZLinearrK   rL   r4   r,   r   r   r   r   r   Ú<module>   s"   ýÿ