Conversation
Introduce a `train_stream` verb, the training counterpart to the recently
merged `infer_stream`. It loads a model once and trains on batches from an
open-ended IterableDataset (e.g. KafkaStreamDataset) through a context-manager
session object, mirroring the InferStream pattern.
Because a live stream has no epochs, length, or train/validate/test splits, the
verb bypasses the Ignite create_trainer / max_epochs path and drives a per-batch
loop directly, reusing create_process_func("train_batch", ...) — the model's
self-contained train_batch already runs the full optimizer step.
Highlights:
- TrainStream verb + TrainStreamSession (iterable and manual train_batch/process
modes); run_cli raises NotImplementedError (programmatic API only).
- Weights persisted periodically (save_weights_every) and on close; close()
returns the trained model.
- Full MLflow + TensorBoard logging: a session-spanning MLflow run started in
run() and ended in close(), per-batch loss logged to both back-ends.
- Ragged/partial batches (streaming timeout flushes) are trained as-is, with a
defensive empty-batch skip and an optional min_batch_size guard.
- New [train_stream] config section; verb auto-exposed via @hyrax_verb.
Adds tests/hyrax/test_train_stream.py and specs/train_stream.spec.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vhimu4YPAyMBPj3dPzEmp4
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #987 +/- ##
==========================================
+ Coverage 67.52% 69.47% +1.94%
==========================================
Files 87 89 +2
Lines 8309 8689 +380
==========================================
+ Hits 5611 6037 +426
+ Misses 2698 2652 -46 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
Note for Drew for later to run the hyrax dataset producer to emit HSC images: |
|
Check out this pull request on See visual diffs & provide feedback on Jupyter Notebooks. Powered by ReviewNB |
…basic lsdb dataset to dynamically generate getters for simple and nested columns.
…ing TESS data, dim. red. and scatter plotted 33k points.
…o claude/train-stream-verb-planning-8qjyzm
…thub.com/lincc-frameworks/hyrax into claude/train-stream-verb-planning-8qjyzm
| if num_samples == 0: | ||
| logger.debug("Skipping empty batch.") | ||
| return None | ||
| min_batch_size = self._config["train_stream"]["min_batch_size"] |
There was a problem hiding this comment.
Make sure this is build up the batch and not drop it on the floor.
| return self._model | ||
|
|
||
| def checkpoint(self, model_metrics=None) -> None: | ||
| """Save the current model weights if loss is lower than the previous best. |
There was a problem hiding this comment.
Double check on this to see if it's still used.
|
|
||
| return lsdb.open_catalog(self.data_location, **open_catalog_kwargs) | ||
|
|
||
| def _requested_columns_from_config(self, config: dict): |
There was a problem hiding this comment.
Can we just get rid of this entirely? We should just load all the columns.
There was a problem hiding this comment.
This functionality is in HATSDataset, so we could just call it directly.
| open_catalog_kwargs = dict(ds_config["open_catalog_kwargs"] or {}) | ||
| if requested_columns and "columns" not in open_catalog_kwargs: | ||
| open_catalog_kwargs["columns"] = requested_columns | ||
|
|
||
| return lsdb.open_catalog(self.data_location, **open_catalog_kwargs) |
There was a problem hiding this comment.
I would argue for removing this functionality. We should just expect users to hand Hyrax the pandas future. We should then be able to remove _requested_columns_from_config
| self._warn_on_small_chunks(client) | ||
| return client | ||
|
|
||
| def _warn_on_small_chunks(self, client) -> None: |
There was a problem hiding this comment.
Maybe don't do this warning thing. This is copied from the LSDB documentation. We don't need to warn users about it. This is not our fight, this is LSDB and Dask.
| rows: list[dict] = [] | ||
| taken = 0 | ||
|
|
||
| try: |
There was a problem hiding this comment.
Make sure that left over rows are held until the next chunk, and then combined with the first batch.
| self._iterator = None | ||
| self._timings.log() | ||
|
|
||
| def collate_lightcurve(self, samples): |
There was a problem hiding this comment.
This should be tossed out. It was for experimentation.
|
@maxwest-uw - @mtauraso and I came to the conclusion that the best path forward for this PR is likely to leave it as a draft, create a fresh branch and pull over only the important pieces. There has been a lot of experimentation along the way and as a result also a lot of superfluous code, notebooks, etc. Feel free to take a look over it and comment if you have time though :) |
Change Description
Adds a new
train_streamverb that enables training models on open-ended streaming data sources (e.g., Kafka topics) using a context-manager session pattern. This mirrors the existinginfer_streamverb but for training workflows.Solution Description
New Components
TrainStreamverb (src/hyrax/verbs/train_stream.py):TrainStreamSessionfor on-demand batch training[data_request.train_stream]with a streaming dataset; the session is iterable and yields(batch, metrics)pairssample_batchand feed batches viasession.train_batch(batch)create_process_func("train_batch", ...)for the per-batch training step,setup_model/setup_model_from_samplefor model initialization, and MLflow + TensorBoard loggingTrainStreamSessioncontext manager:min_batch_size(guards against size-1 batches breaking BatchNorm in user models)save_weights_everyis set)close()Configuration
Added
[train_stream]section tohyrax_default_config.toml:model_weights_file: warm-start weights path (default:false= train from scratch)weights_filename: checkpoint filename (default:"example_model.pth")save_weights_every: checkpoint interval in batches (default:false= only on close)experiment_name: MLflow experiment (default:"notebook")run_name: MLflow run name (default:false= use results-dir name)min_batch_size: skip batches smaller than this (default:false= train all)Design Rationale
create_trainer/trainer.run(..., max_epochs=...)pathmin_batch_sizeguardinfer_streampattern; no shared-base refactor to avoid over-engineeringTesting
Added comprehensive test suite (
tests/hyrax/test_train_stream.py):KafkaStreamDataset(usingFakeConsumerstand-in)process_functo verify empty/small-batch skippingclose()and error handlingNotImplementedError(programmatic API only)Code Quality
https://claude.ai/code/session_01Vhimu4YPAyMBPj3dPzEmp4