# `waypoint` CLI reference Targets `waypoint-bio` 1.0.2 (PyPI) / 1.0.4 (GitHub main, commit `f45eee6`, 2026-07-16). ``` waypoint {pretrain,benchmark,finetune,embed,prepare-dataset} ... ``` Config paths are resolved first against the working directory, then against the bundled `waypoint_bio/configs/` tree inside the installed wheel. So `--config configs/benchmark.yaml` works from anywhere without cloning the repo. The same fallback applies to the bundled example data (`examples/abundance_matrix.tsv`, `examples/finetune_classification.parquet`, …). --- ## `waypoint prepare-dataset` Converts a sample × taxa abundance matrix into waypoint format. | Flag | Default | Notes | | --- | --- | --- | | `--input` | *required* | `.csv` / `.tsv` abundance matrix. | | `--output` | *required* | `.parquet` recommended; `.csv` supported. | | `--orientation` | `auto` | `auto`, `samples_as_rows`, `taxa_as_rows`. | | `--taxonomy_format` | `full` | `full` for lineage strings; a rank name (`genus`, `species`, …) to prefix bare names. | | `--no_normalize` | off | Skip row-normalisation to relative abundances. | | `--keep_zeros` | off | Keep zero-abundance entries in each sample's lists. | | `--metadata` | none | CSV/TSV/parquet of per-sample metadata, indexed by sample ID, merged in as extra columns. | `auto` treats the file as taxa-as-rows when the first column header is `taxonomy`, `lineage`, `taxon`, `otu`, or `#otu id` (case-insensitive); otherwise samples-as-rows with the first column as the sample ID. `--taxonomy_format genus` prefixes bare column names with `g__`. It disables higher-rank fallback, because a bare name carries no lineage to fall back to — prefer real lineage strings. --- ## `waypoint embed` One fixed-size vector per sample from a pretrained checkpoint. No fine-tuning, no labels needed. | Flag | Default | Notes | | --- | --- | --- | | `--model` | `outpost-bio/Waypoint-6m` | Hub id or local checkpoint directory. | | `--data` | *required* | Waypoint-format `.parquet` / `.csv` / `.tsv`. | | `--output` | *required* | `.parquet`, or `.csv` if the path ends in `.csv`. | | `--pooling` | `last_token` | `last_token`, `mean`, `first_token`, `cls_token`. | | `--batch_size` | `32` | | | `--max_length` | `512` | Truncates after ordering, so the least informative taxa are lost first. | | `--device` | auto | `cuda`, `mps`, or `cpu`; auto-detects in that order. | Output columns are `dim_0 … dim_{H-1}`, indexed by sample ID. Hidden size `H` is 256 (6m), 512 (45m), 768 (170m). **Behaviour worth knowing:** tokens that map to `` are *dropped* before ordering, not encoded. A row with no in-vocabulary taxa still produces an output row, but its sequence is `[BOS][EOS]` and the embedding is meaningless. Run `scripts/vocab_coverage.py` first. Ordering: by descending abundance z-score when `token_std_means.parquet` is present (it ships with every published checkpoint and with `waypoint pretrain` output), otherwise by descending raw relative abundance. --- ## `waypoint finetune` Fine-tunes a checkpoint on your own labelled waypoint-format data. | Flag | Default | Notes | | --- | --- | --- | | `--model` | *required* | Hub id or local checkpoint. | | `--data` | *required* | Waypoint-format file containing `--target`. | | `--output_dir` | *required* | | | `--task_type` | *required* | `classification` or `regression`. | | `--target` | *required* | Target column name. | | `--covariate_column` | none | Categorical column, one-hot encoded and concatenated to the pooled embedding before the head. | | `--config` | task default | Flat YAML; defaults to the bundled classification/regression config. | ### Fine-tuning config keys ```yaml split_column: null # column holding train/validation/test; null = random split val_fraction: 0.1 test_fraction: 0.1 max_length: 512 # must match the checkpoint's pretraining context pooling_strategy: last_token filter_unk_taxa: true # drop out-of-vocabulary taxa rather than feed seed: 42 learning_rate: 0.00003 num_epochs: 1 # raise this; early stopping is what should terminate training batch_size: 64 warmup_steps: 1000 # lower to ~50 for small datasets weight_decay: 0.001 eval_strategy: steps eval_steps: 400 logging_steps: 5 patience: 5 # eval steps without improvement before early stopping save_total_limit: 1 use_lora: false lora_r: 8 lora_alpha: 16 # convention: 2 * r lora_dropout: 0.05 lora_target_modules: [c_attn, c_proj] # GPT-2 fused QKV and output projection lora_bias: none lora_fan_in_fan_out: true # required for GPT-2 Conv1D layouts ``` `num_epochs: 1` in the shipped configs is tuned for the large Compass tasks. On a few-thousand-row dataset one epoch is a handful of optimizer steps and the model barely moves — raise `num_epochs` and let `patience` stop it. Likewise `eval_steps: 400` may never fire; lower it so early stopping and best-checkpoint selection can actually work. LoRA adapters are merged back into the base transformer before saving, so `best_model/` loads with a plain `AutoModel.from_pretrained` and works with `waypoint embed` and `waypoint benchmark`. ### Outputs | Path | Contents | | --- | --- | | `best_model/` | Fine-tuned base transformer in standard HF format, plus tokenizer and `token_std_means.parquet`. | | `best_model/finetuned_model_state.pt` | Full torch state dict: transformer + head + covariate embedding. | | `validation_metrics.json`, `test_metrics.json` | Per-split scores, benchmark-equivalent. | | `training_log.csv`, `training_log.html` | Every row of `trainer.state.log_history`; the HTML is an interactive plotly line plot. | | `finetune_results.json` | Run config, label maps, covariate map, val/test scores. | --- ## `waypoint benchmark` | Flag | Default | Notes | | --- | --- | --- | | `--model` | `outpost-bio/Waypoint-6m` | Hub id or local checkpoint. | | `--config` | bundled `configs/benchmark.yaml` | Shared by all eight tasks. | | `--output_dir` | `outputs/benchmark` | | | `--tasks` | all 8 | Space-separated task numbers, e.g. `--tasks 1 6`. | | `--seed` | `42` | | | `--max_samples` | none | Caps each split; use for smoke tests only, never for a reported score. | `configs/benchmark.yaml` is the fine-tuning config applied identically to every task: `learning_rate: 3e-5`, `num_epochs: 1`, `batch_size: 64`, `warmup_steps: 1000`, `weight_decay: 0.001`, `patience: 5`, `pooling_strategy: last_token`, `eval_steps: 400`, `filter_unk_taxa: true`, `seed: 42`. Change it and your score is no longer comparable to the paper. The paper reports means over three independent runs. A single run is noisy; vary `--seed` and report the spread. --- ## `waypoint pretrain` | Flag | Default | Notes | | --- | --- | --- | | `--model_config` | `configs/models/gpt2-6m.yaml` | Architecture YAML. | | `--pretrain_config` | `configs/pretraining.yaml` | Hyperparameter YAML. | | `--output_dir` | `outputs/pretrain` | Best checkpoint written to `/best_model/`. | | `--max_samples` | none | Limit training samples for a quick test. | | `--data` | none | Local waypoint-format corpus instead of downloading Atlas. | Steps: download the Atlas `pretrain` split → build a taxonomic tokenizer from the corpus → compute per-token abundance mean/std for z-score ordering → train GPT-2 with next-token prediction and early stopping → save `best_model/`. ### `configs/pretraining.yaml` ```yaml training_type: next_token_prediction taxon_rank: genus # tokenization rank; changing it means re-pretraining fallback_to_higher_rank: true # use the most specific higher rank when genus is absent max_length: 512 learning_rate: 0.001 warmup_steps: 1000 weight_decay: 0.001 batch_size: 32 num_epochs: 100 patience: 10 eval_steps: 3261 save_steps: 3261 logging_steps: 100 val_split: 0.1 seed: 42 ``` ### Architectures All share `model_type: gpt2`, `n_positions: 512`, and a fixed per-head dimension of 64. | Config | Layers | Hidden | Heads | ~Params | | --- | --- | --- | --- | --- | | `gpt2-6m.yaml` | 8 | 256 | 4 | 6M | | `gpt2-6m-mgm.yaml` | 8 | 256 | 8 | 6M — matches the MGM baseline architecture | | `gpt2-10m.yaml` | 8 | 320 | 5 | 10M | | `gpt2-18m.yaml` | 10 | 384 | 6 | 18M | | `gpt2-29m.yaml` | 12 | 448 | 7 | 29M | | `gpt2-45m.yaml` | 14 | 512 | 8 | 45M | | `gpt2-79m.yaml` | 16 | 640 | 10 | 79M | | `gpt2-85m-gpt-small.yaml` | 12 | 768 | 12 | 85M — GPT-2 small geometry | | `gpt2-170m.yaml` | 24 | 768 | 12 | 170M | Only 6m, 45m, and 170m are published as checkpoints. The rest exist so the paper's scaling study is reproducible; `gpt2-6m-mgm` isolates the effect of head count against the MGM baseline. Parameter counts exclude token and positional embeddings, so the Hub's reported sizes are larger (the 6m checkpoint reports ~10.1M, the 45m ~51.8M). Pretraining Atlas end to end is a multi-GPU-day job. Validate the pipeline with `--max_samples 5000` before committing to a full run.