
    2VhJ                         d dl Z d dlZd dlZd dlZd dlmZ d dlmZ d dl	m
Z
 d dlmZ d dlmZ  ed       G d d	e
             Zy)
    N)backend)keras_export)Callback)
file_utils)io_utilszkeras.callbacks.ModelCheckpointc                   n     e Zd ZdZ	 	 	 	 	 	 	 d fd	ZddZddZddZd Zd Z	d Z
d	 Zd
 Zd Z xZS )ModelCheckpointa&  Callback to save the Keras model or model weights at some frequency.

    `ModelCheckpoint` callback is used in conjunction with training using
    `model.fit()` to save a model or weights (in a checkpoint file) at some
    interval, so the model or weights can be loaded later to continue the
    training from the state saved.

    A few options this callback provides include:

    - Whether to only keep the model that has achieved the "best performance" so
      far, or whether to save the model at the end of every epoch regardless of
      performance.
    - Definition of "best"; which quantity to monitor and whether it should be
      maximized or minimized.
    - The frequency it should save at. Currently, the callback supports saving
      at the end of every epoch, or after a fixed number of training batches.
    - Whether only weights are saved, or the whole model is saved.

    Example:

    ```python
    model.compile(loss=..., optimizer=...,
                  metrics=['accuracy'])

    EPOCHS = 10
    checkpoint_filepath = '/tmp/ckpt/checkpoint.model.keras'
    model_checkpoint_callback = keras.callbacks.ModelCheckpoint(
        filepath=checkpoint_filepath,
        monitor='val_accuracy',
        mode='max',
        save_best_only=True)

    # Model is saved at the end of every epoch, if it's the best seen so far.
    model.fit(epochs=EPOCHS, callbacks=[model_checkpoint_callback])

    # The model (that are considered the best) can be loaded as -
    keras.models.load_model(checkpoint_filepath)

    # Alternatively, one could checkpoint just the model weights as -
    checkpoint_filepath = '/tmp/ckpt/checkpoint.weights.h5'
    model_checkpoint_callback = keras.callbacks.ModelCheckpoint(
        filepath=checkpoint_filepath,
        save_weights_only=True,
        monitor='val_accuracy',
        mode='max',
        save_best_only=True)

    # Model weights are saved at the end of every epoch, if it's the best seen
    # so far.
    model.fit(epochs=EPOCHS, callbacks=[model_checkpoint_callback])

    # The model weights (that are considered the best) can be loaded as -
    model.load_weights(checkpoint_filepath)
    ```

    Args:
        filepath: string or `PathLike`, path to save the model file.
            `filepath` can contain named formatting options,
            which will be filled the value of `epoch` and keys in `logs`
            (passed in `on_epoch_end`).
            The `filepath` name needs to end with `".weights.h5"` when
            `save_weights_only=True` or should end with `".keras"` or `".h5"`
            when checkpoint saving the whole model (default).
            For example:
            if `filepath` is `"{epoch:02d}-{val_loss:.2f}.keras"` or
            "{epoch:02d}-{val_loss:.2f}.weights.h5"`, then the model
            checkpoints will be saved with the epoch number and the validation
            loss in the filename. The directory of the filepath
            should not be reused by any other callbacks to avoid conflicts.
        monitor: The metric name to monitor. Typically the metrics are set by
            the `Model.compile` method. Note:
            * Prefix the name with `"val_"` to monitor validation metrics.
            * Use `"loss"` or `"val_loss"` to monitor the model's total loss.
            * If you specify metrics as strings, like `"accuracy"`, pass the
                same string (with or without the `"val_"` prefix).
            * If you pass `metrics.Metric` objects, `monitor` should be set to
                `metric.name`
            * If you're not sure about the metric names you can check the
                contents of the `history.history` dictionary returned by
                `history = model.fit()`
            * Multi-output models set additional prefixes on the metric names.
        verbose: Verbosity mode, 0 or 1. Mode 0 is silent, and mode 1
            displays messages when the callback takes an action.
        save_best_only: if `save_best_only=True`, it only saves when the model
            is considered the "best" and the latest best model according to the
            quantity monitored will not be overwritten. If `filepath` doesn't
            contain formatting options like `{epoch}` then `filepath` will be
            overwritten by each new better model.
        mode: one of {`"auto"`, `"min"`, `"max"`}. If `save_best_only=True`, the
            decision to overwrite the current save file is made based on either
            the maximization or the minimization of the monitored quantity.
            For `val_acc`, this should be `"max"`, for `val_loss` this should be
            `"min"`, etc. In `"auto"` mode, the mode is set to `"max"` if the
            quantities monitored are `"acc"` or start with `"fmeasure"` and are
            set to `"min"` for the rest of the quantities.
        save_weights_only: if `True`, then only the model's weights will be
            saved (`model.save_weights(filepath)`), else the full model is
            saved (`model.save(filepath)`).
        save_freq: `"epoch"` or integer. When using `"epoch"`, the callback
            saves the model after each epoch. When using integer, the callback
            saves the model at end of this many batches. If the `Model` is
            compiled with `steps_per_execution=N`, then the saving criteria will
            be checked every Nth batch. Note that if the saving isn't aligned to
            epochs, the monitored metric may potentially be less reliable (it
            could reflect as little as 1 batch, since the metrics get reset
            every epoch). Defaults to `"epoch"`.
        initial_value_threshold: Floating point initial "best" value of the
            metric to be monitored. Only applies if `save_best_value=True`. Only
            overwrites the model weights already saved if the performance of
            current model is better than this value.
    c	                 r    t         	           | _        | _        t	        j
                  |       _        | _        | _        | _	        d _
        d _        | _        |dvrt        j                  d| dd       d}|dk(  r7t        j                    _         j                  t        j$                   _        n|d	k(  r8t        j&                   _         j                  t        j$                    _        nd
 j                  v s j                  j)                  d      r8t        j&                   _         j                  Mt        j$                    _        n6t        j                    _         j                  t        j$                   _         j                  dk7  r3t+         j                  t,              st/        d j                   d      |r4 j                  j1                  d      st/        d j                         y t3         fddD              st/        d j                         y )Nr   )autominmaxzModelCheckpoint mode 'z$' is unknown, fallback to auto mode.   
stacklevelr   r   r   accfmeasureepochzUnrecognized save_freq: z2. Expected save_freq are 'epoch' or integer valuesz.weights.h5zWhen using `save_weights_only=True` in `ModelCheckpoint`, the filepath provided must end in `.weights.h5` (Keras weights format). Received: filepath=c              3   T   K   | ]  }j                   j                  |       ! y wN)filepathendswith).0extselfs     T/home/dcms/DCMS/lib/python3.12/site-packages/keras/src/callbacks/model_checkpoint.py	<genexpr>z+ModelCheckpoint.__init__.<locals>.<genexpr>   s%      03&&s+s   %()z.kerasz.h5zTThe filepath provided must end in `.keras` (Keras model format). Received: filepath=)super__init__monitorverboser   path_to_stringr   save_best_onlysave_weights_only	save_freq_batches_seen_since_last_saving_last_batch_seenbestwarningswarnnpless
monitor_opinfgreater
startswith
isinstanceint
ValueErrorr   any)
r   r   r   r    r"   r#   moder$   initial_value_threshold	__class__s
   `        r   r   zModelCheckpoint.__init__   s    	"11(;,!2"/0, !+	--MM( /) )
 D5= ggDOyy FF	U] jjDOyy VVG	$(?(?
(K"$**99$!#DI"$''99$ "DI>>W$Z-L*4>>*: ;C C 
 ==))-8   !%0  9  7H  !  $0     c                 d    | j                  |      r| j                  | j                  ||       y y )Nr   batchlogs)_should_save_on_batch_save_model_current_epoch)r   r:   r;   s      r   on_train_batch_endz"ModelCheckpoint.on_train_batch_end   s0    %%e,4#6#6e$O -r7   c                     || _         y r   )r>   r   r   r;   s      r   on_epoch_beginzModelCheckpoint.on_epoch_begin   s
    #r7   c                 L    | j                   dk(  r| j                  |d |       y y )Nr   r9   )r$   r=   rA   s      r   on_epoch_endzModelCheckpoint.on_epoch_end   s(    >>W$54@ %r7   c                     | j                   dk(  ry|| j                  k  r|dz   }n|| j                  z
  }| xj                  |z  c_        || _        | j                  | j                   k\  rd| _        yy)z?Handles batch-level saving logic, supports steps_per_execution.r   F   r   T)r$   r&   r%   )r   r:   add_batchess      r   r<   z%ModelCheckpoint._should_save_on_batch   sq    >>W$D)))!)K$"7"77K,,;, %//4>>A34D0r7   c                 8   |xs i }| j                   rZ|j                  | j                        }|&t        j                  d| j                   dd       yt        |t        j                        st        j                  |      r2t        |j                        dkD  rt        j                  d| d       y| j                  || j                        rT| j                  dkD  r=t        j                   d	|d
z    d| j                   d| j                  dd|dd| 
       || _        y| j                  dkD  r6t        j                   d	|d
z    d| j                   d| j                  d       y| j                  dkD  rt        j                   d	|d
z    d|        y)a  Determines whether the model should be saved.

        The model should be saved in the following cases:

        - self.save_best_only is False
        - self.save_best_only is True and `monitor` is a numpy array or
          backend tensor (falls back to `save_best_only=False`)
        - self.save_best_only is True and `self.monitor_op(current, self.best)`
          evaluates to True.

        Args:
            epoch: the epoch this iteration is in.
            batch: the batch this iteration is in. `None` if the `save_freq`
                is set to `"epoch"`.
            logs: the `logs` dict passed in to `on_batch_end` or
                `on_epoch_end`.
            filepath: the path where the model would be saved
        zCan save best model only with z available.r   r   Tr   zECan save best model only when `monitor` is a scalar value. Received: z). Falling back to `save_best_only=False`.z
Epoch rF   z: z improved from z.5fz to z, saving model to z did not improve from Fz: saving model to )r"   getr   r(   r)   r0   r*   ndarrayr   	is_tensorlenshaper,   r'   r    r   	print_msg)r   r   r:   r;   r   currents         r   _should_save_modelz"ModelCheckpoint._should_save_model   s   & zrhht||,G4T\\N+N  7BJJ/73D3DW3Mgmm$q(118	 :>>
 ??7DII6||a' **&uqykDLL> B$$(IIc?$wsm D//7j: !(DI||a' **&uqyk#||n -$$(IIc?4
 !||a""uqyk);H:F r7   c                 8   | j                  |||      }	 | j                  ||||      rt        j                  j	                  |      }|r*t        j                  |      st        j                  |       | j                  r| j                  j                  |d       y| j                  j                  |d       yy# t        $ r t        d|       t        $ r=}dt        |j                  d         j!                         v rt        d|       |d}~ww xY w)a  Saves the model.

        Args:
            epoch: the epoch this iteration is in.
            batch: the batch this iteration is in. `None` if the `save_freq`
                is set to `"epoch"`.
            logs: the `logs` dict passed in to `on_batch_end` or `on_epoch_end`.
        T)	overwritezePlease specify a non-directory filepath for ModelCheckpoint. Filepath used is an existing directory: zis a directoryr   zfPlease specify a non-directory filepath for ModelCheckpoint. Filepath used is an existing directory: fN)_get_file_pathrP   ospathdirnamer   existsmakedirsr#   modelsave_weightssaveIsADirectoryErrorIOErrorstrargslower)r   r   r:   r;   r   rV   es          r   r=   zModelCheckpoint._save_model"  s    &&ueT:	&&ueT8D''//(3:#4#4W#=''0))JJ++H+EJJOOHO= E ! 	&Z) 
  
	  3qvvay>#7#7#99##+*.  G
	s   BB= B= =D8DDc                     	 |d|v r# | j                   j                  dd|dz   i|}|S  | j                   j                  d|dz   |dz   d|}	 |S # t        $ r }t        d| j                    d|       d}~ww xY w)	z%Returns the file path for checkpoint.Nr:   r   rF   )r   r:   z*Failed to format this callback filepath: "z". Reason:  )r   formatKeyError)r   r   r:   r;   	file_pathra   s         r   rS   zModelCheckpoint._get_file_pathJ  s    	
 }40DMM00IuqyIDI	  1DMM00 !)5198<	   	<T]]O L# 	s   'A %A 	A<A77A<c                 ,    t        j                  |      S )z;Returns whether the checkpoint `filepath` refers to exists.)r   rW   )r   r   s     r   _checkpoint_existsz"ModelCheckpoint._checkpoint_exists_  s      **r7   c                 $   t         j                  j                  |      }t         j                  j                  |      }dt	        j
                  dd|      z   dz   }d}d}d}d}t        j                  |      rt        j                  |      D ]x  }	t	        j                  ||	      st         j                  j                  ||	      }
t         j                  j                  |
      }||
|kD  r|
}||kD  r|}|
}d}n||k(  st|dz  }z |dk(  r|S |S )a  Returns the most recently modified filepath matching pattern.

        In the rare case where there are more than one pattern-matching file
        having the same modified time that is most recent among all, return the
        filepath that is largest (by `>` operator, lexicographically using the
        numeric equivalents). This provides a tie-breaker when multiple files
        are most recent. Note that a larger `filepath` can sometimes indicate a
        later time of modification (for instance, when epoch/batch is used as
        formatting option), but not necessarily (when accuracy or loss is used).
        The tie-breaker is put in the logic as best effort to return the most
        recent, and to avoid nondeterministic result.

        Modified time of a file is obtained with `os.path.getmtime()`.

        This utility function is best demonstrated via an example:

        ```python
        file_pattern = 'batch{batch:02d}epoch{epoch:02d}.keras'
        test_dir = self.get_temp_dir()
        path_pattern = os.path.join(test_dir, file_pattern)
        file_paths = [
            os.path.join(test_dir, file_name) for file_name in
            ['batch03epoch02.keras',
             'batch02epoch02.keras', 'batch01epoch01.keras']
        ]
        for file_path in file_paths:
            # Write something to each of the files
            ...
        self.assertEqual(
            _get_most_recently_modified_file_matching_pattern(path_pattern),
            file_paths[-1])
        ```

        Args:
            pattern: The file pattern that may optionally contain python
                placeholder such as `{epoch:02d}`.

        Returns:
            The most recently modified file's full filepath matching `pattern`.
            If `pattern` does not contain any placeholder, this returns the
            filepath that exactly matches `pattern`. Returns `None` if no match
            is found.
        ^z{.*}z.*$r   NrF   )rT   rU   rV   basenameresubr   rW   listdirmatchjoingetmtime)r   patterndir_name	base_namebase_name_regexlatest_mod_timefile_path_with_latest_mod_timen_file_with_latest_mod_time file_path_with_largest_file_name	file_namerf   mod_times               r   1_get_most_recently_modified_file_matching_patternzAModelCheckpoint._get_most_recently_modified_file_matching_patternc  s   X 77??7+GG$$W-	wy AACG)-&&'#+/(X&ZZ1 9	88OY7 "Xy AI!ww//	:H8@$'GG;D8/1*29B6 783!_4 4q83+9. '!+11 43r7   )val_lossr   FFr   r   Nr   )__name__
__module____qualname____doc__r   r?   rB   rD   r<   rP   r=   rS   rh   r}   __classcell__)r6   s   @r   r	   r	      sZ    nf  $FPP$A =~&P*+S4r7   r	   )rT   rm   r(   numpyr*   	keras.srcr   keras.src.api_exportr   keras.src.callbacks.callbackr   keras.src.utilsr   r   r	   rc   r7   r   <module>r      sD    	 	    - 1 & $ /0g4h g4 1g4r7   