Repository navigation
Conversation
Change map
Rule: return the published model's holdout or |
There was a problem hiding this comment.
🧹 Nitpick comments: 1
packages/kumo-engine/test/test_holdout_df.py: 1
112-125: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winCover explanation processing with
refit_trainval.The production path runs
best_trainer.explain(...)before_published_holdout(...). The matrix does not combineexplain=Truewithrefit_trainval=True, so a regression in mode restoration or holdout selection for this path can pass. Add both reachablerefit_trainvalexplanation cases at this matrix site.Suggested fix
@pytest.mark.parametrize('refit_trainval,refit_full,explain,model', [ (False, False, False, 'fit'), (True, True, False, 'refit_trainval'), + (True, False, True, 'refit_trainval'), + (True, True, True, 'refit_trainval'), (False, True, True, 'fit'), ])
ℹ️ Review info
⚙️ Run configuration
- Configuration used: Repository: NVIDIA/kumo-engine/.coderabbit.yaml
- Review profile: QUIET
- Plan: Enterprise
- Run ID:
b9ce2f06-0cec-4ff9-9845-51a2fb62bc8d
📒 Files selected for processing: 1
packages/kumo-engine/kumo/engine/trainer/trainer.py
Included review availability: This review used your included allowance. Your plan provides up to 12 included reviews per hour; 5 remain after this review.
0c37212 to
5cebd6f
Compare
5cebd6f to
39f2531
Compare
5cebd6f to
2108fae
Compare
2108fae to
c36dfd8
Compare
ce86b46 to
893be81
Compare
893be81 to
f8c6502
Compare
fit() read test_df.parquet from best_trainer.log_dir, which is whichever refit stage ran last, not necessarily the model the bundle publishes. With refit_full the published model has seen the test split, so its holdout is meaningless. Read the holdout from the published model's log dir (Trainer.published_fit_mode, also used to pick the prediction model) and return none for refit_full. get_log_dir takes an optional fit_mode override. Verified: test_holdout_df (fit / refit_trainval with explain / refit_full), test_training_explanations, test_semantic_carry_forward: 35 passed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
test_artifacts.py's fake trainer borrows Trainer methods; select_fit_mode now calls published_fit_mode, so the fake needs it too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
f8c6502 to
86fa3c6
Compare
Series: kumo-engine MLOps series: every snapshot, training table, model and prediction run carries a self-contained _provenance.json;
with kumo.mlops(...)stores each artifact under one artifact root, tracks fits and prediction runs in MLflow or Snowflake and registers models; volumes and stages can hold files; prediction runs are monitored for drift and realized performance.Stack: #53 → #112 → #50 → #60 → #64; #114 on #112; #115 on #64
Merge order: one linear stack; merge bottom to top (#53 first); #114 sits on #112 and merges any time after it; #115 (draft) sits on #64 and merges after it
This PR: Makes
TrainingResult.holdout_paththe published model's holdout, orNone, and makes the answer independent of whether explanations are on.Summary
This PR makes
TrainingResult.holdout_paththe published model's holdout, orNone, and makes the answer independent of whether explanations are on.What the holdout is. During
fit(), the trained model scores the test split, and the predictions are written totest_df.parquetin the trial's run directory.TrainingResult.holdout_pathpoints at that file andTrainingResult.holdout_df()reads it. Teams use it to check calibration and score distributions of the model they are about to ship.Which models exist. One fit can produce up to three models from the best trial:
fitrefit_trainval(training_job.refit_trainval)refit_full(training_job.refit_full)The bundle ships the model trained on the most data that was enabled:
refit_full, elserefit_trainval, elsefit(kumo-core's_set_fit_mode_to_use, called when the bundle's checkpoint is chosen).Problem. Whether
fit()returned a holdout, and whose it was, depended on whether explanations were on:refit_fullwith explanations off:holdout_pathwasNone.refit_fullwith explanations on:holdout_pathpointed at thefitorrefit_trainvalmodel's predictions, with nothing saying it was not the shipped model.Cause.
fit()looked fortest_df.parquetinbest_trainer.log_dir, which follows whateverfit_modethe trainer object was last left in. Publishing switches it torefit_full, whose directory has no holdout.explain()switches the mode back as a side effect, so with explanations on the lookup landed in an earlier model's directory.Run directory from a real CPU fit on a small synthetic graph (
users,items,orders) withrefit_trainvalandrefit_fullboth on; the best trial isversion_1:Change. The lookup asks kumo-core's
Trainer.published_fit_mode()(the same refit-flag order the bundle is published in) and reads only that model's directory, instead of following the trainer's currentfit_mode:refit_fullpublished:holdout_path = None. No holdout of the shipped model exists, and another model's would be misleading.refit_trainvalpublished: theversion_N_refit_trainval/holdout.fitpublished: theversion_N/holdout.kumo-core gains two small additive pieces:
Trainer.published_fit_mode()(the refit-flag order_set_fit_mode_to_usealready applied, moved into a method so the holdout lookup and prediction share it) and an optionalfit_modeargument onTrainer.get_log_dir(default: the trainer's own), so the trainer object is never mutated and no empty refit directories are created. The run directory layout andTrainingResultfields are unchanged.From two real fits on the graph above (explanations off; the first picked trial 3 as best):
Every combination:
version_Nversion_N(fit)version_N_refit_trainvalrefit_trainval)version_Nversion_N_refit_trainvalBack-compat
This PR changes only which existing file is returned. It adds no fields, checks or errors.
refit_trainvalonlyholdout_pathas before, with explanations on or off.refit_full+ explanations offholdout_path=None, as before.refit_full+ explanations onfitorrefit_trainval). Now returnsNone, because no holdout of the shipped model exists and substituting another model's would be misleading.holdout_df()raises the sameFileNotFoundErrorit already raises whenever there is no holdout.holdout_path=None, as before.Trainer.load()resultholdout_path=None, as before.Known limitations
refit_fullmodel has no holdout. To inspect thefitorrefit_trainvalmodel's test predictions, read them from the run directory above; they are not returned as the shipped model's.Testing Done
test_holdout_df.py: real CPU fits for no refit (path underversion_N/),refit_trainvalwith explanations on (path underversion_N_refit_trainval/), andrefit_trainval+refit_full(None); the default fit asserts the holdout is not inside the bundle. Verified with the kumo-core artifact, training and checkpoint suites whenget_log_dirchanged.test_training_explanations.py,test_semantic_carry_forward.py: fake trainers exposepublished_fit_mode/get_log_dir.main):test_holdout_df.py+test_training_explanations.py+test_semantic_carry_forward.py: 35 passed (CPU).Checklist
🤖 Generated with Claude Code