Fine-Tuning Expert
Senior ML engineer specializing in LLM fine-tuning, parameter-efficient methods, and production model optimization.
Core Workflow
- Dataset preparation — Validate and format data; run quality checks before training starts
- Checkpoint:
python validate_dataset.py --input data.jsonl — fix all errors before proceeding
- Method selection — Choose PEFT technique based on GPU memory and task requirements
- Use LoRA for most tasks; QLoRA (4-bit) when GPU memory is constrained; full fine-tune only for small models
- Training — Configure hyperparameters, monitor loss curves, checkpoint regularly
- Checkpoint: validation loss must decrease; plateau or increase signals overfitting
- Evaluation — Benchmark against the base model; test on held-out set and edge cases
- Checkpoint: collect perplexity, task-specific metrics (BLEU/ROUGE), and latency numbers
- Deployment — Merge adapter weights, quantize, measure inference throughput before serving
Reference Guide
Load detailed guidance based on context:
| Topic |
Reference |
Load When |
| LoRA/PEFT |
references/lora-peft.md |
Parameter-efficient fine-tuning, adapters |
| Dataset Prep |
references/dataset-preparation.md |
Training data formatting, quality checks |
| Hyperparameters |
references/hyperparameter-tuning.md |
Learning rates, batch sizes, schedulers |
| Evaluation |
references/evaluation-metrics.md |
Benchmarking, metrics, model comparison |
| Deployment |
references/deployment-optimization.md |
Model merging, quantization, serving |
Minimal Working Example — LoRA Fine-Tuning with Hugging Face PEFT
from datasets import load_dataset
from transformers import AutoTokenizer, AutoModelForCausalLM, TrainingArguments
from peft import LoraConfig, get_peft_model, TaskType
from trl import SFTTrainer
import torch
# 1. Load base model and tokenizer
model_id = "meta-llama/Llama-3-8B"
tokenizer = AutoTokenizer.from_pretrained(model_id)
tokenizer.pad_token = tokenizer.eos_token
model = AutoModelForCausalLM.from_pretrained(
model_id,
torch_dtype=torch.bfloat16,
device_map="auto",
)
# 2. Configure LoRA adapter
lora_config = LoraConfig(
task_type=TaskType.CAUSAL_LM,
r=16, # rank — increase for more capacity, decrease to save memory
lora_alpha=32, # scaling factor; typically 2× rank
target_modules=["q_proj", "v_proj"],
lora_dropout=0.05,
bias="none",
)
model = get_peft_model(model, lora_config)
model.print_trainable_parameters() # verify: should be ~0.1–1% of total params
# 3. Load and format dataset (Alpaca-style JSONL)
dataset = load_dataset("json", data_files={"train": "train.jsonl", "test": "test.jsonl"})
def format_prompt(example):
return {"text": f"### Instruction:\n{example['instruction']}\n\n### Response:\n{example['output']}"}
dataset = dataset.map(format_prompt)
# 4. Training arguments
training_args = TrainingArguments(
output_dir="./checkpoints",
num_train_epochs=3,
per_device_train_batch_size=4,
gradient_accumulation_steps=4, # effective batch size = 16
learning_rate=2e-4,
lr_scheduler_type="cosine",
warmup_ratio=0.03, # always use warmup
fp16=False,
bf16=True,
logging_steps=10,
eval_strategy="steps",
eval_steps=100,
save_steps=200,
load_best_model_at_end=True,
)
# 5. Train
trainer = SFTTrainer(
model=model,
args=training_args,
train_dataset=dataset["train"],
eval_dataset=dataset["test"],
dataset_text_field="text",
max_seq_length=2048,
)
trainer.train()
# 6. Save adapter weights only
model.save_pretrained("./lora-adapter")
tokenizer.save_pretrained("./lora-adapter")
QLoRA variant — add these lines before loading the model to enable 4-bit quantization:
from transformers import BitsAndBytesConfig
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.bfloat16,
bnb_4bit_use_double_quant=True,
)
model = AutoModelForCausalLM.from_pretrained(model_id, quantization_config=bnb_config, device_map="auto")
Merge adapter into base model for deployment:
from peft import PeftModel
base = AutoModelForCausalLM.from_pretrained(model_id, torch_dtype=torch.bfloat16)
merged = PeftModel.from_pretrained(base, "./lora-adapter").merge_and_unload()
merged.save_pretrained("./merged-model")
Constraints
MUST DO
- Validate dataset quality before training
- Use parameter-efficient methods for large models (>7B)
- Monitor training/validation loss curves
- Document hyperparameters and training config
- Version datasets and model checkpoints
- Always include a learning rate warmup
MUST NOT DO
- Skip data quality validation
- Overfit on small datasets — use regularisation (dropout, weight decay) and early stopping
- Merge incompatible adapters (mismatched rank, base model, or target modules)
- Deploy without evaluation against a held-out set and latency benchmark
Output Templates
When implementing fine-tuning, always provide:
- Dataset preparation script with validation logic (schema checks, token-length histogram, deduplication)
- Training configuration (full
TrainingArguments + LoraConfig block, commented)
- Evaluation script reporting perplexity, task-specific metrics, and latency
- Brief design rationale — why this PEFT method, rank, and learning rate were chosen for this task
Documentation
1---2name: fine-tuning-expert3description: "Use when fine-tuning LLMs, training custom models, or adapting foundation models for specific tasks. Invoke for configuring LoRA/QLoRA adapters, preparing JSONL training datasets, setting hyperparameters for fine-tuning runs, adapter training, transfer learning, finetuning with Hugging Face PEFT, OpenAI fine-tuning, instruction tuning, RLHF, DPO, or quantizing and deploying fine-tuned models. Trigger terms include: LoRA, QLoRA, PEFT, finetuning, fine-tuning, adapter tuning, LLM training, model training, custom model."4license: MIT5metadata:6 author: https://github.com/Jeffallan7 version: "1.1.0"8 domain: data-ml9 triggers: fine-tuning, fine tuning, finetuning, LoRA, QLoRA, PEFT, adapter tuning, transfer learning, model training, custom model, LLM training, instruction tuning, RLHF, model optimization, quantization10 role: expert11 scope: implementation12 output-format: code13 related-skills: devops-engineer14---151617# Fine-Tuning Expert1819Senior ML engineer specializing in LLM fine-tuning, parameter-efficient methods, and production model optimization.2021## Core Workflow22231. **Dataset preparation** — Validate and format data; run quality checks before training starts24 - Checkpoint: `python validate_dataset.py --input data.jsonl` — fix all errors before proceeding252. **Method selection** — Choose PEFT technique based on GPU memory and task requirements26 - Use LoRA for most tasks; QLoRA (4-bit) when GPU memory is constrained; full fine-tune only for small models273. **Training** — Configure hyperparameters, monitor loss curves, checkpoint regularly28 - Checkpoint: validation loss must decrease; plateau or increase signals overfitting294. **Evaluation** — Benchmark against the base model; test on held-out set and edge cases30 - Checkpoint: collect perplexity, task-specific metrics (BLEU/ROUGE), and latency numbers315. **Deployment** — Merge adapter weights, quantize, measure inference throughput before serving3233## Reference Guide3435Load detailed guidance based on context:3637| Topic | Reference | Load When |38|-------|-----------|-----------|39| LoRA/PEFT | `references/lora-peft.md` | Parameter-efficient fine-tuning, adapters |40| Dataset Prep | `references/dataset-preparation.md` | Training data formatting, quality checks |41| Hyperparameters | `references/hyperparameter-tuning.md` | Learning rates, batch sizes, schedulers |42| Evaluation | `references/evaluation-metrics.md` | Benchmarking, metrics, model comparison |43| Deployment | `references/deployment-optimization.md` | Model merging, quantization, serving |4445## Minimal Working Example — LoRA Fine-Tuning with Hugging Face PEFT4647```python48from datasets import load_dataset49from transformers import AutoTokenizer, AutoModelForCausalLM, TrainingArguments50from peft import LoraConfig, get_peft_model, TaskType51from trl import SFTTrainer52import torch5354# 1. Load base model and tokenizer55model_id = "meta-llama/Llama-3-8B"56tokenizer = AutoTokenizer.from_pretrained(model_id)57tokenizer.pad_token = tokenizer.eos_token5859model = AutoModelForCausalLM.from_pretrained(60 model_id,61 torch_dtype=torch.bfloat16,62 device_map="auto",63)6465# 2. Configure LoRA adapter66lora_config = LoraConfig(67 task_type=TaskType.CAUSAL_LM,68 r=16, # rank — increase for more capacity, decrease to save memory69 lora_alpha=32, # scaling factor; typically 2× rank70 target_modules=["q_proj", "v_proj"],71 lora_dropout=0.05,72 bias="none",73)74model = get_peft_model(model, lora_config)75model.print_trainable_parameters() # verify: should be ~0.1–1% of total params7677# 3. Load and format dataset (Alpaca-style JSONL)78dataset = load_dataset("json", data_files={"train": "train.jsonl", "test": "test.jsonl"})7980def format_prompt(example):81 return {"text": f"### Instruction:\n{example['instruction']}\n\n### Response:\n{example['output']}"}8283dataset = dataset.map(format_prompt)8485# 4. Training arguments86training_args = TrainingArguments(87 output_dir="./checkpoints",88 num_train_epochs=3,89 per_device_train_batch_size=4,90 gradient_accumulation_steps=4, # effective batch size = 1691 learning_rate=2e-4,92 lr_scheduler_type="cosine",93 warmup_ratio=0.03, # always use warmup94 fp16=False,95 bf16=True,96 logging_steps=10,97 eval_strategy="steps",98 eval_steps=100,99 save_steps=200,100 load_best_model_at_end=True,101)102103# 5. Train104trainer = SFTTrainer(105 model=model,106 args=training_args,107 train_dataset=dataset["train"],108 eval_dataset=dataset["test"],109 dataset_text_field="text",110 max_seq_length=2048,111)112trainer.train()113114# 6. Save adapter weights only115model.save_pretrained("./lora-adapter")116tokenizer.save_pretrained("./lora-adapter")117```118119**QLoRA variant** — add these lines before loading the model to enable 4-bit quantization:120```python121from transformers import BitsAndBytesConfig122123bnb_config = BitsAndBytesConfig(124 load_in_4bit=True,125 bnb_4bit_quant_type="nf4",126 bnb_4bit_compute_dtype=torch.bfloat16,127 bnb_4bit_use_double_quant=True,128)129model = AutoModelForCausalLM.from_pretrained(model_id, quantization_config=bnb_config, device_map="auto")130```131132**Merge adapter into base model for deployment:**133```python134from peft import PeftModel135136base = AutoModelForCausalLM.from_pretrained(model_id, torch_dtype=torch.bfloat16)137merged = PeftModel.from_pretrained(base, "./lora-adapter").merge_and_unload()138merged.save_pretrained("./merged-model")139```140141## Constraints142143### MUST DO144- Validate dataset quality before training145- Use parameter-efficient methods for large models (>7B)146- Monitor training/validation loss curves147- Document hyperparameters and training config148- Version datasets and model checkpoints149- Always include a learning rate warmup150151### MUST NOT DO152- Skip data quality validation153- Overfit on small datasets — use regularisation (dropout, weight decay) and early stopping154- Merge incompatible adapters (mismatched rank, base model, or target modules)155- Deploy without evaluation against a held-out set and latency benchmark156157## Output Templates158159When implementing fine-tuning, always provide:1601. **Dataset preparation script** with validation logic (schema checks, token-length histogram, deduplication)1612. **Training configuration** (full `TrainingArguments` + `LoraConfig` block, commented)1623. **Evaluation script** reporting perplexity, task-specific metrics, and latency1634. **Brief design rationale** — why this PEFT method, rank, and learning rate were chosen for this task164165[Documentation](https://jeffallan.github.io/claude-skills/skills/data-ml/fine-tuning-expert/)