You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add coreg/atlas layout-2 support and rare-pathology rebalanced sampling
Dataloader now picks the image subfolder from --space when scanning the raw
HuggingFace download layout: native_space -> img/, coreg_space -> coreg_img/,
atlas_space -> atlas_img/. Layout 1 (<uid>/<space>/img/) is unchanged.
Adds optional inverse-prevalence weighted sampling for contrastive
pretraining: pass --pathology_labels_csv together with --rebalance_strategy
(inverse_freq | sqrt_inverse_freq | max_inverse_freq) to switch the
DataLoader to a WeightedRandomSampler that upsamples subjects with rare
positive pathologies. Unlabeled / all-negative subjects keep
--rebalance_base_weight (default 1.0). 8 new unit tests cover the weight
formulas and sampler integration; 5 new tests cover the coreg/atlas layout
discovery.
│ │ └── coreg_img/ # img/ for native, atlas_img/ for atlas
154
163
│ │ ├── SUBJECT_001_t1w-raw-axi.nii.gz
155
164
│ │ ├── SUBJECT_001_flair-raw-axi.nii.gz
156
165
│ │ └── ...
157
166
│ ├── SUBJECT_002/
158
-
│ │ └── img/
167
+
│ │ └── coreg_img/
159
168
│ │ └── ...
160
169
├── batch01/
161
170
│ └── ...
162
171
```
163
172
173
+
After `merge_downloaded_repos.py` consolidates native + coreg + atlas under a single tree, all three subfolders (`img/`, `coreg_img/`, `atlas_img/`) live side-by-side under each study, and `--space` selects which one to load.
174
+
164
175
Reports are stored in a JSONL file with one entry per subject:
-**W&B integration**: `--wandb` logs loss, learning rate, volume count per step; run ID is persisted for seamless resume across SLURM jobs
250
264
-**Gradient checkpointing**: Nested checkpointing at both volume level (in MRRATE) and chunk level (in sliding encoders) for maximum memory efficiency
251
265
-**Dual checkpoints**: Saves both model-only `.pt` (for inference) and full `.pt` (model + optimizer + scheduler + step, for resume)
266
+
-**Rare-pathology rebalancing** (see below): inverse-prevalence weighted sampling so contrastive batches see uncommon pathologies more often
267
+
268
+
### Rare-Pathology Rebalancing
269
+
270
+
Pathology prevalence in MR-RATE is heavily skewed (~43% of studies are all-negative; the rarest pathology, *Hemangioma of vertebral column*, occurs in ~0.23% of studies; *Gliosis* in ~37%). Under uniform sampling, contrastive batches are dominated by common findings and the model rarely sees rare ones. Passing `--pathology_labels_csv` together with `--rebalance_strategy` switches the training DataLoader to a `WeightedRandomSampler` whose per-subject weights are derived from inverse prevalence.
271
+
272
+
#### How the weighting works
273
+
274
+
Each subject's report is **multi-label** — a single scan can have zero, one, or many positive pathologies. Every subject is reduced to a single sampling weight `w_i`. Bigger weight = drawn more often. The three strategies differ in how a subject's binary label vector is collapsed into that one number.
275
+
276
+
Concrete walk-through with two pathologies and three subjects (using real prevalences from `mrrate_labels.csv`: *Hemangioma of vertebral column* ≈ 0.23% → inv-freq ≈ 433; *Gliosis* ≈ 37% → inv-freq ≈ 2.7):
Subject A is drawn ~436× more often than C, and ~118× more often than B.
285
+
286
+
#### Strategy choice
287
+
288
+
For each pathology `p`, `prevalence[p]` is the positive rate across labeled subjects in the active split, and `inv_freq[p] = 1 / max(prevalence[p], eps)`. The three strategies are different ways to aggregate across a subject's positive labels:
|`sqrt_inverse_freq`|`base + Σ_p y_p · √inv_freq[p]`|`22.4`| Sum with diminishing returns. Rarest pathology mass: 0.23% → ~1.5%. Use when `inverse_freq` over-amplifies. |
294
+
|`max_inverse_freq`|`max(base, max_p y_p · inv_freq[p])`|`433`|**Max** — a subject's weight is set by its single rarest positive pathology. Doesn't matter if they have one rare finding or five — caps combinatorial blow-up. |
295
+
296
+
Recommendation: start with `inverse_freq`. Switch to `sqrt_inverse_freq` if training loss gets noisy from over-sampling the same handful of rare subjects.
297
+
298
+
Subjects missing from the labels CSV — and all-negative subjects — receive `--rebalance_base_weight` (default `1.0`), so they remain in the pool but do not dominate it.
Without those flags, nothing changes — uniform `shuffle=True` as before. With them, the dataset prints a one-line summary at startup so you can verify the math:
[Trainer] Using WeightedRandomSampler (strategy=inverse_freq)
318
+
```
319
+
320
+
Total compute is unchanged (still `--num_train_steps` steps × batch_size × num_processes draws). Rebalancing only **redistributes** that draw budget toward rare-pathology subjects via `WeightedRandomSampler(..., replacement=True)`.
0 commit comments