
    Pi%C                     |   U 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	m
Z
mZ d dlmZ d dlZd dlmZ d dlmZmZ d dlmZ dZeed	<   ej        d
ddej        de	eef         dedej        dedefdZdededee         fdZ ej        d
ddej        de	eef         dedej        dedefdZ!ej        d
fdej        dej        defdZ"e j#        dej        de
d         fd            Z$e j#        ddddej        dedej%        dej        dee         d ee         de
d         fd!            Z&dej        fd"Z'dS )#    N)OrderedDict)partial)AnyDict	GeneratorOptional)warn)FakeTensorConverterFakeTensorMode)	NF4TensorF_use_low_cpu_ramTdtypeoffload_to_cpumodel
state_dictargsr   r   kwargsc                    |                                 D ]Q\  }}t          |t                    r7|                    |          ||<   |r||                                         ||<   RdS )a  
    A state_dict hook that replaces NF4 tensors with their restored
    higher-precision weight and optionally offloads the restored weight to CPU.
    Use this hook to avoid increased peak GPU memory usage during checkpoint
    save when training with QLoRA.

    This function is meant to be used with PyTorch's ``nn.Module._register_state_dict_hook``, i.e.

    >>> m = MyModule()
    >>> m._register_state_dict_hook(reparametrize_as_dtype_state_dict_post_hook)

    If the hook is registered per the above process, this hook will be called _after_ the module's
    ``state_dict`` method is called. The hook will replace all ``NF4Tensor`` instances by unquantizing
    them to the original dtype, and optionally offload the restored weight to CPU.

    Args:
        model (nn.Module): the model to take ``state_dict()`` on
        state_dict (Dict[str, Any]): the state dict to modify
        *args (Any): Unused args passed when running this as a state_dict hook.
        dtype (torch.dtype): the dtype to restore the weight to. Default is ``torch.bfloat16``.
        offload_to_cpu (bool): whether to offload the restored weight to CPU. Default is ``True``.
        **kwargs (Any): Unused keyword args passed when running this as a state_dict hook.
    N)items
isinstancer   tocpu)r   r   r   r   r   r   kvs           r/home/jaya/work/projects/VOICE-AGENT/VIET/agent-env/lib/python3.11/site-packages/torchtune/modules/common_utils.py+reparametrize_as_dtype_state_dict_post_hookr      st    >   "" 4 41a## 	4DDKKJqM 4 *1 1 1 3 3
1	4 4    	slice_strlengthreturnc                 ~   d| vsd| vs
J d            d| v rVd |                      d          D             }t          fd|D                       s
J d            dgz  }|D ]}d||<   |S |                      d          }t          |          d	k    s
J d
            d\  }}}t          |          dk    r)|d         dk    rt          |d                   }|dz   }d}nt          |          dk    rG|d         dk    rt          |d                   nd}|d         dk    rt          |d                   nd}n|t          |          d	k    ri|d         dk    rt          |d                   nd}|d         dk    rt          |d                   nd}|d         dk    rt          |d                   nd}|d|cxk    rk     sn J d            |d|cxk    rk     sn J d            ||dk    s
J d            dgz  }t	          ||nd||n||nd          }	|	D ]}d|cxk    rk     rn d||<   |S )af  
    Convert a string representing a Python slice or index into a boolean array.

    The resulting array will have the same length as the specified `length` parameter.
    Each element in the array corresponds to an index in the original sequence,
    with `True` indicating that the index is included in the slice and `False` otherwise.

    Args:
        slice_str (str): A string representing a Python slice or index, e.g. "1:3", ":5", "2::3", "0,4,5".
        length (int): The length of the original sequence.

    Returns:
        list[bool]: A boolean array representing the slice.

    Examples:
        >>> slice_str_to_array("1:3", 5)
        [False, True, True, False, False]
        >>> slice_str_to_array(":", 5)
        [True, True, True, True, True]
        >>> slice_str_to_array("::2", 5)
        [True, False, True, False, True]
        >>> slice_str_to_array("1::2", 5)
        [False, True, False, True, False]
        >>> slice_str_to_array("2:5:2", 6)
        [False, False, True, False, True, False]
        >>> slice_str_to_array("0,4,5", 7)
        [True, False, False, False, True, True, False]
    ,:zCannot mix commas and colonsc                 ,    g | ]}t          |          S  )int).0is     r   
<listcomp>z&slice_str_to_array.<locals>.<listcomp>_   s    888a3q66888r   c              3   8   K   | ]}d |cxk    ok     nc V  dS )r   Nr&   )r(   r)   r    s     r   	<genexpr>z%slice_str_to_array.<locals>.<genexpr>`   s7      44q1????F????444444r   zIndex out of rangeFT   zInvalid slice formatNNN   r       NzStart index out of rangezEnd index out of rangezStep cannot be zero)splitalllenr'   range)
r   r    indicesresultr)   partsstartendstepslice_indicess
    `        r   slice_str_to_arrayr=   >   s   < i3i#7#7#79W#7#77
i889??3#7#78884444G44444JJ6JJJ46! 	 	AF1IIOOC  Eu::???2???'E3
5zzQ58r>>E!Hai	Uq!&qRE!HT$Qx2~~c%(mmm4	Uq!&qRE!HT$Qx2~~c%(mmm4 %aBs58}}}D=A/////////1K///;!s++++V+++++-E+++<41999&;99$WvF"F a M   ????F?????F1IMr   c                $   t                      }t                      }t                      }|                                D ]\  }	}
t	          |
t
                    r-|                    ||
                              |          ||	<   n|                    ||
          ||	<   |r||	                                         ||	<   d}t          j
                            d          5  t          j        ||           ddd           n# 1 swxY w Y   t          j
                            t          j                  5  t          j        |dd          }ddd           n# 1 swxY w Y   |                                D ]s}	t	          ||	         t
                    r5||	                             ||	                             |                     R||	                             ||	                    t|                                D ]}	||	         ||	<   dS )ax  
    A state_dict hook that replaces NF4 tensors with their restored
    higher-precision weight and optionally offloads the restored weight to CPU.
    Use this hook to avoid increased peak GPU memory usage during checkpoint
    save when training with QLoRA.

    This hook is similar to ``reparametrize_as_dtype_state_dict_post_hook`` but uses
    FakeTensor and mmap(2) to avoid CPU OOM on colab.

    This function is meant to be used with PyTorch's ``nn.Module._register_state_dict_hook``, i.e.

    >>> m = MyModule()
    >>> m._register_state_dict_hook(reparametrize_as_dtype_state_dict_post_hook)

    If the hook is registered per the above process, this hook will be called _after_ the module's
    ``state_dict`` method is called. The hook will replace all ``NF4Tensor`` instances by unquantizing
    them to the original dtype, and optionally offload the restored weight to CPU.

    Args:
        model (nn.Module): the model to take ``state_dict()`` on
        state_dict (Dict[str, Any]): the state dict to modify
        *args (Any): Unused args passed when running this as a state_dict hook.
        dtype (torch.dtype): the dtype to restore the weight to. Default is ``torch.bfloat16``.
        offload_to_cpu (bool): whether to offload the restored weight to CPU. Default is ``True``.
        **kwargs (Any): Unused keyword args passed when running this as a state_dict hook.
    z/tmp/fake_state_dict.ptT)materialize_fake_tensorsN)mmapweights_only)r   r
   r   r   r   r   from_real_tensorr   r   torchserialization	skip_datasaveset_default_mmap_optionsr@   
MAP_SHAREDloadkeyscopy_)r   r   r   r   r   r   mode	converterfake_state_dictr   r   dest_state_dict_pathdest_state_dicts                r   4_low_ram_reparametrize_as_dtype_state_dict_post_hookrQ      s   F D#%%I!mmO  "" : :1a## 	E!*!;!;D!!D!D!G!G!N!NOA!*!;!;D!!D!DOA 	:!0!3!7!7!9!9OA 5			&	&	&	E	E : :
?$8999: : : : : : : : : : : : : : :			5	5do	F	F Y Y*%9SWXXXY Y Y Y Y Y Y Y Y Y Y Y Y Y Y
 __ 4 4jmY// 	4A$$Z]%5%5e%<%<====A$$Z]3333
 __ + +'*
1+ +s$   !DD
D7EE"Emodulec                     t           r't          j        dk    rt          d          t          }nt
          }|                     t          |||                     dS )a}  
    Register the reparametrize state dict hooks to the module and its submodules.

    This function is a wrapper that is meant to toggle between the low_cpu_ram
    and regular versions of the ``reparametrize_as_dtype`` state dict hooks.

    Args:
        module (nn.Module): the module to register the hooks to.
        dtype (torch.dtype): the dtype to restore the weight to. Default is ``torch.bfloat16``.
        offload_to_cpu (bool): whether to offload the restored weight to CPU. Default is ``True``.

    Raises:
        RuntimeError: If the low RAM reparametrize hook is used on Windows or an incompatible torch version.
    win32zPLow RAM reparametrize_as_dtype_state_dict_post_hook is not supported on Windows.r   N)r   sysplatformRuntimeErrorrQ   r   _register_state_dict_hookr   )rR   r   r   hooks       r   (_register_reparametrize_state_dict_hooksrZ      sq    &  	;<7""b   HDD:
$$E.AAA    r   r.   c              #   6  K   |                                  st          d          |                                 st          d           |                                 D ]-}t          |d          rt          |j                  rd|_        .	 dV  |                                 D ]-}t          |d          rt          |j                  rd|_        .dS # |                                 D ]-}t          |d          rt          |j                  rd|_        .w xY w)a  
    This context manager temporarily disables KV-cacheing on a given model, which must already
    already have KV-caches setup. All forward passes using the model within this context manager
    will not use KV-caches.

    KV-caches will be disabled when entering the context manager, and will be enabled upon exit,
    without being modified.

    This is useful in cases where we might wish to alternate between model calls which use KV-cacheing,
    and model calls which do not use KV-cacheing, without the additional overhead of deleting and setting caches up
    every time.

    Example:
        >>> from torchtune.models.llama3_2 import llama3_2_1b
        >>> from torchtune.modules import disable_kv_cache
        >>> import torch
        >>> model = llama3_2_1b()
        >>> # setup caches
        >>> model.setup_caches(batch_size=1,
        >>>                     dtype=torch.float32,
        >>>                     decoder_max_seq_len=1024)
        >>> print(model.caches_are_setup())
        True
        >>> print(model.caches_are_enabled())
        True
        >>> print(model.layers[0].attn.kv_cache)
        KVCache()
        >>> # now temporarily disable caches
        >>> with disable_kv_cache(model):
        >>>     print(model.caches_are_setup())
        True
        >>>     print(model.caches_are_enabled())
        False
        >>>     print(model.layers[0].attn.kv_cache)
        KVCache()
        >>> # caches are now re-enabled, and their state is untouched
        >>> print(model.caches_are_setup())
        True
        >>> print(model.caches_are_enabled())
        True
        >>> print(model.layers[0].attn.kv_cache)
        KVCache()

    Args:
        model (nn.Module): model to disable KV-cacheing for.

    Yields:
        None: Returns control to the caller with KV-caches disabled on the given model.

    Raises:
        ValueError: If the model does not have caches setup. Use :func:`~torchtune.modules.TransformerDecoder.setup_caches` to
            setup caches first.
    zrModel caches must be setup before calling disable_kv_cache! Please use model.setup_caches() to setup model caches.zYou are using disable_kv_cache with a model that does not have caches enabled. This is a no-op and the expected behaviour may not occur.kv_cacheFNT)	caches_are_setup
ValueErrorcaches_are_enabledr	   moduleshasattrcallabler\   cache_enabledr   rR   s     r   disable_kv_cachere      sM     n !!## 
E
 
 	
 ##%% 
	
 	
 	

 --// ) )6:&& 	)8FO+D+D 	)#(F ,mmoo 	, 	,Fvz** ,x/H/H ,'+$	, 	,emmoo 	, 	,Fvz** ,x/H/H ,'+$	,s   C ADencoder_max_seq_lendecoder_max_seq_len
batch_sizedevicerg   rh   c             #     K   |                                  rt          d          |5  |                     ||||           ddd           n# 1 swxY w Y   	 dV  t          |            dS # t          |            w xY w)a  
    This context manager temporarily enables KV-cacheing on a given model, which does not
    already have KV-caches setup. All forward passes using the model within this context manager
    will use KV-caches.

    KV-caches will be set-up with the given ``batch_size``, ``dtype``, and ``max_seq_len`` when
    entering the context manager, and will be deleted on exit.

    Example:
        >>> from torchtune.models.llama3_2 import llama3_2_1b
        >>> from torchtune.modules import local_kv_cache
        >>> import torch
        >>> model = llama3_2_1b()
        >>> print(model.caches_are_setup())
        False
        >>> print(model.caches_are_enabled())
        False
        >>> print(model.layers[0].attn.kv_cache)
        None
        >>> # entering cacheing mode
        >>> with local_kv_cache(model,
        >>>                     batch_size=1,
        >>>                     device=torch.device("cpu"),
        >>>                     dtype=torch.float32,
        >>>                     decoder_max_seq_len=1024):
        >>>     print(model.caches_are_setup())
        True
        >>>     print(model.caches_are_enabled())
        True
        >>>     print(model.layers[0].attn.kv_cache)
        KVCache()
        >>> # exited cacheing mode
        >>> print(model.caches_are_setup())
        False
        >>> print(model.caches_are_enabled())
        False
        >>> print(model.layers[0].attn.kv_cache)
        None

    Args:
        model (nn.Module): model to enable KV-cacheing for.
        batch_size (int): batch size for the caches.
        device (torch.device): device to setup caches on. this should be the same device
            the model is on.
        dtype (torch.dtype): dtype for the caches.
        encoder_max_seq_len (Optional[int]): maximum encoder cache sequence length.
        decoder_max_seq_len (Optional[int]): maximum decoder cache sequence length.

    Yields:
        None: Returns control to the caller with KV-caches setup and enabled on the given model.

    Raises:
        ValueError: If the model already has caches setup.
            You may use :func:`~torchtune.modules.common_utils.delete_kv_caches` to delete existing caches.
    zModel caches must be not setup prior to entering this context manager! Please use delete_kv_caches(model) to delete model caches.rf   N)r]   r^   setup_cachesdelete_kv_caches)r   ri   rj   r   rg   rh   s         r   local_kv_cachern   =  s      B  
I
 
 	

 
 
 
 3 3	 	 	
 	
 	

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 s   AAAA/ /B c                     |                                  st          d          |                                 D ]4}t          |d          r"t	          |j                  rd|_        d|_        5dS )a  
    Deletes KV caches from all attention layers in a model,
    and also ensures ``cache_enabled`` is set to False.

    Example:
        >>> from torchtune.models.llama3_2 import llama3_2_1b
        >>> from torchtune.modules import delete_kv_caches
        >>> import torch
        >>> model = llama3_2_1b()
        >>> model.setup_caches(batch_size=1,
        >>>                     dtype=torch.float32,
        >>>                     decoder_max_seq_len=1024)
        >>> print(model.caches_are_setup())
        True
        >>> print(model.caches_are_enabled())
        True
        >>> print(model.layers[0].attn.kv_cache)
        KVCache()
        >>> delete_kv_caches(model)
        >>> print(model.caches_are_setup())
        False
        >>> print(model.caches_are_enabled())
        False
        >>> print(model.layers[0].attn.kv_cache)
        None

    Args:
        model (nn.Module): model to enable KV-cacheing for.

    Raises:
        ValueError: if this function is called on a model which does not have
            caches setup. Use :func:`~torchtune.modules.TransformerDecoder.setup_caches` to
            setup caches first.
    zuYou have tried to delete model caches, but model.caches_are_setup() is False! Please setup caches on the model first.r\   FN)r]   r^   r`   ra   rb   r\   rc   rd   s     r   rm   rm     s    F !!## 
@
 
 	
 --// # #6:&& 	#8FO+D+D 	##(F "FO# #r   )(
contextlibr@   rU   collectionsr   	functoolsr   typingr   r   r   r   warningsr	   rC   torch.nnnntorch._subclasses.fake_tensorr
   r   torchao.dtypes.nf4tensorr   r   bool__annotations__bfloat16Modulestrr   r   r'   listr=   rQ   rZ   contextmanagerre   rj   rn   rm   r&   r   r   <module>r      s9         



 # # # # # #       1 1 1 1 1 1 1 1 1 1 1 1              M M M M M M M M . . . . . . $    #4 #4 #49#4S#X#4 #4 ;	#4
 #4 #4 #4 #4 #4LG# Gs GtDz G G G G\ C+ C+ C+9C+S#XC+ C+ ;	C+
 C+ C+ C+ C+ C+P  I;    D I,BI I,)4D*E I, I, I, I,X  *.)-P  P  P 9P  P  L	P 
 ;P  "#P  "#P   P  P  P  P f+#BI +# +# +# +# +# +#r   