Skip to content

Make training-callback and LR-scheduler monitored metrics configurable via YAML - #85

Open
p-grontas wants to merge 14 commits into
gridfm:mainfrom
p-grontas:feat-metric-cli
Open

Make training-callback and LR-scheduler monitored metrics configurable via YAML#85
p-grontas wants to merge 14 commits into
gridfm:mainfrom
p-grontas:feat-metric-cli

Conversation

@p-grontas

@p-grontas p-grontas commented Jul 14, 2026

Copy link
Copy Markdown

Summary

Makes the validation metric monitored by the training callbacks and the LR scheduler
configurable through the YAML callbacks: section, instead of being hard-coded to
"Validation loss". Three independent keys are introduced:

  • early_stopping_monitor — metric watched by EarlyStopping.
  • checkpoint_monitor — metric watched by best-model saving and ModelCheckpoint.
  • lr_scheduler_monitor — metric watched by the ReduceLROnPlateau scheduler.

Each defaults to Validation loss when omitted. All are minimized (mode="min", lower is
better); the direction is fixed and not configurable. This lets a run be driven by, e.g., a
per-layer physics residual (Validation layer_11_residual) rather than the aggregate loss.

Changes

  • Callback wiring (cli.py): get_training_callbacks reads callbacks.early_stopping_monitor
    and callbacks.checkpoint_monitor, each defaulting to DEFAULT_MONITOR="Validation loss".
  • LR scheduler (tasks/base_task.py): ReduceLROnPlateau now reads
    callbacks.lr_scheduler_monitor (previously hard-coded to "Validation loss").
  • Fail-loud on bad metric names: every monitor key aborts the run rather than silently
    no-op'ing.
    • checkpoint_monitor — checked explicitly by SaveBestModelStateDict (training/callbacks.py):
      it skips the sanity-check pass, then raises KeyError listing the available metrics. This
      is the sole consumer of the key — ModelCheckpoint is configured monitor-free
      (save_last=True, save_top_k=0, only writes last.ckpt), so it no longer watches any metric.
    • early_stopping_monitorEarlyStopping(strict=True) (Lightning's default, now set
      explicitly in cli.py) raises when the metric is missing.
    • lr_scheduler_monitor — the ReduceLROnPlateau scheduler dict sets strict=True explicitly
      (base_task.py), so Lightning raises MisconfigurationException with the available metrics
      at the end of the first training epoch.
  • Configs: the three keys added to all examples/config/*.yaml and tests/config/*.yaml.
  • Docs: docs/quick_start/yaml_config.md documents the new keys and constraints; README
    CLI tables updated.
  • Tests: two unit tests in tests/test_pipeline.py cover the config-driven wiring and the
    default fallback.
  • Repo hygiene & CI: pre-commit runs at the pre-push stage and is re-enabled in CI; secrets
    baseline updated (ignore *.ipynb, whitelist a known false positive); CONTRIBUTING checklist
    • integration-tests step added; README/CONTRIBUTING document a from-source
      torch-scatter/torch-sparse install for PyTorch versions without a prebuilt PyG wheel.
      Formatting-only fixes applied to integrationtests/test_base_set.py.
  • Dependencies & security: build setuptools >= 83.0.0, pinned in CI, to clear advisory
    PYSEC-2026-3447.

Backward compatibility

No behavior change for existing configs: all three keys default to Validation loss when
absent, matching the previous hard-coded behavior.

Usage

callbacks:
  patience: 100
  tol: 0
  early_stopping_monitor: Validation loss
  checkpoint_monitor: Validation loss
  lr_scheduler_monitor: Validation layer_11_residual

Testing

MLFLOW_ALLOW_FILE_STORE=true pytest tests/test_pipeline.py

Signed-off-by: Panagiotis Grontas <72163196+p-grontas@users.noreply.github.com>
Signed-off-by: Panagiotis Grontas <72163196+p-grontas@users.noreply.github.com>
Signed-off-by: Panagiotis Grontas <72163196+p-grontas@users.noreply.github.com>
Signed-off-by: Panagiotis Grontas <72163196+p-grontas@users.noreply.github.com>
Signed-off-by: Panagiotis Grontas <72163196+p-grontas@users.noreply.github.com>
Signed-off-by: Panagiotis Grontas <72163196+p-grontas@users.noreply.github.com>
Signed-off-by: Panagiotis Grontas <72163196+p-grontas@users.noreply.github.com>
Signed-off-by: Panagiotis Grontas <72163196+p-grontas@users.noreply.github.com>
Signed-off-by: Panagiotis Grontas <72163196+p-grontas@users.noreply.github.com>
@p-grontas
p-grontas marked this pull request as ready for review July 15, 2026 09:31
@p-grontas

Copy link
Copy Markdown
Author

@albanpuech ready for review

Signed-off-by: Panagiotis Grontas <72163196+p-grontas@users.noreply.github.com>
@p-grontas p-grontas changed the title Add configurable --monitor / --monitor_mode flags for training callbacks Make training-callback and LR-scheduler monitored metrics configurable via YAML Jul 16, 2026

@albanpuech albanpuech left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

THANK YOU!!
just a few things to check

- name: Install dependencies
run: |
python -m pip install --upgrade pip wheel
# setuptools>=83.0.0 clears PYSEC-2026-3447

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@romeokienzler @p-grontas Maybe for a future PR we will want to also pin the version of setuptools in the pyproject... but no need to do it now

Comment on lines +216 to +220
Note: A monitored metric name must exactly match a logged validation metric.
For example, `Validation layer_11_residual` is only produced by the
`LayeredWeightedPhysics` loss and requires a model deep enough to have a
layer index 11 (a 12-layer model). Pointing a monitor at a metric that is
never logged aborts the run once training begins.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cool!

Comment thread examples/config/HGNS_OPF_datakit_case118.yaml Outdated
patience: 100
tol: 0
early_stopping_monitor: Validation loss
checkpoint_monitor: Validation layer_11_residual

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
checkpoint_monitor: Validation layer_11_residual
checkpoint_monitor: Validation loss

patience: 100
tol: 0
early_stopping_monitor: Validation loss
checkpoint_monitor: Validation layer_11_residual

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
checkpoint_monitor: Validation layer_11_residual
checkpoint_monitor: Validation loss

patience: 100
tol: 0
early_stopping_monitor: Validation loss
checkpoint_monitor: Validation layer_11_residual

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
checkpoint_monitor: Validation layer_11_residual
checkpoint_monitor: Validation loss

patience: 100
tol: 0
early_stopping_monitor: Validation loss
checkpoint_monitor: Validation layer_11_residual

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
checkpoint_monitor: Validation layer_11_residual
checkpoint_monitor: Validation loss

Comment thread gridfm_graphkit/tasks/base_task.py Outdated
lr_scheduler_monitor = getattr(
self.args.callbacks,
"lr_scheduler_monitor",
"Validation loss",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could use DEFAULT_MONITOR https://github.com/gridfm/gridfm-graphkit/pull/85/changes#diff-2453c8aec0e4d354dfe0c000a28790240cf2de314239087c06e01902066e3a5dR30

DEFAULT_MONITOR should be defined somewhere else than in cli in this case

otherwise, fine to not use DEFAULT_MONITOR, but it should be clear in cli.py that DEFAULT_MONITOR is not the the LR scheduler

Comment thread .pre-commit-config.yaml
@@ -1,3 +1,5 @@
default_install_hook_types: [pre-push]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is this?

@p-grontas p-grontas Jul 16, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you install the pre-commit hooks (with pre-commit install), then when you git push, the pre-commit checks run and the branch is only pushed if they pass. So that the pre-commits are not forgotten and caught by the CI

Comment thread CONTRIBUTING.md Outdated

* [ ] **Rebase your branch onto the latest `main` before opening a PR.**
* [ ] **Sign off all commits** with the Developer Certificate of Origin (`git commit -s`). See [Developer Certificate of Origin signoff].
* [ ] Open a PR with a short description of your changes and add Alban Puech as a reviewer.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* [ ] Open a PR with a short description of your changes and add Alban Puech as a reviewer.
* [ ] Open a PR with a short description of your changes.

@albanpuech
albanpuech requested a review from romeokienzler July 16, 2026 13:25
@albanpuech

Copy link
Copy Markdown
Collaborator

@romeokienzler JFYI

Signed-off-by: Panagiotis Grontas <72163196+p-grontas@users.noreply.github.com>
@albanpuech

Copy link
Copy Markdown
Collaborator

Some comments from cc are useful: @p-grontas

  • DEFAULT_MONITOR not reused: base_task.py:123 hardcodes "Validation loss" for the LR scheduler. Move DEFAULT_MONITOR to a neutral module (not cli.py) and use it in both places — importing cli→task is the wrong dependency direction.

  • Dead monitor on ModelCheckpoint: with save_top_k=0, Lightning 2.6.5's _save_topk_checkpoint returns immediately, so monitor/mode are never read — dead, misleading config (best-model selection is actually SaveBestModelStateDict; this only writes last.ckpt). Drop monitor=/mode= or comment that it only saves last.

  • Fail-loud is asymmetric but adequate: only SaveBestModelStateDict raises explicitly. EarlyStopping covers itself via strict=True; ModelCheckpoint can't (see above). So a bad early_stopping_monitor/checkpoint_monitor still aborts — worth a one-line PR note that early-stopping's fail-loud comes from Lightning, not this code.

Signed-off-by: Panagiotis Grontas <72163196+p-grontas@users.noreply.github.com>
Signed-off-by: Panagiotis Grontas <72163196+p-grontas@users.noreply.github.com>
@albanpuech

Copy link
Copy Markdown
Collaborator

@p-grontas Should I check again?

@p-grontas
p-grontas requested a review from albanpuech July 17, 2026 09:15

@albanpuech albanpuech left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two final things

  • docs/quick_start/yaml_config.md still says checkpoint_monitor is for “best-model saving and checkpointing” — slightly stale now that ModelCheckpoint only writes last.ckpt.
  • Test comment in test_pipeline.py still says save-best and checkpoint “share” checkpoint_monitor.

Thank you!

Signed-off-by: Panagiotis Grontas <72163196+p-grontas@users.noreply.github.com>
@p-grontas

Copy link
Copy Markdown
Author

@albanpuech Thanks, good catch!

@p-grontas
p-grontas requested a review from albanpuech July 29, 2026 12:22
@albanpuech

Copy link
Copy Markdown
Collaborator

Thanks for the work @p-grontas

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants