o
    *i[                     @   s  d 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mZmZmZmZ ddlZddlmZ zddlmZmZmZmZmZ ddlmZmZmZmZ d	ZW n eyo   d
ZdZdZdZdZdZdZdZdZdZY nw g dZ defddZ!	 dej"j#dej$fddZ%dej"j#dej&de'fddZ(	 dee)ej$f dej$fddZ*dej"j#dej$fddZ+	dHdej"j#de'dej"j,deeej$ed f  fd d!Z-	dHdej"j#de'd"ej&deeej$ed f  fd#d$Z.dej"j#de'fd%d&Z/e!e0 d'ej1dej"j#fd(d)Z2e!dd'	dHd*eee
ef d+e'd,ej&deeej$ed f  fd-d.Z3e!dd'd*eee
ef d+e'fd/d0Z4e!e0 d'ej1dej"j#fd1d2Z5e!e0 d'ej1	dHd3eej"j#eej"j# f d4eej$ fd5d6Z6d7ej"j#de'dej"j#fd8d9Z7d7ej"j#de'fd:d;Z8e!d<d'e$d=fdej"j#d4ej$deej$ed f dej"j#fd>d?Z9dej"j#dej"j#fd@dAZ:ej1dBdC Z;	 e!d
d'dej"j#de<fdDdEZ=e!e0 d'ej1	dHdej"j#d4eej$ fdFdGZ>dS )Iaw  
Utilities associated with offloading functionality provided by `accelerate`.

| ------------------------------------------------------------------------------------------------------ | # noqa: E501
| Operation  | Without offloading support             | With offloading support                          | # noqa: E501
| ---------- | -------------------------------------- | ------------------------------------------------ | # noqa: E501
| Add        | module.register_parameter(name, param) | register_offload_parameter(module, name, param)  | # noqa: E501
| Check      | N/A                                    | has_offloaded_params(module)                     | # noqa: E501
| Onload     | N/A                                    | with align_module_device(module)                 | # noqa: E501
| Update     | module.name.data.copy_(new_data)       | update_offload_parameter(module, name, new_data) | # noqa: E501
| Delete     | del module.name                        | delete_offload_parameter(module, name)           | # noqa: E501
| Add Module | module.register_module(name, child)    | register_offload_module(name, child)             | # noqa: E501
| Del Module | del module.name                        | delete_offload_module(module, name)              | # noqa: E501
| ------------------------------------------------------------------------------------------------------ | # noqa: E501
    N)wraps)
attrgetter)AnyCallableDictIterableLiteralOptionalTupleUnion)
patch_attr)AlignDevicesHookadd_hook_to_moduleattach_align_device_hooknamed_module_tensorsremove_hook_from_module)OffloadedWeightsLoaderPrefixedDatasetfind_tied_parametersset_module_tensor_to_deviceTF)get_execution_deviceget_offloaded_deviceupdate_parameter_dataregister_offload_parameterupdate_offload_parameterdelete_offload_parameterhas_offloaded_paramsdisable_hf_hookdisable_offloadalign_modulesalign_module_deviceregister_offload_moduledelete_offload_moduleoffloaded_dispatchdisable_offloadingremove_dispatchcast_to_devicefallbackc                    s    dt tgtf f fdd}|S )Nfuncc                    s<   t s dkrt| dd }|S t|  fdd}|S | S )Nerrorc                  _   s   t d)Nz9Please install `accelerate` in order to use this function)
ValueErrorargskwargs r.   ]/home/ubuntu/veenaModal/venv/lib/python3.10/site-packages/compressed_tensors/utils/offload.pyfallback_fn`   s   z8check_accelerate.<locals>.decorator.<locals>.fallback_fnc                     s    S Nr.   r+   r'   r.   r/   r0   h   s   )_has_accelerater   )r(   r0   r2   r.   r/   	decorator\   s   
z#check_accelerate.<locals>.decorator)r   r   )r'   r4   r.   r2   r/   check_accelerate[   s   r5   modulereturnc                 C   s8   t | rt| jj d }| jjj}|| jS t| S )zk
    :param module: module to check
    :return: device module is offloaded to onto after forward pass
    r   )r   list_hf_hookweights_mapkeysdatasetdevicer   )r6   	first_keyprefix_datasetr.   r.   r/   r   v   s
   

r   new_param_data
param_namec                 C   s   t | || dS )aG  
    Update the data of an existing parameter and its offload dict. Supports both
    parameters of offloaded modules and non-offloaded modules

    :param module: module containing the parameter to update
    :param new_param_data: tensor to update parameter with
    :param param_name: name of module parameter to update
    N)r   )r6   r@   rA   r.   r.   r/   r      s   r   device_specc                 C   s,   t | trt| dkrd|  S dS | S )a  
    Convert an integer device index or torch.device into a torch.device object.

    :param device_spec: Device index (int) or torch.device object.
                        Negative integers map to CPU.
    :return: torch.device corresponding to the given device specification.
    r   zcuda:cpu)
isinstanceinttorchr=   )rB   r.   r.   r/   r&      s   
r&   c                 C   sf   |   D ] }t|rt|jj  S t|jddd}|dur$|j  S qt	d|  d t
dS )z
    Get the device which inputs should be moved to before module execution.
    Assume that modules execute in the same order as returned by `model.modules()`

    :param module: module to check, may be offloaded
    :return: onload device of module
    FrecurseNz"Unable to get execution device of z, falling back to CPUrC   )modulesr   r&   r9   execution_devicenext
parametersr=   warningswarnrF   )r6   	submoduleparamr.   r.   r/   r      s   

r   name	parameteroffload_devicediskc                 C   s   t dd |  D }| || t| rI| j}|jdusJ |j|j|< t|j||j	| |j| }|j
dur?i |j
| < |sKt| |d dS dS dS )aj  
    Register a parameter to the given module which may be offloaded

    :param module: maybe offloaded module
    :param name: name of newly registered parameter
    :param parameter: parameter being registered
    :param offload_device: device on which weight will be offloaded to. If None is
        provided, then infer device from parameters on module
    c                 s   s     | ]}|j t d kV  qdS )metaN)r=   rF   ).0pr.   r.   r/   	<genexpr>   s    z-register_offload_parameter.<locals>.<genexpr>NrU   )anyrL   register_parameterr   r9   r:   r=   original_devicesoffload_to_weights_mapdatatied_params_mapdata_ptrr   )r6   rQ   rR   rS   
has_onloadhook	offloadedr.   r.   r/   r      s   

r   r]   c                 C   s   t | |}|jj|jkrtd|jj d|j  |jtdkr-||jur-|j| t| r>| j	j
}t|||| dS dS )a  
    Update the data of an existing parameter and its offload dict. Supports both
    parameters of offloaded modules and non-offloaded modules

    :param module: module containing the parameter to update
    :param name: name of module parameter to update
    :param data: tensor to update parameter with
    :param offload_device: device on which weight will be offloaded to. If None is
        provided, then infer device from parameters on module
    z!Shape of parameter being updated z% does not match shape of update data rU   N)getattrr]   shaperM   rN   r=   rF   copy_r   r9   r:   r\   )r6   rQ   r]   rS   rP   r:   r.   r.   r/   r      s   
r   c                 C   s,   t | | t| r| jj}t|| dS dS )z
    Delete a parameter from a module which may be offloaded

    :param module: maybe offloaded module
    :param name: name of parameter being deleted
    N)delattrr   r9   r:   delete_from_weights_map)r6   rQ   r:   r.   r.   r/   r      s
   
r   r2   c                 #   sB    i   fdd}|  | d V    D ]	\}}t|| qd S )Nc                    s$   t | dr| j | < t|  d S d S )Nr9   )hasattrr9   r   r6   hooksr.   r/   collect_hooks  s   

z&disable_hf_hook.<locals>.collect_hooks)applyitemsr   )r6   rl   rO   ra   r.   rj   r/   r     s   
r   r:   keyvaluec                 C   s*  t | tr%|dkrtdt|  | j}| j | }t|||| dS t | trN|| jvr5| j	| t
| jdkrJ|dkrJt| j||| dS tdt | tr|dkr`tdt|  |du r|| v rn| | j}ntt|  d}|du rtd|j}|j|d| |< dS tdt|  )	a  
    Helper function which implements offloaded item assignment for PrefixedDataset,
    OffloadedWeightsLoader, and Dict types.

    :param weights_map: weight map to be updated with offload information
    :param key: key used to identify weight location
    :param value: weight being offloaded
    :param offload_device: device on which weight will be offloaded to. If None is
        provided, then infer device from parameters in weights_map
    rT   z!Cannot offload to disk with type r   z@Updating weights_map with disk offloading is not implemented yetNz2Cannot infer offload device from empty weights_mapr=   >Updating offload data not implemented for weights_map of type )rD   r   r*   typer<   prefixr\   r   all_keysappendlenindex
state_dictNotImplementedErrordictr=   rK   itervaluesto)r:   ro   rp   rS   r<   tensr.   r.   r/   r\      s@   



r\   c                 C   s   t | tr| j}| j | }t|| d S t | tr.t| jdkr*t| j| d S t	dt | t
r8| |= d S t	dt|  )Nr   zCDelete from weights_map with disk offloading is not implemented yetrr   )rD   r   r<   rt   rg   r   rw   rx   ry   rz   r{   rs   )r:   ro   r<   r.   r.   r/   rg   ^  s"   



rg   c                 c   s.    t | rd| j_dV  d| j_dS dV  dS )z
    Context manager to disable module onloading and offloading. Parameters will stay on
    their current device

    :param module: module to disable offloading for
    FNT)r   r9   offloadri   r.   r.   r/   r   {  s   	
r   rI   rJ   c                 c   sv    t | tjjr| fn| } t  }| D ]}|t|| |t| qdV  W d   dS 1 s4w   Y  dS )a2  
    Context manager for onloading modules to a device, and disabling onload and offload
    attempts triggered by forward calls. Used for sequential onloading of layers

    :param modules: `torch.nn.Module` or iterable of `torch.nn.Module`s to onload
    :param execution_device: device to onload to
    N)	rD   rF   nnModule
contextlib	ExitStackenter_contextr    r   )rI   rJ   stackr6   r.   r.   r/   r     s   
"r   basec              
   C   s  t | rz| j}|jsJ |jdusJ d}d}t|  j}t| }t|||dD ]*\}}	|		|}
|j
dur>i |j
|
 < t|j| d| |
 |jrSt||| q)|jszt|jj|jj | dd}t|j|jd|||d|j
d}t|| | || dS )z
    Register a submodule with offloading if the parent module is offloaded

    :param base: module to attach submodule to
    :param name: name of submodule
    :param module: submodule to attach
    NFT)include_buffersrH   .)rt   )rJ   r   io_same_devicer:   offload_buffersplace_submodules	skip_keysr^   )r   r9   r   r:   rK   rL   r=   r   r   r~   r^   r_   r\   r   r   r   r<   rt   r   rJ   r   register_module)r   rQ   r6   ra   r   r   current_devicerS   rA   rP   rb   r:   submodule_hookr.   r.   r/   r!     sD   	




r!   c                 C   s8   t | |}t| D ]	\}}t|| qt| | dS )z
    Delete a submodule from a model which may contain offloading
    :param base: parent module to delete submodule from
    :param name: name of submodule on parent
    N)rc   r8   named_parametersr   rf   )r   rQ   r6   rA   _r.   r.   r/   r"     s   
r"   r)   rC   c           
         s    dkrt dt|  |  } fdd| D }t| d}t| }i }|D ]}|D ]}t||  }	i ||	< q-q)t| |d||d t	| dd	d
d | S )a  
    Unlike `dispatch_model`, this function forces a module (and its submodules) to
    offload all parameters and replace them with meta tensors, utiliizing the
    `AlignDevicesHook` to control onloading and offloading.

    :param module: module containing parameters to offload
    :param execution_device: device that modules will onload and execute on
    :param offload_device: device that module parameters will offload to
    :return: module with offloading device hooks
    rT   z*Disk offloading is not currently supportedc                    s   i | ]
\}}||  qS r.   )r~   )rV   ro   valrS   r.   r/   
<dictcomp>  s    z&offloaded_dispatch.<locals>.<dictcomp>)ry   r=   T)rJ   r   r:   r^   hf_device_maprC   zcuda:0)fake_offload	fake_exec)
rz   r%   ry   rn   r   r   r   r_   r   setattr)
r6   rJ   rS   ry   r:   tied_paramsr^   grouprA   r_   r.   r   r/   r#     s,   
r#   c                 C   s.   t | dd t| drt| d | d | S )z
    Remove any existing dispatches from module

    :param module: module which may be dispatched with hf hooks
    :return: module without dispatch
    TrG   r   rC   )r   rh   rf   r~   ri   r.   r.   r/   r%   $  s
   


r%   c                  #   s    t jt  dt f fdd} tt d|  dV  W d   n1 s%w   Y    D ]!\}\}}||_|jddD ]\}}t|||j q=|	|d q.dS )z
    Keep modules onloaded and disable offloading until this context exits.
    Affects modules which have been hooked with accelerate's `AlignDevicesHook`
    selfc                    s8   | |g|R i |}| vr| | j f |< d| _ |S )NF)r   )r   r6   r,   r-   retonloaded_modulesoriginal_pre_forwardr.   r/   keep_onload_pre_forward=  s
   z3disable_offloading.<locals>.keep_onload_pre_forwardpre_forwardNFrG   )
r   r   r{   r   rn   r   r   r   r]   post_forward)r   r6   ra   r   rQ   rP   r.   r   r/   r$   3  s   r$   c                 C   s   t | dot| jto| jjS )ad  
    Checks if a module has offloaded parameters by checking if the given module has a
    AlignDevicesHook attached with offloading enabled

    Args:
        module (`torch.nn.Module`): The module to check for an offload hook.

    Returns:
        bool: `True` if the module has an offload hook and offloading is enabled,
        `False` otherwise.
    r9   )rh   rD   r9   r   r   ri   r.   r.   r/   r   U  s
   

r   c                 c   s   t | r?|dur| jj}|| j_z| j|  dV  W | j| d |dur-|| j_dS dS | j| d |dur>|| j_w |durdd | jddD }z |D ]}t| || qQdV  W | D ]
\}}t| || qbdS | D ]
\}}t| || qsw dV  dS )a~  
    Context manager that moves a module's parameters to the specified execution device.

    Args:
        module (`torch.nn.Module`):
            Module with parameters to align.
        execution_device (`torch.device`, *optional*):
            If provided, overrides the module's execution device within the context.
            Otherwise, use hook execution device or pass
    Nc                 S   s   i | ]\}}||j qS r.   rq   )rV   rQ   rP   r.   r.   r/   r     s    z'align_module_device.<locals>.<dictcomp>FrG   )r   r9   rJ   r   r   r   r   rn   )r6   rJ   original_devicedevicesrQ   r=   r.   r.   r/   r    j  s:   


r    r1   )?__doc__r   rM   	functoolsr   operatorr   typingr   r   r   r   r   r	   r
   r   rF   compressed_tensors.utilsr   accelerate.hooksr   r   r   r   r   accelerate.utilsr   r   r   r   r3   ImportError__all__r5   r   r   r=   r   Tensorstrr   rE   r&   r   	Parameterr   r   r   nullcontextcontextmanagerr   r\   rg   r   r   r!   r"   r#   r%   r$   boolr   r    r.   r.   r.   r/   <module>   s   (

,
!=9:
