spacr.qt.screens.train_compare¶
Training Runs — several runs’ curves on one axis, with the settings diffed.
The question this screen exists to answer is “why is run B better than run A”, which today is answered by opening two folders of PDFs in one window, two settings CSVs in another, and holding the difference in your head.
Layout:
┌──────────────────────────────────────────────────────────────────────┐
│ /data/screen1/model [Choose folder…] [Scan] │
├──────────────────────┬───────────────────────────────────────────────┤
│ Runs found (4) │ ┌───────────────────────────┐ │
│ ☑ maxvit_t/…/ep_25 │ │ accuracy, 5 series │ │
│ 25 epochs · tr+val │ │ ╱‾‾‾‾ B val │ │
│ ☑ maxvit_t/…/ep_10 │ │ ╱ ─ ─ A val │ │
│ ☐ resnet50/…/ep_8 │ └───────────────────────────┘ │
│ 8 ep x 3 folds ├───────────────────────────────────────────────┤
│ ☐ maxvit_t/…/ep_3 ! │ 2 settings changed · 1 env drift · 0 drift │
│ │ bucket setting A B │
│ Metric [accuracy ▾] │ changed learning_rate 1e-4 1e-3 │
│ Folds [per fold ▾] │ changed batch_size 64 32 │
│ [Overlay selected] │ env n_jobs 30 8 │
├──────────────────────┴───────────────────────────────────────────────┤
│ ! maxvit_t/…/epochs_3: no per-epoch curves in this folder │
│ Clicked: maxvit_t/…/epochs_25 · val — best 0.87 @ 18, last 0.85 @ 25 │
└──────────────────────────────────────────────────────────────────────┘
Design notes:
Discovery runs off the GUI thread. A scan walks a model tree and parses every progress CSV under it, which on a real screen is hundreds of files. It goes through
spacr.qt.bridge.make_thread()like every other spaCR job; tests passthreaded=False, which runs the same code inline. Drawing stays on the GUI thread — by then the data is already in memory.No modal dialogs on any error path. A folder with no runs, a run with no curves, a metric nothing logged — all of it lands in the inline status and problem labels. A QMessageBox hangs a headless run.
Broken runs are listed, not hidden. A folder holding checkpoints but no
train.csvstill appears, marked, with its note in the problem line. A scan that silently drops the folder you were looking for is worse than one that says what is wrong with it.The diff is bucketed, never flat. It renders
spacr.train_compare.diff_settings(), which reuses the provenance bucketing fromspacr.run_journal: environment drift (paths, hosts, worker counts) is shown in its own bucket instead of being counted as something the user changed, and schema drift is summarised. When two runs match, the table says “no differences” in words rather than going blank.Every series says run · split · fold. Clicking a line names its run, folder and both its best and last epoch, because a legend that only carries the run id invites reading a train curve as a held-out result.
Attributes¶
Classes¶
Compare training runs: overlaid curves plus the bucketed settings diff. |
Module Contents¶
- class spacr.qt.screens.train_compare.TrainCompareScreen(parent=None, threaded: bool = True)[source]¶
Bases:
PySide6.QtWidgets.QWidgetCompare training runs: overlaid curves plus the bucketed settings diff.
- Parameters:
threaded – discover and load runs on a worker thread (the default). Tests pass
Falsefor deterministic, synchronous behaviour.- Variables:
last_error – text of the most recent failure,
""when the last operation succeeded. Errors are only ever reported here and in the inline status label — never in a modal dialog.
- comparison() spacr.train_compare.Comparison | None[source]¶
- identify_series(label: str) str[source]¶
Name the run behind a series label and report it inline.
- Returns:
the description shown, or
''when the label is unknown.
- overlay() bool[source]¶
Compare the ticked runs: draw their curves and fill the diff table.
Everything the drawing needs is already in memory after
scan(), so this runs on the GUI thread.- Returns:
True when a comparison was produced.
- runs() List[spacr.train_compare.TrainingRun][source]¶
- scan(root: Any) bool[source]¶
Discover training runs under
rootand list them.Runs off the GUI thread unless the screen was built with
threaded=False. Every failure is reported inline.- Parameters:
root – folder to walk.
- Returns:
True when the scan started (or, unthreaded, succeeded).
- select_runs(run_ids: Sequence[str]) bool[source]¶
Tick exactly these run ids. Unknown ids are reported inline.
- selected_metric() str[source]¶
Return the metric selected for the comparison plot.
This deliberately must not be named
metric.QWidgetinheritsQPaintDevice.metric(PaintDeviceMetric), which Qt calls while laying out and painting the widget. A no-argument Python override here used to raise duringshow()and could take the whole GUI down.