o
    ei\                     @   sZ   d Z ddlZddlmZ ddlmZmZmZ eeZ	eG dd dZ
G dd	 d	e
ZdS )
zImplements a checkpointable epoch counter (loop), optionally integrating early stopping.

Authors
 * Aku Rouhe 2020
 * Davide Borra 2021
    N)
get_logger   )mark_as_loadermark_as_saverregister_checkpoint_hooksc                   @   sB   e Zd ZdZdd Zdd Zdd Zedd	 Ze	dddZ
dS )EpochCountera  An epoch counter which can save and recall its state.

    Use this as the iterator for epochs.
    Note that this iterator gives you the numbers from [1 ... limit] not
    [0 ... limit-1] as range(limit) would.

    Arguments
    ---------
    limit: int
        maximum number of epochs

    Example
    -------
    >>> from speechbrain.utils.checkpoints import Checkpointer
    >>> tmpdir = getfixture('tmpdir')
    >>> epoch_counter = EpochCounter(10)
    >>> recoverer = Checkpointer(tmpdir, {"epoch": epoch_counter})
    >>> recoverer.recover_if_possible()
    >>> # Now after recovery,
    >>> # the epoch starts from where it left off!
    >>> for epoch in epoch_counter:
    ...     # Run training...
    ...     ckpt = recoverer.save_checkpoint()
    c                 C   s   d| _ t|| _d S )Nr   )currentintlimit)selfr
    r   Z/home/ubuntu/transcripts/venv/lib/python3.10/site-packages/speechbrain/utils/epoch_loop.py__init__0   s   zEpochCounter.__init__c                 C   s   | S )Nr   r   r   r   r   __iter__4   s   zEpochCounter.__iter__c                 C   s6   | j | jk r|  j d7  _ td| j   | j S t)Nr   zGoing into epoch )r   r
   loggerinfoStopIterationr   r   r   r   __next__7   s
   zEpochCounter.__next__c                 C   sD   t |ddd}|t| j W d    d S 1 sw   Y  d S )Nwutf-8encoding)openwritestrr   r   pathfor   r   r   _save>   s   "zEpochCounter._saveTc                 C   sd   t |dd"}t| }|r|| _n|d | _W d    d S W d    d S 1 s+w   Y  d S )Nr   r   r   )r   r	   readr   )r   r   end_of_epochfisaved_valuer   r   r   _recoverC   s   "zEpochCounter._recoverN)T)__name__
__module____qualname____doc__r   r   r   r   r   r   r$   r   r   r   r   r      s    
r   c                       sN   e Zd ZdZ fddZ fddZdd Zedd	 Ze	dddZ
  ZS )EpochCounterWithStoppera-  An epoch counter which can save and recall its state, integrating an early stopper by tracking a target metric.

    Arguments
    ---------
    limit: int
        maximum number of epochs
    limit_to_stop : int
        maximum number of consecutive epochs without improvements in performance
    limit_warmup : int
        number of epochs to wait until start checking for early stopping
    direction : "max" or "min"
        direction to optimize the target metric

    Example
    -------
    >>> limit = 10
    >>> limit_to_stop = 5
    >>> limit_warmup = 2
    >>> direction = "min"
    >>> epoch_counter = EpochCounterWithStopper(limit, limit_to_stop, limit_warmup, direction)
    >>> for epoch in epoch_counter:
    ...     # Run training...
    ...     # Track a validation metric, (insert calculation here)
    ...     current_valid_metric = 0
    ...     # Update epoch counter so that we stop at the appropriate time
    ...     epoch_counter.update_metric(current_valid_metric)
    ...     print(epoch)
    1
    2
    3
    4
    5
    6
    7
    8
    c                    s   t  | || _|| _|| _d| _d| _d| _| jdk r!td| jdk r*td| jdkr:t	dd| _
| _d S | jd	krKt	d d
| _
| _d S td)NFr   gư>z$Stopper 'limit_to_stop' must be >= 0z#Stopper 'limit_warmup' must be >= 0mininfr   maxz*Stopper 'direction' must be 'min' or 'max')superr   limit_to_stoplimit_warmup	directionshould_stop
best_limit	min_delta
ValueErrorfloat
best_scoresign)r   r
   r/   r0   r1   	__class__r   r   r   w   s    



z EpochCounterWithStopper.__init__c                    s   | j rtt  S )z.Stop iteration if we've reached the condition.)r2   r   r.   r   r   r9   r   r   r      s   
z EpochCounterWithStopper.__next__c                 C   s|   | j | jkr:| j| | jd| j | j  k r| j | _|| _| j | j }|| jk| _| jr<t	| d| j d dS dS dS )a
  Update the state to reflect most recent value of the relevant metric.

        NOTE: Should be called only once per validation loop.

        Arguments
        ---------
        current_metric : float
            The metric used to make a stopping decision.
        r   z) epochs without improvement.
Patience of z is exhausted, stopping.N)
r   r0   r8   r4   r7   r3   r/   r2   r   r   )r   current_metricepochs_without_improvementr   r   r   update_metric   s    
	z%EpochCounterWithStopper.update_metricc                 C   sR   t |ddd}t| j| j| j| jd| W d    d S 1 s"w   Y  d S )Nr   r   r   )current_epoch
best_epochr7   r2   )r   yamldumpr   r3   r7   r2   r   r   r   r   r      s   "zEpochCounterWithStopper._saveTNc                 C   sz   ~t |dd,}t|}|r|d | _n|d d | _|d | _|d | _|d | _W d    d S 1 s6w   Y  d S )Nr   r   r>   r   r?   r7   r2   )r   r@   	safe_loadr   r3   r7   r2   )r   r   r!   devicer"   
saved_dictr   r   r   r$      s   


"z EpochCounterWithStopper._recover)TN)r%   r&   r'   r(   r   r   r=   r   r   r   r$   __classcell__r   r   r9   r   r)   Q   s    %
r)   )r(   r@   speechbrain.utils.loggerr   checkpointsr   r   r   r%   r   r   r)   r   r   r   r   <module>   s    ;