
    yj                    J   d dl mZ d dlZd dlmZ d dlmZ d dlmZm	Z	m
Z
 d dlZd dlZd dlmZmZ d dlmZmZ d dlmZ d d	lmZmZmZ d d
lmZ ddlmZ er d dlmZ d dlmZ d dl m!Z!  G d de
          Z" G d de          Z#d Z$ G d d          Z% G d de%          Z&dS )    )annotationsN)defaultdict)Enum)TYPE_CHECKINGAny	TypedDict)_C_ops_legacy_C_ops)coreunique_name)
check_type)Operator_dygraph_tracerin_pir_mode)in_dynamic_mode   )amp_global_state)Tensor)OptimizerWithMixedPrecision)	Optimizerc                  `    e Zd ZU ded<   ded<   ded<   ded<   ded<   ded	<   ded
<   ded<   dS )_ScaleStateDictr   scalefloat
incr_ratio
decr_ratiointincr_every_n_stepsdecr_every_n_nan_or_inf
incr_count
decr_countbooluse_dynamic_loss_scalingN)__name__
__module____qualname____annotations__     f/lsinfo/ai/hellotax_ai/data_center/backend/venv/lib/python3.11/site-packages/paddle/amp/grad_scaler.pyr   r   )   si         $$$$&&&&&&r)   r   c                      e Zd ZdZdZdZdS )OptimizerStater   r      N)r$   r%   r&   INITUNSCALEDSTEPPEDr(   r)   r*   r,   r,   4   s        DHGGGr)   r,   c                     dt           j        iS )Nstate)r,   r.   r(   r)   r*   _refresh_optimizer_stater3   :   s    ^())r)   c                      e Zd ZdZ	 	 	 	 	 	 	 d7d8dZd9dZd:d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?d+Zd@d,ZdAd.Zd@d/ZdBd1ZdCd3ZdDd5Zd6S )E	AmpScalera	  
    AmpScaler is used for Auto-Mixed-Precision training/inferring in imperative
    mode. It controls the scaling of loss, helps avoiding numerical overflow.
    The object of this class has seventeen methods `scale()`, `unscale_()`, `minimize()` and `get`/`set` api of parameters.

    `scale()` is used to multiply the loss by a scale ratio.
    `unscale_()` is used to unscale the gradients of parameters, multiplies the gradients of parameters by 1/(scale ratio)
    `minimize()` is similar as `optimizer.minimize()`, performs parameters updating, and it will update the loss_scaling.

    Commonly, it is used together with `amp_guard` to achieve Auto-Mixed-Precision in
    imperative mode.

    Args:
        enable(bool, optional): Enable loss scaling or not. Default is True.
        init_loss_scaling (float, optional): The initial loss scaling factor. Default is 2**15.
        incr_ratio(float, optional): The multiplier to use when increasing the loss
                        scaling. Default is 2.0.
        decr_ratio(float, optional): The less-than-one-multiplier to use when decreasing
                        the loss scaling. Default is 0.5.
        incr_every_n_steps(int, optional): Increases loss scaling every n consecutive
                                steps with finite gradients. Default is 1000.
        decr_every_n_nan_or_inf(int, optional): Decreases loss scaling every n
                                    accumulated steps with nan or inf gradients. Default is 2.
        use_dynamic_loss_scaling(bool, optional): Whether to use dynamic loss scaling. If False, fixed loss_scaling is used. If True, the loss scaling is updated dynamically. Default is True.
    Returns:
        An AmpScaler object.

    Examples:

        .. code-block:: python

            >>> import numpy as np
            >>> import paddle

            >>> data = np.random.uniform(-1, 1, [10, 3, 32, 32]).astype('float32')
            >>> model = paddle.nn.Conv2D(3, 2, 3)
            >>> optimizer = paddle.optimizer.SGD(
            ...         learning_rate=0.01, parameters=model.parameters())
            >>> scaler = paddle.amp.AmpScaler(init_loss_scaling=1024)
            >>> data = paddle.to_tensor(data)
            >>> with paddle.amp.amp_guard():
            ...     conv = model(data)
            ...     loss = paddle.mean(conv)
            ...     scaled = scaler.scale(loss)
            ...     scaled.backward()
            ...     scaler.minimize(optimizer, scaled)
    T      @       @      ?  r   enabler"   init_loss_scalingr   r   r   r   r   r   r#   returnNonec                   t                      rt                      }|st          d          |rj|j                                        sQ|j                                        s8|j                                        st          j        d|j         d           d}|| _	        d| _
        d| _        d | _        | j	        r|dk    s
J d            |dk     s
J d            || _        || _        || _        || _        || _        d| _        d| _        || _
        t'                      rjt(          j        j                            d	d
gt1          j        d          t(          j        j                            | j                            | _        d S t)          j        t=          j        dg                               t<          j!                            | _"        t)          j        t=          j        dg                               t<          j!                            | _#        t)          j        t=          j        dg                               t<          j!                            | _$        t)          j        t=          j        dg                               t<          j!                            | _%        t)          j        t=          j        dg                               t<          j!                            | _&        t)          j        t=          j        | j        g                               t<          j'                            | _        d | _(        tS          tT                    | _+        d S d S )Nz;current_tracer is None, maybe it is not in imperative mode.zWAmpScaler can only be enabled on CUDAPlace, XPUPlace and CustomPlace, current place is z, so it makes no effect.F      ?zThe incr_ratio must be > 1.0.zThe decr_ratio must be < 1.0.r   float32r   loss_scaling)value)dtypeshapenameinitializer),r   r   
ValueError_expected_placeis_gpu_placeis_xpu_placeis_custom_placewarningswarn_enable_use_dynamic_loss_scaling_init_loss_scaling_scale_incr_ratio_decr_ratio_incr_every_n_steps_decr_every_n_nan_or_inf_incr_count_decr_countr   paddlepirr   create_persistable_valuer   generatennrF   ConstantInitializer	to_tensornparrayastypebool_
_found_inf_temp_found_inf_value_false_temp_found_inf_fp16_temp_found_inf_bf16_temp_found_inf_fp32r@   _cache_found_infr   r3   _optimizer_states)	selfr:   r;   r   r   r   r   r#   tracers	            r*   __init__zAmpScaler.__init__o   s=     	$&&F  Q    &3355)6688 )99;;
  _nt  oE  _  _  _   ).&"%< *	O###%D######%D###&7D#)D)D'9D$,CD) D D-ED*}} O$joFF##$-n== &	 5 I I"5 !J ! !	 G   #)"2HaSMM((22# # 4:3CHaSMM((224 40 -3,<HaSMM((22- -) -3,<HaSMM((22- -) -3,<HaSMM((22- -) %.Hd5677>>rzJJ  )-%)45M)N)N&&&U*	O *	Or)   varr   c                   t          |dt          j        t          j        j        fd           | j        r\t                      j        dk    rE| j        r>d| _        d| _        d| _	        t          j        dt                      j         d           t                      r|j        t          j        j        k    r|                    d          }| j        s|S t          j                            || j                  }|                                }|                                }|j        rz|j        rst          j        j        j                            |j        j        |j                                        |j                                        |j        j                  |_        |S | j        r|                                s|S || j        z  S )	al  
        Multiplies a Tensor by the scale factor and returns scaled outputs.
        If this instance of :class:`AmpScaler` is not enabled, output are returned unmodified.

        Args:
            var (Tensor):  The Tensor to scale.
        Returns:
            The scaled Tensor or original Tensor.

        Examples:

            .. code-block:: python

                >>> import numpy as np
                >>> import paddle

                >>> data = np.random.uniform(-1, 1, [10, 3, 32, 32]).astype('float32')
                >>> model = paddle.nn.Conv2D(3, 2, 3)
                >>> optimizer = paddle.optimizer.SGD(
                ...         learning_rate=0.01, parameters=model.parameters())
                >>> scaler = paddle.amp.AmpScaler(init_loss_scaling=1024)
                >>> data = paddle.to_tensor(data)
                >>> with paddle.amp.amp_guard():
                ...     conv = model(data)
                ...     loss = paddle.mean(conv)
                ...     scaled = scaler.scale(loss)
                ...     scaled.backward()
                ...     scaler.minimize(optimizer, scaled)
        rm   zAmpScaler.scale()float16Fr?   z6It is not recommended to use dynamic loss scaling for z&, so GradScaler is disable by default.r@   )r   rX   r   rY   ValuerN   r   	amp_dtyperO   rP   rL   rM   r   rC   r   DataTypeFLOAT32ra   r	   multiplyrQ   get_defining_op	dist_attrbase	libpaddlecreate_op_dist_attributeprocess_meshoperandsresultschunk_id_is_initialized)rj   rm   	scale_outmultiply_op
src_var_ops        r*   r   zAmpScaler.scale   s   < 	]FJ,-		
 	
 	
 L
	 "",	99. : !DL-2D*&)D#M NIYI[I[Ie  N  N  N   == 	yDM111jj++1 
..sDK@@I#3355K,,..J$ )= K)-FF#-:#-6688#-5577",5	  %  | 	3#6#6#8#8 	JT[  r)   	optimizer'Optimizer | OptimizerWithMixedPrecisionargsr   kwargs2tuple[list[Operator], list[tuple[Tensor, Tensor]]]c                   t                      rt          |t          j        j        j        j                  sJ | j        |_        | j        |_        | j	        |_
        |d         |_        | j        r>| j        |_        | j        |_        | j        |_        | j        |_        d|_        d|_         |j        |i |S | j        s |j        |i |S | j        t+          |                   }|d         t,          j        u r|                     |           d\  }}t3          |d          rF|                    d| j                    |j        |i |\  }}|                    d          | _        n&| j        rd| _        n |j        |i |\  }}d| _        | j        r|                                  t?          t@                    | _        ||fS )	a  
        This function is similar as `Optimizer.minimize()`, which performs parameters updating.

        If the scaled gradients of parameters contains NAN or INF, the parameters updating is skipped.
        Otherwise, if `unscale_()` has not been called, it first unscales the scaled gradients of parameters, then updates the parameters.

        Finally, the loss scaling ratio is updated.

        Args:
            optimizer(Optimizer):  The optimizer used to update parameters.
            args:  Arguments, which will be forward to `Optimizer.minimize()`.
            kwargs: Keyword arguments, which will be forward to `Optimizer.minimize()`.

        Examples:

            .. code-block:: python

                >>> import numpy as np
                >>> import paddle

                >>> data = np.random.uniform(-1, 1, [10, 3, 32, 32]).astype('float32')
                >>> model = paddle.nn.Conv2D(3, 2, 3)
                >>> optimizer = paddle.optimizer.SGD(
                ...     learning_rate=0.01,
                ...     parameters=model.parameters()
                ... )
                >>> scaler = paddle.amp.AmpScaler(init_loss_scaling=1024)
                >>> data = paddle.to_tensor(data)
                >>> with paddle.amp.amp_guard():
                ...     conv = model(data)
                ...     loss = paddle.mean(conv)
                ...     scaled = scaler.scale(loss)
                ...     scaled.backward()
                ...     scaler.minimize(optimizer, scaled)
        r   Nr2   )NN_set_auxiliary_var	found_infTF)!r   
isinstancerX   staticamp	decoratorr   rO   rP   rQ   _loss_scaling_scaled_lossrT   rU   rR   rS   _num_good_steps_num_bad_stepsminimizerN   ri   idr,   r.   _unscalehasattrr   rc   _get_auxiliary_varrh   _updater   r3   )rj   r   r   r   optimizer_stateoptimize_opsparams_gradss          r*   r   zAmpScaler.minimize  s   T == 	7!+G     372PI/+/+BI(&*kI#%)!WI"- 0040H	-1 2 )-(8	%(,(8	%,0	)+/	(%9%t6v666| 	7%9%t6v6660I? 7#~':::MM)$$$%1"l9233 
	.((doFFF););T)LV)L)L&L,$-$@$@$M$MD!! .(,%%-?Y-?-P-P-P*l(-%) 	LLNNN!,-E!F!F\))r)   c                   | j         sdS | j        t          |                   }|d         t          j        u rt          d          |d         t          j        u rt          d          t          |dd          rCt          |j	        d         t                    r"g }g }g }g }|j	        D ]}|d         D ]}|                                |                    |                                           |                                j        t          j        k    r(|                    |                                           |                                j        t          j        k    r(|                    |                                           |                    |                                           nlt#                      r)t$          j                            |j                  \  }}}n5d |j        D             }d	 |D             }d
 |D             }d |D             }| j        | _        t1          |          rEt3          j        || j        || j                   t;          j        | j        | j                  | _        t1          |          rEt3          j        || j        || j                   t;          j        | j        | j                  | _        t1          |          rEt3          j        || j        || j                    t;          j        | j        | j                   | _        t          j        |d<   dS )a  
        Unscale the gradients of parameters, multiplies the gradients of parameters by 1/(loss scaling ratio).
        If this instance of :class:`GradScaler` is not enabled, output are returned unmodified.
        Args:
            optimizer(Optimizer):  The optimizer used to update parameters.
        Returns:
            The unscaled parameters or original parameters.
        Nr2   zMunscale_() has already been called on this optimizer since the last update().z(unscale_() is being called after step()._param_groupsr   paramsc                ^    g | ]*}|                                 |                                 +S N)
_grad_ivar.0params     r*   
<listcomp>z&AmpScaler._unscale.<locals>.<listcomp>  s@       ''))5 $$&&555r)   c                <    g | ]}|j         t          j        k    |S r(   )rC   rX   ro   r   s     r*   r   z&AmpScaler._unscale.<locals>.<listcomp>  1     $ $ ${fn44 444r)   c                <    g | ]}|j         t          j        k    |S r(   )rC   rX   bfloat16r   s     r*   r   z&AmpScaler._unscale.<locals>.<listcomp>  s1     $ $ ${fo55 555r)   c                <    g | ]}|j         t          j        k    |S r(   )rC   rX   r@   r   s     r*   r   z&AmpScaler._unscale.<locals>.<listcomp>  r   r)   )!rN   ri   r   r,   r/   RuntimeErrorr0   getattrr   r   dictr   appendrC   rX   ro   r   r   r   eagerget_grads_lists_parameter_listrd   rc   lenr
   check_finite_and_unscalerQ   re   r	   
bitwise_orrf   rg   )	rj   r   r   param_gradsparam_grads_fp16param_grads_bf16param_grads_fp32groupr   s	            r*   r   zAmpScaler._unscaleb  s    | 	F0I?7#~'>>>_   W%)???IJJJ9ot44 0	#A&:
 :
 0	 K!!!"0 	H 	H"8_ H HE''))5#**5+;+;+=+=>>> ++--3v~EE,33E4D4D4F4FGGGG"--//5HH,33E4D4D4F4FGGGG,33E4D4D4F4FGGGH	H     J..y/HII	$$$$
 !*!:  
$ $!,$ $ $ 
$ $!,$ $ $ 
$ $!,$ $ $ 
 :   		2  )	   %/!: DO    		2  )	   %/!: DO    		2  )	   %/!: DO $2#:   r)   c           
        | j         sdS | j        rd| _        | j        dz   | _        | j        | j        k    rit          dt          | j                   dt          | j                   dt          | j                              | j        | j        z  | _        d| _        nAd| _        | j        dz   | _        | j        | j	        k    r| j        | j
        z  | _        d| _        dS )z+
        Updates the loss_scaling.
        Nr   r   z$Found inf or nan, current scale is: z, decrease to: *)rN   rh   rV   rW   rU   printr   rQ   rS   rT   rR   rj   s    r*   r   zAmpScaler._update  s    | 	F  	% D#/!3D4#@@@ M5;M;M  M  M^cdhdo^p^p  M  Msxy}  zJ  tK  tK  M  M   #kD,<<#$  D#/!3D4#;;;"kD,<<#$ r)   c                    | j         S )z
        Enable loss scaling or not.

        Returns:
            bool: enable loss scaling return True else return False.
        )rN   r   s    r*   	is_enablezAmpScaler.is_enable  s     |r)   c                    | j         S )z
        Whether to use dynamic loss scaling.

        Returns:
            bool: if fixed loss_scaling is used return False, if the loss scaling is updated dynamically return true.
        )rO   r   s    r*   is_use_dynamic_loss_scalingz%AmpScaler.is_use_dynamic_loss_scaling  s     --r)   c                    | j         S )z
        Return the initial loss scaling factor.

        Returns:
            float:  the initial loss scaling factor.
        )rP   r   s    r*   get_init_loss_scalingzAmpScaler.get_init_loss_scaling  s     &&r)   new_init_loss_scalingc                    || _         t          j        t          j        | j         g                              t          j                            | _        dS )z
        Set the initial loss scaling factor by `new_init_loss_scaling`.

        Args:
            new_init_loss_scaling(int):  The new_init_loss_scaling used to update initial loss scaling factor.s
        N)rP   rX   r^   r_   r`   ra   r@   rQ   )rj   r   s     r*   set_init_loss_scalingzAmpScaler.set_init_loss_scaling  sG     #8&Hd-.//66rzBB
 
r)   c                    | j         S )z
        Return the multiplier to use when increasing the loss scaling.

        Returns:
            float:  the multiplier to use when increasing the loss scaling.
        rR   r   s    r*   get_incr_ratiozAmpScaler.get_incr_ratio
       r)   new_incr_ratioc                4    |dk    s
J d            || _         dS )a  
        Set the multiplier to use when increasing the loss scaling by `new_incr_ratio`, `new_incr_ratio` should > 1.0.

        Args:
            new_incr_ratio(float):  The new_incr_ratio used to update the multiplier to use when increasing the loss scaling.
        r?   z!The new_incr_ratio must be > 1.0.Nr   )rj   r   s     r*   set_incr_ratiozAmpScaler.set_incr_ratio  ,     ###%H###)r)   c                    | j         S )z
        Get the less-than-one-multiplier to use when decreasing the loss scaling.

        Returns:
            float:  the less-than-one-multiplier to use when decreasing the loss scaling.
        rS   r   s    r*   get_decr_ratiozAmpScaler.get_decr_ratio  r   r)   new_decr_ratioc                4    |dk     s
J d            || _         dS )a)  
        Set the less-than-one-multiplier to use when decreasing the loss scaling by `new_incr_ratio`, `new_decr_ratio` should < 1.0.

        Args:
            new_decr_ratio(float):  The new_decr_ratio used to update the less-than-one-multiplier to use when decreasing the loss scaling.
        r?   z!The new_decr_ratio must be < 1.0.Nr   )rj   r   s     r*   set_decr_ratiozAmpScaler.set_decr_ratio&  r   r)   c                    | j         S )a  
        Return the num `n`, `n` represent increases loss scaling every `n` consecutive steps with finite gradients.

        Returns:
            int:  the num `n`, `n` represent increases loss scaling every `n` consecutive steps with finite gradients.
        rT   r   s    r*   get_incr_every_n_stepsz AmpScaler.get_incr_every_n_steps0  s     ''r)   new_incr_every_n_stepsc                    || _         dS )a^  
        Set the num `n` by `new_incr_every_n_steps`, `n` represent increases loss scaling every `n` consecutive steps with finite gradients.

        Args:
            new_incr_every_n_steps(int):  The new_incr_every_n_steps used to update the num `n`, `n` represent increases loss scaling every `n` consecutive steps with finite gradients.
        Nr   )rj   r   s     r*   set_incr_every_n_stepsz AmpScaler.set_incr_every_n_steps9  s     $:   r)   c                    | j         S )a  
        Return the num `n`, `n` represent decreases loss scaling every `n` accumulated steps with nan or inf gradients.

        Returns:
            int:  the num `n`, `n` represent decreases loss scaling every `n` accumulated steps with nan or inf gradients.
        rU   r   s    r*   get_decr_every_n_nan_or_infz%AmpScaler.get_decr_every_n_nan_or_infB  s     ,,r)   new_decr_every_n_nan_or_infc                    || _         dS )au  
        Set the num `n` by `new_decr_every_n_nan_or_inf`, `n` represent decreases loss scaling every `n` accumulated steps with nan or inf gradients.

        Args:
            new_decr_every_n_nan_or_inf(int):  The new_decr_every_n_nan_or_inf used to update the num `n`, `n` represent decreases loss scaling every `n` accumulated steps with nan or inf gradients.
        Nr   )rj   r   s     r*   set_decr_every_n_nan_or_infz%AmpScaler.set_decr_every_n_nan_or_infK  s     )D%%%r)   r   c           	         | j         rE| j                                        | j        | j        | j        | j        | j        | j        | j	        dni S )a  
        Returns the state of the scaler as a `dict`, If this instance is not enabled, returns an empty dict.

        Returns:
            A dict of scaler includes:
            scale (tensor): The loss scaling factor.
            incr_ratio(float): The multiplier to use when increasing the loss scaling.
            decr_ratio(float): The less-than-one-multiplier to use when decreasing the loss scaling.
            incr_every_n_steps(int): Increases loss scaling every n consecutive steps with finite gradients.
            decr_every_n_nan_or_inf(int): Decreases loss scaling every n accumulated steps with nan or inf gradients.
            incr_count(int): The number of recent consecutive unskipped steps.
            decr_count(int): The number of recent consecutive skipped steps.
            use_dynamic_loss_scaling(bool): Whether to use dynamic loss scaling. If False, fixed loss_scaling is used. If True, the loss scaling is updated dynamically. Default is True.
        )r   r   r   r   r   r    r!   r#   )
rN   rQ   numpyrR   rS   rT   rU   rV   rW   rO   r   s    r*   
state_dictzAmpScaler.state_dictV  sb    4 |**,,".".&*&>+/+H".".,0,J	 	 	 	
r)   r   c                   | j         sdS t          |          dk    rt          d          |d         d         | _        t	          j        t          j        | j        g                              t          j	                            | _
        |d         | _        |d         | _        |d         | _        |d         | _        |d	         | _        |d
         | _        |d         | _        dS )z
        Loads the scaler state.

        Args:
           state_dict(dict): scaler state. Should be an object returned from a call to `AmpScaler.state_dict()`.
        Nr   zdThe input state dict is empty, possibly because it was saved from a disabled instance of GradScaler.r   r   r   r   r   r    r!   r#   )rN   r   r   rP   rX   r^   r_   r`   ra   r@   rQ   rR   rS   rT   rU   rV   rW   rO   )rj   r   s     r*   load_state_dictzAmpScaler.load_state_dictt  s     | 	Fz??a:  
 #-W"5a"8&Hd-.//66rzBB
 
 &l3%l3#-.B#C (23L(M%%l3%l3)34N)O&&&r)   N)Tr6   r7   r8   r9   r   Tr:   r"   r;   r   r   r   r   r   r   r   r   r   r#   r"   r<   r=   rm   r   r<   r   r   r   r   r   r   r   r<   r   r<   r"   r<   r   r   r   r<   r=   r   r   r<   r=   r   r   r<   r=   r<   r   r   r   r<   r=   r   r   r<   r=   r<   r   r   r   r<   r=   )r$   r%   r&   __doc__rl   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r(   r)   r*   r5   r5   >   s       . .d #*"&'()-JO JO JO JO JOXH! H! H! H!T[* [* [* [*zf; f; f;P  2   . . . .' ' ' '

 

 

 

       * * * *       * * * *( ( ( (: : : :- - - -	D 	D 	D 	D
 
 
 
<P P P P P Pr)   r5   c                      e Zd ZdZ	 	 	 	 	 	 	 d8d9 fdZd: fdZd; fdZd<d Zd=d!Z fd"Z	d> fd#Z
d> fd$Zd? fd%Zd@ fd'Zd? fd(ZdA fd*Zd? fd+ZdB fd-ZdC fd.ZdD fd0ZdC fd1ZdE fd3ZdF fd5ZdG fd7Z xZS )H
GradScaleram
  
    GradScaler is used for Auto-Mixed-Precision training in dynamic graph mode.
    It controls the scaling of loss, helps avoiding numerical overflow.
    The object of this class has nineteen methods `scale()`, `unscale_()`, `minimize()`, `step()`, `update()` and `get`/`set` api of parameters.

    `scale()` is used to multiply the loss by a scale ratio.
    `unscale_()` is used to unscale the gradients of parameters, multiplies the gradients of parameters by 1/(scale ratio)
    `minimize()` is similar as `optimizer.minimize()`, performs parameters updating, and it will update the loss_scaling, it equal to `step()` + `update()`.
    `step()` is similar as `optimizer.step()`, which performs parameters updating.
    `update` is used to update the loss_scaling.


    Commonly, it is used together with `paddle.amp.auto_cast` to achieve Auto-Mixed-Precision in
    dynamic graph mode.

    Args:
        enable(bool, optional): Enable loss scaling or not. Default is True.
        init_loss_scaling (float, optional): The initial loss scaling factor. Default is 65536.0.
        incr_ratio(float, optional): The multiplier to use when increasing the loss
                        scaling. Default is 2.0.
        decr_ratio(float, optional): The less-than-one-multiplier to use when decreasing
                        the loss scaling. Default is 0.5.
        incr_every_n_steps(int, optional): Increases loss scaling every n consecutive
                                steps with finite gradients. Default is 2000.
        decr_every_n_nan_or_inf(int, optional): Decreases loss scaling every n
                                    accumulated steps with nan or inf gradients. Default is 1.
        use_dynamic_loss_scaling(bool, optional): Whether to use dynamic loss scaling. If False, fixed loss_scaling is used. If True, the loss scaling is updated dynamically. Default is True.
    Returns:
        An GradScaler object.

    Examples:

        .. code-block:: python

            >>> import paddle

            >>> model = paddle.nn.Conv2D(3, 2, 3, bias_attr=True)
            >>> optimizer = paddle.optimizer.SGD(learning_rate=0.01, parameters=model.parameters())
            >>> scaler = paddle.amp.GradScaler(init_loss_scaling=1024)
            >>> data = paddle.rand([10, 3, 32, 32])

            >>> with paddle.amp.auto_cast():
            ...     conv = model(data)
            ...     loss = paddle.mean(conv)

            >>> scaled = scaler.scale(loss)  # scale the loss
            >>> scaled.backward()            # do backward
            >>> scaler.minimize(optimizer, scaled)  # update parameters
            >>> optimizer.clear_grad()
    T      @r7   r8     r   r:   r"   r;   r   r   r   r   r   r   r#   r<   r=   c           	     V    t                                          |||||||           d S r   )superrl   )	rj   r:   r;   r   r   r   r   r#   	__class__s	           r*   rl   zGradScaler.__init__  s@     	#$	
 	
 	
 	
 	
r)   rm   r   c                F    t                                          |          S )aJ  
        Multiplies a Tensor by the scale factor and returns scaled outputs.
        If this instance of :class:`GradScaler` is not enabled, output are returned unmodified.

        Args:
            var (Tensor):  The tensor to scale.
        Returns:
            The scaled tensor or original tensor.

        Examples:

            .. code-block:: python

                >>> import paddle

                >>> model = paddle.nn.Conv2D(3, 2, 3, bias_attr=True)
                >>> optimizer = paddle.optimizer.SGD(learning_rate=0.01, parameters=model.parameters())
                >>> scaler = paddle.amp.GradScaler(init_loss_scaling=1024)
                >>> data = paddle.rand([10, 3, 32, 32])

                >>> with paddle.amp.auto_cast():
                ...     conv = model(data)
                ...     loss = paddle.mean(conv)

                >>> scaled = scaler.scale(loss)  # scale the loss
                >>> scaled.backward()            # do backward
                >>> scaler.minimize(optimizer, scaled)  # update parameters
                >>> optimizer.clear_grad()
        )r   r   )rj   rm   r   s     r*   r   zGradScaler.scale  s    < ww}}S!!!r)   r   r   r   r   r   r   c                >     t                      j        |g|R i |S )a  
        This function is similar as `optimizer.minimize()`, which performs parameters updating.

        If the scaled gradients of parameters contains NAN or INF, the parameters updating is skipped.
        Otherwise, if `unscale_()` has not been called, it first unscales the scaled gradients of parameters, then updates the parameters.

        Finally, the loss scaling ratio is updated.

        Args:
            optimizer(Optimizer):  The optimizer used to update parameters.
            args:  Arguments, which will be forward to `optimizer.minimize()`.
            kwargs: Keyword arguments, which will be forward to `optimizer.minimize()`.

        Examples:

            .. code-block:: python

                >>> import paddle

                >>> model = paddle.nn.Conv2D(3, 2, 3, bias_attr=True)
                >>> optimizer = paddle.optimizer.SGD(learning_rate=0.01, parameters=model.parameters())
                >>> scaler = paddle.amp.GradScaler(init_loss_scaling=1024)
                >>> data = paddle.rand([10, 3, 32, 32])

                >>> with paddle.amp.auto_cast():
                ...     conv = model(data)
                ...     loss = paddle.mean(conv)

                >>> scaled = scaler.scale(loss)  # scale the loss
                >>> scaled.backward()            # do backward
                >>> scaler.minimize(optimizer, scaled)  # update parameters
                >>> optimizer.clear_grad()
        )r   r   )rj   r   r   r   r   s       r*   r   zGradScaler.minimize  s-    N  uww	;D;;;F;;;r)   r   c                r   | j         s|                                S | j        t          |                   }|d         t          j        u rt          d          |d         t          j        u r|                     |           t          |d          rJ|
                    d| j                   |                                 |                    d          | _        n*| j        rd| _        n|                                 d| _        t          j        |d<   | j        st          t                     | _        dS dS )at  
        This function is similar as `optimizer.step()`, which performs parameters updating.

        If the scaled gradients of parameters contains NAN or INF, the parameters updating is skipped.
        Otherwise, if `unscale_()` has not been called, it first unscales the scaled gradients of parameters, then updates the parameters.

        Args:
            optimizer(Optimizer):  The optimizer used to update parameters.

        Examples:

            .. code-block:: python

                >>> # doctest: +REQUIRES(env:GPU)
                >>> import paddle
                >>> paddle.device.set_device('gpu')

                >>> model = paddle.nn.Conv2D(3, 2, 3, bias_attr=True)
                >>> optimizer = paddle.optimizer.SGD(learning_rate=0.01, parameters=model.parameters())
                >>> scaler = paddle.amp.GradScaler(init_loss_scaling=1024)
                >>> data = paddle.rand([10, 3, 32, 32])
                >>> with paddle.amp.auto_cast():
                ...     conv = model(data)
                ...     loss = paddle.mean(conv)
                >>> scaled = scaler.scale(loss)  # scale the loss
                >>> scaled.backward()            # do backward
                >>> scaler.step(optimizer)       # update parameters
                >>> scaler.update()              # update the loss scaling ratio
                >>> optimizer.clear_grad()
        r2   z7step() has already been called since the last update().r   r   TFN)rN   stepri   r   r,   r0   r   r.   r   r   r   rc   r   rh   rO   r   r3   )rj   r   r   s      r*   r   zGradScaler.step"  s=   > | 	$>>###0I?7#~'===I  
 7#~':::MM)$$$9233 		.((doFFFNN$-$@$@$M$MD!! .(,%%   (-%#1#9 - 	K%01I%J%JD"""	K 	Kr)   c                    | j         sdS | j        r-|                                  t          t                    | _        dS )a  
        Updates the loss_scaling.

        Examples:

            .. code-block:: python

                >>> # doctest: +REQUIRES(env:GPU)
                >>> import paddle

                >>> paddle.device.set_device('gpu')
                >>> model = paddle.nn.Conv2D(3, 2, 3, bias_attr=True)
                >>> optimizer = paddle.optimizer.SGD(learning_rate=0.01, parameters=model.parameters())
                >>> scaler = paddle.amp.GradScaler(init_loss_scaling=1024)
                >>> data = paddle.rand([10, 3, 32, 32])
                >>> with paddle.amp.auto_cast():
                ...     conv = model(data)
                ...     loss = paddle.mean(conv)
                >>> scaled = scaler.scale(loss)     # scale the loss
                >>> scaled.backward()               # do backward
                >>> scaler.step(optimizer)          # update parameters
                >>> scaler.update()                 # update the loss scaling ratio
                >>> optimizer.clear_grad()
        N)rN   rO   r   r   r3   ri   r   s    r*   updatezGradScaler.update^  sB    2 | 	F) 	KLLNNN%01I%J%JD"r)   c                F    t                                          |          S )aE  
        Unscale the gradients of parameters, multiplies the gradients of parameters by 1/(loss scaling ratio).
        If this instance of :class:`GradScaler` is not enabled, output are returned unmodified.

        Args:
            optimizer(Optimizer):  The optimizer used to update parameters.

        Returns:
            The unscaled parameters or original parameters.

        Examples:

            .. code-block:: python

                >>> # doctest: +REQUIRES(env:GPU)
                >>> import paddle

                >>> paddle.device.set_device('gpu')
                >>> model = paddle.nn.Conv2D(3, 2, 3, bias_attr=True)
                >>> optimizer = paddle.optimizer.SGD(learning_rate=0.01, parameters=model.parameters())
                >>> scaler = paddle.amp.GradScaler(init_loss_scaling=1024)
                >>> data = paddle.rand([10, 3, 32, 32])
                >>> with paddle.amp.auto_cast():
                ...     conv = model(data)
                ...     loss = paddle.mean(conv)
                >>> scaled = scaler.scale(loss)  # scale the loss
                >>> scaled.backward()            # do backward
                >>> scaler.unscale_(optimizer)    # unscale the parameter
                >>> scaler.step(optimizer)
                >>> scaler.update()
                >>> optimizer.clear_grad()
        )r   r   )rj   r   r   s     r*   unscale_zGradScaler.unscale_~  s    B ww	***r)   c                D    t                                                      S )a  
        Enable loss scaling or not.

        Returns:
            bool: enable loss scaling return True else return False.

        Examples:
            .. code-block:: python

                >>> # doctest: +REQUIRES(env:GPU, env:XPU)
                >>> import paddle
                >>> scaler = paddle.amp.GradScaler(
                ...     enable=True,
                ...     init_loss_scaling=1024,
                ...     incr_ratio=2.0,
                ...     decr_ratio=0.5,
                ...     incr_every_n_steps=1000,
                ...     decr_every_n_nan_or_inf=2,
                ...     use_dynamic_loss_scaling=True
                ... )
                >>> enable = scaler.is_enable()
                >>> print(enable)
                True
        )r   r   rj   r   s    r*   r   zGradScaler.is_enable  s    2 ww  """r)   c                D    t                                                      S )ax  
        Whether to use dynamic loss scaling.

        Returns:
            bool: if fixed loss_scaling is used return False, if the loss scaling is updated dynamically return True.

        Examples:
            .. code-block:: python

                >>> # doctest: +REQUIRES(env:GPU, env:XPU)
                >>> import paddle
                >>> scaler = paddle.amp.GradScaler(
                ...     enable=True,
                ...     init_loss_scaling=1024,
                ...     incr_ratio=2.0,
                ...     decr_ratio=0.5,
                ...     incr_every_n_steps=1000,
                ...     decr_every_n_nan_or_inf=2,
                ...     use_dynamic_loss_scaling=True
                ... )
                >>> use_dynamic_loss_scaling = scaler.is_use_dynamic_loss_scaling()
                >>> print(use_dynamic_loss_scaling)
                True
        )r   r   r  s    r*   r   z&GradScaler.is_use_dynamic_loss_scaling      2 ww22444r)   c                D    t                                                      S )a&  
        Return the initial loss scaling factor.

        Returns:
            float:  the initial loss scaling factor.

        Examples:
            .. code-block:: python

                >>> # doctest: +REQUIRES(env:GPU, env:XPU)
                >>> import paddle
                >>> scaler = paddle.amp.GradScaler(
                ...     enable=True,
                ...     init_loss_scaling=1024,
                ...     incr_ratio=2.0,
                ...     decr_ratio=0.5,
                ...     incr_every_n_steps=1000,
                ...     decr_every_n_nan_or_inf=2,
                ...     use_dynamic_loss_scaling=True
                ... )
                >>> init_loss_scaling = scaler.get_init_loss_scaling()
                >>> print(init_loss_scaling)
                1024
        )r   r   r  s    r*   r   z GradScaler.get_init_loss_scaling  s    2 ww,,...r)   r   c                J    t                                          |           dS )a  
        Set the initial loss scaling factor by `new_init_loss_scaling`.

        Args:
            new_init_loss_scaling(float):  The new_init_loss_scaling used to update initial loss scaling factor.

        Examples:
            .. code-block:: python

                >>> # doctest: +REQUIRES(env:GPU, env:XPU)
                >>> import paddle
                >>> scaler = paddle.amp.GradScaler(
                ...     enable=True,
                ...     init_loss_scaling=1024,
                ...     incr_ratio=2.0,
                ...     decr_ratio=0.5,
                ...     incr_every_n_steps=1000,
                ...     decr_every_n_nan_or_inf=2,
                ...     use_dynamic_loss_scaling=True
                ... )
                >>> print(scaler.get_init_loss_scaling())
                1024
                >>> new_init_loss_scaling = 1000
                >>> scaler.set_init_loss_scaling(new_init_loss_scaling)
                >>> print(scaler.get_init_loss_scaling())
                1000
        N)r   r   )rj   r   r   s     r*   r   z GradScaler.set_init_loss_scaling  s$    8 	%%&;<<<<<r)   c                D    t                                                      S )a>  
        Return the multiplier to use when increasing the loss scaling.

        Returns:
            float:  the multiplier to use when increasing the loss scaling.

        Examples:
            .. code-block:: python

                >>> # doctest: +REQUIRES(env:GPU, env:XPU)
                >>> import paddle
                >>> scaler = paddle.amp.GradScaler(
                ...     enable=True,
                ...     init_loss_scaling=1024,
                ...     incr_ratio=2.0,
                ...     decr_ratio=0.5,
                ...     incr_every_n_steps=1000,
                ...     decr_every_n_nan_or_inf=2,
                ...     use_dynamic_loss_scaling=True
                ... )
                >>> incr_ratio = scaler.get_incr_ratio()
                >>> print(incr_ratio)
                2.0
        )r   r   r  s    r*   r   zGradScaler.get_incr_ratio      2 ww%%'''r)   r   c                J    t                                          |           dS )a  
        Set the multiplier to use when increasing the loss scaling by `new_incr_ratio`, `new_incr_ratio` should > 1.0.

        Args:
            new_incr_ratio(float):  The new_incr_ratio used to update the multiplier to use when increasing the loss scaling.

        Examples:
            .. code-block:: python

                >>> # doctest: +REQUIRES(env:GPU, env:XPU)
                >>> import paddle
                >>> scaler = paddle.amp.GradScaler(
                ...     enable=True,
                ...     init_loss_scaling=1024,
                ...     incr_ratio=2.0,
                ...     decr_ratio=0.5,
                ...     incr_every_n_steps=1000,
                ...     decr_every_n_nan_or_inf=2,
                ...     use_dynamic_loss_scaling=True
                ... )
                >>> print(scaler.get_incr_ratio())
                2.0
                >>> new_incr_ratio = 3.0
                >>> scaler.set_incr_ratio(new_incr_ratio)
                >>> print(scaler.get_incr_ratio())
                3.0
        N)r   r   )rj   r   r   s     r*   r   zGradScaler.set_incr_ratio+  #    8 	~.....r)   c                D    t                                                      S )aW  
        Get the less-than-one-multiplier to use when decreasing the loss scaling.

        Returns:
            float:  the less-than-one-multiplier to use when decreasing the loss scaling.

        Examples:
            .. code-block:: python

                >>> # doctest: +REQUIRES(env:GPU, env:XPU)
                >>> import paddle
                >>> scaler = paddle.amp.GradScaler(
                ...     enable=True,
                ...     init_loss_scaling=1024,
                ...     incr_ratio=2.0,
                ...     decr_ratio=0.5,
                ...     incr_every_n_steps=1000,
                ...     decr_every_n_nan_or_inf=2,
                ...     use_dynamic_loss_scaling=True
                ... )
                >>> decr_ratio = scaler.get_decr_ratio()
                >>> print(decr_ratio)
                0.5
        )r   r   r  s    r*   r   zGradScaler.get_decr_ratioI  r	  r)   r   c                J    t                                          |           dS )a7  
        Set the less-than-one-multiplier to use when decreasing the loss scaling by `new_incr_ratio`, `new_decr_ratio` should < 1.0.

        Args:
            new_decr_ratio(float):  The new_decr_ratio used to update the less-than-one-multiplier to use when decreasing the loss scaling.

        Examples:
            .. code-block:: python

                >>> # doctest: +REQUIRES(env:GPU, env:XPU)
                >>> import paddle
                >>> scaler = paddle.amp.GradScaler(
                ...     enable=True,
                ...     init_loss_scaling=1024,
                ...     incr_ratio=2.0,
                ...     decr_ratio=0.5,
                ...     incr_every_n_steps=1000,
                ...     decr_every_n_nan_or_inf=2,
                ...     use_dynamic_loss_scaling=True
                ... )
                >>> print(scaler.get_decr_ratio())
                0.5
                >>> new_decr_ratio = 0.1
                >>> scaler.set_decr_ratio(new_decr_ratio)
                >>> print(scaler.get_decr_ratio())
                0.1
        N)r   r   )rj   r   r   s     r*   r   zGradScaler.set_decr_ratiod  r  r)   c                D    t                                                      S )a  
        Return the num `n`, `n` represent increases loss scaling every `n` consecutive steps with finite gradients.

        Returns:
            int:  the num `n`, `n` represent increases loss scaling every `n` consecutive steps with finite gradients.

        Examples:
            .. code-block:: python

                >>> # doctest: +REQUIRES(env:GPU, env:XPU)
                >>> import paddle
                >>> scaler = paddle.amp.GradScaler(
                ...     enable=True,
                ...     init_loss_scaling=1024,
                ...     incr_ratio=2.0,
                ...     decr_ratio=0.5,
                ...     incr_every_n_steps=1000,
                ...     decr_every_n_nan_or_inf=2,
                ...     use_dynamic_loss_scaling=True
                ... )
                >>> incr_every_n_steps = scaler.get_incr_every_n_steps()
                >>> print(incr_every_n_steps)
                1000
        )r   r   r  s    r*   r   z!GradScaler.get_incr_every_n_steps  s    2 ww--///r)   r   c                J    t                                          |           dS )a  
        Set the num `n` by `new_incr_every_n_steps`, `n` represent increases loss scaling every `n` consecutive steps with finite gradients.

        Args:
            new_incr_every_n_steps(int):  The new_incr_every_n_steps used to update the num `n`, `n` represent increases loss scaling every `n` consecutive steps with finite gradients.

        Examples:
            .. code-block:: python

                >>> # doctest: +REQUIRES(env:GPU, env:XPU)
                >>> import paddle
                >>> scaler = paddle.amp.GradScaler(
                ...     enable=True,
                ...     init_loss_scaling=1024,
                ...     incr_ratio=2.0,
                ...     decr_ratio=0.5,
                ...     incr_every_n_steps=1000,
                ...     decr_every_n_nan_or_inf=2,
                ...     use_dynamic_loss_scaling=True
                ... )
                >>> print(scaler.get_incr_every_n_steps())
                1000
                >>> new_incr_every_n_steps = 2000
                >>> scaler.set_incr_every_n_steps(new_incr_every_n_steps)
                >>> print(scaler.get_incr_every_n_steps())
                2000
        N)r   r   )rj   r   r   s     r*   r   z!GradScaler.set_incr_every_n_steps  s$    8 	&&'=>>>>>r)   c                D    t                                                      S )a  
        Return the num `n`, `n` represent decreases loss scaling every `n` accumulated steps with nan or inf gradients.

        Returns:
            int: the num `n`, `n` represent decreases loss scaling every `n` accumulated steps with nan or inf gradients.

        Examples:
            .. code-block:: python

                >>> # doctest: +REQUIRES(env:GPU, env:XPU)
                >>> import paddle
                >>> scaler = paddle.amp.GradScaler(
                ...     enable=True,
                ...     init_loss_scaling=1024,
                ...     incr_ratio=2.0,
                ...     decr_ratio=0.5,
                ...     incr_every_n_steps=1000,
                ...     decr_every_n_nan_or_inf=2,
                ...     use_dynamic_loss_scaling=True
                ... )
                >>> decr_every_n_nan_or_inf = scaler.get_decr_every_n_nan_or_inf()
                >>> print(decr_every_n_nan_or_inf)
                2
        )r   r   r  s    r*   r   z&GradScaler.get_decr_every_n_nan_or_inf  r  r)   r   c                J    t                                          |           dS )a  
        Set the num `n` by `new_decr_every_n_nan_or_inf`, `n` represent decreases loss scaling every `n` accumulated steps with nan or inf gradients.

        Args:
            new_decr_every_n_nan_or_inf(int):  The new_decr_every_n_nan_or_inf used to update the num `n`, `n` represent decreases loss scaling every `n` accumulated steps with nan or inf gradients.

        Examples:
            .. code-block:: python

                >>> # doctest: +REQUIRES(env:GPU, env:XPU)
                >>> import paddle
                >>> scaler = paddle.amp.GradScaler(
                ...     enable=True,
                ...     init_loss_scaling=1024,
                ...     incr_ratio=2.0,
                ...     decr_ratio=0.5,
                ...     incr_every_n_steps=1000,
                ...     decr_every_n_nan_or_inf=2,
                ...     use_dynamic_loss_scaling=True
                ... )
                >>> print(scaler.get_decr_every_n_nan_or_inf())
                2
                >>> new_decr_every_n_nan_or_inf = 3
                >>> scaler.set_decr_every_n_nan_or_inf(new_decr_every_n_nan_or_inf)
                >>> print(scaler.get_decr_every_n_nan_or_inf())
                3
        N)r   r   )rj   r   r   s     r*   r   z&GradScaler.set_decr_every_n_nan_or_inf  s$    < 	++,GHHHHHr)   r   c                D    t                                                      S )a0  
        Returns the state of the scaler as a `dict`, If this instance is not enabled, returns an empty dict.

        Returns:
            A dict of scaler includes:
            scale (tensor): The loss scaling factor.
            incr_ratio(float): The multiplier to use when increasing the loss scaling.
            decr_ratio(float): The less-than-one-multiplier to use when decreasing the loss scaling.
            incr_every_n_steps(int): Increases loss scaling every n consecutive steps with finite gradients.
            decr_every_n_nan_or_inf(int): Decreases loss scaling every n accumulated steps with nan or inf gradients.
            incr_count(int): The number of recent consecutive unskipped steps.
            decr_count(int): The number of recent consecutive skipped steps.
            use_dynamic_loss_scaling(bool): Whether to use dynamic loss scaling. If False, fixed loss_scaling is used. If True, the loss scaling is updated dynamically. Default is True.


        Examples:

            .. code-block:: python

                >>> # doctest: +REQUIRES(env:GPU, env:XPU)
                >>> import paddle

                >>> scaler = paddle.amp.GradScaler(
                ...     enable=True,
                ...     init_loss_scaling=1024,
                ...     incr_ratio=2.0,
                ...     decr_ratio=0.5,
                ...     incr_every_n_steps=1000,
                ...     decr_every_n_nan_or_inf=2,
                ...     use_dynamic_loss_scaling=True
                ... )
                >>> scaler_state = scaler.state_dict()
        )r   r   r  s    r*   r   zGradScaler.state_dict  s    D ww!!###r)   r   c                J    t                                          |           dS )a:  
        Loads the scaler state.

        Args:
            state_dict(dict): scaler state. Should be an object returned from a call to `GradScaler.state_dict()`.

        Examples:

            .. code-block:: python

                >>> # doctest: +REQUIRES(env:GPU, env:XPU)
                >>> import paddle

                >>> scaler = paddle.amp.GradScaler(
                ...     enable=True,
                ...     init_loss_scaling=1024,
                ...     incr_ratio=2.0,
                ...     decr_ratio=0.5,
                ...     incr_every_n_steps=1000,
                ...     decr_every_n_nan_or_inf=2,
                ...     use_dynamic_loss_scaling=True
                ... )
                >>> scaler_state = scaler.state_dict()
                >>> scaler.load_state_dict(scaler_state)
        N)r   r   )rj   r   r   s     r*   r   zGradScaler.load_state_dict  s#    4 	
+++++r)   )Tr   r7   r8   r   r   Tr   r   r   )r   r   r<   r=   )r<   r=   r   r   r   r   r   r   r   r   r   r   )r$   r%   r&   r   rl   r   r   r   r   r  r   r   r   r   r   r   r   r   r   r   r   r   r   r   __classcell__)r   s   @r*   r   r     s       1 1j #*"&'()-
 
 
 
 
 
 
(" " " " " "@'< '< '< '< '< '<R:K :K :K :Kx   @!+ !+ !+ !+ !+F# # # # # #65 5 5 5 5 56/ / / / / /6= = = = = =<( ( ( ( ( (6/ / / / / /<( ( ( ( ( (6/ / / / / /<0 0 0 0 0 06? ? ? ? ? ?<5 5 5 5 5 56I I I I I I@"$ "$ "$ "$ "$ "$H, , , , , , , , , ,r)   r   )'
__future__r   rL   collectionsr   enumr   typingr   r   r   r   r_   rX   r	   r
   paddle.baser   r   paddle.base.data_feederr   paddle.base.frameworkr   r   r   paddle.frameworkr   	auto_castr   r   paddle.static.amp.decoratorr   !python.paddle.optimizer.optimizerr   r   r,   r3   r5   r   r(   r)   r*   <module>r      s+   # " " " " "  # # # # # #                     ( ( ( ( ( ( ( ( ) ) ) ) ) ) ) ) . . . . . . H H H H H H H H H H , , , , , , ' ' ' ' ' ' 'GGGGGG;;;;;;' ' ' ' ') ' ' '    T   * * *P	P P	P P	P P	P P	P P	P P	P P	Pfc
, c
, c
, c
, c
, c
, c
, c
, c
, c
,r)   