Chapter 2: 선호 쌍의 조건 — 어떤 데이터가 DPO를 움직이는가

Ch1에서 DPO의 핵심을 이해했다: 레퍼런스 대비 선호마진을 벌리는 것. 이제 질문은 "어떤 데이터가 이 마진을 의미 있게 만드는가?"다.

그래서 어떤 쌍이 좋은 쌍인가?

DPO가 “마진을 벌리는” 알고리즘이라면, 마진을 벌리는 것이 의미 있으려면 비선호 응답(yly_l)이 특정 조건을 갖춰야 한다. 이것은 좋은 DPO 데이타셋을 만드는 핵심 직관이다. 꼭 기억해두자.

극단적인 쌍 세 개를 비교해보자:

질문: “대한민국의 수도는?”

[쌍 A] ywy_w = “서울입니다” vs yly_l = “zxcgbhjdf” (극단적인 저품질 데이타)

이 쌍에서 DPO가 하는 일:
"서울입니다"의 확률을 올리고, "zxcgbhjdf"의 확률을 내린다.

문제점:
모델은 이미 "zxcgbhjdf"에 거의 0에 가까운 확률을 부여하고 있다.
레퍼런스 대비 마진? 이미 충분히 벌려져 있다.
→ σ(β × (Δ_θ − Δ_ref)) ≈ 1 → 그래디언트 ≈ 0
→ 이 쌍에서 모델은 아무것도 배우지 못한다.

이 쌍이 가르치는 것:
“삐꾸를 생성하지 마라” — 하지만 모델은 원래 그러지 않는다.
SFT로 "서울입니다"만 보여줘도 동일한 효과.
→ DPO를 쓴 이점이 전혀 없다.

[쌍 B] ywy_w = “서울입니다” vs yly_l = “부산입니다”

이 쌍에서 DPO가 하는 일:
"서울"과 “부산” 사이의 마진을 벌린다.

"부산입니다"는:

  • ✓ 문법적으로 완벽하다
  • ✓ 형식도 정확하다 ("~입니다"로 끝남)
  • ✓ 그럴듯하다 — 부산도 대한민국의 대도시니까
  • ✗ 하지만 틀렸다

→ 모델이 "부산"에도 상당한 확률을 부여하고 있을 수 있다.
→ 마진이 좁다 → 그래디언트가 크다 → 학습 시그널이 강하다.
DPO가 진짜 일을 하는 쌍이다.

[쌍 C] ywy_w = “서울입니다” vs yly_l = “서울은 대한민국의 수도이며, 한반도 중부에…”

이 쌍에서 DPO가 하는 일:
간결한 답과 장황한 답 사이의 마진을 벌린다.

"서울은 대한민국의 수도이며…"는:

  • ✓ 사실적으로 정확하다
  • ✓ 문법도 좋다
  • ✗ 하지만 질문에 비해 불필요하게 길다

→ 둘 다 "맞는 답"이지만 스타일이 다르다.
→ 이런 쌍은 정확성이 아니라 "어떤 스타일이 선호되는가"를 가르친다.
DPO가 SFT로 불가능한 일을 하는 쌍이다.

이 세 쌍의 비교에서 원칙이 나온다:

좋은 DPO 쌍의 조건

1. yly_l이 “그럴듯해야” 한다 (plausible)
→ 모델이 실제로 생성할 법한 응답이어야 한다.
→ 모델이 이미 0에 가까운 확률을 부여하는 응답은 쓸모없다.
→ 비선호 응답에 삐꾸, 난수, 빈 응답이 들어간다면? = SFT로 충분.

2. ywy_wyly_l이 “의미 있게 달라야” 한다 (informative margin)
→ 둘의 차이가 모델이 배워야 할 판단 기준을 담고 있어야 한다.
→ “서울 vs 부산” = 사실 정확성의 판단 기준
→ “간결 vs 장황” = 스타일의 판단 기준
→ “안전 vs 위험” = 안전성의 판단 기준

3. 마진이 적정해야 한다 (not too wide, not too narrow)
→ 너무 넓으면: 쌍 A처럼 그래디언트가 0 (이미 알고 있는 것)
→ 너무 좁으면: 노이즈에 가까워서 학습 방향이 불안정
→ JoyCaption이 10개 응답 중 최상/최하를 골라 마진을 확보한 이유

4. yly_l이 현재 모델(πref\pi_\text{ref})의 분포 안에 있어야 한다 (on-distribution)
→ 모델이 절대 생성하지 않을 응답으로 학습하면 = 분포 밖 데이터
→ Ch13에서 배울 "분포 이동"의 원인이 된다

이 네 번째 조건이 사실 가장 근본적이다. 그리고 DPO의 구조적 한계와 직결된다.

왜 "분포 안"이 중요한가 — 분포 관점에서의 설명

DPO는 오프라인이면서 오프폴리시인 알고리즘이다.

오프라인(offline): 학습 중에 새 데이터를 생성하지 않는다. 데이터셋은 학습 전에 미리 만들어둔 것이다.
오프폴리시(off-policy): 데이터를 만든 정책 ≠ 지금 학습 중인 정책. 다른 모델(또는 과거의 자기 자신)이 만든 데이터로 학습한다.

이 둘은 서로 다른 축이다:

온폴리시 오프폴리시
온라인 GRPO — 매 배치마다 현재 모델이 생성 Online DPO — 현재 모델이 생성하되, 업데이트 전 버전의 데이터도 섞어 씀
오프라인 이론적으로 가능하나 실익이 적음 DPO — 고정 데이터셋, 다른 모델이 생성

DPO의 데이터 품질 문제는 주로 "오프폴리시"에서 온다.
데이터 갱신이 안 되는 문제는 "오프라인"에서 온다.
이 두 문제가 겹치기 때문에 DPO의 한계가 구조적이다.

그런데 이 데이터셋을 누가 만들었는가?
반드시 πref\pi_\text{ref}가 만든 것은 아니다:

데이터 생성 주체 예시 분포 일치 비유
경우 1 πref\pi_\text{ref} 자신이 생성 ✓ 일치. 가장 이상적 자기 오답노트로 공부
경우 2 같은 계열의 더 강한 모델 Llama-70B → Llama-7B 학습 △ 부분 일치 선배의 오답노트 — 겹치는 부분은 유용
경우 3 아예 다른 모델 GPT-4 → Llama 학습 ✗ 불일치 가능 다른 학교 학생의 오답노트 — 시험 범위가 다를 수 있다

UltraFeedback 같은 공개 데이터셋이 대표적인 경우 3이다. OpenAI GPT 계열이 생성한 응답으로 만들어졌지만 이 데이터셋으로 Llama, Mistral 등 완전히 다른 모델을 학습시킨다.

이것이 왜 문제인가:

GPT-4가 생성한 yly_l은 GPT-4의 분포 안에 있다.
하지만 Llama-7B의 분포 안에 있다는 보장은 없다.
→ Llama가 절대 생성하지 않을 응답을 "억제하라"고 학습시키는 셈
→ 없는 실수를 교정하라는 시그널 = 낭비이거나, 더 나쁘면 왜곡

학습 초기에도 이미 분포 불일치가 존재한다:
πθπrefπdata\pi_\theta \approx \pi_\text{ref} \neq \pi_\text{data} (데이터 생성 모델)
→ 시작부터 off-distribution 데이터로 학습하는 것

학습이 진행되면 더 벌어진다:
πθ\pi_\thetaπref\pi_\text{ref}에서 점점 멀어짐
πdata\pi_\text{data}와의 거리는 더욱 커짐
→ 데이터셋의 yly_lπθ\pi_\theta에게는 점점 더 "외국어"가 됨
→ 학습 시그널이 소진된다

그런데도 경우 3이 실무에서 작동하는 이유:
GPT-4 수준의 응답 품질이 데이터 자체의 질을 높이기 때문.
분포 불일치의 비용을 데이터 품질의 이득이 상쇄한다.
— 하지만 이 상쇄에는 한계가 있고, 그 한계가 Ch13의 주제다.

온라인 + 온폴리시 RL이 더 양질의 시그널을 주는 이유

GRPO에서는 매 배치마다 현재 πθ\pi_\theta가 직접 응답을 생성한다.
온라인: 학습 중에 새 데이터를 계속 만든다.
온폴리시: 데이터를 만든 정책 = 지금 학습 중인 정책.

이것이 의미하는 바:

1. yly_l이 항상 "지금 모델이 실제로 저지르는 실수"다
→ 이미 졸업한 실수가 아니라, 지금 이 순간의 약점
→ 학습 시그널이 항상 최대한 유효하다

2. 마진이 자동으로 적정해진다
→ 현재 모델이 생성한 응답들 사이의 마진은 현재 모델의 불확실성을 반영한다
→ 쉬운 문제는 마진이 이미 크다 (시그널 약함 → 자연스럽게 건너뜀)
→ 어려운 문제는 마진이 좁다 (시그널 강함 → 여기서 배운다)
→ 마진 기반 큐레이션을 따로 할 필요가 없다 — 분포 자체가 큐레이션

3. 조건 1(“그럴듯해야 한다”)이 자동으로 충족된다
→ 현재 모델이 직접 생성한 것이니까, 당연히 그럴듯하다
→ 삐꾸 vs 정답 같은 쓸모없는 쌍이 나올 확률이 낮다

정리:

데이터 품질 조건 확보 대표 사례
오프라인·오프폴리시 (DPO) 데이터 큐레이션으로 수동 확보 JoyCaption의 6단계 파이프라인 (Ch12)
온라인·온폴리시 (GRPO) 분포의 성질에 의해 자동 충족 데이터 큐레이션 불필요 — 분포가 곧 큐레이션

→ 이것이 Ch10–15에서 다룰 핵심 서사의 예고:
DPO의 데이터 품질 문제(오프폴리시)와 데이터 고정 문제(오프라인)는 결국 GRPO의 자기 생성(온폴리시) + 실시간 갱신(온라인)으로 해결된다.

나쁜 쌍의 패턴 vs 좋은 쌍의 패턴

나쁜 쌍 ✗ 이유
정답 vs 삐꾸 SFT로 충분. DPO 낭비.
정답 vs 정답 마진이 거의 0. 학습 시그널 없음.
좋은 답 vs 모델이 절대 안 만들 답 분포 밖. 의미 없는 마진.
좋은 쌍 ✓ 학습 목표
정답 vs 그럴듯하지만 틀린 답 사실 정확성 학습
간결한 답 vs 장황한 답 스타일 학습
안전한 답 vs 미묘하게 위험한 답 안전성 경계 학습
삐꾸 없는 답 vs 미묘한 삐꾸 JoyCaption이 했던 것

그리고 DPO에는 잘 드러나지 않는 숨은 장점이 하나 더 있다:

DPO에는 보상 모델이 없다 — 따라서 해킹할 대상도 없다

PPO/RLHF에서 벌어지는 일:
보상 모델이 "좋다"고 판정하는 패턴을 모델이 학습한다.
하지만 보상 모델이 완벽하지 않으면, “보상은 높지만 실제로는 쓸모없는” 출력을 만들 수 있다.
이것을 리워드 해킹(reward hacking)이라 부른다.

예시:
보상 모델이 "길고 상세한 답변"을 높게 평가하도록 학습되었다면, 모델은 질문과 무관한 내용을 덧붙여서 답변을 길게 늘릴 수 있다.
→ 보상은 올라가지만, 실제 유용성은 떨어진다.
→ 사용자가 "대한민국의 수도는?"이라고 물었는데 3000자짜리 한국 지리 에세이가 나오는 상황.

DPO는 이 문제에서 구조적으로 자유롭다:
보상 함수가 없으니, 해킹할 대상이 없다.
데이터에 적힌 선호/비선호 쌍이 곧 보상이다.
→ 이것이 DPO가 "안전한 대안"으로 인기를 끈 또 다른 이유.

하지만 대가가 있다:
해킹할 수 없는 대신, 탐색도 할 수 없다 (오프라인·오프폴리시의 한계).
→ 이 트레이드오프가 Ch13–15에서 다시 등장한다.

리워드 해킹은 이 교재 전체에 걸쳐 반복적으로 등장하는 주제다.
Ch5(레퍼런스가 없으면), Ch7(보상을 스칼라로 축약하면), Ch13(온라인 학습의 드리프트), Ch16(디퓨전 모델의 CLIP 해킹), Ch17(에이전트가 지름길을 찾으면) — 형태는 다르지만 본질은 같다:
“불완전한 평가 기준을 최적화하면, 기준의 빈틈을 파고드는 것이 최적 전략이 된다.”


더 깊이 알고 싶다면 → 부록 E: REINFORCE에서 DPO가 어떻게 나왔는가 DPO가 RLHF(PPO)의 수식을 어떻게 변환해서 나왔는지, 로그 미분 트릭이 DPO 안에 어떻게 내장되어 있는지를 수학적으로 추적한다. DPO의 수식 형태가 왜 이런지, 왜 레퍼런스가 필요한지, 왜 탐색 능력이 없는지가 이 도출 과정에서 모두 설명된다.


이제 이 구조를 이해했으니, 각 요소를 하나씩 의심할 수 있다.
첫 번째 질문: 이 구조에서 선호/비선호 쌍은 꼭 필요한가?


의문: 꼭 쌍이어야 하나?

DPO는 (yw,yl)(y_w, y_l) 쌍을 입력받는다. 왜 하나의 응답에 “좋다/나쁘다” 점수를 매기는 게 아니라, 반드시 둘을 비교해야 하는가?

왜 쌍인가 (필수성)

빼면? — 실제로 빼서 성공한 사례

장난감 예제

절대 평가의 불안정성:
평가자 A: “이 응답 7점” → 다음 날: “이 응답 5점”
평가자 B: “이 응답 8점”

상대 비교의 안정성:
“응답 X vs 응답 Y” → A, B 모두 “X가 낫다” (일치율 ~80%)

→ 절대 점수는 개인 내 / 개인 간 편차가 크다
→ 상대 순서는 안정적이다
→ 이것이 쌍비교를 채택한 이유

graph LR
    A["<b>SFT</b><br/>좋은 응답 확률 ↑"] -->|"+ 음성 예제"| B["<b>SFT + 음성</b><br/>나쁜 응답 확률 ↓"]
    B -->|"+ KL 제약"| C["<b>+ 레퍼런스</b><br/>원본에서 이탈 제한"]
    C -->|"σ + −log"| D["<b>DPO</b><br/>상대 마진 최적화"]

    style A fill:#e3f2fd,stroke:#1976D2
    style B fill:#fff3e0,stroke:#F57C00
    style C fill:#fce4ec,stroke:#C62828
    style D fill:#e8f5e9,stroke:#2E7D32,stroke-width:3px
graph LR
    subgraph 데이터 요구량
        direction LR
        DPO["<b>DPO</b><br/>쌍비교 필수<br/>(y_w, y_l)"] ---|"쌍 제거"| KTO["<b>KTO</b><br/>단일 라벨<br/>(좋다/나쁘다)"] ---|"자기 생성"| ORPO["<b>ORPO</b><br/>선호 응답만<br/>(모델이 비선호 생성)"]
    end

    style DPO fill:#ffcdd2,stroke:#C62828
    style KTO fill:#fff9c4,stroke:#F9A825
    style ORPO fill:#c8e6c9,stroke:#2E7D32

시각화 계획

다음 장으로의 질문

DPO가 하는 일을 이해했다: 레퍼런스 대비 마진을 벌린다. 그런데 마진은 logπ(ywx)logπ(ylx)\log \pi(y_w \mid x) - \log \pi(y_l \mid x)로 구한다. 이 "문장 전체의 로그확률"은 실제로 어떻게 계산하는가?