Upload folder using huggingface_hub
Browse files- OpenMidnight/dinov2/configs/train/openpath_vitg14.yaml +95 -0
- README.md +107 -34
- scripts/autoresume.sh +45 -0
- scripts/launch.sh +38 -0
- scripts/run_hest_3way.py +2 -2
- scripts/watch_eval.sh +43 -0
OpenMidnight/dinov2/configs/train/openpath_vitg14.yaml
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# OpenPath โ ViT-g/14 pathology FM pre-training config.
|
| 2 |
+
# DINOv2 (DINO + iBOT + KDE) + gram anchoring, warm-started from Meta DINOv2 ViT-g/14-reg,
|
| 3 |
+
# on the public OpenPath corpus (native 40x tiles). Global batch = 64/GPU x 40 GPU = 2560.
|
| 4 |
+
#
|
| 5 |
+
# LR regime: near-constant (flat). `epochs` only sets the schedule horizon (very large), so the
|
| 6 |
+
# cosine barely descends; the run actually stops at `early_stop`. This keeps LR/wd/momentum
|
| 7 |
+
# near their initial values throughout training.
|
| 8 |
+
compute_precision:
|
| 9 |
+
grad_scaler: false
|
| 10 |
+
teacher:
|
| 11 |
+
backbone:
|
| 12 |
+
sharding_strategy: SHARD_GRAD_OP
|
| 13 |
+
mixed_precision: {param_dtype: bf16, reduce_dtype: bf16, buffer_dtype: fp32}
|
| 14 |
+
dino_head:
|
| 15 |
+
sharding_strategy: SHARD_GRAD_OP
|
| 16 |
+
mixed_precision: {param_dtype: bf16, reduce_dtype: bf16, buffer_dtype: fp32}
|
| 17 |
+
ibot_head:
|
| 18 |
+
sharding_strategy: SHARD_GRAD_OP
|
| 19 |
+
mixed_precision: {param_dtype: bf16, reduce_dtype: bf16, buffer_dtype: fp32}
|
| 20 |
+
student:
|
| 21 |
+
backbone:
|
| 22 |
+
sharding_strategy: SHARD_GRAD_OP
|
| 23 |
+
mixed_precision: {param_dtype: bf16, reduce_dtype: bf16, buffer_dtype: fp32}
|
| 24 |
+
dino_head:
|
| 25 |
+
sharding_strategy: SHARD_GRAD_OP
|
| 26 |
+
mixed_precision: {param_dtype: bf16, reduce_dtype: fp32, buffer_dtype: fp32}
|
| 27 |
+
ibot_head:
|
| 28 |
+
sharding_strategy: SHARD_GRAD_OP
|
| 29 |
+
mixed_precision: {param_dtype: bf16, reduce_dtype: fp32, buffer_dtype: fp32}
|
| 30 |
+
dino:
|
| 31 |
+
head_n_prototypes: 131072
|
| 32 |
+
head_bottleneck_dim: 384
|
| 33 |
+
do_kde: True
|
| 34 |
+
kde_loss_weight: .05
|
| 35 |
+
koleo_loss_weight: 0
|
| 36 |
+
do_koleo: False
|
| 37 |
+
ibot:
|
| 38 |
+
loss_weight: 1.0
|
| 39 |
+
mask_sample_probability: 0.5
|
| 40 |
+
mask_ratio_min_max:
|
| 41 |
+
- 0.1
|
| 42 |
+
- 0.45
|
| 43 |
+
separate_head: true
|
| 44 |
+
head_n_prototypes: 131072
|
| 45 |
+
train:
|
| 46 |
+
# OpenPath corpus (taejoon89/openpath-corpus). Point to the downloaded shards:
|
| 47 |
+
sample_list_path: "openpath:glob=/path/to/openpath-corpus/*/tiles/shards/w*/*.tar"
|
| 48 |
+
streaming_from_hf: false
|
| 49 |
+
batch_size_per_gpu: 64 # x 40 GPU = global 2560
|
| 50 |
+
centering: sinkhorn_knopp
|
| 51 |
+
use_pretrained: True # Meta DINOv2 ViT-g/14-reg warm-start (set MODEL.WEIGHTS)
|
| 52 |
+
OFFICIAL_EPOCH_LENGTH: 1250
|
| 53 |
+
saveckp_freq: 8 # resume ckpt every 8 x 1250 = 10,000 iters
|
| 54 |
+
num_workers: 10
|
| 55 |
+
prefetch_factor: 4
|
| 56 |
+
skip_checkpointer: false
|
| 57 |
+
student:
|
| 58 |
+
arch: vit_giant2
|
| 59 |
+
patch_size: 14
|
| 60 |
+
drop_path_rate: 0.4
|
| 61 |
+
ffn_layer: swiglufused
|
| 62 |
+
block_chunks: 4
|
| 63 |
+
num_register_tokens: 4
|
| 64 |
+
interpolate_antialias: true
|
| 65 |
+
interpolate_offset: 0.0
|
| 66 |
+
teacher:
|
| 67 |
+
momentum_teacher: 0.994
|
| 68 |
+
warmup_teacher_temp_epochs: 41 # 0.27 epoch = 51,250 iters
|
| 69 |
+
optim:
|
| 70 |
+
epochs: 8000 # schedule horizon only (=10,000,000 iter); LR/wd/momentum near-constant
|
| 71 |
+
early_stop: 276 # actual stop: 276 x 1250 = 345,000 iters (~1 native epoch)
|
| 72 |
+
weight_decay_end: 0.2 # not reached within early_stop (wd stays ~0.040)
|
| 73 |
+
base_lr: 2.0e-04 # sqrt_wrt_1024 -> effective ~3.16e-4 @ global 2560
|
| 74 |
+
warmup_epochs: 9 # ~11,250 iter (~4.9%); must be an integer
|
| 75 |
+
freeze_last_layer_epochs: 1
|
| 76 |
+
layerwise_decay: 1.0
|
| 77 |
+
crops:
|
| 78 |
+
local_crops_size: 98
|
| 79 |
+
evaluation:
|
| 80 |
+
eval_period_iterations: 5750 # save a teacher checkpoint every 5,750 iters
|
| 81 |
+
bach_root: ""
|
| 82 |
+
breakhis_root: ""
|
| 83 |
+
pcam_root: ""
|
| 84 |
+
|
| 85 |
+
# Gram anchoring (ported from DINOv3): 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
|
| 89 |
+
normalized: true
|
| 90 |
+
remove_neg: true
|
| 91 |
+
loss_weight: 40.0 # ~5-8% of total loss; lower if it over-constrains DINO/iBOT
|
| 92 |
+
it_first_update: 57500 # activate near the dense-feature peak
|
| 93 |
+
ramp_iters: 3000 # linear ramp of the gram weight
|
| 94 |
+
# Anchor = a strong earlier OpenPath teacher checkpoint (see taejoon89/openpath-checkpoints):
|
| 95 |
+
ckpt: /path/to/openpath-checkpoints/training_63250/teacher_checkpoint.pth
|
README.md
CHANGED
|
@@ -1,48 +1,121 @@
|
|
| 1 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
|
| 3 |
-
|
| 4 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
|
| 6 |
-
## ๊ตฌ์ฑ
|
| 7 |
```
|
| 8 |
-
OpenMidnight/
|
| 9 |
-
dinov2/train/train.py
|
| 10 |
-
dinov2/train/ssl_meta_arch.py
|
| 11 |
-
dinov2/loss/gram_loss.py
|
| 12 |
-
dinov2/data/openpath_wds.py
|
| 13 |
-
dinov2/configs/train/
|
| 14 |
scripts/
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
run_hest_3way.py
|
| 19 |
requirements.txt
|
| 20 |
```
|
| 21 |
|
| 22 |
-
##
|
| 23 |
-
|
| 24 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
|
| 26 |
-
|
| 27 |
-
-
|
| 28 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
|
| 30 |
-
##
|
| 31 |
-
- ViT-g/14 reg4, patch14, warm-start = Meta DINOv2 ViT-g/14-reg.
|
| 32 |
-
- flat-LR (epochs 8000 ์งํ, early_stop 276=345k=native 1 epoch), base_lr 2e-4 (์คํจ 3.16e-4 @global 2560).
|
| 33 |
-
- **gram anchoring**: weight 40, it_first_update 57500(peak ์ง์ ํ์ฑ), ramp 3000. loss = ์ ๊ทํ patch Gram matrix MSE(student vs anchor).
|
| 34 |
-
- FSDP SHARD_GRAD_OP, bf16, sinkhorn-knopp centering, DINO+iBOT+KDE loss.
|
| 35 |
|
| 36 |
-
## ํ์ต ์คํ (๋ฉํฐ๋
ธ๋ 40 GPU ์)
|
| 37 |
```bash
|
| 38 |
-
export PYTHONPATH=$PWD/OpenMidnight
|
| 39 |
-
CFG=OpenMidnight/dinov2/configs/train/
|
| 40 |
-
|
| 41 |
-
|
|
|
|
| 42 |
```
|
| 43 |
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 47 |
|
| 48 |
-
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: apache-2.0
|
| 3 |
+
tags:
|
| 4 |
+
- pathology
|
| 5 |
+
- histopathology
|
| 6 |
+
- foundation-model
|
| 7 |
+
- self-supervised
|
| 8 |
+
- dinov2
|
| 9 |
+
- vision-transformer
|
| 10 |
+
- digital-pathology
|
| 11 |
+
library_name: pytorch
|
| 12 |
+
pipeline_tag: image-feature-extraction
|
| 13 |
+
---
|
| 14 |
|
| 15 |
+
# OpenPath โ Pathology Foundation Model (training code)
|
| 16 |
+
|
| 17 |
+
**OpenPath** is a vision foundation model for computational pathology: a **ViT-g/14** encoder
|
| 18 |
+
pre-trained with self-supervision (**DINOv2** + **gram anchoring**) on **public-only** whole-slide
|
| 19 |
+
histopathology tiles. This repository contains the **training / reproduction code**. The corpus and
|
| 20 |
+
checkpoints are hosted separately (see below).
|
| 21 |
+
|
| 22 |
+
- **Encoder:** ViT-g/14 (reg4), 1536-dim CLS embedding
|
| 23 |
+
- **Objective:** DINO + iBOT + KDE (DINOv2) with **gram anchoring** ported from DINOv3
|
| 24 |
+
- **Data:** public pathology WSIs only (TCGA, TCIA, GTEx, CAMELYON, ACROBAT, SurGen, โฆ), re-tiled at native 40ร
|
| 25 |
+
- **Warm start:** Meta DINOv2 ViT-g/14-reg
|
| 26 |
+
- **Training:** FSDP (SHARD_GRAD_OP), bf16, flat learning-rate schedule, 40ร B200 (multi-node)
|
| 27 |
+
|
| 28 |
+
## Repository layout
|
| 29 |
|
|
|
|
| 30 |
```
|
| 31 |
+
OpenMidnight/ # DINOv2 training fork
|
| 32 |
+
dinov2/train/train.py # training loop (+ gram-weight schedule)
|
| 33 |
+
dinov2/train/ssl_meta_arch.py # SSL arch (+ frozen gram-anchor teacher)
|
| 34 |
+
dinov2/loss/gram_loss.py # gram anchoring loss (ported from DINOv3)
|
| 35 |
+
dinov2/data/openpath_wds.py # WebDataset loader for the OpenPath corpus
|
| 36 |
+
dinov2/configs/train/openpath_vitg14.yaml # training config
|
| 37 |
scripts/
|
| 38 |
+
launch.sh # multi-node launcher (host + workers, 40 GPU)
|
| 39 |
+
autoresume.sh # crash-tolerant auto-resume
|
| 40 |
+
watch_eval.sh # online HEST probing per checkpoint
|
| 41 |
+
run_hest_3way.py # HEST evaluation (Meta DINOv2 / Phikon-v2 / OpenPath)
|
| 42 |
requirements.txt
|
| 43 |
```
|
| 44 |
|
| 45 |
+
## Related artifacts
|
| 46 |
+
|
| 47 |
+
| Artifact | Hugging Face repo | Notes |
|
| 48 |
+
|---|---|---|
|
| 49 |
+
| **Corpus** | `taejoon89/openpath-corpus` | Native 40ร pathology tiles, 33,991 WebDataset shards / ~17 TB (public, gated) |
|
| 50 |
+
| **Checkpoints** | `taejoon89/openpath-checkpoints` | OpenPath teacher checkpoints across training (private) |
|
| 51 |
+
| **Code** | `taejoon89/openpath` | This repository |
|
| 52 |
+
|
| 53 |
+
The training config points to the corpus via
|
| 54 |
+
`train.sample_list_path: "openpath:glob=<corpus>/*/tiles/shards/w*/*.tar"`. The gram anchor
|
| 55 |
+
(`gram.ckpt`) is an earlier OpenPath teacher checkpoint from `openpath-checkpoints`.
|
| 56 |
+
|
| 57 |
+
## Method โ gram anchoring
|
| 58 |
+
|
| 59 |
+
Long self-supervised training degrades dense/patch features. Following **DINOv3**, we add a
|
| 60 |
+
**gram anchoring** loss: the MSE between the L2-normalized patch-token Gram (similarity) matrices
|
| 61 |
+
of the student and a **frozen anchor** model (a strong earlier checkpoint). The loss weight is `40`
|
| 62 |
+
and it activates near the dense-feature peak (iteration `57,500`) with a 3k-iter ramp. This
|
| 63 |
+
**dampens the post-peak decline** of dense representations while DINO/iBOT keep optimizing the
|
| 64 |
+
global representation.
|
| 65 |
+
|
| 66 |
+
## Key hyper-parameters
|
| 67 |
|
| 68 |
+
| | |
|
| 69 |
+
|---|---|
|
| 70 |
+
| Arch | `vit_giant2`, patch 14, 4 register tokens, SwiGLU FFN |
|
| 71 |
+
| Batch | 64 / GPU ร 40 GPU = global 2560 |
|
| 72 |
+
| LR | base 2e-4 (effective โ 3.16e-4 @ global 2560), flat (near-constant) |
|
| 73 |
+
| Schedule | `epochs: 8000` horizon, `early_stop: 276` โ 345k iters โ 1 native epoch |
|
| 74 |
+
| gram | weight 40, `it_first_update 57500`, ramp 3000, normalized, remove-neg |
|
| 75 |
+
| Precision | bf16, FSDP SHARD_GRAD_OP, sinkhorn-knopp centering |
|
| 76 |
|
| 77 |
+
## Reproducing training
|
|
|
|
|
|
|
|
|
|
|
|
|
| 78 |
|
|
|
|
| 79 |
```bash
|
| 80 |
+
export PYTHONPATH="$PWD/OpenMidnight"
|
| 81 |
+
CFG=OpenMidnight/dinov2/configs/train/openpath_vitg14.yaml
|
| 82 |
+
# edit CFG: train.sample_list_path (corpus glob), gram.ckpt (anchor checkpoint), MODEL.WEIGHTS (DINOv2 warm-start)
|
| 83 |
+
bash scripts/launch.sh openpathrun "$CFG" <output_dir> <log_dir>
|
| 84 |
+
# optionally run scripts/autoresume.sh (background) and scripts/watch_eval.sh (online HEST)
|
| 85 |
```
|
| 86 |
|
| 87 |
+
Extract CLS embeddings for downstream use:
|
| 88 |
+
|
| 89 |
+
```python
|
| 90 |
+
import torch, dinov2.models.vision_transformer as vits
|
| 91 |
+
ck = torch.load("teacher_checkpoint.pth", map_location="cpu", weights_only=False)
|
| 92 |
+
sd = {k[len("backbone."):]: v for k, v in ck["teacher"].items() if k.startswith("backbone.")}
|
| 93 |
+
m = vits.vit_giant2(patch_size=14, img_size=224, block_chunks=4, num_register_tokens=4,
|
| 94 |
+
ffn_layer="swiglufused", init_values=1e-5,
|
| 95 |
+
interpolate_antialias=True, interpolate_offset=0.0)
|
| 96 |
+
m.load_state_dict(sd, strict=True); m.eval()
|
| 97 |
+
cls = m.forward_features(x)["x_norm_clstoken"] # (B, 1536)
|
| 98 |
+
```
|
| 99 |
+
|
| 100 |
+
## Evaluation
|
| 101 |
+
|
| 102 |
+
Frozen-encoder linear/ridge probing. The headline benchmark is a **contamination-free** in-house
|
| 103 |
+
HCC (hepatocellular carcinoma) Visium spatial-transcriptomics cohort (leave-one-patient-out, mean
|
| 104 |
+
Pearson over top-50 highly-variable genes) โ no public FM was trained on it.
|
| 105 |
+
|
| 106 |
+
| Benchmark (metric) | OpenPath (best) | OpenMidnight | Phikon-v2 |
|
| 107 |
+
|---|---|---|---|
|
| 108 |
+
| **HCC-ST** (Pearson, clean) | **0.324** | 0.300 | 0.274 |
|
| 109 |
+
| HEST-1K (Pearson) | 0.383 | 0.390 | 0.375 |
|
| 110 |
+
| NCT-CRC-HE (9-class acc) | 0.964 | 0.967 | 0.937 |
|
| 111 |
+
| BACH (4-class acc) | 0.811 | 0.906 | 0.708 |
|
| 112 |
+
|
| 113 |
+
On the clean HCC-ST cohort the majority of OpenPath checkpoints exceed OpenMidnight, and OpenPath
|
| 114 |
+
beats Phikon-v2 across all benchmarks. The best checkpoint (`training_63250`, available in
|
| 115 |
+
`openpath-checkpoints`) is top on both HEST-1K and HCC-ST. Note: PCam / CAMELYON is excluded from
|
| 116 |
+
comparison because it overlaps our training corpus.
|
| 117 |
+
|
| 118 |
+
## License
|
| 119 |
|
| 120 |
+
Code: derived from the OpenMidnight / DINOv2 fork โ see `OpenMidnight/LICENSE`.
|
| 121 |
+
Training data: public pathology datasets under CC-BY / CC0 / NIH-open terms (redistributable).
|
scripts/autoresume.sh
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env bash
|
| 2 |
+
# run(om_vitg14_run) ํฌ๋์ ๋ด์ฑ ์๋ ์ฌ๊ฐ waiter. TJ-1(์ค์ผ์คํธ๋ ์ดํฐ)์ ๋ฐฑ๊ทธ๋ผ์ด๋ ์คํ.
|
| 3 |
+
# - ์์ฃผ(training_230000) ๊ฐ์ง โ exit 0
|
| 4 |
+
# - NaN ๊ฐ์ง โ exit 2 (์ฌ๊ฐ ์ ํจ)
|
| 5 |
+
# - ํฌ๋์(์ ๋ฉธ, ์์ฃผ/NaN ์๋) โ ์ ๋
ธ๋ shm์ ๋ฆฌ ํ launch.sh๋ก resume(๊ฐ์ OUT=๋ง์ง๋ง ์ฒดํฌํฌ์ธํธ), ์ต๋ MAXํ
|
| 6 |
+
# โ
host=TJ-2(alive/NaN ์ฒดํฌ๋ TJ-2). TJ-1์ ํ์ต ์ ์ธ๋ผ ๋์ ์๋.
|
| 7 |
+
set -u
|
| 8 |
+
P=/NHNHOME/WORKSPACE/0526040027_A/OpenPath
|
| 9 |
+
CFG=$P/OpenMidnight/dinov2/configs/train/openpath_vitg14.yaml
|
| 10 |
+
OUT=$P/data/runs/om_vitg14_run
|
| 11 |
+
LOG=$P/data/runs/om_logs/vitg_run
|
| 12 |
+
DONE=$OUT/eval/training_345000/teacher_checkpoint.pth
|
| 13 |
+
TJLOG=$LOG/TJ-2.log
|
| 14 |
+
NODES="TJ-2 TJ-3 TJ-4 TJ-5 TJ-6"
|
| 15 |
+
MAX=40
|
| 16 |
+
retry=0
|
| 17 |
+
|
| 18 |
+
alive_count() {
|
| 19 |
+
timeout 12 ssh -o BatchMode=yes -o ConnectTimeout=8 TJ-2 "ps -eo args 2>/dev/null | grep '[t]rain.py' | wc -l" 2>/dev/null || echo 1
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
echo "[autoresume-run] watching $OUT (host TJ-2, max $MAX auto-resumes)"
|
| 23 |
+
while true; do
|
| 24 |
+
[ -f "$DONE" ] && { echo "RUN2_DONE: ์์ฃผ (training_230000)"; exit 0; }
|
| 25 |
+
if grep -qiE "NaN detected" "$TJLOG" 2>/dev/null; then echo "RUN2_NAN: NaN ๊ฐ์ง โ ์๋์ฌ๊ฐ ์ค๋จ"; exit 2; fi
|
| 26 |
+
|
| 27 |
+
a=$(alive_count)
|
| 28 |
+
if [ "${a:-1}" = "0" ]; then
|
| 29 |
+
sleep 60
|
| 30 |
+
a2=$(alive_count)
|
| 31 |
+
if [ "${a2:-1}" = "0" ] && [ ! -f "$DONE" ]; then
|
| 32 |
+
grep -qiE "NaN detected" "$TJLOG" 2>/dev/null && { echo "RUN2_NAN"; exit 2; }
|
| 33 |
+
retry=$((retry+1))
|
| 34 |
+
if [ "$retry" -gt "$MAX" ]; then echo "RUN2_GIVEUP: ์๋์ฌ๊ฐ $MAXํ ์ด๊ณผ โ ์๋ ๊ฐ์
"; exit 3; fi
|
| 35 |
+
lastit=$(grep -E "helpers.py:110] Training" "$TJLOG" 2>/dev/null | tail -1 | grep -oE "\[ *[0-9]+/" | head -1)
|
| 36 |
+
echo "[autoresume-run] CRASH detected at $lastit โ auto-resume #$retry/$MAX"
|
| 37 |
+
for n in $NODES; do timeout 10 ssh -o BatchMode=yes "$n" "pkill -9 -f 'dinov2/train/train.py' 2>/dev/null; pkill -9 -f torchrun 2>/dev/null; rm -f /dev/shm/nccl* 2>/dev/null" 2>/dev/null; done
|
| 38 |
+
sleep 30
|
| 39 |
+
bash "$P/scripts/launch.sh" "openpathrunr${retry}" "$CFG" "$OUT" "$LOG" >/dev/null 2>&1
|
| 40 |
+
echo "[autoresume-run] relaunched (rdzv openpathrunr${retry}) โ resume from last checkpoint"
|
| 41 |
+
sleep 180
|
| 42 |
+
fi
|
| 43 |
+
fi
|
| 44 |
+
sleep 240
|
| 45 |
+
done
|
scripts/launch.sh
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env bash
|
| 2 |
+
# run ํ์ต ๋ฐ์ฒ: TJ-2~6(5๋
ธ๋ร8=40 GPU) FSDP. host=TJ-2, ์์ปค=TJ-3~6. โ
TJ-1์ ํ์ต ์ ์ธ(eval watcher ์ ์ฉ).
|
| 3 |
+
# TJ-1(์ค์ผ์คํธ๋ ์ดํฐ)์์ ์คํ โ ๋ก์ปฌ ํ์ต ํ๋ก์ธ์ค ์์. host๋ ์๊ฒฉ(ssh TJ-2)์ด๋ผ ์๊ธฐ์ฐธ์กฐ ํจ์ ์์.
|
| 4 |
+
# ์ฌ์ฉ: scripts/launch.sh <rdzv_id> <config_abspath> <outdir> <logdir> [extra train.py args...]
|
| 5 |
+
set -u
|
| 6 |
+
R=/NHNHOME/WORKSPACE/0526040027_A/OpenPath
|
| 7 |
+
RDZV="$1"; CFG="$2"; OUTDIR="$3"; LOGDIR="$4"; shift 4
|
| 8 |
+
EXTRA="$*"
|
| 9 |
+
HOST="TJ-2"
|
| 10 |
+
EP="10.34.15.21:29500" # TJ-2 IB IP (rendezvous rank0)
|
| 11 |
+
WORKERS="TJ-3 TJ-4 TJ-5 TJ-6"
|
| 12 |
+
PYC="\$HOME/.cache/op_pyc_$RDZV" # ๋
ธ๋-๋ก์ปฌ. ์๊ฒฉ ์
ธ์์ ํ์ฅ๋๋๋ก escape
|
| 13 |
+
ENV="WANDB_MODE=disabled NCCL_DEBUG=WARN NCCL_IB_HCA=mlx5_1,mlx5_2,mlx5_4,mlx5_9 \
|
| 14 |
+
NCCL_SOCKET_IFNAME=bond0 GLOO_SOCKET_IFNAME=bond0 \
|
| 15 |
+
NCCL_IB_TIMEOUT=22 NCCL_IB_RETRY_CNT=13 NCCL_IB_QPS_PER_CONNECTION=4 \
|
| 16 |
+
PYTHONDONTWRITEBYTECODE=1 PYTHONPYCACHEPREFIX=$PYC PYTHONPATH=$R/OpenMidnight"
|
| 17 |
+
TR="venv/bin/torchrun --nnodes=5 --nproc-per-node=8 --rdzv-backend=c10d \
|
| 18 |
+
--rdzv-endpoint=$EP --rdzv-id=$RDZV \
|
| 19 |
+
OpenMidnight/dinov2/train/train.py --config-file $CFG --output-dir $OUTDIR $EXTRA"
|
| 20 |
+
|
| 21 |
+
mkdir -p "$LOGDIR" "$OUTDIR"
|
| 22 |
+
|
| 23 |
+
# 1) host(TJ-2) ์๊ฒฉ ๊ธฐ๋ โ โ
ssh๋ฅผ &๋ก ๋ฐฑ๊ทธ๋ผ์ด๋(์ ๊ทธ๋ฌ๋ฉด ์๊ฒฉ setsid์ ์์ fd๋ฅผ ๋ฌผ๊ณ ssh๊ฐ ๋ฐํ ์ ํจ=๋ฐ์ฒ ํ)
|
| 24 |
+
echo "launching host on $HOST ..."
|
| 25 |
+
ssh -n -o BatchMode=yes "$HOST" "mkdir -p $PYC; cd $R && setsid env $ENV $TR > $LOGDIR/${HOST}.log 2>&1 < /dev/null & echo ${HOST}-host-fired" &
|
| 26 |
+
|
| 27 |
+
# 2) host torchrun๊ฐ store ๋ฐ์ธ๋ฉํ ์๊ฐ(๊ณ ์ ๋๊ธฐ). c10d๋ ์์ปค๊ฐ ์ฌ์๋๋ก ๋ถ์ผ๋ฏ๋ก ssํด๋ง ๋ถํ์.
|
| 28 |
+
echo "waiting 30s for host store bind on $EP ..."
|
| 29 |
+
sleep 30
|
| 30 |
+
echo "firing 4 workers"
|
| 31 |
+
|
| 32 |
+
# 3) ์์ปค(TJ-3~6) ๋ณ๋ ฌ ๊ธฐ๋
|
| 33 |
+
for n in $WORKERS; do
|
| 34 |
+
ssh -n -o BatchMode=yes "$n" "mkdir -p $PYC; cd $R && setsid env $ENV $TR > $LOGDIR/${n}.log 2>&1 < /dev/null & echo ${n}-fired" &
|
| 35 |
+
done
|
| 36 |
+
# โ
wait ๋์ ๊ณ ์ sleep โ bg ssh๊ฐ ์๊ฒฉ setsid์ fd๋ฅผ ๋ฌผ์ด ๋ฐํ ์ ํ ์ ์์ด wait๋ ์์ํ ๋ฉ์ถค(autoresume blocking ํธ์ถ๋ ๋งํ).
|
| 37 |
+
sleep 20
|
| 38 |
+
echo "ALL launched: host $HOST + workers $WORKERS | rdzv=$RDZV | logs=$LOGDIR | out=$OUTDIR"
|
scripts/run_hest_3way.py
CHANGED
|
@@ -4,7 +4,7 @@
|
|
| 4 |
benchmark()๋ resnet50์ ์๋ ๊ธฐ์ค์ผ๋ก ํฌํจํ๋ฏ๋ก ์ถ๋ ฅ์ resnet50๋ ํจ๊ป ๋์จ๋ค.
|
| 5 |
|
| 6 |
์คํ(venv_hest):
|
| 7 |
-
PYTHONPATH=
|
| 8 |
--backbone om --weights data/runs/om_vitl14/eval/training_0/teacher_checkpoint.pth \
|
| 9 |
--exp-code meta_dinov2_vitl14 [task1 ...]
|
| 10 |
PYTHONPATH=. venv_hest/bin/python scripts/run_hest_3way.py --backbone phikon --exp-code phikon_v2
|
|
@@ -29,7 +29,7 @@ eval_tf = transforms.Compose([
|
|
| 29 |
|
| 30 |
def build_om(weights):
|
| 31 |
"""OpenMidnight teacher_checkpoint(ViT-L/14 reg4) โ CLS nn.Module."""
|
| 32 |
-
_OM = f"{ROOT}/
|
| 33 |
sys.path = [_OM] + [p for p in sys.path if "third_party/dinov2" not in p]
|
| 34 |
import dinov2.models.vision_transformer as vits
|
| 35 |
ck = torch.load(weights, map_location="cpu", weights_only=False)
|
|
|
|
| 4 |
benchmark()๋ resnet50์ ์๋ ๊ธฐ์ค์ผ๋ก ํฌํจํ๋ฏ๋ก ์ถ๋ ฅ์ resnet50๋ ํจ๊ป ๋์จ๋ค.
|
| 5 |
|
| 6 |
์คํ(venv_hest):
|
| 7 |
+
PYTHONPATH=OpenMidnight:. venv_hest/bin/python scripts/run_hest_3way.py \
|
| 8 |
--backbone om --weights data/runs/om_vitl14/eval/training_0/teacher_checkpoint.pth \
|
| 9 |
--exp-code meta_dinov2_vitl14 [task1 ...]
|
| 10 |
PYTHONPATH=. venv_hest/bin/python scripts/run_hest_3way.py --backbone phikon --exp-code phikon_v2
|
|
|
|
| 29 |
|
| 30 |
def build_om(weights):
|
| 31 |
"""OpenMidnight teacher_checkpoint(ViT-L/14 reg4) โ CLS nn.Module."""
|
| 32 |
+
_OM = f"{ROOT}/OpenMidnight"
|
| 33 |
sys.path = [_OM] + [p for p in sys.path if "third_party/dinov2" not in p]
|
| 34 |
import dinov2.models.vision_transformer as vits
|
| 35 |
ck = torch.load(weights, map_location="cpu", weights_only=False)
|
scripts/watch_eval.sh
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env bash
|
| 2 |
+
# TJ-1 ์ค์๊ฐ HEST eval watcher. run ํ์ต์ด ๋ฑ๋ teacher_checkpoint๋ฅผ ๊ฐ์งโprobeโ๊ณก์ append.
|
| 3 |
+
# TJ-1 ๋ก์ปฌ ์คํ(venv_hestยทGPU ๋ก์ปฌ). 1๊ฐ์ฉ ์์ฐจ(๋์ HDF5 ๋ฒ๊ทธ ํํผ, ~60min<์ฒดํฌํฌ์ธํธ๊ฐ๊ฒฉ ~84min๋ผ ํ์ด์ค ์ ์ง).
|
| 4 |
+
# per-exp embed ๋ถ๋ฆฌ(/dev/shm/hest_emb_<N>), pkill ๋ฏธํฌํจ(self-kill ํํผ).
|
| 5 |
+
set -u
|
| 6 |
+
R=/NHNHOME/WORKSPACE/0526040027_A/OpenPath
|
| 7 |
+
OUTDIR=$R/data/runs/om_vitg14_run
|
| 8 |
+
EVALDIR=$OUTDIR/eval
|
| 9 |
+
RESDIR=$R/data/runs/hest_3way
|
| 10 |
+
CURVE=$RESDIR/curve.txt
|
| 11 |
+
BENCH=/dev/shm/hest_bench
|
| 12 |
+
GPU=0
|
| 13 |
+
mkdir -p "$RESDIR"
|
| 14 |
+
|
| 15 |
+
# hest_bench๋ฅผ TJ-1 /dev/shm์ ํ๋ณด(์์ผ๋ฉด Lustre์ ๋ณต์ฌ, 40G)
|
| 16 |
+
if [ ! -d "$BENCH" ] || [ "$(ls "$BENCH" 2>/dev/null | wc -l)" -lt 5 ]; then
|
| 17 |
+
echo "[watch] copying hest_bench -> $BENCH (40G, ์๋ถ) ..."
|
| 18 |
+
rm -rf "$BENCH"; cp -r "$R/data/eva/hest_bench" "$BENCH"
|
| 19 |
+
fi
|
| 20 |
+
echo "[watch] START โ watching $EVALDIR (TJ-1 GPU$GPU, 1-at-a-time) | curve=$CURVE"
|
| 21 |
+
|
| 22 |
+
cd "$R"
|
| 23 |
+
while true; do
|
| 24 |
+
for ck in $(ls -d "$EVALDIR"/training_* 2>/dev/null | sort -t_ -k2 -n); do
|
| 25 |
+
N=$(basename "$ck" | sed 's/training_//')
|
| 26 |
+
W="$ck/teacher_checkpoint.pth"
|
| 27 |
+
LOG="$RESDIR/run_$N.log"
|
| 28 |
+
[ -f "$W" ] || continue
|
| 29 |
+
grep -q "per-encoder avg Pearson" "$LOG" 2>/dev/null && continue # ์ด๋ฏธ ์๋ฃ
|
| 30 |
+
EMB="/dev/shm/hest_emb_$N"
|
| 31 |
+
rm -rf "$EMB"
|
| 32 |
+
echo "[watch] $(date '+%F %T') probing training_$N ..."
|
| 33 |
+
HEST_EMBED_ROOT="$EMB" HEST_BENCH_ROOT="$BENCH" HDF5_USE_FILE_LOCKING=FALSE \
|
| 34 |
+
CUDA_VISIBLE_DEVICES=$GPU PYTHONPATH=OpenMidnight:. \
|
| 35 |
+
venv_hest/bin/python -u scripts/run_hest_3way.py --backbone om --weights "$W" --exp-code "run_$N" > "$LOG" 2>&1
|
| 36 |
+
rm -rf "$EMB"
|
| 37 |
+
ce=$(grep "per-encoder avg Pearson" "$LOG" 2>/dev/null | tail -1 | grep -oE "'custom_encoder': [0-9.]+" | grep -oE "[0-9.]+")
|
| 38 |
+
rn=$(grep "per-encoder avg Pearson" "$LOG" 2>/dev/null | tail -1 | grep -oE "'resnet50': [0-9.]+" | grep -oE "[0-9.]+")
|
| 39 |
+
printf "%s\tours=%s\tresnet50=%s\t%s\n" "training_$N" "${ce:-FAIL}" "${rn:-NA}" "$(date '+%F %T')" >> "$CURVE"
|
| 40 |
+
echo "[watch] training_$N = ${ce:-FAIL}"
|
| 41 |
+
done
|
| 42 |
+
sleep 120
|
| 43 |
+
done
|