Skip to content

Add baseline_replacement_by_indices_excluding: a placement-controlled perturbation - #380

Open
SubhagSharma wants to merge 1 commit into
understandable-machine-intelligence-lab:mainfrom
SubhagSharma:placement-controlled-perturbation
Open

SubhagSharma wants to merge 1 commit into
understandable-machine-intelligence-lab:mainfrom
SubhagSharma:placement-controlled-perturbation

Conversation

@SubhagSharma

@SubhagSharma SubhagSharma commented Sep 14, 2026

Copy link
Copy Markdown

Adds baseline_replacement_by_indices_excluding — see #379 for the motivation.

Same signature as baseline_replacement_by_indices, plus an optional exclude_mask
and seed. It draws the same number of indices, still scattered, but only from
outside the mask. With exclude_mask=None it's identical to the stock function, so
it can't affect existing results.

It raises ValueError when the region won't fit — if the excluded area is more than
half the frame there aren't enough positions left. I made it raise rather than fall
back to an unconstrained draw, because a silent fallback gives you a number that
looks fine and isn't.

Four tests: the raise/no-raise boundary, non-overlap across seeds, equivalence with
the stock function when no mask is given, and seeded reproducibility.

A few notes:

  • black formatted, flake8 clean. The F405s in the test file come from the
    existing import * and hit every test in there.
  • +163 / −0 — I kept black off the surrounding code so the diff stays readable.
  • I couldn't run tox locally (tests/conftest.py imports keras, which I don't
    have), so the four tests were run directly against the function in the package.
    CI will be the real check.
  • Plain ValueError rather than a new exception class, to keep this to one function.

Happy to move the placement logic into a utils.py helper instead if you'd prefer
that split.

… perturbation

Every perturbation function in Quantus answers what value to substitute or what
transform to apply. None constructs a region subject to a placement constraint.

That matters when a random perturbation is used as a control for the masking
artefact rather than as a random-importance baseline. A control drawn uniformly
from the whole frame removes, in expectation, a fraction gamma of the object it
is meant to be a control for, where gamma is the object's frame coverage. At high
coverage this is enough to reverse the sign of the measured object reliance.

baseline_replacement_by_indices_excluding takes the same arguments as
baseline_replacement_by_indices plus an optional exclude_mask and seed. It draws
the same number of indices, still scattered, only from outside the mask.

It raises ValueError when the region cannot be placed: gamma * W * H distinct
positions cannot be drawn from the (1 - gamma) * W * H outside the object, so the
control exists only while gamma <= 0.5. Falling back to an unconstrained draw
would return a number that looks like a measurement and is not one.

With exclude_mask=None it is bit-identical to baseline_replacement_by_indices,
so it is a drop-in and cannot change existing results.

Tests cover the feasibility bound, non-overlap across seeds, drop-in equivalence
when no mask is given, and seeded reproducibility.

Discussed in understandable-machine-intelligence-lab#379.

This branch has not been deployed

No deployments
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

Successfully merging this pull request may close these issues.

1 participant