finetuning-method-selection
Decide whether to fine-tune at all, and route to the right method (SFT, DPO/ORPO/KTO, GRPO/RLVR, continued pretraining) and base model. Use when starting any fine-tuning effort, when unsure whether RAG or prompting would suffice, or when choosing between preference-optimization a
Install
npx skills add https://github.com/wshobson/agents/tree/main/plugins/llm-finetuning/skills/finetuning-method-selection
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install wshobson-agents@llmmart
git clone https://github.com/wshobson/agents.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole wshobson/agents collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
Fine-Tuning Method Selection
This is the router skill for the fine-tuning
lifecycle: it decides whether fine-tuning is the
right tool at all, and if so, which method and
which base-model size class. Every other skill
in this plugin assumes this routing already
happened — start here before opening
lora-qlora-recipes, preference-optimization,
or grpo-rlvr-training.
When to Use This Skill
- Starting any fine-tuning effort, before a framework or base model has been chosen.
- Unsure whether RAG or prompt engineering would solve the problem more cheaply than training.
- Choosing between preference optimization (DPO family) and a reinforcement method (GRPO/RLVR) for the same underlying task.
- Sizing a candidate model/method combination before committing to a run.
Quick Reference
| Situation | Route |
|---|---|
| Facts change often (prices, docs, news) | RAG, not fine-tuning |
| Desired behavior still being figured out | Prompt engineering |
| Stable domain knowledge, ≥500MB text | CPT then SFT — see Off-Ramps First |
| Have input/output demonstrations | SFT — see lora-qlora-recipes |
| Have preference pairs or thumbs-up/down | DPO/ORPO/KTO — see preference-optimization |
| Have a verifiable pass/fail signal | GRPO+RLVR — see grpo-rlvr-training |
| No eval harness yet | Stop — see eval-harness-first |
Off-Ramps First
Most requests that sound like "fine-tune this" are served better and cheaper elsewhere. Check these off-ramps before opening a training run:
- Knowledge-bound and volatile (the gap is facts that change — prices, docs, current events): route to RAG, not fine-tuning. A fine-tuned model bakes in a snapshot; volatile facts go stale immediately.
- Behavior-bound and shifting (the desired behavior is still being figured out, or changes per request): route to prompt engineering. Fine-tuning locks in a behavior; don't lock in one that hasn't stabilized yet.
- Stable, dense domain knowledge: this is where continued pretraining (CPT) enters, sized by how much domain text exists:
| Domain text volume | Route |
|---|---|
| <10MB | RAG only |
| 10MB–500MB | RAG + fine-tune |
| 500MB–10GB | CPT, then SFT |
| >10GB | CPT required |
CPT learning rate ≈ 10% of the pretraining LR. CPT is guidance-only in this plugin — sizing and LR guidance live here, but this plugin does not execute a CPT run.
Method Router
Once the off-ramps are ruled out, this is the full decision tree (verbatim from the research this plugin is built on):
New FACTS? volatile → RAG | stable+dense → CPT (LR ~10% of pretrain) → SFT
New BEHAVIOR? shifting → prompt-engineering | stable:
demos → SFT (LoRA/QLoRA, all-linear, α=2r)
preference pairs → DPO (SimPO if length-bias, ORPO if memory-bound)
unpaired 👍/👎 → KTO
verifiable success → RLVR + GRPO (DAPO/GSPO/Dr.GRPO per failure mode)
Deploy: FP8 (Hopper+) | NVFP4 (Blackwell scale) | AWQ (older) | GGUF+imatrix (edge)
BEFORE ANY OF THIS: the eval harness must exist first.
Read the tree top-down: answer "new facts or new behavior," then follow the branch that matches the data shape in hand (demos, preference pairs, thumbs up/down, or verifiable success/failure). The data shape picks the method — not the other way around.
Worked Routing Examples
- "Users want the assistant to follow our support macros exactly." Behavior is stable and demonstrable from transcripts → demos → SFT.
- "We have pairs of good/bad responses from reviewer thumbs-up/down, unpaired." → unpaired signal → KTO, not DPO (DPO needs paired preferences).
- "The model can already solve some of these math problems and we can grade correctness automatically." → verifiable success signal → GRPO+RLVR, and only after confirming the model succeeds at least sometimes (see Key Routing Facts below).
- "We want the model to know this week's pricing page." → volatile facts → RAG, no training run at all.
Key Routing Facts
- Loss-function choice is low-leverage. A 240-H100-run study found method choice worth ~1 percentage point versus ~50 points for model scale, and zero of 20 DPO variants beat vanilla DPO. Don't spend a routing decision agonizing over DPO-variant selection — spend it on getting the data shape and scale right.
- DPO is for taste, GRPO+RLVR is for reasoning. Preference pairs that encode a subjective judgment (tone, style, "which answer is better") route to DPO. Tasks with a verifiable pass/fail signal (math, code, tool calls) route to GRPO+RLVR instead.
- RL is not the fix for a model that never succeeds. GRPO and other RL methods sharpen an existing capability — they don't teach one from zero. If the model doesn't yet understand the task or output format, run SFT first; only bring in RL once the model succeeds at least sometimes.
Common Routing Mistakes
- Reaching for fine-tuning to fix facts that change weekly — that's a RAG problem, and fine-tuning will just go stale faster than the source data does.
- Picking a DPO variant before checking whether the actual bottleneck is data quality or model scale — variant choice is the ~1pp lever, not the ~50pp one.
- Starting an RL run on a model that fails every rollout — route to SFT first so RL has something to sharpen.
- Treating CPT as the default for "the model doesn't know our domain" — check the data volume thresholds first; under 500MB, RAG or RAG+fine-tune iterates faster than a CPT run.
Model Selection
Base-model choice is size-class first, family
second, and it goes stale fast — so it lives in
exactly one place: references/model-catalog.md.
That file is the only place in this plugin (and
in the DGX Spark ops plugin) that names a base
model family. Neither this skill nor
references/memory-math.md names one; both
describe models by size class only (for example,
"8B-class LoRA," not a model name).
The catalog is dated on purpose — model rankings turn over quarterly. It carries a "last verified" date and a refresh checklist. Before trusting a row, check that date; if stale, work the refresh checklist in the catalog before recommending a model from it.
Precedence when the catalog and a method skill
disagree: the catalog's per-row Notes column
states hardware/size-class feasibility, not a
method recommendation — lora-qlora-recipes's
LoRA vs QLoRA vs Full FT table (routed by task
shape) governs the actual method choice.
Memory Feasibility
Before committing to a method, size it: total
memory ≈ params × dtype bytes + optimizer
state + gradients + activations. Work each
term for the chosen dtype and method (full
fine-tune, LoRA, or QLoRA) — worked worksheets
and size-class examples live in
references/memory-math.md.
On DGX Spark specifically, unified-memory
behavior breaks the naive estimate (transient
load peaks, nvidia-smi underreporting, thermal
throttling on long runs). Once the
dgx-spark-ops plugin is installed, defer
Spark-specific feasibility calls to its
spark-memory-thermal-ops skill rather than
re-deriving them here.
Related Skills
Once this skill has picked a method, hand off to the skill that executes it:
lora-qlora-recipes— SFT via LoRA/QLoRApreference-optimization— DPO, ORPO, KTOgrpo-rlvr-training— GRPO with verifiable rewards
No method is selected before the eval harness
exists — see eval-harness-first.
Files (agents)
-
references
-
memory-math.md 5.3 KB
Last verified: 2026-07-13 — refresh when a new size-class anchor is validated or optimizer/dtype defaults change. # Memory Math A worksheet for estimating whether a model size-class, method, and batch/pack combination fits available memory before a run. This is planning math, not a guarantee — leave headroom rather than sizing to the byte. Base models are never named here; every example is labeled by size class only (for example, "8B-class LoRA bf16"). See `model-catalog.md` for which actual model to use at a given size class. ## The Four Terms Total footprint ≈ **weights + optimizer states + gradients + activations**, plus a near-zero term for LoRA/QLoRA adapters. Work each term from parameter count and dtype, then sum. ### 1. Weights `params × bytes/param`, by dtype: | dtype | bytes/param | |---|---| | fp32 | 4 | | bf16 / fp16 | 2 | | int8 | 1 | | int4 (QLoRA NF4) | 0.5 | This term dominates for full fine-tuning, and the calculation (`params × bytes/param`) is the same formula regardless of method — but the dtype, and so the result, is not: bf16 LoRA loads weights at 2 bytes/param while int4 QLoRA loads the same parameter count at 0.5 bytes/param, a 4x gap. Reuse the formula across methods; never reuse the resulting weight-memory number from one method's dtype for another's. ### 2. Optimizer states Full fine-tuning carries optimizer state for every trainable parameter; LoRA and QLoRA carry it only for the adapter parameters, which is why this term is negligible for them regardless of base model size. | Optimizer | bytes/param (trainable only) | |---|---| | AdamW, fp32 states | 8 (4B momentum + 4B variance) | | AdamW 8-bit | ≈2 (quantized momentum + variance) | 8-bit AdamW roughly quarters this term versus the fp32 variant for any run that isn't LoRA/QLoRA- adapter-only, where it's already negligible. ### 3. Gradients Same dtype as compute precision — typically bf16, so 2 bytes/param — and, like optimizer state, only for trainable parameters. Full fine-tuning pays this for every weight; LoRA and QLoRA pay it only for the adapter, since frozen base weights never accumulate a gradient. ### 4. Activations The hardest term to pin to a single number — it scales with batch size, sequence/packing length, and architecture, not just parameter count. Two levers matter more than exact estimation: - **Gradient checkpointing** trades recompute for memory: expect roughly **30% savings** on this term versus no checkpointing, at the cost of a recompute pass per checkpointed segment. - Packing/sequence length is a more direct lever than batch size for this term. ### 5. LoRA/QLoRA adapter overhead A rank-`r` adapter on a linear layer adds `r × (in + out)` parameters — `A` is `r×in` and `B` is `out×r`, so together they contribute `r·in + r·out`. At normal rank sizes (1–32 for RL, up to ~256 for SFT-at-scale), this is a small fraction of a percent of base model size — round it to zero in the worksheet unless an unusually high rank is in play. ## Worked Examples ### 8B-class LoRA, bf16 Weights dominate; optimizer state and gradients are adapter-only and small. ```python params = 8e9 weights_gb = params * 2 / 1e9 # bf16, step 1 adapter_gb = 0.2 # step 5, negligible total_gb = weights_gb + adapter_gb # + activations print(f"{total_gb:.0f}GB before activations") ``` Weights alone land around 16GB — the reference point for "an 8B-class model fits comfortably on a single high-memory GPU in bf16 LoRA." ### 8B-class QLoRA Same parameter count, quantized weights: ```python params = 8e9 weights_gb = params * 0.5 / 1e9 # int4 NF4, step 1 adapter_gb = 0.2 # step 5, negligible total_gb = weights_gb + adapter_gb # + activations print(f"{total_gb:.0f}GB before activations") ``` Weights land around 4GB — roughly a 4x reduction versus bf16 LoRA, which is why QLoRA is the method that buys headroom for larger batch size or longer packing at the same size class, not just a way to fit bigger models. ### 70B-class QLoRA (≈40GB anchor) ```python params = 70e9 weights_gb = params * 0.5 / 1e9 # int4 NF4, step 1 adapter_gb = 0.5 # step 5, negligible total_gb = weights_gb + adapter_gb # + activations print(f"{total_gb:.0f}GB before activations") ``` The idealized formula lands weights at **≈35GB** (decimal GB, weights only); treat **≈40GB** as the real-world anchor once quantization metadata (NF4 double-quant constants) and runtime overhead are included — the reference point for "a 70B-class model is reachable via QLoRA, not bf16," where bf16 weights alone (≈140GB) would already exceed most single-device budgets before optimizer state, gradients, or activations are added. A plan estimating far above the ≈40GB anchor for the same size class is a signal to recheck dtype and method, not just add headroom. ## Using These Numbers 1. Pick the size class and method from `model-catalog.md`. 2. Sum weights + optimizer + gradients from the tables above for that combination. 3. Add activations, applying the ~30% gradient- checkpointing saving if it's enabled. 4. Compare against the closest worked example or anchor above rather than trusting the estimate in isolation — a plan far off an anchor for the same size class and method is a signal to recheck inputs before assuming the hardware won't work. -
model-catalog.md 2.7 KB
# Model Catalog Last verified: 2026-07-14 Refresh checklist: (1) check Unsloth supported-models page, (2) check the current open-weights leaderboards for each size class, (3) update rows + bump this date. Refresh at least quarterly; this file is the ONLY place base models are named in the llm-finetuning and dgx-spark-ops plugins. ## How to Read This Table Pick the row matching the target parameter count, then read across: a text recommendation, a vision (VLM) recommendation for the same size class, what that class can do on a single DGX Spark, and any notes that change the recommendation. Cross-check the "last verified" date above before trusting a row — if it's stale, work the refresh checklist first. ## Catalog (2026-07) | Size class | Text recommendation | Vision recommendation | Spark feasibility | Notes | |---|---|---|---|---| | ≤4B | Qwen3 4B class | SmolVLM / Gemma 3 4B | Full fine-tune feasible | Smallest class where full FT is still *feasible* by default — a hardware/size-class note, not a method recommendation. Method choice (LoRA vs. full FT) is `lora-qlora-recipes`'s LoRA vs QLoRA vs Full FT table, routed by task shape (demonstrations vs. dense knowledge injection); that table governs over this feasibility note whenever the two appear to disagree. | | 7–9B | Qwen3 8B, Llama-class 8B | Qwen2.5-VL-7B | Full fine-tune ceiling | Above this class, full FT stops being the default on Spark — see 12–32B row. | | 12–32B | Qwen3 14B/32B, Gemma 3 27B | Qwen2.5-VL-32B | LoRA-only; 27B is the LoRA ceiling at pack≤1024 | 27B is the largest dense model that fits a LoRA run on a single Spark in practice. | | 70B+ | Llama 3.3 70B class | Use the 12–32B vision class instead — no 70B+ VLM recommendation at this size | QLoRA-only, ≈40GB, 30–48h for 3 epochs | bf16 is not feasible at this class on a single Spark; QLoRA is the only path in. | | 100B+ MoE | gpt-oss-120b class | Use the 12–32B vision class instead — no 100B+ MoE VLM recommendation at this size | NVFP4-native LoRA via community recipe (`nvfp4-lora-spark`), experimental | Not the default assumption for other 100B+ MoE models — verify per-model before relying on this row. | ## Vision Model Notes - **LLaVA is legacy.** Do not recommend it for new work; it is listed here only so a stale recommendation can be recognized as such. - **InternVL3.5 MoE variants are the MoE VLM alternative** to the dense Qwen2.5-VL / Qwen3-VL and Gemma 3 vision models above, for cases that specifically call for a mixture-of-experts vision-language architecture — InternVL3.5 also ships dense checkpoints, so pick the MoE variant explicitly rather than assuming every InternVL3.5 release is MoE.
-
-
SKILL.md 7.7 KB
--- name: finetuning-method-selection description: Decide whether to fine-tune at all, and route to the right method (SFT, DPO/ORPO/KTO, GRPO/RLVR, continued pretraining) and base model. Use when starting any fine-tuning effort, when unsure whether RAG or prompting would suffice, or when choosing between preference-optimization and reinforcement methods. --- # Fine-Tuning Method Selection This is the router skill for the fine-tuning lifecycle: it decides whether fine-tuning is the right tool at all, and if so, which method and which base-model size class. Every other skill in this plugin assumes this routing already happened — start here before opening `lora-qlora-recipes`, `preference-optimization`, or `grpo-rlvr-training`. ## When to Use This Skill - Starting any fine-tuning effort, before a framework or base model has been chosen. - Unsure whether RAG or prompt engineering would solve the problem more cheaply than training. - Choosing between preference optimization (DPO family) and a reinforcement method (GRPO/RLVR) for the same underlying task. - Sizing a candidate model/method combination before committing to a run. ## Quick Reference | Situation | Route | |---|---| | Facts change often (prices, docs, news) | RAG, not fine-tuning | | Desired behavior still being figured out | Prompt engineering | | Stable domain knowledge, ≥500MB text | CPT then SFT — see Off-Ramps First | | Have input/output demonstrations | SFT — see `lora-qlora-recipes` | | Have preference pairs or thumbs-up/down | DPO/ORPO/KTO — see `preference-optimization` | | Have a verifiable pass/fail signal | GRPO+RLVR — see `grpo-rlvr-training` | | No eval harness yet | Stop — see `eval-harness-first` | ## Off-Ramps First Most requests that sound like "fine-tune this" are served better and cheaper elsewhere. Check these off-ramps before opening a training run: - **Knowledge-bound and volatile** (the gap is facts that change — prices, docs, current events): route to RAG, not fine-tuning. A fine-tuned model bakes in a snapshot; volatile facts go stale immediately. - **Behavior-bound and shifting** (the desired behavior is still being figured out, or changes per request): route to prompt engineering. Fine-tuning locks in a behavior; don't lock in one that hasn't stabilized yet. - **Stable, dense domain knowledge**: this is where continued pretraining (CPT) enters, sized by how much domain text exists: | Domain text volume | Route | |---|---| | <10MB | RAG only | | 10MB–500MB | RAG + fine-tune | | 500MB–10GB | CPT, then SFT | | >10GB | CPT required | CPT learning rate ≈ **10% of the pretraining LR**. CPT is guidance-only in this plugin — sizing and LR guidance live here, but this plugin does not execute a CPT run. ## Method Router Once the off-ramps are ruled out, this is the full decision tree (verbatim from the research this plugin is built on): ``` New FACTS? volatile → RAG | stable+dense → CPT (LR ~10% of pretrain) → SFT New BEHAVIOR? shifting → prompt-engineering | stable: demos → SFT (LoRA/QLoRA, all-linear, α=2r) preference pairs → DPO (SimPO if length-bias, ORPO if memory-bound) unpaired 👍/👎 → KTO verifiable success → RLVR + GRPO (DAPO/GSPO/Dr.GRPO per failure mode) Deploy: FP8 (Hopper+) | NVFP4 (Blackwell scale) | AWQ (older) | GGUF+imatrix (edge) BEFORE ANY OF THIS: the eval harness must exist first. ``` Read the tree top-down: answer "new facts or new behavior," then follow the branch that matches the data shape in hand (demos, preference pairs, thumbs up/down, or verifiable success/failure). The data shape picks the method — not the other way around. ### Worked Routing Examples - *"Users want the assistant to follow our support macros exactly."* Behavior is stable and demonstrable from transcripts → demos → **SFT**. - *"We have pairs of good/bad responses from reviewer thumbs-up/down, unpaired."* → unpaired signal → **KTO**, not DPO (DPO needs paired preferences). - *"The model can already solve some of these math problems and we can grade correctness automatically."* → verifiable success signal → **GRPO+RLVR**, and only after confirming the model succeeds at least sometimes (see Key Routing Facts below). - *"We want the model to know this week's pricing page."* → volatile facts → **RAG**, no training run at all. ## Key Routing Facts - **Loss-function choice is low-leverage.** A 240-H100-run study found method choice worth ~1 percentage point versus ~50 points for model scale, and zero of 20 DPO variants beat vanilla DPO. Don't spend a routing decision agonizing over DPO-variant selection — spend it on getting the data shape and scale right. - **DPO is for taste, GRPO+RLVR is for reasoning.** Preference pairs that encode a subjective judgment (tone, style, "which answer is better") route to DPO. Tasks with a verifiable pass/fail signal (math, code, tool calls) route to GRPO+RLVR instead. - **RL is not the fix for a model that never succeeds.** GRPO and other RL methods sharpen an existing capability — they don't teach one from zero. If the model doesn't yet understand the task or output format, run SFT first; only bring in RL once the model succeeds at least sometimes. ### Common Routing Mistakes - Reaching for fine-tuning to fix facts that change weekly — that's a RAG problem, and fine-tuning will just go stale faster than the source data does. - Picking a DPO variant before checking whether the actual bottleneck is data quality or model scale — variant choice is the ~1pp lever, not the ~50pp one. - Starting an RL run on a model that fails every rollout — route to SFT first so RL has something to sharpen. - Treating CPT as the default for "the model doesn't know our domain" — check the data volume thresholds first; under 500MB, RAG or RAG+fine-tune iterates faster than a CPT run. ## Model Selection Base-model choice is size-class first, family second, and it goes stale fast — so it lives in exactly one place: `references/model-catalog.md`. That file is the only place in this plugin (and in the DGX Spark ops plugin) that names a base model family. Neither this skill nor `references/memory-math.md` names one; both describe models by size class only (for example, "8B-class LoRA," not a model name). The catalog is dated on purpose — model rankings turn over quarterly. It carries a "last verified" date and a refresh checklist. Before trusting a row, check that date; if stale, work the refresh checklist in the catalog before recommending a model from it. **Precedence when the catalog and a method skill disagree:** the catalog's per-row Notes column states hardware/size-class *feasibility*, not a method recommendation — `lora-qlora-recipes`'s LoRA vs QLoRA vs Full FT table (routed by task shape) governs the actual method choice. ## Memory Feasibility Before committing to a method, size it: total memory ≈ **params × dtype bytes + optimizer state + gradients + activations**. Work each term for the chosen dtype and method (full fine-tune, LoRA, or QLoRA) — worked worksheets and size-class examples live in `references/memory-math.md`. On DGX Spark specifically, unified-memory behavior breaks the naive estimate (transient load peaks, `nvidia-smi` underreporting, thermal throttling on long runs). Once the `dgx-spark-ops` plugin is installed, defer Spark-specific feasibility calls to its `spark-memory-thermal-ops` skill rather than re-deriving them here. ## Related Skills Once this skill has picked a method, hand off to the skill that executes it: - `lora-qlora-recipes` — SFT via LoRA/QLoRA - `preference-optimization` — DPO, ORPO, KTO - `grpo-rlvr-training` — GRPO with verifiable rewards No method is selected before the eval harness exists — see `eval-harness-first`.
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.