Capstone 07 — End-to-End Fine-Tuning Pipeline (Data to SFT to DPO to Serve)
An 8B model trained on your data, aligned with DPO on your preferences, quantized, speculative-decoded, and served at a measured $/1M tokens. The 2026 open stack is Axolotl v0.8, TRL 0.15, Unsloth for iteration, GPTQ/AWQ/GGUF for quantization, and vLLM 0.7 with EAGLE-3 for serving. The capstone is running the whole pipeline reproducibly, YAML in and served endpoint out, then publishing a model card under the Model Openness Framework (MOF).
Learning Objectives
- Wire the data, SFT, DPO/GRPO, quantization, and serving stages so each stage's output is the next stage's input, and rerun the whole chain from one command with fixed seeds.
- Build a MinHash contamination gate that rejects any validation split overlapping the MMLU-Pro, MT-Bench-v2, and RewardBench-2 test sets.
- Run the SFT-only vs SFT+DPO vs SFT+GRPO ablation and judge whether preference tuning earned its compute.
- Quantize to GPTQ, AWQ, and GGUF, serve with vLLM and EAGLE-3, and report tokens/s, acceptance rate, and $/1M tokens alongside a safety eval and a 2026 MOF model card.
Problem
A fine-tuning pipeline is the chain of steps that turns a raw corpus and an open base model into a served, evaluated, documented model: data prep, supervised fine-tuning (SFT), preference tuning, quantization, serving, and eval. Most serious AI teams in 2026 keep one on tap. They aren't shipping a frontier base model. The measurable wins sit downstream: domain SFT, DPO against labeled preferences, distilled drafts for speculative decoding, and serving with EAGLE-3.
The tooling is mature. Axolotl v0.8 handles multi-GPU SFT configs, TRL 0.15 handles DPO and GRPO, and Unsloth gives you fast single-GPU iteration. vLLM 0.7 with EAGLE-3 pushes decode throughput 2-3x without quality loss. What's left is craft: the YAMLs, the data hygiene, and the eval discipline.
You will take an 8B base (Llama 3.3, Qwen3, or Gemma 3) through SFT and then DPO on task-specific data, quantize it for serving, and measure the gains against lm-evaluation-harness, RewardBench-2, MT-Bench-v2, and MMLU-Pro. You will also write a model card under the Model Openness Framework (MOF). Reproducibility is the point: one command reruns the whole pipeline.
Concept
The pipeline has five stages, and each one's output is the next one's input.
- Data: dedup (MinHash / Datatrove), a quality filter (Nemotron-CC style classifier), a PII scrub, and a split-hygiene check for contamination from public benchmarks.
- SFT: an Axolotl YAML, ZeRO-3 on 8xH100, a cosine schedule, packed sequences, 2-3 epochs.
- DPO or GRPO: a TRL config, 1 epoch, preference pairs that are either human-labeled or model-judged, and a beta to tune.
- Quantize: GPTQ, AWQ, and GGUF, so you can deploy to whatever runtime the target needs.
- Serve: vLLM 0.7 with EAGLE-3 speculative heads (or SGLang with SpecForge), a K8s deployment, and an HPA on queue-wait.
The ablations are the deliverable: SFT-only vs SFT+DPO vs SFT+GRPO on three task-specific benchmarks. On the serving side, report tokens/s at batch 1 / 8 / 32, the EAGLE-3 acceptance rate, and $/1M tokens. Add a safety eval (Llama Guard 4 pass rate), and a model card covering bias evaluations, reproducibility seeds, and data licensing.
Architecture
raw data (HF datasets + internal)
|
v
Datatrove dedup + Nemotron-CC quality filter + PII scrub
|
v
split hygiene (MMLU-Pro contamination check)
|
v
Axolotl SFT config (YAML) ---> 8xH100, ZeRO-3
|
v
TRL DPO / GRPO config ---> 4xH100, 1 epoch
|
v
GPTQ + AWQ + GGUF quantize
|
v
vLLM 0.7 + EAGLE-3 speculative decoding
|
v
K8s deployment, HPA on queue-wait
|
v
lm-eval-harness + RewardBench-2 + MT-Bench-v2 + MMLU-Pro
|
v
model card (2026 MOF) + safety eval (Llama Guard 4)
Stack
- Data: Datatrove for dedup, Nemotron-CC classifier for quality, Presidio for PII
- Base: Llama 3.3 8B, Qwen3 14B, or Gemma 3 12B
- SFT: Axolotl v0.8 with ZeRO-3, Flash Attention 3, packed sequences
- Preference tuning: TRL 0.15 for DPO or GRPO; Unsloth for single-GPU iteration
- Quantization: GPTQ (Marlin), AWQ, GGUF via llama.cpp
- Serving: vLLM 0.7 with EAGLE-3 speculative decoding (or SGLang 0.4 + SpecForge)
- Eval: lm-evaluation-harness, RewardBench-2, MT-Bench-v2, MMLU-Pro
- Safety eval: Llama Guard 4, ShieldGemma-2
- Infrastructure: Kubernetes + NVIDIA device plugin, HPA on queue-wait metric
- Observability: W&B for training, Langfuse for inference
Build It
-
Data pipeline. Run Datatrove dedup on the raw corpus, apply a Nemotron-CC-style quality classifier, and scrub PII with Presidio. Write train/val splits with an explicit seed.
-
Contamination check. For every validation split, compute MinHash against the MMLU-Pro, MT-Bench-v2, and RewardBench-2 test sets. Reject any overlap.
-
Axolotl SFT. Write a YAML with ZeRO-3, FA3, and sequence packing. Train 2-3 epochs on 8xH100 and log to W&B.
-
TRL DPO / GRPO. Start from the SFT checkpoint and run one epoch of DPO on preference pairs (or GRPO with a verifiable reward on math/code). Sweep beta.
-
Quantize. Produce three quants: GPTQ-INT4-Marlin, AWQ-INT4, and GGUF-Q4_K_M for llama.cpp. Record size and nominal throughput for each.
-
Serve with speculative decoding. Configure vLLM 0.7 with EAGLE-3 draft heads trained via Red Hat Speculators. Measure acceptance rate and tail latency at batch 1 / 8 / 32, then report $/1M tokens against Anthropic / OpenAI on the same eval.
-
Eval matrix. Run lm-eval-harness, RewardBench-2, MT-Bench-v2, and MMLU-Pro on base, SFT-only, SFT+DPO, and SFT+GRPO. Produce a table.
-
Safety eval. Measure the Llama Guard 4 pass rate on the dev set and add a ShieldGemma-2 output filter.
-
Model card. Fill in the MOF template: data, training, eval, safety, license, and a reproducibility section with the YAMLs and commit SHAs.
Use It
main.py in this lesson is a runnable scaffold of the same DAG: each stage is a function that consumes the previous stage's artifact by content hash, and python main.py prints the manifest, eval report, and endpoint summary. The numbers below are what a full run looks like.
$ ./pipeline.sh config/llama3.3-8b-domainX.yaml
[data] 300k raw, 282k deduped, 256k quality-filtered, 255k after PII scrub (seed=7)
[SFT] 3 epochs, 8xH100, 6h12m, val loss 1.42 -> 1.03
[DPO] 1 epoch, beta=0.08, 4xH100, 1h42m
[quant] GPTQ-INT4 4.6 GB, AWQ-INT4 4.8 GB, GGUF-Q4_K_M 5.1 GB
[serve] vLLM 0.7, EAGLE-3 acceptance 0.74, p99 126ms @ bs=8
[eval] MMLU-Pro +3.2, MT-Bench-v2 +0.41, RewardBench-2 +0.08
[card] model-card.md generated under 2026 MOF
Ship It
outputs/skill-finetuning-pipeline.md describes the deliverable. One command runs data through SFT, DPO, quantization, serving, and eval, and emits a model card plus the served endpoint.
| Weight | Criterion | How it is measured |
|---|---|---|
| 25 | Eval delta vs base | Measured gain on target tasks (MMLU-Pro, MT-Bench-v2, task-specific) |
| 20 | Pipeline reproducibility | One command reruns end to end with identical seeds |
| 20 | Data hygiene | Dedup rate, PII scrub coverage, contamination check green |
| 20 | Serving efficiency | tokens/s at bs=1/8/32, EAGLE-3 acceptance rate, $/1M tokens |
| 15 | Model card + safety eval | MOF completeness + Llama Guard 4 pass rate |
| 100 |
I'd build the contamination gate before the trainer. Exercise 4 exists because leaked MMLU-Pro answers make accuracy jump unrealistically, and a number like that looks like a win until someone checks the splits. Data hygiene carries 20 points in the rubric, the same weight as reproducibility and serving, so treat it as a first-class stage and not a cleanup pass.
My bet is that most of your learning comes from the ablation table, not the endpoint. A single SFT+DPO model with a good MMLU-Pro delta can't tell you whether DPO earned its 1h42m on 4xH100. SFT-only next to SFT+DPO next to SFT+GRPO can. And since one SFT run is 6h12m on 8xH100 in the Use It trace, I'd shake out the YAMLs and the eval harness with Unsloth on a single GPU first, so the expensive run isn't also the first time anything is tested.
Exercises
-
Run SFT-only, SFT+DPO, and SFT+GRPO on the same task-specific benchmark. Report which preference method wins and by how much.
-
Swap Llama 3.3 8B for Qwen3 14B. Measure the $/1M tokens at matched quality.
-
Measure the EAGLE-3 acceptance rate on domain data vs generic ShareGPT. Report the delta and what it means for latency budgets.
-
Inject 1% contamination (leak MMLU-Pro answers into the training data) and rerun eval. Watch MMLU-Pro accuracy jump unrealistically, then build a contamination-check CI gate that catches it.
-
Add LoRA SFT as an alternative to full fine-tuning. Measure the quality gap at 10x lower memory.
Key Terms
| Term | What people say | What it actually means |
|---|---|---|
| Axolotl | "SFT trainer" | Unified YAML-driven trainer for SFT, DPO, and distillation |
| TRL | "Preference tuner" | Hugging Face library for DPO, GRPO, PPO on LLMs |
| GRPO | "Group-relative policy optimization" | DeepSeek R1's RL recipe with verifiable rewards |
| EAGLE-3 | "Speculative decoding draft" | Draft heads that predict N tokens ahead; vLLM verifies with target model |
| MOF | "Model Openness Framework" | standard for grading model releases on data, code, license |
| Contamination check | "Split hygiene" | MinHash-based detection of test-set leakage into training |
| Acceptance rate | "EAGLE / MTP metric" | Fraction of drafted tokens the target model accepts |
Further Reading
- Axolotl documentation: the reference SFT / DPO trainer
- TRL documentation: DPO and GRPO reference implementations
- Unsloth: single-GPU iteration reference
- DeepSeek R1 paper (arXiv:2501.12948): GRPO methodology
- vLLM + EAGLE-3 documentation: reference serving stack
- SGLang SpecForge: alternate speculative-decoding trainer
- The Model Openness Framework (arXiv:2403.13784): the LF AI & Data Generative AI Commons paper that defines the open-release grading classes
- lm-evaluation-harness: canonical eval runner
Code
- main.py (python, 202 lines)