Python and scikit-learn¶
Estimators¶
TabctxClassifier and TabctxRegressor are scikit-learn estimators
whose fitting and predicting happen on a tabctx server.
from tabctx import TabctxClassifier, TabctxRegressor, TabctxClient
client = TabctxClient("http://127.0.0.1:8000")
clf = TabctxClassifier(client=client) # the server's default model
reg = TabctxRegressor(model="tabpfn-3.5", client=client) # or name one
- Input: DataFrames or arrays. Text columns, categories, dates and missing values are sent as they are, as Parquet.
- Labels may be strings, ints or bools;
predictreturns them as given tofit, andpredict_proba's columns followclasses_. - scikit-learn tools: they clone and pickle, and work with
cross_val_scoreandGridSearchCV. - One context per table: the context id is a hash of the table, model and task, so estimators fit on the same data share one cached context on the server.
- Evicted or restarted servers are handled: an estimator keeps its training table and fits again if the server has lost the context.
from sklearn.model_selection import cross_val_score
cross_val_score(TabctxClassifier(client=client), X, y, cv=5)
Prediction intervals¶
TabICL and TabPFN predict a distribution over the target, not just a
number. predict_quantiles returns that distribution's quantiles, from
the same model call as the mean:
reg = TabctxRegressor(client=client).fit(X_train, y_train)
q = reg.predict_quantiles(X_test, quantiles=[0.05, 0.5, 0.95])
low, median, high = q[:, 0], q[:, 1], q[:, 2] # a 90% interval per row
Levels are in (0, 1), in any order; the columns follow it. Check the
intervals on held-out data before relying on them:
examples/prediction_intervals.py
does it for California housing, where the 90% interval held 86.5% of the
prices. Classifiers already return a distribution: predict_proba.
The client¶
TabctxClient is the HTTP client underneath, pure standard library. It
sets the routing and tenant headers for you.
client = TabctxClient("http://localhost:8000", tenant_id="acme")
client.fit(X_train, y_train, dataset_id="churn-v1") # DataFrame, array or rows
client.fit_file("train.parquet", target="churned", dataset_id="churn-v2")
result = client.predict("churn-v1", X_test, return_proba=True)
result.predictions, result.probabilities, result.classes
client.predict("prices", X_test, quantiles=[0.05, 0.95]).quantiles # regression
client.datasets() # what the server holds for this tenant
client.delete("churn-v1") # gone from GPU, host memory and disk
client.models(), client.limits()
base_url and api_key default to TABCTX_BASE_URL and
TABCTX_API_KEY. The key is sent as a bearer token, never appears in
the client's repr, and is left out when the client is pickled.
Errors¶
Server errors come back as tabctx exceptions, importable from tabctx.
The in-process engine raises the same types for the same mistakes
(invalid input, an unknown context, a table too large); conditions that
are only temporary come back from a server as one retryable type,
TabctxBackpressureError.
| HTTP | Exception | Meaning |
|---|---|---|
| 422 | InvalidInputError |
A malformed request: retry won't help. |
| 404 | DatasetNotFoundError |
No such context: never fit, deleted, evicted, past its retention limit, or lost to a restart. Fit again. |
| 404 | UploadNotFoundError |
No such upload: expired, already used, or sent to another replica. |
| 413 | AdmissionRejected |
The table is too large for this deployment's memory, or the request for its upload limit. |
| 503 | TabctxBackpressureError |
Busy or temporarily unable; the client already retried with backoff. |
| 507 | BackendComputeError |
The model failed on the device. |
| 401/403 | PermissionError |
Missing tenant or API key. |
The engine in your own process¶
Without a server, TabctxEngine gives you the same cache and admission
control in one Python process. This example uses the fake model, so it
runs anywhere; swap in tabctx.backends.tabicl.TabICLBackend(device="cuda")
(with the tabicl extra) for real predictions:
from tabctx import ContextCacheManager, TabctxEngine
from tabctx.backends.fake import FakeBackend
from tabctx.memory import A100_40GB_TABICL_CALIBRATION, PowerLawMemoryEstimator
def main() -> None:
estimator = PowerLawMemoryEstimator(A100_40GB_TABICL_CALIBRATION)
print(estimator.confidence())
cache = ContextCacheManager(capacity_bytes=estimator.ceiling_bytes())
engine = TabctxEngine(backend=FakeBackend(), cache=cache, estimator=estimator)
X_train = [[float(i), float(i) * 2] for i in range(20)]
y_train = ["a" if i % 2 == 0 else "b" for i in range(20)]
dataset_id = engine.fit(
X_train, y_train
) # task inferred: text labels -> classification
print(f"fit -> dataset_id={dataset_id}")
result = engine.predict(dataset_id, [[1.0, 2.0], [3.0, 4.0]], return_proba=True)
print(f"predict #1: {result.predictions} (proba shape reused cache)")
# Reuse the same cached context for a different test batch -- no re-fit.
result2 = engine.predict(dataset_id, [[5.0, 10.0]])
print(f"predict #2 (cache reused): {result2.predictions}")
print(f"stats: {engine.stats()}")
engine.evict(dataset_id)
if __name__ == "__main__":
main()