Table Predictions
Hand it a table where one column is filled in for some rows and empty for others. It fills in the rest. Nothing is trained: the labelled rows travel with the request and are read in context, so a prediction takes tens of milliseconds and the model never changes.
What This Replaces
The usual way to predict a column is to train a model: pick features, fit a gradient-boosted tree or a small network, tune it, keep it somewhere, retrain when the data moves. That is the right answer when you have a lot of rows and the problem stays still.
Kumo Tabular is for the other case, which is more common than it gets credit for: a few hundred labelled rows, a column you want filled in now, and no appetite for owning a training pipeline. The labelled rows are the model. Change them and the next call behaves differently, with nothing to refit.
It is not a language model and it does not take instructions. It consumes rows and outcomes.
Availability
A runner serving Kumo answers these endpoints and not the chat ones. Ask it what it is:
curl -s localhost:11540/api/server | jq .tabular
# {
# "model": "kumo-small-classifier",
# "capabilities": {
# "tabular_prediction": true,
# "task": "classification", # or "regression" - separate checkpoints
# "preprocessing": ["prepared", "sdm_v1"],
# "max_context_rows": 4096,
# "max_query_rows": 1024,
# "max_columns": 500,
# "max_classes": 256,
# "model_classes": 10,
# "quantiles": 0, # 999 on a regression endpoint
# "default_estimators": 8,
# "max_estimators": 16,
# "context_cache": true
# }
# }null means this runner serves no table model and both endpoints will refuse.
One task per endpoint. Classification and regression are different checkpoints, so an endpoint does one or the other. task tells you which. Each comes in three sizes (27M, 62M and 214M parameters), all in the F32 weights NVIDIA publishes.
Raw Rows
The straightforward path takes the table as it comes: numbers, strings and empty cells. Set preprocessing to sdm_v1, give it the labelled rows in context with their answers in targets, mark which columns are categorical, and put the rows you want filled in under query.
curl -X POST localhost:11540/v1/tabular/predictions \
-H 'Content-Type: application/json' \
-d '{
"preprocessing": "sdm_v1",
"context": [[34, "gold"], [19, "basic"], [52, "gold"], [27, null]],
"targets": ["renewed", "churned", "renewed", "churned"],
"categorical": [false, true],
"query": [[41, "gold"], [22, "basic"]]
}'{
"classes": ["renewed", "churned"],
"predictions": [
{"class": "renewed", "probabilities": [0.88, 0.12], "logits": [...]},
{"class": "churned", "probabilities": [0.21, 0.79], "logits": [...]}
]
}A null is a missing cell, not an error. categorical has one entry per column and says which to treat as labels rather than quantities.
A Number Instead Of A Class
On a regression endpoint each row comes back with its whole distribution rather than one figure: 999 quantiles, plus the median for convenience.
{"median": 2140.0, "quantiles": [812.0, 835.0, ...]}That is the part worth using. A point estimate hides whether the model is confident, and the quantiles are what let you say "between 1,900 and 2,400 four times out of five" instead of a single number that reads as more certain than it is.
Already-Encoded Rows
If you have done your own feature engineering, preprocessing: "prepared" takes numbers only and skips the encoder, so what you pass is what the model sees:
{
"preprocessing": "prepared",
"context": [[1.0], [2.0]],
"targets": [0.0, 1.0],
"categorical": [false],
"query": [[1.5]]
}The two modes are deliberately separate rather than one auto-detecting path: a request that silently reinterpreted your features, or the units of a regression target, would be worse than one that refuses.
Reusing A Table
When the labelled rows stay the same and only the questions change, sending the whole table every time is waste. Register it once and query it by id:
# 1. the table, once
curl -X POST localhost:11540/v1/tabular/contexts \
-H 'Content-Type: application/json' \
-d '{"preprocessing": "sdm_v1", "context": [...], "targets": [...], "categorical": [...]}'
# {"context_id": "ctx_...", "cache_hit": false, "cache_bytes": 1048576, "classes": [...]}
# 2. ask it about new rows, as often as you like
curl -X POST localhost:11540/v1/tabular/predictions \
-H 'Content-Type: application/json' \
-d '{"context_id": "ctx_...", "query": [[41, "gold"]]}'Up to four tables are held at once, dropped least-recently-used, and a table idle for ten minutes is released. A query whose row shape does not match the table it names is refused rather than padded. DELETE /v1/tabular/contexts/{context_id} drops one before then.
Accuracy For Compute
num_estimators runs the prediction several times over different views of the table and combines them: 8 by default, up to 16. More is steadier and costs proportionally more. seed makes a run reproducible.
Limits
| Limit | Value |
|---|---|
| Labelled rows per request | 4,096 |
| Rows predicted per request | 1,024 |
| Columns | 500 |
| Cells in one request | 131,072 |
| Classes | 256 |
Past these the request is refused with the limit named.
The model itself predicts ten classes. Past that Paddock uses NVIDIA's own error-correcting output codes: the model runs once per code task and the results are combined, the way NVIDIA's pipeline does it, which carries the ceiling to 256. A table of ten classes or fewer takes the single-pass path and gives exactly the results it always did, so nothing changes underneath an existing caller. Beyond ten, expect the work to grow with the number of code tasks rather than staying flat.
In the Studio
The Studio's Tables page does this without a request: paste or open a CSV, choose the column to predict, and the rows where it is empty come back filled in. The result copies out as CSV, and the page will show you the equivalent curl for the call it just made. Tables and their runs are saved, shared with the Mac app, and each table has its own link. See Studio.