Docker one-command WSI TIL inference + smoke test#3
Open
YoniSchirris wants to merge 6 commits into
Open
Conversation
Provide a single end-to-end entry point (ectil/inference.py) that takes a WSI and ECTIL classifier weights and runs mask -> tiling -> RetCCL -> ECTIL, auto-loading RetCCL. Reuses the existing DLUP tiling/FESI mask, RetCCL encoder, and MeanMIL + GatedAttention components so results match extract.py + eval.py. Per slide it writes the final TIL score (tils_score.json), per-tile TIL and attention scores (tile_predictions.csv), the generated feature dataset (features.h5), thumbnail/mask/mask-overlay images, and attention/TIL heatmaps. Add a Dockerfile (conda-based, mirrors README install), .dockerignore, an example run script, and README usage. Weights are mounted at runtime. https://claude.ai/code/session_018mX7wRvMnm23m4uf44Upq8
--wsi now accepts a directory of slides (recursively globbed by extension, including .mrxs, whose companion data directory is never matched). Slides that fail are skipped and recorded rather than aborting the run. RetCCL and the ECTIL classifier are loaded once and reused across all slides. Each run writes a timestamped <output>/<run_name>/ directory (override with --run-name) containing config.json, an aggregate tils_scores.csv (one row per slide, written incrementally), and a per-slide subdir. Per-slide tils_score.json now embeds the full run config. https://claude.ai/code/session_018mX7wRvMnm23m4uf44Upq8
The editable install failed inside the image because pip 23.3.2 was paired with a setuptools whose _core_metadata calls canonicalize_version with strip_trailing_zero, a kwarg the resolved packaging lacked. Pin setuptools/wheel/packaging as a matched set. Also relax python_requires from ==3.10.9 to >=3.10,<3.11 so conda-resolved 3.10.x patch releases install. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add --overwrite-mpp so TCGA-style SVS that lack an embedded micron-per-pixel can be opened and tiled (dlup otherwise raises UnsupportedSlideError); forwarded to both SlideImage.from_file_path and from_standard_tiling. Decode the slide thumbnail a single time and reuse it for the saved PNG and both heatmap overlays, hoist csv/PIL imports, and derive --mask-function choices from AvailableMaskFunctions. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
run_demo.sh downloads the RetCCL encoder and ECTIL classifier weights and five TCGA-BRCA slides, builds the Docker image, runs both single-slide and directory inference on CPU, and asserts the expected per-slide outputs before printing a SMOKE TEST PASSED/FAILED verdict. Ignore the demo's data/inference_output run dir. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Lead with WSI inference (smoke test, Docker, direct), move the manuscript- reproduction details into a collapsible section, and surface run_demo.sh. Fix broken example commands (missing line-continuation backslashes in the extract and eval snippets), a malformed markdown link, the clone URL (YoniSchirris -> nki-ai, also in setup.py), and note --overwrite-mpp for TCGA slides that lack an embedded spacing. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
tils_score.json,tile_predictions.csv,features.h5, thumbnail/mask/heatmap PNGs) and an aggregatetils_scores.csv.setuptools/wheel/packagingas a matched set withpip==23.3.2(the editable install otherwise died oncanonicalize_version(strip_trailing_zero=)), and relaxespython_requiresfrom==3.10.9to>=3.10,<3.11so conda-resolved 3.10.x patches install.--overwrite-mppso slides without an embedded spacing (many TCGA SVS) can be opened/tiled instead of raising dlup'sUnsupportedSlideError. Off by default (None); when set, it supplies the slide's native base spacing so dlup can resample to the model's target--mpp 0.5(the value used in the extraction experiments — seeconfigs/datamodule/encoder/retccl.yaml). For TCGA 40x diagnostic slides that native spacing is0.25.tools/infer/run_demo.sh: a standalone smoke test (plain bash, no external tooling) that downloads the RetCCL + ECTIL weights and 5 TCGA-BRCA slides, builds the image, runs both single-slide and directory modes on CPU, and asserts the outputs before printingSMOKE TEST PASSED/FAILED.Verification
Smoke test passed end-to-end on CPU (both modes, all assertions green). Real TIL scores on 5 TCGA-BRCA slides:
Test plan
This is a single command. It downloads everything, builds the container, runs both inference modes, and validates the output. No weights, no slides, and no Python deps need to be set up by hand.
1. Clone and enter the repo
git clone https://github.com/NKI-AI/ectil cd ectilYou need Docker running, plus
curlandpython3on the host (the latter only to bootstrapgdownand parse the result JSON — all the heavy C deps live inside the image). The script refuses to start and tells you exactly what's missing if not.2. Run the one command
That's it. Everything below happens automatically, and it's idempotent — re-running skips anything already downloaded.
3. What you should see scroll past
The script narrates 7 stages. Roughly:
The two
[6/7]runs are the point of the test: single-slide (--wsi <one .svs>, expect 1 row) and directory (--wsi data/wsi/demo, expect 5 rows) modes.4. What "pass" looks like
It ends with a per-slide score table and:
and exits
0. On any problem it printsSMOKE TEST FAILEDwith the offending[FAIL]lines and exits1.5. Inspect the artifacts (optional)
ls data/inference_output/demo_dir/ # config.json, tils_scores.csv, 5 per-slide subdirs cat data/inference_output/demo_dir/tils_scores.csvEach per-slide subdir holds:
tils_score.json,tile_predictions.csv,features.h5, andthumbnail.png/mask.png/mask_overlay.png/attention_heatmap.png/til_heatmap.png. Spot-check atil_heatmap.pngagainst the slide to sanity-check the spatial predictions.Everything downloaded (
data/wsi,model_zoo/**) and written (data/inference_output) is gitignored.Requesting @NUltee as reviewer (recent commits on
main).🤖 Generated with Claude Code