a
    7SicF                     @   s   d dl Z d dlZd dlmZmZmZmZmZmZ eedf ee j	df dddZ
ee ddddZeee ee j	 f d	d
dZdd	ddZG dd de jjZddedddZdd ZdddZdS )    N)AnyDictIterableListOptionalTuple.)inputsreturnc                 C   sf   t | trRg }| D ]6}t |tjs.|| q| }|j|_|| qt|S tdt| j	d S )Nz@Only tuple of tensors is supported. Got Unsupported input type: )

isinstancetupletorchTensorappenddetachrequires_gradRuntimeErrortype__name__)r   outinpx r   R/var/www/html/django/DPS/env/lib/python3.9/site-packages/torch/utils/checkpoint.pydetach_variable   s    


r   c                 C   s    t dd | D std d S )Nc                 s   s    | ]}t |tjr|jV  qd S N)r
   r   r   r   .0r   r   r   r   	<genexpr>       z*check_backward_validity.<locals>.<genexpr>zBNone of the inputs have requires_grad=True. Gradients will be None)anywarningswarn)r   r   r   r   check_backward_validity   s    r"   )r	   c               	   G   sh   t tdd | D }g }|D ]@}tj|  |tj  W d    q1 sT0    Y  q||fS )Nc                 s   s(   | ] }t |tjr|jr| V  qd S r   )r
   r   r   is_cuda
get_devicer   argr   r   r   r   &   s   z$get_device_states.<locals>.<genexpr>)listsetr   cudadevicer   get_rng_state)argsfwd_gpu_devicesfwd_gpu_statesr*   r   r   r   get_device_states#   s    0r/   c              	   C   sP   t | |D ]@\}}tj| tj| W d    q
1 s@0    Y  q
d S r   )zipr   r)   r*   set_rng_state)devicesstatesr*   stater   r   r   set_device_states1   s    r5   c                   @   s$   e Zd Zedd Zedd ZdS )CheckpointFunctionc                 G   s  t | || _|| _t t t d| _t t	 t d| _
|rzt | _d| _tjjrzd| _t| \| _| _g | _g | _g }t|D ]B\}}t|r|| | j| | jd  q| j| q| j|  t  || }W d    n1 s0    Y  |S )N)enableddtypecache_enabledFT)r"   run_functionpreserve_rng_stater   is_autocast_enabledget_autocast_gpu_dtypeis_autocast_cache_enabledgpu_autocast_kwargsis_autocast_cpu_enabledget_autocast_cpu_dtypecpu_autocast_kwargsr+   fwd_cpu_statehad_cuda_in_fwdr)   _initializedr/   r-   r.   r   tensor_indices	enumerate	is_tensorr   save_for_backwardno_grad)ctxr:   r;   r,   tensor_inputsir&   outputsr   r   r   forward9   s<    




(zCheckpointFunction.forwardc                 G   s
  t j stdt| j}| j}| j}t|D ]\}}|| ||< q0g }| j	r\| j
r\| j}t jj|| j	d | j	rt | j | j
rt| j| j tt|}t   t jjjf i | jP t jjjf i | j | j| }	W d    n1 s0    Y  W d    n1 s0    Y  W d    n1 s:0    Y  W d    n1 sZ0    Y  t|	t jrx|	f}	g }
g }tt|	D ]>}t  |	| r|	| j!r|
"|	|  |"||  qt|
dkrtdt j#|
| tdd |D }d| S )NzCheckpointing is not compatible with .grad() or when an `inputs` parameter is passed to .backward(). Please use .backward() and do not pass its `inputs` argument.r2   r7   r   zInone of output has requires_grad=True, this checkpoint() is not necessaryc                 s   s$   | ]}t |tjr|jnd V  qd S r   )r
   r   r   gradr   r   r   r   r      s   z.CheckpointFunction.backward.<locals>.<genexpr>)NN)$r   autograd_is_checkpoint_validr   r'   r   rF   saved_tensorsrG   r;   rD   r-   randomfork_rngr1   rC   r5   r.   r   r   enable_gradr)   ampautocastr?   cpurB   r:   r
   r   rangelenrH   r   r   backward)rK   r,   r   rF   tensorsrM   idxrng_devicesZdetached_inputsrN   Zoutputs_with_gradZargs_with_gradgradsr   r   r   r]   c   sR    


zCheckpointFunction.backwardN)r   
__module____qualname__staticmethodrO   r]   r   r   r   r   r6   7   s   
)r6   T)use_reentrantc                O   sZ   | dd}|r,tdddd |D  |rDtj| |g|R  S t| |g|R  S dS )a  Checkpoint a model or part of the model

    Checkpointing works by trading compute for memory. Rather than storing all
    intermediate activations of the entire computation graph for computing
    backward, the checkpointed part does **not** save intermediate activations,
    and instead recomputes them in backward pass. It can be applied on any part
    of a model.

    Specifically, in the forward pass, :attr:`function` will run in
    :func:`torch.no_grad` manner, i.e., not storing the intermediate
    activations. Instead, the forward pass saves the inputs tuple and the
    :attr:`function` parameter. In the backwards pass, the saved inputs and
    :attr:`function` is retrieved, and the forward pass is computed on
    :attr:`function` again, now tracking the intermediate activations, and then
    the gradients are calculated using these activation values.

    The output of :attr:`function` can contain non-Tensor values and gradient
    recording is only performed for the Tensor values. Note that if the output
    consists of nested structures (ex: custom objects, lists, dicts etc.)
    consisting of Tensors, these Tensors nested in custom structures will not
    be considered as part of autograd.


    .. warning::
        If :attr:`function` invocation during backward does anything different
        than the one during forward, e.g., due to some global variable, the
        checkpointed version won't be equivalent, and unfortunately it can't be
        detected.

    .. warning::
        If ``use_reentrant=True`` is specified, then if the checkpointed segment
        contains tensors detached from the computational graph by `detach()` or
        `torch.no_grad()`, the backward pass will raise an error. This is
        because `checkpoint` makes all the outputs require gradients which
        causes issues when a tensor is defined to have no gradient in the model.
        To circumvent this, detach the tensors outside of the `checkpoint`
        function. Note that the checkpointed segment can contain tensors
        detached from the computational graph if ``use_reentrant=False`` is
        specified.

    .. warning::
        If ``use_reentrant=True`` is specified, at least one of the inputs needs
        to have :code:`requires_grad=True` if grads are needed for model inputs,
        otherwise the checkpointed part of the model won't have gradients. At
        least one of the outputs needs to have :code:`requires_grad=True` as
        well. Note that this does not apply if ``use_reentrant=False`` is
        specified.

    .. warning::
        If ``use_reentrant=True`` is specified, checkpointing currently only
        supports :func:`torch.autograd.backward` and only if its `inputs`
        argument is not passed. :func:`torch.autograd.grad`
        is not supported. If ``use_reentrant=False`` is specified, checkpointing
        will work with :func:`torch.autograd.grad`.

    Args:
        function: describes what to run in the forward pass of the model or
            part of the model. It should also know how to handle the inputs
            passed as the tuple. For example, in LSTM, if user passes
            ``(activation, hidden)``, :attr:`function` should correctly use the
            first input as ``activation`` and the second input as ``hidden``
        preserve_rng_state(bool, optional, default=True):  Omit stashing and restoring
            the RNG state during each checkpoint.
        use_reentrant(bool, optional, default=True): Use checkpointing
            implementation that requires re-entrant autograd.
            If ``use_reentrant=False`` is specified, ``checkpoint`` will use an
            implementation that does not require re-entrant autograd. This
            allows ``checkpoint`` to support additional functionality, such as
            working as expected with ``torch.autograd.grad``. Note that future
            versions of PyTorch will default to ``use_reentrant=False``.
        args: tuple containing inputs to the :attr:`function`

    Returns:
        Output of running :attr:`function` on :attr:`*args`
    r;   TUnexpected keyword arguments: ,c                 s   s   | ]
}|V  qd S r   r   r%   r   r   r   r      r   zcheckpoint.<locals>.<genexpr>N)pop
ValueErrorjoinr6   apply_checkpoint_without_reentrant)functionre   r,   kwargspreserver   r   r   
checkpoint   s    Mrp   c           	      K   s   | dd}|r,tdddd |D  dd }t| tjjrNt|  } t	| | }d	}t
d
||d  |D ]&}|| d }t|||| ||d}qr||d t	| d | |S )a  A helper function for checkpointing sequential models.

    Sequential models execute a list of modules/functions in order
    (sequentially). Therefore, we can divide such a model in various segments
    and checkpoint each segment. All segments except the last will run in
    :func:`torch.no_grad` manner, i.e., not storing the intermediate
    activations. The inputs of each checkpointed segment will be saved for
    re-running the segment in the backward pass.

    See :func:`~torch.utils.checkpoint.checkpoint` on how checkpointing works.

    .. warning::
        Checkpointing currently only supports :func:`torch.autograd.backward`
        and only if its `inputs` argument is not passed. :func:`torch.autograd.grad`
        is not supported.

    .. warning:
        At least one of the inputs needs to have :code:`requires_grad=True` if
        grads are needed for model inputs, otherwise the checkpointed part of the
        model won't have gradients.

    .. warning:
        Since PyTorch 1.4, it allows only one Tensor as the input and
        intermediate outputs, just like :class:`torch.nn.Sequential`.

    Args:
        functions: A :class:`torch.nn.Sequential` or the list of modules or
            functions (comprising the model) to run sequentially.
        segments: Number of chunks to create in the model
        input: A Tensor that is input to :attr:`functions`
        preserve_rng_state(bool, optional, default=True):  Omit stashing and restoring
            the RNG state during each checkpoint.

    Returns:
        Output of running :attr:`functions` sequentially on :attr:`*inputs`

    Example:
        >>> model = nn.Sequential(...)
        >>> input_var = checkpoint_sequential(model, chunks, input_var)
    r;   Trf   rg   c                 s   s   | ]
}|V  qd S r   r   r%   r   r   r   r      r   z(checkpoint_sequential.<locals>.<genexpr>c                    s    fdd}|S )Nc                    s$   t  d D ]}| | } q| S N   )r[   )inputjend	functionsstartr   r   rO   #  s    z<checkpoint_sequential.<locals>.run_function.<locals>.forwardr   )rx   rv   rw   rO   r   ru   r   r:   "  s    z+checkpoint_sequential.<locals>.run_functionr   rr   )r;   )rh   ri   rj   r
   r   nn
Sequentialr'   childrenr\   r[   rp   )	rw   segmentsrs   rn   ro   r:   Zsegment_sizerv   rx   r   r   r   checkpoint_sequential   s    *r~   c              	      s   t  r0t  dt jjr0dt  \i 	dfdd} 	f	dd}t jj||0   }t jjrrst	dW d	   n1 s0    Y  |S )
a}  Checkpointining without re-entrant autograd
    Args:
        function: describes what to run in the forward pass of the model or
            part of the model. It should also know how to handle the inputs
            passed as the tuple. For example, in LSTM, if user passes
            ``(activation, hidden)``, :attr:`function` should correctly use the
            first input as ``activation`` and the second input as ``hidden``
        preserve_rng_state(bool, optional, default=True):  Omit stashing and restoring
            the RNG state during each checkpoint.
        *args: Arguments to pass in to the given ``function``.
    FTr   c                    s    d7   d S rq   r   )r   )counterr   r   packR  s    z+_checkpoint_without_reentrant.<locals>.packc                    s0  d t 	dkr	 fdd}dd }g }r8r8}tjj|d rft rft t v tjj	H tj
j||  }W d    n1 s0    Y  W d    n1 s0    Y  W d    n1 s0    Y  W d    n1 s
0    Y  | 	vr&td	| S )Nr   c                    s   |  < d7 d S rq   r   )inner)storageunpack_counterr   r   
inner_pack]  s    zA_checkpoint_without_reentrant.<locals>.unpack.<locals>.inner_packc                 S   s   t dd S )NzRYou are calling backwards on a tensor that is never exposed. Please open an issue.)r   )packedr   r   r   inner_unpackc  s    zC_checkpoint_without_reentrant.<locals>.unpack.<locals>.inner_unpackrP   zAttempt to retrieve a tensor saved by autograd multiple times without checkpoint recomputation being triggered in between, this is not currently supported. Please open an issue with details on your use case so that we can prioritize adding this.)r\   r   rU   rV   r1   r5   rW   r)   rX   rY   rR   graphsaved_tensors_hooksr   rh   )r   r   r   r`   Z_unused)	r,   rm   rC   r-   r.   had_autocast_in_fwdrD   r;   r   )r   r   unpackY  s(    


z-_checkpoint_without_reentrant.<locals>.unpackzPyTorch's CUDA state was initialized in the forward pass of a Checkpoint, which is not allowed. Please open an issue if you need this feature.N)
r   r<   r+   r)   rE   r/   rR   r   r   r   )rm   r;   r,   r   r   outputr   )
r,   r   rm   rC   r-   r.   r   rD   r;   r   r   rl   5  s$    %"rl   )T)r   r    typingr   r   r   r   r   r   r   r   r"   intr/   r5   rR   Functionr6   boolrp   r~   rl   r   r   r   r   <module>   s    " b[A