Skip to content

shapiq.vision Sub-package for Image Classification - #549

Open
S2k-1 wants to merge 23 commits into
mmschlk:mainfrom
S2k-1:vision_main
Open

shapiq.vision Sub-package for Image Classification#549
S2k-1 wants to merge 23 commits into
mmschlk:mainfrom
S2k-1:vision_main

Conversation

@S2k-1

@S2k-1 S2k-1 commented Jun 12, 2026

Copy link
Copy Markdown

Motivation and Context

The current shapiq package does not support explaining image models, except for code inside benchmark games, where logic is hardcoded per model, which is not flexible for users who whant to explain their own models.

This PR introduces a new subpackage shapiq.vision for explaining image classification models with Shapley values and interactions. Its shapiq.vision.ImageExplainer and shapiq.vision.ImageImputer work with provided model callables like CNNs and vision transformers, and any supported approximator from shapiq.approximator, covering first-order and higher-order interaction indices. The package fits into the existing shapiq framework of using Explainer, Game and Imputer classes, and adds new functionality for image players and masking strategies.

In general, we provide the following new modules and functionalities:

  • shapiq.vision.architecture: Model-architecture-specific logic for image models, including default player/masking strategies and value functions.
    • Supports a wide range of classifiers via two extensible classes: ClassifierArchitecture (flexible, runs arbitrary callables with players/masks defined in pixel space) and ViTArchitecture (Hugging Face ViTs only, supports masking in latent/token space).
  • shapiq.vision.custom_types: Custom protocols and type aliases for image inputs and model callables.
  • shapiq.vision.explainer: Explains image classification models by passing a model callable, and configure the explanation as usual in the shapiq package
  • shapiq.vision.imputer: Imputes absent players in a coalition, providing batched evaluation of coalitions
  • shapiq.vision.masking: Implements different masking strategies for image models depending on a domain (pixel space or latent space)
  • shapiq.vision.players: Implements different player strategies for image models, depending on a domain (pixel space or latent space)
  • shapiq.vision.utils: Utility functions for image models, including e.g. transforming images to and from torch tensors, extracting logits.
  • shapiq.vision.validation: Validation functions for e.g. checking model is callable or has certain attributes.

Additionally:

  • Dispatch from shapiq.Explainer to shapiq.vision.ImageExplainer if a shapiq.vision.ModelArchitecture is passed in as the modelargument.
  • Plot image interactions with shapiq.vision.plot_image_attributions(), as a heatmap plot and optionally interaction values next to it.

The design of shapiq.vision follows the pattern of existing shapiq subpackages like shapiq.tree, separating the concerns of image players, masking strategies, and model-callable logic into dedicated modules distinct from shapiq's core logic, since these concerns are specific to image models. This isolation also makes it easier to define distinct supported model types and behaviors without needing to provide an universal extension to the core package. Keeping the image logic contained in a single subpackage also keeps the core shapiq package lightweight and avoids introducing optional dependencies like torch or scikit-image into the base install.
We therefore introduce a new optional dependency group vision for the new subpackage, which can be installed with pip install shapiq[vision].


Public API Changes

  • No Public API changes
  • Yes, Public API changes (Details below)

We add a new subpackage shapiq.vision with its own public API, documented and provided with examples in examples/vision. We thus also added dispatching to shapiq.vision.ImageExplainer if a shapiq.vision.ModelArchitecture is passed in as the model argument to shapiq.Explainer. Apart from that we did not change the public API of shapiq and only added new functionality for image models.

To showcase the new functionality, see the following simple example:

from shapiq.vision import ImageExplainer, ClassificationArchitecture, ViTClassificationArchitecture

# --- CNN - resnet example ---
arch = ClassificationArchitecture(model=resnet)
explainer = ImageExplainer(model=arch, data=my_image)
iv = explainer.explain_function(x=None, budget=64)

# --- ViT ---
arch = ViTClassificationArchitecture(model=my_vit, vit_processor=processor)
explainer = ImageExplainer(model=arch, data=my_image)
iv = explainer.explain_function(x=None, budget=64)

# interaction plot
iv.plot_image_attributions(image=my_image, player_masks=explainer.imputer.player_masks)

Notes: We explicitly choose to use a model argument in ImageExplainer that currently only takes subclasses of shapiq.vision.ModelArchitecture instead of a callable model. We did not rename that to architecture, to be consistent with the existing shapiq.Explainer API and to allow for future dispatching of a callable model to a shapiq.vision.ModelArchitecture if the model is recognized as a supported image model. We explored on that in our own repository using forward passes to determine the model type, because there is no distinct way to determine if a model is a vision transformer or CNN from protocols or attributes. We decided to not include that in the final PR, as this might require additional refactoring and enforces a model call at every instantiation of the ImageExplainer, which is not necessary for all use cases. We thus leave it to the user to pass in a shapiq.vision.ModelArchitecture subclass, which is also more explicit, but still allows for more flexibility in the future. We have also added image support for the upset plot in our repository.


How Has This Been Tested?

We provide a test suite for our new shapiq.vision subpackage covering unit tests for individual components and integration tests for the end-to-end explanation pipeline.
All tests are included in tests/test_unit/tests_vision, covering the individual player and masking strategies, batching, explainer and imputer logic, and validation logic for model callables and configuration of players, masking, and model input.

Not covered in the test suite:

  • Benchmarking against real pretrained models is done separately in the efficiency benchmarks (not included in this PR)

  • Benchmarking the performance of shapiq.vision against commonly used methods for explaining image models (like captum) is not included in this PR

  • GPU-specific device-handling paths are tested only on CPU in CI; manual GPU testing was done locally.


Checklist

  • The changes have been tested locally.
  • Documentation has been updated (if the public API or usage changes).
  • An entry has been added to CHANGELOG.md (if relevant for users).
  • The code follows the project's style guidelines.
  • I have considered the impact of these changes on the public API.

t-muras and others added 8 commits June 5, 2026 21:06
* ADD: image imputer implementation for resnet with superpixel players and zero / mean color masking

* added image explainer and game execution to image mvp notebook

* Merge remote-tracking branch 'vision/vit-prototype'

* ADD: initialized package structure for shapiq.vision

* ADD: entry point to Image Explainer

* ADD: players and masking strategies copied from resnet prototype

* ADD: ImageImputer copied from resnet prototype

* ADD: ImageExplainer only for resnet, structur similar to TabularExplainer

* ADD: init file for vision subpackage

* ADD: Patchstrategy for ViT & value function in imputer

* ADD: default masking and player strategy decision in explainer

* ADD: bug fixes to run explainer for both resnet and vit

* ADD: testing notebook to visualize how to interact with the explainer

* ADD: moved prototype notebooks to specific folder

* ADD: cat image from current frontend testing

* REFACTOR: decouple vision package via ModelArchitectureStrategy

Replaces model_type if/elif branches with ResNetArchitecture and ViTArchitecture.
Player and masking strategies split into Pixel/Latent subtypes.
Update test notebook with current implementation

* ADD:
- dynamic dispatch of model architecture based on the given model
- refactor some variable names, cleaned imputer - model architecture interaction

* REMOVE: debugging prints

* REFACTOR: testing notebook

* ADD: plotting function for heatmap

Taking image (as numpy array), the explainer and label type as input and outputting one plot made up of 2 subplots:
First plot is image with alpha overlay of first order interaction values. Second plot is actual values in bar chart.

* ADD: Heatmap only argument, so barchart not plotted

* Merge branch 'superpixel-improvement'

---------

Co-authored-by: Tamara Muras <Tamara.Muras>
Co-authored-by: Alexander Feix <alexander.feix03@gmail.com>
Co-authored-by: S2k-1 <219272227+S2k-1@users.noreply.github.com>
* REFACTOR: Restnet/Pixel -> CNN and ViT/latent -> Transformer. For player and masking strategies aswell as architecture

* REFACTOR: split player definition and masking into respective classes for Transformers

* REFACTOR: rename masking strategy function, move logit call to architecture and adjust arguments for function call.

* ADD: torch import only where necessary and ensure annotations are evaluated lazy

* REFACTOR: move build pixel mask to patch strategy and introduce player mask property in architecture for visualizations

* REFACTOR: change order of player strategies in file

---------

Co-authored-by: Tamara Muras <Tamara.Muras>
Co-authored-by: S2k-1 <219272227+S2k-1@users.noreply.github.com>
…and internal handling between torch and numpy (#34)

* ADD: image conversion methods in utils

* REFACTOR: change internal handling to torch mainly, except for players

* REFACTOR: convert player masks to torch in architecture instead of masking

* ADD: ImageLike typy to also support input of torch and pil images

* Fix: wrong typing in architecture

* remove debug print and unnecessary method

* ADD: appropirate batching in the value function of imputer

* REFACTOR: comment on masking strategies

* comment on players

* REFACTOR: removed model auto dispatch and require to input model architecture

* ADD: improved docstring on imputer

* ADD: player documentation

---------

Co-authored-by: Tamara Muras <Tamara.Muras>
* ADD: imputer fit method and image property in imputer

* fix: explainer only updates imputer when x is not None being passed to explain

* remove unintended import

---------

Co-authored-by: Tamara Muras <Tamara.Muras>
…tom masks from Superpixels (#37)

* ADD: Custom Player strategy and gridstrategy for CNN architectures

* Refactor: exclude custom masks from superpixels and add to customplayer strategy

* Refactor: improve grid strategy to take patch or grid size instead of row and cols

---------

Co-authored-by: Tamara Muras <Tamara.Muras>
* ADD: vision tests

* ADD & FIX: added readl model tests and fixed tensor channel bug

* ADD: unit test cases for custom players

* Fix: custom player mask not casted to bool

* ADD: unit tests for grid strategy

* ADD: tests for imputer fit method

* Fix: imputer not returning self

* Add: Adjust explainer tests due to changed implementation of explain function and renamed batch size arg in imputer

* fix: failing tests due to inconsistent renaming of batch size arg

---------

Co-authored-by: Tamara Muras <Tamara.Muras>
Co-authored-by: Alexander Feix <alexander.feix03@gmail.com>
* Remove: notebooks used for quick testing

* fix: apply pre-commit auto-fixes for vision package

* Refactor: improve code quality and add docstrings

* Refactor: fix all code quality issues from main files of vision package

- did not improve plot functions
- did not remove lazy import statements as recommended

* fix: explainer couldnt be initialized with transformer model

---------

Co-authored-by: Tamara Muras <Tamara.Muras>
@mmschlk

mmschlk commented Jun 17, 2026

Copy link
Copy Markdown
Owner

Hello, thank you for your PR already! Please ping me here as soon as you want a PR review. :)

Note however, that for a review, the CI pipeline should really be green first (all tests pass, the code-quality checks are okay, and the docs building pipeline compiles). Otherwise it's hard for me to give you good feedback. :)

I can also approve the workflows from time to time if you ping me.

@S2k-1

S2k-1 commented Jun 18, 2026

Copy link
Copy Markdown
Author

@mmschlk ty/ruff errors fixed. CI workflow on our fork only got errors for codecov upload. (expected due to missing token)
Please approve the workflow here :)

…s for install (#40)

* ADD: example notebooks for quickstart and on defining players

* Fix: docstring inaccuracies for sphinx doc and finalize image explanation examples

* fix: code quality

* remove code blocks from example

* ADD: proper shapiq[vision] package to install and add tests to ensure import errors appear

* fix: test for import error when running in a row with the other tests

* fix: code quality

* fix: imputer torch import and CI pipeline shapiq import

* ADD: imputer to framework import testing

---------

Co-authored-by: Tamara Muras <Tamara.Muras>
@t-muras

t-muras commented Jun 21, 2026

Copy link
Copy Markdown

We also added two examples to the documentation to showcase how to interact with the vision subpackage and how to define different player strategies. These are kept rather simple until now, we'll extend them after we decided how to refactor the architectures (after the feedback).

We also now copied the behavior from ShaplEIG and SPEX approximators in defining optional dependencies for the vision package.

@t-muras

t-muras commented Jun 26, 2026

Copy link
Copy Markdown

@mmschlk Could you approve the workflow, so we can verify the full pipeline runs successfully?

@S2k-1

S2k-1 commented Jun 29, 2026

Copy link
Copy Markdown
Author

@Advueu963 could you please approve the workflow or ping @mmschlk

@Advueu963
Advueu963 requested a review from mmschlk June 29, 2026 16:21
@codecov

codecov Bot commented Jun 29, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.04918% with 27 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/shapiq/vision/__init__.py 64.00% 9 Missing ⚠️
src/shapiq/vision/imputer.py 91.22% 5 Missing ⚠️
src/shapiq/vision/masking.py 97.81% 4 Missing ⚠️
src/shapiq/vision/architecture.py 98.51% 3 Missing ⚠️
src/shapiq/vision/players.py 98.38% 3 Missing ⚠️
src/shapiq/vision/utils.py 97.05% 3 Missing ⚠️

📢 Thoughts on this report? Let us know!

@mmschlk mmschlk left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Thank you already for your pull request and all of your work already on this matter!! :) I only had some minor comments (see individually). It's already pretty nice!

The only "major-ish" thing I have is also a bit of a question. Did we decided not to wirre ImageExplainer into the Explainer dispatching logic? So, we said we do not expect users to do

explainer = Explainer(image_model, ...)

and expect explainer to be ImageExplainer? Because I think this is not possible, yet. I would however, like to know weather it would be easy to allow users to call

explainer = Explainer(CNNArchitecture(model), ...)

and then get ImageExplainer. But then only these special architectures would work in the dispatching. Is this doable?

Thank you already!

Comment thread src/shapiq/vision/explainer.py Outdated
data: ImageLike,
*,
imputer: ImageImputer | None = None,
index: ExplainerIndices = "k-SII",

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

we actually went to "SV" as default in v1.5.0 and order 1.

Comment thread src/shapiq/interaction_values.py
Comment thread src/shapiq/vision/explainer.py Outdated
Returns:
InteractionValues: The interaction values of the prediction.
"""
budget: int = kwargs.get("budget", 64)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

A few parameters are out of step with our other explainers and I'd like parity before we can merge:

  • budget is read from kwargs here instead of being an explicit argument (compare TabularExplainer.explain_function(x, budget=...)). Please make it a real signature parameter so it shows up in the docs/IDE.
  • no random_state is this not also necessary here?

Comment thread src/shapiq/vision/explainer.py
Comment thread src/shapiq/vision/architecture.py Outdated
def default_player_strategy(self) -> PatchStrategy:
"""Return a patch player strategy with a 3x3 grid."""
grid_size = self._model.config.image_size // self._model.config.patch_size
return PatchStrategy(grid_size=grid_size, n_players=9)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

This hard-codes a 3x3 grid, but PatchStrategy.init requires grid_size % sqrt(n_players) == 0. For one of the most common ViT, vit-base-patch16-224, the grid_size is 224/16 = 14 and 14 % 3 != 0, so this raises ValueError on construction and the default path crashes for the standard model. The examples only work because they use patch32-384 (grid 12). Please make the default adapt to grid_size (pick a perfect square whose root divides the grid), and add a regression test against a 14x14 grid so this can't silently come back.

Comment thread src/shapiq/vision/__init__.py Outdated
"""Vision-based explanation methods for image models."""

try:
from .architecture import CNNArchitecture, ModelArchitectureStrategy, TransformerArchitecture

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Heads-up, and this one isn't really your fault as we already have the same pattern in ShaplEIG. This eager from .architecture import ... pulls architecture.py (and its top-level import torch) at import-shapiq time, so even a tabular-only user pays ~0.5s of torch import. The try/except guards graceful failure but not laziness. Please defer this with a module-level getattr (PEP 562) so torch is only imported when ImageExplainer is actually used. Soon I will open a matching issue against ShaplEIG so we fix both consistently then.

Comment thread src/shapiq/vision/imputer.py
@mmschlk
mmschlk marked this pull request as ready for review June 30, 2026 16:16
@mmschlk mmschlk changed the title [Draft] shapiq.vision subpackage shapiq.vision Sub-package for Image Classification Jul 2, 2026
mmschlk and others added 3 commits July 2, 2026 11:42
* fix: default values for explainer init

* fix: method signature of explain function and missing arguments in init

* Add: class id argument to explainer init and inside architecture / imputer init to hand over

* Add: tests for requested changes in particular setting class index

* Refactor: model architecture argument of explainer init to model (to make suitable for later protocol implementations and to allow dispatch)

* Add: dispatch for image explainer and test function

* Refactor: set slic to default superpixel algorithm

* FIX: decouple plot_image_attributions form vision subpackage

* FIX: adapt default ViT patch grid to model grid_size

* FIX: Defer vision torch import via PEP 562

* FIX: rebuild approximator when player count changes

* FIX: cover image_attribution_plot in tests and change called colormap api

* FIX: handle pre commit errors and change auto fix for subpackage import

* FIX: add blank line to fix ruff auto-fix

---------

Co-authored-by: Tamara Muras <Tamara.Muras>
Co-authored-by: S2k-1 <219272227+S2k-1@users.noreply.github.com>
@t-muras

t-muras commented Jul 6, 2026

Copy link
Copy Markdown

@mmschlk: Thank you for your feedback! We have implemented the requested changes. Could you approve the workflow again and check if the changes match your expectation?
Just as a note: we are still working on including protocols to improve typing and then also include validation functions to ensure proper error messages raise, if players/masking do not match the model architecture.

@mmschlk

mmschlk commented Jul 6, 2026

Copy link
Copy Markdown
Owner

Got it! I approved the runs. There are now some issues with the current main branch after I merged a few things in. Mea culpa 😇

@t-muras

t-muras commented Jul 6, 2026

Copy link
Copy Markdown

@mmschlk: Resolved already 😊, thanks!

@mmschlk mmschlk left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

I already went through the current state and my comments seemed to be all resolved now, apart from the "typing" model definition in the explainer (such that ImageExplainer can be also called without a specific strategy in mind). I think you awyways are still cooking something up there, right? :)

Comment thread src/shapiq/vision/explainer.py
Comment thread src/shapiq/vision/imputer.py
Comment thread src/shapiq/interaction_values.py
vladikko and others added 4 commits July 7, 2026 22:08
CNNMaskingStrategy._build_pixel_mask matmuls the coalition matrix against the
player masks. The player masks follow the model onto the GPU, while the
coalition sampler emits coalitions on the CPU, so the matmul raised
`RuntimeError: Expected all tensors to be on the same device ... mat2 is on
cuda:0, different from other tensors on cpu` and ImageExplainer could not run on
a CUDA model. Move the coalitions onto the masks' device before the matmul
(a no-op on CPU).
FIX: device mismatch in CNN vision masking on GPU
* ADD: dummy typing protocols for model detection and enum to check masking and player scope

* ADD: validation logic for model, masking and player compatibility

* fix: ruff errors

* fix: more pre commit fixes

* fix: runtime errors

* fix: masking validation

* REFACTOR: Remove useless protocol ViTLikeModel

* FIX: ruff error by adding docstring

* REFACTOR: CNNArchitecture and TransformerArchitecture to ClassificationArchitecture and ViTClassificationArchitecture

* REFACTOR: CNN Player and Masking Strategy to PixelBased and Transformer Player and Masking to LatentBased rename. And add guards for checking compatibility between architectures and masking and player strategies aswell as between them

* ADD: validation for BoolMaskedPos

* Merge vision main into pr_final

* FIX: device mismatch in CNN vision masking on GPU

CNNMaskingStrategy._build_pixel_mask matmuls the coalition matrix against the
player masks. The player masks follow the model onto the GPU, while the
coalition sampler emits coalitions on the CPU, so the matmul raised
`RuntimeError: Expected all tensors to be on the same device ... mat2 is on
cuda:0, different from other tensors on cpu` and ImageExplainer could not run on
a CUDA model. Move the coalitions onto the masks' device before the matmul
(a no-op on CPU).


---------

Co-authored-by: vladikko <vladikko@users.noreply.github.com>

* Refactor: Rename ModelArchitectureStrategy to ModelArchitecture; adjust imputer model input to match explainer naming

* Remove model compatible from players

* Refactor: clean comments in masking

* ADD: improved docstrings and error messages

* Add: shared error message for model validation

* ADD: check architecture against protocol to ensure model is callable

* Add: error handling and refactoring of architecture, especially model calls

* Delete testing notebook

* fix: typing issues

* fix: ruff and formatting

* FIX: GPU support and error attribution in the vision architectures

The ViT token path was unusable on GPU: value_function never moved
coalitions to the model's device, and MaskTokenStrategy built the zero mask
token on the CPU. Both are fixed, and the mask token is no longer rebuilt on
every coalition batch.

Both _forward methods also caught every exception and blamed the model's
interface -- which is how the device bugs above stayed hidden. Only
TypeError/ValueError are wrapped now (with the underlying error included);
everything else propagates. Preprocessing moved out of the try block so
processor failures are not re-labelled as model failures.

* ADD & FIX: updated tests, now with 100% vision code coverage, and one bugfix in architecture.py

* FIX: type errors and dead branch in ClassificationArchitecture._forward

_preprocess_batch was only reachable with a processor configured, so its
`if self._processor is None` pass-through branch was dead code. Removing it
also removed the narrowing that kept ty quiet, so the processor is now passed
in explicitly.

This also fixes the pre-existing ty error where pixel_values was typed
`None | Tensor` and handed to a `pixel_values: Tensor` parameter. It is now
always a tensor, and preprocessing still happens outside the try block so
processor failures keep their own error message.

* FEATURE: add four pixel-space masking strategies

Ports the maskers from the abandoned feature/updated-vision-package branch
to the current API. That branch predates the numpy -> torch move in the
masking layer, so these are reimplementations rather than copies, and
masking.py stays numpy-free: MarginalSampling takes numpy/PIL references but
converts them through utils.to_tensor_chw, and the inpainter contract is
torch in, torch out.

  BlurMasking(sigma)                  Gaussian-blurred fill. A separable
                                      convolution in torch, so it runs on GPU
                                      and needs no new dependency. Matches
                                      scipy.ndimage.gaussian_filter to 2e-7
                                      (against scipy's 'mirror' mode; torch
                                      and scipy disagree on what 'reflect'
                                      means at the border).
  DatasetMeanMasking(mean_color)      Fixed dataset-wide baseline. Unlike
                                      MeanColorMasking the fill does not
  BlurMasking(sigma)                  Gaussian-blurred fill. A separable
                                      convolution in torch, so it runs on GPU
                                      and needs no new dependency. Matches
                                      scipy.ndimage.gaussian_filter to 2e-7
                                      (against scipy's 'mirror' mode; torch
                                      and scipy disagree on what 'reflect'
                                      means at the border).
  DatasetMeanMasking(mean_color)      Fixed dataset-wide baseline. Unlike
                                      MeanColorMasking the fill does not
                                      depend on the image, so values stay
                                      comparable across a dataset.
  MarginalSampling(references, seed)  Picks a reference image per coalition:
                                      the marginal removal function of
                                      Covert, Lundberg & Lee (JMLR 2021).
  InpaintingMasking(inpainter)        Delegates to a user callable: the
                                      conditional removal function. Keeps
                                      diffusers/cv2/skimage out of shapiq.

* ADD: vision readme

* ADD: shapiq vision in changelog

* fix: inconsistency in changelog

* FIX: size image_attribution_plot correctly in heatmap-only mode

The figsize (14, 5) is meant for the two-panel layout (heatmap + bar chart); with heatmap_only=True it produced a single square axes floating in a mostly empty wide canvas. Heatmap-only figures now use (6, 5).

* DOCS: rebuild the vision example gallery for the pr_final API

Replaces the three outdated vision examples with seven sphinx-gallery scripts in reading order: CNN quickstart, ViT quickstart, architectures, player strategies, masking strategies, target class, Shapley interactions. All target the current API (ClassificationArchitecture / ViTClassificationArchitecture, explicit architecture construction). Numeric filename prefixes plus within_subsection_order=FileNameSortKey encode the reading order. Adds torch to intersphinx and the Covert, Lundberg and Lee 'Explaining by Removing' (JMLR 2021) reference.

* FIX: stop the docs sidebar from nesting all galleries under Visualization

With sphinx-gallery's default nested_sections=True, the generated gallery root index carries a single hidden toctree at the end of the file, which RST places inside the last section (Visualization). Section-aware themes like furo therefore attached every gallery as a child of that section in the sidebar. nested_sections=False emits one toctree per section header instead, so each gallery nests under its own heading.

* Add: guard to model input in imputer

* Add: quick test notebook

* FIX: run framework-agnostic tests in subprocesses to stop suite pollution

test_framework_agnostic simulated missing torch/skimage by removing them from sys.modules and reloading the vision modules in-process. Reloading a module rebinds its classes to new objects, desynchronising the 'from x import Y' references other modules hold, so every test running after this file (test_imputer, test_integration_real_models) failed with spurious isinstance / default-strategy errors -- 30 failures in the full suite that all passed in isolation.

Each dependency-removal test now runs its snippet in a fresh interpreter via subprocess (the pattern the file already used for the lazy-import test), so the module-graph surgery never touches the parent process. Full vision suite: 336 passed (was 306 passed / 30 failed); the ImportError behaviour is still verified, just isolated.

* Remove test notebook again

* fix: ruff

* FIX: block torch via meta_path instead of sys.modules=None in framework tests

The framework-agnostic subprocess tests simulated a missing torch with sys.modules['torch'] = None. In a fresh subprocess, importing any shapiq.vision.* module pulls in the full stack (shapiq -> approximator -> sklearn -> scipy.stats), and scipy's array-API torch detection runs at import time: getattr(sys.modules['torch'], 'Tensor'). With torch set to None that is getattr(None, 'Tensor') -> AttributeError, crashing the subprocess and failing 5 tests on CI's newer scipy; local runs with older scipy skipped that path and passed.

Simulate 'not installed' by blocking the import with a meta_path finder that raises ModuleNotFoundError, leaving sys.modules untouched. scipy's sys.modules['torch'] lookup then raises KeyError and returns False gracefully, while the vision module's import torch still raises a clean ModuleNotFoundError -> the friendly install hint. Full vision suite: 336 passed sequentially and under --cov -n logical (the CI invocation).

* Refactor: final comment and docstring fixes

* Update README with ViT compatibility details

Clarify compatibility requirements for ViT models and update installation instructions.

* Refactor: readme

* fix: ruff

---------

Co-authored-by: Tamara Muras <Tamara.Muras>
Co-authored-by: S2k-1 <219272227+S2k-1@users.noreply.github.com>
Co-authored-by: vladikko <vladikko@users.noreply.github.com>
Co-authored-by: Alexander Feix <alexander.feix03@gmail.com>
@t-muras

t-muras commented Jul 17, 2026

Copy link
Copy Markdown

@mmschlk: We just submitted our final version for the practical, pipeline ran without errors in our forked repo !

If we need to make further changes so that we can merge this, just ping us :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

5 participants