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

metrics[0]: add per-image overlap (pimo) [GSoC 2023 @ OpenVINO] #1247

Merged
merged 40 commits into from
Aug 23, 2023

Conversation

jpcbertoldo
Copy link
Contributor

@jpcbertoldo jpcbertoldo commented Aug 9, 2023

Description

This is part of Anomaly Segmentation Metrics for Anomalib — GSoC 2023 @ OpenVINO.

Previously in #1220

Per-Image Overlap (PImO)

Adding the metric Per-Image Overlap (PImO) and its area under the curve (AUC).

At each given threshold:

  • X-axis: in-image FPR average on normal images (equivalent to the set FPR of normal images).
  • Y-axis: Overlap between the class 'anomalous' in the ground truth and the predicted masks (in-image TPR).

I choose the vocabulary 'overlap' insted of TPR because it echoes with the Per-Region Overlap (PRO).


binclf curve

The per-image overlap (tpr) needs the binary classification matrix curve (binclf curve), which has to be computed per image , while they must share the thresholds (Since the x-axis (FPR) is shared).

You'll find a weird-looking funciton using itertools to compute thos binclf curves, which i found to be much faster on CPU than the two alternatives in torchmetrics (the latter mentioned in the former's doc) -- image below shows some WIP comparisons; a proper version on the way.

image

However, there is a tensor.cpu().numpy() in there, and I only tested with tensors already in the CPU.
Perhaps when using tensors in the GPU that operation might make the fastest algorithm change?

  • Fixes # (issue)

Changes

  • Bug fix (non-breaking change which fixes an issue)
  • Refactor (non-breaking change which refactors the code base)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

Checklist

  • My code follows the pre-commit style and check guidelines of this project.
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing tests pass locally with my changes
  • I have added a summary of my changes to the CHANGELOG (not for minor changes, docs and tests).

jpcbertoldo and others added 30 commits July 27, 2023 23:34
* New printing stuff

* Remove dead code + address codacy issues

* Refactor try/except + log to comet/wandb during runs

* pre-commit error

* third-party configuration

---------

Co-authored-by: Ashwin Vaidya <[email protected]>
* ignore mask check when dataset has only normal samples

* update changelog
Revert "🚚 Refactor Benchmarking Script (openvinotoolkit#1216)"

This reverts commit 784767f.
* Fix metadata path

* Update benchmarking notebook
@github-actions github-actions bot added Tests Notebooks and removed Metrics Metric Component. labels Aug 9, 2023
@jpcbertoldo
Copy link
Contributor Author

image

there is an issue with the feature branch it seems, could you enable codacy?

@jpcbertoldo
Copy link
Contributor Author

image

This coverage issue it because I saved the notebook with the kernel name in my loca environment (anomalib-dev-gsoc).
Can we ignore it for now and solve it in a later PR?

Copy link
Contributor

@samet-akcay samet-akcay left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jpcbertoldo, thanks for this! I just have minor comments, majority of which are naming-related.

@@ -20,9 +20,22 @@
from .collection import AnomalibMetricCollection
from .min_max import MinMax
from .optimal_f1 import OptimalF1
from .perimg import AUPImO, PerImageBinClfCurve, PImO
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this be per_img instead?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to name PerImageBinClfCurve something more explicit. BinClf may not be obvious initially. Do you think if PerImageBinaryClassificationCurve would be too verbose?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used PerImageBinaryClassificationCurve at first but it feels very wordy and some lines will become tough to read.
binclf is what I found in torchmetrics so i copied them.

per_img i think it's ok; put it in the list of refactors.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is common.py needed? Could these be in __init__.py. Or alternatively, can this be a utils.py?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add doctoring and other headers as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is common.py needed? Could these be in __init__.py. Or alternatively, can this be a utils.py?

In __init__.py it would create circular imports (in future PRs).

common.py -> utils.py is fine IMO, but it will later have more things inside that are not really "utils". I'll add this to the refactors.

Copy link
Contributor Author

@jpcbertoldo jpcbertoldo Aug 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add doctoring and other headers as well?

Sure. I'll add the docstrings, but what other headers specifically (apart from license)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add doctoring and other headers as well?

Sure. I'll add the docstrings, but what other headers specifically (apart from license)?

I reviewed and incremented module docstrings in a future PR.

jpcbertoldo@621f58e

src/anomalib/utils/metrics/perimg/pimo.py Show resolved Hide resolved

# =========================================== METRICS ===========================================

PImOResult = namedtuple(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you have any specific motivation why use named tuple instead of data class. I was just curious :) Just preference or any other motivation?

Copy link
Contributor Author

@jpcbertoldo jpcbertoldo Aug 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes and more or less.

It's possible to just unpack the things, like

_, __, shared_fpr, tprs, image_classes = self.compute()

Also it's just a tuple, I think it makes user code less dependent on in-anomalib classes. I tend to use it for this type of case where I actually just want to return many things but there are so many that it's easier to document it as a namedtuple. I noticed scipy does something similar (?).

Otherwise I'm a big fan of dataclass : )

src/anomalib/utils/metrics/perimg/common.py Show resolved Hide resolved
src/anomalib/utils/metrics/perimg/common.py Show resolved Hide resolved
src/anomalib/utils/metrics/perimg/common.py Show resolved Hide resolved
@jpcbertoldo
Copy link
Contributor Author

List of refactors before merging feature branch:
https://github.com/jpcbertoldo/anomalib/blob/metrics/refactors/src/anomalib/utils/metrics/perimg/.refactors

Adds from this PR

1. rename `perimg` to `per_img`
  1.1 in functions
  1.2 the module
2. rename`common.py` to `utils.py`
3. add license header to files
4. remove `.ignore`
5. rename `atleast` to `at_least` (?)

@jpcbertoldo
Copy link
Contributor Author

@samet-akcay i put the naming issues in the todo list for the final refactor
i think we can merge this and move to the next PR?

@samet-akcay
Copy link
Contributor

@samet-akcay i put the naming issues in the todo list for the final refactor
i think we can merge this and move to the next PR?

Notebook tests are failing due to your notebook, but you could address that later too

@samet-akcay samet-akcay merged commit 103c22c into openvinotoolkit:feature/pimo Aug 23, 2023
@jpcbertoldo jpcbertoldo changed the title metrics[0]: add per-image overlap (pimo) metrics[0]: add per-image overlap (pimo) [GSoC 2023 @ OpenVINO Aug 24, 2023
@jpcbertoldo jpcbertoldo changed the title metrics[0]: add per-image overlap (pimo) [GSoC 2023 @ OpenVINO metrics[0]: add per-image overlap (pimo) [GSoC 2023 @ OpenVINO] Aug 24, 2023
@jpcbertoldo jpcbertoldo deleted the metrics/root branch February 9, 2024 12:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants