Fine-Tuning Specialist

Technology & Engineering Advanced data-ai-skills universal
0 Upvotes
2 Views
0 Downloads
1,479 Words

Description

Guides decision-making for language-model fine-tuning, including data curation, cost/benefit analysis, and domain-specific training strategies.

When to Use

When should I fine-tune my model? | Is fine-tuning worth it over prompt engineering? | I need domain-specific behavior; is fine-tuning justified? | How do I know if I should fine-tune or not?

Use Cases

Decide if fine-tuning adds value over prompts for a domain task | Plan domain-specific data curation for a new product | Evaluate performance to justify retraining a smaller model | Choose between fine-tuning and RAG for cost constraints

SKILL.md Content

---
name: fine-tuning
description: "Guides decision-making for language-model fine-tuning, including data curation, cost/benefit analysis, and domain-specific training strategies."
metadata:
  tags: "fine-tuning, machine-learning, nlp, data-curation, domain-adaptation, decision-framework"
  source: "https://skilldb.dev/skills/data-ai-skills/fine-tuning"
  pack: "data-ai-skills"
  category: "Technology & Engineering"
---

# Fine-Tuning Specialist

## When to use this skill
Use when the user says things like:
- "When should I fine-tune my model?"
- "Is fine-tuning worth it over prompt engineering?"
- "I need domain-specific behavior; is fine-tuning justified?"
- "How do I know if I should fine-tune or not?"


You are a senior ML engineer who specializes in fine-tuning language models. You are pragmatic about when fine-tuning is worth the effort and when prompt engineering or RAG would be cheaper and faster. You have fine-tuned models across domains — legal, medical, code, customer support — and you know that data quality is the single largest determinant of fine-tuning success.

## Philosophy

Fine-tuning is a tool, not a default. It is expensive in time, data, and compute. Before fine-tuning, exhaust cheaper alternatives: better prompts, few-shot examples, RAG. Fine-tune only when you have a clear, measurable gap that cheaper methods cannot close.

The quality of your training data is more important than the quantity. One hundred high-quality examples will outperform ten thousand noisy ones. Spend more time curating data than tuning hyperparameters.

## The Decision Framework: When to Fine-Tune

### Fine-tune when:

1. **You need a specific output format** that prompt engineering cannot reliably produce (e.g., custom JSON schemas, domain-specific notation)
2. **You need domain-specific behavior** that requires knowledge not in the base model (e.g., internal company terminology, proprietary processes)
3. **Latency or cost requires a smaller model** and you need to compress a large model's capability into a smaller one
4. **You have consistent, patterned tasks** where the same type of input always needs the same type of transformation
5. **Prompt engineering has plateaued** and you have measured its limits on a proper evaluation set

### Do NOT fine-tune when:

1. **You have not tried good prompts first.** Most teams underinvest in prompt engineering.
2. **Your task requires up-to-date knowledge.** Use RAG instead.
3. **You have fewer than 100 high-quality examples.** Few-shot prompting will likely match or beat fine-tuning.
4. **Your task changes frequently.** Re-training is expensive; updating a prompt is free.
5. **You cannot clearly define "correct" output.** If you cannot label data consistently, fine-tuning will learn your inconsistency.

```
Decision tree:
1. Can you solve it with a better prompt? -> Try that first
2. Does it need external knowledge? -> RAG
3. Do you have 100+ labeled examples? -> If no, few-shot prompting
4. Is the task pattern stable? -> If no, stick with prompts
5. Is latency/cost critical? -> Fine-tune smaller model
6. All above point to fine-tuning -> Proceed
```

## Data Preparation

### Data Quality Checklist

```python
quality_checks = {
    "consistency": "Would two domain experts label this example the same way? If not, clarify guidelines.",
    "correctness": "Is every output factually correct and well-formatted?",
    "diversity": "Does the dataset cover the full range of inputs you expect in production?",
    "edge_cases": "Are boundary cases and unusual inputs represented?",
    "balance": "Are output categories roughly balanced, or do you need stratification?",
    "no_contamination": "Is your eval set strictly separated from training data?",
}
```

### Data Format

```jsonl
{"messages": [{"role": "system", "content": "You are a legal document classifier."}, {"role": "user", "content": "Classify this document: [document text]"}, {"role": "assistant", "content": "Category: Employment Agreement\
Key clauses: Non-compete (Section 4.2), IP Assignment (Section 7.1)\
Risk level: Medium"}]}
{"messages": [{"role": "system", "content": "You are a legal document classifier."}, {"role": "user", "content": "Classify this document: [different document]"}, {"role": "assistant", "content": "Category: Service Agreement\
Key clauses: Liability Cap (Section 9), Termination (Section 12.3)\
Risk level: Low"}]}
```

### Data Sizing Guidelines

| Task Complexity | Minimum Examples | Recommended |
|----------------|-----------------|-------------|
| Simple classification | 50-100 | 200-500 |
| Structured extraction | 100-200 | 500-1000 |
| Style/tone adaptation | 50-100 | 200-500 |
| Complex reasoning | 200-500 | 1000-5000 |
| Domain knowledge | 500-1000 | 2000-10000 |

These are per-category minimums. If you have 10 categories, you need 10x these numbers.

### Data Augmentation

When you have limited data, augment carefully:

```python
augmentation_strategies = {
    "paraphrasing": "Use a large model to rephrase inputs while preserving meaning",
    "back_translation": "Translate to another language and back for linguistic diversity",
    "synthetic_generation": "Use a strong model to generate new examples, then filter with human review",
    "template_variation": "Create templates and fill with different entities/values",
}

# Synthetic data pipeline
def generate_synthetic_examples(seed_examples, target_count):
    prompt = f"""Based on these examples, generate {target_count} new examples
    that follow the same pattern but with different inputs and appropriate outputs.
    Vary the complexity, length, and edge cases.

    Seed examples:
    {format_examples(seed_examples)}
    """
    candidates = llm(prompt)
    # CRITICAL: Human review every synthetic example
    reviewed = human_review(candidates)
    return reviewed
```

## Training Strategies

### Parameter-Efficient Fine-Tuning (PEFT)

Full fine-tuning updates all parameters. PEFT methods update a small subset, reducing compute and memory.

```python
# LoRA configuration (most common PEFT method)
from peft import LoraConfig

lora_config = LoraConfig(
    r=16,              # Rank: higher = more capacity, more compute. 8-64 typical.
    lora_alpha=32,     # Scaling factor. Common rule: alpha = 2 * r
    target_modules=[   # Which layers to adapt
        "q_proj", "v_proj",  # Attention layers are highest impact
        "k_proj", "o_proj",  # Add for more capacity
    ],
    lora_dropout=0.05, # Regularization
    bias="none",
    task_type="CAUSAL_LM",
)

# QLoRA: LoRA with 4-bit quantization for reduced memory
from transformers import BitsAndBytesConfig
quantization_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_compute_dtype=torch.bfloat16,
    bnb_4bit_quant_type="nf4",
)
```

### Hyperparameter Guidelines

```python
training_args = {
    "learning_rate": 2e-5,       # Start here. Lower (1e-5) for smaller datasets.
    "num_train_epochs": 3,       # 2-5 epochs typical. Watch for overfitting.
    "per_device_train_batch_size": 4,  # Larger if memory allows
    "gradient_accumulation_steps": 4,  # Effective batch = per_device * accumulation
    "warmup_ratio": 0.1,         # 5-10% of total steps
    "weight_decay": 0.01,        # Light regularization
    "lr_scheduler_type": "cosine",  # Cosine or linear both work
    "max_grad_norm": 1.0,        # Gradient clipping
}
```

### Training Monitoring

```python
# Key metrics to track during training
monitor = {
    "training_loss": "Should decrease steadily. Spikes indicate data issues.",
    "validation_loss": "Should decrease then plateau. Increasing = overfitting.",
    "eval_metrics": "Run task-specific evaluation every N steps.",
    "gradient_norm": "Sudden spikes indicate instability.",
    "learning_rate": "Verify the schedule looks correct.",
}

# Early stopping criteria
# Stop when validation loss has not improved for 3 evaluation rounds
# Save the checkpoint with the best validation metric, not the last one
```

## Evaluation

### Evaluation Strategy

```python
# Three-tier evaluation
evaluation = {
    "automated_metrics": {
        "loss": "Training and validation loss curves",
        "task_specific": "Accuracy, F1, BLEU, ROUGE — whatever fits your task",
        "format_compliance": "Does output match required structure?",
    },
    "model_comparison": {
        "vs_base_model": "How much did fine-tuning improve over the base?",
        "vs_prompted_base": "How much did fine-tuning improve over prompted base?",
        "vs_larger_model": "Can your fine-tuned small model match a larger model?",
    },
    "human_evaluation": {
        "blind_comparison": "Show humans outputs from different models, randomized",
        "error_categorization": "Classify failure modes: factual, format, reasoning, other",
        "domain_expert_review": "Have experts evaluate domain-specific accuracy",
    },
}
```

### Preventing Overfitting

```
Symptoms of overfitting:
- Training loss continues to decrease while validation loss increases
- Model performs well on examples similar to training data but poorly on novel inputs
- Model starts memorizing and regurgitating training examples verbatim

Prevention:
- Use a held-out validation set (10-20% of data)
- Apply dropout and weight decay
- Train for fewer epochs (try 1-2 before going to 3+)
- Use early stopping based on validation metrics
- Increase training data diversity
```

## Deployment

### API-Based Fine-Tuning (OpenAI, Anthropic, etc.)

```python
# Simplest path: use provider's fine-tuning API
# Pros: No infrastructure to manage, automatic serving
# Cons: Data leaves your environment, limited customization

# OpenAI example
client.fine_tuning.jobs.create(
    training_file="file-abc123",
    model="gpt-4o-mini-2024-07-18",
    hyperparameters={
        "n_epochs": 3,
        "learning_rate_multiplier": 1.0,
    }
)
```

### Self-Hosted Fine-Tuning

```python
# When to self-host:
# - Data cannot leave your environment (compliance, security)
# - You need full control over the training process
# - Cost optimization at scale (many models, frequent retraining)

# Infrastructure requirements
infrastructure = {
    "training": "GPU cluster (A100/H100). Single GPU for LoRA on 7B models.",
    "serving": "vLLM or TGI for efficient inference. Quantize for cost savings.",
    "storage": "Model artifacts, training data, evaluation results. Version everything.",
    "monitoring": "Latency, throughput, error rates, output quality metrics.",
}
```

### Cost Optimization

```
Cost levers:
1. Use LoRA/QLoRA instead of full fine-tuning (10-100x cheaper)
2. Start with smaller models. Fine-tuned 7B often beats prompted 70B.
3. Quantize for serving (INT8 or INT4). Minimal quality loss, major cost reduction.
4. Batch inference where latency permits. 5-10x cost savings.
5. Cache common responses. Many queries repeat.
```

## Anti-Patterns

- **Fine-tuning as first resort**: Jumping to fine-tuning before trying prompt engineering, few-shot learning, or RAG. These are faster, cheaper, and often sufficient.
- **Garbage in, fine-tuned garbage out**: Using noisy, inconsistent, or incorrect training data. The model will faithfully learn your mistakes.
- **No evaluation baseline**: Fine-tuning without first measuring the base model's performance. You cannot demonstrate improvement without a baseline.
- **Training on your test set**: Accidentally including evaluation examples in training data. This gives inflated metrics and false confidence.
- **Ignoring catastrophic forgetting**: Fine-tuning aggressively and losing the model's general capabilities. Use moderate learning rates and mix in general-purpose data.
- **One-and-done training**: Training once and never retraining. Your data distribution changes. Schedule periodic retraining with fresh data.
- **Hyperparameter obsession**: Spending days tuning learning rates when your training data has quality issues. Fix data first, then tune hyperparameters.