From 5a567fa91647db02de045114e7e5b52337e2ff39 Mon Sep 17 00:00:00 2001 From: F-G Fernandez <26927750+frgfm@users.noreply.github.com> Date: Sat, 16 Sep 2023 16:42:42 +0200 Subject: [PATCH 1/5] chore: Bumps torch and torchvision --- .conda/meta.yaml | 6 +++--- .pre-commit-config.yaml | 2 +- pyproject.toml | 12 +++++++----- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/.conda/meta.yaml b/.conda/meta.yaml index e89216f..6f5e932 100644 --- a/.conda/meta.yaml +++ b/.conda/meta.yaml @@ -22,9 +22,9 @@ requirements: - setuptools run: - - pytorch >=1.7.0, <2.0.0 - - numpy >=1.14.0, <2.0.0 - - pillow >=8.3.2 + - pytorch >=2.0.0, <3.0.0 + - numpy >=1.17.2, <2.0.0 + - pillow >=8.4.0, !=9.2.0 - matplotlib >=3.0.0, <4.0.0 test: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 55d02fb..b302143 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -22,7 +22,7 @@ repos: hooks: - id: black - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: 'v0.0.278' + rev: 'v0.0.289' hooks: - id: ruff args: diff --git a/pyproject.toml b/pyproject.toml index 7fd25d8..8d8795f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,10 +30,12 @@ classifiers = [ dynamic = ["version"] dependencies = [ # cf. https://github.com/frgfm/torch-cam/discussions/148 - "torch>=1.7.0,<2.0.0", + "torch>=2.0.0,<3.0.0", "numpy>=1.14.0,<2.0.0", # cf. https://github.com/advisories/GHSA-98vv-pw6r-q6q4 - "Pillow>=8.3.2", + # cf. https://github.com/pytorch/vision/issues/4934 + # https://github.com/frgfm/Holocron/security/dependabot/5 + "Pillow>=8.4.0,!=9.2.0", "matplotlib>=3.0.0,<4.0.0", ] @@ -42,7 +44,7 @@ test = [ "pytest>=5.3.2", "coverage[toml]>=4.5.4", "requests>=2.20.0,<3.0.0", - "torchvision>=0.4.0,<1.0.0", + "torchvision>=0.15.0,<1.0.0", ] quality = [ "ruff>=0.0.273,<1.0.0", @@ -64,14 +66,14 @@ docs = [ ] demo = [ "streamlit>=0.65.0,<2.0.0", - "torchvision>=0.12.0,<1.0.0", + "torchvision>=0.15.0,<1.0.0", ] dev = [ # test "pytest>=5.3.2", "coverage[toml]>=4.5.4", "requests>=2.20.0,<3.0.0", - "torchvision>=0.4.0,<1.0.0", + "torchvision>=0.15.0,<1.0.0", # style "ruff>=0.0.273,<1.0.0", "mypy==1.4.1", From a08f3303bc680f49228fa49c9cc550abf70482f2 Mon Sep 17 00:00:00 2001 From: F-G Fernandez <26927750+frgfm@users.noreply.github.com> Date: Sat, 16 Sep 2023 16:43:46 +0200 Subject: [PATCH 2/5] chore: Bumps ruff --- .pre-commit-config.yaml | 2 +- pyproject.toml | 27 +++++++++++++++++++-------- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b302143..e4b5108 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -22,7 +22,7 @@ repos: hooks: - id: black - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: 'v0.0.289' + rev: 'v0.0.290' hooks: - id: ruff args: diff --git a/pyproject.toml b/pyproject.toml index 8d8795f..853053a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,6 +23,7 @@ classifiers = [ "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", "Topic :: Scientific/Engineering", "Topic :: Scientific/Engineering :: Mathematics", "Topic :: Scientific/Engineering :: Artificial Intelligence", @@ -47,7 +48,7 @@ test = [ "torchvision>=0.15.0,<1.0.0", ] quality = [ - "ruff>=0.0.273,<1.0.0", + "ruff>=0.0.290,<1.0.0", "mypy==1.4.1", "black==23.3.0", "bandit[toml]>=1.7.0,<1.8.0", @@ -75,7 +76,7 @@ dev = [ "requests>=2.20.0,<3.0.0", "torchvision>=0.15.0,<1.0.0", # style - "ruff>=0.0.273,<1.0.0", + "ruff>=0.0.290,<1.0.0", "mypy==1.4.1", "black==23.3.0", "bandit[toml]>=1.7.0,<1.8.0", @@ -113,7 +114,7 @@ select = [ "D201","D202","D207","D208","D214","D215","D300","D301","D417", "D419", # pydocstyle "F", # pyflakes "I", # isort - "C", # flake8-comprehensions + "C4", # flake8-comprehensions "B", # flake8-bugbear "CPY001", # flake8-copyright "ISC", # flake8-implicit-str-concat @@ -121,6 +122,13 @@ select = [ "NPY", # numpy "PERF", # perflint "RUF", # ruff specific + "PTH", # flake8-use-pathlib + "S", # flake8-bandit + "N", # pep8-naming + "T10", # flake8-debugger + "T20", # flake8-print + "PT", # flake8-pytest-style + "LOG", # flake8-logging ] ignore = [ "E501", # line too long, handled by black @@ -130,28 +138,31 @@ ignore = [ "F403", # star imports "E731", # lambda assignment "C416", # list comprehension to list() + "N812", # lowercase imported as non-lowercase ] exclude = [".git"] line-length = 120 target-version = "py39" +preview = true [tool.ruff.per-file-ignores] "**/__init__.py" = ["I001", "F401", "CPY001"] -"scripts/**.py" = ["D"] -".github/**.py" = ["D"] +"scripts/**.py" = ["D", "T201", "N812"] +".github/**.py" = ["D", "T201", "S602"] "docs/**.py" = ["E402", "D103"] -"tests/**.py" = ["D103", "CPY001"] +"tests/**.py" = ["D103", "CPY001", "S101", "PT011",] "demo/**.py" = ["D103"] +"setup.py" = ["T201"] [tool.ruff.flake8-quotes] docstring-quotes = "double" [tool.ruff.isort] -known-first-party = ["app"] +known-first-party = ["torchcam", "app"] known-third-party = ["torch", "torchvision"] [tool.mypy] -python_version = "3.8" +python_version = "3.9" files = "torchcam/" show_error_codes = true pretty = true From 1f94494451085ccf38bcfa88cea907ab44b90146 Mon Sep 17 00:00:00 2001 From: F-G Fernandez <26927750+frgfm@users.noreply.github.com> Date: Sat, 16 Sep 2023 16:44:07 +0200 Subject: [PATCH 3/5] ci: Bumps CI to Python 3.9 --- .github/collect_env.py | 37 +++++++++++++---------------- .github/workflows/demo.yml | 2 +- .github/workflows/doc-status.yml | 5 ++-- .github/workflows/docs.yaml | 2 +- .github/workflows/pull_requests.yml | 2 +- .github/workflows/release.yml | 8 +++---- .github/workflows/scripts.yml | 4 ++-- .github/workflows/style.yml | 8 +++---- .github/workflows/tests.yml | 2 +- 9 files changed, 33 insertions(+), 37 deletions(-) diff --git a/.github/collect_env.py b/.github/collect_env.py index 844d0d8..2cf8777 100644 --- a/.github/collect_env.py +++ b/.github/collect_env.py @@ -16,7 +16,8 @@ import re import subprocess import sys -from collections import namedtuple +from pathlib import Path +from typing import NamedTuple try: import torchcam @@ -36,20 +37,16 @@ # System Environment Information -SystemEnv = namedtuple( - "SystemEnv", - [ - "torchcam_version", - "torch_version", - "os", - "python_version", - "is_cuda_available", - "cuda_runtime_version", - "nvidia_driver_version", - "nvidia_gpu_models", - "cudnn_version", - ], -) +class SystemEnv(NamedTuple): + torchcam_version: str + torch_version: str + os: str + python_version: str + is_cuda_available: bool + cuda_runtime_version: str + nvidia_driver_version: str + nvidia_gpu_models: str + cudnn_version: str def run(command): @@ -125,13 +122,13 @@ def get_cudnn_version(run_lambda): # find will return 1 if there are permission errors or if not found if len(out) == 0 or rc not in (1, 0): lib = os.environ.get("CUDNN_LIBRARY") - if lib is not None and os.path.isfile(lib): + if lib is not None and Path(lib).is_file(): return os.path.realpath(lib) return None files = set() for fn in out.split("\n"): fn = os.path.realpath(fn) # eliminate symbolic links - if os.path.isfile(fn): + if Path(fn).is_file(): files.add(fn) if not files: return None @@ -149,11 +146,11 @@ def get_nvidia_smi(): if get_platform() == "win32": system_root = os.environ.get("SYSTEMROOT", "C:\\Windows") program_files_root = os.environ.get("PROGRAMFILES", "C:\\Program Files") - legacy_path = os.path.join(program_files_root, "NVIDIA Corporation", "NVSMI", smi) - new_path = os.path.join(system_root, "System32", smi) + legacy_path = Path(program_files_root) / "NVIDIA Corporation" / "NVSMI" / smi + new_path = Path(system_root) / "System32" / smi smis = [new_path, legacy_path] for candidate_smi in smis: - if os.path.exists(candidate_smi): + if Path(candidate_smi).exists(): smi = '"{}"'.format(candidate_smi) break return smi diff --git a/.github/workflows/demo.yml b/.github/workflows/demo.yml index ed24153..65b5e71 100644 --- a/.github/workflows/demo.yml +++ b/.github/workflows/demo.yml @@ -13,7 +13,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest] - python: [3.8, 3.9] + python: [3.9] steps: - uses: actions/checkout@v2 - name: Set up Python diff --git a/.github/workflows/doc-status.yml b/.github/workflows/doc-status.yml index 017a798..d2f2d9d 100644 --- a/.github/workflows/doc-status.yml +++ b/.github/workflows/doc-status.yml @@ -6,10 +6,9 @@ jobs: see-page-build-payload: runs-on: ubuntu-latest steps: - - name: Set up Python - uses: actions/setup-python@v4 + - uses: actions/setup-python@v4 with: - python-version: 3.8 + python-version: 3.9 architecture: x64 - name: check status run: | diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index 6b3c9e1..192caa3 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -9,7 +9,7 @@ jobs: strategy: matrix: os: [ubuntu-latest] - python: [3.8] + python: [3.9] steps: - uses: actions/checkout@v2 with: diff --git a/.github/workflows/pull_requests.yml b/.github/workflows/pull_requests.yml index 3149c4a..2d9ac11 100644 --- a/.github/workflows/pull_requests.yml +++ b/.github/workflows/pull_requests.yml @@ -12,7 +12,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v4 with: - python-version: 3.8 + python-version: 3.9 architecture: x64 - name: Cache python modules uses: actions/cache@v2 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b3b26a6..dd799de 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,7 +13,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v4 with: - python-version: 3.8 + python-version: 3.9 architecture: x64 - name: Cache python modules uses: actions/cache@v2 @@ -47,7 +47,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v4 with: - python-version: 3.8 + python-version: 3.9 architecture: x64 - name: Install package run: | @@ -64,7 +64,7 @@ jobs: uses: conda-incubator/setup-miniconda@v2 with: auto-update-conda: true - python-version: 3.8 + python-version: 3.9 auto-activate-base: true - name: Install dependencies run: | @@ -93,7 +93,7 @@ jobs: uses: conda-incubator/setup-miniconda@v2 with: auto-update-conda: true - python-version: 3.8 + python-version: 3.9 auto-activate-base: true - name: Install package run: | diff --git a/.github/workflows/scripts.yml b/.github/workflows/scripts.yml index 5cf8b4a..bf6a957 100644 --- a/.github/workflows/scripts.yml +++ b/.github/workflows/scripts.yml @@ -13,7 +13,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest] - python: [3.8] + python: [3.9] steps: - uses: actions/checkout@v2 - name: Set up Python @@ -41,7 +41,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest] - python: [3.8] + python: [3.9] steps: - uses: actions/checkout@v2 - name: Set up Python diff --git a/.github/workflows/style.yml b/.github/workflows/style.yml index 902b908..3760d45 100644 --- a/.github/workflows/style.yml +++ b/.github/workflows/style.yml @@ -12,7 +12,7 @@ jobs: strategy: matrix: os: [ubuntu-latest] - python: [3.8] + python: [3.9] steps: - uses: actions/checkout@v2 - name: Set up Python @@ -31,7 +31,7 @@ jobs: strategy: matrix: os: [ubuntu-latest] - python: [3.8] + python: [3.9] steps: - uses: actions/checkout@v2 - name: Set up Python @@ -59,7 +59,7 @@ jobs: strategy: matrix: os: [ubuntu-latest] - python: [3.8] + python: [3.9] steps: - uses: actions/checkout@v2 - name: Set up Python @@ -78,7 +78,7 @@ jobs: strategy: matrix: os: [ubuntu-latest] - python: [3.8] + python: [3.9] steps: - uses: actions/checkout@v2 - name: Set up Python diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 4868323..f783baa 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -12,7 +12,7 @@ jobs: strategy: matrix: os: [ubuntu-latest] - python: [3.8] + python: [3.9] steps: - uses: actions/checkout@v2 with: From 5392dd7daaeeb5fb753d1d8ac3ccbd2524aa6333 Mon Sep 17 00:00:00 2001 From: F-G Fernandez <26927750+frgfm@users.noreply.github.com> Date: Sat, 16 Sep 2023 16:44:23 +0200 Subject: [PATCH 4/5] style: Fixes ruff --- demo/app.py | 2 +- docs/source/conf.py | 4 ++-- scripts/eval_perf.py | 3 ++- setup.py | 2 +- tests/conftest.py | 4 ++-- tests/test_methods_activation.py | 32 ++++++++++++++++---------------- tests/test_methods_core.py | 15 ++++++++------- tests/test_methods_gradient.py | 28 ++++++++++++++-------------- torchcam/methods/core.py | 7 ++++++- 9 files changed, 52 insertions(+), 45 deletions(-) diff --git a/demo/app.py b/demo/app.py index f09e6dc..7653821 100644 --- a/demo/app.py +++ b/demo/app.py @@ -35,7 +35,7 @@ def main(): # Wide mode - st.set_page_config(layout="wide") + st.set_page_config(page_title="TorchCAM - Class activation explorer", layout="wide") # Designing the interface st.title("TorchCAM: class activation explorer") diff --git a/docs/source/conf.py b/docs/source/conf.py index 80ca2b2..f0cf0f9 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -15,11 +15,11 @@ # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # -import os import sys from datetime import datetime +from pathlib import Path -sys.path.insert(0, os.path.abspath("../..")) +sys.path.insert(0, Path().resolve().parent.parent) import torchcam # -- Project information ----------------------------------------------------- diff --git a/scripts/eval_perf.py b/scripts/eval_perf.py index 79d9ac9..e641ce7 100644 --- a/scripts/eval_perf.py +++ b/scripts/eval_perf.py @@ -11,6 +11,7 @@ import math import os from functools import partial +from pathlib import Path import torch from torch.utils.data import SequentialSampler @@ -49,7 +50,7 @@ def main(args): ) ds = ImageFolder( - os.path.join(args.data_path, "val"), + Path(args.data_path).joinpath("val"), T.Compose(eval_tf), ) loader = torch.utils.data.DataLoader( diff --git a/setup.py b/setup.py index 92ad5df..ccc9ccc 100644 --- a/setup.py +++ b/setup.py @@ -18,7 +18,7 @@ # Dynamically set the __version__ attribute cwd = Path(__file__).parent.absolute() - with open(cwd.joinpath("torchcam", "version.py"), "w", encoding="utf-8") as f: + with cwd.joinpath("torchcam", "version.py").open("w", encoding="utf-8") as f: f.write(f"__version__ = '{VERSION}'\n") setup(name=PKG_NAME, version=VERSION) diff --git a/tests/conftest.py b/tests/conftest.py index 6621145..fe2c3b7 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -12,8 +12,8 @@ def mock_img_tensor(): try: # Get a dog image - URL = "https://www.woopets.fr/assets/races/000/066/big-portrait/border-collie.jpg" - response = requests.get(URL, timeout=5) + url = "https://www.woopets.fr/assets/races/000/066/big-portrait/border-collie.jpg" + response = requests.get(url, timeout=5) # Forward an image pil_img = Image.open(BytesIO(response.content), mode="r").convert("RGB") diff --git a/tests/test_methods_activation.py b/tests/test_methods_activation.py index a581ff1..8f1e8eb 100644 --- a/tests/test_methods_activation.py +++ b/tests/test_methods_activation.py @@ -10,11 +10,11 @@ def test_base_cam_constructor(mock_img_model): for p in model.parameters(): p.requires_grad_(False) # Check that multiple target layers is disabled for base CAM - with pytest.raises(ValueError): + with pytest.raises(ValueError, match="base CAM does not support multiple target layers"): activation.CAM(model, ["classifier.1", "classifier.2"]) # FC layer checks - with pytest.raises(TypeError): + with pytest.raises(TypeError, match="invalid argument type for `target_layer`"): activation.CAM(model, fc_layer=3) @@ -26,16 +26,16 @@ def _verify_cam(activation_map, output_size): @pytest.mark.parametrize( - "cam_name, target_layer, fc_layer, num_samples, output_size, batch_size", + ("cam_name", "target_layer", "fc_layer", "num_samples", "output_size", "batch_size"), [ - ["CAM", None, None, None, (7, 7), 1], - ["CAM", None, None, None, (7, 7), 2], - ["CAM", None, "classifier.1", None, (7, 7), 1], - ["CAM", None, lambda m: m.classifier[1], None, (7, 7), 1], - ["ScoreCAM", "features.16.conv.3", None, None, (7, 7), 1], - ["ScoreCAM", lambda m: m.features[16].conv[3], None, None, (7, 7), 1], - ["SSCAM", "features.16.conv.3", None, 4, (7, 7), 1], - ["ISCAM", "features.16.conv.3", None, 4, (7, 7), 1], + ("CAM", None, None, None, (7, 7), 1), + ("CAM", None, None, None, (7, 7), 2), + ("CAM", None, "classifier.1", None, (7, 7), 1), + ("CAM", None, lambda m: m.classifier[1], None, (7, 7), 1), + ("ScoreCAM", "features.16.conv.3", None, None, (7, 7), 1), + ("ScoreCAM", lambda m: m.features[16].conv[3], None, None, (7, 7), 1), + ("SSCAM", "features.16.conv.3", None, 4, (7, 7), 1), + ("ISCAM", "features.16.conv.3", None, 4, (7, 7), 1), ], ) def test_img_cams(cam_name, target_layer, fc_layer, num_samples, output_size, batch_size, mock_img_tensor): @@ -70,12 +70,12 @@ def test_cam_conv1x1(mock_fullyconv_model): @pytest.mark.parametrize( - "cam_name, target_layer, num_samples, output_size", + ("cam_name", "target_layer", "num_samples", "output_size"), [ - ["CAM", "0.3", None, (1, 8, 16, 16)], - ["ScoreCAM", "0.3", None, (1, 8, 16, 16)], - ["SSCAM", "0.3", 4, (1, 8, 16, 16)], - ["ISCAM", "0.3", 4, (1, 8, 16, 16)], + ("CAM", "0.3", None, (1, 8, 16, 16)), + ("ScoreCAM", "0.3", None, (1, 8, 16, 16)), + ("SSCAM", "0.3", 4, (1, 8, 16, 16)), + ("ISCAM", "0.3", 4, (1, 8, 16, 16)), ], ) def test_video_cams(cam_name, target_layer, num_samples, output_size, mock_video_model, mock_video_tensor): diff --git a/tests/test_methods_core.py b/tests/test_methods_core.py index c7dd6fc..c5d4e56 100644 --- a/tests/test_methods_core.py +++ b/tests/test_methods_core.py @@ -56,13 +56,13 @@ def test_cam_precheck(mock_img_model, mock_img_tensor): @pytest.mark.parametrize( - "input_shape, spatial_dims", + ("input_shape", "spatial_dims"), [ - [(8, 8), None], - [(8, 8, 8), None], - [(8, 8, 8), 2], - [(8, 8, 8, 8), None], - [(8, 8, 8, 8), 3], + ((8, 8), None), + ((8, 8, 8), None), + ((8, 8, 8), 2), + ((8, 8, 8, 8), None), + ((8, 8, 8, 8), 3), ], ) def test_cam_normalize(input_shape, spatial_dims): @@ -72,7 +72,8 @@ def test_cam_normalize(input_shape, spatial_dims): assert normalized_tensor.shape == input_shape # Value check assert not torch.any(torch.isnan(normalized_tensor)) - assert torch.all(normalized_tensor <= 1) and torch.all(normalized_tensor >= 0) + assert torch.all(normalized_tensor <= 1) + assert torch.all(normalized_tensor >= 0) def test_cam_remove_hooks(mock_img_model): diff --git a/tests/test_methods_gradient.py b/tests/test_methods_gradient.py index cfd41a2..0def8eb 100644 --- a/tests/test_methods_gradient.py +++ b/tests/test_methods_gradient.py @@ -14,15 +14,15 @@ def _verify_cam(activation_map, output_size): @pytest.mark.parametrize( - "cam_name, target_layer, output_size, batch_size", + ("cam_name", "target_layer", "output_size", "batch_size"), [ - ["GradCAM", "features.18.0", (7, 7), 1], - ["GradCAMpp", "features.18.0", (7, 7), 1], - ["SmoothGradCAMpp", lambda m: m.features[18][0], (7, 7), 1], - ["SmoothGradCAMpp", "features.18.0", (7, 7), 1], - ["XGradCAM", "features.18.0", (7, 7), 1], - ["LayerCAM", "features.18.0", (7, 7), 1], - ["LayerCAM", "features.18.0", (7, 7), 2], + ("GradCAM", "features.18.0", (7, 7), 1), + ("GradCAMpp", "features.18.0", (7, 7), 1), + ("SmoothGradCAMpp", lambda m: m.features[18][0], (7, 7), 1), + ("SmoothGradCAMpp", "features.18.0", (7, 7), 1), + ("XGradCAM", "features.18.0", (7, 7), 1), + ("LayerCAM", "features.18.0", (7, 7), 1), + ("LayerCAM", "features.18.0", (7, 7), 2), ], ) def test_img_cams(cam_name, target_layer, output_size, batch_size, mock_img_tensor): @@ -60,13 +60,13 @@ def test_img_cams(cam_name, target_layer, output_size, batch_size, mock_img_tens @pytest.mark.parametrize( - "cam_name, target_layer, output_size", + ("cam_name", "target_layer", "output_size"), [ - ["GradCAM", "0.3", (1, 8, 16, 16)], - ["GradCAMpp", "0.3", (1, 8, 16, 16)], - ["SmoothGradCAMpp", "0.3", (1, 8, 16, 16)], - ["XGradCAM", "0.3", (1, 8, 16, 16)], - ["LayerCAM", "0.3", (1, 8, 16, 16)], + ("GradCAM", "0.3", (1, 8, 16, 16)), + ("GradCAMpp", "0.3", (1, 8, 16, 16)), + ("SmoothGradCAMpp", "0.3", (1, 8, 16, 16)), + ("XGradCAM", "0.3", (1, 8, 16, 16)), + ("LayerCAM", "0.3", (1, 8, 16, 16)), ], ) def test_video_cams(cam_name, target_layer, output_size, mock_video_model, mock_video_tensor): diff --git a/torchcam/methods/core.py b/torchcam/methods/core.py index a515baa..e89979e 100644 --- a/torchcam/methods/core.py +++ b/torchcam/methods/core.py @@ -81,7 +81,12 @@ def __init__( def __enter__(self) -> "_CAM": return self - def __exit__(self, exct_type: Type[BaseException], exce_value: BaseException, traceback: TracebackType) -> None: + def __exit__( + self, + exct_type: Union[Type[BaseException], None], + exce_value: Union[BaseException, None], + traceback: Union[TracebackType, None], + ) -> None: self.remove_hooks() self.reset_hooks() From 17b630cd0ee03cc2a0e9f15cfcb3437dbea389b3 Mon Sep 17 00:00:00 2001 From: F-G Fernandez <26927750+frgfm@users.noreply.github.com> Date: Sat, 16 Sep 2023 16:54:45 +0200 Subject: [PATCH 5/5] fix: Fixes ruff --- tests/test_methods_activation.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_methods_activation.py b/tests/test_methods_activation.py index 8f1e8eb..56841da 100644 --- a/tests/test_methods_activation.py +++ b/tests/test_methods_activation.py @@ -10,11 +10,11 @@ def test_base_cam_constructor(mock_img_model): for p in model.parameters(): p.requires_grad_(False) # Check that multiple target layers is disabled for base CAM - with pytest.raises(ValueError, match="base CAM does not support multiple target layers"): + with pytest.raises(ValueError): activation.CAM(model, ["classifier.1", "classifier.2"]) # FC layer checks - with pytest.raises(TypeError, match="invalid argument type for `target_layer`"): + with pytest.raises(TypeError): activation.CAM(model, fc_layer=3)