Upload README.md with huggingface_hub
Browse files
README.md
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: mit
|
| 3 |
+
pipeline_tag: image-segmentation
|
| 4 |
+
tags:
|
| 5 |
+
- vesuvius
|
| 6 |
+
- herculaneum
|
| 7 |
+
- fibers
|
| 8 |
+
- ink-detection
|
| 9 |
+
- computed-tomography
|
| 10 |
+
- 3d-segmentation
|
| 11 |
+
- self-distillation
|
| 12 |
+
- self-supervised
|
| 13 |
+
- volumetric-imaging
|
| 14 |
+
---
|
| 15 |
+
|
| 16 |
+
# PHerc. Paris 4 β 4-class fiber/ink segmentation, self-distilled (step 29000)
|
| 17 |
+
|
| 18 |
+
Segments **background / vertical fiber / horizontal-angular fiber / ink** β 4
|
| 19 |
+
classes, in 3D, directly in micro-CT of **PHerc. Paris 4** β trained with **no
|
| 20 |
+
fixed ground truth** via self-distillation from two frozen teacher UNets. This
|
| 21 |
+
is villa's [`scripts/fiber_5class`](https://github.com/ScrollPrize/villa/tree/main/scripts/fiber_5class)
|
| 22 |
+
pipeline (PR [#985](https://github.com/ScrollPrize/villa/pull/985)), and this
|
| 23 |
+
checkpoint is confirmed (via direct inspection of its embedded training config,
|
| 24 |
+
which matches its W&B run exactly) to be the real, finished model that
|
| 25 |
+
pipeline produced.
|
| 26 |
+
|
| 27 |
+
**This model's own training pipeline does not use DINO at all** β it is pure
|
| 28 |
+
two-teacher self-distillation (see below). DINO only appears earlier/elsewhere
|
| 29 |
+
in this broader fiber-modeling effort, in a separate checkpoint that may feed
|
| 30 |
+
this run's fiber teacher input β see **Related models**.
|
| 31 |
+
|
| 32 |
+

|
| 33 |
+
|
| 34 |
+
*Training-time debug visualization from this run at step 29899 (image slice,
|
| 35 |
+
teacher probability maps, watershed instances, student prediction). Logged to
|
| 36 |
+
W&B, not an independent evaluation.*
|
| 37 |
+
|
| 38 |
+
## Model details
|
| 39 |
+
|
| 40 |
+
| | |
|
| 41 |
+
|---|---|
|
| 42 |
+
| Architecture | `vesuvius` `NetworkFromConfig` 3D UNet (`shared_encoder`/`shared_decoder`/`task_heads`) β verified directly from the checkpoint: 544 encoder tensors, 60 decoder tensors, single head |
|
| 43 |
+
| Output | **4 channels**, softmax, head named `task_heads.labels` β verified shape `(4, 32, 1, 1, 1)` |
|
| 44 |
+
| Classes | `0` background Β· `1` vertical fiber Β· `2` horizontal/angular fiber Β· `3` ink |
|
| 45 |
+
| Input | 1-channel CT, 256Β³ patches |
|
| 46 |
+
| This checkpoint | step **29000** of a 30000-step schedule Β· W&B run [`p4_4class_ddp8_20260526`](https://wandb.ai/vesuvius-challenge/paris4-full-features/runs/36pykwky) (`36pykwky`, project `paris4-full-features`, state **finished**) |
|
| 47 |
+
| Weights | `model` (raw) and `ema` (**EMA β recommended for inference**, decay 0.9995) |
|
| 48 |
+
| Optimisation | SGD + Nesterov (lr 0.005, momentum 0.99, weight_decay 3e-5), cosine LR, 2000-step warmup, bf16, CE + multiclass soft Dice (0.1 label smoothing each, Dice over foreground classes only), batch size 2 Γ 8 GPUs (`ddp8`) |
|
| 49 |
+
| Trained on | PHerc. Paris 4, 2.4 Β΅m scan (`s3://vesuvius-challenge-open-data/PHercParis4/volumes/20260411134726-2.400um-0.2m-78keV-masked.zarr/`) |
|
| 50 |
+
|
| 51 |
+
We verified this checkpoint directly (`torch.load(..., weights_only=False)`):
|
| 52 |
+
its embedded `config.wandb_run_name` is `p4_4class_ddp8_20260526`, its
|
| 53 |
+
`config.out_dir` is `/ephemeral/fiber_5class_ckpts/p4_4class_ddp8_20260526` β
|
| 54 |
+
both matching the W&B run's own recorded config exactly, and `step=29000`
|
| 55 |
+
matches the file's provenance exactly. `save_every=1000` with
|
| 56 |
+
`num_iterations=30000` means step 29000 is mathematically the **last**
|
| 57 |
+
checkpoint this run could have saved (the loop exits at step 30000 before
|
| 58 |
+
another save triggers) β this is the final checkpoint of a finished run, not
|
| 59 |
+
an arbitrary snapshot.
|
| 60 |
+
|
| 61 |
+
This run was reached after two earlier attempts under the same name failed
|
| 62 |
+
(`5ga68dxv`) or crashed (`q8jmzbiv`), and after an even earlier, broader
|
| 63 |
+
experiment line tagged `5class`/`fiber-ink-papyrus` (`out_channels=5`, adding a
|
| 64 |
+
"papyrus" class) was simplified down to the 4-class scheme published here.
|
| 65 |
+
|
| 66 |
+
## Training procedure: two-teacher self-distillation (verified against source)
|
| 67 |
+
|
| 68 |
+
Read directly from `label_generator.py` (`FiveClassLabelGenerator`) and
|
| 69 |
+
`train.py` in PR #985 β this is a from-source description, not an inference
|
| 70 |
+
from config field names:
|
| 71 |
+
|
| 72 |
+
1. `fiber_prob = sigmoid(fiber_teacher(image))`, `ink_prob = sigmoid(ink_teacher(image))` β two independent frozen teacher UNets, FG channel only.
|
| 73 |
+
2. `fiber_mask = fiber_prob > fiber_thr` (0.5).
|
| 74 |
+
3. GPU watershed-from-minima (`cuws`) on the distance transform of `fiber_mask` (`ws_image_mode="distance"`, `ws_h_merge=14000`) β per-instance fiber segmentation.
|
| 75 |
+
4. **Per-instance PCA** on each instance's ZYX voxel coordinates: `|principal_axis Β· αΊ| > pca_cos_threshold` (0.819 = cos 35Β°) β class **1** (vertical), else class **2** (horizontal/angular). Instances below `ws_min_voxels` (400) default to class 2 rather than being dropped.
|
| 76 |
+
5. **Ink overrides fiber:** `label[ink_prob > ink_thr] = 3` (`ink_thr=0.1`) β applied after the fiber/orientation assignment, so ink always wins where the ink teacher is confident.
|
| 77 |
+
6. **Dark-voxel guard (final step):** `label[raw < dark_voxel_thr] = 0` (`dark_voxel_thr=90`) β forces very dark/air voxels to background regardless of any earlier assignment.
|
| 78 |
+
|
| 79 |
+
Loss = cross-entropy (label smoothing 0.1) + multiclass soft Dice (smoothing
|
| 80 |
+
0.1, foreground classes only). A fresh pseudo-label is generated from the two
|
| 81 |
+
frozen teachers **every step** β there is no fixed/static label set at any
|
| 82 |
+
point in training.
|
| 83 |
+
|
| 84 |
+
The two teacher checkpoints for this run were configured as
|
| 85 |
+
`/ephemeral/fiber_5class_inputs/fiber_teacher.pth` and `ink_teacher.pth` β
|
| 86 |
+
generic on-disk names that don't self-identify their origin. Per the identical
|
| 87 |
+
`scripts/fiber_5class/train.py` module docstring, the fiber teacher is
|
| 88 |
+
documented as "ihoo3tpl ckpt", i.e. very likely
|
| 89 |
+
[`scrollprize/fiber_dinoguided_2class_step010000`](https://huggingface.co/scrollprize/fiber_dinoguided_2class_step010000)
|
| 90 |
+
(not proven byte-identical β it was copied/renamed on the training box). The
|
| 91 |
+
ink teacher is a separate checkpoint we never had; it no longer exists on the
|
| 92 |
+
original training instance and was not found anywhere else we checked, so we
|
| 93 |
+
are treating it **as unrecoverable** and are not able to publish it.
|
| 94 |
+
|
| 95 |
+
## Metrics
|
| 96 |
+
|
| 97 |
+
Final logged values at step 29999 (run marked **finished**; checkpoint
|
| 98 |
+
published here is step 29000, the last one actually saved):
|
| 99 |
+
|
| 100 |
+
| metric | value |
|
| 101 |
+
|---|---|
|
| 102 |
+
| `loss` (ce + dice) | 1.0055 |
|
| 103 |
+
| `loss_ce` | 0.4513 |
|
| 104 |
+
| `loss_dice` | 0.5542 |
|
| 105 |
+
| `metrics/dice_0_bg` | 0.961 |
|
| 106 |
+
| `metrics/dice_1_vert_fiber` | 0.673 |
|
| 107 |
+
| `metrics/dice_2_horiz_fiber` | 0.705 |
|
| 108 |
+
| `metrics/dice_3_ink` | 0.791 |
|
| 109 |
+
| `metrics/dice_fg_mean` | 0.723 |
|
| 110 |
+
| `pseudo/frac_bg` / `frac_vert` / `frac_horiz` / `frac_ink` | 0.845 / 0.026 / 0.080 / 0.049 |
|
| 111 |
+
| `pseudo/n_instances_mean` | 27.5 |
|
| 112 |
+
| `pseudo/n_vert_mean` | 9 |
|
| 113 |
+
|
| 114 |
+
**Important:** the per-class Dice above is **student-vs-its-own-pseudo-label
|
| 115 |
+
self-consistency**, recomputed each `val_every` steps by re-forwarding the
|
| 116 |
+
student on a clean (non-augmented) training crop and comparing to that crop's
|
| 117 |
+
pseudo-label β confirmed directly from `train.py`'s logging code. It is **not**
|
| 118 |
+
accuracy against independent, human-verified ground truth (none exists for
|
| 119 |
+
this pipeline). Treat these numbers as a training-health signal, not a
|
| 120 |
+
benchmark score.
|
| 121 |
+
|
| 122 |
+

|
| 123 |
+
|
| 124 |
+
*Categorical mask visualization (pseudo-label vs. student prediction) from the
|
| 125 |
+
same step, with the fixed class palette used throughout this pipeline.*
|
| 126 |
+
|
| 127 |
+
## Relationship to other fiber-effort models β please read before conflating pipelines
|
| 128 |
+
|
| 129 |
+
This is the only one of the four related repos published so far whose own
|
| 130 |
+
training loop is DINO-free. The others are separate, earlier, or upstream
|
| 131 |
+
components of the same broader effort:
|
| 132 |
+
|
| 133 |
+
- **[`scrollprize/fiber_dinoguided_2class_step010000`](https://huggingface.co/scrollprize/fiber_dinoguided_2class_step010000)** β 2-class (background/fiber) DINO-embedding-guided self-training checkpoint, very likely (not proven byte-identical) the `fiber_teacher` input consumed by this run. Trains completely differently (Otsu + DINO-similarity dynamic pseudo-labels, no watershed, no PCA, no ink).
|
| 134 |
+
- **[`scrollprize/dinovol_v2_ps8_supcon3class_step362500`](https://huggingface.co/scrollprize/dinovol_v2_ps8_supcon3class_step362500)** and **[`scrollprize/fiber_selftrain_teacher_epoch30`](https://huggingface.co/scrollprize/fiber_selftrain_teacher_epoch30)** β further upstream still (inputs to producing this run's likely fiber-teacher checkpoint, not direct inputs to this run itself).
|
| 135 |
+
- **[`scrollprize/fiber_hz_vt`](https://huggingface.co/scrollprize/fiber_hz_vt)** β an independent, supervised, real-annotation-trained 2-class horizontal/vertical model (villa PR [#825](https://github.com/ScrollPrize/villa/pull/825)). Different pipeline, different training data (WebKnossos skeleton traces vs. self-distillation), not directly comparable.
|
| 136 |
+
|
| 137 |
+
## Files
|
| 138 |
+
|
| 139 |
+
| File | Size | Role |
|
| 140 |
+
|---|---|---|
|
| 141 |
+
| `p4_4class_ddp8_20260526_step029000.pth` | ~2.1 GB | `model` (raw) + `ema.model_state` (recommended for inference) + `optimizer` + embedded `config`. |
|
| 142 |
+
| `images/p4_4class_36pykwky_debug_figure_step29899.png` | β | Training-time debug figure (illustrative only), from this run's W&B logs. |
|
| 143 |
+
| `images/p4_4class_36pykwky_debug_mask_step29899.png` | β | Training-time categorical mask visualization (illustrative only), from this run's W&B logs. |
|
| 144 |
+
|
| 145 |
+
## Usage
|
| 146 |
+
|
| 147 |
+
```python
|
| 148 |
+
import torch
|
| 149 |
+
from huggingface_hub import hf_hub_download
|
| 150 |
+
|
| 151 |
+
path = hf_hub_download(
|
| 152 |
+
"scrollprize/fiber_ink_4class_selfdistill",
|
| 153 |
+
"p4_4class_ddp8_20260526_step029000.pth",
|
| 154 |
+
)
|
| 155 |
+
ckpt = torch.load(path, map_location="cpu", weights_only=False)
|
| 156 |
+
state = ckpt["ema"]["model_state"] # recommended over ckpt["model"]
|
| 157 |
+
# Build with vesuvius' NetworkFromConfig (target "labels", out_channels=4,
|
| 158 |
+
# in_channels=1, patch_size 256^3) then load_state_dict(state).
|
| 159 |
+
```
|
| 160 |
+
The `vesuvius` package and the full training pipeline are in
|
| 161 |
+
<https://github.com/ScrollPrize/villa> (`scripts/fiber_5class/`).
|
| 162 |
+
|
| 163 |
+
## Links
|
| 164 |
+
|
| 165 |
+
- **Code:** <https://github.com/ScrollPrize/villa> β PR [#985](https://github.com/ScrollPrize/villa/pull/985) (`scripts/fiber_5class`, this model's exact training code) Β· PR [#825](https://github.com/ScrollPrize/villa/pull/825) (related cross-frame affine infra, separate pipeline)
|
| 166 |
+
- **W&B run:** <https://wandb.ai/vesuvius-challenge/paris4-full-features/runs/36pykwky>
|
| 167 |
+
- **Data:** <https://scrollprize.org/data_browser>
|
| 168 |
+
- **Vesuvius Challenge:** <https://scrollprize.org>
|
| 169 |
+
|
| 170 |
+
## Caveats
|
| 171 |
+
|
| 172 |
+
- Metrics are self-consistency (student vs. its own pseudo-label), not
|
| 173 |
+
held-out validation against independent ground truth β there is none in
|
| 174 |
+
this pipeline.
|
| 175 |
+
- The ink teacher checkpoint used to train this model is not published here
|
| 176 |
+
and is believed unrecoverable (no longer present on the original training
|
| 177 |
+
instance; not found elsewhere in our search).
|
| 178 |
+
- The fiber teacher checkpoint used to train this model is very likely
|
| 179 |
+
[`scrollprize/fiber_dinoguided_2class_step010000`](https://huggingface.co/scrollprize/fiber_dinoguided_2class_step010000)
|
| 180 |
+
based on matching documentation in the training source, but this was not
|
| 181 |
+
proven byte-identical (it was renamed to a generic filename on the training
|
| 182 |
+
box before this run consumed it).
|
| 183 |
+
- Trained on a single scroll (PHerc. Paris 4); generalization to other scrolls
|
| 184 |
+
is untested by us.
|
| 185 |
+
|
| 186 |
+
## License
|
| 187 |
+
|
| 188 |
+
MIT.
|