o
    xi"                     @  sX   d dl mZ d dlZd dlmZ d dlmZ d dlZd dlm	Z	 G dd deej
ZdS )    )annotationsN)Any)Callback)	telemetryc                      s   e Zd ZdZd- fd
dZd.d/ddZd.d0ddZejd.d/ddZ	ej	d.d0ddZ
d1ddZd1ddZ	 d2d3d%d&Z	'	(	d4d5d+d,Z  ZS )6WandbEvalCallbacka
  Abstract base class to build Keras callbacks for model prediction visualization.

    You can build callbacks for visualizing model predictions `on_epoch_end`
    that can be passed to `model.fit()` for classification, object detection,
    segmentation, etc. tasks.

    To use this, inherit from this base callback class and implement the
    `add_ground_truth` and `add_model_prediction` methods.

    The base class will take care of the following:
    - Initialize `data_table` for logging the ground truth and
        `pred_table` for predictions.
    - The data uploaded to `data_table` is used as a reference for the
        `pred_table`. This is to reduce the memory footprint. The `data_table_ref`
        is a list that can be used to access the referenced data.
        Check out the example below to see how it's done.
    - Log the tables to W&B as W&B Artifacts.
    - Each new `pred_table` is logged as a new version with aliases.

    Example:
        ```python
        class WandbClfEvalCallback(WandbEvalCallback):
            def __init__(self, validation_data, data_table_columns, pred_table_columns):
                super().__init__(data_table_columns, pred_table_columns)

                self.x = validation_data[0]
                self.y = validation_data[1]

            def add_ground_truth(self):
                for idx, (image, label) in enumerate(zip(self.x, self.y)):
                    self.data_table.add_data(idx, wandb.Image(image), label)

            def add_model_predictions(self, epoch):
                preds = self.model.predict(self.x, verbose=0)
                preds = tf.argmax(preds, axis=-1)

                data_table_ref = self.data_table_ref
                table_idxs = data_table_ref.get_index()

                for idx in table_idxs:
                    pred = preds[idx]
                    self.pred_table.add_data(
                        epoch,
                        data_table_ref.data[idx][0],
                        data_table_ref.data[idx][1],
                        data_table_ref.data[idx][2],
                        pred,
                    )


        model.fit(
            x,
            y,
            epochs=2,
            validation_data=(x, y),
            callbacks=[
                WandbClfEvalCallback(
                    validation_data=(x, y),
                    data_table_columns=["idx", "image", "label"],
                    pred_table_columns=["epoch", "idx", "image", "label", "pred"],
                )
            ],
        )
        ```

    To have more fine-grained control, you can override the `on_train_begin` and
    `on_epoch_end` methods. If you want to log the samples after N batched, you
    can implement `on_train_batch_end` method.
    data_table_columns	list[str]pred_table_columnsargsr   kwargsreturnNonec                   sl   t  j|i | tjd u rtdtjtjd}d|j_W d    n1 s)w   Y  || _	|| _
d S )Nz>You must call `wandb.init()` first before using this callback.)runT)super__init__wandbr   Errorr   contextfeaturekeras_wandb_eval_callbackr   r	   )selfr   r	   r
   r   tel	__class__ d/home/ubuntu/.local/lib/python3.10/site-packages/wandb/integration/keras/callbacks/tables_builder.pyr   S   s   


zWandbEvalCallback.__init__Nlogsdict[str, float] | Nonec                 C  s$   | j | jd | | |   d S N)column_names)init_data_tabler   add_ground_truthlog_data_tabler   r   r   r   r   on_train_beging   s   
z WandbEvalCallback.on_train_beginepochintc                 C  s&   | j | jd | || |   d S r   )init_pred_tabler	   add_model_predictionslog_pred_tabler   r%   r   r   r   r   on_epoch_endo   s   zWandbEvalCallback.on_epoch_endc                 C     t | jj d)a  Add ground truth data to `data_table`.

        Use this method to write the logic for adding validation/training data to
        `data_table` initialized using `init_data_table` method.

        Example:
            ```python
            for idx, data in enumerate(dataloader):
                self.data_table.add_data(idx, data)
            ```
        This method is called once `on_train_begin` or equivalent hook.
        z.add_ground_truthNotImplementedErrorr   __name__r#   r   r   r   r!   w   s   z"WandbEvalCallback.add_ground_truthc                 C  r,   )a  Add a prediction from a model to `pred_table`.

        Use this method to write the logic for adding model prediction for validation/
        training data to `pred_table` initialized using `init_pred_table` method.

        Example:
            ```python
            # Assuming the dataloader is not shuffling the samples.
            for idx, data in enumerate(dataloader):
                preds = model.predict(data)
                self.pred_table.add_data(
                    self.data_table_ref.data[idx][0],
                    self.data_table_ref.data[idx][1],
                    preds,
                )
            ```
        This method is called `on_epoch_end` or equivalent hook.
        z.add_model_predictionsr-   r*   r   r   r   r(      s   z'WandbEvalCallback.add_model_predictionsr   c                 C  s   t j|dd| _dS )a  Initialize the W&B Tables for validation data.

        Call this method `on_train_begin` or equivalent hook. This is followed by adding
        data to the table row or column wise.

        Args:
            column_names: (list) Column names for W&B Tables.
        T)columnsallow_mixed_typesN)r   Table
data_tabler   r   r   r   r   r       s   	z!WandbEvalCallback.init_data_tablec                 C  s   t j|d| _dS )a  Initialize the W&B Tables for model evaluation.

        Call this method `on_epoch_end` or equivalent hook. This is followed by adding
        data to the table row or column wise.

        Args:
            column_names: (list) Column names for W&B Tables.
        )r0   N)r   r2   
pred_tabler4   r   r   r   r'      s   	z!WandbEvalCallback.init_pred_tablevaldatasetval_datanamestrtype
table_namec                 C  sN   t j||d}|| j| t jdusJ t j| |  ||| _dS )a  Log the `data_table` as W&B artifact and call `use_artifact` on it.

        This lets the evaluation table use the reference of already uploaded data
        (images, text, scalar, etc.) without re-uploading.

        Args:
            name: (str) A human-readable name for this artifact, which is how you can
                identify this artifact in the UI or reference it in use_artifact calls.
                (default is 'val')
            type: (str) The type of the artifact, which is used to organize and
                differentiate artifacts. (default is 'dataset')
            table_name: (str) The name of the table as will be displayed in the UI.
                (default is 'val_data').
        r;   N)	r   Artifactaddr3   r   use_artifactwaitgetdata_table_ref)r   r9   r;   r<   data_artifactr   r   r   r"      s   z WandbEvalCallback.log_data_table
evaluation	eval_dataaliaseslist[str] | Nonec                 C  sP   t jdusJ t jdt jj d|d}|| j| t jj||p#dgd dS )a+  Log the W&B Tables for model evaluation.

        The table will be logged multiple times creating new version. Use this
        to compare models at different intervals interactively.

        Args:
            type: (str) The type of the artifact, which is used to organize and
                differentiate artifacts. (default is 'evaluation')
            table_name: (str) The name of the table as will be displayed in the UI.
                (default is 'eval_data')
            aliases: (List[str]) List of aliases for the prediction table.
        Nrun__predr=   latest)rG   )r   r   r>   idr?   r5   log_artifact)r   r;   r<   rG   pred_artifactr   r   r   r)      s   z WandbEvalCallback.log_pred_table)
r   r   r	   r   r
   r   r   r   r   r   )N)r   r   r   r   )r%   r&   r   r   r   r   )r   r   r   r   )r6   r7   r8   )r9   r:   r;   r:   r<   r:   r   r   )rE   rF   N)r;   r:   r<   r:   rG   rH   r   r   )r/   
__module____qualname____doc__r   r$   r+   abcabstractmethodr!   r(   r    r'   r"   r)   __classcell__r   r   r   r   r      s$    F

r   )
__future__r   rR   typingr   tensorflow.keras.callbacksr   r   wandb.sdk.libr   ABCr   r   r   r   r   <module>   s    