RLHF(Reinforcement Learning from Human Feedback)은 인간의 피드백을 바탕으로 언어 모델을 최적화시키는 대표적인 방식이다. 이때, 학습 방식은 크게 두 가지로 나눌 수 있는데,
으로 나눌 수 있다.
이번 포스팅에서 알아볼 Direct Preference Optimization(이하 DPO) 학습 방식은 명시적이 듯, 두 번째 방식에 해당되며, '직접적으로 선호도를 학습하는 최적화 기법'이다.
이러한 학습 방식이 제안된 배경은 다음과 같다:
기존의 RLHF에서는 보상 모델을 만들고, Proximal Policy Optimization(PPO)와 같은 알고리즘으로 fine-tuning을 진행하였음.
이때,
이러한 문제점을 해결하기 위해, DPO는
이라는 개선점을 보이는 학습 방식이다.
💁 배경 지식 한 입.... 작지만 큰... 한 입....
강화학습과 RLHF
* 강화학습(Reinforcement Learning, RL)
Agent가 Environment와 상호작용하며 Reward를 최대화하는 행동을 학습하는 방식
이때, Agent는 학습 주체, Environment는 상호작용 대상으로 생각하면 쉽다.
(좀 더 쉬운 이해를 위해 아래에서 예시를 적용하겠다.)
이는 보상 신호를 최대화하는 정책(Policy)을 학습하는 것으로, 좋은 행동(Reward를 받는 행동)은 강화되며, 그렇지 않은 행동은 억제되는 식의 학습 방식이다.* RLHF(Reinforcement Learning from Human Feedback)
RL의 한 분야로, Environment의 Reward 대신 Human Feedback(Preference)을 이용해 Agent를 튜닝
e.g.,) LLM Tuning
인간이 A, B 두 응답 중 어떤 것이 더 좋은지 평가 → 이를 기반으로 보상 모델(RM)을 학습
이후 PPO 등을 사용해 LLM을 fine-tuning
(대표 사례) ChatGPT[RL Example]
- Agent: 학습 주체 (예: 로봇, AI, 아이)
- Environment: Agent가 상호작용하는 외부 시스템 (예: 게임, 교실)
- State: 현재 환경의 상태 정보 (예: 지금이 수학 시간인지 국어 시간인지)
- Action: Agent가 선택할 수 있는 행동들 (예: 손들기, 조용히 있기)
- Reward: 행동 결과로 받는 수치적 피드백 (예: 칭찬, 점수)
즉, RL은 환경 보상 기반이며 RLHF는 인간의 주관적 평가를 보상처럼 사용
* PPO(Proximal Policy Optimization)
OpenAI에서 제안한 정책 기반 RL 알고리즘으로, 기존 Policy를 너무 급격히 바꾸지 않도록 하여 학습 안정성과 효율성을 동시에 확보한 방식
- 주요 내용
- KL-divergence 또는 clip function을 사용해 policy update 제한
- 너무 급격한 정책 변화를 방지하여 안정적인 학습을 유도
- Loss Function
- : 정책 비율
- : Advantage function (이 행동이 얼마나 좋은지)
- : 정책이 급격히 바뀌는 것을 억제(비율이 범위를 넘지 않도록 제한)
- 장점
- 학습이 안정적이고 구현이 비교적 간단
- 많은 RL 적용 분야에서 기본 선택지로 사용됨(범용성 Good~)
LLM에 인간의 선호도를 반영한 응답 생성을 직접 최적화하기 위함이다.
PPO보다 더 안정적이고 간단하며, 효율적인 학습을 가능하게 함.
한 줄 요약: 사용자 또는 평가자가 선호하는 응답(A)와 그렇지 않은 응답(B)이 있을 때, 모델이 A를 더 높은 확률로 생성하도록 학습하는 방식
DPO는 (입력 x, 선호 응답 y, 비선호 응답 y-)의 삼중쌍을 사용한다.
즉, 사용자 또는 평가자가 응답 A를 B보다 선호한다고 판단할 경우, 모델은 A를 더 높은 확률로 생성하도록 학습하는 방식이다.
이를 위해, DPO는 아래와 같은 loss를 최소화한다.
Loss Function:
이때,
- : 현재 모델이 입력 x에 대해 출력 y를 생성할 확률
- : 선호, 비선호 응답
- 는
tempHyper-Parmeter으로, 선택성(sharpness)을 조절
이 식은 로지스틱 회귀(Logistic Regression) 기반 확률 모델과 유사한 식 형태를 가지며, 선호 응답이 더 높은 확률을 가지도록 모델을 업데이트하는 방향으로 학습된다.
1. Win Rate/Preference Accuracy
평가자 혹은 GPT가 생성된 응답 A와 B 중 선호하는 답변을 투표
DPO로 학습한 모델의 응답이 기존 SFT나 모델보다 더 많이 선택되면 우수한 성능으로 판단
평가 방식:
• 각 질문에 대해 SFT, PPO, DPO 등 여러 모델의 응답을 생성
• 평가자 또는 GPT-4가 어떤 응답을 더 선호하는지 선택
• DPO 응답이 더 많이 선택된 비율 = Win rate
2. Pairwise Accuracy/Agreement Rate
수식:
3. Language Quality Metrics
보통은 직접 평가가 아니지만, 생성 텍스트 퀄리티도 참고하기도 함
- BLEU, ROUGE
- BERTScore, BLEURT
- Toxicity Score: 응답이 공격/차별적 표현을 포함하는지 확인하기 위함
1. GPT-4 등 LLM 기반 평가자 사용
사람 대신 GPT-4에게 각 응답에 대해 다음 기준을 평가하게 함:
- Helpfulness (도움이 되는가?)
- Relevance (질문과 관련 있는가?)
- Correctness (사실 기반인가?)
- Harmlessness (독성/편향이 없는가?)
2. Human Evaluation
from transformers import AutoTokenizer, AutoModelForCausalLM, TrainingArguments
from trl import DPOTrainer
from datasets import load_dataset
import torch
# 1. Load model & tokenizer
model_name = "meta-llama/Llama-2-7b-hf" # HuggingFace Model
tokenizer = AutoTokenizer.from_pretrained(model_name, use_fast=True)
model = AutoModelForCausalLM.from_pretrained(
model_name,
torch_dtype=torch.bfloat16, # 혼합정밀도 가속
device_map="auto"
)
# 2. Define TrainingArguments
training_args = TrainingArguments(
output_dir="./dpo-checkpoints",
per_device_train_batch_size=2,
per_device_eval_batch_size=2,
gradient_accumulation_steps=8,
num_train_epochs=3,
learning_rate=5e-6,
logging_dir="./logs",
logging_steps=10,
save_strategy="epoch",
eval_strategy="steps",
eval_steps=100,
report_to="wandb",
)
# 3. Define triplet dataset: (prompt, chosen, rejected)
# Must be a HuggingFace `Dataset` object with columns: prompt, chosen, rejected
from datasets import Dataset
triplet_data = [
{
"prompt": "Explain the theory of relativity.",
"chosen": "The theory of relativity, developed by Einstein, includes the special and general theories...",
"rejected": "Relativity is when things are related, like people in a family."
},
...
]
triplet_dataset = Dataset.from_list(triplet_data)
# 4. Initialize DPOTrainer
dpo_trainer = DPOTrainer(
model=model,
tokenizer=tokenizer,
args=training_args,
beta=0.1, # temp: sharpness of preference
train_dataset=triplet_dataset
)
# 5. Start training
dpo_trainer.train()
이때,
from transformers import pipeline
pipe = pipeline("text-generation", model="./final-dpo-model", tokenizer=tokenizer)
pipe("Why is the sky blue?", max_new_tokens=50)