Skip to content

Hand the trained model to the prediction in memory, keeping a file only when asked - #2701

Open
Flix6x wants to merge 6 commits into
mainfrom
feat/2111-no-model-artifacts-by-default
Open

Flix6x wants to merge 6 commits into
mainfrom
feat/2111-no-model-artifacts-by-default

Conversation

@Flix6x

@Flix6x Flix6x commented Oct 8, 2026

Copy link
Copy Markdown
Member

Description

Closes #2111 and #2683.

Every forecast cycle pickled its trained model to a folder, only for the prediction to read it back in the same job a moment later. Nothing in production deleted it (delete_model was only ever set by tests), so the folder kept one model per sensor and cycle number. A single model can be hundreds of MB: one development checkout held 589 MB in 12 files, the largest 330 MB. The default folder, flexmeasures/data/models/forecasting/artifacts/models, was also relative, so a worker created it under whichever directory it was started from. And since files were named by sensor and cycle number only, two runs for the same sensor at the same time shared file names.

The file had no other reader: no documentation mentions it, the API cannot set the folder, and #2479's parallel per-horizon training fits its models in threads, so no model crosses a process boundary through the file.

  • TrainPipeline.run returns the trained model, and PredictPipeline accepts it (model=), reading a model file only when none is handed over. A pipeline given neither says so, rather than failing to open None.
  • model-save-dir defaults to None. A model is kept as a file only when the option is given, so flexmeasures add forecasts --model-save-dir DIR keeps one model per cycle in DIR, as before.
  • Deleting a kept model after prediction (delete_model) still works, and is skipped when no file was kept.
  • Added changelog items in documentation/changelog.rst and documentation/cli/change_log.rst, with a note that hosts can delete the old artifacts folder.

How to test

pytest flexmeasures/data/tests/test_forecasting_jobs_fresh_db.py -k keeps_its_model

A forecast runs in an empty working directory, since the old default folder was relative to it.

  • [False]: without model-save-dir, the forecasts are made and no model file is written anywhere. On main, this fails: two model files appear under the working directory.
  • [True]: with model-save-dir, one model per cycle is kept there, and it can be read back.

Full suite: 2973 passed, 4 xfailed; the only failures are test_closest_sensor[1] and [3], which fail the same way on main in my sandbox, because a bare postgres:16 lacks the distance functions they call.

Related Items

Closes #2111 and #2683. #2683 asked why the model was written at all; this PR answers both from the same change.

🤖 Generated with Claude Code

Flix6x and others added 2 commits October 8, 2026 23:14
Context:
- #2111 and #2683: every forecast cycle pickled its trained model to a
  folder, only for the prediction to read it back in the same job a moment
  later, and nothing in production deleted it. A model can be hundreds of MB
  (589 MB for 12 files in one development checkout), the default folder was
  relative to the worker's working directory, and two runs for the same
  sensor shared file names. #2479's parallel training uses threads, so no
  model crosses a process boundary through the file.

Change:
- TrainPipeline.run returns the trained model, and PredictPipeline accepts
  it, reading a model file only when none is handed over.
- model-save-dir defaults to None: a model is kept as a file only when it is
  given, as an explicit request.
- Deleting a kept model after prediction still works, and is skipped when
  no file was kept.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: F.N. Claessen <claessen@seita.nl>
Context:
- #2111.

Change:
- A forecast run from an empty working directory makes its forecasts and
  writes no model file anywhere; given a model-save-dir, it keeps one model
  per cycle there, which can be read back. On main, the first case fails:
  two model files appear under the working directory.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: F.N. Claessen <claessen@seita.nl>
@Flix6x Flix6x added this to the 1.1.0 milestone Oct 8, 2026
Context:
- #2111, #2683.

Change:
- Infrastructure entry for #2701, telling hosts the old artifacts folder can
  be deleted, and a CLI changelog entry for --model-save-dir.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: F.N. Claessen <claessen@seita.nl>
@read-the-docs-community

read-the-docs-community Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 Needs a closer look

It changes a default behavior across the core forecasting train/predict/service flow, so a human should confirm the operational impact of no longer persisting models by default even though the diff itself is clean and well-tested.

0 open findings

What changed in this PR

This PR changes the forecasting pipeline so a trained model is handed from training to prediction in memory within a single cycle, rather than being pickled to a directory and read back by the same job. Writing a model to disk becomes opt-in via the existing --model-save-dir CLI option, which now defaults to None. This closes #2111 (model .pkl files piling up in a relative, un-cleaned default folder) and #2683 (the file was merely the transport between the two halves of a cycle, not an artifact anyone asked for).

Changes:

  • TrainPipeline.run now returns the trained model and writes a file only when model_save_dir is set; PredictPipeline accepts model= and reads a file only when no model is handed over, raising a clear error when given neither.
  • model-save-dir defaults to None (schema + removal of the dead default-read in resolve_config); ForecastCycleResult.model_path is now optional, and the delete_model cleanup in the service is guarded by model_path is not None.
  • Added a parametrized fresh_db test proving no model file is written by default and two are kept (and re-readable) when model-save-dir is given, plus changelog entries in both changelogs with an upgrade note that hosts can delete the old folder.
File Description
flexmeasures/​data/​models/​forecasting/​pipelines/​train.py run returns the model; file save gated on model_save_dir is not None; docstrings updated.
flexmeasures/​data/​models/​forecasting/​pipelines/​predict.py New model= arg; load_model returns the handed-over model, else loads the file, else raises a clear error.
flexmeasures/​data/​models/​forecasting/​pipelines/​train_predict.py compute_cycle passes model= and a conditional model_path; ForecastCycleResult.model_path made optional.
flexmeasures/​data/​services/​forecasting.py delete_model cleanup skipped when no file was kept (model_path is not None).
flexmeasures/​data/​schemas/​forecasting/​pipeline.py model-save-dir default → None; removed dead schema-default fallback; updated description.
flexmeasures/​data/​models/​forecasting/​__init__.py Updated _clean_parameters comment for model-save-dir.
flexmeasures/​data/​tests/​test_forecasting_jobs_fresh_db.py New parametrized test covering keep/no-keep behavior; fails on main.
documentation/​changelog.rst, documentation/​cli/​change_log.rst Changelog entries (PR #2701) with host upgrade note.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@Flix6x
Flix6x requested a review from BelhsanHmida October 8, 2026 21:26
Signed-off-by: Felix Claessen <30658763+Flix6x@users.noreply.github.com>
@Flix6x Flix6x self-assigned this Oct 8, 2026
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
These tests still asked for the old default folder, so running them left .pkl files in the working tree.

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>

@BelhsanHmida BelhsanHmida left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nice, clean change.

I tried it locally with the CLI: without --model-save-dir, no model file is written, and with it, one model per cycle is kept in the given folder.

I pushed two small fixes on top:

  • typed the model handed from training to prediction (BaseModel)
  • dropped the old model-save-dir path from the forecasting tests, which still left .pkl files in the working tree

Approving.

This branch has not been deployed

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Stop persisting forecasting model artifacts by default

3 participants