Skip to content

feat: add PCam dataset support and customizable preprocessing#22

Open
dhalmazna wants to merge 3 commits into
masterfrom
feat/pcam
Open

feat: add PCam dataset support and customizable preprocessing#22
dhalmazna wants to merge 3 commits into
masterfrom
feat/pcam

Conversation

@dhalmazna

@dhalmazna dhalmazna commented Jul 14, 2026

Copy link
Copy Markdown
Collaborator

Context:
Extends CIAO to support the PCam (PatchCamelyon) dataset alongside ImageNet models. Adds configurable preprocessing functions so different datasets can define their own normalization constants.

What's Changed / Added:

  • ciao/data/preprocessing.py: Added make_preprocessing factory function and Preprocessing named tuple; ImageNet and PCam preprocessing configs provided as module-level constants.
  • ciao/data/constants.py: Removed unused PCAM_MEAN/PCAM_STD constants (PCam normalization is now inlined in preprocessing.py).
  • ciao/data/replacement.py: Added make_mean_color_replacement and make_solid_color_replacement factory functions that accept configurable mean/std; both validate inputs at construction time.
  • ciao/model/pcam.py: Added PCam-compatible ResNet50 model wrapper.
  • ciao/model/classes.py: Added PCam class names.
  • ciao/explainer/ciao_explainer.py: No changes required (replacement functions are injected externally).
  • configs/: Added preprocessing/imagenet.yaml, preprocessing/pcam.yaml, model/pcam_resnet50.yaml, classes/pcam.yaml, replacement/mean_color_pcam.yaml.

Related Task:
XAI-29

Summary by CodeRabbit

  • New Features
    • Added support for PatchCamelyon image classification, including a pretrained model option and tumor/non-tumor labels.
    • Added configurable image preprocessing, including a PCam-specific pipeline.
    • Added flexible mean-color and solid-color replacement options for different normalization settings.
    • Added configuration-driven preprocessing during explanations.
  • API Improvements
    • Exposed new PCam preprocessing, model, class-label, and replacement utilities.
    • Explanation workflows can now accept custom preprocessing functions.

…PCam support

- Added `preprocess_fn` parameter to `CIAOExplainer` for custom image preprocessing.
- Introduced `get_pcam_classes` function to retrieve class names for PatchCamelyon dataset.
- Implemented `load_pcam_model` function to load a pretrained ResNet50 model for PCam.
- Updated base configuration to include preprocessing settings for ImageNet.
- Created new configuration files for PCam classes and model.
- Added preprocessing configurations for PCam dataset.
- Refactored mean color replacement configuration to include mean and std parameters.
- Updated dependencies in `pyproject.toml` to include `timm` for model loading.
- Added new packages and their versions in `uv.lock` for dependency management.
@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds an optional preprocess_fn hook threaded through _build_pipeline and CIAOExplainer.explain, introduces PCam-specific preprocessing (load_and_preprocess_image_pcam), model loading (load_pcam_model), and class labels (get_pcam_classes), refactors mean-color replacement into make_mean_color_replacement, and adds corresponding Hydra configs and a timm dependency.

Changes

PCam Support and Configurable Preprocessing

Layer / File(s) Summary
Preprocessing refactor and PCam transform
ciao/data/preprocessing.py, ciao/data/__init__.py
Adds shared _load_and_preprocess helper, preprocess_pcam transform, exported load_and_preprocess_image_pcam, and updates package re-exports/__all__.
Mean-color replacement factory and solid-color update
ciao/data/replacement.py
Replaces calculate_image_mean_color/mean_color_replacement with make_mean_color_replacement and imagenet_mean_replacement; extends make_solid_color_replacement to accept mean/std.
Explainer preprocess_fn hook
ciao/explainer/ciao_explainer.py
Adds optional preprocess_fn parameter to explain, updates docstring, and selects it over the default loader when provided.
Pipeline wiring for preprocess_fn
ciao/__main__.py
_build_pipeline conditionally instantiates cfg.preprocessing and returns it; main unpacks and passes preprocess_fn into explainer.explain(...).
PCam model and class labels
ciao/model/pcam.py, ciao/model/classes.py, pyproject.toml
Adds load_pcam_model (via timm) and get_pcam_classes; adds timm>=1.0.0 dependency.
Hydra config wiring for PCam and preprocessing
configs/base.yaml, configs/classes/pcam.yaml, configs/model/pcam_resnet50.yaml, configs/preprocessing/*.yaml, configs/replacement/mean_color*.yaml
Adds/updates YAML targets for preprocessing, PCam model, PCam classes, and mean-color replacement, plus base defaults entry.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

  • RationAI/ciao#5: Builds on the same preprocessing/replacement functionality refactored in this PR.
  • RationAI/ciao#10: Extends the CIAOExplainer.explain(...) pipeline introduced there with the new preprocess_fn hook.
  • RationAI/ciao#11: Both modify CIAOExplainer.explain's signature and wiring into the explanation pipeline.

Suggested reviewers: adames4, vejtek

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding PCam support and configurable preprocessing.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/pcam

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request introduces support for the PatchCamelyon (PCam) dataset and model, including custom preprocessing, constants, model loading via timm, and configurations. It also refactors the image replacement strategies to accept parameterized normalization constants (mean and std). The review feedback suggests optimizing make_mean_color_replacement and make_solid_color_replacement by pre-computing and pre-creating the normalization and color tensors on the CPU once, rather than recreating them inside the inner replacement function on every call, to reduce runtime overhead.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread ciao/data/replacement.py
Comment thread ciao/data/replacement.py
…move unused PCam constants

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@dhalmazna
dhalmazna marked this pull request as ready for review July 15, 2026 11:47
@dhalmazna
dhalmazna requested review from a team and Copilot July 15, 2026 11:47

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Adds PatchCamelyon (PCam) support to CIAO by introducing a PCam-compatible model/config set and threading a configurable preprocessing callable through the CLI → pipeline → explainer path, while also making replacement strategies configurable with dataset-specific normalization parameters.

Changes:

  • Added PCam model/class/config entries (timm/HuggingFace-backed ResNet50 + binary class labels).
  • Introduced configurable preprocessing selection via Hydra configs and plumbed a preprocess_fn through the explainer pipeline.
  • Refactored mean-color and solid-color replacement logic to accept configurable normalization (mean/std) rather than hardcoding ImageNet.

Reviewed changes

Copilot reviewed 15 out of 16 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
uv.lock Locks new dependency set (notably timm and its transitive deps).
pyproject.toml Adds timm>=1.0.0 runtime dependency.
configs/replacement/mean_color.yaml Switches replacement config to make_mean_color_replacement with explicit ImageNet mean/std.
configs/replacement/mean_color_pcam.yaml Adds PCam-oriented mean/std config (identity normalization).
configs/preprocessing/pcam.yaml Adds Hydra preprocessing target for PCam image loading/preprocessing.
configs/preprocessing/imagenet.yaml Adds Hydra preprocessing target for ImageNet preprocessing.
configs/model/pcam_resnet50.yaml Adds Hydra model target for PCam ResNet50 wrapper.
configs/classes/pcam.yaml Adds Hydra classes target for PCam label set.
configs/base.yaml Adds preprocessing config entry to defaults.
ciao/model/pcam.py Implements PCam model loader via timm.create_model(...) from HuggingFace hub.
ciao/model/classes.py Adds PCam binary class names.
ciao/explainer/ciao_explainer.py Adds optional preprocess_fn parameter and uses it to create the input tensor.
ciao/data/replacement.py Refactors mean/solid-color replacements to be normalization-configurable; adds ImageNet-mean replacement.
ciao/data/preprocessing.py Adds PCam preprocessing transform and shared loader helper.
ciao/data/init.py Updates exports for new preprocessing/replacement APIs.
ciao/main.py Instantiates preprocessing from Hydra config and passes it through to the explainer.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread ciao/data/replacement.py
Comment thread ciao/model/pcam.py
Comment thread ciao/data/preprocessing.py
Comment thread ciao/data/replacement.py
…solid_color_replacement

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
ciao/data/replacement.py (1)

26-36: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Simplify the mean color computation.

Because normalization is a linear transformation (a scalar multiply and add per channel), calculating the spatial mean of the normalized image yields the exact same result mathematically as unnormalizing it, calculating the mean, and then re-normalizing it.

You can remove the redundant math, tensor instantiations, and device transfers by simply calculating the mean of the input image. The mean and std arguments can be left in the function signature if needed to fulfill the Hydra configuration contract.

♻️ Proposed refactor
-    t_mean_cpu = torch.tensor(mean, dtype=torch.float32).view(3, 1, 1)
-    t_std_cpu = torch.tensor(std, dtype=torch.float32).view(3, 1, 1)
-
     def replacement(image: torch.Tensor) -> torch.Tensor:
-        t_mean = t_mean_cpu.to(device=image.device, dtype=image.dtype)
-        t_std = t_std_cpu.to(device=image.device, dtype=image.dtype)
-        unnormalized = (image * t_std) + t_mean
-        mean_color = unnormalized.mean(dim=(1, 2), keepdim=True)
-        normalized_mean = (mean_color - t_mean) / t_std
+        normalized_mean = image.mean(dim=(1, 2), keepdim=True)
         _, height, width = image.shape
         return normalized_mean.expand(-1, height, width)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ciao/data/replacement.py` around lines 26 - 36, Simplify replacement by
computing the spatial mean directly from image in replacement, then expanding it
to height and width. Remove the t_mean_cpu/t_std_cpu tensors, device transfers,
and unnormalize/renormalize calculations; retain mean and std parameters in the
surrounding configuration interface if required by Hydra.
ciao/model/pcam.py (1)

7-9: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Pin the Hugging Face checkpoint revision.

The model is fetched from the Hub at runtime using a mutable repository reference, so later changes to its configuration or weights could silently change prediction and explanation results. Pin a commit revision or vendor a checksum-verified artifact; confirm the supported timm/Hub revision mechanism before implementing it. (huggingface.co)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ciao/model/pcam.py` around lines 7 - 9, Update the timm.create_model call for
the Hugging Face PCAM checkpoint to use a supported immutable Hub commit
revision or checksum-verified vendored artifact instead of the mutable
repository reference. Preserve pretrained loading while ensuring future
configuration and weight changes cannot alter the model.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@ciao/model/pcam.py`:
- Around line 5-10: Update load_pcam_model to pin the Hugging Face checkpoint by
appending @<revision> to the model_name passed to timm.create_model. Use the
intended immutable commit or tag revision while preserving pretrained=True and
the existing model-loading behavior.

---

Nitpick comments:
In `@ciao/data/replacement.py`:
- Around line 26-36: Simplify replacement by computing the spatial mean directly
from image in replacement, then expanding it to height and width. Remove the
t_mean_cpu/t_std_cpu tensors, device transfers, and unnormalize/renormalize
calculations; retain mean and std parameters in the surrounding configuration
interface if required by Hydra.

In `@ciao/model/pcam.py`:
- Around line 7-9: Update the timm.create_model call for the Hugging Face PCAM
checkpoint to use a supported immutable Hub commit revision or checksum-verified
vendored artifact instead of the mutable repository reference. Preserve
pretrained loading while ensuring future configuration and weight changes cannot
alter the model.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f6b5328b-a4e8-4804-b6b1-fee8310dc272

📥 Commits

Reviewing files that changed from the base of the PR and between cf94b49 and 8c23af1.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (15)
  • ciao/__main__.py
  • ciao/data/__init__.py
  • ciao/data/preprocessing.py
  • ciao/data/replacement.py
  • ciao/explainer/ciao_explainer.py
  • ciao/model/classes.py
  • ciao/model/pcam.py
  • configs/base.yaml
  • configs/classes/pcam.yaml
  • configs/model/pcam_resnet50.yaml
  • configs/preprocessing/imagenet.yaml
  • configs/preprocessing/pcam.yaml
  • configs/replacement/mean_color.yaml
  • configs/replacement/mean_color_pcam.yaml
  • pyproject.toml

Comment thread ciao/model/pcam.py
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.

2 participants