Repository navigation
Give each regression member its own target pipeline [RES-2639] - #1198
Conversation
d5e41e0 to
09ebdd7
Compare
09ebdd7 to
05ed97d
Compare
b5da313 to
e541339
Compare
LeoGrin
left a comment
There was a problem hiding this comment.
LGTM!
One comment from claude, which makes sense IMO. Not sure we want to guarantee this always work, but maybe we could find a way to fail loudly for safety?
- Fit states saved before this PR load and predict wrong values, with no error.
- A .tabpfn_fit archive stores the fitted member configs and has no version stamp. An old archive holds bare presets whose inverse already lands in z-norm space.
- transform_borders_one now standardizes that result a second time.
- transform_borders_one now standardizes that result a second time.
- Repro: I saved a fit with the parent commit (4 estimators, 2 with a preset) and loaded it with the PR. Predictions went from [1057, 1029, 1025, 1005] to [524, 510, 508, 498]. Loading with the parent reproduces the original exactly.
- The same applies to pickled fitted estimators.
- Suggested fix: stamp the archive and raise on an old one, or detect a transform without the standardize_target step.
A few other nits from Claude which look correct:
- _targets_in_estimator_space returns raw targets when target_transform is None. That branch is now unreachable from the dataset path, and wrong if reached. Raise there instead.
- The None branch in _translate_batched_logits is dead for the same reason.
- data_util floors the frame std at 1e-8, while the member uses std + 1e-20. On a near-constant fine-tuning split the two disagree and the borders collapse. One shared constant would remove this.
- The comment at regressor.py:1340 still says "before the z-normalisation below". There is none after this PR.
- target_preprocessors is still annotated list[TransformerMixin | Pipeline | None], but it is now always a Pipeline.
ba2656f to
28fe360
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 28fe360. Configure here.
28fe360 to
f48014d
Compare
|
I addressed all nits. For saved fit states, I chose to document this as a breaking change requiring refitting rather than add version stamps or runtime compatibility checks. This means old archives and pickled estimators remain unsupported and can silently produce incorrect predictions if reused; the PR does not make them fail loudly but I think this is fine? |

Generated by Codex
Give each regression ensemble member an invertible target pipeline while retaining the order: standardize, then apply the preset. Keep the raw-target mean and standard deviation as the shared aggregation frame, and require that frame when fitting preprocessed regression batches. Document that saved fitted regressors must be refitted after this change.
PR 1 of 2 for RES-2639. Follow-up: #1199 changes transform order and preserves input standardization inside regression safepower.
Behavior and review fixes
Row-subsampled members normalize using their own training rows. With full contexts, small prediction differences can still arise from floating-point border mapping.
Inverse-transformed borders return to the shared standardized frame in float64 before narrowing. Grouped prediction uses each dataset's frame.
Saved
.tabpfn_fitregressors and fitted pickles from earlier versions are incompatible and must be refitted. The breaking changelog documents this; there is no version stamp or runtime compatibility check.RegressorBatch.y_train_meanandy_train_stdare required. Custom loops must pass both toTabPFNRegressor.fit_from_preprocessed; that method now sets the frame instead of relying on an earlierfit()or fine-tuning setup call.Fine-tuning and member preprocessing use the same
StandardizeTargetstatistics and epsilon, including near-constant targets.Missing member pipelines raise in regression loss and grouped border translation. The separate no-transform path for differentiable inputs remains valid.
Target pipeline annotations and the stale normalization comment are corrected.
Rebased onto main
ffd53715. Preserve main's CPU float64 border reconstruction and new serialization coverage. Update main's custom-loop tests to pass the required target frame while retaining their state-isolation assertions.Validation
Rebased validation: the broad non-slow suite reported 244 passed, 55 skipped, 66 deselected, and two failures. The border-frame assertion used float32 arithmetic despite main now reconstructing borders in float64; its corrected CPU and MPS variants both pass without changing tolerances. The config-equivalence test differed by 1.6e-5 on the Mac accelerator and passed in isolation without changes. All four custom-loop state-isolation tests pass.
The border-remapping suite adds 28 passed and 3 skipped. Pre-commit checks, including Mypy and Ruff, pass.
Command:
PYTHONPATH=src python -m pytest tests/test_preprocessing/test_target_transform.py tests/test_regressor_interface.py tests/test_batched_prediction_shape_safety.py tests/test_batched_prediction_data_util.py tests/test_finetuning_regressor.py tests/test_downsample_correction.py tests/test_save_load_fitted_model.py tests/test_fit_from_preprocessed.py -q -m 'not slow'Earlier full-context validation on the original revision found all 24 model-input target arrays bit-identical to its main baseline. Those measurements predate these review fixes; no new benchmark claim is made here.