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
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: MIT5---67# Fine-Tuning Expert89Senior ML engineer specializing in LLM fine-tuning, parameter-efficient methods, and production model optimization.1011## Core Workflow12131. **Dataset preparation** — Validate and format data; run quality checks before training starts14 - Checkpoint: `python validate_dataset.py --input data.jsonl` — fix all errors before proceeding152. **Method selection** — Choose PEFT technique based on GPU memory and task requirements16 - Use LoRA for most tasks; QLoRA (4-bit) when GPU memory is constrained; full fine-tune only for small models173. **Training** — Configure hyperparameters, monitor loss curves, checkpoint regularly18 - Checkpoint: validation loss must decrease; plateau or increase signals overfitting194. **Evaluation** — Benchmark against the base model; test on held-out set and edge cases20 - Checkpoint: collect perplexity, task-specific metrics (BLEU/ROUGE), and latency numbers215. **Deployment** — Merge adapter weights, quantize, measure inference throughput before serving2223## Reference Guide2425Load detailed guidance based on context:2627| Topic | Reference | Load When |28|-------|-----------|-----------|29| LoRA/PEFT | `references/lora-peft.md` | Parameter-efficient fine-tuning, adapters |30| Dataset Prep | `references/dataset-preparation.md` | Training data formatting, quality checks |31| Hyperparameters | `references/hyperparameter-tuning.md` | Learning rates, batch sizes, schedulers |32| Evaluation | `references/evaluation-metrics.md` | Benchmarking, metrics, model comparison |33| Deployment | `references/deployment-optimization.md` | Model merging, quantization, serving |3435## Minimal Working Example — LoRA Fine-Tuning with Hugging Face PEFT3637```python38from datasets import load_dataset39from transformers import AutoTokenizer, AutoModelForCausalLM, TrainingArguments40from peft import LoraConfig, get_peft_model, TaskType41from trl import SFTTrainer42import torch4344# 1. Load base model and tokenizer45model_id = "meta-llama/Llama-3-8B"46tokenizer = AutoTokenizer.from_pretrained(model_id)47tokenizer.pad_token = tokenizer.eos_token4849model = AutoModelForCausalLM.from_pretrained(50 model_id,51 torch_dtype=torch.bfloat16,52 device_map="auto",53)5455# 2. Configure LoRA adapter56lora_config = LoraConfig(57 task_type=TaskType.CAUSAL_LM,58 r=16, # rank — increase for more capacity, decrease to save memory59 lora_alpha=32, # scaling factor; typically 2× rank60 target_modules=["q_proj", "v_proj"],61 lora_dropout=0.05,62 bias="none",63)64model = get_peft_model(model, lora_config)65model.print_trainable_parameters() # verify: should be ~0.1–1% of total params6667# 3. Load and format dataset (Alpaca-style JSONL)68dataset = load_dataset("json", data_files={"train": "train.jsonl", "test": "test.jsonl"})6970def format_prompt(example):71 return {"text": f"### Instruction:\n{example['instruction']}\n\n### Response:\n{example['output']}"}7273dataset = dataset.map(format_prompt)7475# 4. Training arguments76training_args = TrainingArguments(77 output_dir="./checkpoints",78 num_train_epochs=3,79 per_device_train_batch_size=4,80 gradient_accumulation_steps=4, # effective batch size = 1681 learning_rate=2e-4,82 lr_scheduler_type="cosine",83 warmup_ratio=0.03, # always use warmup84 fp16=False,85 bf16=True,86 logging_steps=10,87 eval_strategy="steps",88 eval_steps=100,89 save_steps=200,90 load_best_model_at_end=True,91)9293# 5. Train94trainer = SFTTrainer(95 model=model,96 args=training_args,97 train_dataset=dataset["train"],98 eval_dataset=dataset["test"],99 dataset_text_field="text",100 max_seq_length=2048,101)102trainer.train()103104# 6. Save adapter weights only105model.save_pretrained("./lora-adapter")106tokenizer.save_pretrained("./lora-adapter")107```108109**QLoRA variant** — add these lines before loading the model to enable 4-bit quantization:110```python111from transformers import BitsAndBytesConfig112113bnb_config = BitsAndBytesConfig(114 load_in_4bit=True,115 bnb_4bit_quant_type="nf4",116 bnb_4bit_compute_dtype=torch.bfloat16,117 bnb_4bit_use_double_quant=True,118)119model = AutoModelForCausalLM.from_pretrained(model_id, quantization_config=bnb_config, device_map="auto")120```121122**Merge adapter into base model for deployment:**123```python124from peft import PeftModel125126base = AutoModelForCausalLM.from_pretrained(model_id, torch_dtype=torch.bfloat16)127merged = PeftModel.from_pretrained(base, "./lora-adapter").merge_and_unload()128merged.save_pretrained("./merged-model")129```130131## Constraints132133### MUST DO134- Validate dataset quality before training135- Use parameter-efficient methods for large models (>7B)136- Monitor training/validation loss curves137- Document hyperparameters and training config138- Version datasets and model checkpoints139- Always include a learning rate warmup140141### MUST NOT DO142- Skip data quality validation143- Overfit on small datasets — use regularisation (dropout, weight decay) and early stopping144- Merge incompatible adapters (mismatched rank, base model, or target modules)145- Deploy without evaluation against a held-out set and latency benchmark146147## Output Templates148149When implementing fine-tuning, always provide:1501. **Dataset preparation script** with validation logic (schema checks, token-length histogram, deduplication)1512. **Training configuration** (full `TrainingArguments` + `LoraConfig` block, commented)1523. **Evaluation script** reporting perplexity, task-specific metrics, and latency1534. **Brief design rationale** — why this PEFT method, rank, and learning rate were chosen for this task