Skip to content

Add a ConceptLocalizer via Black-box Attributions - #186

Draft
Agustin-Picard wants to merge 9 commits into
masterfrom
feat/concept-localizer
Draft

Add a ConceptLocalizer via Black-box Attributions#186
Agustin-Picard wants to merge 9 commits into
masterfrom
feat/concept-localizer

Conversation

@Agustin-Picard

Copy link
Copy Markdown
Member

This PR introduces input-to-concept localization for HolisticCraft,
answering the question "which regions of the input are responsible for
activating concept k?"
by exposing the fitted concept extractor as a
K-output black-box model and delegating to any compatible Xplique
attribution method (initially validated with Rise and
SobolAttributionMethod).

It complements — but does not replace — the existing coefficient-based
concept visualization, and reuses the standard Xplique attribution
machinery instead of introducing a parallel concept-specific explanation
stack.

Motivation

HolisticCraft currently visualizes concept coefficients U_k(x) as spatial
heatmaps by resizing them to the input resolution. This is a direct
visualization of the latent coefficients — not an input attribution — and can
be misleading for deep architectures, large receptive fields, attention-based
models, complex latent cuts, multi-scale models, and object-detection
backbones.

This PR adds a second, complementary interpretation:

flowchart LR
    X["input x"] --> LOC["ConceptLocalizer"]
    subgraph LOC_INTERNALS ["ConceptLocalizer internals"]
        direction LR
        E["latent extractor"] --> F["factorizer.encode(...)"]
        F --> R["spatial reduction<br/>per concept"]
        R --> S["[s_1(x), ..., s_K(x)]"]
    end
    LOC --> LOC_INTERNALS
    LOC_INTERNALS --> BB["black-box attribution<br/>method targeting concept k"]
    BB --> H["input-space<br/>localization heatmap"]
Loading

The ConceptLocalizer behaves like a K-output black-box model, so
concept k can be targeted with an ordinary one-hot vector, without any
custom attribution operator.

The proposed abstraction is symmetric with the existing ConceptDecoder:

flowchart LR
    subgraph EXISTING ["Existing"]
        direction LR
        C1["concept coefficients"] --> D1["ConceptDecoder"] --> P1["final prediction"]
    end
    subgraph NEW ["New"]
        direction LR
        I2["input image"] --> L2["ConceptLocalizer"] --> S2["concept scores"]
    end
Loading

Concept vocabulary

The PR makes the three distinct quantities explicit throughout docstrings:

Concept Answers Existing / New
Concept activation How strongly concept k is present in the latent Existing
Concept importance How much concept k contributes to the task prediction Existing
Concept localization Which input regions drive activation of concept k New

What this PR adds

New abstractions

  • ConceptLocalizer (xplique/concepts/holistic_craft.py)

    • Framework-agnostic base that maps encoded concept coefficients to one
      scalar score per concept.
    • Supports string reducers "mean", "sum", "max" and arbitrary
      callables. Default is "mean" (consistent with the existing
      top-image ranking).
    • Handles spatial [B, H, W, K], token [B, T, K], and already-global
      [B, K] coefficient layouts; validates output shape and finiteness.
    • Wraps NotImplementedError from non-inductive factorizers into a
      clear RuntimeError explaining that factorizer.encode() is
      required because attribution methods evaluate perturbed inputs.
    • Signed coefficients are preserved; users can pass a callable reducer
      (e.g. mean absolute activation) when magnitude is intended.
  • ConceptLocalizerTf (xplique/concepts/tf/holistic_craft.py)

    • Callable that returns a tf.Tensor with shape (B, K).
  • ConceptLocalizerTorch (xplique/concepts/torch/holistic_craft.py)

    • nn.Module that accepts native NCHW tensors.
    • HolisticCraftTorch.make_concept_localizer() returns it wrapped in
      Xplique's existing TorchWrapper with is_channel_first=True and
      requires_grad=False, so Xplique's standard NHWC-to-NCHW conversion
      and device handling apply and no gradient path is used.

New HolisticCraft API

  • HolisticCraft.make_concept_localizer(concept_reducer="mean") (abstract,
    implemented per framework). Mirrors the existing
    make_concept_decoder(latent_data) symmetry:

    ConceptDecoder   : coefficients -> prediction
    ConceptLocalizer : input        -> concept scores
    
  • HolisticCraft.compute_concept_attributions(images, partial_explainer, ...)

    • Accepts any PartialExplainer configured with a compatible
      black-box explainer (validated for Rise and
      SobolAttributionMethod; compatible with Occlusion, Lime,
      KernelShap, and callable explainer factories).
    • Rejects WhiteBoxExplainer subclasses and any explicit operator
      argument with an actionable error.
    • Validates concept_ids (integers, no booleans, no duplicates,
      in range, non-empty) before any expensive work; enforces
      non-empty batches with positive spatial dimensions.
    • Normalizes image batches to Xplique's channel-last convention
      (NHWC), including PyTorch Tensor / list inputs.
    • Builds the localizer and the explainer instance once and reuses
      them across all requested concepts.
    • Returns float32 maps of shape (N, H, W, number_of_concepts).
      Uncomputed channels are NaN so that "not computed" is
      unambiguously distinguishable from a valid zero attribution.
      concept_ids=None returns a fully finite tensor.
    • Accepts explainer outputs shaped (N, H, W) or (N, H, W, 1);
      unexpected shapes / channel counts / non-finite values are rejected
      with informative errors.

Visualization integration

  • display_concept_heatmap()
    • Extended to also accept input-resolution attribution maps.
    • Skips the resize step when the heatmap already matches the image
      resolution (avoids needlessly resampling RISE / Sobol maps).
    • Squeezes (H, W, 1) maps to (H, W) and validates finiteness.
  • display_images_per_concept(..., concept_maps=None)
    • When concept_maps=None, behavior is identical to v2.0.0 (uses
      coeffs_u).
    • When concept_maps is provided, it drives the overlays; coeffs_u
      keeps its original meaning.
  • display_top_images_per_concept(..., concept_maps=None)
    • Top-image ranking remains coefficient-based (coeffs_u);
      attribution maps only drive the overlays. This preserves the
      semantic that concept-coefficient magnitude represents presence
      while attribution maps represent input sensitivity of the concept
      score.
  • Shared helpers _normalize_image_batch_to_nhwc,
    _validate_concept_ids, _prepare_concept_maps, and
    _resolve_concept_map_source back both display paths and the new
    attribution API, eliminating the previous duplicated NHWC / order
    validation and concentrating localization-specific logic in one
    place.

Backward compatibility

  • All existing calls to display_images_per_concept(images[, coeffs_u=...])
    and display_top_images_per_concept(images[, coeffs_u=...]) retain the
    exact v2.0.0 rendering and ordering behavior.
  • No existing user incurs additional attribution computation.
  • ConceptDecoder, compute_explanation_per_concept(),
    estimate_importance(), and get_topk_images_per_concept() are
    not modified.
  • Public API additions are opt-in.

Documentation and tutorials

WIP, coming up soon!

@Agustin-Picard Agustin-Picard self-assigned this Aug 31, 2026
@Agustin-Picard Agustin-Picard added feature-attribution New feature or issue concerning Attribution methods concept New feature or issue concerning Concept based method labels Aug 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

concept New feature or issue concerning Concept based method feature-attribution New feature or issue concerning Attribution methods

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant