o
    -wi"                     @   sX   d dl Z d dlmZmZmZ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 )    N)AnyDictListOptional)Callback)	telemetryc                
       sH  e Zd ZdZdee dee dededdf
 fdd	Zd&d
ee	ee
f  ddfddZd&ded
ee	ee
f  ddfddZejd&d
ee	ee
f  ddfddZej	d&ded
ee	ee
f  ddfddZdee ddfddZdee ddfddZ	d'dedededdfdd Z	!	"	d(deded#eee  ddfd$d%Z  ZS ))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pred_table_columnsargskwargsreturnNc                    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__ m/home/ubuntu/sommelier/.venv/lib/python3.10/site-packages/wandb/integration/keras/callbacks/tables_builder.pyr   Q   s   


zWandbEvalCallback.__init__logsc                 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_begine   s   
z WandbEvalCallback.on_train_beginepochc                 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_endm   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    u   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.
        )r.   N)r   r0   
pred_tabler2   r   r   r   r%      s   	z!WandbEvalCallback.init_pred_tablevaldatasetval_dataname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').
        r8   N)	r   Artifactaddr1   r   use_artifactwaitgetdata_table_ref)r   r7   r8   r9   data_artifactr   r   r   r!      s   z WandbEvalCallback.log_data_table
evaluation	eval_dataaliasesc                 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)rD   )r   r   r;   idr<   r3   log_artifact)r   r8   r9   rD   pred_artifactr   r   r   r'      s   z WandbEvalCallback.log_pred_table)N)r4   r5   r6   )rB   rC   N)r-   
__module____qualname____doc__r   strr   r   r   r   floatr#   intr)   abcabstractmethodr    r&   r   r%   r!   r'   __classcell__r   r   r   r   r   
   sd    F $"

r   )rQ   typingr   r   r   r   tensorflow.keras.callbacksr   r   wandb.sdk.libr   ABCr   r   r   r   r   <module>   s    