arXiv Preprint | MedIA | Free-accessible paper link (50 days)
TL;DR:
This work proposes a novel adversarial MIL framework for the survival analysis on gagipixel Whole-Slide Images (WSIs). This framework directly estimates the distribution of time-to-event from WSIs by implicitly sampling from generator. It introduces adversarial time-to-event modeling into the MIL paradigm that is much necessary for WSI analysis, by constructing a MIL encoder and a region-level instance projection fusion network for generator and discriminator, respectively. We empirically demonstrate that AdvMIL has the following advantages or abilities: (1) combining it with existing MIL networks for predictive performance enhancement; (2) effectively utilizing unlabeled WSIs for semi-supervised learning; (3) the robustness to patch occlusion, image Gaussian blurring, and image HED color variation.
Our experiments run on a workstation with 2 V100s GPUs (python 3.6, torch 1.9.0, and cuda 11.1).
Here we show how to run AdvMIL for WSI survival analysis.
WSI preprocessing toolkit: it is highly recommended to utilize an easy-to-use tool, CLAM, for WSI preprocessing, including dataset download, tissue segmentation, patching, and patch feature extraction. Please see a detailed documentation at https://github.com/mahmoodlab/CLAM, or refer to Tutorial - Processing WSIs for MIL from Scratch for a complete and more detailed tutorial built opon CLAM.
Next, we provide detailed steps to preprocess WSIs using CLAM
(assuming you have already known its basic usage):
patching at level = 2
(downsampled 16x
): go to CLAM directory and run
# DATA_DIRECTORY should be the path to raw images (e.g., svs files).
# '/data/nlst/processed/tiles-l2-s256' is the path for saving patching results.
python create_patches_fp.py \
--source DATA_DIRECTORY \
--save_dir /data/nlst/processed/tiles-l2-s256 \
--patch_level 2 --patch_size 256 --seg --patch --stitch
This step will save the coordinates of segmented patches at level = 2
.
patching at level = 1
(downsampled 4x
): go back to AdvMIL, go to ./tools
, and run
# '/data/nlst/processed/tiles-l2-s256' is the path for reading the coordinates of patches at the level 2.
# '/data/nlst/processed/tiles-l1-s256' is the path for saving the coordinates of patches at the level 1.
python3 big_to_small_patching.py \
/data/nlst/processed/tiles-l2-s256 \
/data/nlst/processed/tiles-l1-s256
This step will compute and save the patch coordinates at level = 1
. /data/nlst/processed/tiles-l2-s256
is exactly the full path of the patch coordinates at level = 2
from previous step.
Feature extracting: go to CLAM directory and run
# DATA_DIRECTORY should be the path to raw images (e.g., svs files).
# 'process_list_autogen.csv' is a csv file generated by the first step, initially in '/data/nlst/processed/tiles-l2-s256'.
# This csv file is automatically copied to '/data/nlst/processed/tiles-l1-s256'.
CUDA_VISIBLE_DEVICES=0,1 python extract_features_fp.py \
--data_h5_dir /data/nlst/processed/tiles-l1-s256 \
--data_slide_dir DATA_DIRECTORY \
--csv_path /data/nlst/processed/tiles-l1-s256/process_list_autogen.csv \
--feat_dir /data/nlst/processed/feat-l1-RN50-B \
--batch_size 512 --slide_ext .svs
This step will compute all patch features and save them in /data/nlst/processed/feat-l1-RN50-B
. Note that --data_h5_dir
should be the full path of the patch coordinates at level = 1
from previous step.
Now it is expected that you have the following file directories (taking nlst
for example) in your computer.
/data/nlst/processed/feat-l1-RN50-B
: path to all patch features. /data/nlst/processed/tiles-l1-s256
: path to all segmented patch coordinates. ./table/nlst_path_full.csv
: path to the csv table with patient_id
, pathology_id
, t
, e
. We have uploaded these files. Please see them in ./table
. ./data_split/nlst-foldk.npz
: path to the file with data splitting details. We have uploaded these files. Please see them in ./data_split
. A detailed file structure would be as follows:
/data/nlst # The directory of nlst.
└─ processed
├─ feat-l1-RN50-B # The directory of all patch features (level = 1).
│ └─ pt_files
│ ├─ 10015.pt # The patch features of slide 10015.
│ ├─ 10016.pt
│ └─ ...
│
├─ tiles-l1-s256 # The directory of all segmented patch coordinates (level = 1).
│ ├─ patches
│ │ ├─ 10015.h5 # The patch coordinates of slide 10015.
│ │ ├─ 10016.h5
│ │ └─ ...
│ └─ process_list_autogen.csv # csv file recording all processing details (autogeneraed by CLAM).
└─ ... # other intermediate directories, such as "tiles-l2-s256" from the first step.
Options: if you want to a graph-based or cluster-based model, you should further prepare the followings:
./tools/
and run python3 patchgcn_graph_s2.py nlst
. It will generate a new directory /data/nlst/processed/wsigraph-l1-features
that stores patient-level graphs. ./tools/
and run python3 deepattnmisl_cluster.py nlst 8
. It will generate a new directory /data/nlst/processed/patch-l1-cluster8-ids
that stores cluster labels. Now you should prepare a YAML
file for configuring the setting of read/save path, network architecture, network training, etc. We have provided an example configuration (./config/cfg_nlst.yaml
) for training nlst with AdvMIL, as well as the detailed descriptions regarding important configurations.
Here we show and explain some important configurations so that you can successfully finish the configuration of network training.
save_path
: the path for saving models, predictions, configurations, and evaluation results.wandb_prj
: wandb project name, used to record all training logs. Please refer to wandb for more details.bcb_mode
: the backbone of generator, one of patch
(ESAT), graph
(PatchGCN), cluster
(DeepAttnMISL), and abmil
(ABMIL).disc_prj_iprd
: the way of fusion operation, one of instance
(RLIP) and bag
(regular fusion).gen_noi_noise
: the setting of noise adding, one of 0-1
, 1-0
, and 1-1
.semi_training
: whether running semi-supervised training with AdvMIL. All the related configurations are started with ssl_
.test
: whether in a test mode. Trained models will be loaded from test_load_path
for testing the samples in test_path
. All the related configurations are started with test_
. Three running modes in AdvMIL:
./config/cfg_nlst.yaml
).test: False
to test: True
in ./config/cfg_nlst.yaml
before running. semi_training: False
to semi_training: True
in ./config/cfg_nlst.yaml
before running. When you finished the configuration above, you can run the following command (on all folds) for training, validation, and testing:
# load your config in config/cfg_nlst.yaml, and run AdvMIL
# there are three possible running modes after configuration:
# 1. common train/val/test pipeline
# 2. only test using the models trained before (if set `test` to True)
# 3. semi-supervised train/val/test pipeline (if set `semi_training`` to True)
python3 main.py \
--config config/cfg_nlst.yaml \
--handler adv \
--multi_run
If you only run once (e.g., only single fold), you can use the following command:
# load your config in config/cfg_nlst.yaml, and run AdvMIL
# there are three possible running modes after configuration:
# 1. common train/val/test pipeline (single fold)
# 2. only test using the models trained before (if set `test` to True)
# 3. semi-supervised train/val/test pipeline (if set `semi_training`` to True)
python3 main.py \
--config config/cfg_nlst.yaml \
--handler adv
The best models trained on WSIs, with an architecture of ESAT + AdvMIL, and their training logs are publicly-available at Google Rrive - AdvMIL-models.
If this work helps your research, please consider citing our paper:
@article{LIU2024103020,
author = {Liu, Pei and Ji, Luping and Ye, Feng and Fu, Bo},
title = {{AdvMIL: Adversarial multiple instance learning for the survival analysis on whole-slide images}},
journal = {Medical Image Analysis},
volume = {91},
pages = {103020},
year = {2024},
doi = {https://doi.org/10.1016/j.media.2023.103020},
}