본문 바로가기
강화학습

[강화학습 28] RLHF ① 선호에서 보상모델로

by 카이스토 2026. 9. 15.

CH 28 강화학습 · Part 5 보상을 사람에게서 배우다

RLHF ① 선호에서 보상모델로

27장은 시연에서 보상을 거꾸로 알아내려 했다. 이 장은 재료를 바꾼다. 사람에게 "이 답변 몇 점?"이라 묻지 않고 "둘 중 어느 쪽이 낫나"만 묻는다. 절대점수는 평가자마다·날마다 흔들리지만 쌍 비교는 흔들리지 않는다. 이 장은 그 비교 더미에서 보상함수를 꺼내는 브래들리–테리 모형을 손으로 풀고, SFT → RM → PPO 3단 파이프라인을 조립하고, KL 페널티가 붙은 목적 𝔼[r] − β·KL 의 최적해가 πref(y)·exp(r(y)/β) 에 비례함을 유도한다. 이 마지막 식이 29장 DPO 의 출발점이다.

  • 01 직관
  • 02 수식 읽는 법
  • 03 손으로 풀기
  • 04 코드
  • 05 시각화

약어 및 기호 정의

RLHF
Reinforcement Learning from Human Feedback. 사람의 선호를 보상으로 바꿔 정책을 미세조정하는 절차
프롬프트 x
모델에 주는 입력. 토큰 단위 MDP 에서는 초기 상태에 해당한다
응답 y
모델이 생성한 토큰열 전체. 한 에피소드의 궤적 하나로 본다
선호쌍 (yw, yl)
preference pair. 같은 x 에 대한 두 응답 중 사람이 이긴 쪽(win)과 진 쪽(lose)
브래들리–테리 BT
Bradley–Terry(1952). P(yw ≻ yl) = σ(rw − rl). 승패를 잠재점수 차이로 설명하는 모형
보상모델 RM
reward model. rφ(x,y) ∈ ℝ. 선호쌍으로 학습한 사람 취향의 대리인
SFT
Supervised Fine-Tuning. 사람이 쓴 시범 응답을 그대로 모방하는 1단계. 27장의 행동복제와 같은 것이다
기준정책 πref
reference policy. 보통 SFT 모델을 고정해 쓴다. KL 페널티의 기준점이자 초기값
KL 페널티 β
β·KL(π‖πref) 의 계수. 작으면 과감하고 크면 πref 에 붙어 있는다
분할함수 Z(x)
Σy πref(y|x)exp(r(x,y)/β). KL 정규화 최적해의 정규화 상수. 29장에서 DPO 가 지워 없애는 항
게이지 자유도 gauge freedom
보상 전체를 같은 상수만큼 옮겨도 모든 예측이 같은 성질. 27장 보상 비유일성과 같은 이야기
보상 해킹 reward hacking
보상모델의 점수만 올리고 실제 품질은 떨어지는 현상. 29장의 주제
STEP 01

직관: 점수는 흔들리지만 순서는 흔들리지 않는다

27장은 보상이 주어지지 않는 상황을 시연으로 풀었다. 전문가가 어떻게 하는지 보여 주면 그 궤적을 설명하는 보상함수를 역으로 추정할 수 있다. 그런데 "좋은 답변을 쓰는 일"에는 잘 맞지 않는다. 시연을 모으는 비용이 크고 — 사람이 직접 좋은 답변을 써야 한다 — 무엇보다 사람이 쓴 것보다 잘하는 모델을 만들 수 없다. 모방의 천장은 시연자다.

그러면 사람에게 채점을 부탁하면 어떨까. 응답 하나를 보여 주고 1점부터 7점까지 매기라고 하는 것이다. 이 방법은 실제로 써 보면 무너진다. 이유가 셋이다.

절대점수가 무너지는 세 가지 방식

1. 기준점이 사람마다 다르다. 어떤 평가자는 어지간하면 5점을 주고, 어떤 평가자는 7점을 아껴 둔다. 같은 응답이 평가자 A 에게 6점, B 에게 4점을 받는다. 점수를 평균하면 두 사람의 서로 다른 자(ruler)를 섞는 것이다.

2. 기준점이 시간에 따라 흐른다. 오늘 50개를 채점하고 나면 눈이 높아진다. 아침에 6점이던 품질이 오후에는 4점이 된다. 같은 평가자 안에서도 자가 늘어난다.

3. 맥락 효과가 크다. 직전에 본 응답이 나빴으면 다음 응답이 후하게 평가된다. 앵커링은 의식해서 막을 수 있는 편향이 아니다.

그런데 이 세 가지 문제 모두 두 응답을 나란히 놓고 "어느 쪽?"이라 물으면 대부분 사라진다. 내 자가 늘어났든 줄어들었든, 같은 자로 둘을 재면 순서는 그대로다. 맥락도 두 응답에 똑같이 작용하니 상쇄된다.

이것이 RLHF 의 첫 번째 설계 결정이다. 절대평가를 버리고 쌍 비교만 모은다. 정보량으로 보면 손해다. 7점 척도는 한 응답에 대해 약 log27 ≈ 2.8 비트를 주고, 쌍 비교는 1비트를 준다. 그런데 그 1비트는 믿을 수 있는 1비트다. 2.8비트 중 2비트가 평가자의 자에서 온 잡음이면 쓸 데가 없다.

ch28-d1
도해 1. 왼쪽 세 점수 (6,4,7) 에서 평가자 편향응답 품질을 분리할 방법은 없다. 오른쪽은 같은 세 사람이 같은 판단을 내놓았다. RLHF 는 오른쪽을 재료로 삼고, 왼쪽의 점수는 모형이 역으로 복원한다. 복원된 점수가 보상모델이다.

마지막 문장이 이 장의 전부다. 우리는 1비트짜리 비교를 수만 개 모아 실수값 보상함수를 역추정한다. 구조만 보면 27장의 역강화학습과 같다. 관측이 "전문가의 궤적"에서 "사람의 선호 순서"로 바뀌었을 뿐이고, 어느 쪽이든 드러나지 않은 보상을 관측 가능한 행동에서 거꾸로 읽어 내는 일이다. 그래서 27장에서 본 문제가 여기서도 그대로 돌아온다 — 보상은 유일하게 정해지지 않는다. 선호로 식별되는 것은 보상의 차이뿐이다. 이 점을 다음 절에서 못박는다.

그래서 왜 강화학습이 필요한가

보상모델만 있으면 되지 않나 — 응답을 여러 개 뽑아 점수가 가장 높은 것을 고르면 된다. 실제로 이것이 최선의 N 개 중 선택(best-of-N sampling)이고 잘 동작하지만, 추론 때마다 N 배의 계산을 쓴다. 강화학습은 그 선택을 모델 파라미터 안으로 옮긴다 — 학습 때 한 번 비용을 치르고 추론은 한 번만 생성한다. 갱신 수단은 이미 우리 손에 있다. 20장의 PPO 다. 언어모델 생성은 토큰을 하나씩 고르는 순차적 의사결정이고, PPO 는 그런 문제의 표준 정책경사다. RLHF 가 "새 알고리즘"이 아니라 새 보상 정의 + 기존 PPO 인 이유다.

STEP 02

수식 읽는 법: 차이만 식별된다

브래들리–테리 모형

응답 하나하나에 숨은 실수값 점수 r(x,y) 가 있다고 가정한다. 사람이 두 응답을 비교할 때, 점수가 높은 쪽을 고르지만 확정적으로는 아니다. 차이가 크면 거의 확실히, 차이가 작으면 반쯤 동전 던지기로 고른다. 이 가정을 가장 단순하게 쓴 것이 브래들리–테리 모형(Bradley–Terry model, 1952)이다.

P(yw ≻ yl | x) = σ( r(x,yw) − r(x,yl) ) = 11 + exp(−(rw − rl)) (28.1) σ 는 로지스틱 함수. 입력이 보상의 차이 하나뿐이라는 점이 핵심이다.

식 (28.1) 을 읽는 요령은 오른쪽에 들어가는 것이 차이뿐이라는 데 있다. rw = 3.0, rl = 2.0 인 경우와 rw = −7.0, rl = −8.0 인 경우의 예측은 똑같이 σ(1) = 0.7311 이다. 따라서 데이터가 아무리 많아도 보상의 절대 수준은 결정되지 않는다.

1
모든 응답의 보상에 같은 상수 c 를 더한 r′(x,y) = r(x,y) + c 를 생각한다.
2
차이는 변하지 않는다.
r′w − r′l = (rw+c) − (rl+c) = rw − rl
3
따라서 모든 쌍의 예측 확률이 같고, 우도도 같다. rr′데이터로 구분할 수 없다.
ℒ(r) = ℒ(r + c·𝟙) 모든 c ∈ ℝ 에 대해
4
해가 하나의 점이 아니라 직선 전체다. 수치최적화기에 그냥 넣으면 방향 하나가 평평해 수렴 판정이 애매해진다. 해결은 게이지를 하나 고정하는 것 — 기준 응답의 보상을 0 으로 두거나, Σy r(y) = 0 을 요구하거나, 작은 항을 붙인다.

27장에서 역강화학습의 해가 유일하지 않았던 것과 정확히 같은 구조다. 27장에서는 상태마다 임의의 함수 Φ(s) 를 더하는 보상 성형이 최적정책을 바꾸지 않았고, 여기서는 전역 상수 c 가 선호 확률을 바꾸지 않는다. 관측이 상대적인 양(정책의 순서, 비교의 승패)인 한, 보상의 절대 수준은 관측 밖에 있다.

보상모델의 손실과 그 기울기

선호쌍 데이터 𝒟 = {(x, yw, yl)} 에 대해 (28.1) 의 음의 로그우도를 최소화한다.

RM(φ) = − 𝔼(x,yw,yl)∼𝒟[ log σ( rφ(x,yw) − rφ(x,yl) ) ] (28.2) 이진 분류의 교차엔트로피와 같은 꼴이지만, 분류 대상이 응답 하나가 아니라 쌍의 순서다.

기울기를 구해 보면 이 손실이 무엇을 하는지 한눈에 보인다. Δ = rw − rl 로 줄여 쓴다.

1
log σ(Δ) 의 미분은 1 − σ(Δ) 다. 이것은 σ(−Δ) 와 같다.
d log σ(Δ) = 1 − σ(Δ) = σ(−Δ)
2
연쇄율로 파라미터 기울기를 쓴다. Δrw 에 대해 +1, rl 에 대해 −1 인 점을 쓴다.
φRM = −(1 − σ(Δ)) · ( ∇φ rφ(x,yw) − ∇φ rφ(x,yl) )
3
경사하강은 이 기울기의 반대 방향으로 간다. 즉 rw올리고 rl내린다. 올리는 양과 내리는 양이 같은 크기다.
φ ← φ + α(1 − σ(Δ))(∇rw − ∇rl)
4
그 크기를 정하는 것이 앞의 스칼라 1 − σ(Δ) 다. 이미 잘 맞으면(Δ 가 크면) 0 으로 줄고, 틀렸으면(Δ < 0) 1 에 가까워진다.
기울기 스칼라 1 − σ(Δ). 아래 값은 모두 검산한 것이다.
Δ = rw − rl σ(Δ) = 예측 승률 1 − σ(Δ) = 기울기 크기 −log σ(Δ) = 손실 해석
−2.0 0.119203 0.880797 2.126928 순서를 거꾸로 맞혔다 — 세게 고친다
0.0 0.500000 0.500000 0.693147 판단 보류 상태. 손실 ln 2
+1.0 0.731059 0.268941 0.313262 맞지만 아직 밀어 줄 여지
+3.0 0.952574 0.047426 0.048587 거의 끝났다
+5.0 0.993307 0.006693 0.006715 사실상 학습이 멈춘다

마지막 줄이 중요하다. Δ 가 커지면 기울기가 지수적으로 죽으므로, 손실은 보상을 무한히 벌리지 않는다. 쉬운 쌍은 일찍 포화되고, 애매한 쌍 — 사람도 반쯤 갈린 쌍 — 이 학습의 남은 기울기를 차지한다. 레이블 잡음이 있는 쌍은 영원히 큰 기울기를 내므로, 실무에서 선호 데이터의 품질이 보상모델 품질을 직접 결정하는 이유가 여기 있다.

3단 파이프라인

RLHF 는 단계가 셋이다. 각 단계가 쓰는 데이터목적이 서로 다르다는 점을 분명히 구분해야 한다.

InstructGPT 계열 논문이 정리한 3단 구성. 각 단계의 산출물이 다음 단계의 입력이 된다.
단계 데이터 손실 / 목적 산출물 이 시리즈의 어디
1. SFT 사람이 쓴 (x, y) 시범 응답 토큰 교차엔트로피 −Σ log π(yt|x,y<t) πSFT → 이것이 πref 이자 초기화 27장 행동복제와 같다
2. RM 같은 x 의 응답 쌍 + 사람의 선호 BT 손실 (28.2) rφ(x,y) 스칼라 보상 이 장의 손계산 절
3. PPO 프롬프트 x 만 (응답은 모델이 생성) 𝔼[rφ] − β·KL(π‖πref) 정렬된 정책 πθ 20장 PPO 를 그대로

3단계가 레이블 없는 프롬프트만 먹는다는 점이 이 구조의 경제성이다. 그 대가가 29장의 주제인 보상 해킹이다 — 대리인을 너무 믿으면 대리인만 만족시킨다.

3단계의 목적함수 — 보상만 올리면 안 되는 이유

3단계에서 최대화하는 것은 보상의 기댓값 하나가 아니다. 기준정책에서 멀어진 정도를 빼 준 값이다.

maxθ   𝔼x∼𝒟, y∼πθ(·|x)[ rφ(x,y) ]  −  β · KL( πθ(·|x) ‖ πref(·|x) ) (28.3) 앞 항은 "사람이 좋아하게", 뒤 항은 "원래 모델에서 너무 멀어지지 말게". β 가 둘의 환율이다.

보상만 올리면 될 것 같은데 왜 두 번째 항을 붙이는가. 이유가 둘이고, 둘 다 실패 사례에서 나왔다.

KL 항이 있는 첫 번째 이유 — 보상모델은 좁은 곳에서만 믿을 만하다

rφ 는 사람이 아니라 사람의 대리인이고, 학습 데이터는 πref 근처에서 뽑은 응답 쌍이다. 정책이 그 영역을 벗어나면 보상모델은 외삽을 하게 되고, 외삽 구간에서 나온 높은 점수는 근거가 없다. 26장 오프라인 RL 에서 본 분포 이탈과 완전히 같은 병이다. 거기서는 Q 함수가 본 적 없는 행동을 과대평가했고, 여기서는 보상모델이 본 적 없는 응답을 과대평가한다. 치료법도 같다 — 데이터가 있는 곳 근처에 머물게 한다.

그래서 KL 항은 정규화가 아니라 대리인의 유효 범위를 지정하는 장치다. β 를 키운다는 것은 "보상모델을 덜 믿겠다"는 선언이다.

두 번째 이유 — SFT 가 쌓아 둔 것을 지킨다

πSFT 에는 보상모델이 채점하지 않는 성질 — 문법, 사실성, 어휘의 다양성 — 이 많이 들어 있다. 채점되지 않는 성질은 최적화 과정에서 거리낌 없이 희생된다. 극단은 모드 붕괴(mode collapse)다. 보상모델이 가장 좋아하는 문장 하나를 찾아내면 정책은 프롬프트와 무관하게 그 문장만 뱉는다.

KL 항은 이것을 직접 막는다. 한 응답에 확률을 몰수록 KL 이 커지고, 완전히 결정적이 되면 −log πref(y) 로 뛴다. 응답 하나의 확률이 10−30 수준인 언어모델에서 이 값은 수십 nats 이므로 β 가 작아도 붕괴는 비싸다.

19장의 TRPO 와 식의 모양이 같으니 헷갈리기 쉬운데, 기준이 다르다. TRPO 와 20장 PPO 의 KL 은 πold직전 갱신의 정책 — 에 대한 것이고, 매 갱신마다 기준이 따라 움직인다. 그것은 한 걸음의 크기를 재는 자다. 반면 (28.3) 의 KL 은 처음부터 끝까지 고정된 πref 를 본다. 이것은 걸음 크기가 아니라 출발점에서 총 얼마나 멀어졌는지를 재는 자다. RLHF 를 PPO 로 돌리면 두 KL 이 동시에 작동한다 — 클리핑이 한 걸음을 잡고, β 가 전체 이동거리를 잡는다.

언어 생성을 MDP 로 적기

3장에서 MDP 는 (𝒮, 𝒜, P, R, γ) 다섯 개였다. 응답 생성을 그 틀에 끼워 넣으면 이렇게 된다.

토큰 단위 MDP. 전이가 결정적이라는 점이 게임·로봇 환경과 결정적으로 다르다.
MDP 요소 언어 생성에서 비고
상태 st (x, y1, …, yt−1) — 프롬프트 + 지금까지 생성한 토큰열 상태공간이 |V|t 로 폭발한다. 표는 불가능
행동 at 다음 토큰 yt ∈ V 행동 개수 = 어휘 크기. 보통 104~105
전이 P st+1 = st ⊕ yt — 이어붙이기. 확률이 없다 결정적. 환경 잡음이 0 이므로 잡음은 전부 정책에서 나온다
보상 R t < T 이면 0, t = T 에서 rφ(x,y) 한 번 가장 희소한 형태의 보상. 신용할당이 이 장의 문제
γ 보통 1 길이가 유한하므로 감가하지 않아도 발산하지 않는다

실제 구현에서는 KL 항을 목적에 따로 두지 않고 토큰별 보상에 녹여 넣는다. KL 은 토큰마다 분해되기 때문에 이것이 가능하다.

rt = −β ( log πθ(yt|st) − log πref(yt|st) )  +  𝟙[t = T] · rφ(x, y) (28.4) 앞 항은 모든 토큰에 붙는 밀집 보상이고, 뒤 항은 마지막 토큰에만 붙는 희소 보상이다.

(28.4) 를 모든 t 에 대해 더하고 πθ 로 기댓값을 취하면 정확히 (28.3) 이 된다 — 앞 항의 합의 기댓값이 −β·KL 이기 때문이다. 즉 두 식은 같은 것을 다르게 적은 것이고, (28.4) 쪽이 PPO 구현에 바로 들어간다.

그런데 뒤 항의 모양을 다시 보라. 수백 토큰을 생성하고 마지막에 스칼라 하나를 받는다. 1장에서 강화학습의 세 난점 중 첫 번째로 꼽았던 신용할당(credit assignment) 문제의 가장 순수한 형태다. 응답이 좋았다면 어느 토큰 덕분인가. 300개 토큰 중 세 번째 문단의 한 단어 선택이 결정적이었을 수도 있는데, 우리가 받은 것은 전체에 대한 점수 하나다. 6장 몬테카를로와 구조가 같고, 18장 GAE 의 λ 가 그 배분을 조절한다. 손계산 절의 마지막 계산이 이것을 숫자로 보여 준다.

STEP 03

손으로 풀기: 선호 13개에서 점수 세 개를 꺼낸다

1. 브래들리–테리 최대우도

응답이 셋뿐인 장난감을 만든다. 같은 프롬프트에 대한 응답 A, B, C 를 사람들이 13번 비교했고 결과는 아래와 같다. 이 숫자만 가지고 세 응답의 보상 rA, rB, rC 를 추정한다.

선호 데이터. 총 13번의 쌍 비교. 오른쪽 두 열은 각 응답이 참가한 비교 수와 이긴 횟수다.
비교 앞이 이김 뒤가 이김 관측 승률
A vs B 3 1 4 0.7500
A vs C 2 1 3 0.6667
B vs C 4 2 6 0.6667
승수 합계 — A: 3+2 = 5 · B: 1+4 = 5 · C: 1+2 = 3  (합 13)

음의 로그우도는 (28.2) 를 이 데이터에 그대로 적은 것이다. nij 를 "ij 를 이긴 횟수"라 쓴다.

ℒ(r) = −  Σi≠j nij · log σ(ri − rj)  =  −[ 3 log σ(rA−rB) + 1 log σ(rB−rA) + 2 log σ(rA−rC) + 1 log σ(rC−rA) + 4 log σ(rB−rC) + 2 log σ(rC−rB) ]

1차 조건을 세운다. 앞서 본 d log σ(Δ)/dΔ = 1 − σ(Δ) = σ(−Δ) 만 쓰면 된다.

1
ri 로 미분한다. rii 가 이긴 항에 + 로, 진 항에 로 들어간다.
∂ℒ/∂ri = − Σj nij(1 − σ(ri−rj)) +  Σj nji(1 − σ(rj−ri))
2
두 번째 합에서 1 − σ(rj−ri) = σ(ri−rj) 로 바꾸고, 첫 합을 −nij + nijσ(·) 로 펼친다.
∂ℒ/∂ri = − Σj nij +  Σj (nij + nji) σ(ri−rj)
3
0 으로 놓으면 아주 읽기 좋은 형태가 된다. wi 는 실제 승수, Nij = nij+nji 는 맞붙은 횟수다.
wi =  Σj Nij · σ(ri − rj) 실제 승수 = 모형이 예측한 기대 승수
4
세 식을 다 더하면 양변이 모두 13 이 되어 항등식이 된다. 독립인 식은 둘뿐이다. 미지수도 셋이므로 자유도 하나가 남는다 — 앞 절의 게이지 자유도가 여기서 다시 나타난다.
5
rC = 0 으로 고정한다. 남은 두 식이 미지수 두 개를 정한다.
4σ(rA−rB) + 3σ(rA) = 5   ·   4σ(rB−rA) + 6σ(rB) = 5

이 두 식은 닫힌 꼴로 풀리지 않는다. 뉴턴법으로 풀면 아래 값이 나온다. 손으로는 검산만 하면 된다.

BT 최대우도 추정치(rC = 0 고정). er 열은 BT 를 "강도의 비"로 읽을 때 쓰는 값이다.
응답 r (추정) er 실제 승수 기대 승수
A 1.198002 3.313490 5 5.000000
B 0.472247 1.603593 5 5.000000
C 0.000000 (고정) 1.000000 3 3.000000

검산 — 1차 조건 두 줄

rA − rB = 1.198002 − 0.472247 = 0.725755 이고 σ(0.725755) = 0.673873, σ(1.198002) = 0.768169 다.

A 의 식: 4 × 0.673873 + 3 × 0.768169 = 2.695492 + 2.304508 = 5.000000

B 의 식: σ(−0.725755) = 0.326127, σ(0.472247) = 0.615915 이므로 4 × 0.326127 + 6 × 0.615915 = 1.304508 + 3.695492 = 5.000000

C 의 식(자동으로 맞아야 한다): 3 × 0.231831 + 6 × 0.384085 = 0.695492 + 2.304508 = 3.000000

최소 NLL 은 ℒ* = 8.146215 다. 비교 13번에 대해 응답당 평균 8.146215 / 13 = 0.626632 nats — ln 2 = 0.693147 보다 조금 낮다. 동전 던지기보다 약간 나은 설명력이라는 뜻이고, 데이터가 13개뿐이니 당연한 결과다.

게이지를 고정하지 않으면 어떻게 되나

앞 절의 주장을 숫자로 확인한다. 세 보상을 통째로 옮겨 보면 NLL 이 소수점 열 자리까지 같다.

ℒ(1.198002, 0.472247,  0.000000) = 8.1462145665
ℒ(3.698002, 2.972247,  2.500000) = 8.1462145665      ← 전부 +2.5
ℒ(-5.801998, -6.527753, -7.000000) = 8.1462145665      ← 전부 −7.0

완전히 같은 값이다. 최적화기 입장에서 (1,1,1) 방향은 곡률이 정확히 0 인 평평한 골짜기이고, 헤시안이 특이행렬이라 뉴턴법이 죽는다. 그래서 실무 보상모델 코드에는 예외 없이 게이지 고정 장치가 들어 있다 — 배치 평균을 빼거나, λ‖r‖² 를 더하거나, 기준 응답을 0 으로 못박는다. 이 장의 코드는 10−6(Σr)² 라는 아주 약한 항을 썼다. 평평한 방향만 잡고 나머지 최적해는 건드리지 않게 하려는 것이다.

2. 모형이 맞힌 것과 못 맞힌 것

추정한 r 로 승률을 다시 예측하고 관측 빈도와 비교한다.

BT 예측 승률 vs 관측 빈도. 세 줄 어느 것도 정확히 일치하지 않는다는 점이 중요하다.
Δ = ri − rj 모형 σ(Δ) 관측 빈도 모형 기대승수 실제 승수
A ≻ B 0.725755 0.673873 3/4 = 0.750000 2.695492 3
A ≻ C 1.198002 0.768169 2/3 = 0.666667 2.304508 2
B ≻ C 0.472247 0.615915 4/6 = 0.666667 3.695492 4

세 쌍 모두 어긋난다. 그런데 각 응답의 총 승수는 정확히 맞는다(위 표의 기대 승수 합계: A 2.695492+2.304508 = 5, B 1.304508+3.695492 = 5, C 0.695492+2.304508 = 3). 이것이 1차 조건이 말하던 바다.

왜 쌍별로는 못 맞히는가 — 자유도 세기

관측된 쌍별 빈도는 세 개인데, 게이지를 고정한 모형의 자유 파라미터는 두 개다. 셋을 둘로 설명하려니 하나가 남는다. BT 가 강제하는 것은 이행성이다 — ΔAB + ΔBC = ΔAC 가 자동으로 성립한다. 실제로 0.725755 + 0.472247 = 1.198002 로 정확히 맞는다.

관측 빈도는 이 제약을 만족할 이유가 없다. 관측대로면 σ−1(0.75) + σ−1(2/3) = 1.098612 + 0.693147 = 1.791759 인데 σ−1(2/3) = 0.693147 이므로 어긋난다. 최대우도는 이 어긋남을 비교 횟수로 가중해 절충한 지점이다. B vs C 가 6번으로 가장 많이 비교됐으므로 그쪽 빈도에 가장 크게 끌려간다.

실무에서 비이행적 선호(A≻B, B≻C, C≻A)가 데이터에 섞여 들어오면 BT 는 그것을 표현할 수 없고, 세 응답의 점수를 비슷하게 만들어 "잘 모르겠다"고 답한다. 사람의 선호가 실제로 비이행적인 영역 — 취향이 갈리는 창작물 같은 것 — 에서 보상모델이 흐려지는 이유다.

3. KL 이 얼마나 큰 수인가

β 를 고르려면 KL 이 어느 정도 크기의 수인지 감이 있어야 한다. 어휘가 셋뿐인 장난감으로 재 본다. πref = (0.5, 0.3, 0.2) 로 두고 KL(π‖πref) = Σy π(y) log(π(y)/πref(y)) 를 정확히 계산한다(단위는 nats).

πref = (0.5, 0.3, 0.2) 기준 KL. 확률을 한쪽으로 아무리 몰아도 KL 은 몇 nats 를 넘지 못한다.
π KL(π‖πref) 해석
(0.5, 0.3, 0.2) 0.000000 기준 그대로
(0.7, 0.2, 0.1) 0.085123 눈에 띄게 바뀌었는데도 0.1 이 안 된다
(0.9, 0.08, 0.02) 0.377216 거의 한쪽으로 몰았을 때
(0.98, 0.01, 0.01) 0.595516
(1, 0, 0) 0.693147 결정적. = ln(1/0.5)
(0, 0, 1) 1.609438 이 문제의 최대 KL. = ln(1/0.2)

마지막 두 줄이 계산의 뼈대다. 정책이 y 하나에 확률 1 을 주면 KL = 1·log(1/πref(y)) = −log πref(y) 이므로, KL 의 최댓값은 기준정책이 가장 낮게 보던 선택지의 놀라움이다. 어휘가 셋이면 최대 1.61 nats 밖에 안 된다.

역산 — 보상 1.0 을 얻으려면 KL 을 얼마까지 써도 되나

(28.3) 의 목적은 𝔼[r] − β·KL 이다. 보상이 1.0 올랐을 때 목적이 손해를 보지 않으려면 β·KL ≤ 1.0, 즉 KL ≤ 1.0/β 여야 한다.

β = 0.1KL ≤ 10.0 nats · β = 0.02KL ≤ 50.0 nats.

그런데 이 장난감에서 가능한 KL 의 최댓값이 1.609438 이다. 두 경우 모두 한계에 한참 못 미친다 — 즉 어휘 3개짜리 문제에서 β = 0.020.1사실상 아무것도 막지 않는다. 정책은 보상이 가장 높은 토큰에 전부 몰아도 이득이다.

실제 언어모델에서 이 수치가 의미를 갖는 이유는 규모가 다르기 때문이다. KL 을 재는 대상이 토큰 하나가 아니라 응답 전체(수백 토큰의 합)이고, 어휘가 104 이상이라 토큰 하나를 못박는 데 드는 KL 도 훨씬 크다. 응답 수준 KL 이 수십 nats 에 이르므로 β0.01~0.1 사이에 둔다. 여기서 얻을 교훈은 숫자 자체가 아니라 β 의 의미는 KL 을 무엇에 대해 재느냐에 전적으로 의존한다는 점이다. 토큰당 평균 KL 에 곱하는지 응답 전체 KL 에 곱하는지만 바뀌어도 같은 β 가 수백 배 다르게 작동한다.

4. KL 정규화된 최적 정책 — 이 장에서 가장 중요한 식

(28.3) 에서 π 를 자유롭게 고를 수 있다면, 즉 신경망의 표현력 제약을 무시한다면, 최적해가 닫힌 꼴로 나온다. 프롬프트 x 를 하나 고정하고 유도한다.

1
목적을 π 의 함수로 적는다. 제약은 Σy π(y) = 1 하나다.
J(π) =  Σy π(y) r(y) − β  Σy π(y) log π(y)πref(y)
2
라그랑주 함수를 세운다.
ℒ(π, λ) = J(π) + λ(  Σy π(y) − 1 )
3
π(y) 로 편미분한다. d/dp [ p log(p/q) ] = log(p/q) + 1 을 쓴다.
∂ℒ/∂π(y) = r(y) − β( log π(y)πref(y) + 1 ) + λ = 0
4
log 항에 대해 정리하고 지수를 취한다. λ 관련 항은 y 에 무관한 상수다.
π(y) = πref(y) · exp( r(y)/β ) · exp( λ/β − 1 )
5
그 상수는 정규화가 정해 준다. 합이 1 이 되게 하는 값이 곧 1/Z 다.
π*(y|x) = 1Z(x) πref(y|x) · exp( r(x,y)β )  ,  Z(x) =  Σy πref(y|x) exp(r(x,y)/β)
π*(y|x) ∝ πref(y|x) · exp( r(x,y) / β ) (28.5) 기준정책을 보상의 지수로 재가중한 것. β→∞πref 그대로, β→0 이면 보상 최대인 응답으로 몰린다.

최적값도 깔끔하게 나온다. (28.5) 를 뒤집으면 r(y) = β log(π*(y)/πref(y)) + β log Z 이고, 이것을 π* 로 평균 내면 𝔼π*[r] = β·KL(π*‖πref) + β log Z 이므로

J* = 𝔼π*[r] − β·KL(π*‖πref) = β log Z soft-max 형태의 자유에너지. 21장 최대엔트로피 RL 의 soft 가치함수와 같은 구조다.

숫자로 확인

πref = (0.5, 0.3, 0.2), r = (1.0, 0.0, −0.5) 로 두고 β = 0.1β = 1 을 계산한다. 비정규화 가중치 πref(y)er(y)/β 를 먼저 구하면 된다.

β = 0.1 — 지수가 10배로 증폭된다

r/β = (10, 0, −5) 이므로 가중치는

0.5·e10 = 0.5 × 22026.465795 = 11013.232897 · 0.3·e0 = 0.300000 · 0.2·e−5 = 0.2 × 0.00673795 = 0.001348

Z = 11013.534245. 나누면 π* = (0.99997264, 0.00002724, 0.00000012).

확인: 𝔼[r] = 0.999973, KL = 0.692846, 목적 = 0.999973 − 0.1 × 0.692846 = 0.930688. 그리고 β log Z = 0.1 × 9.306880 = 0.930688 — 일치한다. ✓

β = 1 — 기준정책의 모양이 상당히 남는다

r/β = (1, 0, −0.5) 이므로 가중치는

0.5·e1 = 1.359141 · 0.3 · 0.2·e−0.5 = 0.2 × 0.606531 = 0.121306

Z = 1.780447. 나누면 π* = (0.763371, 0.168497, 0.068132).

확인: 𝔼[r] = 0.763371 − 0.5 × 0.068132 = 0.729305, KL = 0.152441, 목적 = 0.729305 − 0.152441 = 0.576864. 그리고 log Z = log 1.780447 = 0.576864. ✓

β 에 따른 최적 정책. β 가 커질수록 πref = (0.5,0.3,0.2) 로 되돌아간다. 마지막 줄은 β 가 아주 클 때의 극한이다.
β π*(y1) π*(y2) π*(y3) 𝔼[r] KL J* = β log Z
0.1 0.999973 0.000027 <10−6 0.999973 0.692846 0.930688
0.3 0.976468 0.020901 0.002632 0.975152 0.586506 0.799200
0.5 0.908170 0.073744 0.018086 0.899127 0.395076 0.701589
1.0 0.763371 0.168497 0.068132 0.729304 0.152440 0.576864
5.0 0.559420 0.274809 0.165771 0.476534 0.007599 0.438538
100 0.502999 0.298797 0.198204 0.403897 0.000019 0.401949

β = 0.1 줄을 보라. KL 이 0.692846 으로 결정적 정책의 한계 0.693147 에 거의 닿았다. 위 KL 역산에서 예고한 그대로다 — 어휘 셋짜리 문제에서 β = 0.1 은 붕괴를 막지 못한다. 반대로 β = 5 에서는 KL 이 0.0076 밖에 안 되고 𝔼[r]0.4765 에 그친다 — 보상을 거의 포기한 것이다.

29장 예고 — 이 식을 뒤집으면 보상모델이 사라진다

(28.5) 를 r 에 대해 풀면 r(x,y) = β log(π*(y|x)/πref(y|x)) + β log Z(x) 다. 이제 이 r 을 BT 손실 (28.2) 의 rw − rl 에 넣어 본다. 두 응답이 같은 프롬프트 x 에서 나왔으므로 β log Z(x) 가 똑같이 들어가 깨끗이 소거된다.

rw − rl = β log π*(yw|x)πref(yw|x) − β log π*(yl|x)πref(yl|x)

오른쪽에 보상모델이 없다. 정책과 기준정책만 있다. 이것을 −log σ(·) 에 넣으면 선호 데이터로 정책을 직접 학습하는 손실이 되고, 그것이 29장의 DPO 다. 2단계(RM)와 3단계(PPO)가 한 단계로 접힌다. 계산하기 어려운 Z(x) 가 사라지는 이 한 줄이 DPO 의 전부라고 해도 과하지 않다.

5. 마지막 토큰의 보상을 스무 개 토큰에 나누기

길이 L = 20 의 응답을 만들었고, 보상은 마지막에 rφ = 1.0 한 번만 들어온다. 가치함수가 아직 아무것도 배우지 못해 V ≡ 0 이고 γ = 1 이라 하자. TD 오차는

δt = rt + γV(st+1) − V(st) = rt  →  δ0 = ⋯ = δ18 = 0,   δ19 = 1

18장의 GAE 는 Ât = Σk≥0 (γλ)k δt+k 다. δ 가 마지막 하나뿐이므로 합이 항 하나로 줄어든다.

Ât = (γλ)19−t · δ19 = λ19−t (28.6) 토큰이 끝에서 멀수록 λ 의 거듭제곱만큼 이점이 줄어든다.
L=20, 끝에만 r=1, V≡0, γ=1 일 때 토큰별 이점 Ât.
λ Â0 (첫 토큰) Â10 Â18 Â19 (마지막) Σt Ât
1.00 1.000000 1.000000 1.000000 1.000000 20.0000
0.95 0.377354 0.630249 0.950000 1.000000 12.8303
0.90 0.135085 0.387420 0.900000 1.000000 8.7842
0.50 0.000002 0.001953 0.500000 1.000000 2.0000

첫 줄이 λ=1 이다. 스무 개 토큰 전부가 똑같이 +1 의 이점을 받는다. 응답이 좋았다는 이유로 첫 토큰의 선택도, 마지막 토큰의 선택도 똑같이 강화된다. 이것은 6장 몬테카를로와 정확히 같고, 편향이 없는 대신 어느 토큰이 실제로 기여했는지 구분하지 못한다. 잡음이 많은 토큰까지 같이 밀려 올라가므로 분산이 크다.

λ 를 내리면 크레딧이 뒤쪽으로 쏠린다. λ = 0.95 에서 첫 토큰은 마지막 토큰의 37.7% 만 받고, λ = 0.5 에서는 0.0002% — 사실상 아무 신호도 못 받는다. 여기서 V ≡ 0 이므로 이 감쇠는 순수한 편향이다. V 가 잘 학습되면 앞쪽 토큰의 크레딧을 V 가 대신 전달해 주어 편향이 줄지만, 학습 초기에는 이 표가 실제 상황에 가깝다.

길이가 길어지면 이 문제가 심각해진다

λ = 0.95 는 게임 환경에서 표준처럼 쓰이는 값이다. 길이 20 에서는 첫 토큰이 37.7% 를 받으니 괜찮다. 그런데 응답 길이가 200 이면 0.95199 = 3.69×10−5 다. 앞 문단 전체가 학습 신호를 못 받는다.

그래서 RLHF 구현에서는 γ = 1 과 함께 λ 를 1 에 가깝게 두거나 아예 λ = 1 로 두는 선택이 흔하다. 대신 늘어난 분산은 (28.4) 의 밀집 KL 항과 가치함수, 그리고 배치 크기로 감당한다. 29장에서 볼 GRPO 는 여기서 한 발 더 나가 가치함수를 아예 없애고 같은 프롬프트에 대한 여러 응답의 보상 평균을 기저선으로 쓴다 — 16장에서 본 기저선 아이디어를 응답 그룹에 적용한 것이다.

STEP 04

코드: 손계산을 재현하고, 작은 언어모델에 붙여 본다

세 조각이다. (a) 브래들리–테리 최대우도를 경사하강으로 풀어 앞 절의 표를 재현하고, (b) KL 정규화 최적해를 닫힌식과 수치최적화 양쪽으로 구해 일치를 확인하고, (c) 문자 네 개짜리 장난감 언어모델에 선호 학습을 통째로 돌린다. 전부 시드를 고정했고 CPU 2코어에서 2분 남짓 걸린다.

rl28.py — (a) 브래들리–테리 최대우도
import numpy as np, torch
torch.manual_seed(0); np.random.seed(0)
torch.set_num_threads(2)
D = [(0,1,3),(1,0,1),(0,2,2),(2,0,1),(1,2,4),(2,1,2)]   # (이긴쪽, 진쪽, 횟수)
r = torch.zeros(3, requires_grad=True)
opt = torch.optim.Adam([r], lr=0.05)
for it in range(6000):
    opt.zero_grad()
    loss = sum(-n*torch.nn.functional.logsigmoid(r[w]-r[l]) for w,l,n in D)
    loss = loss + 1e-6*(r.sum())**2              # 상수 이동 자유도만 고정(게이지)
    loss.backward(); opt.step()
rr = (r - r[2]).detach().numpy()                 # r_C = 0 으로 평행이동
print("(a) BT MLE  r_A=%.6f r_B=%.6f r_C=%.6f   NLL=%.6f"
      % (*rr, sum(-n*np.log(1/(1+np.exp(-(rr[w]-rr[l])))) for w,l,n in D)))
for i,j in [(0,1),(0,2),(1,2)]:
    nij = next(n for w,l,n in D if (w,l)==(i,j))
    nji = next(n for w,l,n in D if (w,l)==(j,i))
    print("    P(%s>%s) 모형 %.4f   관측 %d/%d = %.4f"
          % ("ABC"[i],"ABC"[j], 1/(1+np.exp(-(rr[i]-rr[j]))), nij, nij+nji, nij/(nij+nji)))
(a) BT MLE  r_A=1.197915 r_B=0.471799 r_C=0.000000   NLL=8.146214
    P(A>B) 모형 0.6740   관측 3/4 = 0.7500
    P(A>C) 모형 0.7682   관측 2/3 = 0.6667
    P(B>C) 모형 0.6158   관측 4/6 = 0.6667

손계산 절의 뉴턴해 (1.198002, 0.472247) 와 소수 셋째 자리까지 같다. 차이는 게이지 항 10−6(Σr)² 이 해를 아주 미세하게 끌어당긴 탓이고, NLL 은 8.146214 로 최소값 8.146215 와 사실상 구분되지 않는다. 게이지 항을 빼면 r(1,1,1) 방향으로 정처 없이 떠다니지만 r - r[2] 로 평행이동한 결과는 같다 — 직접 확인해 볼 만하다.

rl28.py — (b) KL 정규화 최적 정책: 닫힌식 vs 경사최적화
pref = torch.tensor([0.5,0.3,0.2]); rv = torch.tensor([1.0,0.0,-0.5])
print("\n(b) pi* = softmax(log pi_ref + r/beta)")
for beta in [0.1, 0.3, 1.0]:
    closed = torch.softmax(torch.log(pref) + rv/beta, 0)      # 식 (28.5)
    z = torch.zeros(3, requires_grad=True); o = torch.optim.Adam([z], lr=0.05)
    for _ in range(20000):                                    # 목적을 직접 최대화
        o.zero_grad(); p = torch.softmax(z,0)
        J = (p*rv).sum() - beta*(p*(torch.log(p)-torch.log(pref))).sum()
        (-J).backward(); o.step()
    p = torch.softmax(z,0).detach()
    print("  beta=%-4s 닫힌식 %s  경사 %s  |차| %.2e  beta*lnZ=%.6f"
          % (beta, np.array2string(closed.numpy(), precision=6),
             np.array2string(p.numpy(), precision=6),
             (closed-p).abs().max().item(),
             beta*torch.logsumexp(torch.log(pref)+rv/beta,0).item()))
(b) pi* = softmax(log pi_ref + r/beta)
  beta=0.1  닫힌식 [9.999726e-01 2.723922e-05 1.223576e-07]  경사 [9.999726e-01 2.724351e-05 1.698816e-07]  |차| 4.75e-08  beta*lnZ=0.930688
  beta=0.3  닫힌식 [0.976468 0.020901 0.002632]  경사 [0.976468 0.020901 0.002632]  |차| 3.73e-09  beta*lnZ=0.799200
  beta=1.0  닫힌식 [0.763371 0.168497 0.068132]  경사 [0.763371 0.168497 0.068132]  |차| 0.00e+00  beta*lnZ=0.576865

β 모두 앞 절의 표와 일치하고, 닫힌식과 수치최적화의 차이는 10−8 이하다. 그리고 β log Z 가 최적 목적값과 같다는 것도 확인된다(0.930688, 0.799200, 0.576865).

둘째 줄의 코드가 (28.5) 의 실무 형태다 — π* = softmax(log πref + r/β). 로그확률에 보상을 β 로 나누어 더하고 다시 정규화하는 한 줄이다. 이 형태는 제어된 디코딩(controlled decoding)에서 그대로 쓰이고, 21장 SAC 의 π ∝ exp(Q/α) 와도 같은 구조다. 그때 πref 자리에 균등분포를 넣으면 두 식이 문자 그대로 같아진다.

rl28.py — (c) 문자 네 개짜리 장난감에서 선호 학습 전 과정
V, T = 4, 4                                     # 어휘 abcd, 길이 4
def sample(logits, n):                          # bigram 정책: 상태=직전 문자(BOS=4)
    s = torch.full((n,), V, dtype=torch.long); out, lp = [], 0.0
    for _ in range(T):
        d = torch.distributions.Categorical(logits=logits[s])
        a = d.sample(); lp = lp + d.log_prob(a); out.append(a); s = a
    return torch.stack(out,1), lp
ref = torch.randn(V+1, V)*0.8                   # pi_ref: 고정된 무작위 기준모델
def truth(x): return (x==3).float().sum(1)      # 사람의 잠재 기준 = 'd' 개수
x1,_ = sample(ref, 4000); x2,_ = sample(ref, 4000)      # pi_ref 로 응답 쌍 생성
m = truth(x1) != truth(x2)                              # 동점 쌍은 버린다
w = torch.where(truth(x1[m])>truth(x2[m]), 1, 0)        # 사람의 선호 레이블
win = torch.where(w[:,None].bool(), x1[m], x2[m]); los = torch.where(w[:,None].bool(), x2[m], x1[m])
ntr = int(0.8*len(win))
RM = torch.nn.Sequential(torch.nn.Linear(V*T,16), torch.nn.Tanh(), torch.nn.Linear(16,1))
oh = lambda x: torch.nn.functional.one_hot(x, V).float().flatten(1)
orm = torch.optim.Adam(RM.parameters(), lr=0.01)
for _ in range(600):                                    # 2단계: BT 손실로 RM 학습
    orm.zero_grad()
    l = -torch.nn.functional.logsigmoid(RM(oh(win[:ntr]))-RM(oh(los[:ntr]))).mean()
    l.backward(); orm.step()
for beta in [0.05, 0.5, 3.0]:                           # 3단계: 정책경사 + KL 페널티
    pol = ref.clone().requires_grad_(True); op = torch.optim.Adam([pol], lr=0.05)
    for _ in range(400):
        op.zero_grad(); x, lp = sample(pol, 256)
        with torch.no_grad(): rew = RM(oh(x)).squeeze(1)
        kl = ((torch.softmax(pol,1)*(torch.log_softmax(pol,1)-torch.log_softmax(ref,1))).sum(1)).mean()
        adv = rew - rew.mean()                          # 16장 기저선
        (-(adv.detach()*lp).mean() + beta*kl*T).backward(); op.step()
(c) 보상모델: 학습쌍 1983개  보류쌍 정확도 1.000  BT손실 0.0003  r 범위 [-8.75, 11.18]
  beta=0.05  'd' 개수  pi_ref 0.906 -> pi 3.974   전부 d 비율 0.000 -> 0.978   평균KL/토큰 1.3092
  beta=0.5   'd' 개수  pi_ref 0.913 -> pi 3.643   전부 d 비율 0.000 -> 0.656   평균KL/토큰 0.9288
  beta=3.0   'd' 개수  pi_ref 0.900 -> pi 1.981   전부 d 비율 0.000 -> 0.005   평균KL/토큰 0.3085

읽을 것이 넷이다.

(c) 의 결과에서 읽을 것

1. 보상모델이 선호를 복원했다. 사람의 진짜 기준은 "문자 d 가 몇 개인가"인데, 보상모델은 그 기준을 한 번도 보지 못했다. 1983개의 승패 레이블만 봤다. 그런데 보류한 쌍에서 정확도 1.000 이다. 1비트짜리 비교를 충분히 모으면 실수값 기준이 복원된다는 첫 절의 주장이 여기서 확인된다.

2. 보상의 절대 수준은 여전히 의미가 없다. r 의 범위 [−8.75, 11.18] 에는 아무 의미가 없고, 시드를 바꾸면 통째로 옮겨 간다. 그래서 3단계에서 adv = rew − rew.mean() 로 배치 평균을 빼고 쓴다.

3. β 가 정확히 예상대로 작동한다. 기준정책에서 d 의 개수는 평균 0.9 개였다(무작위라면 4 × 0.25 = 1.0 근처가 맞다). β=0.053.974 까지 올라가고 응답의 97.8% 가 dddd 가 된다 — 모드 붕괴다. β=0.53.643, β=3.0 이면 1.981 로 기준정책에 훨씬 가깝게 머문다.

4. 붕괴가 KL 로 그대로 드러난다. 토큰당 평균 KL 이 1.3092 → 0.9288 → 0.3085β 에 따라 단조롭게 줄었다. β=0.051.31 nats 는 어휘가 4개일 때 가능한 최대치 log 4 = 1.386 에 육박한다. KL 을 로그로 찍어 두면 붕괴를 사후가 아니라 학습 중에 잡을 수 있다는 것이 여기서 얻을 실무 교훈이다.

이 장난감에서 β=0.05 의 결과는 사실 "성공"이다 — 사람의 기준이 진짜로 d 의 개수였으니, dddd 를 내놓는 정책이 옳다. 실제 RLHF 에서 이 상황이 재앙인 이유는 보상모델이 사람의 기준과 다르기 때문이다. 보상모델의 최댓값은 사람이 원하던 것이 아니라 보상모델의 허점인 경우가 많다. 29장이 그 이야기다.

STEP 05

시각화: 파이프라인·시그모이드·끌림·크레딧

도해 1 에서 이미 이 장의 출발점 — 절대평가를 버리고 쌍 비교를 택하는 이유 — 을 보았다. 여기서는 나머지 네 그림으로 파이프라인 전체와 세 개의 핵심 곡선을 정리한다.

ch28-d2
도해 2. RLHF 3단 파이프라인. 위 줄이 각 단계가 먹는 데이터, 가운데 줄이 손실, 화살표가 산출물의 흐름이다. 점선이 이 구조의 핵심 — πSFT 는 3단계의 초기값이면서 동시에 KL 의 기준점으로 끝까지 고정되어 남는다. 오른쪽 위 상자만 레이블이 필요 없다는 점이 RLHF 의 규모 경제다.
ch28-d3
도해 3. 실선이 BT 예측 승률 σ(Δ), 점선이 기울기 스칼라 1−σ(Δ) 다. 두 곡선은 서로의 거울상이다. Δ=0 에서 둘 다 0.5 — 판단이 반반이면 학습 신호가 가장 세다. Δ+3 을 넘으면 점선이 0.047 아래로 떨어져 그 쌍은 사실상 학습에서 빠진다. 보상모델 학습 후반의 기울기는 거의 전부 가운데 좁은 구간 — 사람도 갈렸던 쌍 — 에서 나온다.
ch28-d4
도해 4. 같은 πref·같은 r 에서 β 만 바꿨을 때의 최적 정책 (28.5). 맨 위가 β→∞, 즉 πref 그 자체다. 아래로 내려갈수록 첫 칸이 오른쪽으로 밀리며 나머지 둘을 삼킨다. 오른쪽 KL 값이 그 이동거리다. β=0.1 줄의 KL 0.693 은 결정적 정책의 한계값 ln(1/0.5)=0.693147 에 사실상 도달한 것 — 붕괴 직전이다.
ch28-d5
도해 5. 끝에 한 번 들어온 r=1 이 20개 토큰에 어떻게 배분되는지. λ=1 은 전부 똑같이 1.0 — 어느 토큰이 기여했는지 구분하지 않는다. λ=0.5 는 마지막 서너 토큰만 신호를 받고 앞쪽은 10−6 수준으로 사라진다. 응답이 길어지면 이 감쇠는 지수적으로 악화되어, 길이 200·λ=0.95 에서 첫 토큰의 이점은 3.69×10−5 다.

이 장이 남긴 두 개의 실 끝

첫째, 보상모델은 대리인이다. 3단계는 사람이 아니라 2단계가 만든 근사를 최적화하고, 그 근사가 정확한 영역은 πref 근처뿐이다. KL 항이 그 영역을 지키며, 방어가 뚫릴 때 일어나는 일이 보상 해킹이다. 둘째, 식 (28.5) 는 파이프라인을 접을 수 있다고 말한다. 최적 정책이 보상으로 닫힌 꼴이면 거꾸로 보상을 정책으로 적을 수 있고, 그러면 보상모델이라는 중간 산물이 필요 없어진다. 29장의 DPO 가 그 길을 간다.

여기서 인용할 만한 실증은 InstructGPT 논문(Ouyang 외, 2022)이 보고한 사람 평가 결과다 — 그 논문은 13억 파라미터 InstructGPT 의 출력이 1750억 파라미터 GPT-3 의 출력보다 사람 평가자에게 더 선호되었다고 보고했다. 파라미터 수를 백 배 이상 줄이고도 선호도가 높았다는 것이 RLHF 가 주목받은 직접적 계기다. 이 시리즈에서는 그 규모의 실험을 재현하지 않으며, 위 문장은 원논문의 보고값을 인용한 것이다. 우리가 직접 확인한 것은 앞의 코드 장난감 — 선호 레이블만으로 보이지 않던 기준이 복원된다는 사실 — 까지다.

이것만 기억하자

  1. 브래들리–테리는 보상의 차이만 식별한다. σ(rw−rl) 에 절대 수준이 들어갈 자리가 없으므로, 게이지를 고정하지 않으면 해가 직선 전체다. 그래서 보상모델의 출력값 자체는 해석하지 않는다.
  2. 1차 조건은 "실제 승수 = 기대 승수" 한 줄이다. 세 응답 13번 비교에서 rC=0 으로 고정하면 rA=1.198002, rB=0.472247 이고, 쌍별 승률은 못 맞히지만 응답별 총 승수는 정확히 맞는다.
  3. KL 정규화 목적의 최적해는 π* ∝ πref·exp(r/β) 이고 최적값은 β log Z 다. β=1 이면 (0.763371, 0.168497, 0.068132), β=0.1 이면 (0.999973, 0.000027, ≈0) 로 사실상 결정적이 된다. 이 식을 뒤집는 것이 29장 DPO 다.

흔한 오해

  1. "보상모델 점수가 5.0 이면 3.0 짜리보다 확실히 낫다" — 같은 보상모델·같은 프롬프트 안에서만 그렇다. 모델을 다시 학습시키면 출력 범위가 통째로 옮겨 가고, 프롬프트가 다르면 비교 자체가 의미 없다. 비교 가능한 것은 같은 x 에 대한 두 응답의 차이뿐이다.
  2. "KL 페널티는 과적합을 막는 정규화다" — 목적이 다르다. 이것은 보상모델의 유효 범위를 지정하는 장치다. 26장 오프라인 RL 의 분포 이탈 대책과 같은 계열이고, 겸해서 모드 붕괴를 막는다. β 를 키운다는 것은 "대리인을 덜 믿겠다"는 뜻이지 "덜 학습하겠다"는 뜻이 아니다.
  3. "RLHF 의 KL 은 PPO 의 KL 과 같은 것이다" — 기준이 다르다. PPO·TRPO 의 KL 은 πold 를 보며 매 갱신마다 기준이 따라 움직이는 걸음 크기의 자다. RLHF 의 KL 은 고정된 πref 를 보는 총 이동거리의 자다. 실제 구현에서는 둘이 동시에 작동한다.
  4. "λ=0.95 면 신용할당은 해결된다" — 길이에 달렸다. L=20 에서 첫 토큰은 0.377 을 받지만 L=200 에서는 3.69×10−5 다. 응답 앞부분이 학습에서 사실상 배제된다. 긴 응답을 다룰 때 λ 를 1 에 가깝게 두는 구현이 많은 이유가 이것이다.

댓글