이 글의 목표

강화학습이나 RLHF(Reinforcement Learning from Human Feedback)를 보다 보면 아래 식을 자주 만나게 된다.

RLHF, PPO, DPO, GRPO는 이름도 다르고 수식도 달라 보이지만, 결국 공통으로 묻는 질문은 같다.

어떻게 하면 좋은 응답의 확률을 높일 수 있을까?

이 글은 그 질문에 대한 가장 기본적인 답인 policy gradient를 처음부터 따라가며 이해하는 노트다. 목표는 policy gradient 식을 외우는 것이 아니라, 왜 그런 모양이 되는지를 이해하는 것이다. 그 과정속에서 수학적 엄밀성이 떨어질 수도 있겠지만, 이해를 우선으로 두도록 하자.

이 글에서는 어떻게 위 식으로 바뀌는지 하나씩 따라가본다.


왜 Policy Gradient부터 봐야 하나

RLHF, PPO, DPO, GRPO는 서로 다른 방법처럼 보이지만 큰 흐름에서는 모두 “좋은 응답을 더 자주 생성하게 만드는 방법”이라는 공통점을 가진다.

  • RLHF는 reward model이 준 점수를 바탕으로 policy를 업데이트한다.
  • PPO는 policy gradient를 더 안정적으로 업데이트하는 방법이다.
  • DPO는 RLHF의 일부 단계를 직접 최적화 문제로 다시 쓴 것이다.
  • GRPO는 다시 policy optimization 쪽으로 돌아오되, 상대 비교를 더 적극적으로 활용한다.

즉, policy gradient를 이해하면 이후의 RLHF 계열 알고리즘이 훨씬 덜 낯설어진다.


기호 정의 및 연습

수식 설명에 앞서, 사용할 기호는 다음과 같이 정의한다.

  • (세타): 모델 파라미터
  • (파이): 정책(policy)
  • (타우): trajectory(하나의 전체 경험)
  • (기댓값): expectation, 확률을 고려한 평균
  • (시그마): 합
  • (곱): 여러 항의 곱
  • (나블라 세타): 세타에 대한 gradient
  • (로그): 보통 자연로그
  • (given, 바): “~가 주어졌을 때”
  • (“~를 따른다”): 샘플링 또는 분포를 따른다
  • (state): 상태
  • (action): 행동
  • (reward): 보상

그렇다면 이제 다음 수식은 어떻게 읽히는가?

상태 가 주어졌을 때, 정책 가 행동 를 선택할 확률(또는 확률밀도)


평균과 기댓값

평균과 기댓값은 너무 익숙한 개념이지만, 한번 짚고 넘어가자. 한 줄로 요약하면 다음과 같다.

평균은 이미 관측한 데이터의 요약이고,
기댓값은 확률분포가 만들어내는 장기적인 평균이다.

평균: 이미 관측한 데이터의 중심

숫자 세 개 이 있다고 하자. 이들의 평균은 이다. 이 값은 이미 손에 들어온 데이터를 똑같이 한 번씩 반영해서 계산한 것이다. 즉, 평균은 관측된 표본(sample)의 중심을 요약한다.

이를 일반화하면, 개의 관측값 의 평균은 다음으로 정의된다.

기댓값: 확률을 고려한 평균

이번에는 어떤 값이 나올 확률이 서로 다르다고 하자.

  • 1이 나올 확률: 0.8
  • 5가 나올 확률: 0.2

이때 확률까지 고려한 평균은 이다. 이 값이 바로 기댓값(expected value) 이다. 즉, 기댓값은 단순한 평균이 아니라 확률을 가중치로 둔 평균이다.

이를 일반화하면, 이산형 확률변수 의 기댓값은 다음으로 정의된다.

연속형 확률변수라면 합 대신 적분을 사용하여

로 쓴다.

그렇다면 다음 수식은 어떻게 읽히는가?

가능한 모든 값 에 대해, 그 값이 나올 확률 와 값 자체 를 곱해서 모두 더한 것


강화학습에서의 목표: 기대 Return 최대화

강화학습에서는 한 번의 실행 결과를 trajectory라고 부르며, 이는 다음과 같이 (시점 의 상태), (시점 의 행동)로 구성된다.

그리고 이 trajectory 전체의 점수를 return 이라고 한다.

  • : trajectory 의 전체 return
  • : 시점 의 보상(reward)
  • : discount factor

이때, 감마 는 미래 보상을 얼마나 중요하게 볼지 정한다.

  • : 미래 보상도 동일하게 중요
  • : 먼 미래의 보상은 조금 덜 중요

이제 정책 의 목표는 기대 return이 큰 trajectory를 더 자주 생성하도록 하는 것이다.

여기서 는 현재 정책 아래에서 trajectory가 샘플링된다는 뜻의 약식 표기다.

조금 더 엄밀하게 쓰면, 정책 와 환경의 상태 전이 확률이 함께 결정하는 trajectory 분포를 라고 둘 수 있고, 이때

와 같이 쓸 수 있다. 즉, 이후에 등장할 는 정책 와 환경의 상태 전이 확률이 함께 결정하는 trajectory distribution이다.

즉, policy optimization기대 return 를 최대화하는 문제와 같다. 실제 학습에서는 이 기댓값을 여러 rollout의 표본평균으로 추정한다.


그래도 와닿지 않는다면?

기댓값이 아직 추상적으로 느껴진다면, 정의를 그대로 풀어 써보면 된다.

이 식은 이산형(discrete)인 경우 다음과 같이 쓸 수 있다.

  • : 현재 정책과 환경 전이 아래에서 trajectory 가 생성될 확률
  • : 그 trajectory의 return

그렇다면 이제 이 식은 어떻게 읽히는가?

가능한 모든 trajectory에 대해, “그 trajectory가 나올 확률 × 그 trajectory의 return”을 전부 더한 것이 정책의 기대 return이다.


우리의 목표는 최대화

이제 다시 한번 목표를 상기시켜보자. 우리는 를 최대화하고 싶다. 주어진 목표함수는

이므로, 에 대해 미분하면

를 얻는다. 여기서 는 “주어진 trajectory의 return”으로 보고, 에 직접 의존하지 않는다고 둔다. 따라서 미분은 에만 걸리고, 다음과 같이 정리 가능하다.


Log-Derivative Trick

이제 로그미분 트릭을 사용해 식을 더 다루기 쉬운 형태로 바꿔보자. 먼저 다음 항등식을 떠올리자.

이를 에 적용하면

이고, 양변에 를 곱하면

를 얻는다. 이제 이 식을 앞에서 얻은

에 대입하면,

를 얻는다.

이제 식이 다시 기댓값의 형태로 보인다. 왜냐하면 일반적으로 어떤 함수 에 대해

이기 때문이다.

따라서 위 식은 다음처럼 다시 쓸 수 있다.

이 식은 어떻게 읽히는가?

policy gradient는 trajectory별 return과 trajectory log-probability gradient의 곱을, 현재 정책이 만드는 trajectory 분포 위에서 평균낸 것이다.

즉, 평균적으로 보았을 때 return이 큰 trajectory일수록 그 trajectory를 만들어낸 선택들의 확률을 높이는 방향으로 업데이트 가 이루어진다.

이 식이 policy gradient 유도의 첫 번째 핵심식이다.


Trajectory 확률은 어떻게 생겼을까?

이제 를 더 구체적으로 보자. trajectory의 확률은 보통 다음과 같이 쓸 수 있다.

  • : 초기 상태 가 나올 확률
  • : 정책이 상태 에서 행동 를 선택할 확률
  • : 환경이 다음 상태 로 전이될 확률

즉, 하나의 trajectory가 나올 확률은

  1. 처음 상태가 어떻게 시작되는지
  2. 각 시점에서 정책이 어떤 행동을 선택하는지
  3. 그 행동 이후 환경이 어떻게 다음 상태로 전이되는지 를 모두 곱한 것으로 볼 수 있다.

로그: 곱을 합으로 바꾸기

이제 이 식을 미분하기 쉬운 형태로 바꾸기 위해 로그를 취해보자. 로그의 기본 성질은 다음과 같다.

이를 이용하면 trajectory 확률의 로그는 다음과 같이 쓸 수 있다.

이제 에 대해 미분하면

를 얻는다. 표준적인 model-free setting에서는 (1) 초기 상태 분포 와 무관하고, (2) 환경 전이 와 무관하다고 둔다.

따라서 앞의 두 항은 0이 되고, 결국 남는 것은 다음과 같다.

이를 앞에서 얻은 식에 다시 대입하면, 다음과 같다.

이것이 REINFORCE의 가장 기본적인 형태다.

이 식은 어떻게 읽히는가?

어떤 trajectory의 결과가 좋았다면, 그 trajectory 안에서 선택된 행동들의 확률을 높이는 방향으로 업데이트한다.

즉,

  • 좋은 결과를 낸 행동은 더 자주 하게 만들고
  • 나쁜 결과를 낸 행동은 덜 자주 하게 만든다.

그런데 왜 전체 Return을 다 곱할까?

위 식은 맞지만, 분산이 큰 형태다. 과거 보상은 현재 행동 가 바꿀 수 없는 값 이다. 그런데도 전체 return 를 그대로 곱하면, 현재 행동과 무관한 변동까지 gradient estimator에 함께 들어간다. 그 결과 기댓값은 같더라도 샘플마다 업데이트가 더 크게 흔들린다. 따라서 시점 의 행동은 그 이후에 얻는 보상으로 평가하는 편이 더 자연스럽다.

이처럼 시점 이후의 보상만 합친 값을 reward-to-go라고 부른다. 그러면 policy gradient는 다음과 같이 쓸 수 있다.

이 식은 어떻게 읽히는가?

시점 의 행동은 그 이후의 결과로 평가하자.


Baseline은 왜 빼도 될까?

이제 policy gradient는 흔히 다음처럼 쓰기도 한다.

여기서 는 baseline이다. 상태 에서의 기준점이라고 보면 된다.

baseline을 빼는 이유는 분산을 줄이기 위해서다. 직관적으로는 “그 행동의 절대 점수”보다 “평균보다 얼마나 더 좋았는가”를 보는 쪽이 업데이트를 더 안정적으로 만든다.

그런데 baseline을 빼면 gradient 자체가 바뀌는 것처럼 보인다. 핵심은, action에 의존하지 않는 baseline 항의 기댓값은 0 이라는 점이다.

먼저 아래 식을 보자.

왜냐하면

이므로,

가 되고, 따라서

가 된다.

그러므로 baseline 항의 조건부 기댓값은

이 된다.

즉, action에 의존하지 않는 baseline은 평균적으로 사라진다. 따라서 baseline을 빼도 bias는 생기지 않고, 대신 variance는 줄일 수 있다.


Baseline을 Value로 두면 Advantage의 추정치가 된다

baseline의 가장 대표적인 선택은 상태가치 함수다.

여기서 상태가치 함수와 행동가치 함수는 각각 다음처럼 정의된다.

즉,

  • 는 상태 에 도착했을 때, 이후 정책 를 따라가면 평균적으로 얼마나 좋은가
  • 는 상태 에서 행동 를 한 뒤, 이후 정책 를 따라가면 평균적으로 얼마나 좋은가

를 나타낸다.

이 둘의 차이가 바로 advantage다.

이 식은 다음처럼 읽을 수 있다.

상태 에서 행동 가, 그 상태의 평균적인 선택보다 얼마나 더 좋았는가

그런데 실제 rollout에서 우리가 직접 관측하는 것은 자체가 아니라, 그 시점 이후 실제로 얻은 return인 다.

중요한 점은 와 항상 같은 값은 아니라는 것이다. 는 하나의 rollout에서 나온 샘플값이고, 는 그런 샘플들의 조건부 기댓값이다. 이를 수식으로 쓰면

이다.

따라서 baseline을 상태가치 함수로 두면

는 advantage 그 자체라기보다는, advantage의 샘플 추정치로 해석하는 것이 정확하다. 실제로 그 조건부 기댓값은

가 된다.

즉, 는 샘플마다 흔들릴 수는 있지만, 평균적으로는 정확히 advantage를 맞춘다. 그래서 실제 학습에서는 이 값을 사용해 “이 행동이 평균보다 얼마나 더 좋았는가”를 샘플 단위에서 추정한다고 볼 수 있다.

이 관점에서 policy gradient는 다음처럼 쓸 수 있다.

여기서 는 advantage의 추정치이며, 가장 단순한 형태로는 다음처럼 둘 수 있다.

이 식은 직관적으로 어떻게 읽히는가?

평균보다 더 좋았던 행동이면 그 확률을 높이고, 평균보다 덜 좋았던 행동이면 그 확률을 낮춘다.

실제에서는 보통 를 정확히 알 수 없기 때문에, 이를 근사하는 value function 를 학습해서 사용한다. 또한 더 안정적인 학습을 위해 TD error나 GAE 같은 더 정교한 advantage estimator를 쓰기도 한다. 정리하면, baseline을 상태가치 함수로 두면 policy gradient의 기댓값은 유지하면서도 분산을 줄일 수 있고, 이때 는 advantage의 가장 기본적인 샘플 추정치로 이해할 수 있다.


LLM과 RLHF 문맥으로 다시 읽기

이제 이 식을 언어모델 쪽으로 다시 해석해 보자. 전통적인 강화학습에서는 상태 , 행동 를 다루지만, LLM에서는 이를 :prompt, :completion 로 생각할 수 있다.

즉, 는 “프롬프트 가 주어졌을 때 응답 를 생성할 확률”이다.

엄밀하게 보면, LLM을 강화학습으로 해석할 때는 completion 전체를 한 번에 내는 것이 아니라 토큰 단위의 순차적 의사결정 과정 으로 보는 쪽이 더 표준적이다.

즉, 상태(state)는 “지금까지 생성한 prefix”이고, 행동(action)은 “다음 토큰을 무엇으로 생성할 것인가”에 해당한다.

다만 RLHF를 처음 이해하는 단계에서는 이를 prompt 와 completion 수준으로 추상화해도 큰 흐름을 이해하는 데는 충분하다.

그러면 policy gradient도 같은 구조로 읽을 수 있다.

좋은 응답이면 그 응답의 확률을 높이고,
나쁜 응답이면 그 응답의 확률을 낮춘다.

RLHF는 결국 이 아이디어를 reward model, KL penalty, PPO 같은 장치와 결합한 것이다. 즉, RLHF는 policy gradient를 언어모델 post-training에 맞게 이식한 것 이라고 보는 편이 이해하기 쉽다.


다시 정리

policy gradient의 전개는 다음 흐름으로 이해할 수 있다.

1. 정책의 목표는 기대 return을 최대화하는 것이다.

즉, 정책이 만들어내는 trajectory들의 기대 return이 커지도록 를 업데이트하고 싶다.

2. 기댓값은 확률가중합으로 풀어쓸 수 있다.

즉, 가능한 모든 trajectory에 대해 “그 trajectory가 나올 확률 그 trajectory의 return”을 더한 값이 정책의 기대 return다.

3. 이제 이를 에 대해 미분한다.

여기서는 표준적인 model-free setting에서 에 직접 의존하지 않는다고 둔다.

4. 로그미분 트릭을 적용하면 gradient를 더 다루기 쉬운 형태로 바꿀 수 있다.

따라서 다음식을 얻을 수 있다.

5. trajectory 확률의 로그를 전개하면, 결국 정책 항만 남는다.

따라서

가 된다. 이것이 REINFORCE의 가장 기본적인 형태다.

6. 하지만 시점 의 행동을 평가할 때 전체 return을 그대로 쓰면 불필요한 분산이 커질 수 있다.

그래서 시점 이후의 return만 사용하는 reward-to-go를 도입한다.

그러면 식은 다음과 같이 쓸 수 있다.

7. 여기에 baseline을 빼면 기댓값은 유지하면서 분산을 더 줄일 수 있다.

특히 baseline으로 상태가치 함수를 사용하면

이고, 이때

는 advantage의 샘플 기반 추정치로 볼 수 있다. 이상적인 advantage는

이며, 실제 학습에서는 보통

또는 그 변형을 사용한다. 따라서 policy gradient는 최종적으로

처럼 이해할 수 있다.

즉, policy gradient의 핵심은 다음 한 문장으로 요약된다.

평균보다 더 좋았던 행동이면 그 확률을 높이고, 평균보다 덜 좋았던 행동이면 그 확률을 낮춘다.


다음 글

다음 글에서는 REINFORCE와 baseline 를 살펴본다.

policy gradient의 기댓값이 실제 rollout 샘플을 이용한 업데이트 규칙으로 어떻게 바뀌는지, 그리고 왜 이 방식이 high variance 문제를 갖는지 정리할 예정이다.


시리즈 메모

📎 Reference

References