Add prediction_scaling to rescale predictions toward the training target distribution - #1261
Closed
psinger-prior wants to merge 4 commits into
Closed
Add prediction_scaling to rescale predictions toward the training target distribution#1261psinger-prior wants to merge 4 commits into
psinger-prior wants to merge 4 commits into
Conversation
…t distribution One constructor argument on both estimators with modes none, balanced, sampler, holdout, and auto. Every mode is a multiplicative correction of the predicted distribution; they differ in where the factors come from. The sampler mode undoes the label shift introduced by majority_downsample row subsampling for free, and is the default under that sampler via auto. balance_probabilities becomes a deprecated alias for prediction_scaling=balanced.
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 b8242ee. Configure here.
…ntiable path fit_with_differentiable_input z-normalizes y before fitting, so the majority value was located in z-score units against raw-space borders. Pass the pre-normalization tensor instead and test that the differentiable path matches fit().
… batch sizes The forward pass is not bit-identical across batch sizes on Linux CPU, and the bar-distribution mean amplifies those differences; the property that matters is that the fitted weights are applied row by row.
psinger-prior
marked this pull request as draft
September 11, 2026 13:35
Contributor
Author
|
Will simplify in follow-up PR |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Summary
Adds a
prediction_scalingargument to both estimators that rescales predictions toward the training target distribution. Every mode is one multiplicative correction of the predicted distribution and they differ only in where the factors come from:none,balanced(the existingbalance_probabilities),sampler(undo the label shift introduced bymajority_downsamplerow subsampling, for free), andholdout(fit the correction on held-out rows). The defaultautoresolves tosamplerwhen the row sampler shifted the prior and tononeotherwise, so behavior is unchanged for every configuration that does not usemajority_downsample, and that mode now comes out calibrated by default. Follow-up to #1253.What changed
tabpfn.prediction_scalingholds the mode enum, the resolver, and the pure factor functions: class weights forbalanced/sampler, the holdout fixed-point fit for class weights, per-bucket log weights for the regressionsamplermode, and the holdout affine fit.balancedis the inverse training prior (identical to the old behavior), or the inverse context prior when the sampler shifted it.sampleris training prior over context prior.holdoutiteratesw_c <- w_c * freq_c / mean_pred_con the held-out probabilities until the mean predicted probability per class matches the observed frequency.samplerreweights the bar-distribution bucket holding the most frequent target value by its training share over its context share, and every other bucket by the ratio of the complements.holdoutfits a scalar (or additive shift for signed targets) on held-out mean predictions and applies it to the raw-space borders, so mean, median, quantiles, andoutput_type="full"all move together.balancedis rejected.holdoutreuses the split-fit-predict of the tuning machinery. Withtuning_configset, it shares the holdout predictions with temperature calibration at no extra cost; without it, it runs one holdout pass with the tuning defaults. Tuning clones are forced toprediction_scaling="none"so the holdout rows are scored unscaled. Order is temperature, then scaling, then decision thresholds.balance_probabilities=Truestill works, emits aDeprecationWarning, and maps toprediction_scaling="balanced"; combining it with another mode raises.predict_proba_batched/predict_batchedraise when a mode would actually apply per-dataset state, and keep working underautowhen nomajority_downsamplesampler is configured.TabPFNEnsemblePreprocessorexposes the resolved row-sampling method and asampler_shifted_priorflag.Results
Same laptop-scale setups as #1253: 4 estimators, 10k rows of context per estimator, seed 0, MPS. Ranking metrics are unchanged by the classifier modes by construction, so only calibration moves there.
Credit card fraud (0.17% positive, 200k-row pool, 50k test rows, base rate 0.0015)
The downsampled context ranks better but predicts three times too many positives. Both corrections bring the mean prediction back to the base rate and make it the best-calibrated arm on every metric.
freMTPL2 loss cost (3.7% nonzero, 100k-row pool, 20k test rows, raw target with default transforms)
For regression the
samplercorrection is the analytic label-shift fix and turns Tweedie skill positive, but it overshoots the level: the model adopts the context prior only partially, so removing the full shift lands below the true mean. It also changes the ranking slightly, since the bucket reweighting is nonlinear per row; raw Gini drops while in-decile Gini improves.holdoutmeasures the actual level and is the stronger choice for regression when the extra fit is affordable. Both beat leaving the shift in place.Review guide
src/tabpfn/prediction_scaling.py. It is short, pure, and carries the math; the estimator changes are plumbing around it._resolve_prediction_scalingand the two-line change inlogits_to_probabilities. Note that the ensemble preprocessor is now constructed before the tuning step, because the free modes need the context prior and the tuning step applies whatever weights are known. The two are independent otherwise._rebuild_raw_space_bardist,_reduce_accumulated_logits, and the extended_maybe_calibrate_ensemble_temperature. The affine map has to be in place before the raw-space borders are built, which is why the holdout fit happens in the tuning step and the sampler weights after the preprocessor exists.prediction_scaling="none"in both tuning clones, the batched-predict guards.balancedunder a shifted context divides by the context prior rather than the training prior. Balancing relative to a prior the model never saw would be wrong; this composes the sampler correction with plain balancing. Without subsampling it is bit-identical to the oldbalance_probabilities.samplershould stay theautodefault for regression given the overshoot above, or whetherautoshould meannonefor regressors and leavesampler/holdoutopt-in. The classifier case is clear-cut.Testing
tests/test_prediction_scaling.py: 36 tests covering every factor function (including an exactness check that the sampler weights recover the training posterior under synthetic label shift, and that the legacy balancing is reproduced bit for bit), the resolver, and the estimator wiring for both tasks: auto resolution, ranking invariance, batch independence (predict(X[:1]) == predict(X)[:1]), the deprecation alias and its conflict error, holdout fitting without atuning_config, rejection ofbalancedfor regressors and ofholdoutunder differentiable input, and the batched-predict guards.Breaking changes / follow-ups
balance_probabilitiesis deprecated in favor ofprediction_scaling="balanced". No behavior change yet.SAMPLE_SUBSAMPLING_METHOD="majority_downsample", which now applies thesamplercorrection. Passprediction_scaling="none"to get the previous uncorrected output.autodefault question raised above.