Part I: DPO 이해와 해부


Chapter 1: DPO는 무엇을 하는가 — SFT에서 한 걸음씩

이미 알고 있는 것에서 출발하자

DPO를 이해하는 가장 빠른 길은 SFT(Supervised Finetuning)에서 출발하는 것이다. SFT를 알고 있다면, RL까지는 세 걸음이면 된다.

[SFT — 당신이 이미 아는 것]

  데이터: (프롬프트, 좋은 응답) 쌍의 모음
  학습: 좋은 응답의 확률을 올린다
  손실: −log P_θ(y|x)  ← NLL 손실

  이것만으로 모델은 꽤 잘 작동한다.
  하지만 한계가 있다: 약 90% 신뢰도에서 정체한다.
  10번 중 1번은 반복 루프에 빠지거나 엉뚱한 답을 낸다.
  SFT는 "무엇이 좋은가"만 가르치고 "무엇이 나쁜가"는 가르치지 않기 때문이다.

첫 번째 걸음: 나쁜 예제를 추가한다

[SFT + 음성 예제]

  데이터: (프롬프트, 좋은 응답, 나쁜 응답)
  학습: 좋은 응답의 확률은 올리고, 나쁜 응답의 확률은 내린다

  프롬프트: "대한민국의 수도는?"
  좋은 응답: "서울입니다."    → 확률 ↑
  나쁜 응답: "부산입니다."    → 확률 ↓

  SFT와 RL의 경계는 사실 여기다.
  음성 예제가 들어오는 순간, SFT는 RL이 된다.

두 번째 걸음: 원본에서 너무 멀어지지 않게 줄을 묶는다

[SFT + 음성 예제 + KL 제약]

  문제: 좋은 응답을 올리고 나쁜 응답을 내리다 보면
        모델이 원래 갖고 있던 능력까지 잊어버린다.
        "서울"만 미친 듯이 강화하다가 다른 모든 질문에도 "서울"이라 답한다.

  해결: 원본 모델(레퍼런스)과 너무 달라지면 벌점을 준다.
        KL(π_θ ‖ π_ref) — "지금 모델이 원본에서 얼마나 벗어났는가"

  → 음성 예제: "나쁜 것에서 멀어져라"
  → KL 제약: "하지만 원본에서 너무 멀어지진 마라"

여기까지가 RL의 직관적 토대다. 이제 DPO의 수식을 볼 준비가 됐다.

자연스러운 오해: “좋은 건 올리고 나쁜 건 내리면 끝 아닌가?”

미묘한 오해:
  "DPO는 좋은 응답의 확률을 올리고 나쁜 응답의 확률을 내리는 것이다."

이것이 아주 틀린 답은 아니지만 부족한 이유:
  모델이 이미 좋은 응답에 99%, 나쁜 응답에 1%를 부여하고 있다면?
  → "좋은 건 올리고 나쁜 건 내리기"로는 할 일이 거의 없다.
  → 하지만 모델은 여전히 문제가 있을 수 있다.

  반대로, 모델이 두 응답에 50%, 50%를 주고 있다면?
  → 둘 다 같은 확률인데, 원본 모델도 50:50이었다면,
     그건 이미 원본 수준이지 개선이 아니다.

핵심: 절대 확률이 아니라 "원본 대비 얼마나 더 벌렸는가"가 중요하다.

DPO의 진짜 논리:

레퍼런스 대비
모델의 마진을 벌린다

이제 수식을 보자. 한 줄이다:

L_DPO = −log σ( β × (Δ_θ − Δ_ref) )

여기서:
  Δ_θ   = log π_θ(y_w|x) − log π_θ(y_l|x)   ← 학습 모델의 선호마진
  Δ_ref  = log π_ref(y_w|x) − log π_ref(y_l|x) ← 원본 모델의 선호마진

이 수식이 하는 일을 한국어로 풀면:

1. 학습 모델이 보는 선호마진 (Δ_θ):
   "지금 내가 좋은 답과 나쁜 답 사이에 얼마나 차이를 두고 있는가?"

2. 원본 모델이 보는 선호마진 (Δ_ref):
   "원래 모델은 이 차이를 얼마로 보고 있었는가?"

3. 둘의 차이 (Δ_θ − Δ_ref):
   "원본 대비 내가 선호마진을 얼마나 더 벌렸는가?"

4. 이 차이를 σ(시그모이드)에 통과:
   → 양수면 σ > 0.5 → −log σ가 작아짐 → 손실 작음 → 잘하고 있다
   → 음수면 σ < 0.5 → −log σ가 커짐 → 손실 큼 → 더 벌려야 한다
   → 0이면 σ = 0.5 → −log(0.5) = 0.693 → 아직 할 일이 있다!

장난감 예제: 왜 "절대 확률"이 아니라 "상대 마진"인가

상황 A: 레퍼런스모델이 이미 잘 구분하는 경우

  π_ref: P(서울) = 0.9,  P(부산) = 0.1  → Δ_ref = log(0.9) − log(0.1) = 2.2
  π_θ:   P(서울) = 0.95, P(부산) = 0.05 → Δ_θ   = log(0.95) − log(0.05) = 2.9

  Δ_θ − Δ_ref = 2.9 − 2.2 = +0.7
  → 레퍼런스모델보다 마진을 0.7만큼 더 벌렸다. 좋다!
상황 B: 레퍼런스모델이 구분 못하는 경우

  π_ref: P(서울) = 0.5,  P(부산) = 0.5  → Δ_ref = 0
  π_θ:   P(서울) = 0.5,  P(부산) = 0.5  → Δ_θ   = 0

  Δ_θ − Δ_ref = 0 − 0 = 0
  L = −log σ(0) = −log(0.5) = 0.693
  → 손실이 0이 아니다! 그래디언트가 살아 있다.
  → "레퍼런스모델도 모르고 나도 모르지만, 나는 더 벌려야 한다."
상황 C: "절대 확률만 올리기"가 실패하는 경우

  π_ref: P(서울) = 0.70, P(부산) = 0.01 → Δ_ref = log(0.70) − log(0.01) = 4.2
  π_θ:   P(서울) = 0.80, P(부산) = 0.05 → Δ_θ   = log(0.80) − log(0.05) = 2.8

  절대 확률만 보면: "서울이 70%에서 80%로 올랐으니 개선 아닌가?"
  마진으로 보면: Δ_θ − Δ_ref = 2.8 − 4.2 = −1.4
  → 부산도 1%에서 5%로 따라 올랐다. 하지만 마진은 오히려 줄었다!
  → "좋은 답의 확률은 올랐지만, 나쁜 답도 덩달아 올라서 구분력은 후퇴했다."

아래 그래프가 세 상황의 마진을 시각적으로 비교한다:

레퍼런스 마진 vs 학습 모델 마진 마진 (Δ) 5 2.5 0 Δ_ref 2.2 Δ_θ 2.9 +0.7 상황 A 좋다! Δ_ref=0 Δ_θ=0 0 상황 B L=0.693, 아직 할 일 있음 Δ_ref 4.2 Δ_θ 2.8 -1.4 상황 C 확률↑인데 손실 큼!

직관에서 수식으로: 세 걸음의 대응

직관 수식의 대응
좋은 응답 확률 올리기 log π_θ(y_w) ↑
나쁜 응답 확률 내리기 log π_θ(y_l) ↓
→ 이 둘의 합: 마진 벌리기 → Δ_θ = log π_θ(y_w) − log π_θ(y_l)
원본에서 멀어지지 마라 (KL) 레퍼런스 기준으로 상대화
→ "얼마나 벌렸는가"가 아니라 “원본 대비 얼마나 더” → (Δ_θ − Δ_ref): “원본보다 얼마나 더”
β (온도 파라미터) 줄의 길이
→ β 크면 보수적 학습 → 큰 β = 짧은 줄 = 원본 근처
→ β 작으면 공격적 학습 → 작은 β = 긴 줄 = 멀리 갈 수 있다

이것이 DPO의 핵심이다. 좋은 답의 절대 확률을 높이는 것이 아니라, 원본 대비 선호/비선호 사이의 상대적 마진을 벌리는 것.


다음 장으로의 질문

DPO가 마진을 벌린다는 것을 이해했다. 그렇다면 모든 선호/비선호 쌍이 똑같이 유용한가? 어떤 쌍이 학습 시그널을 만들고, 어떤 쌍이 낭비인가?