--- license: mit library_name: pytorch tags: - pathology - computational-pathology - virtual-staining - multiplex-immunofluorescence - diffusion - flow-matching - image-to-image base_model: xiangjx/MuPaD-512 pipeline_tag: image-to-image --- # MuPaD-HE2mIF Predict a **16-channel Orion multiplexed immunofluorescence (mIF) panel from a single H&E tile**, by finetuning [MuPaD-512](https://huggingface.co/xiangjx/MuPaD-512) as a conditional **mean** predictor. Code: [github.com/jinxixiang/MUPAD](https://github.com/jinxixiang/MUPAD) → `5-HE2mIF/` ## Why a mean predictor The evaluation metric is a per-channel Pearson correlation against ground truth, and that is maximized by the conditional mean `E[mIF | H&E]` — not by a sharp sample from `p(mIF | H&E)`. The model is trained with flow matching but **read out at `t = 1`**, where the input is pure noise and the loss-optimal output *is* the conditional mean. Inference is a single forward pass, not a multi-step sampler. ``` z_he = LatentNorm_he( HE_VAE(he) ) # pretrained H&E latent, frozen z_mif = LatentNorm_mif( mIF_VAE(mif) ) # stage-1 mIF latent, frozen z_t = (1-t)·z_mif + t·ε x̂ = SiT( [z_t ; z_he], t, MUSK(he) ) # x-prediction inference: x̂ = SiT( [ε ; z_he], t=1, MUSK(he) ) → decode ``` H&E enters as **input, not context**: `z_he` is concatenated channel-wise at the patch embedder, and the new condition slots are initialized by copying the pretrained patch-embed weights, so `z_he` lives in exactly the latent space the trunk was pretrained on. MUSK cross-attention is a secondary semantic channel. ## Contents ``` stage1_vae/ vae/config.json vae/diffusion_pytorch_model.safetensors 16-channel mIF VAE (335 MB) latent_stats.json mIF latent mean/var, fitted at 256px latent_stats_512.json same, fitted at 512px <- used at inference mif_input_scale.json raw-intensity scaling used by the VAE config.yaml stage-1 training config stage2_denoising/ diffusion_pytorch_model.safetensors SiT trunk, 1.39B params, fp32 (5.56 GB) config.yaml stage-2 training config ``` **Latent statistics are resolution-specific.** `latent_stats.json` was fitted at the VAE's own 256px; applying it at 512px leaves normalized latents at std 0.68–0.79 instead of 1.0, which unbalances the interpolant. Use `latent_stats_512.json` for 512px inference — the code selects it automatically. ## Requires This repository holds only the HE2mIF-specific weights. You also need [**xiangjx/MuPaD-512**](https://huggingface.co/xiangjx/MuPaD-512) for the SiT trunk architecture, the H&E VAE, and the MUSK encoder. ## Usage ```bash git clone https://github.com/jinxixiang/MUPAD && cd MUPAD/5-HE2mIF pip install -r ../requirements.txt huggingface-cli download xiangjx/MuPaD-512 --local-dir pretrained/MuPaD-512 huggingface-cli download xiangjx/MuPaD-HE2mIF --local-dir exps export MUPAD_PRETRAINED_ROOT=$PWD/pretrained/MuPaD-512 export ORION_DATA_ROOT=/path/to/ORIONCRC_dataset_tile_20x ``` ```bash python generate.py \ --config configs/stage2_denoising.yaml \ --denoise-ckpt exps/stage2_denoising/diffusion_pytorch_model.safetensors \ --vae-ckpt exps/stage1_vae \ --val-csv $ORION_DATA_ROOT/val_dataframe.csv \ --out-dir predictions/run \ --guidance-scale 1.25 python eval/evaluate.py --pred-dir predictions/run \ --csv $ORION_DATA_ROOT/val_dataframe.csv --out results.csv ``` Guidance uses zeroed conditioning as the null branch (there is no conditioning dropout in training). `--guidance-scale 1.25` measurably beats the unguided default. ## Markers 16 of Orion's 17 channels. `PD-1` is excluded: its positivity column is 1.0000 on every training tile — a broken threshold, not biology — so it carries no usable supervision. `Hoechst`, `CD31`, `CD45`, `CD68`, `CD4`, `FOXP3`, `CD8a`, `CD45RO`, `CD20`, `PD-L1`, `CD3e`, `CD163`, `E-cadherin`, `Ki67`, `Pan-CK`, `SMA` ## Data Trained on **ORION-CRC** tiles at 20× (512 × 512 px), [Zenodo record 15340874](https://zenodo.org/records/15340874). ## License MIT, following the REPA/SiT lineage the trunk derives from.