
    ȅi6                         S SK r S SKrS SKJr  S SK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)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   S-  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\\\\S4   4   S-  4S jjrSS\4S\R"                  S\\\R"                     \\R"                     4   S-  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     e/home/james-whalen/.local/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rC   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deepcopyrA   r
   modelRuntimeErrorparametrizations
isinstancer	   torchonesgetattrshaper   register_parametrizationgetpoprG   r)   r*   )r   rC   rE   r   statesrH   sarg_infor   r   foundprG   rB   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    rK   SUPPORTED_MODULESc                 f   / U l         U/nU(       a  UR                  5       nUR                  5        Hr  u  pV[        U5      U;   aM  [	        X5      n[        U[        5      (       d  [        S5      eU R                   R                  SUS-   05        Ma  UR                  U5        Mt     U(       a  M  g g )Nzmodule_fqn must be a stringrH   z.weight)	configrU   named_childrentyper   rN   strAssertionErrorappend)r   rK   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,-JKK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  [        S5      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 H8  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`: ... }, ...]zdefaults must be a dictrH   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!)rK   r_   rh   rN   r   rc   r   rI   rJ   r)   rT   r
   r   rd   _prepare)r   rK   r_   module_config
local_argsrH   info_from_tensor_fqnr6   s           r   prepareBaseSparsifier.prepare   sT    
 ;;''. "[[MmT22$T 
 dmmT22$%>??t}}5Jm,#d;J!$M  $@#R  ,$,1Z_D</ #&:&? ?:? R -*3%/no  , 23KKz*M )N 	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   parametrizationrG   rH   N)	r   rT   r	   rO   	ones_likerQ   r   r   rS   )r   argskwargsr_   r   r   rs   rG   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)   rT   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   )
NotImplementedErrorrI   rJ   r`   r   r   r   convertrA   _modules)
r   r   r   r   r   reassignnamemodr6   values
             r   r   BaseSparsifier.convert2  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   rO   no_gradr   update_mask)r   r   r_   s      r   stepBaseSparsifier.step^  s@    &&]]_++  *6* & __s   &A
A%r   c                     g r'   r   )r   r   r   rv   s       r   r   BaseSparsifier.update_maske  s    r    )r_   r   r   r   rK   r   r'   )T)NN)"r/   
__module____qualname____firstlineno____doc__r   rb   r   r   r$   r*   r7   rC   boolr[   r]   r   Modulesetra   Linearrh   rp   rl   tupler   r	   r   r   abcabstractmethodr   __static_attributes____classcell__)r   s   @r   r   r      s   2'c3h$!6 ' '
d38n 
$$sDcN':"; $ $
DcN 
4?$sCx. ?$ ?< 3D(yy( tBII/( 
	($8t
 26FJL5c3h$.L5 #'sE#s(O';"<t"CL5b BF,8*		* d299otBII67$>* 	*
 ryy/*X+T +T + 	")) #  r    )r   rI   collectionsr   typingr   rO   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 @ JSWW Jr    