How to fine-tune pre-trained language models for your specific NLP tasks.
| Approach | Data Needed | Latency | Accuracy | Cost |
|---|---|---|---|---|
| Zero-shot (prompt a large LLM) | 0 examples | High (API call) | Good for general tasks | Per-token API cost |
| Few-shot (in-context examples) | 3-10 examples | High (longer prompt) | Better than zero-shot | Higher per-token cost |
| Fine-tune small model | 100-10k examples | Low (local inference) | Best for specific tasks | One-time GPU cost |
| Fine-tune with LoRA | 100-10k examples | Low | Near full fine-tune | Lower GPU cost |
Fine-tune when: You have labeled data, need low latency, want to avoid API costs, or need domain-specific accuracy that general models cannot match.
| Task | Recommended Base | Why |
|---|---|---|
| Text classification | distilbert-base-uncased | Fast, 60% fewer params than BERT, 97% accuracy |
| Sentiment analysis | distilbert-base-uncased | Same — sentiment is classification |
| NER | bert-base-cased | Case matters for entity recognition |
| Multi-label | roberta-base | Better at nuanced multi-class decisions |
| Domain-specific | allenai/scibert_scivocab_uncased | Match your domain (sci, bio, legal, fin) |
| Low-resource language | xlm-roberta-base | 100+ language support |
from nlp_starter_kit.fine_tuning import FineTuningConfig, HuggingFaceFineTuner
config = FineTuningConfig(
model_name="distilbert-base-uncased",
num_epochs=3,
batch_size=16,
learning_rate=2e-5,
)
tuner = HuggingFaceFineTuner(config)
tuner.prepare_data(
train_texts=["Great product!", "Terrible service", ...],
train_labels=["positive", "negative", ...],
eval_texts=["Loved it!", "Would not recommend", ...],
eval_labels=["positive", "negative", ...],
)
metrics = tuner.train()
print(f"Accuracy: {metrics['eval_accuracy']}")
tuner.save_model("./my-classifier")LoRA (Low-Rank Adaptation) freezes the base model and injects small trainable matrices into attention layers. Benefits:
config = FineTuningConfig(
model_name="bert-large-uncased",
use_peft=True,
lora_r=8, # Rank — lower = fewer params, less expressive
lora_alpha=16, # Scaling factor — typically 2x lora_r
lora_dropout=0.05, # Regularization
lora_target_modules=["query", "value"], # Which attention matrices
learning_rate=3e-4, # LoRA uses higher LR than full fine-tuning
num_epochs=5,
batch_size=8,
gradient_accumulation_steps=4, # Effective batch = 32
fp16=True,
)| Rank (r) | Trainable Params | Use Case |
|---|---|---|
| 4 | ~0.3% of total | Small dataset (<1k), overfitting risk |
| 8 | ~0.6% of total | Default — good balance |
| 16 | ~1.2% of total | Larger datasets, complex tasks |
| 32 | ~2.4% of total | When you need near-full-fine-tune quality |
| 64+ | ~5%+ of total | Rarely needed — consider full fine-tuning |
The kit provides two schedulers, both matching Hugging Face Trainer behavior:
LR
│ /‾‾‾‾‾‾‾‾‾‾‾‾\
│ / \
│/ \
└──────────────────── Steps
warmup decay
Good for most tasks. The warmup prevents early training instability.
LR
│ /‾‾‾‾‾\_
│ / ‾‾\_
│/ ‾‾‾‾
└──────────────────── Steps
warmup cosine decay
Better for longer training runs. The gradual decay lets the model explore longer before converging.
| Dataset Size | Epochs | LR | Batch Size | Weight Decay |
|---|---|---|---|---|
| < 500 | 10-20 | 1e-5 | 8 | 0.1 |
| 500-5k | 3-5 | 2e-5 | 16 | 0.01 |
| 5k-50k | 2-3 | 3e-5 | 32 | 0.01 |
| 50k+ | 1-2 | 5e-5 | 64+ | 0.001 |
If your GPU cannot fit batch_size=32, use gradient accumulation:
batch_size=8,
gradient_accumulation_steps=4, # Effective batch = 8 × 4 = 32The optimizer updates after accumulating gradients from 4 mini-batches, giving the same training dynamics as a larger batch without the memory cost.
Always evaluate during training to catch overfitting early:
config = FineTuningConfig(
eval_strategy="epoch", # Evaluate after each epoch
save_strategy="epoch", # Save checkpoint after each epoch
save_total_limit=3, # Keep only 3 most recent checkpoints
)Watch for:
1. Using the wrong casing. If you're doing NER, use a cased model (bert-base-cased). Uncased models lose important entity signals.
2. Too many epochs on small data. With <1000 examples, 3 epochs of full fine-tuning will overfit. Use LoRA or early stopping.
3. Not shuffling training data. If all positive examples come before negative examples, the model learns order, not content. Hugging Face Trainer shuffles by default.
4. Ignoring class imbalance. If 90% of your data is one class, the model will just predict that class. Use weighted loss or oversample the minority class.
5. Not saving the tokenizer. When you save a fine-tuned model, always save the tokenizer too — it defines how text is converted to input IDs.
Get the full NLP Starter Kit and unlock everything.
Get the complete guide with every chapter unlocked, including code samples, diagrams, and best practices.
Access all interactive tools with complete data, all workload profiles, and the full scenario library.
Downloadable source code, configuration files, and working examples from every chapter.
Free updates for life. Every new chapter, tool, and improvement included.