U
    <ºc)  ã                   @   sp   d dl Z d dlmZ d dlZd dlZd dlmZ ddddgZG dd„ deƒZ	d	d„ Z
d
d„ ZG dd„ deƒZdS )é    N)ÚOrderedDict)ÚAnyÚRemovableHandleÚunserializable_hookÚwarn_if_has_hooksÚBackwardHookc                   @   s|   e Zd ZU dZeed< dZeed< eddœdd„Zdd	œd
d„Z	dd„ Z
dd	œdd„Zd d	œdd„Zeeeddœdd„ZdS )r   z8A handle which provides the capability to remove a hook.Úidr   Únext_idN)Ú
hooks_dictÚreturnc                 C   s&   t  |¡| _tj| _t jd7  _d S )Né   )ÚweakrefÚrefÚhooks_dict_refr   r	   r   ©Úselfr
   © r   ú5/tmp/pip-unpacked-wheel-gikjz4vx/torch/utils/hooks.pyÚ__init__   s    zRemovableHandle.__init__)r   c                 C   s&   |   ¡ }|d k	r"| j|kr"|| j= d S ©N©r   r   r   r   r   r   Úremove   s    zRemovableHandle.removec                 C   s   |   ¡ | jfS r   r   ©r   r   r   r   Ú__getstate__   s    zRemovableHandle.__getstate__c                 C   sN   |d d krt  tƒ ¡| _nt  |d ¡| _|d | _ttj| jd ƒt_d S )Nr   r   )r   r   r   r   r   Úmaxr   r	   )r   Ústater   r   r   Ú__setstate__   s
    
zRemovableHandle.__setstate__c                 C   s   | S r   r   r   r   r   r   Ú	__enter__%   s    zRemovableHandle.__enter__)ÚtypeÚvalueÚtbr   c                 C   s   |   ¡  d S r   )r   )r   r   r   r    r   r   r   Ú__exit__(   s    zRemovableHandle.__exit__)Ú__name__Ú
__module__Ú__qualname__Ú__doc__ÚintÚ__annotations__r	   r   r   r   r   r   r   r!   r   r   r   r   r   	   s   
	c                 C   s
   d| _ | S )z·
    Decorator which marks a function as an unserializable hook.
    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   ,   s    c                 C   s>   | j r:| j D ],}| j | }t|dƒst d t|ƒ¡¡ qd S )Nr(   z«backward hook {} 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)Z_backward_hooksÚhasattrÚwarningsÚwarnÚformatÚrepr)ZtensorÚkÚhookr   r   r   r   6   s    


ý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   s.   || _ || _d | _d| _d | _d| _d | _d S )Néÿÿÿÿ)Ú
user_hooksÚmoduleÚgrad_outputsÚ	n_outputsÚoutput_tensors_indexÚn_inputsÚinput_tensors_index)r   r3   r2   r   r   r   r   J   s    zBackwardHook.__init__c                 C   s.   d g| }t ||ƒD ]\}}|||< qt|ƒS r   )ÚzipÚtuple)r   ÚindicesÚvaluesÚsizeÚresÚidxÚvalr   r   r   Ú_pack_with_noneT   s    

zBackwardHook._pack_with_nonec                 C   s$   g }|D ]}|  || ¡ qt|ƒS r   )Úappendr:   )r   r;   r<   r>   r?   r   r   r   Ú_unpack_none[   s    zBackwardHook._unpack_nonec                    s   ‡ fdd„}|  |¡ d S )Nc                    s†   ˆ j d krd S ˆ  ˆ j| ˆ j¡}ˆ jD ]J}|ˆ j|ˆ j ƒ}|d krDq&t|ƒt|ƒkrltd t|ƒt|ƒ¡ƒ‚|}q&d ˆ _ ˆ  	ˆ j|¡S )NzOBackward hook returned an invalid number of grad_input, got {}, but expected {})
r4   rA   r8   r7   r2   r3   ÚlenÚRuntimeErrorr-   rC   )Z
grad_inputÚ_r>   r0   Úoutr   r   r   r0   c   s    

 ÿz)BackwardHook._set_user_hook.<locals>.hook©Úregister_hook)r   Úgrad_fnr0   r   r   r   Ú_set_user_hookb   s    zBackwardHook._set_user_hookc                 C   sà   g }g }d}t |ƒD ]2\}}t|tjƒr| |¡ | |¡ ||jO }q|rTt ¡ s\|d fS tjjj	j
j|Ž }t|ƒdkr‚tdƒ‚dd„ |D ƒ}	t|	ƒdkr¤tdƒ‚||	d ƒ t|ƒ}
t||ƒD ]\}}||
|< qÂt|
ƒ|fS )NFr   zCCannot set Module backward hook for a Module with no input Tensors.c                 S   s*   g | ]"}|j d k	r|j  ¡ dkr|j ‘qS )NZBackwardHookFunctionBackward)rJ   Úname)Ú.0Útr   r   r   Ú
<listcomp>‘   s     
  z2BackwardHook._apply_on_tensors.<locals>.<listcomp>zaError while setting up backward hooks. Please open an issue with a code sample to reproduce this.)Ú	enumerateÚ
isinstanceÚtorchZTensorrB   Úrequires_gradZis_grad_enabledÚnnÚmodulesZ
_functionsZBackwardHookFunctionÚapplyrD   rE   Úlistr9   r:   )r   ÚfnÚargsZtensors_idxZtensorsrS   ÚiÚargZnew_tensorsZgrad_fnsÚarg_listr?   r@   r   r   r   Ú_apply_on_tensors}   s*    


zBackwardHook._apply_on_tensorsc                    s0   ‡ fdd„}ˆ   ||¡\}}t|ƒˆ _|ˆ _|S )Nc                    s   ˆ   | ¡ d S r   )rK   )rJ   r   r   r   rX   Ÿ   s    z)BackwardHook.setup_input_hook.<locals>.fn)r]   rD   r7   r8   )r   rY   rX   r>   Z	input_idxr   r   r   Úsetup_input_hookž   s
    
zBackwardHook.setup_input_hookc                    sT   ‡ fdd„}d}t |tƒs$|f}d}ˆ  ||¡\}}t|ƒˆ _|ˆ _|sP|d }|S )Nc                    s   ‡ fdd„}|   |¡ d S )Nc                    s€   ˆ   ˆ j|ˆ j¡ˆ _ˆ jd kr|ˆ   g g ˆ j¡}ˆ jD ]@}|ˆ j|ˆ jƒ}|d k	r4t|t	ƒrlt
dd„ |D ƒƒs4tdƒ‚q4d ˆ _d S )Nc                 s   s   | ]}|d kV  qd S r   r   )rM   Úelr   r   r   Ú	<genexpr>´   s     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.)rA   r6   r5   r4   r8   r7   r2   r3   rQ   r:   ÚallrE   )rF   Zgrad_outputZgrad_inputsZ	user_hookr>   r   r   r   r0   ©   s    þ

$
z8BackwardHook.setup_output_hook.<locals>.fn.<locals>.hookrH   )rJ   r0   r   r   r   rX   ¨   s    z*BackwardHook.setup_output_hook.<locals>.fnTFr   )rQ   r:   r]   rD   r5   r6   )r   rY   rX   Zis_tupler>   Z
output_idxr   r   r   Úsetup_output_hook§   s    

zBackwardHook.setup_output_hookN)r"   r#   r$   r%   r   rA   rC   rK   r]   r^   rb   r   r   r   r   r   @   s   	
!	)rR   Úcollectionsr   r   r+   Útypingr   Ú__all__Úobjectr   r   r   r   r   r   r   r   Ú<module>   s   #

