Как сбросить матрицу путаницы с помощью логгера TensorBoard в pytorch-lightning?

В официальном документе указано только

>>> from pytorch_lightning.metrics import ConfusionMatrix
>>> target = torch.tensor([1, 1, 0, 0])
>>> preds = torch.tensor([0, 1, 0, 0])
>>> confmat = ConfusionMatrix(num_classes=2)
>>> confmat(preds, target)

Это не показывает, как использовать метрику с фреймворком.

Моя попытка (методы не полные и показывают только соответствующие части):

def __init__(...):
    self.val_confusion = pl.metrics.classification.ConfusionMatrix(num_classes=self._config.n_clusters)

def validation_step(self, batch, batch_index):
    ...
    log_probs = self.forward(orig_batch)
    loss = self._criterion(log_probs, label_batch)
   
    self.val_confusion.update(log_probs, label_batch)
    self.log('validation_confusion_step', self.val_confusion, on_step=True, on_epoch=False)

def validation_step_end(self, outputs):
    return outputs

def validation_epoch_end(self, outs):
    self.log('validation_confusion_epoch', self.val_confusion.compute())

После 0-й эпохи это дает

    Traceback (most recent call last):
      File "C:\code\EPMD\Kodex\Templates\Testing\venv\lib\site-packages\pytorch_lightning\trainer\trainer.py", line 521, in train
        self.train_loop.run_training_epoch()
      File "C:\code\EPMD\Kodex\Templates\Testing\venv\lib\site-packages\pytorch_lightning\trainer\training_loop.py", line 588, in run_training_epoch
        self.trainer.run_evaluation(test_mode=False)
      File "C:\code\EPMD\Kodex\Templates\Testing\venv\lib\site-packages\pytorch_lightning\trainer\trainer.py", line 613, in run_evaluation
        self.evaluation_loop.log_evaluation_step_metrics(output, batch_idx)
      File "C:\code\EPMD\Kodex\Templates\Testing\venv\lib\site-packages\pytorch_lightning\trainer\evaluation_loop.py", line 346, in log_evaluation_step_metrics
        self.__log_result_step_metrics(step_log_metrics, step_pbar_metrics, batch_idx)
      File "C:\code\EPMD\Kodex\Templates\Testing\venv\lib\site-packages\pytorch_lightning\trainer\evaluation_loop.py", line 350, in __log_result_step_metrics
        cached_batch_pbar_metrics, cached_batch_log_metrics = cached_results.update_logger_connector()
      File "C:\code\EPMD\Kodex\Templates\Testing\venv\lib\site-packages\pytorch_lightning\trainer\connectors\logger_connector\epoch_result_store.py", line 378, in update_logger_connector
        batch_log_metrics = self.get_latest_batch_log_metrics()
      File "C:\code\EPMD\Kodex\Templates\Testing\venv\lib\site-packages\pytorch_lightning\trainer\connectors\logger_connector\epoch_result_store.py", line 418, in get_latest_batch_log_metrics
        batch_log_metrics = self.run_batch_from_func_name("get_batch_log_metrics")
      File "C:\code\EPMD\Kodex\Templates\Testing\venv\lib\site-packages\pytorch_lightning\trainer\connectors\logger_connector\epoch_result_store.py", line 414, in run_batch_from_func_name
        results = [func(include_forked_originals=False) for func in results]
      File "C:\code\EPMD\Kodex\Templates\Testing\venv\lib\site-packages\pytorch_lightning\trainer\connectors\logger_connector\epoch_result_store.py", line 414, in <listcomp>
        results = [func(include_forked_originals=False) for func in results]
      File "C:\code\EPMD\Kodex\Templates\Testing\venv\lib\site-packages\pytorch_lightning\trainer\connectors\logger_connector\epoch_result_store.py", line 122, in get_batch_log_metrics
        return self.run_latest_batch_metrics_with_func_name("get_batch_log_metrics",
*args, **kwargs)
      File "C:\code\EPMD\Kodex\Templates\Testing\venv\lib\site-packages\pytorch_lightning\trainer\connectors\logger_connector\epoch_result_store.py", line 115, in run_latest_batch_metrics_with_func_name
        for dl_idx in range(self.num_dataloaders)
      File "C:\code\EPMD\Kodex\Templates\Testing\venv\lib\site-packages\pytorch_lightning\trainer\connectors\logger_connector\epoch_result_store.py", line 115, in <listcomp>
        for dl_idx in range(self.num_dataloaders)
      File "C:\code\EPMD\Kodex\Templates\Testing\venv\lib\site-packages\pytorch_lightning\trainer\connectors\logger_connector\epoch_result_store.py", line 100, in get_latest_from_func_name
        results.update(func(*args, add_dataloader_idx=add_dataloader_idx, **kwargs))
      File "C:\code\EPMD\Kodex\Templates\Testing\venv\lib\site-packages\pytorch_lightning\core\step_result.py", line 298, in get_batch_log_metrics
        result[dl_key] = self[k]._forward_cache.detach()
    AttributeError: 'NoneType' object has no attribute 'detach'

                                                      

Он проходит проверку на вменяемость перед тренировкой.

Сбой происходит при возврате в validation_step_end. Для меня это не имеет особого смысла.

Точно такой же метод использования mertics отлично работает с точностью.

Как получить правильную матрицу неточностей?


person Gulzar    schedule 29.12.2020    source источник
comment
Предоставьте ожидаемый MRE. Покажите, где промежуточные результаты отличаются от ожидаемых. Мы должны иметь возможность вставить один блок вашего кода в файл, запустить его и воспроизвести вашу проблему. Это также позволяет нам проверять любые предложения в вашем контексте.   -  person Prune    schedule 30.12.2020
comment
Ссылка на документы, которую вы предоставляете, дает больше информации, чем вы предоставили в вопросе, а также более полный пример. Насколько я могу судить, ваш update в validation_step предполагает реализацию, несовместимую со структурой объекта ConfusionMatrix. Поскольку вы пропустили так много кода, мы не можем сказать; вы оставили нас, чтобы мы проверяли ваши неотслеживаемые фрагменты кода, а не тестировали.   -  person Prune    schedule 30.12.2020
comment
@Prune MRE невыполнимо, код машинного обучения берет хотя бы набор данных и config. Это просто вопрос, из-за которого не хватает документа, и мой воспроизводимый текст в любом случае бесполезен, я просто хочу увидеть правильное использование. Скажите, пожалуйста, какая часть документа мне не хватает? Очевидно, моя реализация не такая, как ожидалось, но я также не понимаю, что ожидается, поскольку я использую то же самое, что и в примере с более полной точностью.   -  person Gulzar    schedule 30.12.2020
comment
Пример точности в самом документе не является MRE, потому что в этом случае он менее читабелен ... pytorch-lightning.readthedocs.io/en/stable/metrics.html   -  person Gulzar    schedule 30.12.2020


Ответы (2)


Вы можете сообщить эту цифру, используя self.logger.experiment.add_figure(*tag*, *figure*).

Переменная self.logger.experiment на самом деле SummaryWriter (от PyTorch, а не от Lightning). В этом классе есть метод add_figure (документация).

Вы можете использовать его следующим образом: (пример MNIST)

    def validation_step(self, batch, batch_idx):
        x, y = batch
        preds = self(x)
        loss = F.nll_loss(preds, y)
        return { 'loss': loss, 'preds': preds, 'target': y}

    def validation_epoch_end(self, outputs):
        preds = torch.cat([tmp['preds'] for tmp in outputs])
        targets = torch.cat([tmp['target'] for tmp in outputs])
        confusion_matrix = pl.metrics.functional.confusion_matrix(preds, targets, num_classes=10)

        df_cm = pd.DataFrame(confusion_matrix.numpy(), index = range(10), columns=range(10))
        plt.figure(figsize = (10,7))
        fig_ = sns.heatmap(df_cm, annot=True, cmap='Spectral').get_figure()
        plt.close(fig_)
        
        self.logger.experiment.add_figure("Confusion matrix", fig_, self.current_epoch)
person Yorick    schedule 08.01.2021
comment
Замечательно! принял твой вместо моего - person Gulzar; 11.01.2021

На это ушло много времени.

Это самый минимальный код, который я мог вставить, который все еще читается и воспроизводится.

Я не хотел помещать здесь весь набор данных модели и параметры, поскольку они не представляют интереса для читателей этого вопроса и представляют собой просто шум.


Тем не менее, вот необходимый код для создания матрицы путаницы для каждой эпохи и отображения в Tensorboard

Например, это одиночный кадр:

введите описание изображения здесь


import pytorch_lightning as pl
import seaborn as sn
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image

def __init__(self, config, trained_vae, latent_dim):
    self.val_confusion = pl.metrics.classification.ConfusionMatrix(num_classes=self._config.n_clusters)
    self.logger: Optional[TensorBoardLogger] = None

def forward(self, x):
    ...
    return log_probs

def validation_step(self, batch, batch_index):
    if self._config.dataset == "mnist":
        orig_batch, label_batch = batch
        orig_batch = orig_batch.reshape(-1, 28 * 28)

    log_probs = self.forward(orig_batch)
    loss = self._criterion(log_probs, label_batch)

    self.val_confusion.update(log_probs, label_batch)
    return {"loss": loss, "labels": label_batch}

def validation_step_end(self, outputs):
    return outputs

def validation_epoch_end(self, outs):
    tb = self.logger.experiment

    # confusion matrix
    conf_mat = self.val_confusion.compute().detach().cpu().numpy().astype(np.int)
    df_cm = pd.DataFrame(
        conf_mat,
        index=np.arange(self._config.n_clusters),
        columns=np.arange(self._config.n_clusters))
    plt.figure()
    sn.set(font_scale=1.2)
    sn.heatmap(df_cm, annot=True, annot_kws={"size": 16}, fmt='d')
    buf = io.BytesIO()
    
    plt.savefig(buf, format='jpeg')
    buf.seek(0)
    im = Image.open(buf)
    im = torchvision.transforms.ToTensor()(im)
    tb.add_image("val_confusion_matrix", im, global_step=self.current_epoch)

и звонок тренеру

logger = TensorBoardLogger(save_dir=tb_logs_folder, name='Classifier')
trainer = Trainer(deterministic=True,
                  max_epochs=10,
                  default_root_dir=classifier_checkpoints_path,
                  logger=logger,
                  gpus=1
                  )
person Gulzar    schedule 30.12.2020