o
    %ݫi                     @   s  U d Z ddlZddlZddlZddlZddlZddlZddlZddlZddl	Z	ddl
mZ ddlZddlZddlmZ ddlm  mZ ddlmZmZmZmZ ddlmZ eeZdZe dZd	Zd
ddZ ee!e!f e"d< dee!ej#f dee!e!f dee!ej#f fddZ$dee!ej#f dee!ej#f fddZ%dd Z&d:ddZ'edd Z(dd Z)ej*j+e&ej,j-e&ej,j.j/e&ia0ej*j+e(ej,j-e(ej,j.j/e(ia1e2ej3e2dk re&t0ej,j.j4< e(t1ej,j.j4< ne&t0ej,j.j5< e(t1ej,j.j5< e2ej3e2dk re&t0ej6j7j8j9< e(t1ej6j7j8j9< ne&t0ej7j8j9< e(t1ej7j8j9< ej*j+e)ia:zddl;Z<d d! Z=e=t:e<j>< [<W n
 e?y@   Y nw ej@t1ej,j.jA< ejBt0ej,j.jA< d"d# ZCd$d% ZDd&d' ZEd;d)d*ZFd+d, ZGeHd-g d.ZId/eI_ d0d1 eI_Jd2d3 ZKG d4d5 d5ZLd6d7 ZMejNeMfd8d9ZOdS )<a7  This module implements a checkpoint saver and loader.

A checkpoint in an experiment usually needs to save the state of many different
things: the model parameters, optimizer parameters, what epoch is this, etc.
The save format for a checkpoint is a directory, where each of these separate
saveable things gets its own file. Additionally, a special file holds meta
information about the checkpoint (by default just time of creation, but you
can specify anything else you may wish, e.g. validation loss).

The interface for the checkpoint system requires you to specify what things to
save. This approach is flexible and agnostic of how your experiment is actually
run.

The interface requires you to specify names for each thing to save. This name
is used to give the right parameter file to the right object when recovering.

Default saving and loading methods are only added for torch.nn.Modules (and
their subclasses), and torch.optim.Optimizers. If those methods do not work for
your object, you can specify your own saving and/or loading methods, either for
a particular instance or a for a class.

Example
-------
>>> # Toy example Module:
>>> class Recoverable(torch.nn.Module):
...     def __init__(self, param):
...         super().__init__()
...         self.param = torch.nn.Parameter(torch.tensor([param]))
...     def forward(self, x):
...         return x * self.param
>>> model = Recoverable(1.)
>>> tempdir = getfixture('tmpdir')
>>> # In simple cases, the module aims to have a terse syntax,
>>> # consisting of three steps.
>>> # 1. Specifying where to save checkpoints and what is included in a
>>> # checkpoint:
>>> checkpointer = Checkpointer(tempdir, {"network": model})
>>> # 2. Recover from the latest checkpoint, if one is found:
>>> checkpointer.recover_if_possible()
>>> # Run your experiment:
>>> data = [(0.1, 0.9), (0.3, 0.8)]
>>> for example, target in data:
...     loss = (model(example) - target)**2
...     # 3. Save checkpoints, and keep by default just one, the newest:
...     ckpt = checkpointer.save_and_keep_only()

Authors
 * Aku Rouhe 2020
 * Adel Moumen 2024
    N)Dict)version)ddp_barrierddp_broadcastif_main_processmain_process_only)
get_loggerCKPTz.yamlz.ckptz.multihead_attnz.convs_intermediate)z.mutihead_attnz.convs_intermediteKEYS_MAPPING
state_dictmappingreturnc              	   C   s\   |  D ]'\}}t|  D ]}||v r*|||}| || |< td|||| qq| S )a_  
    Maps the keys in the old state dictionary according to the provided mapping.

    NOTE: This function will remap all state_dict keys that contain the old key.
    For instance, if the state_dict is {'model.encoder.layer.0.atn.self.query.weight': ...}
    and the mapping is {'.atn': '.attn'}, the resulting state_dict will be
    {'model.encoder.layer.0.attn.self.query.weight': ...}.

    Since this effectively works as a mass substring replacement, partial key
    matches (e.g. in the middle of one layer name) will also work, so be
    careful to avoid false positives.

    Parameters
    ----------
    state_dict : dict
        The old state dictionary to be mapped.
    mapping : dict
        A dictionary specifying the mapping between old and new keys.

    Returns
    -------
    dict
        The modified state dictionary with mapped keys.
    z`Due to replacement compatibility rule '%s'->'%s', renamed `state_dict['%s']`->`state_dict['%s']`)itemslistkeysreplacepoploggerinfo)r   r   replacement_oldreplacement_newold_keynew_key r   Q/home/ubuntu/.local/lib/python3.10/site-packages/speechbrain/utils/checkpoints.pymap_old_state_dict_weightsX   s   r   c                 C   s   t | t}|S )a  Hook to be called when loading a state_dict checkpoint.

    This hook is called when loading a state_dict checkpoint. It can be used
    to modify the state_dict before it is loaded into the model.

    By default, this hook will map the old state_dict keys to the new ones.

    Arguments
    ---------
    state_dict : dict
        The state_dict to be loaded.

    Returns
    -------
    dict
        The modified state_dict.
    )r   r
   )r   altered_state_dictr   r   r   %hook_on_loading_state_dict_checkpoint   s   
r   c                 C   sD   ~d}t ||}z
| j|dd W dS  ty!   | | Y dS w )a  Loads a torch.nn.Module state_dict from the given path instantly.

    This can be made the default for torch.nn.Modules with:
    >>> DEFAULT_LOAD_HOOKS[torch.nn.Module] = torch_recovery

    Arguments
    ---------
    obj : torch.nn.Module
        Instance for which to load the parameters.
    path : str, pathlib.Path
        Path where to load from.
    end_of_epoch : bool
        Whether the recovery comes from an end of epoch checkpoint.
    cpuTstrictN)torch_patched_state_dict_loadload_state_dict	TypeError)objpathend_of_epochdevicer   r   r   r   torch_recovery   s   
r(   r   c                 C   s   t j| |d}t|}|S )a  Loads a `state_dict` from the given path using :func:`torch.load` and
    calls the SpeechBrain `state_dict` loading hooks, e.g. to apply key name
    patching rules for compatibility.

    The `state_dict` sees no further preprocessing and is not applied into a
    model, see :func:`~torch_recovery` or :func:`~torch_parameter_transfer`.

    Arguments
    ---------
    path : str, pathlib.Path
        Path where to load from.
    device : str
        Device where the loaded `state_dict` tensors should reside. This is
        forwarded to :func:`torch.load`; see its documentation for details.

    Returns
    -------
    The loaded state dict.
    map_location)torchloadr   )r%   r'   r   r   r   r   r!      s   r!   c                 C   s4   |   }|std|  d| d t|| dS )a  Saves the obj's parameters to path.

    Default save hook for torch.nn.Modules
    For saving torch.nn.Module state_dicts.

    Arguments
    ---------
    obj : torch.nn.Module
        Instance to save.
    path : str, pathlib.Path
        Path where to save to.
    zSaving an empty state_dict for z in .N)r   r   warningr+   save)r$   r%   r   r   r   r   
torch_save   s   r0   c                 C   s   d}t ||}| j|dd}|jD ]}td|  d| d d|   q|jD ]}td|  d| d d	|   q*d
S )a  Non-strict Torch Module state_dict load.

    Loads a set of parameters from path to obj. If obj has layers for which
    parameters can't be found, only a warning is logged. Same thing
    if the path has parameters for layers which don't find a counterpart
    in obj.

    Arguments
    ---------
    obj : torch.nn.Module
        Instance for which to load the parameters.
    path : str
        Path where to load from.
    r   Fr   zDuring parameter transfer to z loading from z*, the transferred parameters did not have zparameters for the key: z1, the object could not use the parameters loaded zwith the key: N)r!   r"   missing_keysr   r.   unexpected_keys)r$   r%   r'   r   incompatible_keysmissing_keyunexpected_keyr   r   r   torch_parameter_transfer   s(   




r6   z2.0.0z2.4.0c                 C   s   |  t| d S N)r,   str)r$   r%   r   r   r   	_load_spm"  s   r9   c                 C   H   t | }z|t td W n ty   d}t|w d| _| S )a  Method decorator which marks given method as the checkpoint saving hook.

    See register_checkpoint_hooks for example.

    Arguments
    ---------
    method : callable
        Method of the class to decorate. Must be callable with
        signature (instance, path) using positional arguments. This is
        satisfied by for example: def saver(self, path):

    Returns
    -------
    The decorated method, marked as a checkpoint saver.

    Note
    ----
    This will not add the hook (not possible via a method decorator),
    you must also decorate the class with @register_checkpoint_hooks
    Only one method can be added as the hook.
    testpathz6Checkpoint saver must match signature (instance, path)T)inspect	signaturebindobjectpathlibPathr#   _speechbrain_savermethodsigMSGr   r   r   mark_as_saver0  s   
rG   c                 C   sJ   t | }z|t tdd W n ty   d}t|w d| _| S )a  Method decorator which marks given method as checkpoint loading hook.

    Arguments
    ---------
    method : callable
        Method of the class to decorate. Must be callable with
        signature (instance, path, end_of_epoch) using positional
        arguments. This is satisfied by for example:
        `def loader(self, path, end_of_epoch):`

    Returns
    -------
    The decorated method, registered as a checkpoint loader.

    Note
    ----
    This will not add the hook (not possible via a method decorator),
    you must also decorate the class with @register_checkpoint_hooks
    Only one method can be added as the hook.
    r;   Tz@Checkpoint loader must have signature (self, path, end_of_epoch))r<   r=   r>   r?   r@   rA   r#   _speechbrain_loaderrC   r   r   r   mark_as_loaderP  s   
rI   c                 C   r:   )a)  Method decorator which marks given method as a parameter transfer hook.

    Arguments
    ---------
    method : callable
        Method of the class to decorate. Must be callable with
        signature (instance, path) using positional
        arguments. This is satisfied by for example:
        `def loader(self, path):`

    Returns
    -------
    The decorated method, registered as a transfer method.

    Note
    ----
    This will not add the hook (not possible via a method decorator),
    you must also decorate the class with @register_checkpoint_hooks
    Only one method can be added as the hook.

    Note
    ----
    The transfer hook is prioritized over the loader hook by the ``Pretrainer``
    However, if no transfer hook is registered, the Pretrainer will use the
    loader hook.
    r;   z.Transfer hook must have signature (self, path)T)r<   r=   r>   r?   r@   rA   r#   _speechbrain_transferrC   r   r   r   mark_as_transfero  s   
rK   Tc                 C   s   | j  D ]@\}}t|dr#|rt|t| < n|t| < td|  t|dr4|t| < td|  t|drE|t| < td|  q| S )a  Class decorator which registers the load, save and transfer hooks.

    The hooks must have been marked with mark_as_loader and mark_as_saver,
    and possibly mark_as_transfer.

    Arguments
    ---------
    cls : class
        Class to decorate
    save_on_main_only : bool
        By default, the saver is only run on a single process. This argument
        provides the option to run the saver on all processes, needed
        for some savers where data is first gathered before saving.

    Returns
    -------
    the decorated class with hooks registered

    Example
    -------
    >>> @register_checkpoint_hooks
    ... class CustomRecoverable:
    ...     def __init__(self, param):
    ...         self.param = int(param)
    ...
    ...     @mark_as_saver
    ...     def save(self, path):
    ...         with open(path, "w", encoding="utf-8") as fo:
    ...             fo.write(str(self.param))
    ...
    ...     @mark_as_loader
    ...     def load(self, path, end_of_epoch):
    ...         del end_of_epoch  # Unused here
    ...         with open(path, encoding="utf-8") as fi:
    ...             self.param = int(fi.read())
    rB   z$Registered checkpoint save hook for rH   z$Registered checkpoint load hook for rJ   z'Registered parameter transfer hook for )	__dict__r   hasattrr   DEFAULT_SAVE_HOOKSr   debugDEFAULT_LOAD_HOOKSDEFAULT_TRANSFER_HOOKS)clssave_on_main_onlynamerD   r   r   r   register_checkpoint_hooks  s   (


rU   c                 C   s0   t t| }|D ]}||v r||   S q	dS )af  Finds the default save/load hook to use with the given object.

    Follows the Method Resolution Order, i.e., if no hook is registered for
    the class of the object itself, also searches classes which the object
    inherits from.

    Arguments
    ---------
    obj : instance
        Instance of a class.
    default_hooks : dict
        Mapping from classes to (checkpointing hook) functions.

    Returns
    -------
    The correct method or None if no method is registered.

    Example
    -------
    >>> a = torch.nn.Module()
    >>> get_default_hook(a, DEFAULT_SAVE_HOOKS) == torch_save
    True
    N)r<   getmrotype)r$   default_hooksmrorR   r   r   r   get_default_hook  s   rZ   
Checkpoint)r%   meta
paramfilesa  NamedTuple describing one saved checkpoint

To select a checkpoint to load from many checkpoint,
Checkpoints are first filtered and sorted based on this namedtuple.
Checkpointers put pathlib.Path in path and a dict in meta.
You can essentially add any info you want to meta when saving a checkpoint.
The only default key in meta is "unixtime".
Checkpoint.paramfiles is a dict from recoverable name to parameter filepath.
c                 C   s
   t | jS r7   )hashr%   selfr   r   r   <lambda>  s   
 ra   c                 C   s
   | j d S )zRecency as Checkpoint importance metric.

    This function can also act as an example of how to make checkpoint
    importance keyfuncs. This is a named function, but as you can see
    it could be easily implemented as a lambda in a pinch.
    unixtimer\   ckptr   r   r   ckpt_recency  s   
rf   c                
   @   s.  e Zd ZdZ				d-ddZ			d.ddZdd	 Zi d
dejfddZ	i d
ddd
g g g dejf
ddZ
				d/ddZ					d0ddZ				d/ddZdd Zdd ZdddegdejdddZeeejfddZdd  Zd!d" Zed#d$ Zed%d& Zd'd( Zd)d* Zi d
fd+d,ZdS )1Checkpointera
  Saves checkpoints and recovers from them.

    Arguments
    ---------
    checkpoints_dir : str, pathlib.Path
        Path to directory where to save checkpoints.
    recoverables : mapping, optional
        Objects to to recover. They need a (unique) name: this is used
        to connect the parameters in a checkpoint to the correct recoverable.
        The name is also used in the filename of the
        savefile for the objects parameters. These can also be added with
        add_recoverable or add_recoverables or just modifying
        checkpointer.recoverables directly.
    custom_load_hooks : mapping, optional
        A mapping from name [same as in recoverables] to function or method.
        Sets a custom loading hook for a particular object. The
        function/method must be callable with signature (instance, path)
        using positional arguments. This is satisfied by for example:
        `def loader(self, path)`.
    custom_save_hooks : mapping, optional
        Mapping from name [same as in recoverables] to function or method.
        Sets a custom saving hook for a particular object. The
        function/method must be callable with
        signature (instance, path) using positional arguments. This is
        satisfied by for example: def saver(self, path):
    allow_partial_load : bool, optional
        If True, allows loading a checkpoint where a savefile is not found
        for every registered recoverable. In that case, only the found
        savefiles are loaded. When False, loading such a save will raise
        RuntimeError. (default: False)

    Example
    -------
    >>> import torch
    >>> #SETUP:
    >>> tempdir = getfixture('tmpdir')
    >>> class Recoverable(torch.nn.Module):
    ...     def __init__(self, param):
    ...         super().__init__()
    ...         self.param = torch.nn.Parameter(torch.tensor([param]))
    ...     def forward(self, x):
    ...         return x * self.param
    >>> recoverable = Recoverable(1.)
    >>> recoverables = {'recoverable': recoverable}
    >>> # SETUP DONE.
    >>> checkpointer = Checkpointer(tempdir, recoverables)
    >>> first_ckpt = checkpointer.save_checkpoint()
    >>> recoverable.param.data = torch.tensor([2.])
    >>> loaded_ckpt = checkpointer.recover_if_possible()
    >>> # Parameter has been loaded:
    >>> assert recoverable.param.data == torch.tensor([1.])
    >>> # With this call, by default, oldest checkpoints are deleted:
    >>> checkpointer.save_and_keep_only()
    >>> assert first_ckpt not in checkpointer.list_checkpoints()
    NFc                 C   sx   t || _tj| jdd i | _i | _|d ur| | i | _|d ur*| j	| i | _
|d ur7| j
	| || _d S )NTexist_ok)r@   rA   checkpoints_dirosmakedirsrecoverablesoptional_recoverablesadd_recoverablescustom_load_hooksupdatecustom_save_hooksallow_partial_load)r`   rj   rm   rp   rr   rs   r   r   r   __init__A  s   

zCheckpointer.__init__c                 C   s@   || j |< || j|< |dur|| j|< |dur|| j|< dS dS )a  Register a recoverable with possible custom hooks.

        Arguments
        ---------
        name : str
            Unique name for recoverable. Used to map savefiles to objects.
        obj : instance
            The object to recover.
        custom_load_hook : callable, optional
            Called to load the object's savefile. The function/method must be
            callable with signature (instance, path) using positional
            arguments. This is satisfied by for example: def load(self, path):
        custom_save_hook : callable, optional
            Called to save the object's parameters. The function/method must
            be callable with signature (instance, path) using positional
            arguments. This is satisfied by for example: def saver(self, path):
        optional_load : bool, optional
            If True, allows for the optional loading of an object from a checkpoint.
            If the checkpoint lacks the specified object, no error is raised.
            This is particularly useful during transitions between different training
            configurations, such as changing precision from floating point 32 to 16.
            For example, suppose you have a training checkpoint that does not includes
            a `scaler` object. If you intend to continue pre-training in floating point 16,
            where the `scaler` object is needed, marking it as optional prevents loading errors.
            Without marking it as optional, attempting to load the `scaler` object from a checkpoint
            trained in floating point 32 would fail, as the `scaler` object is not present
            in that checkpoint.
        N)rm   rn   rp   rr   )r`   rT   r$   custom_load_hookcustom_save_hookoptional_loadr   r   r   add_recoverableW  s   
$

zCheckpointer.add_recoverablec                 C   s:   t |tjjr| j| dS t|}d| d}t|)a  Update the recoverables dict from the given mapping.

        Arguments
        ---------
        recoverables : mapping
            Objects to recover.
            They need a (unique) name: this is used to
            connect the parameters in a checkpoint to the correct
            recoverable. The name is also used in the filename of the
            savefile for the objects parameters.
        zBCheckpointer needs a mapping (e.g. dict),                     got z	 instead.N)
isinstancecollectionsabcMappingrm   rq   reprAttributeError)r`   rm   recrF   r   r   r   ro     s   zCheckpointer.add_recoverablesTc                 C   s  d}t  r#|du r|  }n| |}tj|dd | |t ||}t|dd}i }| j	 D ]9\}}| t
 }	||	 }
|
||< || jv rO| j| ||
 q0t|t}|dur^|||
 q0dt| d}t|t  r|rqdnd	}t|d
| d|  t|||S dS )a  Saves a checkpoint.

        The whole checkpoint becomes a directory.
        Saves each registered object's parameters in a separate file.
        Also a meta file is added. The meta file by default has just the
        unixtime (seconds since unix epoch), but you can add anything
        relevant yourself. The meta information is later used to pick the
        checkpoint to load.

        The value of end_of_epoch is saved in the meta. This can affect how
        epoch counters and dataset iterators load their state.

        For multi-process saving there are cases where we may want to run
        saving code on multiple processes (e.g. FSDP where we need to collect
        parameters before saving). This works by creating a save folder
        on the main process and communicating it to all processes, and then
        letting each saver/loader method control whether it should save
        on one or all processes.

        Arguments
        ---------
        meta : mapping, optional
            A mapping which is added to the meta file in the checkpoint. The
            key "unixtime" is included by default.
        end_of_epoch : bool, optional
            Whether the checkpoint is at the end of an epoch. True by default.
            May affect loading.
        name : str, optional
            Specify a custom name for your checkpoint.
            The name will still have a prefix added. If no name is given,
            a name is created from a timestamp and a random unique id.
        verbosity : logging level
            Set logging level this save.

        Returns
        -------
        Checkpoint
            namedtuple [see above], the saved checkpoint, unless this is run
            on a non-main process, in which case it returns None.
        NTrh   r   )srczDon't know how to save O. Register default hook                     or add custom hook for this object.end-of-epochzintra-epochz	Saved an z checkpoint in )r   _new_checkpoint_dirpath_custom_checkpoint_dirpathrk   rl   _save_checkpoint_metafile	METAFNAMEr   rm   r   PARAMFILE_EXTrr   rZ   rN   rW   RuntimeErrorr   logr[   )r`   r\   r&   rT   	verbosityckpt_dir
saved_metasaved_paramfilesr$   objfnamesavepathdefault_hookrF   	ckpt_typer   r   r   save_checkpoint  s>   +






zCheckpointer.save_checkpoint   c                 C   s:   | j ||||
d |r|t | j|||||	|
d dS )a  Saves a checkpoint, then deletes the least important checkpoints.

        Essentially this combines ``save_checkpoint()`` and
        ``delete_checkpoints()`` in one call, providing short syntax.

        Arguments
        ---------
        meta : mapping, optional
            A mapping which is added to the meta file in the checkpoint. The
            key "unixtime" is included by default.
        end_of_epoch : bool, optional
            Whether the checkpoint is at the end of an epoch. True by default.
            May affect loading.
        name : str, optional
            Specify a custom name for your checkpoint.
            The name will still have a prefix added. If no name is given,
            a name is created from a timestamp and a random unique id.
        num_to_keep : int, optional
            Number of checkpoints to keep. Defaults to 1. This deletes all
            checkpoints remaining after filtering. Must be >=0.
        keep_recent : bool, optional
            Whether to keep the most recent ``num_to_keep`` checkpoints.
        importance_keys : list, optional
            A list of key functions used in sorting (see the sorted built-in).
            Each callable defines a sort order and num_to_keep checkpoints are
            kept for callable. The checkpoint with the highest keys are kept.
            The functions are passed Checkpoint namedtuples (see above).
        max_keys : list, optional
            A list of keys for which the *highest* value will be kept.
        min_keys : list, optional
            A list of keys for which the *lowest* value will be kept.
        ckpt_predicate : callable, optional
            Use this to exclude some checkpoints from deletion. Before any
            sorting, the list of checkpoints is filtered with this predicate.
            Only the checkpoints for which ckpt_predicate is True can be
            deleted. The function is called with Checkpoint namedtuples
            (see above).
        verbosity : int
            The logging level, default logging.INFO

        Note
        ----
        Unlike save_checkpoint, this does not return anything, since we cannot
        guarantee that the saved checkpoint actually survives deletion.
        )r\   r&   rT   r   )num_to_keepmax_keysmin_keysimportance_keysckpt_predicater   N)r   appendrf   delete_checkpoints)r`   r\   r&   rT   r   keep_recentr   r   r   r   r   r   r   r   save_and_keep_only  s   :

zCheckpointer.save_and_keep_onlyc                 C   s$   | j ||||dd}|r|d S dS )a  Picks a particular checkpoint from all available checkpoints.

        If none of ``importance_key``, ``max_key``, and ``min_key`` is
        used, then most recent checkpoint will be returned. No more than
        one of them may be used.

        Most functionality is actually implemented in ``find_checkpoints()``
        but this is kept as a useful interface.

        Arguments
        ---------
        importance_key : callable, optional
            The key function used in sorting.
            The checkpoint with the highest returned value is picked.
            The function is called with Checkpoint namedtuples.
        max_key : str, optional
            The checkpoint with the highest value for this key will
            be returned. Only checkpoints with this key will be considered!
        min_key : str, optional
            The checkpoint with the lowest value for this key will
            be returned. Only checkpoints with this key will be considered!
        ckpt_predicate : callable, optional
            Before sorting, the list of
            checkpoints is filtered with this predicate.
            See the filter builtin.
            The function is called with Checkpoint namedtuples (see above).
            By default, all checkpoints are considered.

        Returns
        -------
        Checkpoint
            If found.
        None
            If no Checkpoints exist/remain after filtering.
        N)importance_keymax_keymin_keyr   max_num_checkpointsr   )find_checkpoints)r`   r   r   r   r   ckpts_foundr   r   r   find_checkpoint8  s   *zCheckpointer.find_checkpointc                    s   |du rdu r du rt } r!|s! fdd}|f fdd	}nr4|s4fdd}|ffdd	}ns8 r<td|  }tt||}t|t d	d
}|rct||d	d
}|dura|d| S |S g S )a  Picks multiple checkpoints.

        If none of ``importance_key``, ``max_key``, and ``min_key`` is
        used, then the most recent checkpoints will be returned. No more than
        one of these may be used.

        Arguments
        ---------
        importance_key : callable, optional
            The key function used in sorting.
            The checkpoint with the highest returned value is picked.
            The function is called with Checkpoint namedtuples.
        max_key : str, optional
            The checkpoint with the highest value for this key will
            be returned. Only checkpoints with this key will be considered!
        min_key : str, optional
            The checkpoint with the lowest value for this key will
            be returned. Only checkpoints with this key will be considered!
        ckpt_predicate : callable, optional
            Before sorting, the list of
            checkpoints is filtered with this predicate.
            See the filter builtin.
            The function is called with Checkpoint namedtuples (see above).
            By default, all checkpoints are considered.
        max_num_checkpoints : int, None
            The maximum number of checkpoints to return, or None to return all
            found checkpoints.

        Returns
        -------
        list
            List containing at most the max specified number of Checkpoints.

        Nc                    s
   | j   S zDefines the importance key.rc   rd   r   r   r   r     s   
z5Checkpointer.find_checkpoints.<locals>.importance_keyc                    $   |dur | j v o|| S  | j v S zCheckpoints predicate.Nrc   re   old_predicater   r   r   r        
z5Checkpointer.find_checkpoints.<locals>.ckpt_predicatec                    s   | j    S r   rc   rd   r   r   r   r     s   c                    r   r   rc   r   r   r   r   r     r   zDMust specify only one of 'importance_key', 'max_key', and 'min_key'.T)keyreverse)rf   
ValueErrorlist_checkpointsr   filtersorted)r`   r   r   r   r   r   ckptsranked_ckptsr   )r   r   r   r   n  s*   *zCheckpointer.find_checkpointsc                 C   s4   |  ||||}|dur| | |S td |S )aY  Picks a checkpoint and recovers from that, if one is found.

        If a checkpoint is not found, no recovery is run.

        If none of ``importance_key``, ``max_key``, and ``min_key`` is
        used, then most recent checkpoint will be returned. No more than
        one of them may be used.

        Arguments
        ---------
        importance_key : callable, optional
            The key function used in sorting.
            The checkpoint with the highest returned value is loaded.
            The function is called with Checkpoint namedtuples.
        max_key : str, optional
            The checkpoint with the highest value for this key will be loaded.
            Only checkpoints with this key will be considered!
        min_key : str, optional
            The checkpoint with the lowest value for this key will be loaded.
            Only checkpoints with this key will be considered!
        ckpt_predicate : callable, optional
            Before sorting, the list of
            checkpoints is filtered with this predicate.
            See the filter builtin.
            The function is called with Checkpoint namedtuples (see above).
            By default, all checkpoints are considered.

        Returns
        -------
        Checkpoint
            If found.
        None
            If no Checkpoints exist/remain after filtering.
        Nz1Would load a checkpoint here, but none found yet.)r   load_checkpointr   r   )r`   r   r   r   r   chosen_ckptr   r   r   recover_if_possible  s   )

z Checkpointer.recover_if_possiblec                 C   s   |  | dS )zLoads the specified checkpoint.

        Arguments
        ---------
        checkpoint : Checkpoint
            Checkpoint to load.
        N)_call_load_hooks)r`   
checkpointr   r   r   r        zCheckpointer.load_checkpointc                 C   s   |  |  S )zList all checkpoints in the checkpoints directory.

        Returns
        -------
        list
            List of Checkpoint namedtuple (see above).
        )_construct_checkpoint_objects_list_checkpoint_dirsr_   r   r   r   r   	  r   zCheckpointer.list_checkpoints)r   r   r   r   r   r   c                C   s   |dk rt dt }t }dd |pg D }	|	dd |pg D  |	dd |D  |	D ]}
||
d< || jdi |
 || jdd|i|
 q/t  |D ]}||vr`tj||d	 qSt  d
S )a.	  Deletes least important checkpoints.

        Since there can be many ways to define importance (e.g. lowest WER,
        lowest loss), the user should provide a list of sort key functions,
        each defining a particular importance order. In essence, each
        importance key function extracts one importance metric (higher is more
        important). For each of these orders, num_to_keep checkpoints are kept.
        However if there is overlap between each orders' preserved checkpoints,
        the additional checkpoints are not preserved, so the total number of
        preserved checkpoints can be less than::

            num_to_keep * len(importance_keys)

        Arguments
        ---------
        num_to_keep : int, optional
            Number of checkpoints to keep.
            Defaults to 10. You choose to keep 0. This deletes all
            checkpoints remaining after filtering. Must be >=0
        min_keys : list, optional
            List of strings representing keys in the meta. The lowest of
            these values will be kept, up to num_to_keep.
        max_keys : list, optional
            List of strings representing keys in the meta. The highest of
            these values will be kept, up to num_to_keep.
        importance_keys : list, optional
            A list of key functions used in sorting (see the sorted built-in).
            Each callable defines a sort order and num_to_keep checkpoints are
            kept for  callable. To be clear, those with the highest key are
            kept.
            The functions are called with Checkpoint namedtuples
            (see above). See also the default (ckpt_recency,
            above). The default deletes all but the latest checkpoint.
        ckpt_predicate : callable, optional
            Use this to exclude some checkpoints from deletion. Before any
            sorting, the list of checkpoints is filtered with this predicate.
            Only the checkpoints for which ckpt_predicate is True can be
            deleted. The function is called with Checkpoint namedtuples
            (see above).
        verbosity : logging level
            Set logging level for this deletion.

        Note
        ----
        Must be called with keyword arguments, as a signoff that you
        know what you are doing. Deletion is permanent.
        r   z/Number of checkpoints to keep must be positive.c                 S      g | ]}d |iqS r   r   .0r   r   r   r   
<listcomp>R      z3Checkpointer.delete_checkpoints.<locals>.<listcomp>c                 S   r   r   r   r   r   r   r   r   S  r   c                 S   r   )r   r   r   r   r   r   r   T  r   r   r   )r   Nr   )r   setextendrq   r   r   rg   _delete_checkpoint)r`   r   r   r   r   r   r   potential_deletionsprotected_checkpointsr   
key_kwargsre   r   r   r   r     s.   9	
zCheckpointer.delete_checkpointsc                 C   s8   t | js
tdt| j t|d| j  d S )Nz.Checkpoint does not appear valid for deletion.zDeleted checkpoint in )rg   _is_checkpoint_dirr%   r   shutilrmtreer   r   )r   r   r   r   r   r   o  s   zCheckpointer._delete_checkpointc              	   C   s"  t d|j  |jd }| j D ]{\}}z|j| }W nE tyc   | jr*Y qd|v r?d|j d| }t	
|t Y q| j| rVd|j d| d}t	
|t Y qd|j d| }t|w || jv rs| j| ||| qt|t}|d ur|||| qd	t| d
}t|d S )NzLoading a checkpoint from r   
dataloaderzLoading checkpoint from z:,                             but missing a load path for zTrying to load checkpoint from z>,                                 but missing a load path for zU. Skipping as this                                 recoverable is marked as optional.zDon't know how to load r   )r   r   r%   r\   rm   r   r]   KeyErrorrs   warningswarnUserWarningrn   r   rp   rZ   rP   rW   )r`   r   r&   rT   r$   loadpathrF   r   r   r   r   r   w  sF   






zCheckpointer._call_load_hooksc                 C   s   dd | j  D S )Nc                 S   s   g | ]	}t |r|qS r   )rg   r   )r   xr   r   r   r     s    z6Checkpointer._list_checkpoint_dirs.<locals>.<listcomp>)rj   iterdirr_   r   r   r   r     s   z"Checkpointer._list_checkpoint_dirsc              	   C   s   g }| D ]>}t |t dd}tj|tjd}W d    n1 s!w   Y  i }| D ]}|jtkr8|||j< q,|	t
||| q|S )Nutf-8encoding)Loader)openr   yamlr,   r   r   suffixr   stemr   r[   )checkpoint_dirscheckpointsr   fir\   r]   ckptfiler   r   r   r     s   

z*Checkpointer._construct_checkpoint_objectsc                 C   s2   t | } |  sdS | jtsdS | t  S )NF)r@   rA   is_dirrT   
startswithCKPT_PREFIXr   exists)r%   r   r   r   r     s   
zCheckpointer._is_checkpoint_dirc                 C   s   t   }t dt |}d}| jt d| d|d  r3|d7 }| jt d| d|d  s| jt d| d|d S )Nz%Y-%m-%d+%H-%M-%Sr   +02dr   )timestrftime	localtimerj   r   r   )r`   tstamp
suffix_numr   r   r   r     s   z$Checkpointer._new_checkpoint_dirpathc                 C   s   | j t d|  S )Nr   )rj   r   )r`   rT   r   r   r   r     s   z'Checkpointer._custom_checkpoint_dirpathc                 C   sf   t   |d}|| t|ddd}|d |t| W d    |S 1 s,w   Y  |S )N)rb   r   wr   r   z# yamllint disable
)r   rq   r   writer   dump)r`   fpathmeta_to_includer&   r\   for   r   r   r     s   


z&Checkpointer._save_checkpoint_metafile)NNNF)NNF)NNNN)NNNNN)__name__
__module____qualname____doc__rt   rx   ro   loggingINFOr   r   r   r   r   r   r   rf   r   staticmethodr   r   r   r   r   r   r   r   r   r   r   r   r   rg     s~    ;

+

[
K
8
a
2
\,	


rg   c                 C   s   t | }zt|}W n ty   tdw d}t 6 |D ]}| D ]\}}||  |j7  < q%|d7 }q| D ]\}}|jt| ||< q<W d   |S 1 sUw   Y  |S )ag  Produces an average state_dict from an iterator over state_dicts.

    Note that at one time, this keeps two of the state_dicts in memory, which
    is the minimum memory requirement.

    Arguments
    ---------
    state_dicts : iterator, list
        The state_dicts to average.

    Returns
    -------
    state_dict
        The averaged state_dict.
    zNo state dicts to average.r   N)	iternextStopIterationr   r+   no_gradr   datafloat)state_dictsiteratorrunning_sum	num_dictsr   pnameparamr   r   r   average_state_dicts  s&   


		r  c                    s4   d  fdd| D }dd |D }||}|S )a	  Average parameters from multiple checkpoints.

    Use Checkpointer.find_checkpoints() to get the list of checkpoints to
    average over.
    Averaging parameters from some of the last checkpoints in training has been
    shown to sometimes improve performance.

    The default loader and averager work for standard PyTorch modules.

    Arguments
    ---------
    checkpoint_list : list
        List of checkpoints to average.
    recoverable_name : str
        The name of the recoverable, the parameters of which are loaded and
        averaged.
    parameter_loader : function
        A function which takes a single argument, the path to a parameter file,
        and loads the parameters from that file. By default, torch.load,
        which produces state_dict dictionaries.
    averager : function
        A function which takes an iterator over the parameters from each
        checkpoint, as loaded by parameter_loader, and produces their average.
        Note that the function is called with an iterator, so the length is
        initially unknown; the implementation should simply count the number of
        different parameter sets as they are yielded. See average_state_dicts
        above for an example. It is the default averager, and averages
        state_dicts.

    Returns
    -------
    Any
        The output of the averager function.

    Example
    -------
    >>> # Consider this toy Module again:
    >>> class Recoverable(torch.nn.Module):
    ...     def __init__(self, param):
    ...         super().__init__()
    ...         self.param = torch.nn.Parameter(torch.tensor([param]))
    ...     def forward(self, x):
    ...         return x * self.param
    >>> # Now let's make some checkpoints:
    >>> model = Recoverable(1.)
    >>> tempdir = getfixture('tmpdir')
    >>> checkpointer = Checkpointer(tempdir, {"model": model})
    >>> for new_param in range(10):
    ...     model.param.data = torch.tensor([float(new_param)])
    ...     _ = checkpointer.save_checkpoint()  # Suppress output with assignment
    >>> # Let's average the 3 latest checkpoints
    >>> # (parameter values 7, 8, 9 -> avg=8)
    >>> ckpt_list = checkpointer.find_checkpoints(max_num_checkpoints = 3)
    >>> averaged_state = average_checkpoints(ckpt_list, "model")
    >>> # Now load that state in the normal way:
    >>> _ = model.load_state_dict(averaged_state)  # Suppress output
    >>> model.param.data
    tensor([8.])
    r   c                 3   s"    | ]}|j   d V  qdS )r)   N)r]   )r   re   r'   parameter_loaderrecoverable_namer   r   	<genexpr>H  s
    
z&average_checkpoints.<locals>.<genexpr>c                 s   s    | ]}t |V  qd S r7   )r   )r   r   r   r   r   r  L  s
    
r   )checkpoint_listr  r  averagerparameter_iteratoravg_ckptr   r  r   average_checkpoints  s   Ar  )r   )T)Pr   rz   collections.abcr<   r   rk   r@   r   r   r   typingr   r+   r   	packagingr   speechbrain.utils._workaroundsutils_workarounds__waspeechbrain.utils.distributedr   r   r   r   speechbrain.utils.loggerr   r   r   r   r   r   r
   r8   __annotations__Tensorr   r   r(   r!   r0   r6   nnModuleoptim	Optimizerlr_schedulerReduceLROnPlateaurP   rN   parse__version___LRSchedulerLRSchedulercudaampgrad_scaler
GradScalerrQ   sentencepiecespmr9   SentencePieceProcessorImportError_cycliclrsaverCyclicLR_cycliclrloaderrG   rI   rK   rU   rZ   
namedtupler[   __hash__rf   rg   r  r,   r  r   r   r   r   <module>   s    3


+


"


 
%: 


     a%