o
    Zh4                     @   sR  d dl Z d dlZd dlZd dlZd dlmZmZ d dlmZ d dl	m
Z
 d dlmZ ddlmZ e r;d dlZd dlZddlmZ eeZej Zd	d
 ZedZdedefddZdd Zdd ZdejfddZ dd Z!edZ"dd Z#dd Z$dd Z%	 	!d*d"e
e d#e
e& fd$d%Z'ed&d'ed+d"e
e d#e
e& fd(d)Z(dS ),    N)contextmanagerredirect_stdout)StringIO)Optional)requires   )is_torch_available)loggingc                   C   s    t rtj s	dS tj dkS )z7Return True if rank=0 or we aren't running distributed.Tr   )_torch_distributed_availabletorchdistributedZis_initializedZget_rank r   r   Q/var/www/auris/lib/python3.10/site-packages/transformers/model_debugging_utils.py_is_rank_zero+   s   r   zobject at 0x[0-9A-Fa-f]+x_strreturnc                 C   s   t d| S )z
    Replace memory addresses in an object's repr with a stable placeholder
    so that beautiful JSON diffs won't be ruined by ephemeral addresses.
    zobject at 0xXXXXXXXX)MEMORY_ADDRESS_REGEXsub)r   r   r   r   _sanitize_repr_for_diff5   s   r   c                 C   s   t  rdt| j S dS )z@Return a stable string representation for a DTensor-like object.zDTensor (rank0) -> zDTensor(non-rank0))r   repr_local_tensor)xr   r   r   _dtensor_repr=   s   r   c              	   C   s~  t | ttfrdd | D S t | trdd |  D S t| drntjdd t| }t	| j
jt	| j
j|d}| j
jtjtjtjhv rl| j
 } |tt	|  tt	|  tt	|  tt	|  d	 |S t | tjrtjdd t| }t	| jt	| j|d}| jtjtjtjhv r|tt	|  tt	|  tt	|  tt	|  d	 |S tt	| S )
a  
    Recursively build a JSON-serializable Python structure from `value`.
    Tensors and DTensors become sanitized repr strings.
    Lists/tuples/dicts are recursed into.
    All memory addresses are replaced with a stable placeholder.

    Args:
        value: Any Python object, often including torch Tensors, lists, dicts, etc.

    Returns:
        A nested Python structure (list, dict, or sanitized string) that is safe to json.dump.
    c                 S   s   g | ]}t |qS r   _serialize_io).0vr   r   r   
<listcomp>R       z!_serialize_io.<locals>.<listcomp>c                 S   s   i | ]	\}}|t |qS r   r   )r   kr   r   r   r   
<dictcomp>U   s    z!_serialize_io.<locals>.<dictcomp>r   T)sci_mode)shapedtypevalue)meanstdminmax)
isinstancelisttupledictitemshasattrr   set_printoptions_repr_to_listr   r   r"   r#   Zfloat16Zfloat32Zbfloat16cloneupdater   r%   r&   r'   r(   Tensor)r$   Zval_reproutr   r   r   r   D   sL   




r   r$   c              	   C   sx   t jddd t $}t| t|  | }W d   n1 s"w   Y  W d   n1 s1w   Y  t| S )z
    Converts a tensor into a sanitized multi-line string representation.

    Args:
        value (`torch.Tensor`): The tensor to represent.

    Returns:
        `List[str]`: List of string lines representing the tensor.
    Tx   )r!   Z	linewidthN)r   r/   r   r   printgetvaluer   
splitlines)r$   bufrawr   r   r   r0      s   

 r0   c                 C   s4   |  dr| dd  | d D ]}t| qd S d S )Nchildrenoutputs)getpopprune_outputs_if_childrennodechildr   r   r   r?      s   

r?   z(.*)\.(\d+)$c                    sH   t | dd}|r| dsdS |d t fdd| d D S )z
    Checks whether a node represents a layer block with submodules.

    Args:
        node (`dict`): A node from the call tree.

    Returns:
        `bool`: Whether the node is a layer block.
    module_path r;   F   c                 3   s(    | ]}d   d | ddv V  qdS ).rC   rD   Nr=   )r   rB   numberr   r   	<genexpr>   s   & z!is_layer_block.<locals>.<genexpr>)LAYER_SUFFIX_REmatchr=   groupany)rA   rL   r   rH   r   is_layer_block   s
   

rO   c                    s~   |  dsdS dd t| d D }t|dkr2dd |dd D   fd	dt| d D | d< | d D ]}t| q6dS )
z
    Recursively removes intermediate layers from the tree to improve readability.
    Keeps at least the first and last layers if many consecutive layers are present.

    Args:
        node (`dict`): The root or subnode to prune recursively.
    r;   Nc                 S   s    g | ]\}}t |r||fqS r   )rO   r   irB   r   r   r   r      s     z-prune_intermediate_layers.<locals>.<listcomp>rE   c                 S   s   g | ]\}}|qS r   r   )r   rQ   _r   r   r   r      r   r   c                    s   g | ]
\}}| vr|qS r   r   rP   	to_remover   r   r      s    )r=   	enumeratelenprune_intermediate_layers)rA   Zlayer_blocksrB   r   rT   r   rX      s   

rX   c              
      s0  | r,zt j| dd t j| |jd }W n ty+ } z
td|  d| d }~ww |jd }td| d |d }|d	 }t	|j
 t|d
}tj|j
|dd W d    n1 s`w   Y   fdd tt|j
} | t|d
}tj||dd W d    d S 1 sw   Y  d S )NT)exist_okZ_debug_treez"Unexpected or existing debug_path=z. zWriting model trace at z.jsonz_FULL_TENSORS.jsonz_SUMMARY.jsonwrE   )indentc                    sJ    fdd  |  di   |  di  |  dg D ]}| qd S )Nc                    sT   t | tr| dd  |  D ]} | qd S t | tr&| D ]} | qd S d S )Nr$   )r)   r,   r>   valuesr*   )valr   itemcleanr   r   r`      s   



z:log_model_debug_trace.<locals>.strip_values.<locals>.cleaninputsr<   r;   rG   r@   strip_valuesr_   r   rc      s   	
z+log_model_debug_trace.<locals>.strip_values)osmakedirspathjoin_debugger_module_dump_name	Exception
ValueErrorloggerinfor?   
_call_treeopenjsondumploadsdumps)
debug_pathmodelbasee	full_pathZsummary_pathfZ	tree_copyr   rb   r   log_model_debug_trace   s,   

"ry   rF   Trs   do_prune_layersc                    s   j j  ddg d_g _ _fdd} D ]\}}|dkr%q||  d|  qjt fdd}|_dS )	a  
    Attaches a debugging wrapper to every module in the model.

    This records structured inputs and outputs during the forward pass into a call tree.

    Args:
        model (`PreTrainedModel`, `nn.Module`): Model to wrap.
        debug_path (`str`): Optional directory to dump debug JSON files.
        do_prune_layers (`bool`, *optional*, defaults to `True`): Whether to prune intermediate layers.
    NrC   ra   r<   r;   c                    s,   j t fdd}|_ d S )Nc                     s   t  r | |d  fdd D  t d g d}j| t  | i |}W d    n1 s6w   Y  t  rqtdd  D dkrPd |d< nt||d< j }|d	 sd|d	 jrqjd
 d	 | |S )Nargskwargsc                    s&   i | ]}t  | d kr| | qS )r   )rW   r   r   Zdict_inputsr   r   r      s   & zY_attach_debugger_logic.<locals>.wrap_forward.<locals>.wrapped_forward.<locals>.<dictcomp>r{   c                 s   s    | ]}d V  qdS )r   Nr   )r   rR   r   r   r   rJ     s    zX_attach_debugger_logic.<locals>.wrap_forward.<locals>.wrapped_forward.<locals>.<genexpr>r   r<   r;   rS   )	r   r   _debugger_model_call_stackappendr   Zno_gradsumZnamed_childrenr>   )inpskwsrA   r4   finished)rw   rt   moduleorig_forwardr   r   wrapped_forward  s,   




zE_attach_debugger_logic.<locals>.wrap_forward.<locals>.wrapped_forward)forward	functoolswraps)r   rw   r   rt   )rw   r   r   r   wrap_forward  s   
z,_attach_debugger_logic.<locals>.wrap_forwardrD   rF   c                     s   t  r  dt| |dd g d}j| | i |}t  r`jr`t||d< j }|d jd< |d jd< |d jd< fddtj D  rZtj t	d	 |S )
Nz (top-level)r|   r{   r<   ra   r;   c                    s$   g | ]} j | s j |d qS )N)rm   r>   r   r   r   r   r   D  s   $ zG_attach_debugger_logic.<locals>.top_wrapped_forward.<locals>.<listcomp>)rs   rt   )
r   r   r   r   r>   rm   r*   keysrX   ry   )r   r   Ztop_noder4   r   
class_namers   rz   rt   Zreal_top_forwardr   r   top_wrapped_forward1  s&   

z3_attach_debugger_logic.<locals>.top_wrapped_forward)		__class____name__rm   r   rh   named_modulesr   r   r   )rt   rs   rz   r   name	submoduler   r   r   r   _attach_debugger_logic   s   $
r   )r   )backendsc              	   c   sj    dd |   D }| j|| < t| || z| V  W | D ]\}}||_qdS | D ]\}}||_q,w )a]  
    # Model addition debugger - context manager for model adders
    This context manager is a power user tool intended for model adders.
    It tracks all forward calls within a model forward and logs a slice of each input and output on a nested Json.
    To note, this context manager enforces `torch.no_grad()`.

    ## Usage

    add the context manager to a model to debug

    ```python
    import torch
    from PIL import Image
    import requests
    from transformers import LlavaProcessor, LlavaForConditionalGeneration
    from transformers.model_debugging_utils import model_addition_debugger_context
    torch.random.manual_seed(673)

    # load pretrained model and processor
    model_id = "llava-hf/llava-1.5-7b-hf"
    processor = LlavaProcessor.from_pretrained(model_id)
    model = LlavaForConditionalGeneration.from_pretrained(model_id, low_cpu_mem_usage=True)

    # create random image input
    random_image = Image.fromarray(torch.randint(0, 256, (224, 224, 3), dtype=torch.uint8).numpy())

    # prompt
    prompt = "<image>Describe this image."

    # process inputs
    inputs = processor(text=prompt, images=random_image, return_tensors="pt")

    # call forward method (not .generate!)
    with model_addition_debugger_context(model, debug_path="Your_debug_path", do_prune_layers=False):
        output = model.forward(**inputs)
    ```

    c                 S   s   i | ]\}}||j qS r   )r   )r   rR   mr   r   r   r    y  s    z3model_addition_debugger_context.<locals>.<dictcomp>N)r   r   r   r-   )rt   rs   rz   Zorig_forwardsZmodule_instanceZforward_methodr   r   r   model_addition_debugger_contextP  s   )
r   )rF   T)NT))r   ro   rd   re
contextlibr   r   ior   typingr   Ztransformers.utils.import_utilsr   utilsr   r   Ztorch.distributed.tensorr	   Z
get_loggerr   rk   r   Zis_availabler
   r   compiler   strr   r   r   r3   r0   r?   rK   rO   rX   ry   boolr   r   r   r   r   r   <module>   sH   


>
	-
a$