
    0h                     ^    d Z ddlZddlZddlmZ ddlmZ  edg        G d d             Zy)	zThread utilities.    N)logging)keras_exportzkeras.utils.TimedThread)v1c                   ^    e Zd ZdZd Zd Zd Zd Zd Zd Z	d Z
ej                  d	        Zy
)TimedThreada
  Time-based interval Threads.

    Runs a timed thread every x seconds. It can be used to run a threaded
    function alongside model training or any other snippet of code.

    Args:
        interval: The interval, in seconds, to wait between calls to the
            `on_interval` function.
        **kwargs: additional args that are passed to `threading.Thread`. By
            default, `Thread` is started as a `daemon` thread unless
            overridden by the user in `kwargs`.

    Examples:

    ```python
    class TimedLogIterations(keras.utils.TimedThread):
        def __init__(self, model, interval):
            self.model = model
            super().__init__(interval)

        def on_interval(self):
            # Logs Optimizer iterations every x seconds
            try:
                opt_iterations = self.model.optimizer.iterations.numpy()
                print(f"Epoch: {epoch}, Optimizer Iterations: {opt_iterations}")
            except Exception as e:
                print(str(e))  # To prevent thread from getting killed

    # `start` and `stop` the `TimerThread` manually. If the `on_interval` call
    # requires access to `model` or other objects, override `__init__` method.
    # Wrap it in a `try-except` to handle exceptions and `stop` the thread run.
    timed_logs = TimedLogIterations(model=model, interval=5)
    timed_logs.start()
    try:
        model.fit(...)
    finally:
        timed_logs.stop()

    # Alternatively, run the `TimedThread` in a context manager
    with TimedLogIterations(model=model, interval=5):
        model.fit(...)

    # If the timed thread instance needs access to callback events,
    # subclass both `TimedThread` and `Callback`.  Note that when calling
    # `super`, they will have to called for each parent class if both of them
    # have the method that needs to be run. Also, note that `Callback` has
    # access to `model` as an attribute and need not be explictly provided.
    class LogThreadCallback(
        keras.utils.TimedThread, keras.callbacks.Callback
    ):
        def __init__(self, interval):
            self._epoch = 0
            keras.utils.TimedThread.__init__(self, interval)
            keras.callbacks.Callback.__init__(self)

        def on_interval(self):
            if self.epoch:
                opt_iter = self.model.optimizer.iterations.numpy()
                logging.info(f"Epoch: {self._epoch}, Opt Iteration: {opt_iter}")

        def on_epoch_begin(self, epoch, logs=None):
            self._epoch = epoch

    with LogThreadCallback(interval=5) as thread_callback:
        # It's required to pass `thread_callback` to also `callbacks` arg of
        # `model.fit` to be triggered on callback events.
        model.fit(..., callbacks=[thread_callback])
    ```
    c                 j    || _         |j                  dd      | _        || _        d | _        d | _        y )NdaemonT)intervalpopr	   thread_kwargsthreadthread_stop_event)selfr
   kwargss      Z/var/www/html/engine/venv/lib/python3.12/site-packages/tf_keras/src/utils/timed_threads.py__init__zTimedThread.__init__`   s2     jj40#!%    c                     | j                   j                         sQ| j                          | j                   j                  | j                         | j                   j                         sPy y N)r   is_seton_intervalwaitr
   r   s    r   _call_on_intervalzTimedThread._call_on_intervalg   sL    ((//1""''6 ((//1r   c                 X   | j                   r0| j                   j                         rt        j                  d       yt	        j
                  d| j                  | j                  d| j                  | _         t	        j                         | _
        | j                   j                          y)z"Creates and starts the thread run.zThread is already running.N)targetr	    )r   is_aliver   warning	threadingThreadr   r	   r   Eventr   startr   s    r   r#   zTimedThread.startm   s    ;;4;;//1OO89&& 
));;
   

 "+!2r   c                 R    | j                   r| j                   j                          yy)zStops the thread run.N)r   setr   s    r   stopzTimedThread.stopz   s"    !!""&&( "r   c                 P    | j                   r| j                   j                         S y)z;Returns True if thread is running. Otherwise returns False.F)r   r   r   s    r   r   zTimedThread.is_alive   s    ;;;;''))r   c                 &    | j                          | S r   )r#   r   s    r   	__enter__zTimedThread.__enter__   s    

r   c                 $    | j                          y r   )r&   )r   argsr   s      r   __exit__zTimedThread.__exit__   s    		r   c                     t        d      )z3User-defined behavior that is called in the thread.zURuns every x interval seconds. Needs to be implemented in subclasses of `TimedThread`)NotImplementedErrorr   s    r   r   zTimedThread.on_interval   s     "9
 	
r   N)__name__
__module____qualname____doc__r   r   r#   r&   r   r)   r,   abcabstractmethodr   r   r   r   r   r      sF    DL&7)

 	
 
r   r   )r2   r3   r    abslr    tensorflow.python.util.tf_exportr   r   r   r   r   <module>r7      s:     
   9 'B/{
 {
 0{
r   