U
    ©Ê¹j5-  ã                   @   sà  d Z ddlmZ ddlmZ ddlZddlmZ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 ddlZddlmZmZ dd	lmZ dd
lmZ dddddddddddddgZee Zeeef Zeeef Zeeee f ZG dd„ deƒZedœdd„Z G dd„ dƒZ!G dd„ dej"ƒZ#e#ƒ Z$ee	d dœdd„ƒZ%ee	d dœd d„ƒZ&e'dœd!d„Z(e'dœd"d„Z)G d#d„ dƒZ*ej+ee dd$œd%d„Z,eej+ee e	d d$œd&d„ƒZ-G d'd„ dej.jƒZ/G d(d„ dej.jƒZ0dS ))a·  Checkpointing with preceding recomputation.

PyTorch already provides the official checkpointing utilities in
:mod:`torch.utils.checkpoint`. The official checkpointing combines
recomputation and recursive backpropagation into one autograd function named
``CheckpointFunction``. Hence, the recomputation can be started only when the
gradients arrive to the function. In Pipe, the recomputation needs to precede
the gradient arrival to minimize the GPU idle time.

We solve this problem by introducing separate autograd functions named
:class:`Recompute` and :class:`Checkpoint`. Each function represents
recomputation and recursive backpropagation, respectively. We can manipulate
the control flow in aspect of both the autograd engine and CUDA with a pair of
the functions.

Specifically, we place CUDA stream synchronization between :class:`Recompute`
and :class:`Checkpoint` to delay only :class:`Checkpoint` until the gradient is
copied entirely.

é    )Údeque)ÚcontextmanagerN)	ÚAnyÚDequeÚ	GeneratorÚListÚOptionalÚProtocolÚUnionÚSequenceÚTuple)ÚTensoré   )ÚforkÚjoin)ÚBatch)Ú	get_phonyÚFunctionÚ
checkpointÚCheckpointingÚThreadLocalÚenable_checkpointingÚenable_recomputingÚis_checkpointingÚis_recomputingÚContextÚsave_rng_statesÚrestore_rng_statesÚ
CheckpointÚ	Recomputec                   @   s   e Zd Zeedœdd„ZdS )r   )ÚinputÚreturnc                 C   s   d S ©N© )Úselfr    r#   r#   úi/var/www/html/bwave/python/venv/lib/python3.8/site-packages/torch/distributed/pipeline/sync/checkpoint.pyÚ__call__B   s    zFunction.__call__N)Ú__name__Ú
__module__Ú__qualname__ÚTensorOrTensorsr&   r#   r#   r#   r%   r   A   s   )Úfunctionc                 C   s*   t |ƒ}t| |ƒ}| ¡ }| |¡ |jS )zÇMakes a checkpoint with a simple interface like
    :func:`torch.utils.checkpoint.checkpoint`. It's only used to test or debug
    :class:`Checkpoint` and :class:`Recompute` without boilerplate.
    )r   r   r   Ú	recomputeÚvalues)r+   r    ÚbatchZchkr#   r#   r%   r   F   s
    

c                   @   s@   e Zd ZdZeeddœdd„Zedœdd„Zedd	œd
d„ZdS )r   z?Generates a pair of :class:`Checkpoint` and :class:`Recompute`.N)r+   r.   r!   c                 C   s(   || _ || _tdd�| _tdd�| _d S )Nr   )Úmaxlen)r+   r.   r   Ú
recomputedÚ
rng_states)r$   r+   r.   r#   r#   r%   Ú__init__W   s    zCheckpointing.__init__©r!   c                 C   sf   | j j}t| j ƒ}t| j  ¡ dd�}tj|| j| j| j	|f|žŽ }t
|tƒr^tdd„ |D ƒƒ}t|ƒS )z/Returns a batch applied by :class:`Checkpoint`.T)Úrequires_gradc                 S   s*   g | ]"}t  |¡r"| ¡ s"| ¡ n|‘qS r#   )ÚtorchÚ	is_tensorZis_floating_pointÚdetach©Ú.0Úxr#   r#   r%   Ú
<listcomp>n   s     z,Checkpointing.checkpoint.<locals>.<listcomp>)r.   ÚatomicÚtupler   Z
get_devicer   Úapplyr0   r1   r+   Ú
isinstancer   )r$   Úinput_atomicÚinputsÚphonyÚoutputr#   r#   r%   r   `   s    

zCheckpointing.checkpoint)r.   r!   c                 C   sb   | j j}t| j ƒ}| ¡ }t|| ƒ\||< }tj|| j| j| j	|f|žŽ }t
|| |ƒ||< dS )z1Applies :class:`Recompute` to the batch in place.N)r.   r<   r=   Zfind_tensor_idxr   r   r>   r0   r1   r+   r   )r$   r.   r@   rA   Z
tensor_idxrB   r#   r#   r%   r,   r   s    
zCheckpointing.recompute)	r'   r(   r)   Ú__doc__r   r   r2   r   r,   r#   r#   r#   r%   r   T   s   	c                   @   s   e Zd Zddœdd„ZdS )r   Nr3   c                 C   s   d| _ d| _d S )NF)r   r   )r$   r#   r#   r%   r2   �   s    zThreadLocal.__init__)r'   r(   r)   r2   r#   r#   r#   r%   r   €   s   )NNNr3   c                  c   s$   t j} dt _z
dV  W 5 | t _X dS )zDMakes :func:`is_checkpointing` return :data:`True` within a context.TN©Úthread_localr   ©Úorigr#   r#   r%   r   ‰   s
    
c                  c   s$   t j} dt _z
dV  W 5 | t _X dS )zBMakes :func:`is_recomputing` return :data:`True` within a context.TN©rF   r   rG   r#   r#   r%   r   ”   s
    
c                   C   s   t jS )z‹Whether the current forward propagation is under checkpointing.

    Returns:
        bool: :data:`True` if it's under checkpointing.

    rE   r#   r#   r#   r%   r   Ÿ   s    c                   C   s   t jS )a9  Whether the current forward propagation is under checkpoint
    recomputation. Use this to prevent duplicated side-effects at forward
    propagation::

        class Counter(nn.Module):
            def __init__(self):
                super().__init__()
                self.counter = 0

            def forward(self, input):
                if not is_recomputing():
                    self.counter += 1
                return input

    Returns:
        bool: :data:`True` if it's under checkpoint recomputation.

    .. seealso:: :ref:`Detecting Recomputation`

    rI   r#   r#   r#   r%   r   ©   s    c                   @   sf   e Zd ZU dZee ed< ee ed< eed< e	ed< e
e ed< eedf ed< ed	d
œdd„Zd	S )r   z]The common interface between the :class:`Checkpoint` and
    :class:`Recompute` context.
    r0   r1   r+   r@   rA   .Zsaved_tensorsN)Útensorsr!   c                 G   s   d S r"   r#   )r$   rJ   r#   r#   r%   Úsave_for_backwardÎ   s    zContext.save_for_backward)r'   r(   r)   rD   r   Ú
RecomputedÚ__annotations__Ú	RNGStatesr   Úboolr   r   r   r   rK   r#   r#   r#   r%   r   Á   s   
)Údevicer1   r!   c                 C   s6   t  ¡ }| jdkr t j | ¡}nd}| ||f¡ dS )zË:meth:`Checkpoint.forward` captures the current PyTorch's random number
    generator states at CPU and GPU to reuse in :meth:`Recompute.backward`.

    .. seealso:: :ref:`Referential Transparency`

    ÚcudaN)r5   Zget_rng_stateÚtyperQ   Úappend)rP   r1   Úcpu_rng_stateÚgpu_rng_stater#   r#   r%   r   Ò   s
    
c              	   c   sf   |  ¡ \}}g }| jdkr$| | ¡ tj |¡�, t |¡ |dk	rRtj || ¡ dV  W 5 Q R X dS )zº:meth:`Recompute.backward` restores the random number generator states
    captured by :func:`save_rng_states` within its context.

    .. seealso:: :ref:`Referential Transparency`

    rQ   N)ÚpoprR   rS   r5   ÚrandomZfork_rngZset_rng_staterQ   )rP   r1   rT   rU   Zgpu_devicesr#   r#   r%   r   ä   s    


c                   @   sR   e Zd Zeeeee ee e	e
dœdd„ƒZeeeeee df dœdd„ƒZdS )	r   )ÚctxrB   r0   r1   r+   r@   c           
   
   G   s¶   || _ || _t|j| jƒ || _|| _|r6|d g}n"g }|D ]}t |¡r>| |¡ q>| j	|Ž  t 
¡ �B tƒ �0 |r–t|ƒdksˆt‚||d ƒ}	n||Ž }	W 5 Q R X W 5 Q R X |	S )Nr   r   )r0   r1   r   rP   r+   r@   r5   r6   rS   rK   Zno_gradr   ÚlenÚAssertionError)
rX   rB   r0   r1   r+   r@   rA   rJ   r    rC   r#   r#   r%   Úforwardú   s$    

zCheckpoint.forward.©rX   Úgrad_outputr!   c                 G   s€   | j  ¡ \}}t|tƒr|}n|f}tdd„ |D ƒƒrVtdd„ |D ƒƒ}tj ||¡ d d d d d g}| dd„ |D ƒ¡ t|ƒS )Nc                 s   s   | ]}t  |¡o|jV  qd S r"   ©r5   r6   r4   )r9   Úyr#   r#   r%   Ú	<genexpr>&  s     z&Checkpoint.backward.<locals>.<genexpr>c                 S   s    g | ]}t  |¡r|jr|‘qS r#   r^   r8   r#   r#   r%   r;   '  s     
  z'Checkpoint.backward.<locals>.<listcomp>c                 s   s"   | ]}t  |¡r|jnd V  qd S r"   )r5   r6   Zgradr8   r#   r#   r%   r`   +  s     )	r0   rV   r?   r=   Úanyr5   ÚautogradÚbackwardÚextend)rX   r]   rC   Z
input_leafÚoutputsrJ   Ú
grad_inputr#   r#   r%   rc     s    
zCheckpoint.backwardN)r'   r(   r)   Ústaticmethodr   r   r   rL   rN   r   rO   r[   r   r   rc   r#   r#   r#   r%   r   ù   s   ú"c                	   @   sL   e Zd Zeeeee ee e	e
edœdd„ƒZeeeed dœdd„ƒZdS )	r   )rX   rB   r0   r1   r+   r@   r!   c           	      G   s^   || _ || _|| _|| _|| _|r.|d g}n"g }|D ]}t |¡r6| |¡ q6| j|Ž  |S )Nr   )	r0   r1   r+   r@   rA   r5   r6   rS   rK   )	rX   rB   r0   r1   r+   r@   rA   rJ   r    r#   r#   r%   r[   0  s    

zRecompute.forward)N.r\   c                 G   sú   | j }tdd„ |D ƒƒ}d }|D ]}t |¡r |j} q:q |d krPtd|› �ƒ‚t|| jƒ�\ t ¡ �H t	ƒ �6 | j
r–t|ƒdks†t‚|  |d ¡}n
| j|Ž }W 5 Q R X W 5 Q R X W 5 Q R X | j ||f¡ d d d d d g}| dd„ | j D ƒ¡ t|ƒS )Nc                 s   s,   | ]$}t  |¡r | ¡  |j¡n|V  qd S r"   )r5   r6   r7   Zrequires_grad_r4   r8   r#   r#   r%   r`   O  s     z%Recompute.backward.<locals>.<genexpr>zNo tensors found in r   r   c                 s   s   | ]
}d V  qd S r"   r#   )r9   Ú_r#   r#   r%   r`   f  s     )rA   r=   r5   r6   rP   ÚRuntimeErrorr   r1   Zenable_gradr   r@   rY   rZ   r+   r0   rS   rd   )rX   r]   rA   Zinputs_leafrP   r    rC   rf   r#   r#   r%   rc   L  s&    
(zRecompute.backwardN)r'   r(   r)   rg   r   r   r   rL   rN   r   rO   r[   r   rc   r#   r#   r#   r%   r   /  s   ø)1rD   Úcollectionsr   Ú
contextlibr   Ú	threadingÚtypingr   r   r   r   r   r	   r
   r   r   r5   r   Ztorch.autogradÚ
dependencyr   r   Z
microbatchr   rB   r   Ú__all__ZTensorsr*   rL   rN   r   r   r   Úlocalr   rF   r   r   rO   r   r   r   rP   r   r   rb   r   r   r#   r#   r#   r%   Ú<module>   sR   ,
      þ,


6