|$ curl https://forge-ai.dev/api/markdown?path=docs/ai/training-methods
$cat docs/sft-/-dpo-/-rlhf.md
updated Recentlyยท40 min readยทpublished

SFT / DPO / RLHF

โ—†AIโ—†Advanced
Introduction

Modern LLMs are trained through a multi-stage pipeline that typically begins with pre-training on massive web corpora, followed by supervised fine-tuning (SFT), and then alignment through preference optimization (DPO, RLHF) or reinforcement learning. Each stage serves a distinct purpose in shaping model behavior.

SFT teaches the model to follow instructions and produce coherent completions. DPO directly optimizes for human preferences without a separate reward model. RLHF introduces a learned reward model to guide the policy through reinforcement learning (PPO). Understanding when and how to use each method is critical for building aligned, capable models.

This guide provides a detailed comparison of these training paradigms, with practical code examples for implementing each approach using established libraries and frameworks.

Supervised Fine-Tuning (SFT)

SFT is the first post-training stage for most LLMs. The pre-trained base model is fine-tuned on high-quality instruction-response pairs to learn the format and style of helpful conversation. SFT uses standard autoregressive language modeling with cross-entropy loss computed only on the response tokens.

Key characteristics of SFT include: teacher forcing (the model sees the correct response during training), maximum likelihood estimation (MLE) objective, and label masking to exclude prompt tokens from loss computation. SFT is simple, stable, and computationally efficient compared to RL-based methods.

sft-trl.py
Python
1import torch
2from datasets import load_dataset
3from trl import SFTTrainer
4from transformers import TrainingArguments, AutoModelForCausalLM, AutoTokenizer
5
6model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-3.2-3B")
7tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-3.2-3B")
8tokenizer.pad_token = tokenizer.eos_token
9
10dataset = load_dataset("json", data_files="training_data.jsonl")
11
12training_args = TrainingArguments(
13 output_dir="./sft-model",
14 per_device_train_batch_size=4,
15 gradient_accumulation_steps=4,
16 learning_rate=2e-4,
17 warmup_steps=100,
18 num_train_epochs=3,
19 logging_steps=25,
20 save_strategy="epoch",
21 bf16=True,
22 report_to="wandb"
23)
24
25trainer = SFTTrainer(
26 model=model,
27 args=training_args,
28 train_dataset=dataset["train"],
29 tokenizer=tokenizer,
30 max_seq_length=2048,
31 dataset_text_field="text",
32)
33
34trainer.train()
โœ“

best practice

Use the TRL library's SFTTrainer for SFT โ€” it handles chat template formatting, label masking, and packing (concatenating multiple short examples into one sequence for efficiency) automatically. This reduces boilerplate and prevents common errors like computing loss on prompt tokens.
Direct Preference Optimization (DPO)

DPO is a preference optimization method that directly optimizes the policy from pairwise preference data without training a separate reward model. It reformulates the RLHF objective into a simple binary classification loss that compares the likelihood of chosen vs rejected responses under the trained policy, relative to a reference model.

The DPO loss function takes the form: -log(sigmoid(beta * (log(pi(y_w|x)/pi_ref(y_w|x)) - log(pi(y_l|x)/pi_ref(y_l|x))))) where y_w is the preferred response, y_l is the dispreferred response, pi is the trained policy, and pi_ref is the frozen reference model. The beta parameter controls how far the policy can deviate from the reference.

PropertyDPORLHF (PPO)
Reward ModelNot neededRequired (separate model)
Training StabilityHighModerate โ€” sensitive to KL penalty
Computational CostLow (2 forward passes)High (RL loop + reward model)
Data EfficiencyHighModerate
Online SamplingNo (offline)Yes (on-policy)

DPO Training Implementation

dpo-training.py
Python
1from trl import DPOTrainer
2from datasets import Dataset
3
4# Preference dataset format
5preference_data = [
6 {
7 "prompt": "Explain quantum computing",
8 "chosen": "Quantum computing uses qubits that can exist in superposition...",
9 "rejected": "Quantum computing is when computers are really fast..."
10 },
11]
12
13dataset = Dataset.from_list(preference_data)
14
15dpo_trainer = DPOTrainer(
16 model=model,
17 ref_model=None, # Auto-initialized from model
18 args=training_args,
19 train_dataset=dataset,
20 tokenizer=tokenizer,
21 beta=0.1, # KL divergence coefficient
22 max_length=2048,
23 max_prompt_length=512,
24)
25
26dpo_trainer.train()
๐Ÿ”ฅ

pro tip

The beta parameter in DPO controls how much the policy can diverge from the reference model. Lower beta (0.01-0.05) allows more deviation and stronger preference optimization but risks overfitting to the preference data. Higher beta (0.1-0.5) keeps the model closer to the SFT checkpoint. Start with beta=0.1.
Reinforcement Learning from Human Feedback (RLHF)

RLHF is the three-stage pipeline pioneered by InstructGPT that consists of: (1) SFT on human demonstrations, (2) training a reward model on human preferences, and (3) optimizing the policy against the reward model using PPO. This approach allows the model to generate novel responses that are optimized for human preferences, not just imitate the training data.

Stage 1: Reward Model Training

The reward model is trained on comparison data โ€” pairs of responses where one is preferred over the other. It learns to assign higher scores to preferred responses. The reward model is typically initialized from the same base model as the policy but with a scalar output head replacing the language modeling head.

reward-model.py
Python
1import torch.nn as nn
2from transformers import AutoModelForSequenceClassification
3
4reward_model = AutoModelForSequenceClassification.from_pretrained(
5 "meta-llama/Llama-3.2-3B",
6 num_labels=1, # Single scalar reward
7 torch_dtype=torch.bfloat16
8)
9
10# Reward model training loop
11optimizer = torch.optim.AdamW(reward_model.parameters(), lr=1e-5)
12
13for batch in dataloader:
14 chosen_rewards = reward_model(batch["chosen_ids"]).logits
15 rejected_rewards = reward_model(batch["rejected_ids"]).logits
16
17 # Bradley-Terry preference loss
18 loss = -nn.functional.logsigmoid(
19 chosen_rewards - rejected_rewards
20 ).mean()
21
22 loss.backward()
23 optimizer.step()

Stage 2: PPO Training

PPO (Proximal Policy Optimization) optimizes the policy model to maximize the reward signal from the reward model while staying close to the reference model via a KL divergence penalty. This prevents the policy from exploiting the reward model by generating nonsensical but high-scoring text.

ppo-training.py
Python
1from trl import PPOConfig, PPOTrainer
2from trl.core import LengthSampler
3
4ppo_config = PPOConfig(
5 model_name="meta-llama/Llama-3.2-3B",
6 learning_rate=1.41e-5,
7 batch_size=16,
8 mini_batch_size=4,
9 gradient_accumulation_steps=1,
10 ppo_epochs=4,
11 kl_penalty=0.05,
12 clip_range=0.2,
13 init_kl_coef=0.05,
14 target_kl=0.1,
15)
16
17# Setup PPO trainer
18ppo_trainer = PPOTrainer(
19 config=ppo_config,
20 model=model,
21 ref_model=ref_model,
22 tokenizer=tokenizer,
23 dataset=dataset,
24)
25
26# PPO training step
27for query_tensors, response_tensors in ppo_trainer.dataloader:
28 rewards = reward_model(
29 torch.cat([query_tensors, response_tensors], dim=-1)
30 ).logits
31
32 stats = ppo_trainer.step(query_tensors, response_tensors, rewards)
33 ppo_trainer.log_stats(stats)
โš 

warning

PPO is sensitive to hyperparameters and reward scale. Monitor the KL divergence between the policy and reference model โ€” if it spikes, the model is moving too fast and generating potentially degenerate outputs. The target_kl parameter should be adjusted based on the reward scale. Always normalize rewards to unit variance before PPO updates.
Method Comparison & Selection Guide

Choosing between SFT, DPO, and RLHF depends on your data, compute budget, and quality requirements. SFT is the minimum viable alignment method. DPO offers a practical middle ground. RLHF provides the highest potential quality but at significantly greater complexity and cost.

โ—†SFT โ€” Use when you have high-quality demonstrations and want to teach format, style, or basic instruction following. Fastest path to a functional model.
โ—†DPO โ€” Use when you have pairwise preference data and want to align without training a reward model. Good for most preference optimization scenarios.
โ—†RLHF / PPO โ€” Use when you have a high-quality reward model and need online exploration. Best for complex tasks where simple imitation is insufficient.
โ—†Iterative DPO โ€” Use online DPO variants (online DPO, iterative DPO) when you can generate new samples during training. Combines DPO simplicity with RL-like exploration.
Preference Datasets

Preference datasets are the fuel for both DPO and RLHF. Each example consists of a prompt, a chosen (preferred) response, and a rejected (dispreferred) response. High-quality preference data is difficult and expensive to collect, often requiring human annotators with domain expertise.

Common sources of preference data include: human annotation (labelers compare model outputs), AI feedback (another LLM judges outputs), implicit feedback (user clicks, dwell time), and synthetic data (using a reward model to rank candidates).

DatasetSizeSourceUse Case
Anthropic HH-RLHF170KHuman feedbackHarmlessness, helpfulness
OpenAI Summarize93KHuman comparisonsSummarization alignment
UltraFeedback64KGPT-4 feedbackGeneral preference
Nectar183KGPT-4 rankedMulti-task alignment
โ„น

info

When collecting your own preference data, ensure annotators agree on criteria (helpfulness, harmlessness, accuracy). Use inter-annotator agreement metrics (Krippendorff's alpha, Cohen's kappa) to measure annotation quality. Low agreement suggests unclear criteria or difficult examples that should be filtered.
$Blueprint โ€” Engineering DocumentationยทSection ID: AI-TM-01ยทRevision: 1.0