Persist test metrics, log CPU usage, and make run identity window-aware - #54
Merged
Merged
Conversation
Four small fixes found while running the Tranche 1 sweep. 1. Test evaluation was gated on wandb. `if wandb_logger.enabled and test_loader is not None` meant a run without --wandb never computed test metrics at all -- not merely unlogged, never calculated. Ungated. 2. Test metrics are now written to test_metrics.json. metrics_history.json carries validation only and log.txt has no test lines, so the numbers that go in a paper previously lived nowhere on disk: only in stdout and W&B, recoverable afterwards only by re-scoring predictions_*.csv by hand. 3. Per-epoch CPU accounting alongside the existing VRAM and epoch_time_s: train_cpu_seconds and train_cpu_util_pct. Counts dataloader workers, since self-only time badly understates a data-loading-bound run. psutil is already present via wandb, with a resource fallback. 4. exp_name and the W&B run name now include the observation window. An observation-window arm is a different experiment from the full-stay run at the same task/model/seed, but both resolved to the same name -- so they shared an output directory and collided in W&B. Runs also now set W&B group (arm) and job_type (backbone) so a many-cell sweep is navigable. Also: create_directory used `if not exists: makedirs`, which two processes importing pyhealth for the first time can both pass, leaving one to die on FileExistsError. Seen on a shared cluster home with two concurrent jobs.
will-pang
merged commit Sep 5, 2026
0b83af8
into
ml4h-merge-tranche-1-wp-20260830
0 of 2 checks passed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Four small fixes found while running the Tranche 1 sweep. None of them change what a model computes — no numerics move.
1. Test evaluation was gated on wandb
A run without
--wandbnever computed test metrics at all — not merely unlogged, never calculated. Now ungated; the logger only decides whether they get shipped.2. Test metrics are written to disk
metrics_history.jsonholds validation only andlog.txthas no test lines, so the numbers that go in a paper lived nowhere on disk — only in stdout and W&B. If a log scrolled away, the only route back was re-scoringpredictions_*.csvby hand, which is exactly what I ended up doing to build the results table.Now
test_metrics.jsonlands next to the predictions, witheval_splitrecorded alongside so it is unambiguous which split produced them.3. Per-epoch CPU accounting
The trainer already recorded
train_vram_allocated_mb,train_vram_peak_mb, andepoch_time_s. Addedtrain_cpu_secondsandtrain_cpu_util_pctnext to them.Counts dataloader workers, not just the parent: workers are separate processes, so self-only CPU time badly understates a run whose cost is data loading — which is the interesting case for this toolkit.
psutilis already present via wandb; there is aresourcefallback, which reads low while persistent workers are still alive because it only sees reaped children.Utilisation above 100% is expected and means several cores are busy.
4. Run identity now includes the observation window
exp_namewas{task}_{model}_seed{seed}. An observation-window arm is a different experiment from the full-stay run at the same task/model/seed, but both resolved to the same name — so they shared an output directory and collided in W&B under one run name. Two runs in our project were genuinely indistinguishable except by tag.Now suffixed
_w48when a window is set. Runs also set W&Bgroup(arm) andjob_type(backbone), so a many-cell sweep is navigable instead of one flat list — 37 runs withgroup=Noneis not a project you can read.Also:
create_directoryraceTwo processes importing pyhealth for the first time both pass the check and one dies with
FileExistsError. Hit this on a shared cluster home when two jobs started together and raced on~/.cache/pyhealth/medcode/. Nowexist_ok=True.Verification
Dev split, two cells on the same tree:
--wandb)--observation-window-hours 48)labs_mlp_seed1labs_mlp_seed1_w48test_metrics.jsontrain_cpu_seconds/train_cpu_util_pctCell A is the one that matters: before this change it would have produced no test metrics at all.