GRPO Trainer

GRPO Trainer (그룹 상대 정책 최적화)

모델의 추론 능력, 특히 수학 문제 해결 능력을 키우는 데 효과적인 강화학습 방법이 GRPO(Group Relative Policy Optimization)예요. TRL의 GRPOTrainer가 이 방법을 지원합니다. PPO가 항상 필요했던 별도의 value 네트워크 없이, 그룹 내 상대 비교만으로 어드밴티지를 계산해 메모리 사용을 줄인다는 점이 특징이에요.

출처: GRPO Trainer - Hugging Face TRL 공식문서

개요

TRL은 논문 DeepSeekMath: Pushing the Limits of Mathematical Reasoning in Open Language Models에 기술된 GRPO 트레이너를 지원해요. 저자는 Zhihong Shao, Peiyi Wang, Qihao Zhu, Runxin Xu, Junxiao Song, Mingchuan Zhang, Y. K. Li, Y. Wu, Daya Guo입니다.

논문 초록의 핵심을 요약하면 다음과 같아요.

수학적 추론은 그 복잡하고 구조화된 특성 때문에 언어 모델에 큰 도전 과제다. 이 논문에서 DeepSeekMath 7B를 소개하는데, DeepSeek-Coder-Base-v1.5 7B를 Common Crawl에서 수집한 120B 개의 수학 관련 토큰 + 자연어·코드 데이터로 계속 사전학습했다. DeepSeekMath 7B는 외부 도구·투표 기법 없이 대회 수준 MATH 벤치마크에서 51.7%를 기록해 Gemini-Ultra·GPT-4 수준에 근접했다. 64개 샘플의 self-consistency로는 MATH에서 60.9%를 달성했다. 수학 추론 능력의 원인은 두 가지다. 첫째, 정교하게 설계된 데이터 선택 파이프라인으로 공개 웹 데이터의 큰 잠재력을 활용했다. 둘째, PPO의 변형인 GRPO를 도입해 수학적 추론 능력을 높이면서 동시에 PPO의 메모리 사용을 최적화했다.

이 사후훈련 방법은 Quentin Gallouédec이 기여했어요.

빠른 시작

이 예시는 GRPO 방법으로 모델을 훈련하는 법을 보여줍니다. Qwen2.5 0.5B Instruct 모델DeepMath-103K 데이터셋의 prompt로 훈련해요.

# train_grpo.py
from datasets import load_dataset
from trl import GRPOTrainer
from trl.rewards import accuracy_reward

dataset = load_dataset("trl-lib/DeepMath-103K", split="train")

trainer = GRPOTrainer(
    model="Qwen/Qwen2.5-0.5B-Instruct",
    reward_funcs=accuracy_reward,
    train_dataset=dataset,
)
trainer.train()

다음 명령으로 스크립트를 실행합니다.

accelerate launch train_grpo.py

8개 GPU에 분산하면 훈련에 약 1일이 걸립니다.

GRPO curves

Note: 위 보상 곡선은 Qwen/Qwen2-0.5B-Instruct로 생성됐어요. Qwen/Qwen2.5-0.5B-Instruct 결과도 질적으로 비슷합니다.

GRPO 방법 자세히 보기

GRPO는 온라인 학습 알고리즘으로, 훈련 중에 훈련되는 모델 스스로가 생성한 데이터를 사용해 반복적으로 개선돼요. GRPO 목적 함수의 직관은 생성된 completion의 어드밴티지를 최대화하되, 모델이 참조 정책(reference policy)에 가깝게 유지되도록 하는 것입니다. GRPO가 어떻게 동작하는지는 네 단계로 나눌 수 있어요: completion 생성, 어드밴티지 계산, KL 발산 추정, 손실 계산.

GRPO visual

Completion 생성

각 훈련 단계에서 prompt 배치를 샘플링하고, 각 prompt에 대해 ( G ) 개의 completion 집합을 생성합니다(( o_i ) 로 표기).

어드밴티지 계산

( G ) 개 시퀀스 각각에 대해 보상 모델 또는 보상 함수로 보상을 계산해요. 보상 모델은 보통 같은 질문에 대한 출력 비교 데이터셋으로 훈련되므로, 어드밴티지는 그 상대 비교를 반영하도록 계산됩니다. 다음과 같이 정규화해요.

$$\hat{A}_{i,t} = \frac{r_i - \text{mean}(\mathbf{r})}{\text{std}(\mathbf{r})}$$

이 방식이 방법의 이름인 Group Relative Policy Optimization (GRPO) 의 유래입니다.

[!TIP] 논문 Understanding R1-Zero-Like Training: A Critical Perspective에서 ( \text{std}(\mathbf{r}) ) 로 스케일링하면 질문 수준의 난이도 편향이 생길 수 있음이 밝혀졌어요. GRPOConfig에서 scale_rewards=False로 설정하면 이 스케일링을 끌 수 있습니다. std 기반 스케일링을 끄면 분산 정규화도 제거되므로, 업데이트 크기가 원시 보상 스케일과 배치 구성에 직접 의존하게 됩니다.

[!TIP] Part I: Tricks or Traps? A Deep Dive into RL for LLM Reasoning (Lite PPO)에서 보여주듯, 평균은 로컬(그룹) 수준, 표준편차는 글로벌(배치) 수준으로 계산하면 더 견고한 보상 형태가 됩니다. GRPOConfig에서 scale_rewards="batch"로 설정해 이 스케일링 전략을 쓸 수 있어요.

KL 발산 추정

KL 발산은 Schulman et al. (2020)이 도입한 근사기를 사용해 추정합니다.

$$\mathbb{D}{\text{KL}}\left[\pi\theta |\pi_{\text{ref}}\right] = \frac{\pi_{\text{ref}}(o_{i,t} \mid q, o_{i,<t})}{\pi_\theta(o_{i,t} \mid q, o_{i,<t})} - \log \frac{\pi_{\text{ref}}(o_{i,t} \mid q, o_{i,<t})}{\pi_\theta(o_{i,t} \mid q, o_{i,<t})} - 1,$$

손실 계산

목표는 모델이 참조 정책에 가깝게 유지되면서 어드밴티지를 최대화하는 것입니다. 따라서 손실은 다음과 같이 정의됩니다.

$$ \mathcal{L}{\text{GRPO}}(\theta) = -\frac{1}{\sum{i=1}^G |o_i|} \sum_{i=1}^G \sum_{t=1}^{|o_i|} \left[ \frac{\pi_\theta(o_{i,t} \mid q, o_{i,< t})}{\left[\pi_\theta(o_{i,t} \mid q, o_{i,< t})\right]{\text{no grad}}} \hat{A}{i,t} - \beta \mathbb{D}{\text{KL}}\left[\pi\theta | \pi_{\text{ref}}\right] \right], $$

여기서 첫 항은 스케일링된 어드밴티지, 두 번째 항은 KL 발산을 통한 참조 정책과의 편차 페널티입니다.

[!TIP] 원래 DeepSeekMath 정식화와 달리 ( \frac{1}{|o_i|} ) 로는 스케일링하지 않아요. Understanding R1-Zero-Like Training 논문에서 이 항이 응답 수준 길이 편향을 유발함이 밝혀졌기 때문입니다. 자세한 내용은 loss types 참고.

또한 원래 정식화와 달리 기본값으로 ( \beta = 0.0 ) 을 씁니다. 즉 KL 발산 항을 사용하지 않아요. 여러 최근 연구(예: Open-Reasoner-Zero)가 KL 발산 항이 GRPO 훈련에 필수적이지 않음을 보였고, 그래서 제외하는 게 일반적입니다. 포함하려면 GRPOConfig에서 beta를 0이 아닌 값으로 설정하세요.

원래 논문에서는 이 정식화가 clipped surrogate objective를 이용해 각 생성 이후 여러 번의 업데이트(num_iterations로 설정, ( \mu ) 로 표기)를 허용하도록 일반화됩니다.

$$ \mathcal{L}{\text{GRPO}}(\theta) = - \frac{1}{\sum{i=1}^G |o_i|} \sum_{i=1}^G \sum_{t=1}^{|o_i|} \left[ \min \left( \frac{\pi_\theta(o_{i,t} \mid q, o_{i,< t})}{\pi_{\theta_{\text{old}}}(o_{i,t} \mid q, o_{i,< t})} \hat{A}{i,t}, , \text{clip}\left( \frac{\pi\theta(o_{i,t} \mid q, o_{i,< t})}{\pi_{\theta_{\text{old}}}(o_{i,t} \mid q, o_{i,< t})}, 1 - \epsilon, 1 + \epsilon \right) \hat{A}{i,t} \right) - \beta \mathbb{D}{\text{KL}}\left[\pi_\theta | \pi_{\text{ref}}\right] \right], $$

여기서 ( \text{clip}(\cdot, 1 - \epsilon, 1 + \epsilon) ) 는 정책 비율을 ( 1 - \epsilon ) 과 ( 1 + \epsilon ) 사이로 묶어 업데이트가 참조 정책에서 과도하게 벗어나지 않게 합니다. ( \mu = 1 )(TRL 기본값)이면 clipped surrogate objective는 원래 목적 함수로 단순화됩니다.

손실 타입

문헌에는 여러 목적 함수 정식화가 제안됐어요. 처음에는 GRPO의 목적 함수가 다음과 같이 정의됐습니다.

$$ \mathcal{L}{\text{GRPO}}(\theta) = - \frac{1}{G} \sum{i=1}^G \frac{1}{|o_i|} \sum_{t=1}^{|o_i|} l_{i,t}, $$

여기서

$$ l_{i,t} = \frac{\pi_\theta(o_{i,t} \mid q, o_{i,< t})}{\left[\pi_\theta(o_{i,t} \mid q, o_{i,< t})\right]{\text{no grad}}} \hat{A}{i,t} - \beta \mathbb{D}{\text{KL}}\left[\pi\theta | \pi_{\text{ref}}\right]. $$

DAPO 논문은 긴 CoT 시나리오에서 GRPO의 샘플 레벨 손실 한계를 지적합니다. 긴 응답은 과소 페널티되어 출력 품질이 떨어지죠. 제안된 해결책은 토큰 레벨 정규화로, 응답 길이와 무관하게 개별 토큰에 더 균형 잡힌 보상을 배분해 긴 시퀀스를 더 잘 처리합니다.

$$ \mathcal{L}{\text{DAPO}}(\theta) = - \frac{1}{\sum{i=1}^G |o_i|} \sum_{i=1}^G \sum_{t=1}^{|o_i|} l_{i,t}, $$

더 알아보기 (Learn more)