Upload folder using huggingface_hub
Browse files- OpenPath/README.md +1 -1
- OpenPath/dinov2/configs/train/openpath_vitg14.yaml +1 -1
- README.md +4 -3
- eval/run_hest_ref.py +45 -0
- scripts/run_hest_3way.py +1 -1
OpenPath/README.md
CHANGED
|
@@ -6,7 +6,7 @@ Kaiko.AI's *Midnight*), with substantial modifications:
|
|
| 6 |
|
| 7 |
- **Corpus:** trains on the public **OpenPath corpus** (native 40× tiles) via a WebDataset
|
| 8 |
loader (`dinov2/data/openpath_wds.py`) instead of the upstream TCGA-12K Parquet stream.
|
| 9 |
-
- **Gram anchoring** (
|
| 10 |
teacher in `dinov2/train/ssl_meta_arch.py`, to dampen dense-feature degradation.
|
| 11 |
- **Schedule:** flat (near-constant) LR, `early_stop` at ~1 native epoch (345k iters).
|
| 12 |
- Multi-node FSDP launcher / crash-tolerant auto-resume / online HEST probing under `../scripts/`.
|
|
|
|
| 6 |
|
| 7 |
- **Corpus:** trains on the public **OpenPath corpus** (native 40× tiles) via a WebDataset
|
| 8 |
loader (`dinov2/data/openpath_wds.py`) instead of the upstream TCGA-12K Parquet stream.
|
| 9 |
+
- **Gram anchoring** (technique from DINOv3; loss re-implemented clean-room, Apache-2.0): `dinov2/loss/gram_loss.py` + a frozen anchor
|
| 10 |
teacher in `dinov2/train/ssl_meta_arch.py`, to dampen dense-feature degradation.
|
| 11 |
- **Schedule:** flat (near-constant) LR, `early_stop` at ~1 native epoch (345k iters).
|
| 12 |
- Multi-node FSDP launcher / crash-tolerant auto-resume / online HEST probing under `../scripts/`.
|
OpenPath/dinov2/configs/train/openpath_vitg14.yaml
CHANGED
|
@@ -82,7 +82,7 @@ evaluation:
|
|
| 82 |
breakhis_root: ""
|
| 83 |
pcam_root: ""
|
| 84 |
|
| 85 |
-
# Gram anchoring (
|
| 86 |
# student vs a frozen anchor. Dampens dense-feature degradation during long training.
|
| 87 |
gram:
|
| 88 |
use_loss: true
|
|
|
|
| 82 |
breakhis_root: ""
|
| 83 |
pcam_root: ""
|
| 84 |
|
| 85 |
+
# Gram anchoring (technique from DINOv3; clean-room re-implementation): MSE between L2-normalized patch-token Gram matrices of
|
| 86 |
# student vs a frozen anchor. Dampens dense-feature degradation during long training.
|
| 87 |
gram:
|
| 88 |
use_loss: true
|
README.md
CHANGED
|
@@ -24,8 +24,8 @@ The corpus and checkpoints are hosted separately (see below).
|
|
| 24 |
> **Headline result.** On **AMC-HCC-ST** — a contamination-free in-house Asan Medical Center
|
| 25 |
> hepatocellular-carcinoma spatial-transcriptomics cohort, the least leakage-prone benchmark since no
|
| 26 |
> public foundation model was trained on it — OpenPath **ranks #1 among seven foundation models** (mean
|
| 27 |
-
> Pearson: OpenPath **0.323** > UNI2-h 0.301 > OpenMidnight 0.300 > Virchow2 0.292 > prov-gigapath 0.286
|
| 28 |
-
>
|
| 29 |
> See [Evaluation](#evaluation).
|
| 30 |
|
| 31 |
- **Encoder:** ViT-g/14 (reg4), 1536-dim CLS embedding
|
|
@@ -40,7 +40,7 @@ The corpus and checkpoints are hosted separately (see below).
|
|
| 40 |
OpenPath/ # DINOv2 training fork (derived from OpenMidnight)
|
| 41 |
dinov2/train/train.py # training loop (+ gram-weight schedule)
|
| 42 |
dinov2/train/ssl_meta_arch.py # SSL arch (+ frozen gram-anchor teacher)
|
| 43 |
-
dinov2/loss/gram_loss.py # gram anchoring loss (
|
| 44 |
dinov2/data/openpath_wds.py # WebDataset loader for the OpenPath corpus
|
| 45 |
dinov2/configs/train/openpath_vitg14.yaml # training config
|
| 46 |
scripts/
|
|
@@ -52,6 +52,7 @@ eval/ # downstream benchmark / referenc
|
|
| 52 |
openpath_eva_backbone.py # backbone factories: OpenPath + Phikon / OpenMidnight / UNI / UNI2-h / gigapath / Virchow2
|
| 53 |
st_bench.py # AMC-HCC-ST benchmark (LOPO ridge, headline)
|
| 54 |
run_patch_eval.sh # PCam / CRC / BACH patch probing via kaiko-eva
|
|
|
|
| 55 |
eva_configs/ # eva YAML configs (crc / bach / patch_camelyon)
|
| 56 |
requirements.txt
|
| 57 |
```
|
|
|
|
| 24 |
> **Headline result.** On **AMC-HCC-ST** — a contamination-free in-house Asan Medical Center
|
| 25 |
> hepatocellular-carcinoma spatial-transcriptomics cohort, the least leakage-prone benchmark since no
|
| 26 |
> public foundation model was trained on it — OpenPath **ranks #1 among seven foundation models** (mean
|
| 27 |
+
> Pearson: OpenPath **0.323** > UNI2-h 0.301 > OpenMidnight 0.300 > Virchow2 0.292 > prov-gigapath 0.286 >
|
| 28 |
+
> Phikon-v2 0.274 > UNI 0.257). Released checkpoint: **`training_316250`** (in `openpath-checkpoints`).
|
| 29 |
> See [Evaluation](#evaluation).
|
| 30 |
|
| 31 |
- **Encoder:** ViT-g/14 (reg4), 1536-dim CLS embedding
|
|
|
|
| 40 |
OpenPath/ # DINOv2 training fork (derived from OpenMidnight)
|
| 41 |
dinov2/train/train.py # training loop (+ gram-weight schedule)
|
| 42 |
dinov2/train/ssl_meta_arch.py # SSL arch (+ frozen gram-anchor teacher)
|
| 43 |
+
dinov2/loss/gram_loss.py # gram anchoring loss (clean-room re-impl, Apache-2.0)
|
| 44 |
dinov2/data/openpath_wds.py # WebDataset loader for the OpenPath corpus
|
| 45 |
dinov2/configs/train/openpath_vitg14.yaml # training config
|
| 46 |
scripts/
|
|
|
|
| 52 |
openpath_eva_backbone.py # backbone factories: OpenPath + Phikon / OpenMidnight / UNI / UNI2-h / gigapath / Virchow2
|
| 53 |
st_bench.py # AMC-HCC-ST benchmark (LOPO ridge, headline)
|
| 54 |
run_patch_eval.sh # PCam / CRC / BACH patch probing via kaiko-eva
|
| 55 |
+
run_hest_ref.py # HEST-1K for reference FMs (UNI / UNI2-h / gigapath / Virchow2)
|
| 56 |
eva_configs/ # eva YAML configs (crc / bach / patch_camelyon)
|
| 57 |
requirements.txt
|
| 58 |
```
|
eval/run_hest_ref.py
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""HEST-1K for reference timm pathology FMs (UNI/UNI2/gigapath/Virchow2).
|
| 3 |
+
run_hest_3way와 동일 프로토콜: 224px, ImageNet norm, CLS 임베딩, PCA256+ridge, 9 task 평균 Pearson.
|
| 4 |
+
(참조모델 CRC/BACH/HCC와 동일하게 CLS만 사용 — Virchow2도 CLS 1280.)
|
| 5 |
+
"""
|
| 6 |
+
import argparse, os, sys
|
| 7 |
+
import torch
|
| 8 |
+
from torchvision import transforms
|
| 9 |
+
|
| 10 |
+
ROOT = os.environ.get("OPENPATH_ROOT", os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
| 11 |
+
BENCH = os.environ.get("HEST_BENCH_ROOT", f"{ROOT}/data/eva/hest_bench")
|
| 12 |
+
ALL = ["IDC", "PRAD", "PAAD", "SKCM", "COAD", "READ", "CCRCC", "LUNG", "LYMPH_IDC"]
|
| 13 |
+
eval_tf = transforms.Compose([
|
| 14 |
+
transforms.Resize(224), transforms.CenterCrop(224), transforms.ToTensor(),
|
| 15 |
+
transforms.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225)),
|
| 16 |
+
])
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
def main():
|
| 20 |
+
ap = argparse.ArgumentParser()
|
| 21 |
+
ap.add_argument("--backbone", required=True, choices=["uni", "uni2", "gigapath", "virchow2"])
|
| 22 |
+
ap.add_argument("--exp-code", required=True)
|
| 23 |
+
ap.add_argument("tasks", nargs="*")
|
| 24 |
+
args = ap.parse_args()
|
| 25 |
+
|
| 26 |
+
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
| 27 |
+
import openpath_eva_backbone as B
|
| 28 |
+
fn = {"uni": B.build_uni, "uni2": B.build_uni2,
|
| 29 |
+
"gigapath": B.build_gigapath, "virchow2": B.build_virchow2}[args.backbone]
|
| 30 |
+
model = fn().cuda().eval()
|
| 31 |
+
|
| 32 |
+
from hest.bench import benchmark
|
| 33 |
+
tasks = args.tasks or ALL
|
| 34 |
+
print(f"[hest-ref] backbone={args.backbone} exp={args.exp_code} tasks={tasks}", flush=True)
|
| 35 |
+
dataset_perfs, perf_per_enc = benchmark(
|
| 36 |
+
model, eval_tf, torch.float32,
|
| 37 |
+
exp_code=args.exp_code, datasets=tasks, bench_data_root=BENCH,
|
| 38 |
+
embed_dataroot=os.environ.get("HEST_EMBED_ROOT", f"eval/ST_data_emb_{args.exp_code}"),
|
| 39 |
+
dimreduce="PCA", latent_dim=256, method="ridge", normalize=True,
|
| 40 |
+
)
|
| 41 |
+
print(f"=== HEST per-encoder avg Pearson [{args.exp_code}] ===", perf_per_enc, flush=True)
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
if __name__ == "__main__":
|
| 45 |
+
main()
|
scripts/run_hest_3way.py
CHANGED
|
@@ -17,7 +17,7 @@ import torch
|
|
| 17 |
import torch.nn as nn
|
| 18 |
from torchvision import transforms
|
| 19 |
|
| 20 |
-
ROOT = "
|
| 21 |
BENCH = os.environ.get("HEST_BENCH_ROOT", f"{ROOT}/data/eva/hest_bench")
|
| 22 |
ALL = ["IDC", "PRAD", "PAAD", "SKCM", "COAD", "READ", "CCRCC", "LUNG", "LYMPH_IDC"]
|
| 23 |
|
|
|
|
| 17 |
import torch.nn as nn
|
| 18 |
from torchvision import transforms
|
| 19 |
|
| 20 |
+
ROOT = os.environ.get("OPENPATH_ROOT", os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
| 21 |
BENCH = os.environ.get("HEST_BENCH_ROOT", f"{ROOT}/data/eva/hest_bench")
|
| 22 |
ALL = ["IDC", "PRAD", "PAAD", "SKCM", "COAD", "READ", "CCRCC", "LUNG", "LYMPH_IDC"]
|
| 23 |
|