o
    h                     @   s2  d Z ddlZddlmZmZ ddlmZ ddlZG dd deZG dd deZ	G d	d
 d
eZ
G dd deZG dd deZG dd deZG dd deZG dd deZdd Zdd Zd3ddZdd Zd3ddZd3dd Zd!d" Zd#d$ Zd%d& Zd'd( Zd)d* Zd+d, Zd-d. Zd/d0 Zd1d2 ZdS )4zPruning methods.    N)ABCabstractmethod)Iterablec                   @   sZ   e Zd ZU dZeed< dd Zedd Zdd Z	e
d	d
ddZdddZdd Zd	S )BasePruningMethodzAbstract base class for creation of new pruning techniques.

    Provides a skeleton for customization requiring the overriding of methods
    such as :meth:`compute_mask` and :meth:`apply`.
    _tensor_namec                 C   s   t || j| | dS )a  Multiply the mask into original tensor and store the result.

        Multiplies the mask (stored in ``module[name + '_mask']``)
        into the original tensor (stored in ``module[name + '_orig']``)
        and stores the result into ``module[name]`` by using :meth:`apply_mask`.

        Args:
            module (nn.Module): module containing the tensor to prune
            inputs: not used.
        N)setattrr   
apply_mask)selfmoduleinputs r   h/var/www/html/construction_image-detection-poc/venv/lib/python3.10/site-packages/torch/nn/utils/prune.py__call__   s   zBasePruningMethod.__call__c                 C   s   dS )a  Compute and returns a mask for the input tensor ``t``.

        Starting from a base ``default_mask`` (which should be a mask of ones
        if the tensor has not been pruned yet), generate a random mask to
        apply on top of the ``default_mask`` according to the specific pruning
        method recipe.

        Args:
            t (torch.Tensor): tensor representing the importance scores of the
            parameter to prune.
            default_mask (torch.Tensor): Base mask from previous pruning
            iterations, that need to be respected after the new mask is
            applied. Same dims as ``t``.

        Returns:
            mask (torch.Tensor): mask to apply to ``t``, of same dims as ``t``
        Nr   )r	   tdefault_maskr   r   r   compute_mask    s    zBasePruningMethod.compute_maskc                 C   sP   | j dusJ d| dt|| j d }t|| j d }|j|jd| }|S )a  Simply handles the multiplication between the parameter being pruned and the generated mask.

        Fetches the mask and the original tensor from the module
        and returns the pruned version of the tensor.

        Args:
            module (nn.Module): module containing the tensor to prune

        Returns:
            pruned_tensor (torch.Tensor): pruned version of the input tensor
        NModule z has to be pruned_mask_origdtype)r   getattrtor   )r	   r
   maskorigpruned_tensorr   r   r   r   4   s   
zBasePruningMethod.apply_maskNimportance_scoresc             
   O   s2  dd }|| ||g|R i |}t ||}|dur+|j|jks*J d| d| n|}t|tsD||d | |j|= t|}	nt ||d  j	tj
d}	z |j||	d	}
||d |
 t|||| || W |S  ty } zt|tst ||d }||| |j|d = |d}~ww )
a  Add pruning on the fly and reparametrization of a tensor.

        Adds the forward pre-hook that enables pruning on the fly and
        the reparametrization of a tensor in terms of the original tensor
        and the pruning mask.

        Args:
            module (nn.Module): module containing the tensor to prune
            name (str): parameter name within ``module`` on which pruning
                will act.
            args: arguments passed on to a subclass of
                :class:`BasePruningMethod`
            importance_scores (torch.Tensor): tensor of importance scores (of
                same shape as module parameter) used to compute mask for pruning.
                The values in this tensor indicate the importance of the
                corresponding elements in the parameter being pruned.
                If unspecified or None, the parameter will be used in its place.
            kwargs: keyword arguments passed on to a subclass of a
                :class:`BasePruningMethod`
        c                 _   s   d }d}g }|j  D ]\}}	t|	tr$|	j|kr$|	}|| |d7 }q|dks4J d| d| d|D ]}|j |= q6| |i |}
||
_|d urit|trY||
 |}
|
S t|trit|}||
 |}
|
S )Nr      zFAvoid adding multiple pruning hooks to the                same tensor z of module z. Use a PruningContainer.)_forward_pre_hooksitems
isinstancer   r   appendPruningContaineradd_pruning_method)clsr
   nameargskwargs
old_methodfoundhooks_to_removekhookmethod	containerr   r   r   _get_composite_methoda   s<   







z6BasePruningMethod.apply.<locals>._get_composite_methodNzJimportance_scores should have the same shape as parameter                 z of r   r   memory_formatr   )r   shaper!   r#   register_parameter_parameterstorch	ones_likedetachclonecontiguous_formatr   register_bufferr   r   register_forward_pre_hook	Exception)r%   r
   r&   r   r'   r(   r0   r.   r   r   r   er   r   r   applyJ   s>   /


	
zBasePruningMethod.applyc                 C   sJ   |dur|j |j ksJ dn|}|dur|nt|}|| j||d S )a  Compute and returns a pruned version of input tensor ``t``.

        According to the pruning rule specified in :meth:`compute_mask`.

        Args:
            t (torch.Tensor): tensor to prune (of same dimensions as
                ``default_mask``).
            importance_scores (torch.Tensor): tensor of importance scores (of
                same shape as ``t``) used to compute mask for pruning ``t``.
                The values in this tensor indicate the importance of the
                corresponding elements in the ``t`` that is being pruned.
                If unspecified or None, the tensor ``t`` will be used in its place.
            default_mask (torch.Tensor, optional): mask from previous pruning
                iteration, if any. To be considered when determining what
                portion of the tensor that pruning should act on. If None,
                default to a mask of ones.

        Returns:
            pruned version of tensor ``t``.
        Nz8importance_scores should have the same shape as tensor tr3   )r4   r7   r8   r   )r	   r   r   r   r   r   r   prune   s   zBasePruningMethod.prunec                 C   s   | j dusJ d| d| |}t|| j rt|| j  |j| j d  }|j|_|j| j d = |j| j d = t|| j | dS )ar  Remove the pruning reparameterization from a module.

        The pruned parameter named ``name`` remains permanently pruned,
        and the parameter named ``name+'_orig'`` is removed from the parameter list.
        Similarly, the buffer named ``name+'_mask'`` is removed from the buffers.

        Note:
            Pruning itself is NOT undone or reversed!
        Nr   z: has to be pruned            before pruning can be removedr   r   )r   r   hasattrdelattrr6   data_buffersr   )r	   r
   weightr   r   r   r   remove   s   

zBasePruningMethod.remove)NN)__name__
__module____qualname____doc__str__annotations__r   r   r   r   classmethodr@   rA   rG   r   r   r   r   r   
   s   
 
 
r   c                   @   s@   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dS )r#   a  Container holding a sequence of pruning methods for iterative pruning.

    Keeps track of the order in which pruning methods are applied and handles
    combining successive pruning calls.

    Accepts as argument an instance of a BasePruningMethod or an iterable of
    them.
    c                 G   sh   d| _ t|ts|j| _| | d S t|dkr(|d j| _| |d  d S |D ]}| | q*d S )Nr   r   r   )_pruning_methodsr!   r   r   r$   len)r	   r'   r.   r   r   r   __init__  s   
zPruningContainer.__init__c                 C   sr   t |ts|durtt| d|dur/| j|jkr/td| j d|  dd|j d |  j|f7  _dS )zAdd a child pruning ``method`` to the container.

        Args:
            method (subclass of BasePruningMethod): child pruning method
                to be added to the container.
        Nz$ is not a BasePruningMethod subclassz<Can only add pruning methods acting on the parameter named 'z' to PruningContainer .z Found '')r!   r   	TypeErrortyper   
ValueErrorrO   )r	   r.   r   r   r   r$     s   z#PruningContainer.add_pruning_methodc                 C   
   t | jS N)rP   rO   r	   r   r   r   __len__.     
zPruningContainer.__len__c                 C   rW   rX   )iterrO   rY   r   r   r   __iter__1  r[   zPruningContainer.__iter__c                 C   s
   | j | S rX   rO   )r	   idxr   r   r   __getitem__4  r[   zPruningContainer.__getitem__c                 C   s"   dd }| j d }||||}|S )a  Apply the latest ``method`` by computing the new partial masks and returning its combination with the ``default_mask``.

        The new partial mask should be computed on the entries or channels
        that were not zeroed out by the ``default_mask``.
        Which portions of the tensor ``t`` the new mask will be calculated from
        depends on the ``PRUNING_TYPE`` (handled by the type handler):

        * for 'unstructured', the mask will be computed from the raveled
          list of nonmasked entries;

        * for 'structured', the mask will be computed from the nonmasked
          channels in the tensor;

        * for 'global', the mask will be computed across all entries.

        Args:
            t (torch.Tensor): tensor representing the parameter to prune
                (of same dimensions as ``default_mask``).
            default_mask (torch.Tensor): mask from previous pruning iteration.

        Returns:
            mask (torch.Tensor): new mask that combines the effects
            of the ``default_mask`` and the new mask from the current
            pruning ``method`` (of same dimensions as ``default_mask`` and
            ``t``).
        c                    s  |}|j |jd}| jdkr|dk}n_| jdkrXt| ds!td| }| j  dk r0|    dk r;td| |j fd	d
t|D ddk}t	dg| }|| < n| jdkrjt
|j}t	dg| }ntd| j | j|| || d}|j |jd||< |S )a  Combine the masks from all pruning methods and returns a new mask.

            Args:
                method (a BasePruningMethod subclass): pruning method
                    currently being applied.
                t (torch.Tensor): tensor representing the parameter to prune
                    (of same dimensions as mask).
                mask (torch.Tensor): mask from previous pruning iteration

            Returns:
                new_mask (torch.Tensor): new mask that combines the effects
                    of the old mask and the new mask from the current
                    pruning method (of same dimensions as mask and t).
            r   unstructuredr   
structureddimzVPruning methods of PRUNING_TYPE "structured" need to have the attribute `dim` defined.r   z2Index is out of bounds for tensor with dimensions c                    s   g | ]}| kr|qS r   r   ).0drc   r   r   
<listcomp>  s    zIPruningContainer.compute_mask.<locals>._combine_masks.<locals>.<listcomp>rf   NglobalzUnrecognized PRUNING_TYPE r3   )r   r   PRUNING_TYPErB   AttributeErrorrc   
IndexErrorsumrangeslicerP   r4   rV   r   )r.   r   r   new_maskslcn_dimskeep_channelpartial_maskr   rf   r   _combine_masksS  s6   



"


z5PruningContainer.compute_mask.<locals>._combine_masksr^   )r	   r   r   rt   r.   r   r   r   r   r   7  s   
?zPruningContainer.compute_maskN)
rH   rI   rJ   rK   rQ   r$   rZ   r]   r`   r   r   r   r   r   r#     s    	r#   c                       s0   e Zd ZdZdZdd Ze fddZ  ZS )IdentityzsUtility pruning method that does not prune any units but generates the pruning parametrization with a mask of ones.ra   c                 C   s   |}|S rX   r   r	   r   r   r   r   r   r   r     s   zIdentity.compute_maskc                    s   t  ||S )  Add pruning on the fly and reparametrization of a tensor.

        Adds the forward pre-hook that enables pruning on the fly and
        the reparametrization of a tensor in terms of the original tensor
        and the pruning mask.

        Args:
            module (nn.Module): module containing the tensor to prune
            name (str): parameter name within ``module`` on which pruning
                will act.
        superr@   )r%   r
   r&   	__class__r   r   r@     s   zIdentity.apply)	rH   rI   rJ   rK   ri   r   rN   r@   __classcell__r   r   r{   r   rv     s    rv   c                       s8   e Zd ZdZdZdd Zdd Ze fddZ  Z	S )	RandomUnstructureda  Prune (currently unpruned) units in a tensor at random.

    Args:
        name (str): parameter name within ``module`` on which pruning
            will act.
        amount (int or float): quantity of parameters to prune.
            If ``float``, should be between 0.0 and 1.0 and represent the
            fraction of parameters to prune. If ``int``, it represents the
            absolute number of parameters to prune.
    ra   c                 C      t | || _d S rX   _validate_pruning_amount_initamountr	   r   r   r   r   rQ        
zRandomUnstructured.__init__c                 C   sf   |  }t| j|}t|| |jtjd}|dkr1t|}tj|	d|d}d|	d|j
< |S )Nr1   r   ru   r,   )nelement_compute_nparams_topruner   _validate_pruning_amountr:   r7   r;   	rand_liketopkviewindices)r	   r   r   tensor_sizenparams_topruner   probr   r   r   r   r     s   

zRandomUnstructured.compute_maskc                       t  j|||dS )a  Add pruning on the fly and reparametrization of a tensor.

        Adds the forward pre-hook that enables pruning on the fly and
        the reparametrization of a tensor in terms of the original tensor
        and the pruning mask.

        Args:
            module (nn.Module): module containing the tensor to prune
            name (str): parameter name within ``module`` on which pruning
                will act.
            amount (int or float): quantity of parameters to prune.
                If ``float``, should be between 0.0 and 1.0 and represent the
                fraction of parameters to prune. If ``int``, it represents the
                absolute number of parameters to prune.
        r   ry   )r%   r
   r&   r   r{   r   r   r@     s   zRandomUnstructured.apply
rH   rI   rJ   rK   ri   rQ   r   rN   r@   r}   r   r   r{   r   r~     s    r~   c                       s:   e Zd ZdZdZdd Zdd Zed
 fdd		Z  Z	S )L1Unstructuredav  Prune (currently unpruned) units in a tensor by zeroing out the ones with the lowest L1-norm.

    Args:
        amount (int or float): quantity of parameters to prune.
            If ``float``, should be between 0.0 and 1.0 and represent the
            fraction of parameters to prune. If ``int``, it represents the
            absolute number of parameters to prune.
    ra   c                 C   r   rX   r   r   r   r   r   rQ     r   zL1Unstructured.__init__c                 C   sd   |  }t| j|}t|| |jtjd}|dkr0tjt|	d|dd}d|	d|j
< |S )Nr1   r   ru   Fr,   largest)r   r   r   r   r:   r7   r;   r   absr   r   )r	   r   r   r   r   r   r   r   r   r   r     s   
zL1Unstructured.compute_maskNc                       t  j||||dS )aJ  Add pruning on the fly and reparametrization of a tensor.

        Adds the forward pre-hook that enables pruning on the fly and
        the reparametrization of a tensor in terms of the original tensor
        and the pruning mask.

        Args:
            module (nn.Module): module containing the tensor to prune
            name (str): parameter name within ``module`` on which pruning
                will act.
            amount (int or float): quantity of parameters to prune.
                If ``float``, should be between 0.0 and 1.0 and represent the
                fraction of parameters to prune. If ``int``, it represents the
                absolute number of parameters to prune.
            importance_scores (torch.Tensor): tensor of importance scores (of same
                shape as module parameter) used to compute mask for pruning.
                The values in this tensor indicate the importance of the corresponding
                elements in the parameter being pruned.
                If unspecified or None, the module parameter will be used in its place.
        r   r   ry   )r%   r
   r&   r   r   r{   r   r   r@     s   zL1Unstructured.applyrX   r   r   r   r{   r   r     s    	r   c                       s<   e Zd ZdZdZd
ddZdd Zed
 fdd		Z  Z	S )RandomStructureda  Prune entire (currently unpruned) channels in a tensor at random.

    Args:
        amount (int or float): quantity of parameters to prune.
            If ``float``, should be between 0.0 and 1.0 and represent the
            fraction of parameters to prune. If ``int``, it represents the
            absolute number of parameters to prune.
        dim (int, optional): index of the dim along which we define
            channels to prune. Default: -1.
    rb   ru   c                 C   s   t | || _|| _d S rX   )r   r   rc   )r	   r   rc   r   r   r   rQ   ;  s   
zRandomStructured.__init__c                 C   st   t | t|| j |j| j }t| j|}t|| dd }|dkr'|}|S ||| j||}||j|jd9 }|S )a  Compute and returns a mask for the input tensor ``t``.

        Starting from a base ``default_mask`` (which should be a mask of ones
        if the tensor has not been pruned yet), generate a random mask to
        apply on top of the ``default_mask`` by randomly zeroing out channels
        along the specified dim of the tensor.

        Args:
            t (torch.Tensor): tensor representing the parameter to prune
            default_mask (torch.Tensor): Base mask from previous pruning
                iterations, that need to be respected after the new mask is
                applied. Same dims as ``t``.

        Returns:
            mask (torch.Tensor): mask to apply to ``t``, of same dims as ``t``

        Raises:
            IndexError: if ``self.dim >= len(t.shape)``
        c           	      S   sT   t |}t j||dj}||k}t | }td gt| j }|||< d||< |S )Nr   r   )r7   randkthvaluevalues
zeros_likern   rP   r4   )	r   rc   	nchannelsnchannels_topruner   	thresholdchannel_maskr   rp   r   r   r   	make_maski  s   

z0RandomStructured.compute_mask.<locals>.make_maskr   r   )	_validate_structured_pruning_validate_pruning_dimrc   r4   r   r   r   r   r   )r	   r   r   r   r   r   r   r   r   r   r   A  s   
zRandomStructured.compute_maskc                    r   )a;  Add pruning on the fly and reparametrization of a tensor.

        Adds the forward pre-hook that enables pruning on the fly and
        the reparametrization of a tensor in terms of the original tensor
        and the pruning mask.

        Args:
            module (nn.Module): module containing the tensor to prune
            name (str): parameter name within ``module`` on which pruning
                will act.
            amount (int or float): quantity of parameters to prune.
                If ``float``, should be between 0.0 and 1.0 and represent the
                fraction of parameters to prune. If ``int``, it represents the
                absolute number of parameters to prune.
            dim (int, optional): index of the dim along which we define
                channels to prune. Default: -1.
        )r   rc   ry   )r%   r
   r&   r   rc   r{   r   r   r@     s   zRandomStructured.applyru   r   r   r   r{   r   r   -  s    
?r   c                       s<   e Zd ZdZdZdddZdd Zed fd	d
	Z  Z	S )LnStructuredae  Prune entire (currently unpruned) channels in a tensor based on their L\ ``n``-norm.

    Args:
        amount (int or float): quantity of channels to prune.
            If ``float``, should be between 0.0 and 1.0 and represent the
            fraction of parameters to prune. If ``int``, it represents the
            absolute number of parameters to prune.
        n (int, float, inf, -inf, 'fro', 'nuc'): See documentation of valid
            entries for argument ``p`` in :func:`torch.norm`.
        dim (int, optional): index of the dim along which we define
            channels to prune. Default: -1.
    rb   ru   c                 C   s   t | || _|| _|| _d S rX   )r   r   nrc   )r	   r   r   rc   r   r   r   rQ     s   
zLnStructured.__init__c           
      C   s   t | t|| j |j| j }t| j|}|| }t|| t|| j| j}t	j
||dd}dd }|dkr;|}	|	S ||| j|j}	|	|j|	jd9 }	|	S )a  Compute and returns a mask for the input tensor ``t``.

        Starting from a base ``default_mask`` (which should be a mask of ones
        if the tensor has not been pruned yet), generate a mask to apply on
        top of the ``default_mask`` by zeroing out the channels along the
        specified dim with the lowest L\ ``n``-norm.

        Args:
            t (torch.Tensor): tensor representing the parameter to prune
            default_mask (torch.Tensor): Base mask from previous pruning
                iterations, that need to be respected after the new mask is
                applied.  Same dims as ``t``.

        Returns:
            mask (torch.Tensor): mask to apply to ``t``, of same dims as ``t``

        Raises:
            IndexError: if ``self.dim >= len(t.shape)``
        Tr   c                 S   s2   t | }td gt| j }|||< d||< |S )Nr   )r7   r   rn   rP   r4   )r   rc   r   r   rp   r   r   r   r     s
   
z,LnStructured.compute_mask.<locals>.make_maskr   r   )r   r   rc   r4   r   r   r   _compute_normr   r7   r   r   r   r   )
r	   r   r   r   r   nparams_tokeepnormr   r   r   r   r   r   r     s   
zLnStructured.compute_maskNc                    s   t  j||||||dS )a=  Add pruning on the fly and reparametrization of a tensor.

        Adds the forward pre-hook that enables pruning on the fly and
        the reparametrization of a tensor in terms of the original tensor
        and the pruning mask.

        Args:
            module (nn.Module): module containing the tensor to prune
            name (str): parameter name within ``module`` on which pruning
                will act.
            amount (int or float): quantity of parameters to prune.
                If ``float``, should be between 0.0 and 1.0 and represent the
                fraction of parameters to prune. If ``int``, it represents the
                absolute number of parameters to prune.
            n (int, float, inf, -inf, 'fro', 'nuc'): See documentation of valid
                entries for argument ``p`` in :func:`torch.norm`.
            dim (int): index of the dim along which we define channels to
                prune.
            importance_scores (torch.Tensor): tensor of importance scores (of same
                shape as module parameter) used to compute mask for pruning.
                The values in this tensor indicate the importance of the corresponding
                elements in the parameter being pruned.
                If unspecified or None, the module parameter will be used in its place.
        )r   r   rc   r   ry   )r%   r
   r&   r   r   rc   r   r{   r   r   r@     s   zLnStructured.applyr   rX   r   r   r   r{   r   r     s    
Fr   c                       s4   e Zd ZdZdd Zdd Ze fddZ  ZS )CustomFromMaskrh   c                 C   s
   || _ d S rX   r   )r	   r   r   r   r   rQ     r[   zCustomFromMask.__init__c                 C   s*   |j | jj ks	J || jj|jd }|S )Nr   )r4   r   r   r   rw   r   r   r   r     s   zCustomFromMask.compute_maskc                    r   )rx   r   ry   )r%   r
   r&   r   r{   r   r   r@   "  s   zCustomFromMask.apply)	rH   rI   rJ   ri   rQ   r   rN   r@   r}   r   r   r{   r   r     s    r   c                 C   s   t | | | S )aB  Apply pruning reparametrization without pruning any units.

    Applies pruning reparametrization to the tensor corresponding to the
    parameter called ``name`` in ``module`` without actually pruning any
    units. Modifies module in place (and also return the modified module)
    by:

    1) adding a named buffer called ``name+'_mask'`` corresponding to the
       binary mask applied to the parameter ``name`` by the pruning method.
    2) replacing the parameter ``name`` by its pruned version, while the
       original (unpruned) parameter is stored in a new parameter named
       ``name+'_orig'``.

    Note:
        The mask is a tensor of ones.

    Args:
        module (nn.Module): module containing the tensor to prune.
        name (str): parameter name within ``module`` on which pruning
                will act.

    Returns:
        module (nn.Module): modified (i.e. pruned) version of the input module

    Examples:
        >>> # xdoctest: +SKIP
        >>> m = prune.identity(nn.Linear(2, 3), 'bias')
        >>> print(m.bias_mask)
        tensor([1., 1., 1.])
    )rv   r@   )r
   r&   r   r   r   identity2  s   r   c                 C      t | || | S )a?  Prune tensor by removing random (currently unpruned) units.

    Prunes tensor corresponding to parameter called ``name`` in ``module``
    by removing the specified ``amount`` of (currently unpruned) units
    selected at random.
    Modifies module in place (and also return the modified module) by:

    1) adding a named buffer called ``name+'_mask'`` corresponding to the
       binary mask applied to the parameter ``name`` by the pruning method.
    2) replacing the parameter ``name`` by its pruned version, while the
       original (unpruned) parameter is stored in a new parameter named
       ``name+'_orig'``.

    Args:
        module (nn.Module): module containing the tensor to prune
        name (str): parameter name within ``module`` on which pruning
                will act.
        amount (int or float): quantity of parameters to prune.
            If ``float``, should be between 0.0 and 1.0 and represent the
            fraction of parameters to prune. If ``int``, it represents the
            absolute number of parameters to prune.

    Returns:
        module (nn.Module): modified (i.e. pruned) version of the input module

    Examples:
        >>> # xdoctest: +SKIP
        >>> m = prune.random_unstructured(nn.Linear(2, 3), 'weight', amount=1)
        >>> torch.sum(m.weight_mask == 0)
        tensor(1)

    )r~   r@   )r
   r&   r   r   r   r   random_unstructuredU  s   !r   c                 C   s   t j| |||d | S )a  Prune tensor by removing units with the lowest L1-norm.

    Prunes tensor corresponding to parameter called ``name`` in ``module``
    by removing the specified `amount` of (currently unpruned) units with the
    lowest L1-norm.
    Modifies module in place (and also return the modified module)
    by:

    1) adding a named buffer called ``name+'_mask'`` corresponding to the
       binary mask applied to the parameter ``name`` by the pruning method.
    2) replacing the parameter ``name`` by its pruned version, while the
       original (unpruned) parameter is stored in a new parameter named
       ``name+'_orig'``.

    Args:
        module (nn.Module): module containing the tensor to prune
        name (str): parameter name within ``module`` on which pruning
                will act.
        amount (int or float): quantity of parameters to prune.
            If ``float``, should be between 0.0 and 1.0 and represent the
            fraction of parameters to prune. If ``int``, it represents the
            absolute number of parameters to prune.
        importance_scores (torch.Tensor): tensor of importance scores (of same
            shape as module parameter) used to compute mask for pruning.
            The values in this tensor indicate the importance of the corresponding
            elements in the parameter being pruned.
            If unspecified or None, the module parameter will be used in its place.

    Returns:
        module (nn.Module): modified (i.e. pruned) version of the input module

    Examples:
        >>> # xdoctest: +SKIP
        >>> m = prune.l1_unstructured(nn.Linear(2, 3), 'weight', amount=0.2)
        >>> m.state_dict().keys()
        odict_keys(['bias', 'weight_orig', 'weight_mask'])
    r   )r   r@   )r
   r&   r   r   r   r   r   l1_unstructuredz  s   &r   c                 C   s   t | ||| | S )a  Prune tensor by removing random channels along the specified dimension.

    Prunes tensor corresponding to parameter called ``name`` in ``module``
    by removing the specified ``amount`` of (currently unpruned) channels
    along the specified ``dim`` selected at random.
    Modifies module in place (and also return the modified module)
    by:

    1) adding a named buffer called ``name+'_mask'`` corresponding to the
       binary mask applied to the parameter ``name`` by the pruning method.
    2) replacing the parameter ``name`` by its pruned version, while the
       original (unpruned) parameter is stored in a new parameter named
       ``name+'_orig'``.

    Args:
        module (nn.Module): module containing the tensor to prune
        name (str): parameter name within ``module`` on which pruning
                will act.
        amount (int or float): quantity of parameters to prune.
            If ``float``, should be between 0.0 and 1.0 and represent the
            fraction of parameters to prune. If ``int``, it represents the
            absolute number of parameters to prune.
        dim (int): index of the dim along which we define channels to prune.

    Returns:
        module (nn.Module): modified (i.e. pruned) version of the input module

    Examples:
        >>> # xdoctest: +SKIP
        >>> m = prune.random_structured(
        ...     nn.Linear(5, 3), 'weight', amount=3, dim=1
        ... )
        >>> columns_pruned = int(sum(torch.sum(m.weight, dim=0) == 0))
        >>> print(columns_pruned)
        3
    )r   r@   )r
   r&   r   rc   r   r   r   random_structured  s   %r   c                 C   s   t j| |||||d | S )a  Prune tensor by removing channels with the lowest L\ ``n``-norm along the specified dimension.

    Prunes tensor corresponding to parameter called ``name`` in ``module``
    by removing the specified ``amount`` of (currently unpruned) channels
    along the specified ``dim`` with the lowest L\ ``n``-norm.
    Modifies module in place (and also return the modified module)
    by:

    1) adding a named buffer called ``name+'_mask'`` corresponding to the
       binary mask applied to the parameter ``name`` by the pruning method.
    2) replacing the parameter ``name`` by its pruned version, while the
       original (unpruned) parameter is stored in a new parameter named
       ``name+'_orig'``.

    Args:
        module (nn.Module): module containing the tensor to prune
        name (str): parameter name within ``module`` on which pruning
                will act.
        amount (int or float): quantity of parameters to prune.
            If ``float``, should be between 0.0 and 1.0 and represent the
            fraction of parameters to prune. If ``int``, it represents the
            absolute number of parameters to prune.
        n (int, float, inf, -inf, 'fro', 'nuc'): See documentation of valid
            entries for argument ``p`` in :func:`torch.norm`.
        dim (int): index of the dim along which we define channels to prune.
        importance_scores (torch.Tensor): tensor of importance scores (of same
            shape as module parameter) used to compute mask for pruning.
            The values in this tensor indicate the importance of the corresponding
            elements in the parameter being pruned.
            If unspecified or None, the module parameter will be used in its place.

    Returns:
        module (nn.Module): modified (i.e. pruned) version of the input module

    Examples:
        >>> from torch.nn.utils import prune
        >>> m = prune.ln_structured(
        ...     nn.Conv2d(5, 3, 2), 'weight', amount=0.3, dim=1, n=float('-inf')
        ... )
    r   )r   r@   )r
   r&   r   r   rc   r   r   r   r   ln_structured  s   )r   c                    s  t | ts	td dur ni  t  tstdtjj fdd| D }tjjdd | D }t }d|_	|di |}d|_	|j
dkrTtd	| d
|j
 || |||}d}	| D ]#\}
}t|
|}| }||	|	|  |}t|
||d |	|7 }	qcdS )a
  
    Globally prunes tensors corresponding to all parameters in ``parameters`` by applying the specified ``pruning_method``.

    Modifies modules in place by:

    1) adding a named buffer called ``name+'_mask'`` corresponding to the
       binary mask applied to the parameter ``name`` by the pruning method.
    2) replacing the parameter ``name`` by its pruned version, while the
       original (unpruned) parameter is stored in a new parameter named
       ``name+'_orig'``.

    Args:
        parameters (Iterable of (module, name) tuples): parameters of
            the model to prune in a global fashion, i.e. by aggregating all
            weights prior to deciding which ones to prune. module must be of
            type :class:`nn.Module`, and name must be a string.
        pruning_method (function): a valid pruning function from this module,
            or a custom one implemented by the user that satisfies the
            implementation guidelines and has ``PRUNING_TYPE='unstructured'``.
        importance_scores (dict): a dictionary mapping (module, name) tuples to
            the corresponding parameter's importance scores tensor. The tensor
            should be the same shape as the parameter, and is used for computing
            mask for pruning.
            If unspecified or None, the parameter will be used in place of its
            importance scores.
        kwargs: other keyword arguments such as:
            amount (int or float): quantity of parameters to prune across the
            specified parameters.
            If ``float``, should be between 0.0 and 1.0 and represent the
            fraction of parameters to prune. If ``int``, it represents the
            absolute number of parameters to prune.

    Raises:
        TypeError: if ``PRUNING_TYPE != 'unstructured'``

    Note:
        Since global structured pruning doesn't make much sense unless the
        norm is normalized by the size of the parameter, we now limit the
        scope of global pruning to unstructured methods.

    Examples:
        >>> from torch.nn.utils import prune
        >>> from collections import OrderedDict
        >>> net = nn.Sequential(OrderedDict([
        ...     ('first', nn.Linear(10, 4)),
        ...     ('second', nn.Linear(4, 1)),
        ... ]))
        >>> parameters_to_prune = (
        ...     (net.first, 'weight'),
        ...     (net.second, 'weight'),
        ... )
        >>> prune.global_unstructured(
        ...     parameters_to_prune,
        ...     pruning_method=prune.L1Unstructured,
        ...     amount=10,
        ... )
        >>> print(sum(torch.nn.utils.parameters_to_vector(net.buffers()) == 0))
        tensor(10)

    z4global_unstructured(): parameters is not an IterableNz=global_unstructured(): importance_scores must be of type dictc                    s&   g | ]\}}  ||ft||qS r   )getr   rd   r
   r&   r   r   r   rg   E  s    z'global_unstructured.<locals>.<listcomp>c              
   S   s,   g | ]\}}t ||d  tt ||qS )r   )r   r7   r8   r   r   r   r   rg   M  s    tempra   zROnly "unstructured" PRUNING_TYPE supported for the `pruning_method`. Found method z	 of type r   r   r   )r!   r   rT   dictr7   nnutilsparameters_to_vectorr#   r   ri   r$   r   r   numelview_ascustom_from_mask)
parameterspruning_methodr   r(   relevant_importance_scoresr   r/   r.   
final_maskpointerr
   r&   param	num_param
param_maskr   r   r   global_unstructured  sJ   
>

	



r   c                 C   r   )aE  Prune tensor corresponding to parameter called ``name`` in ``module`` by applying the pre-computed mask in ``mask``.

    Modifies module in place (and also return the modified module) by:

    1) adding a named buffer called ``name+'_mask'`` corresponding to the
       binary mask applied to the parameter ``name`` by the pruning method.
    2) replacing the parameter ``name`` by its pruned version, while the
       original (unpruned) parameter is stored in a new parameter named
       ``name+'_orig'``.

    Args:
        module (nn.Module): module containing the tensor to prune
        name (str): parameter name within ``module`` on which pruning
            will act.
        mask (Tensor): binary mask to be applied to the parameter.

    Returns:
        module (nn.Module): modified (i.e. pruned) version of the input module

    Examples:
        >>> from torch.nn.utils import prune
        >>> m = prune.custom_from_mask(
        ...     nn.Linear(5, 3), name='bias', mask=torch.tensor([0, 1, 0])
        ... )
        >>> print(m.bias_mask)
        tensor([0., 1., 0.])

    )r   r@   )r
   r&   r   r   r   r   r   u  s   r   c                 C   sX   | j  D ]\}}t|tr |j|kr ||  | j |= |   S qtd| d|  d)a  Remove the pruning reparameterization from a module and the pruning method from the forward hook.

    The pruned parameter named ``name`` remains permanently pruned, and the parameter
    named ``name+'_orig'`` is removed from the parameter list. Similarly,
    the buffer named ``name+'_mask'`` is removed from the buffers.

    Note:
        Pruning itself is NOT undone or reversed!

    Args:
        module (nn.Module): module containing the tensor to prune
        name (str): parameter name within ``module`` on which pruning
            will act.

    Examples:
        >>> m = random_unstructured(nn.Linear(5, 7), name='weight', amount=0.2)
        >>> m = remove(m, name='weight')
    zParameter 'z' of module z/ has to be pruned before pruning can be removed)r   r    r!   r   r   rG   rV   )r
   r&   r,   r-   r   r   r   rG     s   
rG   c                 C   s8   |   D ]\}}|j D ]}t|tr  dS qqdS )at  Check if a module is pruned by looking for pruning pre-hooks.

    Check whether ``module`` is pruned by looking for
    ``forward_pre_hooks`` in its modules that inherit from the
    :class:`BasePruningMethod`.

    Args:
        module (nn.Module): object that is either pruned or unpruned

    Returns:
        binary answer to whether ``module`` is pruned.

    Examples:
        >>> from torch.nn.utils import prune
        >>> m = nn.Linear(5, 7)
        >>> print(prune.is_pruned(m))
        False
        >>> prune.random_unstructured(m, name='weight', amount=0.2)
        >>> print(prune.is_pruned(m))
        True
    TF)named_modulesr   r   r!   r   )r
   _	submoduler-   r   r   r   	is_pruned  s   
r   c                 C   sl   t | tjstd|  dt | tjr| dk s*t | tjs2t| dks*t| dk r4td|  ddS dS )	a  Validate helper to check the range of amount at init.

    Args:
        amount (int or float): quantity of parameters to prune.
            If float, should be between 0.0 and 1.0 and represent the
            fraction of parameters to prune. If int, it represents the
            absolute number of parameters to prune.

    Raises:
        ValueError: if amount is a float not in [0, 1], or if it's a negative
            integer.
        TypeError: if amount is neither a float nor an integer.

    Note:
        This does not take into account the number of parameters in the
        tensor to be pruned, which is known only at prune.
    zInvalid type for amount: z. Must be int or float.r   g      ?g        amount=zG should either be a float in the range [0, 1] or a non-negative integerN)r!   numbersRealrT   IntegralfloatrV   r   r   r   r   r     s   

r   c                 C   s0   t | tjr| |krtd|  d| dS dS )a?  Validate that the pruning amount is meaningful wrt to the size of the data.

    Validation helper to check that the amount of parameters to prune
    is meaningful wrt to the size of the data (`tensor_size`).

    Args:
        amount (int or float): quantity of parameters to prune.
            If float, should be between 0.0 and 1.0 and represent the
            fraction of parameters to prune. If int, it represents the
            absolute number of parameters to prune.
        tensor_size (int): absolute number of parameters in the tensor
            to prune.
    r   z: should be smaller than the number of parameters to prune=N)r!   r   r   rV   r   r   r   r   r   r     s
   r   c                 C   s0   | j }t|dkrtd| dt| ddS )ai  Validate that the tensor to be pruned is at least 2-Dimensional.

    Validation helper to check that the tensor to be pruned is multi-
    dimensional, such that the concept of "channels" is well-defined.

    Args:
        t (torch.Tensor): tensor representing the parameter to prune

    Raises:
        ValueError: if the tensor `t` is not at least 2D.
    r   zZStructured pruning can only be applied to multidimensional tensors. Found tensor of shape z with z dimsN)r4   rP   rV   )r   r4   r   r   r   r     s   r   c                 C   s   t | tjr| S t| | S )a  Convert the pruning amount from a percentage to absolute value.

    Since amount can be expressed either in absolute value or as a
    percentage of the number of units/channels in a tensor, this utility
    function converts the percentage to absolute value to standardize
    the handling of pruning.

    Args:
        amount (int or float): quantity of parameters to prune.
            If float, should be between 0.0 and 1.0 and represent the
            fraction of parameters to prune. If int, it represents the
            absolute number of parameters to prune.
        tensor_size (int): absolute number of parameters in the tensor
            to prune.

    Returns:
        int: the number of units to prune in the tensor
    )r!   r   r   roundr   r   r   r   r     s   r   c                 C   s&   ||   krtd| d| j dS )zValidate that the pruning dimension is within the bounds of the tensor dimension.

    Args:
        t (torch.Tensor): tensor representing the parameter to prune
        dim (int): index of the dim along which we define channels to prune
    zInvalid index z for tensor of size N)rc   rk   r4   )r   rc   r   r   r   r   6  s   r   c                 C   s>   t t|  }|dk r|| }|| tj| ||d}|S )aZ  Compute the L_n-norm of a tensor along all dimensions except for the specified dimension.

    The L_n-norm will be computed across all entries in tensor `t` along all dimension
    except for the one identified by dim.
    Example: if `t` is of shape, say, 3x2x4 and dim=2 (the last dim),
    then norm will have Size [4], and each entry will represent the
    `L_n`-norm computed using the 3x2=6 entries for each of the 4 channels.

    Args:
        t (torch.Tensor): tensor representing the parameter to prune
        n (int, float, inf, -inf, 'fro', 'nuc'): See documentation of valid
            entries for argument p in torch.norm
        dim (int): dim identifying the channels to prune

    Returns:
        norm (torch.Tensor): L_n norm computed across all dimensions except
            for `dim`. By construction, `norm.shape = t.shape[-1]`.
    r   )prc   )listrm   rc   rG   r7   r   )r   r   rc   dimsr   r   r   r   r   A  s   
r   rX   )rK   r   abcr   r   collections.abcr   r7   r   r#   rv   r~   r   r   r   r   r   r   r   r   r   r   r   rG   r   r   r   r   r   r   r   r   r   r   r   <module>   s>    | ;Bi #
%,
)
/w!