Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: ValueError: Image result predicted mask is None. on model Ganomaly #2432

Open
1 task done
Ly-Lynn opened this issue Nov 24, 2024 · 2 comments
Open
1 task done

Comments

@Ly-Lynn
Copy link

Ly-Lynn commented Nov 24, 2024

Describe the bug

Hello authors,
I had followed exactly the description for implementation on the jupyter notebook, however, when it came to testing, I got this bug.

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[30], line 1
----> 1 engine.test(datamodule=datamodule, model=model)

File /opt/conda/lib/python3.10/site-packages/anomalib/engine/engine.py:696, in Engine.test(self, model, dataloaders, ckpt_path, verbose, datamodule)
    694     logger.info("Running validation before testing to collect normalization metrics and/or thresholds.")
    695     self.trainer.validate(model, dataloaders, None, verbose=False, datamodule=datamodule)
--> 696 return self.trainer.test(model, dataloaders, ckpt_path, verbose, datamodule)

File /opt/conda/lib/python3.10/site-packages/lightning/pytorch/trainer/trainer.py:748, in Trainer.test(self, model, dataloaders, ckpt_path, verbose, datamodule)
    746 self.state.status = TrainerStatus.RUNNING
    747 self.testing = True
--> 748 return call._call_and_handle_interrupt(
    749     self, self._test_impl, model, dataloaders, ckpt_path, verbose, datamodule
    750 )

File /opt/conda/lib/python3.10/site-packages/lightning/pytorch/trainer/call.py:47, in _call_and_handle_interrupt(trainer, trainer_fn, *args, **kwargs)
     45     if trainer.strategy.launcher is not None:
     46         return trainer.strategy.launcher.launch(trainer_fn, *args, trainer=trainer, **kwargs)
---> 47     return trainer_fn(*args, **kwargs)
     49 except _TunerExitException:
     50     _call_teardown_hook(trainer)

File /opt/conda/lib/python3.10/site-packages/lightning/pytorch/trainer/trainer.py:788, in Trainer._test_impl(self, model, dataloaders, ckpt_path, verbose, datamodule)
    784 assert self.state.fn is not None
    785 ckpt_path = self._checkpoint_connector._select_ckpt_path(
    786     self.state.fn, ckpt_path, model_provided=model_provided, model_connected=self.lightning_module is not None
    787 )
--> 788 results = self._run(model, ckpt_path=ckpt_path)
    789 # remove the tensors from the test results
    790 results = convert_tensors_to_scalars(results)

File /opt/conda/lib/python3.10/site-packages/lightning/pytorch/trainer/trainer.py:981, in Trainer._run(self, model, ckpt_path)
    976 self._signal_connector.register_signal_handlers()
    978 # ----------------------------
    979 # RUN THE TRAINER
    980 # ----------------------------
--> 981 results = self._run_stage()
    983 # ----------------------------
    984 # POST-Training CLEAN UP
    985 # ----------------------------
    986 log.debug(f"{self.__class__.__name__}: trainer tearing down")

File /opt/conda/lib/python3.10/site-packages/lightning/pytorch/trainer/trainer.py:1018, in Trainer._run_stage(self)
   1015 self.lightning_module.zero_grad()
   1017 if self.evaluating:
-> 1018     return self._evaluation_loop.run()
   1019 if self.predicting:
   1020     return self.predict_loop.run()

File /opt/conda/lib/python3.10/site-packages/lightning/pytorch/loops/utilities.py:178, in _no_grad_context.<locals>._decorator(self, *args, **kwargs)
    176     context_manager = torch.no_grad
    177 with context_manager():
--> 178     return loop_run(self, *args, **kwargs)

File /opt/conda/lib/python3.10/site-packages/lightning/pytorch/loops/evaluation_loop.py:135, in _EvaluationLoop.run(self)
    133     self.batch_progress.is_last_batch = data_fetcher.done
    134     # run step hooks
--> 135     self._evaluation_step(batch, batch_idx, dataloader_idx, dataloader_iter)
    136 except StopIteration:
    137     # this needs to wrap the `*_step` call too (not just `next`) for `dataloader_iter` support
    138     break

File /opt/conda/lib/python3.10/site-packages/lightning/pytorch/loops/evaluation_loop.py:410, in _EvaluationLoop._evaluation_step(self, batch, batch_idx, dataloader_idx, dataloader_iter)
    405     hook_kwargs = self._build_kwargs(
    406         batch, batch_idx, dataloader_idx if self._is_sequential and self.num_dataloaders > 1 else None
    407     )
    409 hook_name = "on_test_batch_end" if trainer.testing else "on_validation_batch_end"
--> 410 call._call_callback_hooks(trainer, hook_name, output, *hook_kwargs.values())
    411 call._call_lightning_module_hook(trainer, hook_name, output, *hook_kwargs.values())
    413 trainer._logger_connector.on_batch_end()

File /opt/conda/lib/python3.10/site-packages/lightning/pytorch/trainer/call.py:218, in _call_callback_hooks(trainer, hook_name, monitoring_callbacks, *args, **kwargs)
    216     if callable(fn):
    217         with trainer.profiler.profile(f"[Callback]{callback.state_key}.{hook_name}"):
--> 218             fn(trainer, trainer.lightning_module, *args, **kwargs)
    220 if pl_module:
    221     # restore current_fx when nested context
    222     pl_module._current_fx_name = prev_fx_name

File /opt/conda/lib/python3.10/site-packages/anomalib/callbacks/visualizer.py:88, in _VisualizationCallback.on_test_batch_end(self, trainer, pl_module, outputs, batch, batch_idx, dataloader_idx)
     86 for generator in self.generators:
     87     if generator.visualize_on == VisualizationStep.BATCH:
---> 88         for result in generator(
     89             trainer=trainer,
     90             pl_module=pl_module,
     91             outputs=outputs,
     92             batch=batch,
     93             batch_idx=batch_idx,
     94             dataloader_idx=dataloader_idx,
     95         ):
     96             if self.save:
     97                 if result.file_name is None:

File /opt/conda/lib/python3.10/site-packages/anomalib/utils/visualization/image.py:173, in ImageVisualizer._visualize_batch(self, batch)
    159     file_name = Path(batch["video_path"][i]) / suffix
    161 image_result = ImageResult(
    162     image=image,
    163     pred_score=batch["pred_scores"][i].cpu().numpy().item() if "pred_scores" in batch else None,
   (...)
    171     normalize=self.normalize,
    172 )
--> 173 yield GeneratorResult(image=self.visualize_image(image_result), file_name=file_name)

File /opt/conda/lib/python3.10/site-packages/anomalib/utils/visualization/image.py:185, in ImageVisualizer.visualize_image(self, image_result)
    176 """Generate the visualization for an image.
    177 
    178 Args:
   (...)
    182     The full or simple visualization for the image, depending on the specified mode.
    183 """
    184 if self.mode == VisualizationMode.FULL:
--> 185     return self._visualize_full(image_result)
    186 if self.mode == VisualizationMode.SIMPLE:
    187     return self._visualize_simple(image_result)

File /opt/conda/lib/python3.10/site-packages/anomalib/utils/visualization/image.py:222, in ImageVisualizer._visualize_full(self, image_result)
    220 if image_result.pred_mask is None:
    221     msg = "Image result predicted mask is None."
--> 222     raise ValueError(msg)
    224 image_grid.add_image(image_result.image, "Image")
    225 if image_result.gt_mask is not None:

ValueError: Image result predicted mask is None.

Here is my code

model = Ganomaly()
callbacks = [
    ModelCheckpoint(
        monitor="image_AUROC",
        mode="max",
        save_top_k=1,
        filename="best-ganomaly-{epoch:02d}-{image_AUROC:.4f}",
        save_last=True,
    ),
    EarlyStopping(
        monitor="image_AUROC", 
        mode="max",
        patience=3,        
        min_delta=0.001,     
    ),
]
engine = Engine(
    callbacks=callbacks,
    gradient_clip_val=1.0,    
    accelerator="auto",
    devices="auto",        
    logger=True,             
)
engine.fit(datamodule=datamodule, model=model)
engine.test(datamodule=datamodule, model=model)

Are there any issues with my code and config?
If so, could you suggest some ways to fix them?
Thank you very much!

Dataset

MVTec

Model

GANomaly

Steps to reproduce the behavior

model = Ganomaly()
callbacks = [
    ModelCheckpoint(
        monitor="image_AUROC",
        mode="max",
        save_top_k=1,
        filename="best-ganomaly-{epoch:02d}-{image_AUROC:.4f}",
        save_last=True,
    ),
    EarlyStopping(
        monitor="image_AUROC", 
        mode="max",
        patience=3,        
        min_delta=0.001,     
    ),
]
engine = Engine(
    callbacks=callbacks,
    gradient_clip_val=1.0,    
    accelerator="auto",
    devices="auto",        
    logger=True,             
)
engine.fit(datamodule=datamodule, model=model)
engine.test(datamodule=datamodule, model=model)

OS information

OS information:

  • OS: [e.g. Ubuntu 20.04]
  • Python version: [e.g. 3.10.0]
  • Anomalib version: [e.g. 0.3.6]
  • PyTorch version: [e.g. 1.9.0]
  • CUDA/cuDNN version: [e.g. 11.1]
  • GPU models and configuration: [e.g. 2x GeForce RTX 3090]
  • Any other relevant information: [e.g. I'm using a custom dataset]

Expected behavior

I believe the output should resemble the introduction in Jupyter Notebook.
I'm unsure about the error I encountered after switching the model to Ganomaly.

Screenshots

No response

Pip/GitHub

pip

What version/branch did you use?

No response

Configuration YAML

None

Logs

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[30], line 1
----> 1 engine.test(datamodule=datamodule, model=model)

File /opt/conda/lib/python3.10/site-packages/anomalib/engine/engine.py:696, in Engine.test(self, model, dataloaders, ckpt_path, verbose, datamodule)
    694     logger.info("Running validation before testing to collect normalization metrics and/or thresholds.")
    695     self.trainer.validate(model, dataloaders, None, verbose=False, datamodule=datamodule)
--> 696 return self.trainer.test(model, dataloaders, ckpt_path, verbose, datamodule)

File /opt/conda/lib/python3.10/site-packages/lightning/pytorch/trainer/trainer.py:748, in Trainer.test(self, model, dataloaders, ckpt_path, verbose, datamodule)
    746 self.state.status = TrainerStatus.RUNNING
    747 self.testing = True
--> 748 return call._call_and_handle_interrupt(
    749     self, self._test_impl, model, dataloaders, ckpt_path, verbose, datamodule
    750 )

File /opt/conda/lib/python3.10/site-packages/lightning/pytorch/trainer/call.py:47, in _call_and_handle_interrupt(trainer, trainer_fn, *args, **kwargs)
     45     if trainer.strategy.launcher is not None:
     46         return trainer.strategy.launcher.launch(trainer_fn, *args, trainer=trainer, **kwargs)
---> 47     return trainer_fn(*args, **kwargs)
     49 except _TunerExitException:
     50     _call_teardown_hook(trainer)

File /opt/conda/lib/python3.10/site-packages/lightning/pytorch/trainer/trainer.py:788, in Trainer._test_impl(self, model, dataloaders, ckpt_path, verbose, datamodule)
    784 assert self.state.fn is not None
    785 ckpt_path = self._checkpoint_connector._select_ckpt_path(
    786     self.state.fn, ckpt_path, model_provided=model_provided, model_connected=self.lightning_module is not None
    787 )
--> 788 results = self._run(model, ckpt_path=ckpt_path)
    789 # remove the tensors from the test results
    790 results = convert_tensors_to_scalars(results)

File /opt/conda/lib/python3.10/site-packages/lightning/pytorch/trainer/trainer.py:981, in Trainer._run(self, model, ckpt_path)
    976 self._signal_connector.register_signal_handlers()
    978 # ----------------------------
    979 # RUN THE TRAINER
    980 # ----------------------------
--> 981 results = self._run_stage()
    983 # ----------------------------
    984 # POST-Training CLEAN UP
    985 # ----------------------------
    986 log.debug(f"{self.__class__.__name__}: trainer tearing down")

File /opt/conda/lib/python3.10/site-packages/lightning/pytorch/trainer/trainer.py:1018, in Trainer._run_stage(self)
   1015 self.lightning_module.zero_grad()
   1017 if self.evaluating:
-> 1018     return self._evaluation_loop.run()
   1019 if self.predicting:
   1020     return self.predict_loop.run()

File /opt/conda/lib/python3.10/site-packages/lightning/pytorch/loops/utilities.py:178, in _no_grad_context.<locals>._decorator(self, *args, **kwargs)
    176     context_manager = torch.no_grad
    177 with context_manager():
--> 178     return loop_run(self, *args, **kwargs)

File /opt/conda/lib/python3.10/site-packages/lightning/pytorch/loops/evaluation_loop.py:135, in _EvaluationLoop.run(self)
    133     self.batch_progress.is_last_batch = data_fetcher.done
    134     # run step hooks
--> 135     self._evaluation_step(batch, batch_idx, dataloader_idx, dataloader_iter)
    136 except StopIteration:
    137     # this needs to wrap the `*_step` call too (not just `next`) for `dataloader_iter` support
    138     break

File /opt/conda/lib/python3.10/site-packages/lightning/pytorch/loops/evaluation_loop.py:410, in _EvaluationLoop._evaluation_step(self, batch, batch_idx, dataloader_idx, dataloader_iter)
    405     hook_kwargs = self._build_kwargs(
    406         batch, batch_idx, dataloader_idx if self._is_sequential and self.num_dataloaders > 1 else None
    407     )
    409 hook_name = "on_test_batch_end" if trainer.testing else "on_validation_batch_end"
--> 410 call._call_callback_hooks(trainer, hook_name, output, *hook_kwargs.values())
    411 call._call_lightning_module_hook(trainer, hook_name, output, *hook_kwargs.values())
    413 trainer._logger_connector.on_batch_end()

File /opt/conda/lib/python3.10/site-packages/lightning/pytorch/trainer/call.py:218, in _call_callback_hooks(trainer, hook_name, monitoring_callbacks, *args, **kwargs)
    216     if callable(fn):
    217         with trainer.profiler.profile(f"[Callback]{callback.state_key}.{hook_name}"):
--> 218             fn(trainer, trainer.lightning_module, *args, **kwargs)
    220 if pl_module:
    221     # restore current_fx when nested context
    222     pl_module._current_fx_name = prev_fx_name

File /opt/conda/lib/python3.10/site-packages/anomalib/callbacks/visualizer.py:88, in _VisualizationCallback.on_test_batch_end(self, trainer, pl_module, outputs, batch, batch_idx, dataloader_idx)
     86 for generator in self.generators:
     87     if generator.visualize_on == VisualizationStep.BATCH:
---> 88         for result in generator(
     89             trainer=trainer,
     90             pl_module=pl_module,
     91             outputs=outputs,
     92             batch=batch,
     93             batch_idx=batch_idx,
     94             dataloader_idx=dataloader_idx,
     95         ):
     96             if self.save:
     97                 if result.file_name is None:

File /opt/conda/lib/python3.10/site-packages/anomalib/utils/visualization/image.py:173, in ImageVisualizer._visualize_batch(self, batch)
    159     file_name = Path(batch["video_path"][i]) / suffix
    161 image_result = ImageResult(
    162     image=image,
    163     pred_score=batch["pred_scores"][i].cpu().numpy().item() if "pred_scores" in batch else None,
   (...)
    171     normalize=self.normalize,
    172 )
--> 173 yield GeneratorResult(image=self.visualize_image(image_result), file_name=file_name)

File /opt/conda/lib/python3.10/site-packages/anomalib/utils/visualization/image.py:185, in ImageVisualizer.visualize_image(self, image_result)
    176 """Generate the visualization for an image.
    177 
    178 Args:
   (...)
    182     The full or simple visualization for the image, depending on the specified mode.
    183 """
    184 if self.mode == VisualizationMode.FULL:
--> 185     return self._visualize_full(image_result)
    186 if self.mode == VisualizationMode.SIMPLE:
    187     return self._visualize_simple(image_result)

File /opt/conda/lib/python3.10/site-packages/anomalib/utils/visualization/image.py:222, in ImageVisualizer._visualize_full(self, image_result)
    220 if image_result.pred_mask is None:
    221     msg = "Image result predicted mask is None."
--> 222     raise ValueError(msg)
    224 image_grid.add_image(image_result.image, "Image")
    225 if image_result.gt_mask is not None:

ValueError: Image result predicted mask is None.

Code of Conduct

  • I agree to follow this project's Code of Conduct
@clausMeko
Copy link

I can confirm the error on my side.

@samet-akcay
Copy link
Contributor

samet-akcay commented Nov 30, 2024

I think the reason is Ganomaly is a classification model, but Engine is trying to visualise its segmentation mask with VisualizationMode.FULL, which tries to access segmentation masks that are not available.

I believe this has already been addressed in v2, which we plan to release mid December.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants