RLHF and Preference Tuning¶
What You'll Learn¶
| Objective | Time | Difficulty |
|---|---|---|
| Understand the full RLHF pipeline | 45 min | Advanced |
| Compare RLHF, DPO, and other alignment methods | ||
| Prepare preference datasets | ||
| Implement DPO training with TRL |
Why Preference Tuning?¶
Supervised fine-tuning (SFT) teaches a model what to say. Preference tuning teaches it how to say it — aligning outputs with human preferences for helpfulness, safety, and quality.
SFT: "Here is a good response. Learn to generate this."
RLHF/DPO: "Here are two responses. This one is better. Learn why."
This is how ChatGPT, Claude, and other chat models were trained to be helpful and safe.
The RLHF Pipeline¶
Step 1: Supervised Fine-Tuning (SFT)¶
Train the base model on high-quality instruction-response pairs (what we covered in Lessons 2-4).
Step 2: Reward Model Training¶
Train a separate model to predict human preferences:
The reward model learns from human comparisons: - Show annotators two responses to the same prompt - They pick which one is better - Train the reward model to assign higher scores to preferred responses
Step 3: RL Optimization (PPO)¶
Use the reward model to guide further training via Proximal Policy Optimization:
For each training prompt:
1. Generate a response with the current model
2. Score it with the reward model
3. Update the model to increase reward
4. Add KL penalty to prevent diverging too far from SFT model
The Challenge with RLHF¶
RLHF is powerful but complex: - Requires training three models (SFT, reward, policy) - PPO is unstable and sensitive to hyperparameters - Reward hacking: model finds exploits in the reward model - Expensive: needs significant compute and human annotation
DPO: A Simpler Alternative¶
Direct Preference Optimization (DPO) achieves similar results without a reward model or RL.
How DPO Works¶
Instead of training a reward model and then doing RL, DPO directly optimizes the language model on preference pairs:
For each training example:
- Prompt: "Explain quantum computing"
- Chosen response: (the human-preferred response)
- Rejected response: (the less preferred response)
DPO loss pushes the model to:
- Increase probability of chosen response
- Decrease probability of rejected response
DPO vs RLHF¶
| Aspect | RLHF (PPO) | DPO |
|---|---|---|
| Models needed | 3 (SFT + reward + policy) | 1 (just the policy model) |
| Stability | Unstable, needs tuning | Stable, straightforward |
| Compute cost | High (RL loop) | Lower (standard training) |
| Quality | Slightly better in some cases | Comparable for most tasks |
| Complexity | Very high | Moderate |
Preparing Preference Data¶
Data Format¶
{
"prompt": "What causes rain?",
"chosen": "Rain forms when water vapor in the atmosphere condenses into droplets. As warm, moist air rises and cools, the water vapor reaches its dew point and forms clouds. When droplets combine and become heavy enough, they fall as precipitation.",
"rejected": "Rain is water that falls from the sky. It happens because of clouds. The water cycle is involved somehow."
}
Sources of Preference Data¶
- Human annotation: Most reliable, most expensive
- AI feedback: Use a stronger model to rank responses
- Existing datasets: UltraFeedback, HH-RLHF, Nectar
- Implicit signals: User upvotes/downvotes, regeneration requests
Generating Preference Data with AI¶
from openai import OpenAI
import json
client = OpenAI()
def generate_preference_pair(prompt, num_candidates=4):
"""Generate multiple responses and use GPT-4.1 to rank them."""
# Generate candidates with different temperatures
candidates = []
for temp in [0.3, 0.7, 1.0, 1.2]:
response = client.chat.completions.create(
model="gpt-4.1-mini",
messages=[{"role": "user", "content": prompt}],
temperature=temp
)
candidates.append(response.choices[0].message.content)
# Use GPT-4.1 to rank them
ranking_prompt = f"""Rank these {len(candidates)} responses to the prompt: "{prompt}"
{chr(10).join(f'Response {i+1}: {c}' for i, c in enumerate(candidates))}
Return JSON: {{"best": <index>, "worst": <index>, "reasoning": "..."}}"""
ranking = client.chat.completions.create(
model="gpt-4.1",
messages=[{"role": "user", "content": ranking_prompt}],
temperature=0,
response_format={"type": "json_object"}
)
result = json.loads(ranking.choices[0].message.content)
return {
"prompt": prompt,
"chosen": candidates[result["best"] - 1],
"rejected": candidates[result["worst"] - 1]
}
Implementing DPO with TRL¶
from trl import DPOTrainer, DPOConfig
from transformers import AutoModelForCausalLM, AutoTokenizer
from datasets import load_dataset
from peft import LoraConfig
# Load model (start from your SFT model)
model_name = "./my-sft-model" # Your supervised fine-tuned model
model = AutoModelForCausalLM.from_pretrained(model_name, torch_dtype="auto", device_map="auto")
tokenizer = AutoTokenizer.from_pretrained(model_name)
tokenizer.pad_token = tokenizer.eos_token
# Load preference dataset
dataset = load_dataset("json", data_files="preferences.jsonl", split="train")
# LoRA config for DPO (train efficiently)
peft_config = LoraConfig(
r=16,
lora_alpha=32,
target_modules=["q_proj", "k_proj", "v_proj", "o_proj"],
lora_dropout=0.05,
task_type="CAUSAL_LM",
)
# DPO training config
dpo_config = DPOConfig(
output_dir="./dpo-model",
num_train_epochs=1,
per_device_train_batch_size=2,
gradient_accumulation_steps=4,
learning_rate=5e-5,
beta=0.1, # Controls strength of preference (higher = more conservative)
logging_steps=10,
save_strategy="epoch",
bf16=True,
max_length=1024,
max_prompt_length=512,
)
# Create DPO trainer
trainer = DPOTrainer(
model=model,
args=dpo_config,
train_dataset=dataset,
processing_class=tokenizer,
peft_config=peft_config,
)
# Train
trainer.train()
trainer.save_model("./dpo-model")
Key Hyperparameter: Beta¶
The beta parameter controls how strongly the model follows preferences:
| Beta | Effect |
|---|---|
| 0.05 | Strong preference following (risk of overfit) |
| 0.1 | Good default for most tasks |
| 0.2 | Conservative (safer, less dramatic changes) |
| 0.5 | Very conservative (minimal behavior change) |
Resources¶
- DPO Paper: "Direct Preference Optimization: Your Language Model is Secretly a Reward Model" (Rafailov et al., 2023)
- RLHF Paper: "Training Language Models to Follow Instructions with Human Feedback" (Ouyang et al., 2022)
- TRL Documentation: huggingface.co/docs/trl/dpo_trainer
- UltraFeedback Dataset: Large-scale AI preference dataset on Hugging Face
Key Takeaways¶
- RLHF is the gold standard for alignment but complex (3 models, RL training loop)
- DPO achieves comparable results with just preference pairs and standard training
- Preference data needs a chosen (good) and rejected (bad) response for each prompt
- Use AI feedback from stronger models to generate preference data at scale
- Start with
beta=0.1and adjust based on how aggressively you want to shift behavior
Next Lesson¶
Lesson 8: Deploying Fine-Tuned Models — Learn to serve your fine-tuned models in production with vLLM, TGI, and cloud inference platforms.