TRL documentation

비동기 GRPO Trainer

You are viewing main version, which requires installation from source. If you'd like regular pip install, checkout the latest stable version (v1.18.0).
Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

비동기 GRPO Trainer

model badge

개요

AsyncGRPOTrainer는 동일한 GRPO 알고리즘을 구현하지만, 롤아웃 생성과 학습을 분리합니다. 백그라운드 워커가 vLLM 서버에서 완료 결과를 지속적으로 스트리밍하는 동안 학습 루프가 이를 소비하므로, 생성과 그래디언트 업데이트가 번갈아 수행되는 대신 겹쳐서 실행됩니다.

이 trainer는 Amine Dirhoussi와 Quentin Gallouédec에 의해 기여되었습니다.

빠른 시작

이 예제는 비동기 GRPO(Asynchronous GRPO) 방법을 사용하여 모델을 학습하는 방법을 보여줍니다. DeepMath-103K 데이터셋의 프롬프트를 사용하여 Qwen3.5 2B 모델을 학습합니다. 데이터셋의 데이터는 여기서 확인할 수 있습니다:

아래는 모델을 학습하는 스크립트입니다. trainer는 vLLM과 kernels가 필요하며, accuracy_reward는 math-verify가 필요합니다. pip install trl[vllm,kernels,math_verify]로 설치할 수 있습니다.

# train_async_grpo.py
from datasets import load_dataset
from trl import AsyncGRPOTrainer
from trl.rewards import accuracy_reward

if __name__ == "__main__":  # the rollout worker is a spawned process that re-imports this script
    dataset = load_dataset("trl-lib/DeepMath-103K", split="train")

    trainer = AsyncGRPOTrainer(
        model="Qwen/Qwen3.5-2B",
        reward_funcs=accuracy_reward,
        train_dataset=dataset,
    )
    trainer.train()

Generation은 trainer와 다른 GPU에서 실행되는 vLLM 서버에서 수행됩니다. GPU 0에서 시작하세요:

CUDA_VISIBLE_DEVICES=0 VLLM_SERVER_DEV_MODE=1 vllm serve Qwen/Qwen3.5-2B \
    --weight-transfer-config '{"backend": "nccl"}' \
    --logprobs-mode processed_logprobs \
    --api-server-count 8 \
    --max-model-len 4096

다음 명령을 사용하여 GPU 1에서 스크립트를 실행합니다:

CUDA_VISIBLE_DEVICES=1 python train_async_grpo.py

호환성 및 제약

현재 AsyncGRPOTrainer 구현에서는 일부 인자 조합이 의도적으로 제한되어 있습니다:

  • Generation은 항상 vllm serve로 시작되는 별도의 vLLM 서버에서 실행됩니다. colocate 모드는 없습니다.
  • 데이터셋의 프롬프트는 대화형 형식이어야 합니다. environment_factory를 사용하는 경우, 데이터셋에 prompt 열이 없을 수 있으며, reset()이 이를 제공합니다.
  • Reward 함수는 Python에서 호출 가능한 객체여야 합니다. 모델 ID 또는 PreTrainedModel으로 제공되는 Reward 모델은 지원되지 않으며, 사용자 정의 Reward 함수 사용을 참고하세요.
  • Trainer는 transformers>=5.2.0이 필요합니다.
  • Sharded training은 FSDP2를 사용합니다. DeepSpeed는 지원되지 않으며, 컨텍스트 및 시퀀스 병렬성(parallelism_config에서 cp_size > 1 또는 sp_size > 1)도 지원되지 않습니다.
  • use_liger_kernel=True는 지원되지 않습니다.
  • lm_head를 대상으로 하는 PEPT 어댑터는 지원되지 않습니다.
  • Attention sink이 있는 모델은 지원되지 않습니다. 지원되는 비-attention 레이어는 하이브리드 모델(Qwen3.5, Qwen3.6, Qwen3-Next, …)의 gated DeltaNet 레이어뿐이며, transformers>=5.15.0이 필요합니다.
  • 이미지는 지원되지 않으며, 비전 언어 모델 학습을 참조하세요.

Training은 kernels 라이브러리를 통해 Hub에서 attention 커널을 로드합니다: AMD GPU(ROCm)의 경우 kernels-community/aiter-flash-attn, NVIDIA Blackwell GPU의 경우 kernels-community/flash-attn4, 기타 NVIDIA GPU의 경우 kernels-community/flash-attn3입니다. attention logits에 상한을 설정하는 모델(attn_logit_softcapping)은 Gemma 2와 같이 AMD GPU 또는 NVIDIA Blackwell GPU에서 지원되지 않습니다.

비동기 GRPO 방법 자세히 살펴보기

GRPOTrainer에서는 생성과 학습이 순차적으로 수행됩니다: 배치 생성, 손실 계산, 가중치 업데이트, 반복. colocate mode에서도 한 단계가 끝나야 다른 단계가 시작됩니다. AsyncGRPOTrainer에서는 롤아웃 워커가 백그라운드 프로세스에서 완성본을 생성하고 점수를 매기는 동안, 학습 루프가 손실을 계산하고 모델을 업데이트합니다. 동작 방식을 이해하려면 세 가지 주요 단계로 나눌 수 있습니다: 완성본 생성, 어드밴티지 계산, 손실 계산. 참조 모델이 없으므로 KL 발산 항이 없습니다(GRPO의 기본값, beta=0.0).

완성 결과 생성

롤아웃 워커는 vLLM 서버로 최대 max_concurrent_rollouts 개의 요청을 동시에 처리합니다. 각 프롬프트에 대해 G G 개의 완성본(num_generations) )을 생성한 후, 그룹 전체가 완료되면 점수를 매기고 이점을 계산합니다. 생성된 학습 샘플은 큐에 저장되며, 학습 루프에서 이를 가져옵니다. 생성은 학습보다 max_staleness 스텝 앞서 있을 때만 대기하며(참고: 동시성), ), 학습 스텝은 큐가 비어 있을 때만 대기합니다.

weight_sync_steps마다 학습 단계가 진행될 때마다 trainer는 NCCL을 통해 업데이트된 가중치를 vLLM 서버로 전송하여, 다음 completions이 최신 policy에서 생성되도록 합니다. 따라서 completion은 학습 중인 policy보다 몇 단계 오래된 policy에서 생성될 수 있습니다. trainer가 샘플을 가져올 때 max_staleness보다 많은 가중치 업데이트가 뒤처져 있는 샘플은 폐기됩니다.

이 페이지의 지표와 나머지 내용은 완료(completion)가 거치는 단계에 대해 다음 용어를 사용합니다:

  • a 그룹 은 하나의 프롬프트와 그 G G 의 롤아웃으로 구성됩니다. 이 안에서 이점이 계산됩니다.
  • rollout는 프롬프트에 대해 생성된 하나의 전체 대화로, 모든 도구 호출을 포함합니다. 이는 하나 이상의 turn으로 구성되며, 각 turn은 하나의 vLLM 요청에 해당합니다.
  • sample은 손실이 계산되는 대상입니다. 즉, rollout의 토큰과 그 이점(advantage)입니다. 멀티턴 rollout은 여러 개의 sample을 생성할 수 있습니다(Multi-turn rollouts 참고).
  • row은 하나의 프로세스가 하나의 micro-batch에서 전달하는 것으로, 여러 샘플이 함께 패킹된 것입니다(Tree packing 참조). micro-batch는 프로세스당 하나의 row를 포함하며, gradient_accumulation_steps개의 micro-batch가 하나의 step, 즉 옵티마이저 스텝을 구성합니다.

토큰 수는 세 가지 종류가 있습니다: 생성된 토큰은 모델이 생성한 토큰을, 전달된 토큰은 샘플의 모든 토큰(프롬프트 및 도구 결과를 포함)을, 학습된 토큰은 손실이 계산되는 토큰을 나타냅니다.

이점(advantage) 계산

그룹의 각 G G 완성 결과에 대해, 보상은 각 보상 함수의 보상 합입니다. 이점은 GRPO와 마찬가지로 그룹 내에서 정규화됩니다: A^i,t=ri−mean(r)std(r)\hat{A}_{i,t} = \frac{r_i - \text{mean}(\mathbf{r})}{\text{std}(\mathbf{r})}

scale_rewards 옵션은 없습니다. 이점은 항상 그룹의 표준편차로 스케일링됩니다. 모든 보상 함수가 None을 반환한 완료는 그룹의 평균과 표준편차 계산에서 제외되며, 이점 값이 0으로 설정됩니다.

보상이 모두 동일한 그룹은 제외됩니다. 기본 advantage는 모든 위치에서 0이므로, 해당 그룹으로 학습하면 forward와 backward pass만 수행되고 아무것도 이동하지 않기 때문입니다. 이러한 그룹의 비율은 frac_reward_zero_std로 기록됩니다. step은 유지된 그룹으로 채워지므로, 제외된 그룹이 많을수록 step당 생성량이 증가합니다. 제외된 그룹도 epoch에 포함되며, epoch은 프롬프트를 한 번만 통과하는 것을 의미합니다.

손실 계산

vLLM 서버의 로그 확률(log-probabilities)은 트레이너의 값과 정확히 일치하지 않습니다: 커널이 다르고, 정밀도가 다르며, 정책이 몇 단계 뒤처져 있기 때문입니다(참고: 학습-추론 불일치 처리). 트레이너는 샘플러의 로그 확률을 이전 정책으로 사용하므로, 하나의 중요도(importance) 비율이 불일치와 시차(staleness)를 모두 커버합니다: ri,t(θ)=πθ(oi,t∣q,oi,<t)πsampler(oi,t∣q,oi,<t). r_{i,t}(\theta) = \frac{\pi_\theta(o_{i,t} \mid q, o_{i,< t})}{\pi_{\text{sampler}}(o_{i,t} \mid q, o_{i,< t})}.

[vllm_importance_sampling_clip_min, vllm_importance_sampling_clip_max] 범위를 벗어난 비율을 가진 토큰은 손실 계산에서 제외됩니다. 자세한 내용은 Masked Importance Sampling을 참조하세요.

By default (score_centering=True), the trainer uses Score Centering. Importance weights alone do not remove the mismatch: the score ∇θlog⁡πθ \nabla_\theta \log \pi_\theta of a sampled token does not average to zero under the sampler μ \mu , so every update also pulls the policy toward the sampler. Score centering subtracts that expectation at every position: ∇θL=−Eo∼μ[A^(f(rt)∇θlog⁡πθ(ot)−Ev∼μ[f(rv)∇θlog⁡πθ(v)])],rv=πθ(v)μ(v), \nabla_\theta \mathcal{L} = - \mathbb{E}_{o \sim \mu} \left[ \hat{A} \left( f(r_t) \nabla_\theta \log \pi_\theta(o_t) - \mathbb{E}_{v \sim \mu} \left[ f(r_v) \nabla_\theta \log \pi_\theta(v) \right] \right) \right], \quad r_v = \frac{\pi_\theta(v)}{\mu(v)},

여기서 f(r)=r f(r) = r 내부에서 [Cmin⁡,Cmax⁡] [C_{\min}, C_{\max}] 그리고 0 0 외부에서. 내부 기대값은 샘플러의 num_sampler_logprobs 에서 각 위치의 가장 가능성이 높은 토큰에 대해 계산되며, 이는 롤아웃 워커가 서버에 요청합니다.

인수 score_centering=False, 인수를 사용할 때, 트레이너는 동일한 마스크된 비율을 가진 GRPO의 클립된 서브로게이트 목적 함수를 대신 사용합니다: L(θ)=−1∑i∣oi∣∑i∑t=1∣oi∣1[Cmin⁡≤ri,t(θ)≤Cmax⁡]min⁡(ri,t(θ)A^i,t, clip(ri,t(θ),1−ϵlow,1+ϵhigh)A^i,t), \mathcal{L}(\theta) = - \frac{1}{\sum_{i} |o_i|} \sum_{i} \sum_{t=1}^{|o_i|} \mathbb{1}\left[ C_{\min} \le r_{i,t}(\theta) \le C_{\max} \right] \min \left( r_{i,t}(\theta) \hat{A}_{i,t}, \, \text{clip}\left( r_{i,t}(\theta), 1 - \epsilon_{\text{low}}, 1 + \epsilon_{\text{high}} \right) \hat{A}_{i,t} \right),

여기서 ϵlow \epsilon_{\text{low}} 은 epsilon 이고 ϵhigh \epsilon_{\text{high}} 은 epsilon_high.

두 경우 모두 손실은 모든 프로세스에 걸쳐 집계된 마이크로 배치의 학습 토큰 수로 정규화되고, gradient_accumulation_steps개의 마이크로 배치에 걸쳐 평균화됩니다.

기록된 지표

학습 중에 다음 메트릭을 기록합니다:

  • num_tokens: 현재까지 전달된 프롬프트와 완성본의 총 토큰 수. 트리 패킹을 사용하는 경우 여러 샘플이 공유하는 접두사는 한 번만 계산됩니다.
  • completions/mean_length: 생성된 completions의 평균 길이입니다. 도구를 사용할 경우, 도구 토큰을 제외한 토큰만 계산됩니다.
  • completions/min_length: 생성된 completions의 최소 길이입니다. 도구를 사용할 경우, 도구 토큰이 아닌 토큰만 계산됩니다.
  • completions/max_length: 생성된 completions의 최대 길이. 도구를 사용할 경우 도구 토큰은 제외하고 카운트합니다.
  • completions/mean_terminated_length: EOS로 종료되는 생성된 completions의 평균 길이입니다. 도구를 사용할 경우, 도구 토큰은 제외하고 계산합니다.
  • completions/min_terminated_length: EOS로 종료되는 생성된 completions의 최소 길이입니다. 도구를 사용할 경우, 도구 토큰이 아닌 토큰만 계산됩니다.
  • completions/max_terminated_length: EOS로 종료되는 생성된 completions의 최대 길이입니다. 도구를 사용할 경우, 도구 토큰이 아닌 토큰만 계산됩니다.
  • completions/clipped_ratio: 마지막 턴이 EOS 토큰으로 끝나지 않아 잘린(클립된) completion의 비율입니다.
  • completions/duplicate_frac: 그룹 내 이전 rollout과 토큰 단위로 동일한 rollout의 비율입니다. Saturation and duplicates를 참조하세요.
  • tools/call_frequency: 모든 rollout에 걸쳐 완료당 평균 도구 호출 횟수입니다. 이후 제거되는 그룹도 포함합니다. trainer에 도구가 있을 때만 기록됩니다.
  • tools/failure_frequency: 모든 도구 호출(이후 제거되는 그룹 포함) 중 실패한 도구 호출(도구를 찾지 못했거나 예외가 발생함)의 비율입니다. 도구 호출이 없는 로깅 윈도우에서는 NaN이며, GRPO는 0.0을 기록합니다. 트레이너에 도구가 있을 때만 기록됩니다.
  • rewards/{reward_func_name}/mean: 특정 보상 함수가 점수를 매긴 모든 completion에 대한 평균 보상입니다. 이후 제거되는 그룹도 포함됩니다. 환경이 get_reward를 통해 보상을 소유하는 경우, {reward_func_name}은 해당 환경의 클래스 이름입니다.
  • rewards/{reward_func_name}/group_std: 특정 reward function의 reward 표준편차로, 각 그룹 내에서 계산한 후 학습된 샘플에 대해 평균을 낸 값입니다.
  • reward: 모든 점수가 매겨진 completion에 대해 함수 간 보상을 합산한 후 계산된 전체 평균 보상입니다. 이후 제거되는 그룹도 포함됩니다. 이는 정책(policy)의 보상이므로 추적해야 할 값입니다. reward_kept은 보상이 모두 동일한 그룹을 제외합니다.
  • reward_group_std: 각 그룹 내에서 계산된 후 학습된 샘플에 대해 평균을 낸, 함수 간 합산된 보상(reward)의 표준편차입니다. GRPO의 reward_std가 배치 전체에 대해 계산되는 것과 달리, 이 값은 advantage를 나눌 때 사용됩니다.
  • reward_kept: 제외된 그룹을 제외한 학습 샘플의 평균 보상
  • reward_dropped: 제거된 그룹의 평균 보상, 즉 해당 그룹이 정체되어 있는 보상 값입니다. Saturation and duplicates 섹션을 참고하여 frac_reward_zero_std 및 reward와 함께 해석해 보세요.
  • frac_reward_zero_std: 보상 표준편차가 0인 그룹(모든 답변이 정답이거나 오답인 경우) 또는 채점 가능한 완성본이 두 개 미만인 그룹의 비율입니다. 이러한 그룹은 제외됩니다.
  • sampling/sampling_logp_difference/mean: 학습된 토큰에 대해, 샘플러(vLLM)가 반환한 로그 확률과 학습 모델이 다시 계산한 로그 확률 간의 평균 절대 차이.
  • sampling/sampling_logp_difference/max: 해당 절대 차이의 최대값.
  • sampling/importance_sampling_ratio/min: 가장 작은 importance sampling 비율 ri,t(θ) r_{i,t}(\theta) 모델과 sampler 사이의, 학습된 토큰에 대해, [vllm_importance_sampling_clip_min, vllm_importance_sampling_clip_max] 범위 밖의 토큰이 제거되기 전의
  • sampling/importance_sampling_ratio/mean: 해당 importance sampling ratio의 평균.
  • sampling/importance_sampling_ratio/max: 가장 큰 중요도 샘플링 비율.
  • sampling/masked_mean: 중요도 샘플링 비율이 [vllm_importance_sampling_clip_min, vllm_importance_sampling_clip_max] 범위를 벗어나서 손실 계산에서 제외된 학습 토큰의 비율입니다.
  • sampling/sampler_mass: 샘플러의 num_sampler_logprobs개 가장 가능성 높은 토큰이 커버하는 평균 확률 질량. score_centering=True일 때만 기록됩니다.
  • entropy: 학습된 토큰에 대한 토큰 예측의 평균 엔트로피.
  • aux_loss: Mixture-of-Experts 모델의 로드 밸런싱 보조 손실입니다. router_aux_loss_coef로 스케일링되어 손실에 추가되기 전의 값입니다. 모델이 MoE 모델이고 router_aux_loss_coef가 0이 아닌 경우에만 기록됩니다.
  • clip_ratio/region_mean: GRPO 목적 함수가 신뢰 영역(trust region) 내에 머물도록 클리핑되는 토큰 확률의 비율입니다: clip(ri,t(θ),1−ϵlow,1+ϵhigh) \text{clip}\left( r_{i,t}(\theta), 1 - \epsilon_\mathrm{low}, 1 + \epsilon_\mathrm{high} \right) . 인 경우 score_centering=True 손실이 클리핑되지 않으므로 clip_ratio/* 메트릭은 신뢰 영역 밖의 토큰을 집계합니다.
  • clip_ratio/low_mean: trust region의 하한에서 클리핑된 토큰 확률의 평균 비율: ri,t(θ)<1−ϵlowr_{i,t}(\theta) < 1 - \epsilon_\mathrm{low}.
  • clip_ratio/low_min: trust region 하한에서 클리핑되는 토큰의 완료별 최소 비율: ri,t(θ)<1−ϵlowr_{i,t}(\theta) < 1 - \epsilon_\mathrm{low}.
  • clip_ratio/high_mean: trust region의 상한에서 클리핑된 토큰 확률의 평균 비율: ri,t(θ)>1+ϵhighr_{i,t}(\theta) > 1 + \epsilon_\mathrm{high}.
  • clip_ratio/high_max: trust region의 상한에서 클리핑된 토큰의 완료별 최대 비율: ri,t(θ)>1+ϵhighr_{i,t}(\theta) > 1 + \epsilon_\mathrm{high}.

다른 지표들은 비동형 파이프라인을 설명합니다.

Metrics는 logging window마다 한 번씩 기록됩니다. 이는 이전 로그 이후에 기록된 모든 내용으로, 마지막 logging_steps개의 optimizer steps를 포함합니다. 해당 window 동안:

  • reward, rollout/turns_mean, tools/latency_s와 같이 롤아웃, 샘플 또는 호출별로 측정된 평균은 해당 윈도우 내의 모든 롤아웃, 샘플 또는 호출에 대해 평균화됩니다. rollout/generated_tokens_per_s와 같은 레이트는 총 토큰 수를 총 초로 나눈 값입니다.
  • 그렇지 않은 경우, 마지막 부분에 count라는 단어가 포함된 이름은 합산됩니다: sample/dropped_stale_count는 학습 시작 시점이 아니라 마지막 로그 이후에 드롭된 샘플의 수입니다.
  • 마지막 부분에 max 또는 min이라는 단어가 포함된 이름, 예를 들어 sample/staleness_max 또는 completions/max_length와 같은 이름은 가장 큰 값 또는 가장 작은 값을 유지합니다.
  • 다른 모든 지표는 윈도우에 기록된 값들의 평균입니다.

단위:

  • _s: 초.
  • tokens_per_s: 초당 토큰 수.
  • _frac: 0과 1 사이의 비율.
  • _per_step: 하나의 optimizer step당 양으로, 윈도우 내의 step들에 대해 평균화된 값입니다.

롤아웃 지표

  • rollout/duration_s: dispatch부터 rollout 루프가 수집할 때까지의 한 rollout의 경과 시간(wall time)
  • rollout/generated_tokens_per_s: 이전 보고 이후 초당 생성된 토큰 수로 측정된 생성 처리량입니다.
  • rollout/concurrency: vLLM 서버에 동시에 실행 중인 rollout의 수.
  • rollout/concurrency_cap: 서버 부하를 따라가는 현재 진행 중인 rollout의 상한입니다. 동시성을 참조하세요.
  • rollout/turns_mean, rollout/turns_max: 롤아웃당 평균 및 최대 턴 수.
  • rollout/samples_per_rollout: 각 rollout당 학습 샘플 수. 1.0을 초과하면 일부 rollout이 분기되고, 1.0 미만이면 학습된 토큰이 생성되지 않는 rollout이 발생합니다. Multi-turn rollouts를 참조하세요.
  • rollout/fork_frac: held tokens로 시작하지 않는 프롬프트를 가진 턴 전환의 비율. 즉, 해당 턴이 새로운 샘플을 시작했음을 의미합니다.
  • rollout/drift_tokens_mean, rollout/drift_tokens_max: 포크가 다시 렌더링한 보유 토큰의 개수로, 턴 전환에 대해 평균을 낸 값입니다(포크되지 않은 경우 0으로 계산됩니다). 새로운 샘플은 분기점 이전의 토큰을 공유하므로, 이는 각 포크가 포워드에 추가하는 값입니다.
  • rollout/score_queue_size: 채점을 대기 중인 완료된 그룹의 수.
  • rollout/queue_size: rollout 큐에서 채점을 기다리는 샘플의 수입니다. trainer가 샘플을 가져오는 지점에서 측정됩니다. rollout 큐를 참조하세요.
  • rollout/score_s: 그룹을 점수화하는 데 걸리는 시간.
  • rollout/score_wait_s: 완료된 그룹이 점수를 받기 전에 대기한 시간입니다.
  • rollout/score_block_s: 스코어링 큐가 가득 차서 생성이 차단된 시간입니다.
  • rollout/backpressure_s: max_staleness 스텝만큼 학습보다 앞서 있어 롤아웃 시작을 기다린 생성 시간입니다. 로깅 윈도우 내 대기 시간의 평균입니다. 동시성을 참조하세요.
  • rollout/vllm_retry_count: 재시도된 vLLM 요청의 수입니다. 이 값을 확인하지 않으면 서버 성능 저하가 원인을 알 수 없는 느린 응답으로만 보입니다.
  • rollout/vllm_kv_cache_usage_frac: vLLM KV 캐시 사용률(엔진별 최대값)을 로깅 윈도우 내 폴링 횟수에 대해 평균한 값입니다.
  • rollout/vllm_running_requests: 서버의 엔진들이 디코딩 중인 요청의 수입니다(vLLM의 num_requests_running을 엔진별로 합산한 값). rollout/concurrency와의 차이는 API 서버 프로세스에서 응답을 구성하는 동안 대기 중인 요청의 수입니다.
  • rollout/vllm_queued_requests: 서버가 수락했지만 아직 스케줄링되지 않은 요청의 수 (vLLM의 num_requests_waiting을 엔진별로 합산한 값).
  • rollout/vllm_preemption_count: 서버가 선점(preempt)한 요청의 수입니다(vLLM의 num_preemptions_total을 엔진별로 합산한 값). 가중치 동기화는 서버의 캐시를 초기화하여 모든 실행 중인 요청을 선점하므로, 이는 부하 신호가 아닙니다.

도구 지표

  • tools/latency_s, tools/{tool_name}/latency_s: 모든 도구 및 도구별 도구 호출 실행에 소요된 시간.
  • tools/{tool_name}/call_count, tools/{tool_name}/failure_count: 도구별 호출 횟수와 실패한 호출 횟수.
  • tools/unknown_name_count: 존재하지 않는 도구에 대한 호출 횟수. 실행 후 예외를 발생시킨 도구와 달리, 이는 정책 오류입니다.
  • tools/parallel_calls_mean: 도구를 호출하는 어시스턴트 메시지 내 도구 호출의 평균 횟수.
  • tools/loop_exhausted_frac: 도구 호출을 계속하는 상태에서 max_tool_calling_iterations에서 중단된 rollout의 비율입니다. 도구 호출이 없는 rollout과 이후 제거되는 그룹을 포함한 모든 rollout을 기준으로 계산됩니다. trainer에 도구가 있을 때만 기록됩니다.

HarnessAsyncGRPOTrainer는 이 항목 대부분을 동일한 이름으로 기록합니다. 차이점에 대해서는 하네스에서의 학습을 참조하세요.

환경 지표

  • env/reset_s: rollout가 시작되기 전에 환경의 reset()에 소요된 시간. environment_factory가 제공된 경우에만 기록됩니다.
  • env/reward_s: rollout이 종료된 후 환경의 get_reward()에 소요된 시간. 환경이 get_reward를 정의한 경우에만 기록됩니다.

샘플 지표

  • sample/forwarded_tokens_mean, sample/forwarded_tokens_max: 샘플당 전달된 토큰의 평균 및 최대 개수.
  • sample/trained_tokens_mean: 샘플당 학습된 토큰의 평균 개수.
  • sample/time_in_queue_s: 샘플이 학습되기 전에 rollout 큐에서 대기한 시간입니다.
  • sample/staleness_mean, sample/staleness_max: 샘플을 생성한 정책과 해당 샘플로 학습하는 정책 사이의 가중치 업데이트 횟수입니다. sampling/importance_sampling_ratio/* 및 sampling/sampling_logp_difference/* 지표는 이러한 staleness를 학습-추론 불일치(mismatch)와 결합합니다. staleness가 0일 때 1.0에서 벗어난 비율이나 0.0에서 벗어난 로그 확률(log-probability) 차이는 불일치를 가리키며, 예를 들어 서버와의 dtype 차이 등이 해당됩니다.
  • sample/dropped_stale_count: max_staleness를 초과하여 제거된 샘플의 수.

배치 지표

  • batch/forwarded_tokens_per_step, batch/trained_tokens_per_step: 모든 프로세스에 걸쳐 스텝당 포워딩 및 학습된 토큰 수
  • batch/samples_per_step, batch/groups_per_step: 각 스텝당 샘플 수와 서로 다른 그룹 수입니다. 그룹당 샘플 수만큼 차이가 납니다.
  • batch/microbatches_per_step: 각 스텝당 마이크로 배치의 수.
  • batch/masked_token_frac: 전달된 토큰 중 학습되지 않는 토큰의 비율.
  • batch/samples_per_row, batch/row_tokens_mean, batch/row_tokens_max: 행당 샘플 수, 그리고 행당 전달된 토큰의 평균 및 최대 수입니다.
  • batch/row_fill_frac: 각 행이 token_budget의 어느 비율을 사용하는지 나타냅니다.
  • batch/row_imbalance: 가장 비용이 높은 행의 attention 비용과 평균 비용의 비율입니다. 가장 비용이 높은 행을 처리하는 프로세스가 gradient all-reduce에서 다른 프로세스를 대기 상태로 만듭니다. 1.0은 완벽한 균형을 의미합니다.
  • batch/packing_ratio: 포워딩된 토큰 1개당 패킹 전 토큰 수: 패킹이 포워드를 줄이는 배수, 공유되는 것이 없으면 1.0
  • batch/pad_frac: 행의 길이를 동일하게 만들기 위해 추가되는 패딩의 비율입니다. 전송 비용만 발생하며, forward 전에 제거됩니다.
  • batch/dropped_oversize_count: token_budget를 초과하여 제거된 샘플의 수.

성능 지표

  • perf/step_s: 옵티마이저, 가중치 동기화, 샘플 대기 시간을 포함한 스텝의 실제 소요 시간(wall time)
  • perf/fwd_bwd_s, perf/fwd_s: 단계의 forward pass와 backward pass에 소요된 시간, 그리고 forward pass에만 소요된 시간입니다.
  • perf/optimizer_s: 옵티마이저 단계에 소요된 시간.
  • perf/rollout_wait_s: rollout 큐가 비어 있어 학습이 대기한 시간. rollout 큐를 참조하세요.
  • perf/weight_sync_s: 가중치 동기화 시간으로, perf/weight_sync_pause_s(vLLM이 일시중지될 때까지 대기), perf/weight_sync_barrier_s(다른 프로세스가 준비될 때까지 대기), perf/weight_sync_transfer_s(가중치 전송)으로 구분됩니다.
  • perf/fwd_bwd_forwarded_tokens_per_s, perf/wall_clock_forwarded_tokens_per_s: forward pass와 backward pass에 걸쳐, 또는 전체 step에 걸쳐 초당 전달된 토큰 수.
  • perf/wall_clock_trained_tokens_per_s: 전체 스텝에 걸쳐 초당 학습된 토큰 수
  • perf/fwd_bwd_mfu, perf/wall_clock_mfu: 학습 장치의 모델 FLOPs 활용률로, forward 및 backward pass에 걸쳐 또는 전체 step에 걸쳐 측정됩니다. vLLM 서버는 제외됩니다. 학습 정밀도에서 학습 장치의 peak compute가 알려진 경우, 그리고 FLOPs 추정치가 모델의 아키텍처(예: Llama, Qwen2, Qwen3, Qwen3-MoE 또는 Qwen3-VL)를 지원하는 경우에만 기록됩니다.

커스터마이징

vLLM 서버 구성

Trainer는 vllm_server_base_url(기본값은 http://localhost:8000)에서 vLLM 서버에 도달하여 생성합니다:

VLLM_SERVER_DEV_MODE=1 vllm serve <model_name> \
    --weight-transfer-config '{"backend": "nccl"}' \
    --logprobs-mode processed_logprobs \
    --api-server-count 8 \
    --max-model-len 4096
  • VLLM_SERVER_DEV_MODE=1 및 --weight-transfer-config은 트레이너가 가중치를 전송하는 엔드포인트를 노출합니다.
  • --logprobs-mode processed_logprobs는 서버가 temperature와 top-k/top-p를 적용한 후 샘플링한 분포의 log-probabilities를 반환하도록 하며, 이는 importance ratio가 비교하는 대상입니다.
  • --api-server-count 8는 스코어 센터링 요청을 저렴하게 처리할 수 있도록 상위 log-probabilities를 유지합니다(아래 경고 참조).
  • --max-model-len은 예상되는 최대 총 시퀀스 길이(프롬프트와 완성 포함)입니다. 이 값을 낮추면 서버의 GPU 메모리 사용량이 줄어들어 KV 캐시에 더 많은 메모리가 할당되고 처리량이 증가합니다. 좋은 시작점은 설정 파일의 프롬프트 길이에 max_completion_length를 더한 값입니다. 도구를 사용할 경우, 각 턴마다 max_completion_length 토큰과 도구 결과가 추가되므로 예상되는 가장 긴 대화 길이에 맞게 설정해야 합니다. 특정 턴의 프롬프트와 max_completion_length의 합이 --max-model-len보다 길면 서버가 요청을 거부하고 서버의 오류로 실행이 중단됩니다. top_k 또는 top_p를 사용하는 경우, 서버는 해당 턴이 --max-model-len에 도달하면 그 턴을 중단하고, 이미 해당 길이에 도달한 프롬프트만 거부합니다. 또한 이 값은 token_budget의 기본값이기도 합니다.

서버가 trainer와 다른 GPU를 사용하도록 확인하세요. 그렇지 않으면 NCCL 오류가 발생할 수 있습니다. 사용할 GPU는 CUDA_VISIBLE_DEVICES 환경 변수로 지정할 수 있습니다.

vLLM의 API 서버에서 상위 log-probabilities를 직렬화하는 작업은 CPU에서 수행되며, 기본값인 단일 API 서버에서 num_sampler_logprobs=8을 사용하면 생성 처리량이 절반으로 줄어듭니다. vLLM 0.32 이상에서는 서버를 --api-server-count 8 옵션으로 시작하세요. H100 1대에서 1.5B~7B 모델을 측정했을 때, 상위 8개 log-probabilities의 비용이 생성 처리량의 3% 미만으로 줄어듭니다. vLLM 0.31에서는 동일한 플래그를 사용해도 20~40%의 손실이 발생하며, 이는 vllm-project/vllm#58181에서 업스트림으로 수정되었습니다.

동시성

동시에 실행되는 rollout의 수를 결정하는 한계는 세 가지입니다. 첫 번째와 두 번째는 자동으로 조정되며, 세 번째는 사용자가 직접 설정합니다.

Staleness. max_staleness는 생성이 트레이너보다 얼마나 앞선 학습 스텝까지 허용할지를 설정합니다. 워크러는 스텝당 샘플 수가 완성본의 길이에 따라 변하기 때문에 토큰 단위로 이를 추적합니다. 각 스텝이 끝난 후 트레이너는 사용한 토큰 수를 계산하고, 워크러가 해당 토큰 수의 max(max_staleness, 1)배까지 큐에 대기 중이거나 진행 중인 토큰을 유지하도록 허용합니다. 첫 번째 스텝 이전에는 모든 행이 가득 차 있다고 가정합니다. 워크러는 해당 한도 미만일 때만 새로운 롤아웃 그룹을 시작합니다. 처음에는 롤아웃 하나가 얼마나 많은 토큰을 생성하는지 알 수 없으므로, 첫 번째 그룹이 완료될 때까지 한 번에 하나의 그룹씩 시작합니다. 결국 max_staleness 스텝 이상 오래된 샘플은 폐기됩니다.

vLLM 로드. vLLM에 한 번에 너무 많은 요청을 보내면 속도가 느려집니다. KV 캐시가 가득 차면 vLLM이 일부 요청을 일시 중단하고 다시 처리해야 하기 때문입니다. 따라서 워커는 동시에 실행되는 롤아웃 수에 대한 실시간 한도를 유지하며, 이는 rollout/concurrency_cap으로 기록됩니다. 또한 서버의 /metrics를 5초마다 확인하여 한도를 조정합니다. 한도는 처음에 최대 길이에 맞춰 KV 캐시에 들어갈 수 있는 요청 수(KV cache tokens / max_model_len)로 시작하여 서버가 초기에 과부하되지 않도록 합니다. KV 캐시 사용률이 60% 미만이고 대기 중인 요청이 없으면, 완료된 롤아웃 수만큼 한도가 증가할 때마다 최대 25%씩 한도가 올라갑니다. 사용률이 80%를 초과하면 30%씩 한도가 내려갑니다. 이때 실행 중인 요청은 계속 진행되고, 새로운 요청은 대기합니다. 서버에 /metrics 엔드포인트가 없으면 한도는 max_concurrent_rollouts가 됩니다.

리소스. max_concurrent_rollouts(기본값 512)는 동시에 실행되는 rollout의 상한입니다. 트레이너가 환경과 도구가 처리할 수 있는 범위를 알 수 없으므로, 직접 설정해야 하는 유일한 한계입니다. 각 실행 중인 rollout는 환경을 사용하고, 이 크기의 스레드 풀에서 동기식 도구 호출을 실행하며, vLLM 서버에 연결을 유지합니다. 예를 들어 환경 서버가 허용하는 세션 수와 같이, 해당 리소스가 처리할 수 있는 수준으로 설정하세요:

from trl import AsyncGRPOConfig

training_args = AsyncGRPOConfig(
    ...,
    max_concurrent_rollouts=64,
)

너무 낮으면 생성 속도가 느려집니다. 롤아웃은 vLLM이 생성하는 동안뿐만 아니라 도구를 실행하거나 턴 사이에 대기하는 동안에도 슬롯을 유지하므로, 많은 도구를 호출하는 롤아웃은 vLLM이 바쁘게 유지되도록 더 많은 슬롯이 필요합니다. 기본값보다 훨씬 높으면 vLLM 서버가 연결을 드롭하기 시작할 수 있습니다.

기록된 메트릭은 생성을 제한하는 한도가 무엇인지 보여 줍니다:

  • rollout/backpressure_s 값이 0보다 큰 경우: staleness 한계입니다. 추론이 학습보다 빠를 때 예상되는 현상으로, 생성이 학습보다 앞서 있는 상태입니다.
  • rollout/concurrency_cap의 rollout/concurrency가 max_concurrent_rollouts보다 낮은 경우: vLLM 서버의 부하.
  • rollout/concurrency가 max_concurrent_rollouts에 도달하고, rollout/vllm_kv_cache_usage_frac는 낮으며 perf/rollout_wait_s는 높은 경우: 이는 상한선입니다. 환경과 도구가 허용한다면 max_concurrent_rollouts를 높여야 합니다.

롤아웃 큐

워커는 점수가 매겨진 샘플을 큐에 넣고, 트레이너는 해당 큐에서 데이터를 가져옵니다. 이 큐를 설명하는 네 가지 지표가 있습니다:

  • rollout/queue_size: 대기 중인 샘플 수.
  • sample/time_in_queue_s: 단일 샘플이 학습되기까지 대기한 시간, 즉 staleness의 시간 부분입니다.
  • perf/rollout_wait_s: 큐가 비어 있어 학습이 대기한 시간.
  • rollout/backpressure_s: 생성이 학습보다 max_staleness 스텝 앞서 있었기 때문에 대기한 시간.

마지막 두 가지는 거울 이미지입니다. 큐 크기와 함께 읽으면 어느 쪽이 병목인지 알려줍니다:

  • 큐가 거의 비어 있고 perf/rollout_wait_s가 높은 경우: 생성 제한입니다. 트레이너가 기아 상태에 있습니다. rollout/generated_tokens_per_s, rollout/concurrency, rollout/score_queue_size를 확인하세요.
  • 약 max_staleness 스텝 분량의 토큰을 담는 큐, rollout/backpressure_s 높음: trainer-bound. 생성이 지연되고 있으며 sample/staleness_mean이 상한선에 근접해 있습니다.
  • 둘 다 높음: max_staleness 한계 자체를 너무 엄격하게 설정한 것입니다. 진행 중인 롤아웃가 샘플이 큐에 도달하기 전에 이를 채우므로, 생성이 지연되는 동안 트레이너가 대기합니다. max_staleness를 높여야 합니다.
  • 둘 다 0에 가까움: 균형 잡힘.

포화 및 중복

정책은 그룹의 롤아웃 간 차이에서 학습합니다. 각 이점은 그룹의 평균 보상과 비교하여 계산됩니다. 그룹의 모든 롤아웃이 동일한 보상을 받으면, 모든 이점이 0이 되어 해당 그룹은 제외됩니다(기록된 지표 참조) 그리고 정책에는 아무것도 가르치지 않습니다. 실행이 포화 상태에 가까워질수록, 모든 롤아웃이 프롬프트를 해결하거나 아무도 해결하지 못하기 때문에 이러한 그룹이 점점 더 많이 발생합니다. 네 가지 지표가 이러한 경우를 구별하며, 각각은 고유한 질문에 답하므로 플롯에서 바로 읽을 수 있습니다:

메트릭질문
frac_reward_zero_std신호가 없는 그룹의 비율
reward_dropped해당 그룹이 정체된 위치, 즉 평균 보상입니다. 보상이 0/1인 경우, 모든 롤아웃이 통과한 그룹의 비율을 의미하므로 0.9는 거의 모든 그룹이 해결되었음을, 0.1은 거의 모든 그룹이 모든 롤아웃에서 실패했음을 나타냅니다
reward점수화된 모든 그룹(제거된 그룹 포함)에 걸쳐 정책이 얼마나 잘 수행되는지
completions/duplicate_fracsame prompt에 대해 샘플링이 여전히 다른 롤아웃을 생성하는지 여부

보상 범위에 맞춰 처음 세 가지를 함께 읽어보세요:

frac_reward_zero_stdreward_droppedreward진단해야 할 일
낮음any (여러 그룹에 걸쳐 노이즈)anyhealthy: 대부분의 그룹이 그래디언트를 생성nothing
등반범위의 상단 근처등반상단에서 포화 상태: 프롬프트가 정책(policy)에 대해 너무 쉬워진 상태이며, 성공적인 실행은 보통 이렇게 끝납니다실행을 중단하거나 더 어려운 프롬프트로 전환
높음범위의 하단 근처낮고 평탄한하단에 고착: 프롬프트가 너무 어렵거나, 보상 함수가 크레딧을 부여하지 않는 경우완성이 답변 전에 잘리면 0점을 받기 때문에 먼저 completions/clipped_ratio를 확인하고, 그다음 몇 개의 completion을 읽어 reward function이 이를 올바르게 파싱하는지 확인하세요
등반떨어지는떨어지는regression: 이전에 통과하던 그룹이 이제 함께 실패함completions/duplicate_frac와 entropy를 확인하여 붕괴 여부를 점검하세요
높음가운데any혼합: 0/1 보상에서는 일부 프롬프트가 너무 쉽고 다른 프롬프트는 너무 어렵습니다. 부분 점수 보상을 사용하면 그룹이 동일한 부분 점수에 머물러 있을 수도 있습니다rollouts를 읽습니다

completions/duplicate_frac은 모든 턴에 걸쳐 그룹 내 이전 rollout과 토큰 단위로 동일한 rollout의 비율입니다. 동일한 rollout은 동일한 보상을 받으므로 중복도 frac_reward_zero_std 값을 높이는 요인이 됩니다.

completions/duplicate_frac진단
0에 가깝고, 완료 길이가 충분히 짧아 우연히 반복될 수 있는 작업에서는 작은 베이스라인을 보입니다healthy: 그룹의 롤아웃이 독립적으로 샘플링됩니다
(num_generations - 1) / num_generations 방향으로 점프합니다샘플링이 더 이상 무작위가 아닙니다: 모든 그룹이 하나의 롤아웃 사본으로 반환됩니다. 예를 들어, temperature가 0인 경우, 또는 동일한 샘플링 시드를 공유하여 동일한 텍스트를 디코딩하는 데이터 병렬 vLLM 엔진(워커는 이를 방지하기 위해 모든 요청에 고유한 시드를 전송합니다)
천천히 상승하며 entropy가 감소합니다collapse: 정책이 프롬프트당 하나의 답변으로 수렴하고 있습니다

이 메트릭은 샘플이 학습될 때가 아니라 워커가 그룹을 점수화할 때 기록되므로, 학습보다 약간 앞서 실행되며 max_staleness를 초과하여 나중에 제거되는 샘플을 포함하는 그룹도 포함됩니다. 모든 보상 함수가 None을 반환하여 어떤 롤아웃도 점수화할 수 없었던 그룹은 제거되고 frac_reward_zero_std에 집계되지만, 보상이 없으므로 reward_dropped에는 포함되지 않습니다.

트리 패킹

마이크로 배치의 샘플은 패딩 없이 프로세스당 한 행에 패킹됩니다. 행은 단순한 연결이 아니라 prefix trie입니다. 여러 샘플이 공유하는 토큰은 한 번만 전달되며, 어텐션은 각 샘플이 정확히 자신의 히스토리만 보이도록 합니다. 그룹의 롤아웃은 모두 해당 프롬프트를 반복하고, 멀티턴 롤아웃의 모든 턴은 지금까지의 대화를 반복하므로, 포워드는 패킹 비율(batch/packing_ratio)만큼 축소됩니다. 이는 레이아웃 변경일 뿐입니다. 학습되는 모든 토큰은 각자의 타깃, 어드밴티지, 이전 로그 확률을 유지하며, 해당 샘플을 단독으로 전달했을 때의 로그 확률과 일치합니다.

프롬프트 하나에 대한 두 번의 롤아웃에서, p는 프롬프트이고 a, b는 두 개의 완성 결과입니다:

1. Rollouts         r0:  p1 p2 p3 a1 a2                10 tokens
                    r1:  p1 p2 p3 b1 b2

2. Trie             S0 [p1 p2] ─┬─ S1 [p3 a1 a2]       p3 is not shared: a position predicts
                                └─ S2 [p3 b1 b2]       one token, and p3 predicts a1 or b1

3. Packed row       index         0  1 |  2  3  4 |  5  6  7
   (depth-first)    input_ids    p1 p2 | p3 a1 a2 | p3 b1 b2    8 tokens: everything but attention
                    position_ids  0  1 |  2  3  4 |  2  3  4    runs on 8 instead of 10
                    segment      S0    | S1       | S2

4. Attention        segment   queries    keys and values: the segment's path in the trie
   (one call)       S0        p1 p2      p1 p2              index 0 1
                    S1        p3 a1 a2   p1 p2 p3 a1 a2     index 0 1 2 3 4
                    S2        p3 b1 b2   p1 p2 p3 b1 b2     index 0 1 5 6 7

5. Loss             r0: a1 a2 predicted at index 2 3   each trained token is predicted at the index
                    r1: b1 b2 predicted at index 5 6   of the token before it in its rollout

몇 가지 결과:

  • 공통 접두사는 공유됩니다: 프롬프트의 롤아웃, 그리고 프롬프트 간 공통 시스템 프롬프트 또는 도구 스키마입니다. 샘플은 이미 해당 그룹을 보유하고 있는 행, 즉 이미 그 프롬프트가 있는 행으로 이동합니다. 해당 행이 가득 차면, 프로세스에 아직 빈 행이 있거나 가장 부하가 높은 행의 부하를 높이지 않는 경우 다른 행으로 이동합니다. 가장 부하가 높은 행은 마이크로 배치의 시간을 결정합니다. 그렇지 않으면 마이크로 배치가 닫힙니다.
  • 공유가 없는 경우는 단순한 패킹입니다. 각 샘플이 자체 세그먼트가 되며, 이는 일반적인 패딩 없는 패킹입니다.
  • K/V만 중복됩니다: 공유 접두사는 하위 세그먼트별로 한 번만 수집되며, 이는 언패킹된 학습이 보유할 양과 비슷하고, 그룹 쿼리 어텐션에서는 작습니다.
  • Gated DeltaNet 하이브리드가 지원됩니다(Qwen3.5, Qwen3.6, Qwen3-Next, …): 해당 모델의 컨볼루션은 각 토큰의 이전 토큰들을 읽으며, 청크형 델타 규칙은 각 세그먼트를 부모 세그먼트의 최종 상태에서 시작합니다.

token_budget는 행의 토큰 수를 제한하며, 공유되는 토큰은 한 번만 계산합니다. 기본값은 서버의 max_model_len이므로 어떤 샘플도 이를 초과할 수 없습니다. 공유되는 부분이 전혀 없는 경우, 트리 패킹은 단순한 패딩 없는 패킹과 거의 동일한 속도로 실행되며, 속도 향상은 패킹 비율에 따라 대략적으로 증가합니다(Qwen3-0.6B 및 1.7B에서 H100을 사용할 때 비율 3.4 기준 약 2.8~3배). 비율은 공유 접두사 길이와 행당 샘플 수의 곱이므로, batch/samples_per_row가 주요 지표입니다. 이 값이 1에 가까우면 공유할 수 있는 부분이 없으며, 이때 조정 가능한 변수는 token_budget입니다. 샘플이 긴 경우 batch/row_fill_frac가 중요합니다. 10k 토큰 샘플은 32k 예산을 효율적으로 채우지 못합니다(3개는 들어가고 4개는 절대 들어가지 않으므로, 플래너는 보통 2개를 배치하고 행이 약 77%만 채워짐). 반면 1k 토큰 샘플은 예산을 거의 완벽하게 채웁니다.

처리량으로 tree packing을 평가하세요. batch/trained_tokens_per_step / perf/fwd_bwd_s. 패킹된 마이크로 배치에는 더 많은 샘플이 포함되므로 perf/fwd_bwd_s는 증가하고, 포워딩된 토큰으로 나누는 perf/fwd_bwd_mfu는 감소합니다. 둘 다 회귀(regression)가 아닙니다. 행당 샘플 수가 증가하면 스텝당 추출되는 롤아웃 수도 증가하므로, 생성이 병목인 실행은 그 영향이 더 커집니다.

배치 지표는 다음과 같이 구성됩니다: 1단계는 gradient_accumulation_steps × num_processes개의 행을 포함하므로, batch/samples_per_step은 batch/samples_per_row의 약 그 배수이며, 토큰도 마찬가지입니다. 단계별 지표는 합계이고 행별 지표는 평균이므로, 두 값은 단계 내 마이크로 배치 간 변동 범위 내에서만 일치합니다.

행을 더 길게 만들거나 줄이는 모든 작업은 공유를 제거합니다. 분기(fork)가 발생하지 않는 다중 턴 대화는 하나의 긴 샘플이며, rollout/samples_per_rollout는 하나의 대화가 몇 개의 샘플을 생성하는지를 나타냅니다.

Top-k 및 top-p 샘플링

Top-k와 top-p는 전체 어휘가 아닌 제한된 후보 집합에 대해 샘플링 분포를 재정규화합니다. 서버의 로그 확률은 이를 반영하며(--logprobs-mode processed_logprobs), 따라서 트레이너도 동일한 집합에 대해 정규화를 수행해야 합니다. 그렇지 않으면 모든 중요도 비율이 편향됩니다. 전체 어휘 기준 토큰의 확률은 해당 토큰이 추출된 후보 집합 기준 확률보다 낮기 때문입니다(DeepSeek-V3.2, 3.1절). top_p < 1 또는 top_k > 0인 경우, 워커는 서버에 각 샘플링된 토큰의 후보 집합을 요청하고 트레이너는 해당 집합에 대해 로그 확률을 재정규화합니다. 이를 위해 서버 플래그가 두 개 더 필요하며, vLLM이 후보 집합의 크기를 top_k로 제한하기 때문에 top_k를 설정해야 합니다:

VLLM_SERVER_DEV_MODE=1 vllm serve <model_name> \
    --weight-transfer-config '{"backend": "nccl"}' \
    --logprobs-mode processed_logprobs \
    --api-server-count 8 \
    --max-model-len 4096 \
    --return-sampling-mask \
    --enable-scale-out
from trl import AsyncGRPOConfig

training_args = AsyncGRPOConfig(
    ...,
    top_p=0.95,
    top_k=512,
)

--return-sampling-mask은 vLLM이 후보 집합을 기록하도록 합니다(vLLM 0.28 이상, V2 모델 러너 사용 시: 서버가 플래그를 거부하면 VLLM_USE_V2_MODEL_RUNNER=1을 설정). --enable-scale-out는 해당 집합을 반환하는 token-in-token-out 엔드포인트를 노출합니다. 워커는 시작 시 서버에서 두 설정을 모두 확인합니다. 구버전 vLLM은 해당 집합을 반환할 수 없으므로, 트레이너는 전체 어휘에 대해 정규화를 유지하고 편향된 비율에 대해 경고를 표시합니다.

PEFT로 어댑터 학습

🤗 PEFT 라이브러리와 긴밀한 통합을 지원하여, 전체 모델을 학습하는 대신 어댑터를 학습하고 Hub에서 공유할 수 있습니다.

from datasets import load_dataset
from peft import LoraConfig
from trl import AsyncGRPOTrainer
from trl.rewards import accuracy_reward

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

    trainer = AsyncGRPOTrainer(
        model="Qwen/Qwen3.5-2B",
        reward_funcs=accuracy_reward,
        train_dataset=dataset,
        peft_config=LoraConfig(r=32, lora_alpha=64, target_modules="all-linear"),
    )
    trainer.train()

모든 가중치 동기화 시 업데이트된 정책을 서버로 전송해야 합니다. 기본적으로 trainer는 어댑터를 베이스 모델에 병합하여 병합된 전체 가중치를 전송하며, 7B 모델의 경우 동기화마다 약 15 GB가 됩니다. vLLM 서버를 --enable-lora 옵션으로 시작하면 어댑터만 전송하며, r=32일 때 약 160 MB입니다:

VLLM_SERVER_DEV_MODE=1 VLLM_ALLOW_RUNTIME_LORA_UPDATING=1 vllm serve <model_name> \
    --weight-transfer-config '{"backend": "nccl"}' \
    --logprobs-mode processed_logprobs \
    --api-server-count 8 \
    --max-model-len 4096 \
    --enable-lora \
    --max-lora-rank 32 \
    --max-loras 6

VLLM_ALLOW_RUNTIME_LORA_UPDATING=1은 트레이너가 각 새 어댑터를 게시하는 엔드포인트를 노출합니다. --enable-lora를 사용하더라도 --weight-transfer-config를 유지해야 합니다. 트레이너는 시작 시에만 동기화 모드를 선택하는데, 그 시점에는 서버가 이미 실행 중이며 병합 동기화가 폴백으로 사용됩니다.

--max-lora-rank은 1, 8, 16, 32, 64, 128, 256, 320, 512 중 하나여야 합니다. 서버가 제공할 수 있는 최대 랭크를 설정하는 것이므로, 8 환경에서도 r=4 어댑터가 정상적으로 작동합니다. --max-loras는 최소 max_staleness + 2 이상이어야 합니다. 트레이너는 max_staleness + 1개의 어댑터 버전을 등록해 두어, 이전 정책 하에서 시작된 롤아웃이 생성 중간에 정책을 전환하지 않고 해당 정책 하에서 완료될 수 있도록 하며, 각 동기화 시 가장 오래된 버전을 해제하기 전에 다음 버전을 로드합니다. 트레이너는 시작 시 두 값을 확인하고, 서버를 재시작할 때 사용할 값을 알려줍니다.

vLLM은 네트워크가 아닌 디스크에서 어댑터를 로드하므로, 트레이너는 각 버전을 <output_dir>/.vllm_lora/ 아래에 작성하고 서버에 해당 경로를 전달합니다. 서버가 다른 머신에서 실행되는 경우, 해당 디렉토리는 두 머신 모두에서 접근할 수 있는 파일시스템에 위치해야 합니다.

<output_dir>/.vllm_lora/는 서빙 캐시이며, 학습된 어댑터가 저장되는 위치가 아닙니다. 이 디렉터리에는 최신 버전만 보관되며, 각 버전은 스탈니스 윈도우(staleness window)에서 벗어난 직후에 삭제됩니다. 체크포인트가 학습한 어댑터를 보존하므로, 체크포인트 저장을 비활성화하지 마세요. save_strategy="no"를 사용하면 수 시간 동안 실행된 작업이 종료된 후에도 아무것도 남지 않습니다. 또한 output_dir은 서버가 읽을 수 있어야 하고, 작업 종료 후에도 유지되어야 하므로, 느린 공유 파일시스템과의 동기화를 피할 수 있다는 장점에도 불구하고 노드 로컬 스크래치 공간은 사용할 수 없습니다.

Adapter sync가 항상 더 빠르지는 않습니다. vLLM은 LoRA adapter를 서빙할 때 병합된 가중치를 서빙하는 경우보다 토큰당 약 1.33~1.39배 느린 속도로 생성하며, RL에서는 일반적으로 생성 과정이 wall-clock 시간을 지배합니다. 그 대가로 각 sync 시 더 짧은 일시 정지 시간과 약 1%의 sync 대역폭을 얻습니다. 생성 처리량이 병목이라면 병합 sync가 여전히 더 나은 선택인 경우가 많습니다.

사용자 정의 보상 함수 사용

AsyncGRPOTrainer는 사용자 정의 보상 함수를 사용하는 것을 지원합니다. 호환성을 보장하기 위해 보상 함수는 다음 요구 사항을 충족해야 합니다:

Reward 함수는 동기 Python callable이거나 비동기 async def 코루틴일 수 있습니다. 여러 reward 함수를 제공하면 동시에 실행됩니다. 비동기 함수는 함께 await되고 동기 함수는 스레드에서 실행되므로, 지연 시간이 겹칩니다.

  1. 입력 인자:

    • 이 함수는 다음을 키워드 인수로 받아야 합니다:

      • prompts(프롬프트를 포함합니다),
      • completions (생성된 completions을 포함),
      • completion_ids (토큰화된 completions을 포함),
      • 데이터셋에 있을 수 있는 모든 열 이름(prompt 제외). 예를 들어, 데이터셋에 ground_truth라는 이름의 열이 포함된 경우, 해당 함수는 ground_truth를 키워드 인수로 받아 호출됩니다.

      이 요구 사항을 충족하는 가장 쉬운 방법은 함수 시그니처에 **kwargs를 사용하는 것입니다.

    • 데이터셋은 대화 형식이므로 prompts와 completions는 메시지 딕셔너리의 목록입니다.

  2. 반환 값: 함수는 float의 리스트를 반환해야 합니다. 각 float는 단일 completion에 해당하는 보상을 나타냅니다.

Reward 함수는 rollout worker라는 별도 프로세스에서 실행되므로, 해당 프로세스에 전달되는 모든 값은 pickled됩니다. 각 reward 함수, tool, environment_factory(그리고 이들이 close over하는 모든 것)은 picklable이어야 합니다: 모듈 레벨 함수, functools.partial, 또는 callable 클래스 인스턴스를 사용하세요. Lambda와 클로저는 trainer.train()에서 TypeError를 발생시킵니다. 이는 reward 함수가 프로세스 내에서 호출되고 클로저가 동작하는 GRPOTrainer와 다른 점입니다.

Rollout 프로세스도 CUDA_VISIBLE_DEVICES="" 환경에서 실행되므로 GPU를 사용할 수 없습니다. GPU 기반의 보상 모델(예: AutoModelForSequenceClassification 스코어러)은 오류 없이 로드되지만, 조용히 CPU로 폴백됩니다. 보상 함수는 가볍게 유지하세요(예: accuracy_reward와 같은 검증기, 형식 또는 길이 검사). GPU 보상 모델이 필요한 경우, 별도의 GPU에서 자체 추론 엔진(vLLM, TGI, …) 뒤에 모델을 서빙하고, picklable한 보상 함수가 이를 통해 HTTP로 호출하도록 구성하세요.

예제 1: 더 긴 완성본을 보상

다음은 더 긴 완성본을 보상하는 보상 함수의 예시입니다:

def reward_func(completion_ids, **kwargs):
    """Reward function that assigns higher scores to longer completions (in terms of token count)."""
    return [float(len(ids)) for ids in completion_ids]

다음과 같이 테스트할 수 있습니다:

>>> prompts = [[{"role": "user", "content": "The sky is"}], [{"role": "user", "content": "The sun is"}]]  # not used in the reward function, but the trainer will pass it
>>> completions = [[{"role": "assistant", "content": " blue."}], [{"role": "assistant", "content": " in the sky."}]]  # not used in the reward function, but the trainer will pass it
>>> completion_ids = [[6303, 13], [304, 279, 12884, 13]]
>>> reward_func(prompts=prompts, completions=completions, completion_ids=completion_ids)
[2.0, 4.0]

예제 2: 특정 형식으로 보상 완료

아래는 완성물이 특정 형식을 갖는지 확인하는 보상 함수의 예시입니다. 이 예시는 DeepSeek-R1: Incentivizing Reasoning Capability in LLMs via Reinforcement Learning 논문에서 사용된 format reward 함수에서 영감을 받았습니다. 프롬프트와 완성물이 구조화된 메시지로 구성된 대화형 형식을 위해 설계되었습니다.

import re

def format_reward_func(completions, **kwargs):
    """Reward function that checks if the completion has a specific format."""
    pattern = r"^<think>.*?</think><answer>.*?</answer>$"
    completion_contents = [completion[0]["content"] for completion in completions]
    matches = [re.match(pattern, content) for content in completion_contents]
    return [1.0 if match else 0.0 for match in matches]

다음과 같이 이 함수를 테스트할 수 있습니다:

>>> prompts = [
...     [{"role": "user", "content": "What is the result of (1 + 2) * 4?"}],
...     [{"role": "user", "content": "What is the result of (3 + 1) * 2?"}],
... ]
>>> completions = [
...     [{"role": "assistant", "content": "<think>The sum of 1 and 2 is 3, which we multiply by 4 to get 12.</think><answer>(1 + 2) * 4 = 12</answer>"}],
...     [{"role": "assistant", "content": "The sum of 3 and 1 is 4, which we multiply by 2 to get 8. So (3 + 1) * 2 = 8."}],
... ]
>>> format_reward_func(prompts=prompts, completions=completions)
[1.0, 0.0]

예제 3: 참조를 기반으로 보상 완료

아래는 완성물이 올바른지 확인하는 보상 함수의 예시입니다. 이 예시는 DeepSeek-R1: Incentivizing Reasoning Capability in LLMs via Reinforcement Learning 논문에서 사용된 accuracy reward 함수에서 영감을 받았습니다. 데이터셋에는 ground_truth라는 이름의 열이 포함되어 있습니다.

import re

def reward_func(completions, ground_truth, **kwargs):
    # Regular expression to capture content inside \boxed{}
    matches = [re.search(r"\\boxed\{(.*?)\}", completion[0]["content"]) for completion in completions]
    contents = [match.group(1) if match else "" for match in matches]
    # Reward 1 if the content is the same as the ground truth, 0 otherwise
    return [1.0 if c == gt else 0.0 for c, gt in zip(contents, ground_truth)]

다음과 같이 이 함수를 테스트할 수 있습니다:

>>> prompts = [
...     [{"role": "user", "content": "Solve the equation $2x + 3 = 7$."}],
...     [{"role": "user", "content": "Solve the equation $3x - 5 = 10$."}],
... ]
>>> completions = [
...     [{"role": "assistant", "content": r"The solution is \boxed{2}."}],
...     [{"role": "assistant", "content": r"The solution is \boxed{6}."}],
... ]
>>> ground_truth = ["2", "5"]
>>> reward_func(prompts=prompts, completions=completions, ground_truth=ground_truth)
[1.0, 0.0]

예제 4: 다중 작업 보상 함수

아래는 AsyncGRPOTrainer에서 여러 보상 함수를 사용하는 예시입니다. 이 예시에서는 두 가지 작업별 보상 함수인 math_reward_func와 coding_reward_func를 정의합니다. math_reward_func는 수학 문제의 정답 여부 기준으로 보상을 부여하고, coding_reward_func는 코딩 문제의 솔루션이 정상적으로 동작하는지 여부 기준으로 보상을 부여합니다.

from datasets import Dataset
from trl import AsyncGRPOTrainer

# Define a dataset that contains both math and coding problems
dataset = Dataset.from_list(
    [
        {"prompt": [{"role": "user", "content": "What is 2+2?"}], "task": "math"},
        {"prompt": [{"role": "user", "content": "Write a function that returns the sum of two numbers."}], "task": "code"},
        {"prompt": [{"role": "user", "content": "What is 3*4?"}], "task": "math"},
        {"prompt": [{"role": "user", "content": "Write a function that returns the product of two numbers."}], "task": "code"},
    ]
)

# Math-specific reward function
def math_reward_func(prompts, completions, task, **kwargs):
    rewards = []
    for prompt, completion, t in zip(prompts, completions, task):
        if t == "math":
            # Calculate math-specific reward
            correct = check_math_solution(prompt, completion)
            reward = 1.0 if correct else -1.0
            rewards.append(reward)
        else:
            # Return None for non-math tasks
            rewards.append(None)
    return rewards

# Coding-specific reward function
def coding_reward_func(prompts, completions, task, **kwargs):
    rewards = []
    for prompt, completion, t in zip(prompts, completions, task):
        if t == "code":
            # Calculate coding-specific reward
            works = test_code_solution(prompt, completion)
            reward = 1.0 if works else -1.0
            rewards.append(reward)
        else:
            # Return None for non-coding tasks
            rewards.append(None)
    return rewards

# Use both task-specific reward functions
if __name__ == "__main__":
    trainer = AsyncGRPOTrainer(
        model="Qwen/Qwen2.5-0.5B-Instruct",
        reward_funcs=[math_reward_func, coding_reward_func],
        train_dataset=dataset,
    )

    trainer.train()

이 예시에서 math_reward_func와 coding_reward_func는 수학 문제와 코딩 문제를 모두 포함하는 혼합 데이터셋과 함께 작동하도록 설계되었습니다. 데이터셋의 task 컬럼은 각 문제에 어떤 보상 함수를 적용할지 결정하는 데 사용됩니다. 데이터셋의 샘플에 해당하는 보상 함수가 없으면, 보상 함수는 None을 반환하고 AsyncGRPOTrainer는 유효한 함수와 작업을 계속 처리합니다. 이를 통해 AsyncGRPOTrainer는 서로 다른 적용 범위를 가진 여러 보상 함수를 처리할 수 있습니다.

AsyncGRPOTrainer는 보상 함수가 반환하는 None 보상을 무시하고, 관련 함수가 반환한 보상만 고려합니다. 이를 통해 모델은 관련 작업으로 학습되고, 관련 보상 함수가 없는 작업은 무시됩니다.

예제 5: 비동상 보상 함수

커스텀 보상 함수는 async def 코루틴으로 정의할 수도 있습니다. 보상이 느린 I/O(예: 원격 서비스 호출)에 의존하는 경우 유용합니다. 여러 개의 async 보상 함수를 전달하면 AsyncGRPOTrainer는 이를 병렬로 실행하여 지연 시간이 겹치게 합니다.

다음은 I/O 바운드 작업을 시뮬레이션하는 비동기 보상 함수의 최소 예시입니다:

import asyncio

async def async_reward_func(prompts, completions, **kwargs):
    # Simulate an I/O-bound call (e.g., HTTP request, database lookup)
    await asyncio.sleep(0.01)
    # Simple toy reward: 1.0 if the completion is non-empty, else 0.0
    return [1.0 if completion else 0.0 for completion in completions]

트레이너에 보상 함수 전달

사용자 정의 보상 함수를 사용하려면 다음과 같이 AsyncGRPOTrainer에 전달하세요:

from trl import AsyncGRPOTrainer

trainer = AsyncGRPOTrainer(
    reward_funcs=reward_func,
    ...,
)

여러 개의 보상 함수를 리스트로 전달할 수 있으며, 이 리스트에는 동기 함수와 비동기 함수가 모두 포함될 수 있습니다:

from trl import AsyncGRPOTrainer

trainer = AsyncGRPOTrainer(
    reward_funcs=[reward_func, async_reward_func1, async_reward_func2],
    ...,
)

보상은 각 함수의 보상 합으로 계산됩니다.

롤아웃 루프 사용자 정의

생성, 보상, 이점 및 필터링은 AsyncRolloutLoop의 rollout 프로세스에서 실행됩니다. 이 중 하나를 변경하려면 루프를 서브클래스로 상속하고 해당 단계의 메서드를 오버라이드한 후, 해당 서브클래스를 트레이너 서브클래스의 loop_cls로 설정합니다. 트레이너의 생성자는 변경되지 않습니다.

메서드호출됨기본값
filter_prompt(row_index, row, epoch)프롬프트당 한 번, 생성 전에모든 프롬프트를 허용합니다
generate_one(prompt, tools, group_id)롤아웃당 1회멀티턴 도구 루프
generate_one_turn(prompt_ids)샘플링 요청당 1회config의 샘플링 설정을 가진 vLLM 요청 하나
compute_advantages(group)group.rewards에 보상이 합산된 후 그룹별로 한 번그룹 내에서 표준화된 보상
setup(), close()루프가 시작되고 종료되는 시점nothing

예를 들어, 정책이 이미 해결한 프롬프트의 샘플링을 중단하는 커리큘럼은 설정 서브클래스의 임계값을 통해 정의할 수 있습니다:

from dataclasses import dataclass

import numpy as np

from trl import AsyncGRPOConfig, AsyncGRPOTrainer
from trl.trainer.async_grpo_trainer import AsyncRolloutLoop


@dataclass
class CurriculumConfig(AsyncGRPOConfig):
    pass_rate_cap: float = 0.9


class CurriculumRolloutLoop(AsyncRolloutLoop):
    def filter_prompt(self, row_index, row, epoch):
        return self.pass_rates.get(row_index, 0.0) < self.config.pass_rate_cap

    async def setup(self):
        self.pass_rates = {}

    def compute_advantages(self, group):
        scored = group.rewards[~np.isnan(group.rewards)]
        if len(scored):
            self.pass_rates[group.row_index] = float(np.mean(scored > 0))
        return super().compute_advantages(group)


class CurriculumTrainer(AsyncGRPOTrainer):
    loop_cls = CurriculumRolloutLoop

보상은 reward_funcs, get_reward을 정의한 환경, 그리고 커스텀 generate_one이 자신의 Rollout에 설정하는 reward에 대해 합산됩니다. 판정기로 점수를 매기려면 비동기 보상 함수를 전달하거나, generate_one 내부에서 점수를 매기세요. compute_advantages는 모든 그룹에 대해 실행되며, 점수화된 보상이 모두 동일하여 나중에 제거되는 그룹도 포함됩니다. 제거 여부는 보상을 기준으로 판단하며, 이점을 기준으로 하지 않습니다. 루프는 생성된 프로세스에서 구성되므로, 서브클래스를 모듈 수준에서 정의하고 학습 코드는 if __name__ == "__main__": 아래에 유지하세요. 클라이언트는 __init__를 오버라이드하는 대신, 루프의 이벤트 루프에서 실행되는 setup에서 생성하세요. filter_prompt가 거부한 프롬프트는 해당 에포크에서 건너뛰며, 제거된 그룹과 마찬가지로 해당 에포크에 포함됩니다. 한 에포크의 모든 프롬프트를 거부하면 루프가 예외를 발생시킵니다.

체크포인트에서 재개

기본 Trainer는 이미 학습한 배치들을 건너뛰고 다시 재생하는 방식으로 재개되지만, 이는 라이브 롤아웃 큐에는 적용되지 않으므로 ignore_data_skip은 항상 True입니다. 대신 아직 학습되지 않은 첫 번째 프롬프트의 인덱스가 각 체크포인트와 함께 rollout_state.json에 저장되고 재개 시 복원되며, 이를 통해 워커는 샘플을 다시 재생하지 않고 해당 프롬프트까지 빠르게 이동합니다. 이는 생성기의 위치가 아니라 trained 위치입니다. 워커는 롤아웃 큐 깊이에 따라 학습보다 앞서 실행되며, 이러한 버퍼링된 샘플은 실행이 종료되면 손실되므로 생성기의 위치에서 재개하면 생성되었지만 학습되지 않은 프롬프트를 건너뛰게 됩니다. 스트리밍 데이터셋(IterableDataset)은 위치를 재설정할 수 없으므로, 재개 시 워커는 첫 번째 프롬프트부터 다시 시작합니다.

에이전트 학습

Asynchronous GRPO는 에이전트 학습을 지원합니다. 모델은 생성 과정에서 도구를 호출하고 그 결과로부터 학습합니다.

  • tool은 모델에 노출되는 일반 Python 함수(동기 또는 비동기)입니다. 상태가 없는 호출(계산기, 웹 검색)에는 tools를 사용하세요.
  • environment은 보다 일반적인 형태입니다. 각 rollout마다 새로 생성되는 상태가 있는 객체로, 공개된 메서드들이 도구로 노출되며, reset 라이프사이클 훅과 보상을 소유할 수 있도록 하는 선택적 get_reward를 포함합니다. rollout별 상태, reset 훅, 또는 환경이 소유하는 보상이 필요할 때는 environment_factory를 사용하세요.

구성할 수 있습니다 — environment_factory와 함께 독립적인 tools를 전달할 수 있습니다.

도구

tools 인수는 에이전트가 사용할 수 있는 도구를 정의하는 Python 함수(동기 또는 비동기)의 목록을 기대합니다:

from trl import AsyncGRPOTrainer

trainer = AsyncGRPOTrainer(
    tools=[tool1, tool2],
    ...,
)

각 도구는 타입 힌트가 지정된 인자와 반환 타입을 가진 표준 Python 함수여야 하며, 목적, 인자, 반환 값을 설명하는 Google 스타일 docstring을 포함해야 합니다. 자세한 내용은 Passing tools 가이드를 참조하세요.

모델은 도구 이름을 통해 도구를 호출하므로, 각 도구는 __name__ 아래에 등록되어야 하며 모듈 레벨 함수여야 합니다. 이를 통해 rollout worker에서 pickling이 가능하게 유지됩니다. 동기 도구는 max_concurrent_rollouts 크기의 스레드 풀에서 실행되므로, 느린 도구가 진행 중인 다른 rollout을 차단하지 않습니다. 하나의 어시스턴트 턴 내에서 도구 호출은 모델이 출력한 순서대로 실행됩니다. 따라서 최대 max_concurrent_rollouts개의 동기 도구가 동시에 실행될 수 있으므로, 공유 상태를 읽거나 쓰는 도구는 스레드 안전(thread-safe)해야 합니다.

Tool call 루프는 채팅 템플릿이 prefix-preserving이어야 합니다(도구 메시지를 추가해도 이전 메시지의 렌더링 방식이 변경되어서는 안 됩니다). 알려진 모델 계열(예: Qwen3, DeepSeek-V3)의 경우, TRL은 도구가 활성화되면 패치된 학습 템플릿으로 자동으로 교체합니다. 전체 목록은 Chat Templates을 참조하세요.

max_tool_calling_iterations를 AsyncGRPOConfig에서 사용하여 도구 호출 턴의 수를 제한할 수 있습니다. 기본적으로 제한이 없으며, 모델이 도구 호출이 없는 응답 턴을 생성하면 생성이 중단됩니다.

예:

from trl import AsyncGRPOTrainer

def multiply(a: int, b: int) -> int:
    """
    Multiplies two integers.

    Args:
        a: The first integer.
        b: The second integer.

    Returns:
        The product of the two integers.
    """
    return a * b

async def async_add(a: int, b: int) -> int:
    """
    Asynchronously adds two integers.

    Args:
        a: The first integer.
        b: The second integer.

    Returns:
        The sum of the two integers.
    """
    return a + b

trainer = AsyncGRPOTrainer(
    tools=[multiply, async_add],
    ...,
)

환경

environment_factory를 통해 도구를 제공할 수도 있습니다. 이 모드에서 AsyncGRPOTrainer는 각 rollout마다 환경 인스턴스를 하나 생성하고, 환경의 public 메서드를 도구로 노출합니다.

environment_factory를 사용하면 환경이 데이터를 소유합니다. 외부의 train_dataset는 없습니다. 각 rollout마다 reset()이 작업을 생성합니다. 환경이 보유하는 코퍼스에서 자체 샘플링을 하거나 상태를 절차적으로 생성하는 방식입니다. 이후 프롬프트를 반환합니다. max_steps는 학습 길이를 설정합니다. 다음은 타겟을 자체 샘플링하고 increment 메서드(도구로 노출됨)를 노출하는 환경의 최소 예시입니다.

import random

from trl import AsyncGRPOConfig, AsyncGRPOTrainer

class IncrementEnv:
    # Reserved methods
    def reset(self, **kwargs) -> str | None:  # required; called at the start of each rollout
        self.counter = 0
        self.target = random.randint(1, 6)  # self-sample the task
        return f"Increment the counter by {self.target}."  # returned string becomes the prompt

    def get_reward(self) -> float:  # optional: the environment scores itself from its own state
        return float(self.counter == self.target)

    # Public methods (exposed as tools)
    def increment(self, step: int) -> int:
        """
        Increment the internal counter.

        Args:
            step: Value to add to the counter.

        Returns:
            The updated counter value.
        """
        self.counter += step
        return self.counter

if __name__ == "__main__":
    trainer = AsyncGRPOTrainer(
        model="Qwen/Qwen3-0.6B",
        args=AsyncGRPOConfig(max_steps=1000, chat_template_kwargs={"enable_thinking": False}),
        environment_factory=IncrementEnv,
    )
    trainer.train()

환경 클래스에는 reset와 get_reward라는 두 개의 예약된 메서드가 있습니다. 다른 공개 메서드와 달리, 이 메서드들은 모델에 도구로 노출되지 않습니다.

  • reset (필수)는 rollout이 시작될 때 호출됩니다. None 또는 문자열을 반환할 수 있습니다. 문자열을 반환하는 경우, 해당 문자열이 사용자 프롬프트가 됩니다.
  • get_reward (선택 사항, 동기 또는 비동기)는 인수를 받지 않으며 float를 반환합니다. 환경은 자신의 내부 상태(게임이 승리로 끝났는가? 단어가 추측되었는가?)를 기준으로 방금 실행된 에피소드에 점수를 매깁니다. 완료된 롤아웃마다 한 번씩 호출되며 보상 소스로 작용합니다.

둘 다 워커의 도구 스레드 풀에서 실행되므로, 느린 환경은 자신의 롤아웃만 지연시키고 진행 중인 다른 환경에는 영향을 미치지 않습니다. 소요 시간은 env/reset_s와 env/reward_s로 기록됩니다.

환경이 각 reset() 호출 시 자체적으로 샘플링하기 때문에, GRPO 그룹의 G개 멤버는 동일한 초기 상태를 공유하지 않을 수 있으며, 이로 인해 그룹 베이스라인이 약간 더 노이즈가 생길 수 있습니다. 그룹 내에서 동일한 상태를 유지하려면, reset()이 공유된 키로부터 상태를 결정적으로 유도하도록 하세요.

외부 데이터셋 제공 (선택 사항)

환경이 자체적으로 샘플링하도록 두는 대신, 외부 train_dataset를 제공할 수 있습니다. 예를 들어, 작업이 이미 데이터셋에 포함되어 있거나 여러 환경 사이를 라우팅해야 하는 경우에 사용할 수 있습니다. 롤아웃마다 트레이너는 한 행을 샘플링하고, 해당 행의 "prompt" 컬럼을 프롬프트로 사용하며, 행의 컬럼을 reset()에 키워드 인수로 전달합니다(이로써 환경이 데이터셋에서 작업을 읽게 됩니다).

from datasets import Dataset
from trl import AsyncGRPOTrainer

# Each row carries the prompt and the task data (here, the counter target to reach).
dataset = Dataset.from_dict(
    {
        "prompt": [[{"role": "user", "content": f"Increment the counter to {i}."}] for i in range(1, 7)],
        "target": list(range(1, 7)),
    }
)

class IncrementEnv:
    def reset(self, target, **kwargs) -> None:  # the row's `target` column arrives as a keyword argument
        self.counter = 0
        self.target = target

    def get_reward(self) -> float:
        return float(self.counter == self.target)

    def increment(self, step: int) -> int:  # exposed as a tool (see the full docstring above)
        self.counter += step
        return self.counter

if __name__ == "__main__":
    trainer = AsyncGRPOTrainer(
        model="Qwen/Qwen3-0.6B",
        train_dataset=dataset,  # the dataset owns the task; the "target" column reaches reset(target=...)
        environment_factory=IncrementEnv,
    )
    trainer.train()

보상

Environment-owned reward와 trainer-owned reward는 상호 배타적이지 않습니다. completion에서 계산하는 것이 자연스러운 reward(예: 텍스트에 대한 형식 검사)의 경우 reward_funcs를 전달하고, 그리고 environment가 상태에 의존하는 reward를 get_reward를 통해 반환하도록 합니다. 모든 소스는 가중치 1로 합산됩니다.

def format_reward(completions, **kwargs):  # trainer-owned: scores the completion text
    ...

trainer = AsyncGRPOTrainer(
    model="Qwen/Qwen3-0.6B",
    args=AsyncGRPOConfig(max_steps=1000),
    reward_funcs=format_reward,          # trainer-owned: scores the completion
    environment_factory=IncrementEnv,    # env-owned: scores its internal state via `get_reward`
)

여러 환경

단일 실행에서 여러 작업의 혼합으로 학습하려면(예: 코딩 작업과 게임), 단일 callable 대신 환경 이름에서 팩토리로 매핑하는 딕셔너리를 전달합니다. 각 롤아웃은 데이터셋의 environment 필드를 통해 환경을 선택하며, 해당 환경의 도구만 노출됩니다. 이를 통해 관련 없는 도구가 누출되는 것을 방지합니다(게임의 move 도구가 코딩 예시에 노출되거나 그 반대의 경우). 각 환경은 여전히 자신의 데이터를 소유하고 reset()에서 프롬프트를 반환하므로, 데이터셋은 환경 간 라우팅을 위해 environment 컬럼만 필요로 합니다.

import random

from datasets import Dataset
from trl import AsyncGRPOConfig, AsyncGRPOTrainer


class CodingEnv:
    def reset(self, **kwargs) -> str:
        n = random.randint(1, 20)
        return f"Compute the {n}th Fibonacci number."

    def run_code(self, code: str) -> str:  # exposed as a tool only for "coding" examples
        """Run the given Python code and return its stdout.

        Args:
            code: The Python source to execute.

        Returns:
            The captured standard output.
        """
        ...

class GameEnv:
    def reset(self, **kwargs) -> str:
        return "Reach the goal tile."

    def move(self, action: str) -> str:  # exposed as a tool only for "game" examples
        """Apply an action to the game and return the new observation.

        Args:
            action: One of "up", "down", "left", "right".

        Returns:
            The observation after the move.
        """
        ...

# The dataset only routes: each row picks the environment for that rollout
if __name__ == "__main__":
    dataset = Dataset.from_dict({"environment": ["coding", "game"] * 500})

    trainer = AsyncGRPOTrainer(
        model="Qwen/Qwen3-0.6B",
        args=AsyncGRPOConfig(chat_template_kwargs={"enable_thinking": False}),
        train_dataset=dataset,
        reward_funcs=reward_func,
        environment_factory={"coding": CodingEnv, "game": GameEnv},
    )
    trainer.train()

Environment 인스턴스는 스텝 간에 재사용되며(에피소드 간에 리셋됨) 따라서 비용이 높은 __init__는 매 스텝마다가 아닌 한 번만 지불됩니다. environment 필드는 trainer에 의해 소비되며 reset으로 전달되지 않습니다.

멀티턴 롤아웃

각 턴(turn)은 대화 템플릿을 통해 전체 대화를 렌더링하고, 이를 기반으로 생성을 수행합니다. 대화 템플릿은 항상 성장하는 대화를 동일한 방식으로 렌더링하지는 않습니다(예를 들어 이전 턴의 추론을 제거하는 경우가 있음). 따라서 특정 턴의 프롬프트 토큰은 지금까지 유지된 토큰과 다를 수 있습니다. 롤아웃이 끝나면 워커는 턴들을 학습 샘플로 조정합니다. 유지된 토큰으로 시작하는 프롬프트를 가진 턴은 동일한 샘플에 추가되고, 그 외의 턴은 새로운 샘플을 시작합니다. 모든 생성된 토큰은 정확히 하나의 샘플에서만 학습되므로, 포크(fork)는 포워드 토큰 비용은 발생시키지만 학습 신호는 발생시키지 않습니다.

rollout의 각 샘플은 해당 rollout의 advantage를 받습니다. rollout/fork_frac와 rollout/drift_tokens_*는 턴이 어떻게 조정되었는지 보여줍니다.

환경 통합

Harbor 샌드박스에서 실행되는 코딩 에이전트와 같이 자체 하네스에서 실행되는 에이전트를 학습하려면 OpenEnv 가이드의 Training on harnesses를 참조하세요.

비전 언어 모델 학습

비전-언어 모델(Qwen3.5, Qwen3.6, Qwen3-VL, …)은 텍스트 전용 데이터셋으로 학습할 수 있습니다. 모델 ID를 평소와 같이 전달하면 되며, 다른 변경 사항은 없습니다.

비전 타워는 동결됩니다. 텍스트 전용 데이터셋은 이미지 토큰을 생성하지 않으므로, 포워드 패스에서 타워가 사용되지 않습니다. 텍스트 모델 외부의 모든 구성 요소(비전 타워, 멀티모달 프로젝터)는 requires_grad=False 상태입니다. 따라서 그라디언트와 옵티마이저 상태가 할당되지 않으며, 가중치 동기화에서도 제외되어 서버는 체크포인트에서 로드한 값을 유지합니다. 타워는 여전히 로드되므로, 그 가중치를 위해 GPU 메모리를 차지합니다.

이미지는 아직 지원되지 않습니다. 이미지를 포함하는 프롬프트는 vLLM 서버나 학습 forward pass로 전달되지 않습니다. 멀티모달 학습은 이미지 그리드에서 3D M-RoPE 위치를 구성하기 위해 padding-free packing 경로가 필요하지만, 여기서는 구현되어 있지 않습니다.

AsyncGRPOTrainer

클래스 trl.AsyncGRPOTrainer

< >

( model: str | PreTrainedModelreward_funcs: collections.abc.Callable[..., list[float]] | list[collections.abc.Callable[..., list[float]]] | None = Noneargs: trl.trainer.async_grpo_config.AsyncGRPOConfig | None = Nonetrain_dataset: datasets.arrow_dataset.Dataset | datasets.iterable_dataset.IterableDataset | None = Noneprocessing_class: transformers.tokenization_utils_base.PreTrainedTokenizerBase | None = Nonecallbacks: list[transformers.trainer_callback.TrainerCallback] | None = Noneoptimizers: tuple[typing.Optional[torch.optim.Optimizer], typing.Optional[torch.optim.lr_scheduler.LambdaLR]] = (None, None)peft_config: PeftConfig | None = Nonetools: list[collections.abc.Callable] | None = Noneenvironment_factory: collections.abc.Callable[[], trl.trainer.async_grpo_trainer._SupportsReset] | dict[str, collections.abc.Callable[[], trl.trainer.async_grpo_trainer._SupportsReset]] | None = None )

매개변수

  • model (str 또는 PreTrainedModel) — 학습할 모델. 다음 중 하나여야 합니다: huggingface.co의 모델 저장소에 호스팅된 사전 학습 모델의 모델 ID인 문자열, 또는 save_pretrained를 사용하여 모델 가중치를 저장한 디렉터리의 경로(예: './my_model_directory/'). 모델은 config에 선언된 아키텍처로 로드됩니다. 비전-언어 체크포인트의 경우 AutoModelForImageTextToText(비전 타워는 로드되지만 동결되며, Training Vision Language Models 참조), 그 외의 경우 AutoModelForCausalLM이 사용됩니다. PreTrainedModel 객체. packed training을 위해 attention 구현이 trainer의 tree attention 백엔드로 전환됩니다. config의 모델 이름은 생성에 사용되는 vLLM 서버에서 모델을 식별하는 데 사용됩니다.
    • huggingface.co의 모델 저장소에 호스팅된 사전 학습 모델의 model id인 문자열, 또는 save_pretrained를 사용하여 모델 가중치를 저장한 directory의 경로, 예: './my_model_directory/'. 모델은 해당 config에 선언된 아키텍처로 로드됩니다: 비전-언어 체크포인트의 경우 AutoModelForImageTextToText (비전 타워는 로드되지만 동결되며, Training Vision Language Models 참조), 그 외의 경우 AutoModelForCausalLM.
    • PreTrainedModel 객체입니다. 패킹 훈련을 위해 어텐션 구현이 트레이너의 트리 어텐션 백엔드로 전환됩니다.

    생성에 사용되는 vLLM 서버에서 모델을 식별하기 위해 config의 모델 이름이 사용됩니다.

  • reward_funcs (RewardFunc | list[RewardFunc], 선택 사항) — 보상을 계산하는 데 사용할 보상 함수입니다. 보상을 계산하려면 프롬프트와 완성 결과를 인수로 모든 보상 함수를 호출한 후 보상을 합산합니다. 보상이 환경에 의해 environment_factory ((아래 참조)를 통해 제공되는 경우 생략할 수 있습니다. 다음 중 하나여야 합니다:
    • 단일 보상 함수: 이 함수에는 프롬프트와 생성된 완성문, 그리고 데이터셋의 추가 열이 제공됩니다. 보상 목록을 반환해야 합니다. 보상 함수는 동기식 또는 비동기식일 수 있으며, 해당 샘플에 보상이 적용되지 않는 경우 None을 반환할 수도 있습니다. 이는 서로 다른 유형의 샘플에 서로 다른 보상 함수가 적용되는 멀티태스크 학습에 유용합니다. 보상 함수가 특정 샘플에 대해 None을 반환하면, 해당 샘플의 보상 계산에서 그 보상 함수가 제외됩니다. 자세한 내용은 사용자 정의 보상 함수 사용을 참조하세요.
    • 위에서 설명한 바와 같이 각 항목이 보상 함수인 보상 함수 목록입니다. 모든 함수의 보상이 합산됩니다.

    GRPOTrainer와 달리 보상(reward)은 생성된 자식 프로세스에서 계산되므로, 각 보상 함수(그리고 tools 및 environment_factory)는 picklable이어야 합니다. 모듈 레벨 함수, functools.partial, 또는 callable 클래스 인스턴스를 사용해야 하며, 람다와 클로저는 시작 시점에 실패합니다. 도구는 __name__ 아래에 등록되므로 모듈 레벨 함수여야 합니다. 자식 프로세스는 CUDA_VISIBLE_DEVICES=""로 실행되므로, GPU 기반 보상 모델은 트레이너의 GPU가 아닌 CPU에서(느리게) 실행됩니다.

  • args (AsyncGRPOConfig, 선택 사항) — 이 trainer의 설정입니다. None인 경우 기본 설정이 사용됩니다.
  • train_dataset (Dataset 또는 IterableDataset, 선택 사항) — 학습에 사용할 Dataset입니다. 반드시 다음 컬럼을 포함해야 합니다. "prompt". Dataset의 추가 컬럼은 무시됩니다. 샘플은 대화형 형식이어야 합니다: 각 샘플에는 구조화된 메시지(예: role과 content)가 포함됩니다.

    environment_factory가 제공되고 환경이 데이터를 소유하거나 절차적으로 생성하여 reset() 메서드에서 프롬프트를 반환하는 경우에만 생략할 수 있습니다. 이 경우 학습 길이를 정의하기 위해 max_steps를 설정해야 합니다.

  • processing_class (PreTrainedTokenizerBase, 선택 사항) — 데이터를 처리하는 데 사용되는 처리 클래스입니다. 패딩 쪽은 “left”로 설정해야 합니다. None인 경우, from_pretrained를 사용하여 모델 이름에서 처리 클래스를 로드합니다. 패딩 토큰인 tokenizer.pad_token이 설정되어 있어야 합니다. 처리 클래스에 패딩 토큰이 설정되지 않은 경우, tokenizer.eos_token이 기본값으로 사용됩니다.
  • callbacks (의 목록 TrainerCallback, 선택 사항) — 학습 루프를 사용자 정의할 콜백 목록입니다. 여기.

    기본으로 사용되는 콜백 중 하나를 제거하려면 remove_callback 메서드를 사용하세요.

  • optimizers (tuple[torch.optim.Optimizer | None, torch.optim.lr_scheduler.LambdaLR | None], 선택 사항, 기본값 (None, None)) — 사용할 옵티마이저와 스케줄러를 포함하는 튜플입니다. 기본적으로 모델에 AdamW 인스턴스와 args에 의해 제어되는 get_linear_schedule_with_warmup로 생성된 스케줄러를 사용합니다.
  • peft_config (PeftConfig, 선택 사항) — 모델을 래핑하는 데 사용되는 PEFT 구성입니다. None인 경우 모델은 래핑되지 않습니다. vLLM 서버가 --enable-lora로 시작되었을 때, LoRA 어댑터는 병합된 가중치가 아닌 어댑터로 동기화됩니다. AsyncGRPO 문서의 LoRA 섹션을 참조하세요.
  • tools (Callable의 목록, 선택 사항) — 모델이 생성 과정에서 호출할 수 있는 콜러블 도구 함수(동기 또는 비동기)의 목록입니다. 각 도구는 적절히 타입 힌트가 지정된 인자와 반환 값을 가진 표준 Python 함수여야 하며, 목적, 인자, 반환 값을 설명하는 Google 스타일 docstring을 포함해야 합니다. 자세한 내용은 https://huggingface.co/docs/transformers/en/chat_extras#passing-tools를 참조하세요. 모델은 함수의 이름, 타입 힌트, docstring을 기반으로 호출 방법을 결정합니다. 모델의 chat template이 도구 사용을 지원하고 도구 호출을 위해 fine-tuning이 되었는지 확인하세요.
  • environment_factory (EnvironmentFactory 또는 dict[str, EnvironmentFactory], 선택 사항) — 환경 인스턴스를 생성하여 반환하는 호출 가능한 객체, 또는 환경 이름을 이러한 호출 가능한 객체로 매핑하는 사전입니다. 환경 클래스는 생성 중에 도구로 호출될 수 있는 메서드를 정의해야 합니다. 각 메서드는 위에서 설명한 tools 의 동일한 요구 사항을 충족해야 합니다. 환경은 또한 생성 사이에 상태를 초기화하는 데 사용할 수 있는 호출 가능한 reset 메서드를 구현해야 합니다. reset 메서드는 None 또는 문자열을 반환해야 합니다. 문자열을 반환하는 경우, 해당 문자열은 생성 전에 마지막 사용자 메시지에 추가됩니다. 환경은 인자를 받지 않고 get_reward 를 반환하는 float: 메서드를 정의할 수도 있습니다. 이 메서드가 존재하면 환경이 보상을 소유하게 되고, get_reward 는 완료된 롤아웃마다 한 번씩 호출되어 환경의 내부 상태로부터 점수를 매깁니다. 이는 환경의 클래스 이름으로 기록되는 가중치 1의 추가 보상 소스로 작용하며, 동시에 다음 메서드는 선택 사항이 됩니다. 단일 호출 가능한 객체를 사용하는 경우 모든 예제는 동일한 환경을 사용하며, 롤아웃당 하나의 인스턴스가 생성되어 상호작용이 격리됩니다. 사전을 사용하는 경우 각 예제는 환경 필드를 통해 이름을 지정하여 환경을 선택해야 하며, 해당 환경의 도구만 프롬프트에 노출됩니다. 이를 통해 단일 실행에서 여러 작업을 혼합할 수 있습니다(예: 코딩 환경과 게임). 이 기능은 실험적이며 사전 통보 없이 언제든 변경되거나 제거될 수 있습니다. reward_funcs, 이 선택 사항이 됩니다.

    단일 callable을 사용하는 경우, 모든 예제는 동일한 환경을 사용하며 rollout당 하나의 인스턴스가 생성되어 상호작용이 격리됩니다. 딕셔너리를 사용하는 경우, 각 예제는 environment 필드를 통해 이름을 지정하여 환경을 선택해야 하며, 해당 환경의 도구만 프롬프트에 노출됩니다. 이를 통해 단일 실행에서 여러 작업을 혼합할 수 있습니다(예: 코딩 환경과 게임). 이 기능은 실험적이며 사전 통보 없이 언제든 변경되거나 제거될 수 있습니다.

Group Relative Policy Optimization(GRPO) 방법을 위한 Trainer입니다. 이 알고리즘은 DeepSeekMath: Pushing the Limits of Mathematical Reasoning in Open Language Models 논문에서 처음 제안되었습니다. 이 Trainer는 GRPO의 비동기 버전으로, 생성을 외부 vLLM 서버로 오프로드하여 학습과 동시에 비동기적으로 실행함으로써 rollout을 그래디언트 업데이트 루프와 분리합니다.

예:

>>> from trl import AsyncGRPOTrainer
>>> from trl.rewards import accuracy_reward
>>> from datasets import load_dataset

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

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

샘플링할 프롬프트, 롤아웃 생성 방식, 이점(advantage) 계산 방식을 커스터마이즈하려면 AsyncRolloutLoop를 서브클래스로 상속하고 이를 트레이너의 loop_cls로 설정하세요. TRL은 루프를

rollout 과정:

>>> class CurriculumTrainer(AsyncGRPOTrainer):
...     loop_cls = CurriculumRolloutLoop

train

< >

( resume_from_checkpoint: str | bool | None = Nonetrial: optuna.Trial | dict[str, Any] | None = Noneignore_keys_for_eval: list[str] | None = None ) → ~trainer_utils.TrainOutput

매개변수

  • resume_from_checkpoint (str 또는 bool, 선택 사항) — str인 경우, 이전 Trainer 인스턴스가 저장한 체크포인트의 로컬 경로입니다. bool이고 True와 같으면, 이전 Trainer 인스턴스가 args.output_dir에 저장한 마지막 체크포인트를 로드합니다. 이 값이 지정되어 있으면, 여기서 로드된 모델/옵티마이저/스케줄러 상태로부터 학습이 재개됩니다.
  • trial (optuna.Trial 또는 dict[str, Any], 선택 사항) — 하이퍼파라미터 탐색을 위한 트라이얼 실행 또는 하이퍼파라미터 사전입니다.
  • ignore_keys_for_eval (list[str], 선택 사항) — 모델의 출력(사전에 해당하는 경우)에서 학습 중 평가 예측을 수집할 때 무시해야 할 키의 목록입니다.

반환값

~trainer_utils.TrainOutput

전체 스텝 수, 학습 손실, 메트릭을 포함하는 객체.

주요 학습 진입점.

save_model

< >

( output_dir: str | None = None_internal_call: bool = False )

모델을 저장하므로 from_pretrained()를 사용하여 다시 로드할 수 있습니다.

main 프로세스에서만 저장합니다.

push_to_hub

< >

( commit_message: str | None = 'End of training'blocking: bool = Truetoken: str | None = Nonerevision: str | None = None**kwargs )

매개변수

  • commit_message (str, 선택 사항, 기본값 "End of training") — 푸시할 때 커밋할 메시지입니다.
  • blocking (bool, 선택 사항, 기본값 True) — git push가 완료된 후에만 함수가 반환되어야 하는지 여부.
  • token (str, 선택 사항, 기본값 None) — Trainer의 원래 args를 덮어쓸 수 있는 쓰기 권한이 있는 토큰.
  • revision (str, 선택 사항) — 커밋할 git revision입니다. 기본값은 “main” 브랜치의 head입니다.
  • kwargs (dict[str, Any], 선택) — ~Trainer.create_model_card에 함께 전달되는 추가 키워드 인자입니다.

self.args.hub_model_id 저장소에 self.model과 self.processing_class를 🤗 모델 허브에 업로드합니다.

AsyncGRPOConfig

클래스 trl.AsyncGRPOConfig

< >

( output_dir: str | None = Noneper_device_train_batch_size: int = 8num_train_epochs: float = 3.0max_steps: int = -1learning_rate: float = 1e-06lr_scheduler_type: str = 'constant'lr_scheduler_kwargs: dict | str | None = Nonewarmup_steps: float = 0optim: transformers.training_args.OptimizerNames | str = 'adamw_torch_fused'optim_args: str | None = Noneweight_decay: float = 0.0adam_beta1: float = 0.9adam_beta2: float = 0.999adam_epsilon: float = 1e-08optim_target_modules: None | str | list[str] = Nonegradient_accumulation_steps: int = 1average_tokens_across_devices: bool = Truemax_grad_norm: float = 1.0label_smoothing_factor: float = 0.0bf16: bool | None = Nonefp16: bool = Falsebf16_full_eval: bool = Falsefp16_full_eval: bool = Falsetf32: bool | None = Nonegradient_checkpointing: bool = Truegradient_checkpointing_kwargs: dict[str, typing.Any] | str | None = Nonetorch_compile: bool = Falsetorch_compile_backend: str | None = Nonetorch_compile_mode: str | None = Noneuse_liger_kernel: bool = Falseliger_kernel_config: dict[str, bool] | None = Noneuse_cache: bool = Falseneftune_noise_alpha: float | None = Nonetorch_empty_cache_steps: int | None = Noneauto_find_batch_size: bool = Falselogging_strategy: transformers.trainer_utils.IntervalStrategy | str = 'steps'logging_steps: float = 1logging_first_step: bool = Falselog_on_each_node: bool = Truelogging_nan_inf_filter: bool = Trueinclude_num_input_tokens_seen: str | bool = 'no'log_level: str = 'passive'log_level_replica: str = 'warning'disable_tqdm: bool | None = Nonereport_to: None | str | list[str] = 'none'run_name: str | None = Noneproject: str = 'huggingface'trackio_space_id: str | None = Nonetrackio_bucket_id: str | None = Nonetrackio_static_space_id: typing.Union[str, NoneType, typing.Literal[False]] = Noneeval_strategy: transformers.trainer_utils.IntervalStrategy | str = 'no'eval_steps: float | None = Noneeval_delay: float = 0per_device_eval_batch_size: int = 8prediction_loss_only: bool = Falseeval_on_start: bool = Falseeval_do_concat_batches: bool = Trueeval_use_gather_object: bool = Falseeval_accumulation_steps: int | None = Noneinclude_for_metrics: list[str] = <factory>batch_eval_metrics: bool = Falsesave_only_model: bool = Falsesave_strategy: transformers.trainer_utils.SaveStrategy | str = 'steps'save_steps: float = 500save_on_each_node: bool = Falsesave_total_limit: int | None = Noneenable_jit_checkpoint: bool = Falsepush_to_hub: bool = Falsehub_token: str | None = Nonehub_private_repo: bool | None = Nonehub_model_id: str | None = Nonehub_strategy: transformers.trainer_utils.HubStrategy | str = 'every_save'hub_always_push: bool = Falsehub_revision: str | None = Noneload_best_model_at_end: bool = Falsemetric_for_best_model: str | None = Nonegreater_is_better: bool | None = Noneignore_data_skip: bool = Truerestore_callback_states_from_checkpoint: bool = Falsefull_determinism: bool = Falseseed: int = 42data_seed: int | None = Noneuse_cpu: bool = Falseaccelerator_config: dict | str | None = Noneparallelism_config: accelerate.parallelism_config.ParallelismConfig | None = Nonedataloader_drop_last: bool = Falsedataloader_num_workers: int = 0dataloader_pin_memory: bool = Truedataloader_persistent_workers: bool = Falsedataloader_prefetch_factor: int | None = Nonedataloader_multiprocessing_context: str | None = Nonedataloader_in_order: bool = Trueremove_unused_columns: bool = Falselabel_names: list[str] | None = Nonetrain_sampling_strategy: str = 'random'length_column_name: str = 'length'ddp_find_unused_parameters: bool | None = Noneddp_bucket_cap_mb: int | None = Noneddp_broadcast_buffers: bool | None = Noneddp_static_graph: bool | None = Noneddp_backend: str | None = Noneddp_timeout: int = 1800fsdp: str | None = Nonefsdp_config: dict[str, typing.Any] | str | None = Nonedeepspeed: dict | str | None = Nonedebug: str | list[transformers.debug_utils.DebugOption] = ''skip_memory_metrics: bool = Truedo_train: bool = Falsedo_eval: bool = Falsedo_predict: bool = Falseresume_from_checkpoint: str | None = Nonelocal_rank: int = -1model_init_kwargs: dict[str, typing.Any] | str | None = Nonedtype: str = 'float32'trust_remote_code: bool = Falserouter_aux_loss_coef: float | None = Nonenum_generations: int = 8max_completion_length: int = 2048temperature: float = 1.0top_p: float = 1.0top_k: int = 0min_p: float | None = Nonechat_template_kwargs: dict | str | None = Nonemax_tool_calling_iterations: int | None = Nonevllm_server_base_url: str = 'http://localhost:8000'vllm_server_timeout: float = 1800.0epsilon: float = 0.2epsilon_high: float | None = Nonescore_centering: bool = Truevllm_importance_sampling_clip_min: float = 0.5vllm_importance_sampling_clip_max: float = 5.0num_sampler_logprobs: int = 8token_budget: int | None = Nonemax_concurrent_rollouts: int = 512max_staleness: int = 4weight_sync_steps: int = 1rollout_worker_timeout: float = 300.0log_completions: bool = Falsenum_completions_to_print: int | None = None )

모델을 제어하는 매개변수

  • model_init_kwargs (dict[str, Any] 또는 str, 선택 사항) — 경로에서 모델을 인스턴스화할 때 from_pretrained에 사용되는 키워드 인수입니다. revision 값은 처리 클래스를 로드할 때에도 사용됩니다.
  • dtype (str, 선택 사항, 기본값은 "float32") — 모델을 로드할 데이터 타입으로, 다음 중 하나입니다. "auto", "bfloat16", "float16" 또는 "float32". 기본값은 "float32" 입니다. 이 트레이너가 측정 기준으로 삼는 학습-추론 불일치(FP16을 통한 학습-추론 불일치 극복) )은 트레이너 자체의 정밀도에 민감합니다. 이러한 격차를 끝에서 끝까지 해소하려면 vLLM 서버도 동일한 dtype(vllm serve --dtype); 으로 서빙해야 하며, 불일치가 발생하면 학습 시작 시 경고로 기록됩니다. dtype 의 model_init_kwargs 우선순위가 더 높습니다.

    이 설정은 가중치가 로드될 때 사용할 dtype만 지정합니다. FSDP의 혼합 정밀도 환경(bf16=True가 기본값)에서 accelerate는 샤딩 전에 모든 학습 가능한 파라미터를 fp32로 업캐스트합니다. 따라서 dtype 값과 관계없이 마스터 가중치와 옵티마이저 상태는 fp32로 유지되며, 포워드와 백워드는 bf16 또는 fp16으로 실행됩니다. 이후 체크포인트는 fp32가 아닌 해당 혼합 정밀도 dtype로 저장됩니다. FSDP를 사용하지 않으면 업캐스트가 발생하지 않습니다. dtype="bfloat16"와 bf16=True를 함께 사용하면 가중치와 옵티마이저 상태가 모두 bf16으로 유지되며, 이는 순수한 bf16 학습을 의미합니다.

  • trust_remote_code (bool, optional, defaults to False) — Whether to allow loading models and tokenizers that ship custom Python code from the Hub. Forwarded to from_pretrained and from_pretrained.
  • router_aux_loss_coef (float, 선택 사항) — Mixture-of-Experts(MoE) 모델의 로드 밸런싱 보조 손실 계수로, 이 가중치로 학습 손실에 추가됩니다. 설정되지 않으면 모델 구성에서 선언된 값이 사용됩니다. 비활성화하려면 0.0으로 설정하세요. MoE가 아닌 모델과 함께 사용하면 실패합니다.

생성을 제어하는 매개변수

  • num_generations (int, 선택 사항, 기본값 8) — 프롬프트당 샘플링할 생성 횟수.
  • max_completion_length (int, 선택 사항, 기본값 2048) — vLLM 요청당, 즉 멀티턴 롤아웃의 턴당 생성되는 최대 토큰 수입니다.
  • temperature (float, 선택 사항, 기본값 1.0) — 샘플링에 사용할 온도입니다. 온도가 높을수록 완성 결과가 더 무작위적으로 생성됩니다.
  • top_p (float, 선택 사항, 기본값 1.0) — 고려할 상위 토큰의 누적 확률을 제어하는 실수입니다. 값은 (0, 1] 범위에 있어야 합니다. 모든 토큰을 고려하려면 1.0으로 설정합니다. 1.0 미만인 경우 top_k도 함께 설정해야 하며, --return-sampling-mask --enable-scale-out 옵션으로 시작된 vLLM 서버(>= 0.28)가 필요합니다. 트레이너는 서버와 마찬가지로 각 토큰이 샘플링된 후보 집합에 대해 로그 확률을 재정규화합니다. 구버전의 vLLM은 전체 어휘를 유지합니다.
  • top_k (int, 선택 사항, 기본값 0) — top-k-filtering을 위해 유지할 가장 높은 확률의 어휘 토큰 수입니다. 0인 경우 top-k-filtering이 비활성화되고 모든 토큰이 고려됩니다. 그 외의 값은 top_p 아래에 설명된 서버 플래그가 필요합니다.
  • min_p (float, 선택 사항) — 최소 토큰 확률입니다. 가장 가능성이 높은 토큰의 확률로 스케일링됩니다. 0.0과 1.0 사이의 값이어야 합니다. 일반적인 값은 0.01~0.2 범위입니다. 0.0보다 큰 값인 경우, top_p 아래에 설명된 서버 플래그와 함께 top_k도 설정해야 합니다.
  • chat_template_kwargs (dict[str, Any], 선택) — 완성 결과를 생성할 때 apply_chat_template 함수에 전달할 추가 키워드 인자입니다.
  • max_tool_calling_iterations (int, 선택 사항) — 에이전트를 학습할 때의 최대 도구 호출 턴 수입니다. None인 경우 제한이 없으며, 모델이 도구 호출이 없는 응답 턴을 생성하면 생성이 중단됩니다.

vLLM 서버를 제어하는 매개변수

  • vllm_server_base_url (str, 선택 사항, 기본값 "http --//localhost:8000"): 생성에 사용되는 vLLM 서버의 기본 URL(예: "http://localhost:8000").
  • vllm_server_timeout (float, 선택 사항, 기본값 1800.0) — vLLM 서버 호출에 대한 초 단위 타임아웃입니다. 서버가 시작 시 준비될 때까지 대기하는 시간, 각 생성 요청, 각 가중치 동기화 호출에 적용됩니다. 서버 대기 및 가중치 동기화 호출은 타임아웃이 발생하면 예외를 발생시키고, 타임아웃이 발생한 생성 요청은 재시도됩니다.

학습을 제어하는 매개변수

  • epsilon (float, 선택 사항, 기본값 0.2) — 클리핑에 사용되는 Epsilon 값입니다.
  • epsilon_high (float, 선택 사항) — 클리핑을 위한 상한 epsilon 값입니다. 지정하지 않으면 epsilon 인수로 지정된 하한 값과 동일한 값이 기본값으로 사용됩니다. DAPO 논문에서는 0.28을 권장합니다.
  • score_centering (bool, 선택 사항, 기본값 True) — 클립된 목적 함수 대신 score centering(논문)으로 학습할지 여부입니다. 이는 각 샘플링된 토큰의 중요도 가중 점수에서 vLLM 샘플러에 대한 기대값을 뺀 값으로, 일정한 이점이 정책이 샘플러 쪽으로 끌려가도록 하지 않도록 합니다. 기대값은 각 위치에서 가장 가능성이 높은 num_sampler_logprobs개의 토큰에 대해 계산되며, 샘플러는 해당 토큰의 로그 확률을 보고합니다.
  • vllm_importance_sampling_clip_min (float, 선택 사항, 기본값 0.5) — 정책과 vLLM 샘플러 간의 중요도 비율의 하한 C_min입니다. 비율이 [vllm_importance_sampling_clip_min, vllm_importance_sampling_clip_max] 범위를 벗어나는 토큰은 손실 계산에서 제외됩니다(마스크 중요도 샘플링).
  • vllm_importance_sampling_clip_max (float, 선택 사항, 기본값 5.0) — 중요도 비율의 상한 C_max입니다.
  • num_sampler_logprobs (int, 선택 사항, 기본값 8) — 생성된 각 토큰에 대해 vLLM sampler에서 요청하는 상위 log-probabilities의 개수로, score centering에 사용됩니다. 값이 클수록 sampler의 확률 질량을 더 많이 커버하지만 직렬화 비용이 증가합니다. 서버의 --max-logprobs가 이 값의 상한을 결정합니다.
  • token_budget (int, 선택 사항) — 단일 행(하나의 DP rank의 forward)에서 전달되는 토큰의 최대 수입니다. TokenBudgetBatcher는 각 행이 이 예산 내에서 유지되도록 주의 비용이 균형 잡힌 마이크로 배치들을 형성하여, 샘플 수와 무관하게 피크 메모리를 제한합니다(행당 샘플 수는 동적으로 결정됩니다). 이 예산은 원본 토큰이 아닌 고유 토큰을 제한하므로 여러 샘플에 의해 공유되는 토큰은 한 번만 계산되며, 행의 손실 항도 제한합니다. None(기본값)인 경우, vLLM 서버의 max_model_len(학습 시작 시 조회)로 설정됩니다. 이는 프롬프트 + 완성 길이의 상한이므로 어떤 롤아웃 샘플도 예산을 초과할 수 없습니다. token_budget보다 긴 샘플은 어떤 행에도 맞지 않아 경고와 함께 제거됩니다.

비동기 롤아웃 파이프라인을 제어하는 매개변수

  • max_concurrent_rollouts (int, 선택 사항, 기본값 512) — 동시에 실행되는 rollout의 최대 수입니다. 각 rollout은 환경을 보유하며 동기식 도구 호출을 실행할 수 있고 vLLM 서버에 대한 연결을 유지하므로, 해당 리소스가 감당할 수 있는 수준으로 설정하세요. 이 값보다 아래에서, 진행 중인 rollout의 수는 vLLM 서버의 KV-cache 사용량과 max_staleness에 따라 결정됩니다.
  • max_staleness (int, 선택 사항, 기본값 4) — 롤아웃 샘플이 현재 모델 버전보다 최대 몇 단계의 가중치 업데이트를 뒤처질 수 있는지, 그 한계치입니다. 이 한계를 초과하면 샘플은 폐기됩니다. 생성 과정은 이 값에 맞춰 제어됩니다. 큐에 대기 중이거나 전송 중인 토큰이 트레이너가 max(max_staleness, 1) 단계 동안 소비하는 양에 맞을 때만 새로운 롤아웃 그룹이 시작됩니다.
  • weight_sync_steps (int, 선택 사항, 기본값 1) — vLLM 서버로 가중치를 동기화하는 간격(학습 스텝 수).
  • rollout_worker_timeout (float, 선택 사항, 기본값 300.0) — rollout worker의 마지막 heartbeat 이후 trainer가 해당 worker를 hung 상태로 간주하고 작업을 중단하기까지의 초 단위 시간입니다.

로깅을 제어하는 매개변수

  • log_completions (bool, 선택 사항, 기본값 False) — logging_steps 단계마다 (prompt, completion) 쌍의 샘플을 기록할지 여부.
  • num_completions_to_print (int, 선택 사항) — rich로 출력할 completions의 수입니다. None인 경우 모든 completions이 기록됩니다.

AsyncGRPOTrainer의 구성 클래스입니다.

이 클래스에는 비동기 GRPO 학습에 특화된 매개변수만 포함되어 있습니다. 학습 인자의 전체 목록은 TrainingArguments 문서를 참고하세요. 이 클래스의 기본값은 TrainingArguments의 기본값과 다를 수 있습니다.

이러한 파라미터는 TrainingArguments와 다른 기본값을 가집니다:

  • logging_steps: 기본값이 500 대신 1입니다.
  • gradient_checkpointing: 기본값이 False가 아닌 True입니다.
  • bf16: fp16가 설정되지 않은 경우 기본값이 False가 아닌 True입니다.
  • learning_rate: 기본값이 5e-5 대신 1e-6입니다.
  • lr_scheduler_type: linear 대신 기본값이 constant입니다(아래 참조).
  • ignore_data_skip: 기본값이 False가 아닌 True입니다. 기본 Trainer의 skip-and-replay 루프는 비동기 rollout 큐에 적용되지 않습니다.
  • remove_unused_columns: 기본값이 True가 아닌 False이며, False로 유지해야 합니다. 모든 데이터셋 열이 보상 함수에 전달되기 때문입니다.

메시지 모드 조정(message-mode reconciliation)에서의 학습 시간과 학습률: 멀티턴 대화는 가변 개수의 학습 행으로 분기될 수 있습니다(대화의 재작성(rewrite)은 새로운 행을 시작합니다). 따라서 에포크당 샘플 수, 즉 옵티마이저 스텝 수는 사전에 알 수 없습니다. 그 결과:

  • num_train_epochs은 prompt 데이터셋에 대한 전체 패스 수로 학습을 제한하며, 실제로 학습에 사용된 서로 다른 프롬프트의 개수로 계산됩니다. 이는 포크가 생성하는 행의 수와 무관하므로, N 에포크를 요청하면 항상 데이터에 대해 N번의 패스로 학습됩니다. max_steps가 설정되지 않은 경우, 이것이 중단 조건이 되며 max_steps는 안전 상한선으로만 기능합니다.
  • max_steps가 명시적으로 설정된 경우(> 0), epoch 기반의 중단 조건 대신 optimizer steps 기반의 중단 조건으로 작동하며 epoch 기반 중단을 비활성화합니다.
  • lr_scheduler_type의 기본값은 constant입니다. 감쇠 기간은 옵티마이저 스텝 단위로 측정되는데, 스텝 수가 포크 비율에 따라 달라지면 사전에 알 수 없기 때문입니다. 감쇠하는 학습률을 사용하려면 감쇠 스케줄과 명시적인 max_steps를 함께 설정하세요.

AsyncRolloutLoop

클래스 trl.trainer.async_grpo_trainer.AsyncRolloutLoop

< >

( config: AsyncGRPOConfigmodel_name: strdataset: Datasetreward_funcs: list[collections.abc.Callable[..., list[float]]]processing_class: PreTrainedTokenizerBaseeos_token_ids: list[int]rollout_buffer: Queuemodel_version_value: Synchronizedtoken_allowance: Synchronizedheartbeat_value: Synchronizedfailed_event: Eventexception_info_queue: Queuemetrics_queue: Queuetools: list[collections.abc.Callable] | None = Noneenvironment_factory: collections.abc.Callable[[], object] | dict[str, collections.abc.Callable[[], object]] | None = Nonescore_queue_maxsize: int = 16lora_name: str | None = Nonedataset_start_index: int = 0 )

spawned rollout 프로세스에서 AsyncGRPOTrainer의 rollouts를 생성하고 점수를 매깁니다.

기본적으로 GRPO를 구현합니다. 실행을 커스터마이징하려면 해당 클래스를 서브클래스로 상속하고, 변경되는 메서드만 오버라이드한 후, 해당 서브클래스를 트레이너의 loop_cls로 설정합니다. 각 프롬프트는 다음 순서대로 처리됩니다:

  • filter_prompt(): 프롬프트에 대해 생성을 수행할지 여부.
  • generate_one(): 각 샘플링 요청에 대해 generate_one_turn()을 호출하는 하나의 전체 롤아웃입니다.
  • num_generations개의 rollout 그룹에 점수가 부여됩니다. 그 보상(reward)은 트레이너의 reward_funcs, get_reward를 정의하는 환경, 그리고 Rollout.reward의 합입니다. 그런 다음 compute_advantages()가 그룹별로 한 번씩 실행됩니다.

setup()와 close()는 HTTP 클라이언트와 같은 리소스를 루프의 이벤트 루프에서 생성하고 해제합니다. 훅은 self.config(AsyncGRPOConfig의 하위 클래스는 자체 필드를 가질 수 있음)와 self.tokenizer를 읽을 수 있습니다. 루프가 생성된(spawned) 프로세스에서 빌드되므로, 하위 클래스는 가져올 수 있어야 합니다(모듈 레벨에서 정의됨).

필터 프롬프트

< >

( row_index: introw: dict[str, typing.Any]epoch: int ) → bool

매개변수

  • row_index (int) — 학습 데이터셋에서 행의 인덱스.
  • row (dict[str, Any]) — 데이터셋의 행입니다.
  • epoch (int) — 이 단계에 앞서 데이터셋을 완전히 몇 번 순회했는지를 나타내는 값.

반환값

bool

True이면 프롬프트에 대해 num_generations개의 롤아웃을 생성하고, False이면 건너뜁니다.

프롬프트에 대해 생성할지 여부입니다. 거부된 프롬프트는 해당 epoch에서 건너뛰어지며, 드롭된 그룹과 마찬가지로 소비된 것으로 집계됩니다. 기본적으로 모든 프롬프트를 허용합니다. 전체 epoch의 모든 프롬프트를 거부하면, 이후에는 어떤 배치도 trainer에 도달할 수 없으므로 예외가 발생합니다.

generate_one

< >

( prompt: list[dict[str, str]]tools: list[collections.abc.Callable]group_id: int = 0 ) → Rollout

매개변수

  • prompt (list[dict[str, Any]]) — 프롬프트 메시지입니다.
  • tools (list[Callable]) — 이 rollout에서 사용할 수 있는 도구: trainer의 tools와 environment_factory를 사용할 경우 environment의 public methods입니다.
  • group_id (int, 선택 사항, 기본값 0) — 해당 rollout이 속한 그룹의 식별자입니다.

반환값

롤아웃

완료된 롤아웃.

프롬프트에 대해 롤아웃 하나를 생성합니다.

기본적으로 다중 턴 도구 루프는 다음과 같이 동작합니다. 각 턴에서 채팅 템플릿을 사용하여 전체 대화를 렌더링하고, generate_one_turn()으로 응답을 샘플링한 후, 해당 응답에 포함된 도구 호출을 실행합니다. 이 과정은 모델이 더 이상 도구를 호출하지 않거나 max_tool_calling_iterations에 도달할 때까지 반복됩니다. 에이전트 프레임워크를 사용하여 다르게 생성하는 등, 이 동작을 오버라이드할 수 있습니다. 학습 시퀀스가 이로부터 구성되므로 모든 샘플링 요청을 Rollout.turns에 반환하고, 여기서 롤아웃을 평가하기 위해 Rollout.reward를 설정하세요.

generate_one_turn

< >

( prompt_ids: list[int] ) → TurnRecord

매개변수

  • prompt_ids (list[int]) — 전체 프롬프트의 토큰 ID입니다.

반환값

TurnRecord

프롬프트와 샘플링된 토큰 및 해당 로그 확률. top_k 또는 top_p를 사용하면 각 샘플링된 토큰의 후보 집합도 포함되며, num_sampler_logprobs를 사용하면 샘플러의 상위 로그 확률도 포함됩니다.

vLLM 서버에서 설정의 샘플링 설정(temperature, top_p, top_k, min_p, repetition_penalty 및 max_completion_length)을 사용하여 응답 하나를 샘플링합니다.

compute_advantages

< >

( group: RolloutGroup ) → np.ndarray

매개변수

  • group (RolloutGroup) — 하나의 프롬프트에 대한 num_generations개의 롤아웃이며, 총 보상 값은 group.rewards에 저장됩니다.

반환값

np.ndarray

group.rewards 순서대로 롤아웃당 하나의 이점(advantage)

그룹의 각 rollout에 대해 하나의 advantage를 계산합니다. 기본적으로 각 reward는 그룹 내에서 표준화됩니다. NaN reward를 가진 rollout은 advantage가 0로 설정되며, 평균과 표준편차 계산에서 제외됩니다.

각 그룹에 대해 실행됩니다. 점수화된 보상이 모두 동일한 그룹은 이 결과가 어떤 이점을 반환하든 제거됩니다.

설정

< >

( )

다른 훅이 필요한 리소스, 예를 들어 HTTP 클라이언트를 생성합니다. 첫 프롬프트 전에 루프의 이벤트 루프에서 실행됩니다. 기본적으로 아무 동작도 하지 않습니다.

닫기

< >

( )

setup()이 생성한 것을 해제합니다. 루프가 중단될 때 실행되며, 실패 시에도 포함됩니다. 기본적으로 아무 동작도 하지 않습니다.

롤아웃

class trl.trainer.async_grpo_trainer.Rollout

< >

( completion: list[dict[str, str]]completion_ids: list[int]turns: list[trl.trainer.async_grpo_trainer.TurnRecord]tool_call_count: int = 0tool_failure_count: int = 0reward: float | None = Nonerollout_id: str = <factory> )

매개변수

  • completion (list[dict[str, Any]]) — Messages generated after the prompt, in conversational format. Passed to the reward functions as completions.
  • completion_ids (list[int]) — 생성된 completion의 토큰 ID입니다. completion_ids로 reward 함수에 전달됩니다.
  • turns (list[TurnRecord]) — rollout를 생성한 샘플링 요청을 순서대로 나열한 것입니다. 학습 시퀀스는 이로부터 구성되며, 샘플링된 토큰은 학습 대상이 되고 각 프롬프트의 나머지 부분은 컨텍스트로 사용됩니다.
  • tool_call_count (int, 선택 사항, 기본값 0) — 롤아웃 동안 수행된 도구 호출의 수입니다.
  • tool_failure_count (int, 선택 사항, 기본값 0) — 실패한 도구 호출의 수입니다.
  • reward (float, 선택 사항) — 생성 과정에서 계산된 보상입니다. 예를 들어 외부 평가자에 의해 계산될 수 있습니다. 이 값은 보상 함수와 환경의 보상에 추가됩니다. None인 경우, 이 롤아웃은 해당 출처에서 보상을 받지 않습니다.
  • rollout_id (str, 선택 사항) — 디버깅을 위해 학습 행에서 rollout을 식별합니다. 기본값은 새로운 랜덤 16진수 ID입니다.

generate_one()에서 반환된 완료된 롤아웃 하나입니다.

TurnRecord

class trl.trainer.async_grpo_trainer.TurnRecord

< >

( prompt_ids: list[int]output_ids: list[int]output_log_probs: list[float] = <factory>output_mask: list[int] | None = Noneoutput_sampling_mask: list[list[int]] | None = Noneoutput_sampler_logprobs: list[dict[int, float]] | None = None )

매개변수

  • prompt_ids (list[int]) — 이 턴에 전송된 전체 프롬프트의 토큰 ID입니다. 대화의 이전 모든 턴을 포함합니다.
  • output_ids (list[int]) — 샘플러가 생성한 토큰 ID입니다.
  • output_log_probs (list[float], 선택 사항, 기본값 []) — output_ids의 각 토큰에 대한 Sampler log-probability입니다. 이 중 하나가 학습 대상인 경우 필수입니다.
  • output_mask (list[int], 선택 사항) — output_ids의 각 토큰에 대해 하나의 값을 지정합니다. 1은 해당 토큰을 학습 대상으로, 0은 컨텍스트로만 유지함을 의미합니다. None인 경우 모든 출력 토큰이 학습 대상이 됩니다.
  • output_sampling_mask (list[list[int]], 선택 사항) — output_ids의 각 토큰에 대한 목록: top_k / top_p 절단 조건에서 샘플러가 선택할 수 있는 토큰 ID입니다. None인 경우 전체 어휘를 의미합니다.
  • output_sampler_logprobs (list[dict[int, float]], 선택) — output_ids의 각 토큰마다 하나의 dict: 토큰 id를 키로 하여 샘플러의 가장 가능성이 높은 토큰들의 log-probabilities를 담고 있습니다. score centering(num_sampler_logprobs)에 사용됩니다.

샘플링 요청 1개: 샘플러에 전송된 프롬프트와 샘플러가 생성한 토큰

RolloutGroup

class trl.trainer.async_grpo_trainer.RolloutGroup

< >

( prompts: list[list[dict[str, str]]]reward_kwargs: dict[str, list[typing.Any]]completions: list[list[dict[str, str]]]completions_ids: list[list[int]]completions_sequences: list[list[trl.trainer.async_grpo_trainer.TrainingSequence]]tool_call_counts: list[int]tool_failure_counts: list[int]model_version: intgroup_id: introw_index: intenv_rewards: list[tuple[type, float] | None]rollout_rewards: list[float | None]queued_at: float = 0.0rewards: numpy.ndarray | None = None )

매개변수

  • prompts (list[list[dict[str, Any]]]) — 각 rollout의 프롬프트.
  • reward_kwargs (dict[str, list[Any]]) — 프롬프트 데이터셋 행의 다른 열들을 리워드 함수에 키워드 인수로 전달합니다.
  • completions (list[list[dict[str, Any]]]) — 각 rollout의 Completion 메시지입니다.
  • completions_ids (list[list[int]]) — 각 rollout의 completion 토큰 ID입니다.
  • completions_sequences (list[list[TrainingSequence]]) — 각 rollout에서 생성된 학습 시퀀스입니다. 턴 사이에 재토큰화 된 히스토리가 변경된 rollout은 하나 이상의 시퀀스를 생성합니다.
  • tool_call_counts (list[int]) — 각 롤아웃의 도구 호출 횟수.
  • tool_failure_counts (list[int]) — 각 롤아웃에서 실패한 도구 호출의 수.
  • model_version (int) — 그룹의 첫 번째 rollout이 시작되었을 때의 정책 버전입니다.
  • group_id (int) — rollout 과정에서 0부터 세는 그룹의 식별자입니다.
  • row_index (int) — 학습 데이터셋에서 프롬프트의 행 인덱스.
  • env_rewards (list[tuple[type, float] or None]) — get_reward를 정의하는 환경이 있는 롤아웃의 경우, 해당 환경 클래스와 그 보상입니다. 그렇지 않으면 None입니다.
  • rollout_rewards (list[float or None]) — 각 Rollout의 .reward.
  • queued_at (float, 선택 사항, 기본값 0.0) — 그룹이 스코어링을 위해 대기열에 추가된 시점의 time.monotonic() 값.
  • rewards (np.ndarray, 선택 사항) — 모든 보상 소스에 걸쳐 합산된 각 rollout의 총 보상입니다. 어떤 소스도 점수를 매기지 않은 경우 NaN입니다. compute_advantages()가 호출되기 전에 설정됩니다.

하나의 프롬프트에 대한 num_generations개의 롤아웃을 함께 점수화한 결과입니다. 각 리스트에는 롤아웃당 하나의 항목이 있습니다.

Update on GitHub