
Llm Fine Tuning Guide
- 176 installs
- 38 repo stars
- Updated January 5, 2026
- qodex-ai/ai-agent-skills
Plan and execute LLM fine-tuning—from dataset curation and eval splits to training jobs and deployment—for domain-specific agents or embedded models.
About
Walks through end-to-end LLM fine-tuning for specialized tasks: data collection, formatting, hyperparameters, evaluation metrics, and safe rollout. Helps teams move beyond prompt engineering to durable, domain-tuned models for agents and API products.
- Dataset preparation and labeling
- Train/validation split strategy
- Fine-tune job configuration
- Evaluation and regression checks
- Deployment of tuned model weights
Llm Fine Tuning Guide by the numbers
- 176 all-time installs (skills.sh)
- +3 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #3,085 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/qodex-ai/ai-agent-skills --skill llm-fine-tuning-guideAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 176 |
|---|---|
| repo stars | ★ 38 |
| Last updated | January 5, 2026 |
| Repository | qodex-ai/ai-agent-skills ↗ |
What it does
Plan and execute LLM fine-tuning—from dataset curation and eval splits to training jobs and deployment—for domain-specific agents or embedded models.
Files
LLM Fine-Tuning Guide
Master the art of fine-tuning large language models to create specialized models optimized for your specific use cases, domains, and performance requirements.
Overview
Fine-tuning adapts pre-trained LLMs to specific tasks, domains, or styles by training them on curated datasets. This improves accuracy, reduces hallucinations, and optimizes costs.
When to Fine-Tune
- Domain Specialization: Legal documents, medical records, financial reports
- Task-Specific Performance: Better results on specific tasks than base model
- Cost Optimization: Smaller fine-tuned model replaces expensive large model
- Style Adaptation: Match specific writing styles or tones
- Compliance Requirements: Keep sensitive data within your infrastructure
- Latency Requirements: Smaller models deploy faster
When NOT to Fine-Tune
- One-off queries (use prompting instead)
- Rapidly changing information (use RAG instead)
- Limited training data (< 100 examples typically insufficient)
- General knowledge questions (base model sufficient)
Quick Start
Full Fine-Tuning:
python examples/full_fine_tuning.pyLoRA (Recommended for most cases):
python examples/lora_fine_tuning.pyQLoRA (Single GPU):
python examples/qlora_fine_tuning.pyData Preparation:
python scripts/data_preparation.pyFine-Tuning Approaches
1. Full Fine-Tuning
Update all model parameters during training.
Pros:
- Maximum performance improvement
- Can completely rewrite model behavior
- Best for significant domain shifts
Cons:
- High computational cost
- Requires large dataset (1000+ examples)
- Risk of catastrophic forgetting
- Long training time
from transformers import AutoModelForCausalLM, AutoTokenizer, TrainingArguments, Trainer
model_id = "meta-llama/Llama-2-7b"
model = AutoModelForCausalLM.from_pretrained(model_id)
tokenizer = AutoTokenizer.from_pretrained(model_id)
training_args = TrainingArguments(
output_dir="./fine-tuned-llama",
num_train_epochs=3,
per_device_train_batch_size=4,
gradient_accumulation_steps=4,
learning_rate=2e-5,
weight_decay=0.01,
logging_steps=10,
save_steps=100,
eval_strategy="steps",
eval_steps=50,
load_best_model_at_end=True,
)
trainer = Trainer(
model=model,
args=training_args,
train_dataset=train_dataset,
eval_dataset=eval_dataset,
)
trainer.train()2. Parameter-Efficient Fine-Tuning (PEFT)
Train only a small fraction of parameters.
LoRA (Low-Rank Adaptation)
Adds trainable low-rank matrices to existing weights.
Pros:
- 99% fewer trainable parameters
- Maintains base model knowledge
- Fast training (10-20x faster)
- Easy to switch between adapters
Cons:
- Slightly lower performance than full fine-tuning
- Requires base model at inference
from peft import get_peft_model, LoraConfig, TaskType
from transformers import AutoModelForCausalLM, AutoTokenizer
base_model_id = "meta-llama/Llama-2-7b"
model = AutoModelForCausalLM.from_pretrained(base_model_id)
tokenizer = AutoTokenizer.from_pretrained(base_model_id)
# Configure LoRA
lora_config = LoraConfig(
r=8, # Rank of low-rank matrices
lora_alpha=16, # Scaling factor
target_modules=["q_proj", "v_proj"], # Which layers to adapt
lora_dropout=0.05,
bias="none",
task_type=TaskType.CAUSAL_LM
)
# Wrap model with LoRA
model = get_peft_model(model, lora_config)
model.print_trainable_parameters()
# Output: trainable params: 4,194,304 || all params: 6,738,415,616 || trainable%: 0.06
# Train as normal
trainer = Trainer(
model=model,
args=training_args,
train_dataset=train_dataset,
)
trainer.train()
# Save only LoRA weights
model.save_pretrained("./llama-lora-adapter")QLoRA (Quantized LoRA)
Combines LoRA with quantization for extreme efficiency.
from peft import prepare_model_for_kbit_training, get_peft_model, LoraConfig
from transformers import AutoModelForCausalLM, BitsAndBytesConfig
# Quantization config
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype="float16",
bnb_4bit_use_double_quant=True
)
# Load quantized model
model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Llama-2-7b",
quantization_config=bnb_config,
device_map="auto"
)
# Prepare for training
model = prepare_model_for_kbit_training(model)
# Apply LoRA
lora_config = LoraConfig(
r=8,
lora_alpha=32,
target_modules=["q_proj", "v_proj", "k_proj", "o_proj"],
lora_dropout=0.05,
bias="none",
task_type=TaskType.CAUSAL_LM
)
model = get_peft_model(model, lora_config)
# Train on single GPU
trainer = Trainer(
model=model,
args=TrainingArguments(
output_dir="./qlora-output",
per_device_train_batch_size=1,
gradient_accumulation_steps=4,
learning_rate=5e-4,
num_train_epochs=3,
),
train_dataset=train_dataset,
)
trainer.train()Prefix Tuning
Prepends trainable tokens to input.
from peft import get_peft_model, PrefixTuningConfig
config = PrefixTuningConfig(
num_virtual_tokens=20,
task_type=TaskType.CAUSAL_LM,
)
model = get_peft_model(model, config)
# Only 20 * embedding_dim parameters trained3. Instruction Fine-Tuning
Train model to follow instructions with examples.
# Training data format
training_data = [
{
"instruction": "Translate to French",
"input": "Hello, how are you?",
"output": "Bonjour, comment allez-vous?"
},
{
"instruction": "Summarize this text",
"input": "Long document...",
"output": "Summary..."
}
]
# Template for training
template = """Below is an instruction that describes a task, paired with an input that provides further context.
### Instruction:
{instruction}
### Input:
{input}
### Response:
{output}"""
# Create formatted dataset
formatted_data = [
template.format(**example) for example in training_data
]4. Domain-Specific Fine-Tuning
Tailor models for specific industries or fields.
Legal Domain Example
legal_training_data = [
{
"prompt": "What are the key clauses in an NDA?",
"completion": """Key clauses typically include:
1. Definition of Confidential Information
2. Non-Disclosure Obligations
3. Permitted Disclosures
4. Term and Termination
5. Return of Information
6. Remedies"""
},
# ... more legal examples
]
# Train on legal domain
model = fine_tune_on_domain(
base_model="gpt-3.5-turbo",
training_data=legal_training_data,
epochs=3,
learning_rate=0.0002,
)Data Preparation
1. Dataset Quality
class DatasetValidator:
def validate_dataset(self, data):
issues = {
"empty_samples": 0,
"duplicates": 0,
"outliers": 0,
"imbalance": {}
}
# Check for empty samples
for sample in data:
if not sample.get("text"):
issues["empty_samples"] += 1
# Check for duplicates
texts = [s.get("text") for s in data]
issues["duplicates"] = len(texts) - len(set(texts))
# Check for length outliers
lengths = [len(t.split()) for t in texts]
mean_length = sum(lengths) / len(lengths)
issues["outliers"] = sum(1 for l in lengths if l > mean_length * 3)
return issues
# Validate before training
validator = DatasetValidator()
issues = validator.validate_dataset(training_data)
print(f"Dataset Issues: {issues}")2. Data Augmentation
from nlpaug.augmenter.word import SynonymAug, RandomWordAug
import nlpaug.flow as naf
# Create augmentation pipeline
text = "The quick brown fox jumps over the lazy dog"
# Synonym replacement
aug_syn = SynonymAug(aug_p=0.3)
augmented_syn = aug_syn.augment(text)
# Random word insertion
aug_insert = RandomWordAug(action="insert", aug_p=0.3)
augmented_insert = aug_insert.augment(text)
# Combine augmentations
flow = naf.Sequential([
SynonymAug(aug_p=0.2),
RandomWordAug(action="swap", aug_p=0.2)
])
augmented = flow.augment(text)3. Train/Validation Split
from sklearn.model_selection import train_test_split
# Create splits
train_data, eval_data = train_test_split(
data,
test_size=0.2,
random_state=42
)
eval_data, test_data = train_test_split(
eval_data,
test_size=0.5,
random_state=42
)
print(f"Train: {len(train_data)}, Eval: {len(eval_data)}, Test: {len(test_data)}")Training Techniques
1. Learning Rate Scheduling
from torch.optim.lr_scheduler import CosineAnnealingLR, LinearLR
# Linear warmup + cosine annealing
def get_scheduler(optimizer, num_steps):
lr_scheduler = get_linear_schedule_with_warmup(
optimizer,
num_warmup_steps=500,
num_training_steps=num_steps
)
return lr_scheduler
training_args = TrainingArguments(
learning_rate=1e-4,
lr_scheduler_type="cosine",
warmup_steps=500,
warmup_ratio=0.1,
)2. Gradient Accumulation
training_args = TrainingArguments(
gradient_accumulation_steps=4, # Accumulate gradients over 4 steps
per_device_train_batch_size=1, # Effective batch size: 1 * 4 = 4
)
# Simulates larger batch on limited GPU memory3. Mixed Precision Training
training_args = TrainingArguments(
fp16=True, # Use 16-bit floats
bf16=False,
)
# Reduces memory usage by 50%, speeds up training4. Multi-GPU Training
training_args = TrainingArguments(
output_dir="./results",
num_train_epochs=3,
per_device_train_batch_size=8,
per_device_eval_batch_size=8,
gradient_accumulation_steps=4,
dataloader_pin_memory=True,
dataloader_num_workers=4,
)
# Automatically uses all available GPUs
trainer = Trainer(
model=model,
args=training_args,
train_dataset=train_dataset,
eval_dataset=eval_dataset,
)Popular Models for Fine-Tuning
Open Source Models
Llama 3.2 (Meta)
from transformers import AutoModelForCausalLM, AutoTokenizer
model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-3.2-7b")
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-3.2-7b")
# Fine-tune on custom data
# ... training codeCharacteristics:
- 7B, 70B parameter versions
- Strong instruction-following
- Excellent for domain adaptation
- Apache 2.0 license
Gemma 3 (Google)
model = AutoModelForCausalLM.from_pretrained("google/gemma-3-2b")
tokenizer = AutoTokenizer.from_pretrained("google/gemma-3-2b")
# Gemma 3 sizes: 2B, 7B, 27B
# Very efficient, great for fine-tuningCharacteristics:
- Small, medium, large sizes
- Efficient architecture
- Good for edge deployment
- Built on cutting-edge research
Mistral 7B
model = AutoModelForCausalLM.from_pretrained("mistralai/Mistral-7B-v0.1")
tokenizer = AutoTokenizer.from_pretrained("mistralai/Mistral-7B-v0.1")
# Strong performance, efficient architectureCharacteristics:
- Sliding window attention
- Efficient inference
- Strong performance-to-size ratio
Commercial Models
OpenAI Fine-Tuning API
import openai
# Prepare training data
training_file = openai.File.create(
file=open("training_data.jsonl", "rb"),
purpose="fine-tune"
)
# Create fine-tuning job
fine_tune_job = openai.FineTuningJob.create(
training_file=training_file.id,
model="gpt-3.5-turbo",
hyperparameters={
"n_epochs": 3,
"learning_rate_multiplier": 0.1,
}
)
# Wait for completion
fine_tuned_model = openai.FineTuningJob.retrieve(fine_tune_job.id)
print(f"Status: {fine_tuned_model.status}")
# Use fine-tuned model
response = openai.ChatCompletion.create(
model=fine_tuned_model.fine_tuned_model,
messages=[{"role": "user", "content": "Hello"}]
)Evaluation and Metrics
1. Perplexity
import torch
from math import exp
def calculate_perplexity(model, eval_dataset):
model.eval()
total_loss = 0
total_tokens = 0
with torch.no_grad():
for batch in eval_dataset:
outputs = model(**batch)
loss = outputs.loss
total_loss += loss.item() * batch["input_ids"].shape[0]
total_tokens += batch["input_ids"].shape[0]
perplexity = exp(total_loss / total_tokens)
return perplexity
perplexity = calculate_perplexity(model, eval_dataset)
print(f"Perplexity: {perplexity:.2f}")2. Task-Specific Metrics
from sklearn.metrics import accuracy_score, f1_score, precision_score, recall_score
def evaluate_task(predictions, ground_truth):
return {
"accuracy": accuracy_score(ground_truth, predictions),
"precision": precision_score(ground_truth, predictions, average='weighted'),
"recall": recall_score(ground_truth, predictions, average='weighted'),
"f1": f1_score(ground_truth, predictions, average='weighted'),
}
# Evaluate on task
predictions = [model.predict(x) for x in test_data]
metrics = evaluate_task(predictions, test_labels)
print(f"Metrics: {metrics}")3. Human Evaluation
class HumanEvaluator:
def evaluate_response(self, prompt, response):
criteria = {
"relevance": self._score_relevance(prompt, response),
"coherence": self._score_coherence(response),
"factuality": self._score_factuality(response),
"helpfulness": self._score_helpfulness(response),
}
return sum(criteria.values()) / len(criteria)
def _score_relevance(self, prompt, response):
# Score 1-5
pass
def _score_coherence(self, response):
# Score 1-5
passCommon Challenges & Solutions
Challenge: Catastrophic Forgetting
Model forgets pre-trained knowledge while adapting to new domain.
Solutions:
- Use lower learning rates (2e-5 to 5e-5)
- Smaller training epochs (1-3)
- Regularization techniques
- Continual learning approaches
# Conservative training settings
training_args = TrainingArguments(
learning_rate=2e-5, # Lower learning rate
num_train_epochs=2, # Few epochs
weight_decay=0.01, # L2 regularization
warmup_steps=500,
save_total_limit=3,
load_best_model_at_end=True,
)Challenge: Overfitting
Model performs well on training data but poorly on new data.
Solutions:
- Use more training data
- Implement dropout
- Early stopping
- Validation monitoring
training_args = TrainingArguments(
eval_strategy="steps",
eval_steps=50,
load_best_model_at_end=True,
early_stopping_patience=3,
metric_for_best_model="eval_loss",
)Challenge: Insufficient Training Data
Few examples for fine-tuning.
Solutions:
- Data augmentation
- Use PEFT (LoRA) instead of full fine-tuning
- Few-shot learning with prompting
- Transfer learning
# Use LoRA when data is limited
lora_config = LoraConfig(
r=8,
lora_alpha=16,
target_modules=["q_proj", "v_proj"],
lora_dropout=0.05,
)Best Practices
Before Fine-Tuning
- ✓ Start with a strong base model
- ✓ Prepare high-quality training data (100+ examples recommended)
- ✓ Define clear evaluation metrics
- ✓ Set up proper train/validation splits
- ✓ Document your objectives
During Fine-Tuning
- ✓ Monitor training/validation loss
- ✓ Use appropriate learning rates
- ✓ Save checkpoints regularly
- ✓ Validate on held-out data
- ✓ Watch for overfitting/underfitting
After Fine-Tuning
- ✓ Evaluate on test set
- ✓ Compare against baseline
- ✓ Perform qualitative analysis
- ✓ Document configuration and results
- ✓ Version your fine-tuned models
Implementation Checklist
- [ ] Determine fine-tuning approach (full, LoRA, QLoRA, instruction)
- [ ] Prepare and validate training dataset (100+ examples)
- [ ] Choose base model (Llama 3.2, Gemma 3, Mistral, etc.)
- [ ] Set up PEFT if using parameter-efficient methods
- [ ] Configure training arguments and hyperparameters
- [ ] Implement data loading and preprocessing
- [ ] Set up evaluation metrics
- [ ] Train model with monitoring
- [ ] Evaluate on test set
- [ ] Save and version fine-tuned model
- [ ] Test in production environment
- [ ] Document process and results
Resources
Frameworks
- Hugging Face Transformers: https://huggingface.co/transformers/
- PEFT (Parameter-Efficient Fine-Tuning): https://github.com/huggingface/peft
- Hugging Face Datasets: https://huggingface.co/datasets
Models
- Llama 3.2: https://www.meta.com/llama/
- Gemma 3: https://deepmind.google/technologies/gemma/
- Mistral: https://mistral.ai/
Papers
- "LoRA: Low-Rank Adaptation of Large Language Models" (Hu et al.)
- "QLoRA: Efficient Finetuning of Quantized LLMs" (Dettmers et al.)
"""
Full Fine-Tuning Example
Update all model parameters during training for maximum performance.
See scripts/ for data preparation utilities.
"""
from transformers import AutoModelForCausalLM, AutoTokenizer, TrainingArguments, Trainer
def full_fine_tune(model_id: str = "meta-llama/Llama-2-7b", output_dir: str = "./fine-tuned-llama"):
"""Full fine-tuning example with all parameters updated."""
model = AutoModelForCausalLM.from_pretrained(model_id)
tokenizer = AutoTokenizer.from_pretrained(model_id)
training_args = TrainingArguments(
output_dir=output_dir,
num_train_epochs=3,
per_device_train_batch_size=4,
gradient_accumulation_steps=4,
learning_rate=2e-5,
weight_decay=0.01,
logging_steps=10,
save_steps=100,
eval_strategy="steps",
eval_steps=50,
load_best_model_at_end=True,
)
trainer = Trainer(
model=model,
args=training_args,
train_dataset=None, # Load your dataset here
eval_dataset=None, # Load your eval dataset here
)
trainer.train()
return trainer.model
if __name__ == "__main__":
model = full_fine_tune()
print("✓ Full fine-tuning completed")
"""
LoRA (Low-Rank Adaptation) Fine-Tuning Example
Parameter-efficient fine-tuning with 99% fewer trainable parameters.
"""
from peft import get_peft_model, LoraConfig, TaskType
from transformers import AutoModelForCausalLM, AutoTokenizer, TrainingArguments, Trainer
def lora_fine_tune(model_id: str = "meta-llama/Llama-2-7b", output_dir: str = "./llama-lora-adapter"):
"""LoRA fine-tuning with low-rank matrices."""
model = AutoModelForCausalLM.from_pretrained(model_id)
tokenizer = AutoTokenizer.from_pretrained(model_id)
# Configure LoRA
lora_config = LoraConfig(
r=8, # Rank of low-rank matrices
lora_alpha=16, # Scaling factor
target_modules=["q_proj", "v_proj"], # Which layers to adapt
lora_dropout=0.05,
bias="none",
task_type=TaskType.CAUSAL_LM,
)
# Wrap model with LoRA
model = get_peft_model(model, lora_config)
model.print_trainable_parameters()
training_args = TrainingArguments(
output_dir=output_dir,
num_train_epochs=3,
per_device_train_batch_size=4,
gradient_accumulation_steps=4,
learning_rate=5e-4,
logging_steps=10,
save_steps=100,
)
trainer = Trainer(
model=model,
args=training_args,
train_dataset=None, # Load your dataset here
)
trainer.train()
# Save only LoRA weights
model.save_pretrained(output_dir)
return model
if __name__ == "__main__":
model = lora_fine_tune()
print("✓ LoRA fine-tuning completed")
"""
QLoRA (Quantized LoRA) Fine-Tuning Example
Combines LoRA with quantization for extreme efficiency on single GPU.
"""
from peft import prepare_model_for_kbit_training, get_peft_model, LoraConfig, TaskType
from transformers import AutoModelForCausalLM, BitsAndBytesConfig, TrainingArguments, Trainer
def qlora_fine_tune(model_id: str = "meta-llama/Llama-2-7b", output_dir: str = "./qlora-output"):
"""QLoRA fine-tuning for efficient single-GPU training."""
# Quantization config
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype="float16",
bnb_4bit_use_double_quant=True,
)
# Load quantized model
model = AutoModelForCausalLM.from_pretrained(
model_id, quantization_config=bnb_config, device_map="auto"
)
# Prepare for training
model = prepare_model_for_kbit_training(model)
# Apply LoRA
lora_config = LoraConfig(
r=8,
lora_alpha=32,
target_modules=["q_proj", "v_proj", "k_proj", "o_proj"],
lora_dropout=0.05,
bias="none",
task_type=TaskType.CAUSAL_LM,
)
model = get_peft_model(model, lora_config)
training_args = TrainingArguments(
output_dir=output_dir,
per_device_train_batch_size=1,
gradient_accumulation_steps=4,
learning_rate=5e-4,
num_train_epochs=3,
logging_steps=10,
)
trainer = Trainer(
model=model,
args=training_args,
train_dataset=None, # Load your dataset here
)
trainer.train()
return model
if __name__ == "__main__":
model = qlora_fine_tune()
print("✓ QLoRA fine-tuning completed")
LLM Fine-Tuning Guide - Code Structure
This skill uses supporting Python files to keep documentation lean and maintainable.
Directory Structure
llm-fine-tuning-guide/
├── SKILL.md # Main documentation (concepts, best practices)
├── README.md # This file
├── examples/ # Implementation examples
│ ├── full_fine_tuning.py # Full parameter fine-tuning
│ ├── lora_fine_tuning.py # LoRA implementation
│ └── qlora_fine_tuning.py # QLoRA (single GPU)
└── scripts/ # Utility modules
├── data_preparation.py # Dataset validation, augmentation, splitting
└── evaluation_metrics.py # Perplexity, task metrics, evaluation utilsRunning Examples
1. Full Fine-Tuning
python examples/full_fine_tuning.pyUpdates all model parameters. Requires powerful GPU.
2. LoRA (Recommended)
python examples/lora_fine_tuning.pyParameter-efficient, ~99% fewer trainable parameters.
3. QLoRA (Single Consumer GPU)
python examples/qlora_fine_tuning.pyQuantized LoRA for 7B models on 24GB GPU.
Using the Utilities
Data Preparation
from scripts.data_preparation import DatasetValidator, create_splits, augment_data
validator = DatasetValidator()
issues = validator.validate_dataset(your_data)
validator.print_issues(issues)
train, val, test = create_splits(your_data)Evaluation Metrics
from scripts.evaluation_metrics import calculate_perplexity, evaluate_task_metrics
perplexity = calculate_perplexity(model, eval_dataset)
metrics = evaluate_task_metrics(predictions, ground_truth)Integration with SKILL.md
- SKILL.md contains conceptual information and best practices
- Code examples are in
examples/for clarity - Utilities are in
scripts/for reusability - This keeps token costs low while maintaining full functionality
Models Supported
- Llama 3.2 (1B, 3B, 8B)
- Gemma 3 (2B, 7B)
- Mistral 7B
- Any HuggingFace compatible model
Requirements
torch>=2.0
transformers>=4.36
peft>=0.7
datasets>=2.14
scikit-learn>=1.3Next Steps
1. Prepare your dataset using scripts/data_preparation.py 2. Choose approach: Full, LoRA, or QLoRA 3. Run corresponding example script 4. Evaluate using scripts/evaluation_metrics.py 5. See SKILL.md for detailed explanations and best practices
"""
Data Preparation Utilities for Fine-Tuning
Handles dataset validation, augmentation, and splitting.
"""
from sklearn.model_selection import train_test_split
from collections import Counter
import textwrap
class DatasetValidator:
"""Validates dataset quality before training."""
def validate_dataset(self, data):
"""Check for common data quality issues."""
issues = {
"empty_samples": 0,
"duplicates": 0,
"outliers": 0,
"imbalance": {},
}
# Check for empty samples
for sample in data:
if not sample.get("text"):
issues["empty_samples"] += 1
# Check for duplicates
texts = [s.get("text") for s in data]
issues["duplicates"] = len(texts) - len(set(texts))
# Check for length outliers
lengths = [len(t.split()) for t in texts if t]
if lengths:
mean_length = sum(lengths) / len(lengths)
issues["outliers"] = sum(1 for l in lengths if l > mean_length * 3)
return issues
def print_issues(self, issues):
"""Print formatted validation report."""
print("Dataset Validation Report:")
print(f" Empty samples: {issues['empty_samples']}")
print(f" Duplicates: {issues['duplicates']}")
print(f" Outliers: {issues['outliers']}")
def create_splits(data, train_size=0.8, val_size=0.1, test_size=0.1, random_state=42):
"""Create train/validation/test splits."""
train_data, temp_data = train_test_split(
data, train_size=train_size, random_state=random_state
)
val_ratio = val_size / (val_size + test_size)
val_data, test_data = train_test_split(
temp_data, train_size=val_ratio, random_state=random_state
)
return train_data, val_data, test_data
def augment_data(data, augmentation_strategy="synonym"):
"""Simple data augmentation strategies."""
augmented = []
for sample in data:
augmented.append(sample)
if augmentation_strategy == "paraphrase":
# Add paraphrased version (requires external library)
pass
elif augmentation_strategy == "shuffle":
# Shuffle word order (except first/last few words)
if "text" in sample:
words = sample["text"].split()
if len(words) > 4:
import random
shuffled = words[:2] + random.sample(words[2:-2], len(words) - 4) + words[-2:]
augmented.append({"text": " ".join(shuffled), "label": sample.get("label")})
return augmented
def format_for_instruction_tuning(data, template=None):
"""Format data for instruction fine-tuning."""
if template is None:
template = """Below is an instruction that describes a task, paired with an input that provides further context.
### Instruction:
{instruction}
### Input:
{input}
### Response:
{output}"""
formatted_data = []
for sample in data:
formatted_text = template.format(
instruction=sample.get("instruction", ""),
input=sample.get("input", ""),
output=sample.get("output", ""),
)
formatted_data.append({"text": formatted_text})
return formatted_data
if __name__ == "__main__":
# Example usage
validator = DatasetValidator()
sample_data = [
{"text": "This is a test sample", "label": 1},
{"text": "This is another test", "label": 0},
]
issues = validator.validate_dataset(sample_data)
validator.print_issues(issues)
"""
Evaluation Metrics for Fine-Tuned Models
Calculate perplexity, task-specific metrics, and quality scores.
"""
import torch
import math
from sklearn.metrics import accuracy_score, f1_score, precision_score, recall_score
def calculate_perplexity(model, eval_dataset):
"""Calculate perplexity on evaluation dataset."""
model.eval()
total_loss = 0
total_tokens = 0
with torch.no_grad():
for batch in eval_dataset:
outputs = model(**batch)
loss = outputs.loss
total_loss += loss.item() * batch["input_ids"].shape[0]
total_tokens += batch["input_ids"].shape[0]
perplexity = math.exp(total_loss / total_tokens)
return perplexity
def evaluate_task_metrics(predictions, ground_truth, average="weighted"):
"""Calculate standard ML metrics."""
metrics = {
"accuracy": accuracy_score(ground_truth, predictions),
"precision": precision_score(ground_truth, predictions, average=average, zero_division=0),
"recall": recall_score(ground_truth, predictions, average=average, zero_division=0),
"f1": f1_score(ground_truth, predictions, average=average, zero_division=0),
}
return metrics
def print_evaluation_report(metrics):
"""Print formatted evaluation report."""
print("\nEvaluation Metrics:")
print("=" * 40)
for metric_name, metric_value in metrics.items():
if isinstance(metric_value, float):
print(f"{metric_name:.<20} {metric_value:.4f}")
else:
print(f"{metric_name:.<20} {metric_value}")
print("=" * 40)
class HumanEvaluationCriteria:
"""Framework for human evaluation of model outputs."""
CRITERIA = {
"relevance": "Does the response address the query?",
"coherence": "Is the response logically consistent?",
"factuality": "Are the facts accurate?",
"helpfulness": "Would this help the user?",
}
@staticmethod
def score_response(response: str, query: str, criteria: str = "relevance") -> int:
"""Score response on a scale of 1-5 for given criteria."""
# Placeholder - implement with your evaluation logic
return 3
if __name__ == "__main__":
# Example usage
sample_predictions = [0, 1, 1, 0, 1]
sample_ground_truth = [0, 1, 0, 0, 1]
metrics = evaluate_task_metrics(sample_predictions, sample_ground_truth)
print_evaluation_report(metrics)