o
    ϯi7                     @   s   d dl Z d dlZd dlmZmZmZmZ g dZG dd dZG dd deZ	G dd	 d	eZ
G d
d deZG dd deZG dd deZG dd deZG dd deZG dd deZG dd deZdS )    N)ListOptionalSequenceUnion)
ParamSchedulerConstantParamSchedulerCosineParamSchedulerExponentialParamSchedulerLinearParamSchedulerCompositeParamSchedulerMultiStepParamSchedulerStepParamScheduler StepWithFixedGammaParamSchedulerPolynomialDecayParamSchedulerc                   @   s&   e Zd ZdZdZdedefddZdS )r   z
    Base class for parameter schedulers.
    A parameter scheduler defines a mapping from a progress value in [0, 1) to
    a number (e.g. learning rate).
    gư>wherereturnc                 C   s   t d)a2  
        Get the value of the param for a given point at training.

        We update params (such as learning rate) based on the percent progress
        of training completed. This allows a scheduler to be agnostic to the
        exact length of a particular run (e.g. 120 epochs vs 90 epochs), as
        long as the relative progress where params should be updated is the same.
        However, it assumes that the total length of training is known.

        Args:
            where: A float in [0,1) that represents how far training has progressed

        z'Param schedulers must override __call__)NotImplementedErrorselfr    r   Q/home/ubuntu/.local/lib/python3.10/site-packages/fvcore/common/param_scheduler.py__call__!   s   zParamScheduler.__call__N)__name__
__module____qualname____doc__WHERE_EPSILONfloatr   r   r   r   r   r      s    r   c                   @   s4   e Zd ZdZdeddfddZdedefdd	ZdS )
r   z/
    Returns a constant value for a param.
    valuer   Nc                 C   s
   || _ d S N)_value)r   r   r   r   r   __init__7      
zConstantParamScheduler.__init__r   c                 C   s   |dkrt d| | jS N      ?z/where in ParamScheduler must be in [0, 1]: got )RuntimeErrorr    r   r   r   r   r   :   s
   zConstantParamScheduler.__call__r   r   r   r   r   r!   r   r   r   r   r   r   2   s    r   c                   @   8   e Zd ZdZdededdfddZdedefd	d
ZdS )r   a  
    Cosine decay or cosine warmup schedules based on start and end values.
    The schedule is updated based on the fraction of training progress.
    The schedule was proposed in 'SGDR: Stochastic Gradient Descent with
    Warm Restarts' (https://arxiv.org/abs/1608.03983). Note that this class
    only implements the cosine annealing part of SGDR, and not the restarts.

    Example:

        .. code-block:: python

          CosineParamScheduler(start_value=0.1, end_value=0.0001)
    start_value	end_valuer   Nc                 C      || _ || _d S r   _start_value
_end_valuer   r(   r)   r   r   r   r!   Q      
zCosineParamScheduler.__init__r   c                 C   s*   | j d| j| j   dttj|    S )Ng      ?   )r-   r,   mathcospir   r   r   r   r   Y   s   zCosineParamScheduler.__call__r&   r   r   r   r   r   B       
r   c                   @   r'   )r	   a  
    Exponetial schedule parameterized by a start value and decay.
    The schedule is updated based on the fraction of training
    progress, `where`, with the formula
    `param_t = start_value * (decay ** where)`.

    Example:

        .. code-block:: python
            ExponentialParamScheduler(start_value=2.0, decay=0.02)

    Corresponds to a decreasing schedule with values in [2.0, 0.04).
    r(   decayr   Nc                 C   r*   r   r,   _decay)r   r(   r5   r   r   r   r!   n   r/   z"ExponentialParamScheduler.__init__r   c                 C   s   | j | j|  S r   r6   r   r   r   r   r   v   s   z"ExponentialParamScheduler.__call__r&   r   r   r   r   r	   _   r4   r	   c                   @   r'   )r
   a  
    Linearly interpolates parameter between ``start_value`` and ``end_value``.
    Can be used for either warmup or decay based on start and end values.
    The schedule is updated after every train step by default.

    Example:

        .. code-block:: python

            LinearParamScheduler(start_value=0.0001, end_value=0.01)

    Corresponds to a linear increasing schedule with values in [0.0001, 0.01)
    r(   r)   r   Nc                 C   r*   r   r+   r.   r   r   r   r!      r/   zLinearParamScheduler.__init__r   c                 C   s   | j | | jd|   S Nr0   )r-   r,   r   r   r   r   r      s   zLinearParamScheduler.__call__r&   r   r   r   r   r
   z   r4   r
   c                	   @   sR   e Zd ZdZ		ddee dee deee  ddfddZd	edefd
dZ	dS )r   a,  
    Takes a predefined schedule for a param value, and a list of epochs or steps
    which stand for the upper boundary (excluded) of each range.

    Example:

        .. code-block:: python

          MultiStepParamScheduler(
            values=[0.1, 0.01, 0.001, 0.0001],
            milestones=[30, 60, 80, 120]
          )

    Then the param value will be 0.1 for epochs 0-29, 0.01 for
    epochs 30-59, 0.001 for epochs 60-79, 0.0001 for epochs 80-120.
    Note that the length of values must be equal to the length of milestones
    plus one.
    Nvaluesnum_updates
milestonesr   c                 C   s6  |du r|du rt d|du r2g }t|tt| }tt|d D ]}|||d   q%n!t|trEt|t|t	|du ksSt dt|t	|du  |du rb|d |dd }}|t|k rlt d|| _
|| _|| _d}| jD ]}|| jkrt d| j|f ||krt d	||f |}qzdS )
aW  
        Args:
            values: param value in each range
            num_updates: the end of the last range. If None, will use ``milestones[-1]``
            milestones: the boundary of each range. If None, will evenly split ``num_updates``

        For example, all the following combinations define the same scheduler:

        * num_updates=90, milestones=[30, 60], values=[1, 0.1, 0.01]
        * num_updates=90, values=[1, 0.1, 0.01]
        * milestones=[30, 60, 90], values=[1, 0.1, 0.01]
        * milestones=[3, 6, 9], values=[1, 0.1, 0.01]  (ParamScheduler is scale-invariant)
        Nz.num_updates and milestones cannot both be Noner0   z3MultiStep scheduler requires a list of %d miletonesz?Total num_updates must be greater than length of param scheduler   zTMilestone must be smaller than total number of updates: num_updates=%d, milestone=%dzHMilestone must be smaller than start epoch: start_epoch=%d, milestone=%d)
ValueErrorr1   ceilr   lenrangeappend
isinstancer   int_param_schedule_num_updates_milestones)r   r9   r:   r;   
step_widthidxstart_epoch	milestoner   r   r   r!      sR   

z MultiStepParamScheduler.__init__r   c                 C   s>   |dkrt d| t|| j | j }| jt| j| S r#   )r%   rC   r   rE   rD   bisectbisect_rightrF   )r   r   	epoch_numr   r   r   r      s   z MultiStepParamScheduler.__call__)NN)
r   r   r   r   r   r   r   rC   r!   r   r   r   r   r   r      s    

@r   c                   @   r'   )r   as  
    Decays the param value after every epoch according to a
    polynomial function with a fixed power.
    The schedule is updated after every train step by default.

    Example:

        .. code-block:: python

          PolynomialDecayParamScheduler(base_value=0.1, power=0.9)

    Then the param value will be 0.1 for epoch 0, 0.099 for epoch 1, and
    so on.
    
base_valuepowerr   Nc                 C   r*   r   _base_value_power)r   rN   rO   r   r   r   r!     r/   z&PolynomialDecayParamScheduler.__init__r   c                 C   s   | j d| | j  S r8   rP   r   r   r   r   r     s   z&PolynomialDecayParamScheduler.__call__r&   r   r   r   r   r      s    
r   c                   @   sD   e Zd ZdZdeeef dee ddfddZdedefd	d
Z	dS )r   a  
    Takes a fixed schedule for a param value.  If the length of the
    fixed schedule is less than the number of epochs, then the epochs
    are divided evenly among the param schedule.
    The schedule is updated after every train epoch by default.

    Example:

        .. code-block:: python

          StepParamScheduler(values=[0.1, 0.01, 0.001, 0.0001], num_updates=120)

    Then the param value will be 0.1 for epochs 0-29, 0.01 for
    epochs 30-59, 0.001 for epoch 60-89, 0.0001 for epochs 90-119.
    r:   r9   r   Nc                 C   s8   |dkrt dt|trt|dkst d|| _d S )Nr   z'Number of updates must be larger than 0z:Step scheduler requires a list of at least one param value)r=   rB   r   r?   rD   )r   r:   r9   r   r   r   r!      s   
zStepParamScheduler.__init__r   c                 C   s"   t || j t| j }| j| S r   )rC   r   r?   rD   )r   r   indr   r   r   r   -  s   
zStepParamScheduler.__call__)
r   r   r   r   r   rC   r   r   r!   r   r   r   r   r   r     s    

r   c                
   @   s@   e Zd ZdZdededededdf
dd	Zd
edefddZdS )r   a  
    Decays the param value by gamma at equal number of steps so as to have the
    specified total number of decays.

    Example:

        .. code-block:: python

          StepWithFixedGammaParamScheduler(
            base_value=0.1, gamma=0.1, num_decays=3, num_updates=120)

    Then the param value will be 0.1 for epochs 0-29, 0.01 for
    epochs 30-59, 0.001 for epoch 60-89, 0.0001 for epochs 90-119.
    rN   
num_decaysgammar:   r   Nc                 C   s   ||fD ]}t |ttfr|dkstdq||fD ]}t |tr%|dks)tdq|| _|| _|| _|| _|g}t|D ]}|	|d |  q=t
||d| _d S )Nr   z-base_value and gamma must be positive numbersz4num_decays and num_updates must be positive integersr<   )r:   r9   )rB   rC   r   r=   rN   rT   rU   r:   r@   rA   r   _step_param_scheduler)r   rN   rT   rU   r:   kr9   _r   r   r   r!   B  s$   z)StepWithFixedGammaParamScheduler.__init__r   c                 C   s
   |  |S r   )rV   r   r   r   r   r   \  r"   z)StepWithFixedGammaParamScheduler.__call__)r   r   r   r   r   rC   r!   r   r   r   r   r   r   2  s    
r   c                   @   sH   e Zd ZdZdee dee dee ddfddZ	d	edefd
dZ
dS )r   a  
    Composite parameter scheduler composed of intermediate schedulers.
    Takes a list of schedulers and a list of lengths corresponding to
    percentage of training each scheduler should run for. Schedulers
    are run in order. All values in lengths should sum to 1.0.

    Each scheduler also has a corresponding interval scale. If interval
    scale is 'fixed', the intermediate scheduler will be run without any rescaling
    of the time. If interval scale is 'rescaled', intermediate scheduler is
    run such that each scheduler will start and end at the same values as it
    would if it were the only scheduler. Default is 'rescaled' for all schedulers.

    Example:

        .. code-block:: python

              schedulers = [
                ConstantParamScheduler(value=0.42),
                CosineParamScheduler(start_value=0.42, end_value=1e-4)
              ]
              CompositeParamScheduler(
                schedulers=schedulers,
                interval_scaling=['rescaled', 'rescaled'],
                lengths=[0.3, 0.7])

    The parameter value will be 0.42 for the first [0%, 30%) of steps,
    and then will cosine decay from 0.42 to 0.0001 for [30%, 100%) of
    training.
    
schedulerslengthsinterval_scalingr   Nc                 C   s   t |t |krtdt |dkrtdtt|d dkr$tdt|dkr6dt|d d  |d< |D ]}|dvrEtd	| q8|| _|| _|| _d S )
Nz*Schedulers and lengths must be same lengthr   z?There must be at least one scheduler in the composite schedulerr$   gMbP?z*The sum of all values in lengths must be 1r<   )rescaledfixedzUnsupported interval_scaling: )r?   r=   abssum_lengths_schedulers_interval_scaling)r   rY   rZ   r[   sr   r   r   r!     s"   
z CompositeParamScheduler.__init__r   c                 C   s   d}| j | }|| j |kr2|t| jd k r2|d7 }|| j | 7 }|| j |kr2|t| jd k s| j| }|}| j| }|dkrR|| j |  }|| | j |  }||S )Nr   r0   r\   )r`   r   r?   ra   rb   )r   r   irunning_total	schedulerscheduler_whereinterval_scalescheduler_startr   r   r   r     s*   


z CompositeParamScheduler.__call__)r   r   r   r   r   r   r   r   strr!   r   r   r   r   r   r   `  s    
r   )rK   r1   typingr   r   r   r   __all__r   r   r   r	   r
   r   r   r   r   r   r   r   r   r   <module>   s    ]#.