U
    ©Ê¹jžn  ã                   @   s    d dl Z d dlZd dlmZmZ d dlmZ d dlmZm	Z	m
Z
mZmZmZ d dlZddlmZ ddgZG d	d
„ d
ƒZG dd„ deƒZdd„ ZG dd„ dƒZdS )é    N)ÚabcÚdefaultdict)ÚEnum)ÚAnyÚcastÚDictÚListÚOptionalÚTupleé   )Úamp_definitely_not_availableÚOptStateÚ
GradScalerc                   @   s2   e Zd ZdZejddœdd„Zejdœdd„ZdS )	Ú_MultiDeviceReplicatorz_
    Lazily serves copies of a tensor to requested devices.  Copies are cached per-device.
    N)Úmaster_tensorÚreturnc                 C   s&   |j s|jjdkst‚|| _i | _d S )NÚxla)Úis_cudaÚdeviceÚtypeÚAssertionErrorÚmasterÚ_per_device_tensors)Úselfr   © r   úY/var/www/html/bwave/python/venv/lib/python3.8/site-packages/torch/cuda/amp/grad_scaler.pyÚ__init__   s    z_MultiDeviceReplicator.__init__©r   c                 C   s6   | j  |d ¡}|d kr2| jj|ddd�}|| j |< |S )NT)r   Únon_blockingÚcopy)r   Úgetr   Úto)r   r   Úretvalr   r   r   r       s
    
z_MultiDeviceReplicator.get)Ú__name__Ú
__module__Ú__qualname__Ú__doc__ÚtorchÚTensorr   r    r   r   r   r   r      s   r   c                   @   s   e Zd ZdZdZdZdS )r   r   r   é   N)r#   r$   r%   ÚREADYÚUNSCALEDÚSTEPPEDr   r   r   r   r   %   s   c                   C   s   t ji dœS )N)ÚstageÚfound_inf_per_device)r   r*   r   r   r   r   Ú_refresh_per_optimizer_state+   s    r/   c                   @   s   e Zd ZU eej ed< eej ed< eeee	e
f f ed< d=d	d
„Zeejejf dœdd„Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zd>dd„Zdd„ Zdd „ Zd!d"„ Zd#d$„ Zd%d&„ Zd'd(„ Zd)d*„ Zd+d,„ Zd-d.„ Zd/d0„ Zd1d2„ Zd3d4„ Z d5d6„ Z!d7d8„ Z"d9d:„ Z#d;d<„ Z$dS )?r   Ú_scaleZ_grows_trackerÚ_per_optimizer_statesç      ð@ç       @ç      à?éÐ  Tc                 C   s€   |rt ƒ rt d¡ d| _n|| _| jr||dks8tdƒ‚|dk sHtdƒ‚|| _d | _|| _|| _|| _	d| _
d | _ttƒ| _d S )NzLtorch.cuda.amp.GradScaler is enabled, but CUDA is not available.  Disabling.Fç      ð?z The growth factor must be > 1.0.z!The backoff factor must be < 1.0.r   )r   ÚwarningsÚwarnÚ_enabledr   Ú_init_scaler0   Ú_growth_factorÚ_backoff_factorÚ_growth_intervalÚ_init_growth_trackerÚ_growth_trackerr   r/   r1   )r   Z
init_scaleÚgrowth_factorÚbackoff_factorÚgrowth_intervalZenabledr   r   r   r   t   s"    
ÿzGradScaler.__init__r   c                 C   sL   d}| j d k	s"td|› d�| ƒ‚| jd k	s@td|› d�| ƒ‚| j | jfS )NzaThis may indicate your script did not use scaler.scale(loss or outputs) earlier in the iteration.z
Attempted z but _scale is None.  z but _growth_tracker is None.  )r0   r   r?   )r   ÚfuncnameZfixr   r   r   Ú_check_scale_growth_tracker“   s    ÿÿz&GradScaler._check_scale_growth_trackerc                 C   sF   | j d kstdƒ‚tjd| jtj|d�| _tjd| jtj|d�| _ d S )Nz)_growth_tracker initialized before _scaler   ©Údtyper   )	r?   r   r'   Úfullr:   Úfloat32r0   r>   Zint32)r   Údevr   r   r   Ú_lazy_init_scale_growth_trackerŸ   s       ÿz*GradScaler._lazy_init_scale_growth_trackerc                    s‚   ˆj s
|S t|tjƒrf|js,|jjdks,t‚ˆjdkrBˆ 	|j¡ ˆjdk	sPt‚|ˆjj
|jdd� S g ‰‡ ‡‡fdd„‰ ˆ |ƒS )a2  
        Multiplies ('scales') a tensor or list of tensors by the scale factor.

        Returns scaled outputs.  If this instance of :class:`GradScaler` is not enabled, outputs are returned
        unmodified.

        Args:
            outputs (Tensor or iterable of Tensors):  Outputs to scale.
        r   NT©r   r   c                    s¸   t | tjƒrv| js"| jjdks"t‚tˆƒdkrbˆjd krDˆ 	| j¡ ˆjd k	sRt‚ˆ 
tˆjƒ¡ | ˆd  | j¡ S t | tjƒr¬tˆ | ƒ}t | ttfƒr¦t| ƒ|ƒS |S ntdƒ‚d S )Nr   r   z2outputs must be a Tensor or an iterable of Tensors)Ú
isinstancer'   r(   r   r   r   r   Úlenr0   rJ   Úappendr   r    r   ÚIterableÚmapÚlistÚtupleÚ
ValueError)ÚvalÚiterable©Úapply_scaler   Ústashr   r   rW   À   s    

z%GradScaler.scale.<locals>.apply_scale)r9   rL   r'   r(   r   r   r   r   r0   rJ   r!   )r   Úoutputsr   rV   r   Úscale¦   s    

þzGradScaler.scalec              
   C   sú   t |ƒ}t |ƒ}tdd„ ƒ}t ¡ �Ê |jD ]‚}|d D ]t}	|	jd krHq8|sb|	jjtjkrbtdƒ‚|	jj	r�|	jjtjkr„|	j 
¡ |	_|	j ¡ }
n|	j}
||
j |
j  |
¡ q8q,| ¡ D ]0\}}| ¡ D ]}t || |¡| |¡¡ qÈq¸W 5 Q R X |jS )Nc                   S   s   t tƒS ©N)r   rQ   r   r   r   r   Ú<lambda>Þ   ó    z,GradScaler._unscale_grads_.<locals>.<lambda>Úparamsz%Attempting to unscale FP16 gradients.)r   r   r'   Zno_gradZparam_groupsZgradrF   Zfloat16rS   Z	is_sparseZcoalesceZ_valuesr   rN   ÚitemsÚvaluesZ*_amp_foreach_non_finite_check_and_unscale_r    r   )r   Ú	optimizerÚ	inv_scaleÚ	found_infZ
allow_fp16Zper_device_inv_scaleZper_device_found_infZper_device_and_dtype_gradsÚgroupÚparamZ
to_unscaler   Zper_dtype_gradsZgradsr   r   r   Ú_unscale_grads_Ô   s8    


ÿþýzGradScaler._unscale_grads_c                 C   sª   | j s
dS |  d¡ | jt|ƒ }|d tjkr:tdƒ‚n|d tjkrPtdƒ‚| jdk	s^t	‚| j 
¡  ¡  ¡ }tjddtj| jjd�}|  |||d	¡|d
< tj|d< dS )as  
        Divides ("unscales") the optimizer's gradient tensors by the scale factor.

        :meth:`unscale_` is optional, serving cases where you need to
        :ref:`modify or inspect gradients<working-with-unscaled-gradients>`
        between the backward pass(es) and :meth:`step`.
        If :meth:`unscale_` is not called explicitly,  gradients will be unscaled  automatically during :meth:`step`.

        Simple example, using :meth:`unscale_` to enable clipping of unscaled gradients::

            ...
            scaler.scale(loss).backward()
            scaler.unscale_(optimizer)
            torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm)
            scaler.step(optimizer)
            scaler.update()

        Args:
            optimizer (torch.optim.Optimizer):  Optimizer that owns the gradients to be unscaled.

        .. note::
            :meth:`unscale_` does not incur a CPU-GPU sync.

        .. warning::
            :meth:`unscale_` should only be called once per optimizer per :meth:`step` call,
            and only after all gradients for that optimizer's assigned parameters have been accumulated.
            Calling :meth:`unscale_` twice for a given optimizer between each :meth:`step` triggers a RuntimeError.

        .. warning::
            :meth:`unscale_` may unscale sparse gradients out of place, replacing the ``.grad`` attribute.
        NÚunscale_r-   zMunscale_() has already been called on this optimizer since the last update().z(unscale_() is being called after step().r   ç        rE   Fr.   )r9   rD   r1   Úidr   r+   ÚRuntimeErrorr,   r0   r   ÚdoubleZ
reciprocalÚfloatr'   rG   rH   r   rf   )r   ra   Úoptimizer_staterb   rc   r   r   r   rg      s(     
ÿ   ÿzGradScaler.unscale_c                 O   s.   d }t dd„ |d  ¡ D ƒƒs*|j||Ž}|S )Nc                 s   s   | ]}|  ¡ V  qd S r[   )Úitem)Ú.0Úvr   r   r   Ú	<genexpr>:  s     z-GradScaler._maybe_opt_step.<locals>.<genexpr>r.   )Úsumr`   Ústep)r   ra   rm   ÚargsÚkwargsr"   r   r   r   Ú_maybe_opt_step8  s    zGradScaler._maybe_opt_stepc           	         s€  | j s|j||ŽS d|kr"tdƒ‚|  d¡ | jt|ƒ }|d tjkrPtdƒ‚d}t|dƒ�r*|j	�r*|}dt
 |j¡jk}|ržt d	t¡ | d| i¡ nd|d tjkr¶|  |¡ |  ¡ ‰ ttjt‡ fd
d„|d  ¡ D ƒƒƒ}|d tjkrödnˆ |_||_|j||Ž}tj|d< |�s&|`|`|S |d tjk�rD|  |¡ t|d ƒdk�s^tdƒ‚| j||f|ž|Ž}tj|d< |S )aƒ  
        :meth:`step` carries out the following two operations:

        1.  Internally invokes ``unscale_(optimizer)`` (unless :meth:`unscale_` was explicitly called for ``optimizer``
            earlier in the iteration).  As part of the :meth:`unscale_`, gradients are checked for infs/NaNs.
        2.  If no inf/NaN gradients are found, invokes ``optimizer.step()`` using the unscaled
            gradients.  Otherwise, ``optimizer.step()`` is skipped to avoid corrupting the params.

        ``*args`` and ``**kwargs`` are forwarded to ``optimizer.step()``.

        Returns the return value of ``optimizer.step(*args, **kwargs)``.

        Args:
            optimizer (torch.optim.Optimizer):  Optimizer that applies the gradients.
            args:  Any arguments.
            kwargs:  Any keyword arguments.

        .. warning::
            Closure use is not currently supported.
        Úclosurez@Closure use is not currently supported if GradScaler is enabled.rs   r-   z7step() has already been called since the last update().NÚ_step_supports_amp_scalingZgrad_scalerzïGradScaler is going to stop passing itself as a keyword argument to the passed optimizer. In the near future GradScaler registers `grad_scale: Tensor` and `found_inf: Tensor` to the passed optimizer and let the optimizer use them directly.c                    s   g | ]}|j ˆ jd d�‘qS )T)r   )r!   r   )ro   Út©Zscalerr   r   Ú
<listcomp>ˆ  s   ÿz#GradScaler.step.<locals>.<listcomp>r.   r   z/No inf checks were recorded for this optimizer.) r9   rs   rj   rD   r1   ri   r   r,   Úhasattrrx   ÚinspectÚ	signatureÚ
parametersr7   r8   ÚFutureWarningÚupdater*   Ú_check_inf_per_deviceÚ_get_scale_asyncr   r'   r(   rr   r`   r+   Z
grad_scalerc   rg   rM   r   rv   )	r   ra   rt   ru   rm   r"   Zkwargs_Zhas_grad_scaler_kwargrc   r   rz   r   rs   >  sn    ÿ
ÿÿþÿü


þÿþ
ÿ

ÿþ
zGradScaler.stepNc                    s  | j s
dS |  d¡\‰ }|dk	r†t|tƒr8| j |¡ nLd}t|tjjƒsRt	|ƒ‚| 
¡ dksft	|ƒ‚|jdksxt	|ƒ‚| j |¡ nz‡ fdd„| j ¡ D ƒ}t|ƒdks²t	d	ƒ‚|d }t|ƒdkrætdt|ƒƒD ]}||| 7 }qÔt ˆ ||| j| j| j¡ ttƒ| _dS )
aS  
        Updates the scale factor.

        If any optimizer steps were skipped the scale is multiplied by ``backoff_factor``
        to reduce it. If ``growth_interval`` unskipped iterations occurred consecutively,
        the scale is multiplied by ``growth_factor`` to increase it.

        Passing ``new_scale`` sets the new scale value manually. (``new_scale`` is not
        used directly, it's used to fill GradScaler's internal scale tensor. So if
        ``new_scale`` was a tensor, later in-place changes to that tensor will not further
        affect the scale GradScaler uses internally.)

        Args:
            new_scale (float or :class:`torch.cuda.FloatTensor`, optional, default=None):  New scale factor.

        .. warning::
            :meth:`update` should only be called at the end of the iteration, after ``scaler.step(optimizer)`` has
            been invoked for all optimizers used this iteration.

        .. warning::
            For performance reasons, we do not check the scale factor value to avoid synchronizations,
            so the scale factor is not guaranteed to be above 1. If the scale falls below 1 and/or
            you are seeing NaNs in your gradients or loss, something is likely wrong. For example,
            bf16-pretrained models are often incompatible with AMP/fp16 due to differing dynamic ranges.
        Nr�   z[new_scale should be a float or a 1-element torch.cuda.FloatTensor with requires_grad=False.r   Fc                    s.   g | ]&}|d    ¡ D ]}|jˆ jdd�‘qqS )r.   TrK   )r`   r!   r   )ro   Ústaterc   ©r0   r   r   r{   Ò  s    þz%GradScaler.update.<locals>.<listcomp>r   z,No inf checks were recorded prior to update.)r9   rD   rL   rl   r0   Úfill_r'   ÚcudaZFloatTensorr   ZnumelZrequires_gradZcopy_r1   r`   rM   ÚrangeZ_amp_update_scale_r;   r<   r=   r   r/   )r   Z	new_scaler?   ÚreasonZ
found_infsZfound_inf_combinedÚir   r…   r   r�   ¦  s8    

þú
zGradScaler.updatec                 C   s   | j S r[   r…   ©r   r   r   r   rƒ   ë  s    zGradScaler._get_scale_asyncc                 C   s*   | j r"| jdkr| jS |  ¡  ¡ S dS dS )z°
        Returns a Python float containing the current scale, or 1.0 if scaling is disabled.

        .. warning::
            :meth:`get_scale` incurs a CPU-GPU sync.
        Nr6   )r9   r0   r:   rƒ   rn   r‹   r   r   r   Ú	get_scaleî  s    ÿ
ýzGradScaler.get_scalec                 C   s   | j S )zL
        Returns a Python float containing the scale growth factor.
        ©r;   r‹   r   r   r   Úget_growth_factorþ  s    zGradScaler.get_growth_factorc                 C   s
   || _ dS )zd
        Args:
            new_scale (float):  Value to use as the new scale growth factor.
        Nr�   ©r   Z
new_factorr   r   r   Úset_growth_factor  s    zGradScaler.set_growth_factorc                 C   s   | j S )zM
        Returns a Python float containing the scale backoff factor.
        ©r<   r‹   r   r   r   Úget_backoff_factor  s    zGradScaler.get_backoff_factorc                 C   s
   || _ dS )ze
        Args:
            new_scale (float):  Value to use as the new scale backoff factor.
        Nr‘   r�   r   r   r   Úset_backoff_factor  s    zGradScaler.set_backoff_factorc                 C   s   | j S )zF
        Returns a Python int containing the growth interval.
        ©r=   r‹   r   r   r   Úget_growth_interval  s    zGradScaler.get_growth_intervalc                 C   s
   || _ dS )za
        Args:
            new_interval (int):  Value to use as the new growth interval.
        Nr”   )r   Znew_intervalr   r   r   Úset_growth_interval  s    zGradScaler.set_growth_intervalc                 C   s(   | j r | jd kr| jS | j ¡ S dS d S )Nr   )r9   r?   r>   rn   r‹   r   r   r   Ú_get_growth_tracker%  s    ÿýzGradScaler._get_growth_trackerc                 C   s   | j S )zM
        Returns a bool indicating whether this instance is enabled.
        )r9   r‹   r   r   r   Ú
is_enabled/  s    zGradScaler.is_enabledc                 C   s(   | j r$|  ¡ | j| j| j|  ¡ dœS i S )a   
        Returns the state of the scaler as a :class:`dict`.  It contains five entries:

        * ``"scale"`` - a Python float containing the current scale
        * ``"growth_factor"`` - a Python float containing the current growth factor
        * ``"backoff_factor"`` - a Python float containing the current backoff factor
        * ``"growth_interval"`` - a Python int containing the current growth interval
        * ``"_growth_tracker"`` - a Python int containing the number of recent consecutive unskipped steps.

        If this instance is not enabled, returns an empty dict.

        .. note::
           If you wish to checkpoint the scaler's state after a particular iteration, :meth:`state_dict`
           should be called after :meth:`update`.
        )rZ   r@   rA   rB   r?   )r9   rŒ   r;   r<   r=   r—   r‹   r   r   r   Ú
state_dict5  s    ùû÷zGradScaler.state_dictc                 C   sˆ   | j s
dS t|ƒdkrtdƒ‚|d | _| jdk	rB| j |d ¡ |d | _|d | _|d | _|d | _	| j
dk	r„| j
 |d ¡ dS )	zç
        Loads the scaler state.  If this instance is disabled, :meth:`load_state_dict` is a no-op.

        Args:
           state_dict(dict): scaler state.  Should be an object returned from a call to :meth:`state_dict`.
        Nr   zeThe source state dict is empty, possibly because it was saved from a disabled instance of GradScaler.rZ   r@   rA   rB   r?   )r9   rM   rj   r:   r0   r†   r;   r<   r=   r>   r?   )r   r™   r   r   r   Úload_state_dictQ  s    ÿ






zGradScaler.load_state_dictc                 C   sR   | j  ¡ }| jrNt| jƒdks&tdƒ‚|  ¡ |d< |  ¡ |d< d |d< d |d< |S )Nr   zpA GradScaler instance may only be pickled at the beginning of an iteration, or at the end after scaler.update().r:   r>   r0   r?   )Ú__dict__r   r9   rM   r1   r   rŒ   r—   ©r   r„   r   r   r   Ú__getstate__k  s    
ÿzGradScaler.__getstate__c                 C   s   | j  |¡ d S r[   )r›   r�   rœ   r   r   r   Ú__setstate__{  s    zGradScaler.__setstate__c                 C   sj   |   d¡\}}tjddtj|jd�}tjddtj|jd�}|  |||d¡| jt|ƒ d< | jt|ƒ d S )Nr‚   r   r6   rE   rh   Tr.   )rD   r'   rG   rH   r   rf   r1   ri   )r   ra   r0   Ú_Zdummy_inv_scalerc   r   r   r   r‚   ~  s    þÿz GradScaler._check_inf_per_devicec                 C   s   | j t|ƒ d S )Nr.   )r1   ri   )r   ra   r   r   r   Ú_found_inf_per_deviceŠ  s    z GradScaler._found_inf_per_device)r2   r3   r4   r5   T)N)%r#   r$   r%   r	   r'   r(   Ú__annotations__r   ÚintÚstrr   r   r
   rD   rJ   rZ   rf   rg   rv   rs   r�   rƒ   rŒ   rŽ   r�   r’   r“   r•   r–   r—   r˜   r™   rš   r�   rž   r‚   r    r   r   r   r   r   /   sD   
D     ú
!þ.,8h
E
)r}   r7   Úcollectionsr   r   Úenumr   Útypingr   r   r   r   r	   r
   r'   Úcommonr   Ú__all__r   r   r/   r   r   r   r   r   Ú<module>   s    