o
    闦i4%                     @   sl   d dl Z d dlmZ d dlZd dlZd dlmZmZ g dZG dd dZ	dd Z
d	d
 ZG dd dZdS )    N)OrderedDict)AnyTuple)RemovableHandleunserializable_hookwarn_if_has_hooksBackwardHookc                   @   s   e Zd ZU dZeed< dZeed< dddeded	dfd
dZdddZ	dd Z
dddZdddZdededed	dfddZdS )r   a]  
    A handle which provides the capability to remove a hook.

    Args:
        hooks_dict (dict): A dictionary of hooks, indexed by hook ``id``.
        extra_dict (Union[dict, List[dict]]): An additional dictionary or list of
            dictionaries whose keys will be deleted when the same keys are
            removed from ``hooks_dict``.
    idr   next_idN)
extra_dict
hooks_dictr   returnc                C   sj   t || _tj| _t jd7  _d| _t|tr"t |f| _d S t|t	r3t
dd |D | _d S d S )N    c                 s       | ]}t |V  qd S Nweakrefref.0dr   r   O/home/ubuntu/transcripts/venv/lib/python3.10/site-packages/torch/utils/hooks.py	<genexpr>!       z+RemovableHandle.__init__.<locals>.<genexpr>)r   r   hooks_dict_refr   r
   r	   extra_dict_ref
isinstancedictlisttuple)selfr   r   r   r   r   __init__   s   

zRemovableHandle.__init__c                 C   sR   |   }|d ur| j|v r|| j= | jD ]}| }|d ur&| j|v r&|| j= qd S r   )r   r	   r   )r!   r   r   r   r   r   r   remove#   s   
zRemovableHandle.removec                 C   s8   | j d u r|  | jfS |  | jtdd | j D fS )Nc                 s   s    | ]}| V  qd S r   r   )r   r   r   r   r   r   1   s    z/RemovableHandle.__getstate__.<locals>.<genexpr>)r   r   r	   r    r!   r   r   r   __getstate__-   s   
 zRemovableHandle.__getstate__c                 C   s   |d d u rt t | _nt |d | _|d | _ttj| jd t_t|dk s1|d d u r6d| _	d S t
dd |d D | _	d S )Nr   r         r   c                 s   r   r   r   r   r   r   r   r   ?   r   z/RemovableHandle.__setstate__.<locals>.<genexpr>)r   r   r   r   r	   maxr   r
   lenr   r    )r!   stater   r   r   __setstate__3   s   

zRemovableHandle.__setstate__c                 C   s   | S r   r   r$   r   r   r   	__enter__A   s   zRemovableHandle.__enter__typevaluetbc                 C   s   |    d S r   )r#   )r!   r-   r.   r/   r   r   r   __exit__D   s   zRemovableHandle.__exit__)r   N)r   r   )__name__
__module____qualname____doc__int__annotations__r
   r   r"   r#   r%   r+   r,   r0   r   r   r   r   r   
   s   
 




r   c                 C   s
   d| _ | S )z
    Mark a function as an unserializable hook with this decorator.

    This suppresses warnings that would otherwise arise if you attempt
    to serialize a tensor that has a hook.
    T)__torch_unserializable__)fr   r   r   r   H   s   r   c                 C   sD   | j r| j D ]}| j | }t|dstdt| d qd S d S )Nr7   zbackward hook z on tensor will not be serialized.  If this is expected, you can decorate the function with @torch.utils.hooks.unserializable_hook to suppress this warning)_backward_hookshasattrwarningswarnrepr)tensorkhookr   r   r   r   S   s   


r   c                   @   sH   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dd Z
dS )r   a  
    A wrapper class to implement nn.Module backward hooks.

    It handles:
      - Ignoring non-Tensor inputs and replacing them by None before calling the user hook
      - Generating the proper Node to capture a set of Tensor's gradients
      - Linking the gradients captures for the outputs with the gradients captured for the input
      - Calling the user hook once both output and input gradients are available
    c                 C   s4   || _ || _|| _d | _d| _d | _d| _d | _d S )N)
user_hooksuser_pre_hooksmodulegrad_outputs	n_outputsoutput_tensors_indexn_inputsinput_tensors_index)r!   rD   rB   rC   r   r   r   r"   h   s   
zBackwardHook.__init__c                 C   s.   d g| }t ||D ]\}}|||< q
t|S r   )zipr    )r!   indicesvaluessizeresidxvalr   r   r   _pack_with_nones   s   

zBackwardHook._pack_with_nonec                    s    fdd|D }t |S )Nc                    s   g | ]} | qS r   r   )r   rO   rL   r   r   
<listcomp>{   s    z-BackwardHook._unpack_none.<locals>.<listcomp>)r    )r!   rK   rL   rN   r   rR   r   _unpack_nonez   s   zBackwardHook._unpack_nonec                    s    fdd}| | d S )Nc                    s    j d u rd S   j|  j} jD ]'}| j| j }|d u r"qt|t|kr8tdt| dt| |}qd  _   j|S )Nz<Backward hook returned an invalid number of grad_input, got , but expected )	rE   rQ   rI   rH   rB   rD   r)   RuntimeErrorrT   )
grad_input_rN   r@   outr$   r   r   r@      s    

z)BackwardHook._set_user_hook.<locals>.hookregister_hook)r!   grad_fnr@   r   r$   r   _set_user_hook   s   zBackwardHook._set_user_hookc                 C   s  g }g }d}t |D ]\}}t|tjr#|| || ||jO }q
|r*t s.|d fS tjjj	j
j| }t|dkrAtddd |D }	t|	dkrRtd||	d  t|}
t||D ]\}}||
|< qat|tu rxt|
}||fS t||
 }||fS )NFr   zCCannot set Module backward hook for a Module with no input Tensors.c                 S   s*   g | ]}|j d ur|j  dkr|j qS )NBackwardHookFunctionBackward)r\   name)r   tr   r   r   rS      s   * z2BackwardHook._apply_on_tensors.<locals>.<listcomp>zaError while setting up backward hooks. Please open an issue with a code sample to reproduce this.)	enumerater   torchTensorappendrequires_gradis_grad_enablednnmodules
_functionsBackwardHookFunctionapplyr)   rV   r   rJ   r-   r    )r!   fnargstensors_idxtensorsre   iargnew_tensorsgrad_fnsarg_listrO   rP   rY   r   r   r   _apply_on_tensors   s4   



zBackwardHook._apply_on_tensorsc                    s0    fdd}  ||\}}t| _| _|S )Nc                    s     |  d S r   )r]   )r\   r$   r   r   rl      s   z)BackwardHook.setup_input_hook.<locals>.fn)ru   r)   rH   rI   )r!   rm   rl   rN   	input_idxr   r$   r   setup_input_hook   s
   
zBackwardHook.setup_input_hookc                    sT    fdd}d}t |ts|f}d} ||\}}t| _| _|s(|d }|S )Nc                    s    fdd}|  | d S )Nc           	         s   j|j_jr9tj}jD ]#}|jj}|d u r#qt|}||kr5td| d| |_qj jd u rp g g j	}j
D ] }|j|j}|d urlt|trhtdd |D sltdqLd _ d urjd us{J t fddjD S d S )NzABackward pre hook returned an invalid number of grad_output, got rU   c                 s   s    | ]}|d u V  qd S r   r   )r   elr   r   r   r          zKBackwardHook.setup_output_hook.<locals>.fn.<locals>.hook.<locals>.<genexpr>zoBackward hook for Modules where no input requires gradient should always return None or None for all gradients.c                 3   s    | ]} | V  qd S r   r   )r   rp   local_grad_outputsr   r   r      ry   )rQ   rG   rF   rE   rC   r)   rD   rV   rI   rH   rB   r   r    all)	rX   grad_outputexpected_lenuser_pre_hookhook_grad_outputs
actual_lengrad_inputs	user_hookrN   r$   rz   r   r@      s>   



$z8BackwardHook.setup_output_hook.<locals>.fn.<locals>.hookrZ   )r\   r@   r$   r   r   rl      s   $z*BackwardHook.setup_output_hook.<locals>.fnTFr   )r   r    ru   r)   rF   rG   )r!   rm   rl   is_tuplerN   
output_idxr   r$   r   setup_output_hook   s   '

zBackwardHook.setup_output_hookN)r1   r2   r3   r4   r"   rQ   rT   r]   ru   rw   r   r   r   r   r   r   ]   s    
%	r   )rb   collectionsr   r   r;   typingr   r   __all__r   r   r   r   r   r   r   r   <module>   s   >
