Quick start¶
This runs the whole workflow on public data, with no files of your own. With your
Prior Labs token exported in the shell (export TABPFN_TOKEN=<your token>):
mkdir -p out ~/.cache/tabpfn
docker run --rm --gpus all --user "$(id -u):$(id -g)" -e TABPFN_TOKEN \
-v "$HOME/.cache/tabpfn:/work/.cache/tabpfn" -v "$PWD/out:/work/out" \
ghcr.io/ilivius/tabflux:1.6.0
The cache mount keeps the TabPFN weights outside the container, so --rm does not
throw away the download; the out/ mount receives the results. mkdir and --user
keep everything the run writes owned by you (why).
See installation for the image and a local build.
Without the token, the run stops
The 3.5 weights download after a one-time licence acceptance on a Prior Labs
account. A container cannot open a browser, so the image sets
TABPFN_NO_BROWSER=1 and the API key passed with -e TABPFN_TOKEN shows the
package that the licence was accepted (see
installation). Without the token the download
fails. Every TabPFN fit runs in its own
process behind a fallback, a dummy that ignores the taxa and always answers the
majority class; TabFlux counts those fallbacks and stops the run after TabPFN's
tuning rather than report the dummy's scores. Once the weights are in the mounted
cache, later runs do not need the token.
What just happened¶
The default configuration, config_cfmd_demo.yaml, asks for
cFMD release v1.3.2 and eighteen of its datasets. TabFlux
downloads the taxonomic profiles (1,020 samples), rewrites them into the three input
files it reads, keeps cFMD's native species-level genome bins (SGBs) without
aggregating, and normalises depth. Categories with fewer than 50 samples are then
dropped, which leaves 891 samples in four: dairy 447, fruits_and_vegetables 159,
fermented_meat 154, meat 131. Each of the four occurs in at least five of the datasets.
The eighteen datasets become three folds, and no dataset is split across two of them. Inside each fold TabFlux selects features and tunes TabPFN and the random forest on the two folds it can see, then scores the held-out one. SHAP at the end says which taxa the winning model used.
A demonstration of the machinery, not a result
Four categories over 891 samples settle nothing. Dairy is half the samples and chance level for balanced accuracy is 0.25. The real analysis is the case study: 57 datasets, 3,680 samples, seven categories, five folds, 1 h 37 min. The demo takes 34 min on the same machine, 22 of them SHAP.
When it finishes, out/ holds one HTML report and one run folder per taxonomic level —
one of each here, since the demo runs SGB alone. The run folder's metrics/ holds:
| file | what it answers |
|---|---|
benchmark_metrics.csv |
how each learner did on average |
benchmark_metrics_spread.csv |
how much that average hides |
lodo_metrics.csv |
how each outer fold scored, and which datasets it held out |
per_class_recall_oof.csv |
which categories a learner gets right, and which it misses |
oof_predictions.csv |
every sample's out-of-fold prediction |
shap_importance.csv |
which taxa the winning model used |
lodo_metrics.csv has one row per held-out group: one whole dataset under
outer: lodo, a fold's worth of datasets under outer: cv.
Read the HTML report first; it contains the same numbers with the figures.
Smaller and faster¶
SHAP is the largest single cost; importance.method: none removes it. Copy
config_cfmd_demo.yaml to my_config.yaml in the current folder — from a clone, or out
of the image with
docker run --rm ghcr.io/ilivius/tabflux:1.6.0 cat config_cfmd_demo.yaml > my_config.yaml
— and cut the dataset list to three:
input:
cfmd:
datasets: [AlvarezOrdonezA_xxxx, DeFilippisF_xxxx, SequinoG_2024_b]
That gives 346 samples in three categories (dairy 157, meat 102, fermented_meat 87),
each present in two of the three datasets, so every fold can learn every class it is
scored on. A class that survives the size filter but lives in a single dataset is
reported by the run as untrainable in the fold that holds that dataset out. Setting
evaluation.nested: false on top makes it cheaper again: feature selection and tuning
run once on all the training data instead of inside every fold, which is mildly
optimistic.
Then mount your copy into /work and name it on the command line. It keeps the demo's
output.dir: "/work/out", so the results still land in out/:
mkdir -p out ~/.cache/tabpfn
docker run --rm --gpus all --user "$(id -u):$(id -g)" -e TABPFN_TOKEN \
-v "$HOME/.cache/tabpfn:/work/.cache/tabpfn" -v "$PWD/out:/work/out" \
-v "$PWD/my_config.yaml:/work/my_config.yaml:ro" \
ghcr.io/ilivius/tabflux:1.6.0 Rscript scripts/run_multi_tax_levels.R my_config.yaml
Give every run its own dataset.version
Tuned models are cached per run folder. A second run with the same version reuses them, which is what makes an interrupted run resumable — and what will silently reuse a cheap test if you forget.
Running on your own data¶
Put the three files in input/, edit config.yaml (the template in the repository)
and run it in the container or on a workstation.
Container. Relative paths in the config resolve against /work, so mount input/
and the config there, and set output.dir: "/work/out" in config.yaml. Left empty, the
run stops at once with --user (the image's /work is not writable for you), and
without --user it writes inside the container, where --rm deletes the results:
mkdir -p out ~/.cache/tabpfn
docker run --rm --gpus all --user "$(id -u):$(id -g)" -e TABPFN_TOKEN \
-v "$HOME/.cache/tabpfn:/work/.cache/tabpfn" -v "$PWD/out:/work/out" \
-v "$PWD/input:/work/input:ro" -v "$PWD/config.yaml:/work/config.yaml:ro" \
ghcr.io/ilivius/tabflux:1.6.0 Rscript scripts/run_multi_tax_levels.R config.yaml
Reports, run folders and the stacked tables land in out/.
Workstation (the conda route of installation; input.* can then
point anywhere):
| how | command | output |
|---|---|---|
| every level | Rscript scripts/run_multi_tax_levels.R |
one tabflux_<version>_<level>.html report per level and its run folder in output.dir (the project root when empty), plus the stacked *_multi_tax_results/ |
| one level | quarto render analysis/tabflux.qmd (with tax_level set to a single string) |
analysis/tabflux.html and the run folder |
| interactive | open analysis/tabflux.qmd in RStudio, RStudio Server, Positron or VS Code with the tabflux-r environment and run the chunks (chunk by chunk) |
in-session objects and the run folder |
To run the chunks inside the container instead, with the image's R and packages, open the repository in VS Code's dev container: chunk by chunk.
What the files must look like and which settings matter: your own data.