fix(regressor): make output_type="full" match a local prediction - #369
Merged
Conversation
ggprior
force-pushed
the
georg/full_output_chunking
branch
from
August 27, 2026 14:20
fb32c68 to
1ec43ed
Compare
ggprior
marked this pull request as ready for review
August 27, 2026 15:31
Two things made a full regression prediction through the client differ from the same call against the local tabpfn package. Bars outside a row's support are -inf, which the response encoding has no representation for, so they arrived as NaN. Softmaxing them yields NaN for the whole row, which propagates into anything that samples from the returned criterion. Restoring them to -inf reproduces the server's own `mean` field to float32 precision. The full-output payload also caps how many test rows one response may cover, so callers above the cap got a ValueError telling them to split by hand. `predict` now splits the request itself and concatenates the parts, which is what the arrays from one unrestricted call would hold.
ggprior
force-pushed
the
georg/full_output_chunking
branch
from
August 27, 2026 15:33
1ec43ed to
ea47711
Compare
simo-prior
approved these changes
Aug 27, 2026
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.
AI;DR: TabPFN output_type=full logits are -inf if bucket probability is zero. Over the wire (JSON) this is transmitted as null. This breaks several extensions including unsupervised and synthetic (whenever logits are turned back into probas via softmax op)
Claude generated description
Two things made
TabPFNRegressor.predict(output_type="full")through the clientdiffer from the same call against the local
tabpfnpackage.Masked bars came back as NaN
Bars a row's distribution puts no mass on carry a logit of
-inflocally. TheAPI serializes non-finite floats as
null(the pydantic default, which keepsthe payload spec-conforming), and the client turned
nullintoNaN. Unlike-inf, a singleNaNpropagates:exp(NaN)makes the normalising sumNaN,so one bar takes out all 5000 and the row's distribution is gone. Anything that
samples from the returned
criterionthen yieldsNaN.On breast-cancer with three features, 529 of 569 rows (93%) had at least one
such bar, so almost every sampled value was
NaN.Restoring
null -> -infon unpack reproduces the API's ownmeanfield tofloat32 precision, which is what pins the interpretation:
meanas returnednullis genuinely lossy —-inf,+infand a realNaNall collapse to it —so this is a recovery, not a decode. It is right for every value the model
actually produces here, and becomes a no-op if the payload ever encodes
non-finite floats losslessly.
The full-output row cap raised instead of splitting
A full-output response carries one logit per bar per test row, so the API caps
the rows one response may cover. Callers above the cap got a
ValueErrortellingthem to split by hand, where the same call locally just works.
predictnowsplits the request itself and concatenates the parts;
bordersisrow-independent so it is taken once, and an unrecognised field fails loudly
rather than silently returning the first chunk.
Verified against the live API: the merged arrays are identical to a manual
split.
Scope
Only
output_type="full"is affected. Other output types keep the existing"split it yourself" behaviour, since their caps are compute limits rather than a
payload-size artefact.
6 new unit tests, all offline.