
    sh~5                         S SK r S SKrS SKJr  S SKJrJr  S SKrS SKJr  S SK	J
r
  S SKJr  SSKJrJrJrJrJr  S	/r\R(                  1r/ S
Qr " S S	\ R.                  5      rg)    N)defaultdict)AnyOptional)nn)parametrize)type_before_parametrizations   )FakeSparsityget_arg_info_from_tensor_fqnmodule_contains_parammodule_to_fqnswap_moduleBaseSparsifier)module
module_fqntensor_namec            
       T  ^  \ rS rSrSrS#S\\\\4      4U 4S jjjr	S\\\4   4S jr
S\\\\\4   4   SS4S	 jrS
 rS\\\4   4S jrS$S\\\4   S\4S jjr\4S\R$                  S\\\R*                        SS4S jjrS rS r  S%S\\\S4      S\\\\\S4   4      4S jjrSS\4S\R$                  S\\\\R$                     \\R$                     4      S\S\\R$                     4S jjrS$S\SS4S jjr\R>                  S\R$                  S \4S! j5       r S"r!U =r"$ )&r      a  Base class for all sparsifiers.

Abstract methods that need to be implemented:

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

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 should be a dict map that includes
        `tensor_fqn` of tensors to sparsify
    - defaults [dict]: default configurations will be attached to the
        configuration. Only the keys that don't exist in the `config` will
        be updated.

Example::

    >>> # xdoctest: +SKIP("Can't instantiate abstract class BaseSparsifier with abstract method update_mask")
    >>> config = [{'tensor_fqn': 'layer1.weight', 'tensor_fqn': 'linear2.weight2', 'sparsity_level': 0.5}]
    >>> defaults = {'sparsity_level': 0.7}
    >>> # model.layer1.weight will have `sparsity_level` = 0.7 (getting default)
    >>> sparsifier = BaseSparsifier(config, defaults)
Ndefaultsc                    > [         TU ]  5         U=(       d    0 U l        [        [        5      U l        / U l        SU l        g )NT)super__init__r   r   dictstategroupsenable_mask_update)selfr   	__class__s     /Users/tiagomarins/Projetos/claudeai/copy_bank/venv/lib/python3.13/site-packages/torch/ao/pruning/sparsifier/base_sparsifier.pyr   BaseSparsifier.__init__7   s4    (0B&1$&7
,."&    returnc                 J    U R                   U R                  U R                  S.$ )Nr   r   r   r$   )r   s    r   __getstate__BaseSparsifier.__getstate__?   s!    ZZkk
 	
r!   r   c                 :    U R                   R                  U5        g N)__dict__update)r   r   s     r   __setstate__BaseSparsifier.__setstate__F   s    U#r!   c                 "   U R                   R                  S-   n[        U R                  5       HW  u  p#US   nUS-  nUSU S3-  nUSU S3-  n[	        UR                  5       5       H  nUS:X  a  M  USU SX5    S3-  nM     MY     US-  nU$ )	Nz (r   
z	Group z	    module: z	    z: ))r   __name__	enumerater   sortedkeys)r   format_stringisparse_argsr   keys         r   __repr__BaseSparsifier.__repr__I   s    //$6'4NA *FT!Mxs"--M~fXR88Mk..01(?6#b1A0B"!EE 2 5 	r!   c           
          U R                    Vs/ s H'  n[        [        S UR                  5       5      5      PM)     nnU R                  US.$ s  snf )aS  Returns the state of the optimizer as a :class:`dict`.

It contains:
* state - current state of the sparsification.
* groups - a list containing all sparsity configuration groups
    with the key 'tensor_fqn' specifying the path to the sparsified tensor within a model

TODO: Need a clean way of loading the state of the "prepared" module
c                     U S   [         ;  $ )Nr   )KEYS_NOT_IN_STATE_DICT)	key_values    r   <lambda>+BaseSparsifier.state_dict.<locals>.<lambda>e   s    il:P&Pr!   r   r   )r   r   filteritemsr   )r   mgr   s      r   
state_dictBaseSparsifier.state_dictW   s`    $ kk(
 " PHHJ " 	 (
 ZZ
 	
(
s   .ArD   strictc           	         [         R                  " US   5      nUS   nUR                  5        GH  u  pV[        U R                  U5      nUS   nUS   n	U(       a  Uc  [        SU S35      eSn
UR                  U	    H  n[        U[        5      (       d  M  Sn
  O   U
(       dI  [        [        R                  " [        X5      R                  5      5      n[        R                  " XU5        UR                  S	S 5      b  UR!                  S	5      nUWl        U H  nUS
   U:X  d  M  UR%                  U5        M!     GM     U R'                  XCS.5        g )Nr   r   r   r   zError loading z into the modelFTmask
tensor_fqnr@   )copydeepcopyrB   r   modelRuntimeErrorparametrizations
isinstancer
   torchonesgetattrshaper   register_parametrizationgetpoprH   r*   r+   )r   rD   rF   r   statesrI   sarg_infor   r   foundprH   rC   s                 r   load_state_dictBaseSparsifier.load_state_dictq   s-   z(34G$#\\^MJ3DJJ
KHh'F"=1K&."^J<#OPPE,,[9a.. E :  GF,H,N,N!OP44V!LuuVT".uuV}l#z1IIh' ' ,, 	F=>r!   rL   SUPPORTED_MODULESc                 T   / U l         U/nU(       a  UR                  5       nUR                  5        Hi  u  pV[        U5      U;   aD  [	        X5      n[        U[        5      (       d   eU R                   R                  SUS-   05        MX  UR                  U5        Mk     U(       a  M  g g )NrI   z.weight)configrV   named_childrentyper   rO   strappend)r   rL   r^   stackr   _namechildr   s           r   make_config_from_model%BaseSparsifier.make_config_from_model   s    
 YY[F & 5 5 7;"33!.u!<J%j#6666KK&&j96L'MNLL' !8 er!   c                    Xl         X l        U R                  c  U R                  U5        U R                   GH  n[        U[        5      (       d   S5       e[        U R
                  [        5      (       d   e[        R                  " U R
                  5      nUR                  U5        UR                  SS5      nUc   S5       e[        X5      nUR                  5        H4  nXt;   d  M
  Xg   XG   :X  a  M  US:X  a  SXg   -   XG   :X  a  M+   SU S35       e   UR                  U5        U R                  R                  U5        GM     U R                  5         g)zPrepares a model, by adding the parametrizations.

Note::

    The model is modified inplace. If you need to preserve the original
    model, use copy.deepcopy.
Nznconfig elements should be dicts not modules i.e.:[{`tensor_fqn`: `foo.bar.weight`}, {`tensor_fqn`: ... }, ...]rI   zttensor_fqn is a required argument in the sparsity config whichreplaces previous `module` and [module]`fqn` arguments.zGiven both `z?` and `tensor_fqn` in the config, it is expected them to agree!)rL   r`   rh   rO   r   r   rJ   rK   r*   rU   r   r3   r   rd   _prepare)r   rL   r`   module_config
local_argsrI   info_from_tensor_fqnr7   s           r   prepareBaseSparsifier.prepare   s[    
 ;;''. "[[MmT22 P2
 dmmT2222t}}5Jm,#d;J) I) $@#R  ,002$,1Z_D</ #&:&? ?:? R	k &cU*ijk 3 23KKz*A )B 	r!   c           
      *   U R                    H  nUS   nUS   nUR                  S[        5      nUR                  S[        R                  " [        XE5      5      5      nXpR                  US      S'   [        R                  " XEU" U5      5        M     g)z-Adds mask parametrization to the layer weightr   r   parametrizationrH   rI   N)	r   rU   r
   rP   	ones_likerR   r   r   rT   )r   argskwargsr`   r   r   rs   rH   s           r   rl   BaseSparsifier._prepare   s    kkFH%F /K$jj):LIO::feoogf6R&STD7;JJvl+,V400_T%: "r!   params_to_keep.params_to_keep_per_layerc                 n   U R                    H  nUS   nUS   n[        R                  " XgSS9  0 nUb%  U V	s0 s H  oXY   _M	     n
n	UR                  U
5        Ub=  UR	                  US   S5      nUb%  U V	s0 s H  oXY   _M	     nn	UR                  U5        U(       d  M  Xl        M     gs  sn	f s  sn	f )a  Squashes the sparse masks into the appropriate tensors.

If either the `params_to_keep` or `params_to_keep_per_layer` is set,
the module will have a `sparse_params` dict attached to it.

Args:
    params_to_keep: List of keys to save in the module or a dict
                    representing the modules and keys that will have
                    sparsity parameters saved
    params_to_keep_per_layer: Dict to specify the params that should be
                    saved for specific layers. The keys in the dict
                    should be the module fqn, while the values should
                    be a list of strings with the names of the variables
                    to save in the `sparse_params`

Examples:
    >>> # xdoctest: +SKIP("locals are undefined")
    >>> # Don't save any sparse params
    >>> sparsifier.squash_mask()
    >>> hasattr(model.submodule1, 'sparse_params')
    False

    >>> # Keep sparse params per layer
    >>> sparsifier.squash_mask(
    ...     params_to_keep_per_layer={
    ...         'submodule1.linear1': ('foo', 'bar'),
    ...         'submodule2.linear42': ('baz',)
    ...     })
    >>> print(model.submodule1.linear1.sparse_params)
    {'foo': 42, 'bar': 24}
    >>> print(model.submodule2.linear42.sparse_params)
    {'baz': 0.1}

    >>> # Keep sparse params for all layers
    >>> sparsifier.squash_mask(params_to_keep=('foo', 'bar'))
    >>> print(model.submodule1.linear1.sparse_params)
    {'foo': 42, 'bar': 24}
    >>> print(model.submodule2.linear42.sparse_params)
    {'foo': 42, 'bar': 24}

    >>> # Keep some sparse params for all layers, and specific ones for
    >>> # some other layers
    >>> sparsifier.squash_mask(
    ...     params_to_keep=('foo', 'bar'),
    ...     params_to_keep_per_layer={
    ...         'submodule2.linear42': ('baz',)
    ...     })
    >>> print(model.submodule1.linear1.sparse_params)
    {'foo': 42, 'bar': 24}
    >>> print(model.submodule2.linear42.sparse_params)
    {'foo': 42, 'bar': 24, 'baz': 0.1}
r   r   T)leave_parametrizedNr   )r   r   remove_parametrizationsr*   rU   sparse_params)r   rx   ry   ru   rv   r`   r   r   r}   kglobal_paramsparamsper_layer_paramss                r   squash_maskBaseSparsifier.squash_mask   s    v kkFH%F /K// M)7E F~!FI~ F$$]3'3155f\6JDQ%>D'Ef69f$'E!(()9:}'4$# " !G
 (Fs   B-8B2Fr   mappinginplaceparameterizationc                 d   Uc  [        S5      eU(       d  [        R                  " U5      n0 nUR                  5        HG  u  pg[	        Xt5      (       a  [        U5      U;   a  [        Xr5      XV'   M3  U R                  UUSUS9XV'   MI     UR                  5        H  u  pXR                  U'   M     U$ )a  Converts submodules in input module to a different module according to `mapping`
by calling `from_dense` 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
zNeed to auto generate mapping T)r   r   r   )
NotImplementedErrorrJ   rK   ra   r   r   r   convertrB   _modules)
r   r   r   r   r   reassignnamemodr7   values
             r   r   BaseSparsifier.convert*  s    " ?%&FGG]]6*F..0ID &c<<05@!,S!: "&# %5	 ". " 1  #..*JC#(OOC  + r!   use_pathc                     U R                   (       d  g [        R                  " 5          U R                   H  nU R                  " S0 UD6  M     S S S 5        g ! , (       d  f       g = f)N )r   rP   no_gradr   update_mask)r   r   r`   s      r   stepBaseSparsifier.stepV  s@    &&]]_++  *6* & __s   &A
A%r   c                     g r(   r   )r   r   r   rv   s       r   r   BaseSparsifier.update_mask]  s    r!   )r`   r   r   r   rL   r   r(   )T)NN)#r0   
__module____qualname____firstlineno____doc__r   r   rc   r   r   r%   r+   r8   rD   boolr\   r^   r   Modulesetrb   Linearrh   rp   rl   tupler   r
   r   r   abcabstractmethodr   __static_attributes____classcell__)r   s   @r   r   r      s   2'$sCx.!9 ' '
d38n 
$$sDcN':"; $ $
DcN 
4?$sCx. ?$ ?< 3D(yy( tBII/( 
	("1f
 59IML5 sCx1L5 #+4U38_0D+E"FL5b EI,8*		* $tBIIRYY?@A* 	*
 ryy/*X+T +T + 	")) #  r!   )r   rJ   collectionsr   typingr   r   rP   r   torch.nn.utilsr   torch.nn.utils.parametrizer   utilsr
   r   r   r   r   __all__r   r^   r<   ABCr   r   r!   r   <module>r      sU    
  #     & C  
YYK @ BSWW Br!   