The bootstrapper's stack
The idea in one line: Training a small decision model now costs less than lunch. Whether your budget turns into a product depends on which labeller you buy from, which licence you build on, and how many runs you let fail.
Why this matters
Section titled “Why this matters”Fine-tuning a 150M-parameter encoder or a roughly 1B-parameter decoder on 100,000 examples costs under $5 of rented GPU time. Labelling 1 million examples with a short rationale, on the other hand, costs anywhere from $48 (GPT-5-nano in batch) to $6,650 (GPT-6-astra in batch) depending on which model does the labelling: a spread of about 140x (derived from OpenAI, Anthropic and Gemini pricing, read 2026-10-28; the arithmetic is in distill a decision model). And a licence can wipe out a plan entirely: the newest TabPFN and TimesFM weights are non-commercial.
So the order-of-magnitude choices are model shape (a small encoder instead of an LLM), the labeller, and the licence. Which GPU brand or cloud you pick is 10% polish. This lesson gives you the real prices so you can stop worrying about compute and spend your attention where it pays.
What an hour of compute costs
Section titled “What an hour of compute costs”Renting a GPU is like renting a car by the hour. Three choices change the price:
- On-demand means the machine is yours until you stop it.
- Interruptible (also called spot) means a cheaper rental that the host can take back at any moment, so your script must save checkpoints (snapshots of the training state) and resume from them.
- Community or marketplace clouds rent other people’s machines: cheaper, less reliable than “secure” datacentre tiers.
| GPU (memory) | Cheapest on-demand seen | Interruptible | Fits |
|---|---|---|---|
| RTX 4090 (24 GB) | $0.34/h RunPod community ($0.89 secure); Vast median $0.46 | Vast median $0.33 | anything under about 1B parameters |
| RTX 3090 (24 GB) | $0.22/h RunPod community; Vast median $0.20 | Vast median $0.16 | encoders, small LoRA |
| A100 (80 GB) | $1.19/h RunPod PCIe; Vast median $1.12 | Vast median $0.40 | 1-8B decoders |
| H100 (80 GB) | $1.99/h RunPod PCIe, $2.69 SXM | Vast from $0.67 (median $1.20); Together preemptible $1.99 | the cheapest serious accelerator |
| B200 (180 GB) | $5.98/h RunPod community; Modal $6.25 | n/a | rarely worth it for a bootstrapper |
Sources: RunPod pricing (updated 2026-10-08), Vast.ai live offers (queried 2026-10-29 UTC; unvetted hosts, so these are market quotes, not list prices), Together pricing and Modal pricing (both read 2026-10-28).
Worked example (derived). Fully fine-tune ModernBERT-base (150M) on 100,000 examples of 128 tokens for 3 epochs on a 4090.
- The ModernBERT paper measured inference at 147,300 tokens/s on a 4090 (Warner et al., Table 2, 2024-12-18).
- A training step costs roughly 3x an inference pass (a rule of thumb: forward plus a backward pass twice as costly). So about 49,000 tokens/s, or about 380 examples/s.
- 300,000 example-passes ÷ 380 per second ≈ 790 s ≈ 13 minutes, so $0.07-0.19 at $0.34-0.89/h.
Even if the real throughput were 4x worse, a run costs under $2. The cost that matters is running many: 5 base models × 3 seeds × a few learning rates is 30-60 runs, still under $50.
For a 1B decoder, the anchor is Karpathy’s nanochat: a 561M model trained at about 135,000 tokens/s per H100 at about 48% MFU (model FLOPs utilisation, the share of the GPU’s peak arithmetic you actually use) (nanochat d20 walkthrough, 2025-10-13). Scaled by size, a 1B model sees about 75,000 tokens/s, so 100k examples of 226 tokens (22.6M tokens) take about 5 H100-minutes. Real fine-tuning runs are 3-10x less efficient, so expect $1-10 per run (derived).
Free compute, and the credits you can actually get
Section titled “Free compute, and the credits you can actually get”| Free option | What you get | Source |
|---|---|---|
| Kaggle Notebooks | T4/P100-class GPUs, sessions up to 12 h; about 30 GPU-hours a week is commonly reported but not in Kaggle’s docs | GPUPerHour (2026-09-21) |
| Google Colab | Free tier, usually a T4; pay-as-you-go works out to about $0.12/h (T4) and $0.75/h (A100-80GB), one third-party measurement | McCormick (updated 2026-03-10) |
| Modal Starter | $30 of free credit a month, per-second billing | Modal pricing |
| Lightning AI | “Up to 30 free credits (about 80 GPU hours on interruptible machines)” (vendor claim) | Lightning pricing |
| HF ZeroGPU | 5 GPU-minutes a day free, 40 with the $9/month PRO plan, for Gradio Spaces only | GPUPerHour |
Credit programmes sound big, but the six-figure tiers need investors. What a solo, incorporated, unfunded founder can realistically get:
| Programme | Amount | Catch |
|---|---|---|
| AWS Activate Founders | $1,000; “select participants may qualify for up to $5,000” | None for you: “Apply directly if you’re bootstrapped or self-funded” |
| Google for Startups, Start tier | Up to $2,000 for a year | You must be “planning to seek venture funding soon” and under 24 months old |
| Microsoft for Startups | Probably $1,000-5,000 | Official page states no tiers; third-party pages conflict |
| NVIDIA Inception | “Free cloud credits”, no amount stated | Must be incorporated, with a website |
That stacks to roughly $4,000-8,000 if you qualify for all of them. Hyperscaler credits are awkward for GPUs: GCP’s $300 trial “can’t add GPUs”, and hyperscaler H100s cost more than RunPod’s. Spend them on frontier-model labels for evaluation (through Bedrock or Vertex) and on storage.
Your Mac is a training box for small models
Section titled “Your Mac is a training box for small models”MLX is Apple’s array framework for its own chips; mlx-lm is its library for running and fine-tuning language models. Apple Silicon shares one pool of memory between CPU and GPU, which is why a laptop can train models a gaming GPU of the same price can’t hold. On the 48 GB test machine, MLX recommended a GPU working set of 40.2 GB, about 78% of RAM (measured).
Measured with mlx-lm 0.32.2, batch size 8, examples of about 226 tokens (lower bounds, see the note above):
| Run | Trainable parameters | Tokens/s | Peak memory |
|---|---|---|---|
| LoRA rank 8, Qwen3-0.6B (bf16) | 2.9M (0.48%) | 1,371-1,381 | 6.37 GB |
| Full fine-tune, Qwen3-0.6B (top 16 of 28 layers) | 251.7M (42%) | 1,224-1,289 | 6.42 GB |
| QLoRA, Qwen3-4B (4-bit base) | 7.3M (0.18%) | 221-223 | 11.67 GB |
| QLoRA, Qwen3-4B, gradient checkpointing | 7.3M | 187-191 | 4.93 GB |
Worked example. 100,000 examples × 226 tokens = 22.6M tokens per epoch. At 1,380 tokens/s that is about 16,400 s, or 4.6 hours per epoch for LoRA on the 0.6B model. QLoRA on the 4B model takes about 28 hours per epoch. An encoder is faster still: ModernBERT-base fine-tuned in PyTorch on the Mac’s GPU (MPS) ran at 26.1 examples/s in bf16, so about 64 minutes per epoch for 100k examples (measured).
mlx-lm’s own docs give one figure, about 250 tokens/s for LoRA on Mistral-7B on a 32 GB M1 Max (mlx-lm LORA.md, read 2026-10-28). Third-party estimates for 8B on an M4 Max range from 380 to 800 tokens/s and conflict, and there are no official 2026 MLX training benchmarks. What fits, assuming the 78% ratio holds on other Macs (derived):
| Mac RAM | QLoRA | LoRA (bf16) | Full fine-tune |
|---|---|---|---|
| 32 GB | up to about 14B | up to about 8B | about 1B (any encoder) |
| 64 GB | 27-32B | about 14B | about 3B |
| 128 GB | about 70B | 27-32B | about 7B |
For typed decisions, a fully fine-tuned encoder or a 0.6-2B decoder is the right size anyway, so a 32 GB Mac covers the whole course.
Small base models, and the licences that bite
Section titled “Small base models, and the licences that bite”A reminder from transformers in plain words: an encoder reads the whole input at once, in both directions, and outputs vectors, the natural shape for classification and scoring; a decoder writes text left to right but can also score known options in one pass (generating vs deciding).
Permissive picks (commercial use allowed; details from the Hugging Face model API, queried 2026-10-28):
| Kind | Models | Licence |
|---|---|---|
| Encoders | ModernBERT-base/large (150M/396M); Ettin (17M-1B); mmBERT (multilingual, 140M/307M); UltraBERT-150M/380M (2026-10-10, claims single-source) | Apache-2.0; MIT; MIT; Apache-2.0 |
| Small decoders | Qwen3.5 0.8B/2B/4B/9B (Feb 2026); Gemma 4 E2B/E4B/12B (Apr 2026, the first Gemma under Apache); SmolLM3-3B; Phi-4-mini; MiniCPM5-2B; Granite 4.0 | Apache-2.0 (Phi-4-mini: MIT) |
| Context models | TabPFN v2; TabICLv2; Mitra-v2; Kumo-Tabular; TimesFM-2.5; Chronos-2; Toto 2.0 | Apache-2.0 plus attribution; BSD-3; Apache-2.0; OpenMDW-1.1; Apache-2.0 for the rest |
Ettin’s paper shows why encoders are the default: with identical data and recipes, “a 400M encoder outperforms a 1B decoder on MNLI”, a sentence-pair reasoning benchmark (Ettin, 2025-07-15).
The licence traps. Several flagship models of this course can’t be used in a product:
| Model | What the licence says | Effect |
|---|---|---|
| TimesFM-3.0 (330.7M, 2026-08-24) | “TimesFM Non-Commercial License v1.0” (model card) | Research only; Google sells commercial use through BigQuery (timesfm repo). TimesFM-2.5 is Apache-2.0. |
| TabPFN-2.5, 2.6, 3 and 3.5 | “Non-commercial and non-production use” for downloaded weights (TabPFN-3.5 licence, revised 2026-09-09) | Use TabPFN v2 (Apache-2.0 plus attribution) or an Apache/BSD rival. Sources disagree on outputs: the 3.5 licence says outputs are “not considered Derivatives”, while the TabPFN-3 paper describes production or commercial use “including of outputs” as needing an enterprise licence. |
| Qwen3.8 (August 2026) | Qwen Community License 1.0: a “Model as a Service” or “AI Work Assistant” business needs a separate commercial licence (licence text, 2026-08-24) | A Jev-like API is plausibly MaaS. Several open decision models build on Qwen3.8-27B (Decision Index data), so check the base, not just the wrapper. |
| Gemma 1-3 | A model trained by “distillation methods” or on Gemma outputs becomes a “Model Derivative” (Gemma Terms, 2026-04-01) | Your student inherits Gemma’s terms; Gemma 4 has its own Apache licence |
| Llama 3.2 | Distributed models trained on it must start their name with “Llama”; 700M monthly-user clause (licence) | Allowed, with branding duties |
| Liquid LFM2/2.5 | Commercial use restricted at “annual revenue of 10 million United States dollars ($10,000,000) or more” (licence) | Fine until you succeed |
Teacher terms matter as much as weights. Anthropic forbids using its services “to train competing AI models” (Commercial Terms, 2025-06-17), Google forbids models “that compete with the Services” (Gemini API terms, 2026-03-23), and OpenAI’s similar clause has an exception for internal classifiers whose exact wording could only be read from a search snippet. DeepSeek explicitly permits “training other models (such as model distillation)” (DeepSeek ToS, 2026-04-29). The data rights lesson covers the rest; distill a decision model turns this into a labelling plan.
Efficient fine-tuning in plain words
Section titled “Efficient fine-tuning in plain words”Recall from three ways to teach a model that fine-tuning means continuing to train a pre-trained model on your data. You can change every weight or only a few.
- Full fine-tuning updates every weight. With the Adam optimizer it needs roughly 8-16 bytes per parameter plus activations: about 2.4 GB for a 150M encoder at 16 bytes, but 64 GB for a 4B decoder. For encoders it is cheap and the default.
- LoRA freezes the model and trains a small low-rank “patch” added to some weight matrices. Think of sticky notes on a textbook instead of a rewrite. The mechanism: a frozen matrix
WbecomesW + B·A, whereAandBare thin. A 1,024 × 1,024 matrix holds 1,048,576 numbers; a rank-8 patch addsA(8 × 1,024) andB(1,024 × 8), 16,384 trainable numbers, 1.6% of that matrix. The original paper reports “10,000 times” fewer trainable parameters for GPT-3 175B and “no additional inference latency” once merged (Hu et al., 2021-06-17). - QLoRA keeps the frozen base in a 4-bit format (“NF4”) and trains LoRA on top. Its paper fine-tuned a 65B model “on a single 48GB GPU” (Dettmers et al., 2023-05-23). On the Mac, QLoRA put a 4B model in 11.7 GB (measured).
- DoRA splits each weight into a size and a direction and applies LoRA to the direction; its authors claim it beats LoRA consistently (Liu et al., 2024-02-14).
- Gradient checkpointing stores fewer intermediate results and recomputes them during the backward pass. On the Mac it cut peak memory by 58% for about 15% of speed (measured).
- Packing fills each training row with several short examples so no compute goes to padding. Worked example: four examples of 40, 60, 120 and 230 tokens padded to 256 use 1,024 slots for 450 real tokens, 56% waste; packed into one 512-token row, 450 of 512 slots are real, 12% waste. TRL’s
SFTConfig(packing=True, packing_strategy="bfd")does this, and its docs say packing needs FlashAttention, a fast attention kernel (TRL docs, read 2026-10-28). Encoders get the same effect from unpadding: on variable-length input BERT’s throughput halves (180.4k to 90.2k tokens/s) while ModernBERT holds 147.3k against 148.1k (ModernBERT). - bf16 is a 16-bit number format that keeps fp32’s range; it is the standard training precision. fp8 halves the bits again and mainly helps large matrix multiplies on H100 and B200 GPUs. On the Mac, bf16 trained the encoder at 26.1 examples/s against 22.9 in fp32, about 14% faster (measured): honest 10% polish.
| Tool | Status in October 2026 |
|---|---|
| Unsloth | “2× faster with 70% less VRAM” (vendor claim; its per-notebook claims for new small models are smaller, 1.5x and 50-60% less memory). Apache-2.0 core. |
| TRL | Hugging Face’s trainers: packing, padding-free batching, checkpointing on by default |
| Axolotl | YAML-driven full, LoRA and QLoRA training, fp8, multi-GPU; Apache-2.0 |
| mlx-lm | LoRA, DoRA and full fine-tuning on Apple Silicon |
| torchtune | “No longer actively maintained”: don’t start new work on it |
| Together fine-tuning | $0.34 per 1M training tokens for 0.8-9B models, $4 minimum: about $23 for 100k examples × 3 epochs (derived) |
The state of the art. Three things moved in 2026. First, purpose-built decision trainers: Unsloth’s FastDecisionModel scores the options you provide and returns a choice with a probability, and it claims Qwen3.5-0.8B went from 36% to 73% on a typed-decisions benchmark using 4 GB and 42 minutes (Unsloth guide, vendor claim). Second, a frozen backbone plus a small adapter and head can lead: blockbrain’s Cygnet, a frozen Gemma-4-12B with a decision head, tied for first on JevBench 1.5, above Jev (BenchLM), and Cloudflare’s Clef trains a rank-256 LoRA and a routing head on a frozen backbone (remio). Third, pre-training itself got cheap: the GPT-2-small speedrun hit its target in 0.665 minutes on 8 H100s (record dated 2026-08-30, about $0.24-0.35 derived) (modded-nanogpt), and nanochat reaches GPT-2-level quality in 1.65 hours on one 8-GPU node (nanochat). Open problems: Unsloth’s page contradicts itself on LoRA rank (64 vs 16) and learning rate (2e-4 vs 2e-5) and doesn’t name its GPU; no official MLX training benchmarks exist; fp8 speedups for small models are undocumented.
The stack at a glance
Section titled “The stack at a glance”C4 · L1 System context · Your decision-model stack
+-----------------------+ | [Person] | | You, the builder | | one Mac, a budget | +-----------------------+ | | trains, tests, ships v +-----------------------+ | [Software system] | | Your training stack | | scripts, data, evals | +-----------------------+ | | | +----------+ | +-----------+ | | | | rents GPUs | buys labels | downloads v by the hour v in batches v base models+-------------------+ +-------------------+ +-------------------+| [External system] | | [External system] | | [External system] || GPU clouds and | | Teacher LLM APIs | | Model hubs || free notebooks | | (check the terms) | | (check licences) |+-------------------+ +-------------------+ +-------------------+Your stack is mostly your own scripts and data on one Mac; it reaches out to three kinds of outside system, and two of them carry legal terms you must check. New to these boxes? See how to read the diagrams.
The $50, $500 and $5,000 plans
Section titled “The $50, $500 and $5,000 plans”Goal: show in a weekend that a small model can learn your decision.
- Model: ModernBERT-base or Ettin-encoder-150m (English) or mmBERT-small (multilingual), fully fine-tuned with a classification head. Or Unsloth’s free Qwen3.5-0.8B decision notebook on Colab or Kaggle.
- Data: 10,000-20,000 labels. Claude Opus 5.5 batch, label only, costs $8.30 per 10k ($26 with short rationales); Gemini 3.8 Flash batch with rationales costs about $10 for 20k. Add a second labeller on 2,000 items to measure agreement ($1-5), and hand-label 300-500 gold items yourself. For an internal experiment the frontier labs’ terms are workable; for anything you will sell, see the teacher terms above.
- Compute: $0. The Mac (10k examples take about 6 minutes per epoch for an encoder), Kaggle, and Modal’s $30 monthly credit.
- Evaluation: accuracy and ECE (expected calibration error, the gap between stated probabilities and actual hit rates; see calibration) on your gold set, against the teacher and against a zero-shot Haiku-class baseline on the same 500 items (under $1).
- Cash out: about $20-40.
Goal: a model you can put behind an endpoint, in 2-4 weeks.
- Data: 100,000 labels for about $150-300. Primary labeller: DeepSeek flash off-peak with rationales ($17, and its terms permit distillation) or Gemini 3.8 Flash batch ($50, price doubles on 2027-01-01, and Google’s terms restrict competing models). Adjudicate 10,000 disagreements with Opus 5.5 batch plus rationales ($26). Label a 2,000-item production-like test set yourself or with a contractor.
- Models: sweep ModernBERT-base and -large, Ettin 150M and 400M, and UltraBERT-150M, 3 seeds each: 30+ runs of 13-36 minutes on a $0.34/h 4090, under $25.
- Decoder baseline: Qwen3.5-0.8B or 2B and Gemma 4 E2B with Unsloth’s decision trainer, on an H100 PCIe at $1.99/h for about 20 hours ($40), or Together’s fine-tuning API (about $23 per 100k examples × 3 epochs).
- Contingency: $100 for failed runs, re-labelling and preempted spot machines.
- Serving: one CPU worker (about $0.76-3.74 per million decisions at full use; see serving for a fraction of a cent); rent a 4090 only once you have volume.
Goal: a small foundation model of your own, in 2-3 months.
- Data: about 1M labels. Gemini 3.8 Flash batch with rationales is $499 if bought before 2027-01-01; Opus 5.5 batch label-only is $830; 100k Fable 5.1 rationales for the hard tail add $654; renting an open 397B teacher (Qwen3.5-397B on DeepInfra) is $801 per 1M with rationales, governed by its Apache-2.0 licence plus DeepInfra’s own terms.
- Option A, a domain encoder. Continue pre-training a 150-400M encoder on 5-20B domain tokens. Training costs about
6 × parameters × tokensFLOPs: 6 × 150M × 20B ≈ 1.8e19. At nanochat’s measured ~450 TFLOP/s per H100 that is about 11 H100-hours, $30-45 (derived; under $250 even at 5x inefficiency). Then fine-tune on the 1M labels. - Option B, a tabular PFN of your own, because the newest TabPFN weights are non-commercial. A TabICL-scale run is about 1,440 A100-hours, $1,100-2,600 at today’s rents (derived from TabICL). See distill a decision model for the cheaper path.
- Option C, a decoder decision model. Fully fine-tune Qwen3.5-2B on 1M examples (about 226M tokens × 2 epochs): about 4 H100-hours at nanochat efficiency, $25-150 allowing 3-10x inefficiency (derived).
- Evaluation: a 5,000-item gold set, calibration, drift sets and a latency target; $500-1,000 if you pay annotators.
- Reserve 30-50% for failed runs.
Check yourself
Section titled “Check yourself”Why is a $0.34-an-hour RTX 4090 enough for most decision models?
Because they are small. A full fine-tune of a 150M encoder on 100,000 examples × 3 epochs takes about 13 minutes (derived from ModernBERT’s measured 147,300 tokens/s), so $0.07-0.19 a run. Even 60 runs of a sweep cost under $50. Big accelerators like the B200 only pay off for jobs large enough to use their extra memory and fp8 arithmetic.
You want to sell an API built on TabPFN-3.5. What’s the problem, and what are your alternatives?
TabPFN-2.5 onward ship weights for “non-commercial and non-production use” only. Commercially usable alternatives include TabPFN v2 (Apache-2.0 plus attribution), TabICLv2 (BSD-3), Mitra-v2 (Apache-2.0) and Kumo-Tabular (OpenMDW-1.1), or training your own PFN.
A rank-8 LoRA on a 2,048 × 2,048 weight matrix: how many numbers do you train, against a full update?
A is 8 × 2,048 and B is 2,048 × 8, so 2 × 16,384 = 32,768 trainable numbers. The full matrix has 4,194,304, so LoRA trains about 0.8% of it.
Your QLoRA run on a 32 GB Mac runs out of memory. Name three levers.
Turn on --grad-checkpoint (cut peak memory by 58% for about 15% of speed in the measured run), lower --batch-size, train fewer layers with --num-layers (default 16), or shorten your sequences. All four are documented in mlx-lm’s LORA.md.
Why spend hyperscaler credits on labels rather than GPUs?
Hyperscaler GPUs cost more per hour than RunPod’s, and GCP’s $300 trial can’t add GPUs at all. The credits do buy frontier-model calls through Bedrock or Vertex, which are most valuable for building and checking your gold and evaluation sets.
Go deeper
Section titled “Go deeper”- Hu et al., LoRA — the original low-rank adaptation paper; short and readable.
- Dettmers et al., QLoRA — how 4-bit bases make big fine-tunes fit one GPU, with the authors’ own caveats about their benchmark.
- mlx-lm LORA.md — every flag you need to fine-tune on a Mac.
- Warner et al., ModernBERT — the encoder most of these plans start from, with throughput tables.
- Weller et al., Ettin — paired encoders and decoders at every size: the cleanest evidence for “start with an encoder”.
- Unsloth, Train your own decision model — the shortest path to a Jev-like model, read with its vendor-claim caveats.