U
    •Ê¹j:$  ã                   @   sp   d dl Z d dlmZ d dlZd dlZd dlmZmZ ddddg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œe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   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   sd   t  |¡| _tj| _t jd7  _d| _t|tƒrBt  |¡f| _nt|t	ƒr`t
dd„ |D ƒƒ| _d S )Né   © c                 s   s   | ]}t  |¡V  qd S ©N©ÚweakrefÚref©Ú.0Údr   r   úP/var/www/html/bwave/python/venv/lib/python3.8/site-packages/torch/utils/hooks.pyÚ	<genexpr>    s     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__)r   c                 C   sR   |   ¡ }|d k	r"| j|kr"|| j= | jD ]$}|ƒ }|d k	r(| j|kr(|| j= q(d S r   )r   r	   r   )r   r   r   r   r   r   r   Úremove"   s    
zRemovableHandle.removec                 C   s<   | j d kr|  ¡ | jfS |  ¡ | jtdd„ | j D ƒƒfS d S )Nc                 s   s   | ]}|ƒ V  qd S r   r   )r   r   r   r   r   r   0   s     z/RemovableHandle.__getstate__.<locals>.<genexpr>)r   r   r	   r   ©r   r   r   r   Ú__getstate__,   s    
zRemovableHandle.__getstate__c                 C   s†   |d d krt  tƒ ¡| _nt  |d ¡| _|d | _ttj| jd ƒt_t|ƒdk sb|d d krjd| _	nt
dd„ |d D ƒƒ| _	d S )Nr   r   é   é   r   c                 s   s   | ]}t  |¡V  qd S r   r   r   r   r   r   r   >   s     z/RemovableHandle.__setstate__.<locals>.<genexpr>)r   r   r   r   r	   Úmaxr   r
   Úlenr   r   )r   Ústater   r   r   Ú__setstate__2   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__C   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   G   s    c                 C   s@   | j r<| j D ].}| j | }t|dƒst dt|ƒ› d�¡ qd S )Nr5   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)Z_backward_hooksÚhasattrÚwarningsÚwarnÚrepr)ZtensorÚkÚhookr   r   r   r   Q   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   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   r@   r>   r?   r   r   r   r    e   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_nonep   s    

zBackwardHook._pack_with_nonec                 C   s$   g }|D ]}|  || ¡ qt|ƒS r   )Úappendr   )r   rG   rH   rJ   rK   r   r   r   Ú_unpack_nonew   s    zBackwardHook._unpack_nonec                    s   ‡ fdd„}|  |¡ d S )Nc                    sŠ   ˆ j d krd S ˆ  ˆ j| ˆ j¡}ˆ jD ]N}|ˆ j|ˆ j ƒ}|d krDq&t|ƒt|ƒkrptdt|ƒ› dt|ƒ› �ƒ‚|}q&d ˆ _ ˆ  ˆ j|¡S )Nz<Backward hook returned an invalid number of grad_input, got ú, but expected )	rA   rM   rE   rD   r>   r@   r'   ÚRuntimeErrorrO   )Z
grad_inputÚ_rJ   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 ]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)rV   Úname)r   Ú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.)Ú	enumerater   ÚtorchZTensorrN   Úrequires_gradZis_grad_enabledÚnnÚmodulesZ
_functionsZBackwardHookFunctionÚapplyr'   rQ   r   rF   r   )r   ÚfnÚargsZtensors_idxZtensorsr]   ÚiÚargZnew_tensorsZgrad_fnsÚarg_listrK   rL   r   r   r   Ú_apply_on_tensors™   s*    


zBackwardHook._apply_on_tensorsc                    s0   ‡ fdd„}ˆ   ||¡\}}t|ƒˆ _|ˆ _|S )Nc                    s   ˆ   | ¡ d S r   )rW   )rV   r"   r   r   ra   »   s    z)BackwardHook.setup_input_hook.<locals>.fn)rf   r'   rD   rE   )r   rb   ra   rJ   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rrtˆ jƒ}ˆ jD ]F}|ˆ jˆ jƒ}|d krFq*t|ƒ}||krjtd|› d|› �ƒ‚|ˆ _q*ˆ jd krÚˆ   g g ˆ j	¡}ˆ j
D ]@}|ˆ j|ˆ jƒ}|d k	r’t|tƒrÊtdd„ |D ƒƒs’tdƒ‚q’d ˆ _ˆ jd k	�rˆ jd k	sôt‚t‡ fdd„ˆ jD ƒƒS d S )NzABackward pre hook returned an invalid number of grad_output, got rP   c                 s   s   | ]}|d kV  qd S r   r   )r   Úelr   r   r   r   Ý   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.c                 3   s   | ]}ˆ j | V  qd S r   )rA   )r   rc   r"   r   r   r   ä   s     )rM   rC   rB   rA   r?   r'   r@   rQ   rE   rD   r>   r   r   ÚallÚAssertionError)	rR   Zgrad_outputÚexpected_lenZuser_pre_hookZhook_grad_outputsÚ
actual_lenZgrad_inputsZ	user_hookrJ   r"   r   r   r<   Å   s0    þ



$
z8BackwardHook.setup_output_hook.<locals>.fn.<locals>.hookrT   )rV   r<   r"   r   r   ra   Ä   s    !z*BackwardHook.setup_output_hook.<locals>.fnTFr   )r   r   rf   r'   rB   rC   )r   rb   ra   Úis_tuplerJ   Z
output_idxr   r"   r   Úsetup_output_hookÃ   s    $

zBackwardHook.setup_output_hookN)r/   r0   r1   r2   r    rM   rO   rW   rf   rg   rn   r   r   r   r   r   [   s   	!	)r\   Úcollectionsr   r   r8   Útypingr   r   Ú__all__r   r   r   r   r   r   r   r   Ú<module>   s   >

