o
    )iX]                     @   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!	 e!d
ddej"j#de$fddZ%dej"j#dej&fddZ'e!dddej"j#de(dej)fddZ*dej"j#dej)de(fddZ+	 dej"j#dej&fddZ,	dIdej"j#d e(d!ej"j-d"eeej&ed# f  fd$d%Z.	dId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)Z0e!e1 dej2dej"j#fd*d+Z3e!dd	dId,eee
ef de(d-ej)d"eeej&ed# f  fd.d/Z4e!ddd,eee
ef de(fd0d1Z5e!e1 dej2dej"j#fd2d3Z6e!e1 dej2	dId4eej"j#eej"j# f d5eej& fd6d7Z7d8ej"j#d e(dej"j#fd9d:Z8d8ej"j#d e(fd;d<Z9e!d=de&d>fdej"j#d5ej&d"eej&ed# f dej"j#fd?d@Z:dej"j#dej"j#fdAdBZ;ej2dCdD Z<	 e!d
ddej"j#de$fdEdFZ=e!e1 dej2	dIdej"j#d5eej& fdGdHZ>dS )Jaw  
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)is_module_offloadedget_execution_deviceget_offloaded_deviceupdate_prefix_dict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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/   l/home/app/PaddleOCR-VL-test/.venv_paddleocr/lib/python3.10/site-packages/compressed_tensors/utils/offload.pyfallback_fna   s   z8check_accelerate.<locals>.decorator.<locals>.fallback_fnc                     s    S Nr/   r,   r(   r/   r0   r1   i   s   )_has_accelerater   )r)   r1   r3   r/   r0   	decorator]   s   
z#check_accelerate.<locals>.decorator)r   r   )r(   r5   r/   r3   r0   check_accelerate\   s   r6   r3   modulereturnc                 C   s   t | S r2   )r   r7   r/   r/   r0   r   w   s   r   c                 C   s>   t | rt| jj d }| jjj}|| jS t|  j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devicenext
parameters)r7   Z	first_keyZprefix_datasetr/   r/   r0   r   |   s
   

r   keydatac                 C   s(   t | std| jj}t||| dS )a  
    Updates the offloaded state dict for a given module. Parameter named key is replaced
    by data. This is neccesary because parameter updates for offloaded modules do not
    persist automatically between loads. This function only affects the offloaded
    state dict and not the current state of the loaded module.

    :param module: module containing the parameter to update
    :param key: name of parameter to update
    :param data: tensor to update parameter with in the offloaded state dict
    z3Prefix dict is only applicable to offloaded modulesN)r   r+   r;   r<   offload_to_weights_map)r7   rB   rC   r<   r/   r/   r0   r      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   )r7   rE   rF   r/   r/   r0   r      s   r   c                 C   sb   |   D ]}t|r|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 CPUcpu)
modulesr   r;   execution_devicer@   rA   r?   warningswarntorch)r7   	submoduleparamr/   r/   r0   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?   rN   ).0pr/   r/   r0   	<genexpr>   s    z-register_offload_parameter.<locals>.<genexpr>NrU   )anyrA   Zregister_parameterr   r;   r<   r?   Zoriginal_devicesrD   rC   tied_params_mapdata_ptrr   )r7   rQ   rR   rS   Z
has_onloadhook	offloadedr/   r/   r0   r      s   

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)getattrrC   shaperL   rM   r?   rN   Zcopy_r   r;   r<   rD   )r7   rQ   rC   rS   rP   r<   r/   r/   r0   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   r;   r<   delete_from_weights_map)r7   rQ   r<   r/   r/   r0   r   	  s
   
r   c                 #   sB    i   fdd}|  | d V    D ]	\}}t|| qd S )Nc                    s$   t | dr| j | < t|  d S d S )Nr;   )hasattrr;   r   r9   hooksr/   r0   collect_hooks  s   

z&disable_hf_hook.<locals>.collect_hooks)applyitemsr   )r7   re   rO   r\   r/   rc   r0   r     s   
r   r<   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 )
isinstancer   r+   typer>   prefixrD   r   all_keysappendlenindex
state_dictNotImplementedErrordictr?   r@   itervaluesto)r<   rB   rh   rS   r>   Ztensr/   r/   r0   rD   *  s@   



rD   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 yetrj   )rk   r   r>   rm   ra   r   rp   rq   rr   rs   rt   rl   )r<   rB   r>   r/   r/   r0   ra   h  s"   



ra   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   r;   offloadr9   r/   r/   r0   r      s   	
r    rJ   rK   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)	rk   rN   nnModule
contextlib	ExitStackenter_contextr"   r    )rJ   rK   stackr7   r/   r/   r0   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)Zinclude_buffersrH   .)rm   )rK   rx   Zio_same_devicer<   offload_buffersplace_submodules	skip_keysrZ   )r   r;   rx   r<   r@   rA   r?   r   r   rw   rZ   r[   rD   r   r   r   r>   rm   r   rK   r   Zregister_module)r   rQ   r7   r\   r   r   Zcurrent_devicerS   rF   rP   r]   r<   Zsubmodule_hookr/   r/   r0   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)r^   r:   named_parametersr   r`   )r   rQ   r7   rF   _r/   r/   r0   r$     s   
r$   r*   rI   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/   )rw   )rV   rB   valrS   r/   r0   
<dictcomp>  s    z&offloaded_dispatch.<locals>.<dictcomp>)rr   r?   T)rK   rx   r<   rZ   hf_device_maprI   zcuda:0)Zfake_offloadZ	fake_exec)
rs   r'   rr   rg   r   r   r   r[   r   setattr)
r7   rK   rS   rr   r<   Ztied_paramsrZ   grouprF   r[   r/   r   r0   r%     s,   
r%   c                 C   s$   t | dd t| drt| 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   )r   rb   r`   r9   r/   r/   r0   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)rx   )r   r7   r-   r.   retZonloaded_modulesZoriginal_pre_forwardr/   r0   keep_onload_pre_forwardF  s
   z3disable_offloading.<locals>.keep_onload_pre_forwardpre_forwardNFrG   )
r   r   rt   r   rg   rx   r   r   rC   post_forward)r   r7   r\   rx   rQ   rP   r/   r   r0   r&   <  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.
    r;   )rb   rk   r;   r   rx   r9   r/   r/   r0   r   ^  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/   ri   )rV   rQ   rP   r/   r/   r0   r     s    z'align_module_device.<locals>.<dictcomp>FrG   )r   r;   rK   r   r   r   r   rg   )r7   rK   Zoriginal_deviceZdevicesrQ   r?   r/   r/   r0   r"   s  s:   


r"   r2   )?__doc__r{   rL   	functoolsr   operatorr   typingr   r   r   r   r   r	   r
   r   rN   Zcompressed_tensors.utilsr   Zaccelerate.hooksr   r   r   r   r   Zaccelerate.utilsr   r   r   r   r4   ImportError__all__r6   ry   rz   boolr   r?   r   strZTensorr   r   r   	Parameterr   r   r   nullcontextcontextmanagerr   rD   ra   r    r!   r#   r$   r%   r'   r&   r   r"   r/   r/   r/   r0   <module>   s   (

,
!=9:
