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.17.1).
Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

GRPO Trainer

model badge

Обзор

TRL поддерживает GRPO Trainer для обучения языковых моделей, как описано в статье DeepSeekMath: Pushing the Limits of Mathematical Reasoning in Open Language Models авторов 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 на 120 млрд токенов, связанных с математикой, полученных из Common Crawl, а также на данных естественного языка и кода. DeepSeekMath 7B достиг впечатляющего результата 51,7% на соревновательном бенчмарке MATH без использования внешних библиотек и методов голосования, приближаясь к уровню производительности Gemini-Ultra и GPT-4. Метод self-consistency по 64 выборкам из DeepSeekMath 7B достигает 60,9% на MATH. Способность к математическому рассуждению в DeepSeekMath обусловлена двумя ключевыми факторами: во-первых, мы используем значительный потенциал общедоступных веб-данных с помощью тщательно спроектированного конвейера отбора данных. Во-вторых, мы вводим Group Relative Policy Optimization (GRPO), вариант Proximal Policy Optimization (PPO), который повышает способности к математическому рассуждению, одновременно оптимизируя использование памяти в PPO.

Метод постобучения был предложен Quentin Gallouédec.

Быстрый старт

В этом примере показано, как обучать модель с использованием метода GRPO. Мы обучаем модель Qwen2.5 0.5B Instruct на промптах из набора данных DeepMath-103K. Данные из набора можно посмотреть здесь:

Ниже приведён скрипт для обучения модели. accuracy_reward требует math-verify, который можно установить с помощью pip install trl[math_verify].

# 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

Примечание: Кривые вознаграждения выше были получены с использованием Qwen/Qwen2-0.5B-Instruct. Результаты с Qwen/Qwen2.5-0.5B-Instruct будут качественно схожи.

Более подробный обзор метода GRPO

GRPO — это алгоритм обучения в режиме онлайн, то есть он итеративно совершенствуется, используя данные, сгенерированные самим обучаемой моделью в процессе обучения. Интуиция, лежащая в основе целевой функции GRPO, состоит в том, чтобы максимизировать преимущество сгенерированных завершений, при этом обеспечивая близость модели к эталонной политике. Чтобы понять, как работает GRPO, его можно разбить на четыре основных шага: генерация завершений, вычисление преимущества, оценка расхождения Кульбака–Лейблера и вычисление функции потерь.

GRPO visual

Генерация завершений

На каждом шаге обучения мы выбираем батч промптов и генерируем набор G G дополнений для каждого промпта (обозначаются как oi o_i ).

Вычисление преимущества

Для каждой из G G последовательностей мы вычисляем вознаграждение с помощью модели или функции вознаграждения. Чтобы согласовать с сравнительной природой моделей вознаграждения — как правило, обученных на наборах данных со сравнениями выходов для одного и того же вопроса — преимущество рассчитывается так, чтобы отражать эти относительные сравнения. Оно нормализуется следующим образом: A^i,t=ri−mean(r)std(r)\hat{A}_{i,t} = \frac{r_i - \text{mean}(\mathbf{r})}{\text{std}(\mathbf{r})}

Этот подход и дал методу его название: Group Relative Policy Optimization (GRPO).

В статье Understanding R1-Zero-Like Training: A Critical Perspective показано, что масштабирование на std(r) \text{std}(\mathbf{r}) может привести к смещению по уровню сложности вопросов. Вы можете отключить это масштабирование, установив scale_rewards=False в GRPOConfig. Обратите внимание, что отключение масштабирования на std также отключает нормализацию дисперсии, поэтому величина обновлений напрямую зависит от исходного масштаба вознаграждения и состава батча.

Как показано в Части I: Хитрости или ловушки? Глубокий анализ RL для рассуждений LLM (Lite PPO), вычисление среднего на локальном (групповом) уровне и стандартного отклонения на глобальном (батчевом) уровне обеспечивает более устойчивое формирование вознаграждения. Вы можете использовать эту стратегию масштабирования, установив scale_rewards="batch" в GRPOConfig.

Оценка расхождения Кульбака–Лейблера

Расхождение KL оценивается с помощью аппроксиматора, предложенного Schulman et al. (2020). Аппроксиматор определяется следующим образом: DKL[πθ∥πref]=πref(oi,t∣q,oi,<t)πθ(oi,t∣q,oi,<t)−log⁡πref(oi,t∣q,oi,<t)πθ(oi,t∣q,oi,<t)−1,\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,

Вычисление функции потерь

Цель состоит в том, чтобы максимизировать преимущество, при этом обеспечивая близость модели к эталонной политике. Следовательно, функция потерь определяется следующим образом: LGRPO(θ)=−1∑i=1G∣oi∣∑i=1G∑t=1∣oi∣[πθ(oi,t∣q,oi,<t)[πθ(oi,t∣q,oi,<t)]no gradA^i,t−βDKL[πθ∥πref]], \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],

где первый член представляет собой масштабированное преимущество, а второй член штрафует за отклонения от эталонной политики через дивергенцию Кульбака-Лейблера.

Обратите внимание, что в отличие от исходной формулировки в DeepSeekMath: Pushing the Limits of Mathematical Reasoning in Open Language Models, мы не масштабируем на 1∣oi∣ \frac{1}{|o_i|} , поскольку в статье Understanding R1-Zero-Like Training: A Critical Perspective показано, что это вносит смещение по длине ответа. Подробнее в разделе типы потерь.

Обратите внимание, что по сравнению с исходной формулировкой в DeepSeekMath: Pushing the Limits of Mathematical Reasoning in Open Language Models, мы используем β=0.0 \beta = 0.0 по умолчанию, что означает, что член KL-расхождения не используется. Этот выбор обусловлен рядом недавних исследований (например, Open-Reasoner-Zero: An Open Source Approach to Scaling Up Reinforcement Learning on the Base Model) ), которые показали, что член KL-расхождения не является обязательным для обучения с GRPO. В результате стало общепринятой практикой исключать его (например, Understanding R1-Zero-Like Training: A Critical Perspective, DAPO: An Open-Source LLM Reinforcement Learning System at Scale). Если вы хотите включить член KL-расхождения, вы можете установить beta в GRPOConfig в ненулевое значение.

В исходной статье эта формулировка обобщена с учётом нескольких обновлений после каждой генерации (обозначается μ \mu , и может быть задано с помощью num_iterations в GRPOConfig) за счёт использования обрезанной целевой функции суррогата: LGRPO(θ)=−1∑i=1G∣oi∣∑i=1G∑t=1∣oi∣[min⁡(πθ(oi,t∣q,oi,<t)πθold(oi,t∣q,oi,<t)A^i,t, clip(πθ(oi,t∣q,oi,<t)πθold(oi,t∣q,oi,<t),1−ϵ,1+ϵ)A^i,t)−βDKL[πθ∥πref]], \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],

где clip(⋅,1−ϵ,1+ϵ)\text{clip}(\cdot, 1 - \epsilon, 1 + \epsilon) обеспечивает, чтобы обновления не отклонялись чрезмерно от эталонной политики, ограничивая отношение политик значениями от 1−ϵ 1 - \epsilon до 1+ϵ 1 + \epsilon . Если μ=1 \mu = 1 (по умолчанию в TRL), обрезанная суррогатная целевая функция упрощается до исходной целевой функции.

Типы потерь

В литературе предложено несколько формулировок целевой функции. Изначально целевая функция GRPO определялась следующим образом: LGRPO(θ)=−1G∑i=1G1∣oi∣∑t=1∣oi∣li,t, \mathcal{L}_{\text{GRPO}}(\theta) = - \frac{1}{G} \sum_{i=1}^G \frac{1}{|o_i|} \sum_{t=1}^{|o_i|} l_{i,t},

где li,t=πθ(oi,t∣q,oi,<t)[πθ(oi,t∣q,oi,<t)]no gradA^i,t−βDKL[πθ∥πref]. 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 подчеркиваются ограничения функции потерь на уровне образцов в алгоритме GRPO в сценариях с длинными цепочками рассуждений (long-CoT), где более длинные ответы получают недостаточное наказание, что приводит к ухудшению качества вывода. Предложенное решение — нормализация на уровне токенов, которая лучше справляется с длинными последовательностями, распределяя более сбалансированные награды между отдельными токенами независимо от длины ответа: LDAPO(θ)=−1∑i=1G∣oi∣∑i=1G∑t=1∣oi∣li,t, \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},

Чтобы использовать эту формулировку, установите loss_type="dapo" в GRPOConfig.

Кроме того, в статье Understanding R1-Zero-Like Training: A Critical Perspective было показано, что исходная формулировка GRPO вносит смещение в длину ответа. Авторы демонстрируют, что хотя формулировка DAPO снижает это смещение, она не устраняет его полностью. Чтобы полностью избавиться от этого смещения, они предлагают делить на константу вместо длины последовательности, что приводит к следующей формулировке: LDr. GRPO(θ)=−1LG∑i=1G∑t=1∣oi∣li,t, \mathcal{L}_{\text{Dr. GRPO}}(\theta) = - \frac{1}{LG} \sum_{i=1}^G \sum_{t=1}^{|o_i|} l_{i,t},

Рекомендуется устанавливать это значение равным максимальной длине завершения. Чтобы использовать эту формулировку, задайте loss_type="dr_grpo" в GRPOConfig.

В качестве альтернативы в статье SAPO команда Qwen предлагает заменить «жёдкий» механизм обрезки в GRPO на плавный механизм мягкого гейтинга с управлением температурой. Если GRPO обнуляет градиенты, когда политика слишком сильно отклоняется от эталонной, то SAPO использует мягкую область доверия, которая плавно снижает вес градиента. Это позволяет модели сохранять полезные сигналы обучения от токенов, близких к текущей политике, подавляя при этом шум от экстремальных отклонений.

Функция потерь определяется следующим образом: LSAPO(θ)=−1G∑i=1G1∣oi∣∑t=1∣oi∣fi,t(πθ(oi,t∣q,oi,<t)πθold(oi,t∣q,oi,<t))A^i,t \mathcal{L}_{\text{SAPO}}(\theta) = - \frac{1}{G} \sum_{i=1}^G \frac{1}{|o_i|} \sum_{t=1}^{|o_i|} f_{i,t} \left( \frac{\pi_\theta(o_{i,t} | q, o_{i,<t})}{\pi_{\theta_{old}}(o_{i,t} | q, o_{i,<t})} \right) \hat{A}_{i,t}

Функция мягкого гейтинга fi,t f_{i,t} определяется с помощью сигмоидной функции σ \sigma следующим образом: fi,t(x)=σ(τi,t(x−1))⋅4τi,t f_{i,t}(x) = \sigma \left( \tau_{i,t} (x - 1) \right) \cdot \frac{4}{\tau_{i,t}}

Температура τi,t \tau_{i,t} выбирается на основе знака преимущества A^i,t \hat{A}_{i,t} : τi,t={τpos,if A^i,t>0τneg,otherwise \tau_{i,t} = \begin{cases} \tau_{\text{pos}}, & \text{if } \hat{A}_{i,t} > 0 \\ \tau_{\text{neg}}, & \text{otherwise} \end{cases}

Они рекомендуют использовать асимметричные температуры, τneg>τpos \tau_{\text{neg}} > \tau_{\text{pos}} (значения по умолчанию: τpos=1.0,τneg=1.05 \tau_{\text{pos}}=1.0, \tau_{\text{neg}}=1.05 ). Это обеспечивает более строгое наказание модели за «плохие» действия для предотвращения нестабильности, при этом допуская более свободное поведение в отношении «хороших» действий.

Чтобы использовать эту формулировку, установите loss_type="sapo" в GRPOConfig.

Записываемые метрики

Во время обучения и оценки мы фиксируем следующие метрики:

  • num_tokens: общее количество обработанных на данный момент токенов, включая как промпты, так и завершения. При использовании инструментов учитываются только нетуловые токены.
  • step_time: среднее время (в секундах), затрачиваемое на один шаг обучения (включая генерацию).
  • completions/mean_length: средняя длина сгенерированных завершений. При использовании инструментов учитываются только токены, не относящиеся к инструментам.
  • completions/min_length: минимальная длина генерируемых завершений. При использовании инструментов учитываются только токены, не относящиеся к инструментам.
  • completions/max_length: максимальная длина генерируемых дополнений. При использовании инструментов учитываются только токены, не относящиеся к инструментам.
  • completions/mean_terminated_length: средняя длина сгенерированных завершений, которые заканчиваются токеном EOS. При использовании инструментов учитываются только нетуловые токены.
  • completions/min_terminated_length: минимальная длина сгенерированных завершений, которые заканчиваются токеном EOS. При использовании инструментов учитываются только токены, не относящиеся к инструментам.
  • completions/max_terminated_length: максимальная длина сгенерированных завершений, которые заканчиваются токеном EOS. При использовании инструментов учитываются только токены, не относящиеся к инструментам.
  • completions/clipped_ratio: Доля обрезанных (усечённых) завершений.
  • tools/call_frequency: среднее количество вызовов инструментов на одно завершение в батче генерации. Записывается в журнал только при наличии tools.
  • tools/failure_frequency: доля вызовов инструментов, завершившихся ошибкой (инструмент не найден, возникло исключение или тип вызова не поддерживается). Значение равно 0.0, если ни один инструмент не был вызван. Записывается в журнал только при наличии tools.
  • rewards/{reward_func_name}/mean: среднее значение вознаграждения от конкретной функции вознаграждения. Если среда владеет вознаграждением через get_reward, то {reward_func_name} — это имя класса среды.
  • rewards/{reward_func_name}/std: стандартное отклонение вознаграждения от конкретной функции вознаграждения.
  • reward: Общая средняя награда после суммирования наград по функциям (с весами reward_weights).
  • reward_std: стандартное отклонение суммарных наград по функциям (с учётом весов reward_weights), вычисленное для всей выборки.
  • frac_reward_zero_std: доля образцов в батче генерации, у которых стандартное отклонение награды равно нулю, что указывает на малое разнообразие для данного промпта (все ответы верные или неверные).
  • sampling/sampling_logp_difference/mean: средняя абсолютная разница между лог-вероятностями, возвращаемыми сэмплером (vLLM), и пересчитанными моделью обучения, по токенам завершения. Рост значения указывает на увеличение рассогласования между обучением и инференсом. Записывается в лог только при use_vllm=True и vllm_importance_sampling_correction=True.
  • sampling/sampling_logp_difference/max: максимальное такое абсолютное значение. Записывается в журнал только при use_vllm=True и vllm_importance_sampling_correction=True.
  • sampling/importance_sampling_ratio/min: минимальное отношение важности (importance sampling ratio), используемое для коррекции рассогласования между обучением и инференсом, после применения ограничения, выбранного параметром vllm_importance_sampling_mode (обрезается до [C_min, C_max] для режимов *_truncate, устанавливается в ноль для режимов *_mask). Вычисляется по токенам завершения (completion tokens) или по последовательностям для режимов sequence_*. Записывается в лог только при use_vllm=True и vllm_importance_sampling_correction=True.
  • sampling/importance_sampling_ratio/mean: среднее значение ограниченного отношения важности (importance sampling ratio). Записывается в журнал только при use_vllm=True и vllm_importance_sampling_correction=True.
  • sampling/importance_sampling_ratio/max: максимальное ограниченное отношение важности выборки. Записывается только при use_vllm=True и vllm_importance_sampling_correction=True.
  • policy_loss: значение потери градиента политики (до добавления бонуса за энтропию). Записывается в журнал, если entropy_coef не равно нулю или use_adaptive_entropy=True.
  • entropy: Средняя энтропия предсказаний токенов по всем сгенерированным завершениям. (Если mask_truncated_completions=True, токены замаскированных последовательностей исключаются.)
  • entropy_coef: Текущий коэффициент регуляризации энтропии. Записывается в журнал, если entropy_coef не равен нулю или use_adaptive_entropy=True. Обновляется один раз на каждый шаг оптимизатора, если use_adaptive_entropy=True.
  • aux_loss: вспомогательная функция потерь для балансировки нагрузки в модели Mixture-of-Experts, до её масштабирования коэффициентом router_aux_loss_coef и добавления к общей функции потерь. Записывается в журнал только в том случае, если модель является MoE и router_aux_loss_coef не равен нулю.
  • kl: средняя дивергенция Кульбака–Лейблера между моделью и эталонной моделью, рассчитанная по сгенерированным завершениям. Записывается в журнал только если beta не равно нулю.
  • clip_ratio/region_mean: Соотношение токенов (или последовательностей, если importance_sampling_level="sequence") вероятностей, для которых цель GRPO обрезается, чтобы оставаться в области доверия: clip(ri,t(θ),1−ϵlow,1+ϵhigh) ,ri,t(θ)=πθ(oi,t∣q,oi,<t)πθold(oi,t∣q,oi,<t) \text{clip}\left( r_{i,t}(\theta), 1 - \epsilon_\mathrm{low}, 1 + \epsilon_\mathrm{high} \right)\,, \quad r_{i,t}(\theta) = \frac{\pi_\theta(o_{i,t} \mid q, o_{i,< t})}{\pi_{\theta_{\text{old}}}(o_{i,t} \mid q, o_{i,< t})} . Более высокое значение означает, что обрезается больше токенов, что ограничивает степень изменения политики πθ\pi_\theta .
  • clip_ratio/low_mean: Среднее отношение вероятностей токенов (или последовательностей, если importance_sampling_level="sequence") было обрезано по нижней границе области доверия: ri,t(θ)<1−ϵlowr_{i,t}(\theta) < 1 - \epsilon_\mathrm{low}.
  • clip_ratio/low_min: Минимальная доля токенов на завершение (или самой последовательности, если importance_sampling_level="sequence") обрезается по нижней границе области доверия: ri,t(θ)<1−ϵlowr_{i,t}(\theta) < 1 - \epsilon_\mathrm{low}.
  • clip_ratio/high_mean: Среднее отношение вероятностей токенов (или последовательностей, если importance_sampling_level="sequence") было обрезано по верхней границе области доверия: ri,t(θ)>1+ϵhighr_{i,t}(\theta) > 1 + \epsilon_\mathrm{high}.
  • clip_ratio/high_max: Максимальная доля токенов на завершение (или последовательность целиком, если importance_sampling_level="sequence") обрезается по верхней границе области доверия: ri,t(θ)>1+ϵhighr_{i,t}(\theta) > 1 + \epsilon_\mathrm{high}.
  • cispo_clip_ratio: Доля токенов (или последовательностей, если importance_sampling_level="sequence") весов importance sampling, которые были обрезаны на уровне epsilon_high при положительном преимуществе: ri,t(θ)>ϵhighr_{i,t}(\theta) > \epsilon_\mathrm{high}. Записывается в журнал только при loss_type="cispo".
  • vespo/phi_seq_mean: Среднее значение весов VESPO Gamma φ(w)\varphi(w) применяется к весам важности на уровне последовательности. Значения ниже 1.0 означают, что последовательности получают меньший вес. Записывается в журнал только при loss_type="vespo".

Настройка

Ускорение обучения с генерацией на базе vLLM

Генерация часто является основным узким местом при обучении с использованием онлайн-методов. Для ускорения генерации можно использовать vLLM — высокопроизводительный движок инференса с низкой задержкой для LLM. Для его включения сначала установите пакет с

pip install trl[vllm]

Мы поддерживаем два способа использования vLLM во время обучения: режим сервера и режим colocation.

По умолчанию для генерации в vLLM включается выборка с маскированием важности на уровне последовательности (vllm_importance_sampling_mode="sequence_mask") для устранения рассогласования между генерацией и обучением, возникающего при использовании разных фреймворков. Это можно отключить, установив vllm_importance_sampling_correction=False. Подробнее см. Masked Importance Sampling и Sequence-level Importance Sampling

Вариант 1: Режим Colocate

В этом режиме vLLM работает внутри процесса тренера и разделяет память GPU с моделью обучения. Это позволяет избежать запуска отдельного сервера и может повысить использование GPU, но может привести к конкуренции за память на GPU, используемых для обучения. Это режим по умолчанию.

from trl import GRPOConfig

training_args = GRPOConfig(
    ...,
    use_vllm=True,  # vllm_mode="colocate" by default
)

Вариант 2: серверный режим

В этом режиме vLLM работает в отдельном процессе (и на отдельных GPU) и взаимодействует с тренером через HTTP. Это идеальный вариант, если у вас есть выделенные GPU для инференса.

  1. Запустите сервер vLLM:

    VLLM_SERVER_DEV_MODE=1 vllm serve <model_name> \
        --weight-transfer-config '{"backend": "nccl"}' \
        --logprobs-mode processed_logprobs \
        --max-logprobs -1
  2. Включите серверный режим в вашем скрипте обучения:

    from trl import GRPOConfig
    
    training_args = GRPOConfig(
        ...,
        use_vllm=True,
        vllm_mode="server",
    )

Убедитесь, что сервер использует другие GPU, чем тренажёр, иначе могут возникнуть ошибки NCCL. Вы можете указать используемые GPU с помощью переменной окружения CUDA_VISIBLE_DEVICES.

В зависимости от размера модели и общих требований к памяти GPU для обучения может потребоваться отрегулировать параметр vllm_gpu_memory_utilization в GRPOConfig, чтобы избежать недоиспользования ресурсов или ошибок нехватки памяти.

Мы предоставляем HF Space, который помогает оценить рекомендуемое использование памяти GPU на основе конфигурации вашей модели и настроек эксперимента. Просто используйте его следующим образом, чтобы получить рекомендацию по vllm_gpu_memory_utilization:

Если рекомендуемое значение не работает в вашей среде, мы рекомендуем добавить небольшой запас (например, +0.05 или +0.1) к рекомендуемому значению для обеспечения стабильности.

Если вы по-прежнему получаете ошибки нехватки памяти, установите vllm_enable_sleep_mode в True, и параметры vllm и кэш будут выгружены во время шага оптимизации. Подробнее см. в разделе Снижение потребления памяти с помощью режима сна vLLM.

По умолчанию GRPO использует MASTER_ADDR=localhost и MASTER_PORT=12345 для vLLM, но вы можете переопределить эти значения, установив соответствующие переменные окружения.

Для получения дополнительной информации см. Ускорение обучения с помощью vLLM.

Устранение рассогласования между обучением и инференсом

Хотя vLLM значительно ускоряет инференс, он также разделяет движок инференса и движок обучения. Теоретически эти движки математически идентичны, однако на практике они могут выдавать разные результаты из-за эффектов точности и аппаратно-специфичных оптимизаций. Это расхождение отражает различные цели оптимизации двух систем. Движки инференса стремятся максимизировать пропускную способность сэмплирования, обычно измеряемую в токенах в секунду, при сохранении приемлемой точности сэмплирования. Фреймворки обучения, напротив, фокусируются на численной стабильности и точности для вычисления градиентов, часто используя форматы с более высокой точностью, такие как FP32, для мастер-весов и состояний оптимизатора. Эти различающиеся приоритеты и ограничения вносят неизбежное, хотя и незначительное, несоответствие между обучением и инференсом.

Это несоответствие приводит к смещённым обновлениям градиента, что, как было замечено, дестабилизирует обучение ([1][2][3][4][5]). Для простоты рассмотрим градиент политики REINFORCE: ∇θJ(x,θ)=Ey∼πtrain(⋅∣x,θ)[∇θlog⁡πtrain(y∣x,θ)⋅R(x,y)] \nabla_\theta \mathcal{J}(x,\theta) = \mathbb{E}_{y \sim \pi^\text{train}(\cdot \mid x,\theta)} \left[ \nabla_\theta \log \pi^\text{train}(y \mid x,\theta) \cdot R(x,y) \right]

Здесь x x обозначает промпты, выбранные из некоторого распределения данных, а πtrain \pi^\text{train} — это политика, реализованная движком обучения. При использовании vLLM в цикле мы получаем отдельную политику инференса πinference \pi^\text{inference} , так что эффективный градиент политики становится ∇θJbiased(x,θ)=Ey∼πinference(⋅∣x,θ)[∇θlog⁡πtrain(y∣x,θ)⋅R(x,y)]. \nabla_\theta \mathcal{J}_{\text{biased}}(x,\theta) = \mathbb{E}_{y \sim \pi^\text{inference}(\cdot \mid x,\theta)} \left[ \nabla_\theta \log \pi^\text{train}(y \mid x,\theta) \cdot R(x,y) \right].

Это превращает задачу RL, которая иначе была бы on-policy, в off-policy.

Стандартный способ коррекции этого смещения распределения — importance sampling (IS). Мы предлагаем два варианта IS: Truncated Importance Sampling (TIS) и Masked Importance Sampling (MIS). Оба варианта можно применять как на уровне токенов, так и на уровне последовательностей. Пусть ρ \rho обозначает вес importance, например ρt \rho_t на токен или ρseq \rho_{\text{seq}} на уровне последовательности. В TIS значения вне диапазона [vllm_importance_sampling_clip_min, vllm_importance_sampling_clip_max] обрезаются: ρ←clip(ρ,Cmin⁡,Cmax⁡). \rho \leftarrow \text{clip}(\rho, C_{\min}, C_{\max}).

В исходной статье TIS был предложен механизм обрезки по верхней границе, а именно min⁡(ρ,Cmax⁡) \min(\rho, C_{\max}) . Реализация в TRL обобщила этот подход, введя также нижнюю границу, что привело к двусторонней формулировке, показанной выше, по мотивам метода IcePop .
Обратите внимание, что в IcePop границы обозначаются как α \alpha и β \beta тогда как в TRL мы используем Cmin⁡ C_{\min} и Cmax⁡ C_{\max} .

В режиме MIS отношения, выходящие за пределы этого диапазона, обнуляются, поэтому такие сэмплы не вносят вклад в градиент. Иными словами, выбросы понизятся по весу в режиме TIS и отбрасываются в режиме MIS. Флаг конфигурации vllm_importance_sampling_mode определяет как вариант IS (маскирование или усечение), так и гранулярность (на уровне токенов или последовательностей).

Импортанс-сэмплинг — это принципиальный алгоритмический ответ на рассогласование между обучением и инференсом. Однако существуют и более прямые подходы, направленные на сокращение рассогласования между самыми движками. Большинство из них представляют собой инженерные решения. Например, MiniMax M1 использует языковую модель с головой в формате FP32 в движке инференса. Thinking Machines исследовала детерминированные ядра инференса, хотя это сопряжено со значительными потерями в эффективности. vLLM продемонстрировала битово согласованные политики, опираясь на детерминированные ядра с инвариантностью по батчу от Thinking Machines, но по состоянию на ноябрь 2025 года сохраняется существенное снижение пропускной способности по сравнению со стандартным инференсом в vLLM.

Ускорение обучения с помощью непрерывного батчинга в transformers

В качестве альтернативы vLLM можно использовать встроенный в transformers движок непрерывного батчинга (continuous batching) для более быстрой генерации. Непрерывный батчинг сразу удаляет завершённые последовательности из батча, а не ждёт завершения самой медленной. Для задач с переменной длиной завершения (например, математическое рассуждение) это обеспечивает более быструю генерацию и меньшее потребление VRAM по сравнению с функцией generate() по умолчанию при больших размерах батча (N≥32).

Continuous batching — это решение, которое можно внедрить без настройки сервера или синхронизации весов. Оно работает в рамках процесса и хорошо подходит для обучения на одном GPU или в средах с ограниченной памятью. Для максимальной пропускной способности генерации в масштабе используйте vLLM.

from trl import GRPOConfig

training_args = GRPOConfig(
    ...,
    use_transformers_continuous_batching=True,
    transformers_continuous_batching_config={
        "use_cuda_graph": False,
        "max_memory_percent": 0.4,  # lower values leave more VRAM for the training backward pass
    },
)

TRL по умолчанию устанавливает max_memory_percent в 0.5 (вместо 0.9 в transformers), чтобы оставить достаточно VRAM для обратного прохода при обучении. Уменьшите это значение до 0.3–0.4 для больших батчей генерации (N≥32) или если вы видите ошибки нехватки памяти.

Полный пример обучения см. в examples/grpo_continuous_batching/grpo_continuous_batching.py.

GRPO в масштабе: обучение модели 70B+ на нескольких узлах

При обучении крупных моделей, таких как Qwen2.5-72B, для обеспечения эффективности и масштабируемости обучения на нескольких GPU и узлах необходимы несколько ключевых оптимизаций. К ним относятся:

  • DeepSpeed ZeRO Stage 3: ZeRO использует параллелизм данных для распределения состояний модели (весов, градиентов, состояний оптимизатора) между несколькими GPU и CPU, что снижает требования к памяти и вычислительным ресурсам на каждом устройстве. Поскольку большие модели не помещаются на одном GPU, для обучения таких моделей необходимо использовать ZeRO Stage 3. Подробнее см. в разделе DeepSpeed Integration.
  • Accelerate: Accelerate — это библиотека, упрощающая распределённое обучение на нескольких GPU и узлах. Она предоставляет простой API для запуска распределённого обучения и берет на себя сложность распределённых вычислений, такую как параллелизм данных, накопление градиентов и распределённая загрузка данных. Подробнее см. Распределение обучения.
  • vLLM: см. предыдущий раздел о том, как использовать vLLM для ускорения генерации.

Ниже приведён пример SLURM-скрипта для обучения модели 70B с GRPO на нескольких узлах. Этот скрипт обучает модель на 4 узлах и использует 5-й узел для генерации на базе vLLM.

#!/bin/bash
#SBATCH --nodes=5
#SBATCH --gres=gpu:8

# Get the list of allocated nodes
NODELIST=($(scontrol show hostnames $SLURM_JOB_NODELIST))

# Assign the first 4 nodes for training and the 5th node for vLLM
TRAIN_NODES="${NODELIST[@]:0:4}"  # Nodes 0, 1, 2, 3 for training
VLLM_NODE="${NODELIST[4]}"  # Node 4 for vLLM

# Run training on the first 4 nodes (Group 1)
srun --nodes=4 --ntasks=4 --nodelist="${NODELIST[@]:0:4}" accelerate launch \
     --config_file examples/accelerate_configs/deepspeed_zero3.yaml \
     --num_processes 32 \
     --num_machines 4 \
     --main_process_ip ${NODELIST[0]} \
     --machine_rank $SLURM_PROCID \
     --rdzv_backend c10d \
     train_grpo.py \
     --server_ip $VLLM_NODE &

# Run vLLM server on the 5th node (Group 2)
srun --nodes=1 --ntasks=1 --nodelist="${NODELIST[4]}" env VLLM_SERVER_DEV_MODE=1 vllm serve Qwen/Qwen2.5-72B --tensor-parallel-size 8 \
    --weight-transfer-config '{"backend": "nccl"}' \
    --logprobs-mode processed_logprobs \
    --max-logprobs -1 &

wait
import argparse

from datasets import load_dataset
from trl import GRPOTrainer, GRPOConfig
from trl.rewards import accuracy_reward

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--vllm_server_host", type=str, default="", help="The server IP")
    args = parser.parse_args()

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

    training_args = GRPOConfig(
        per_device_train_batch_size=4,
        use_vllm=True,
        vllm_mode="server",
        vllm_server_host=args.vllm_server_host.replace("ip-", "").replace("-", "."),  # from ip-X-X-X-X to X.X.X.X
    )

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

if __name__=="__main__":
    main()

Использование пользовательской функции вознаграждения

Объект GRPOTrainer поддерживает использование пользовательских функций вознаграждения вместо плотных моделей вознаграждения. Для обеспечения совместимости ваша функция вознаграждения должна соответствовать следующим требованиям:

Функции вознаграждения могут быть как синхронными вызываемыми объектами Python, так и асинхронными корутинами async def. Если вы указываете несколько асинхронных функций вознаграждения, они ожидаются одновременно (выполняются параллельно через asyncio.gather), что позволяет перекрыть их задержки.

  1. Аргументы ввода:

    • Функция должна принимать следующие аргументы по имени:

      • prompts (содержит промпты),
      • completions (содержит сгенерированные завершения),
      • completion_ids (содержит токенизированные завершения),
      • trainer_state (TrainerState): текущее состояние тренера. Это можно использовать для реализации динамических функций вознаграждения, например, для обучения по программе (curriculum learning), где вознаграждение корректируется в зависимости от прогресса обучения.
      • log_extra: вызываемый объект log_extra(column: str, values: list) для добавления дополнительных столбцов в таблицу с результатами. См. Пример 6.
      • log_metric: вызываемый объект log_metric(name: str, value: float) для записи скалярных метрик в виде графиков наряду с kl, entropy и т. д. См. Пример 6.
      • environments: список экземпляров сред, по одному на каждое завершение. Присутствует только при указании environment_factory. Используйте этот параметр для чтения состояния, накопленного в ходе эпизода (например, env.counter). Для сред с состоянием предпочтительнее передавать управление наградой самой среде через метод get_reward — см. Награды.
      • Все имена столбцов (кроме prompt), которые могут присутствовать в наборе данных. Например, если набор данных содержит столбец с именем ground_truth, функция будет вызвана с ground_truth в качестве именованного аргумента.

      Самый простой способ выполнить это требование — использовать **kwargs в сигнатуре функции.

    • В зависимости от формата набора данных входные данные будут различаться:

  2. Возвращаемое значение: функция должна возвращать список чисел с плавающей точкой. Каждое число представляет награду, соответствующую одному завершению.

Пример 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 = ["The sky is", "The sun is"]  # not used in the reward function, but the trainer will pass it
>>> completions = [" blue.", " 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]

Пример 1.1: Поощрение более длинных завершений (на основе количества символов)

Аналогично предыдущему примеру, но на этот раз функция вознаграждения основана на количестве символов, а не токенов.

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

Вы можете протестировать это следующим образом:

>>> prompts = ["The sky is", "The sun is"]
>>> completions = [" blue.", " in the sky."]
>>> completion_ids = [[6303, 13], [304, 279, 12884, 13]]  # not used in the reward function, but the trainer will pass it
>>> reward_func(prompts=prompts, completions=completions, completion_ids=completion_ids)
[6.0, 12.0]

Пример 2: Награждайте завершения с определенным форматом

Ниже приведен пример функции вознаграждения, которая проверяет, соответствует ли ответ определенному формату. Этот пример вдохновлен функцией format reward, используемой в статье DeepSeek-R1: Incentivizing Reasoning Capability in LLMs via Reinforcement Learning. Она предназначена для диалогового формата, в котором промпты и ответы состоят из структурированных сообщений.

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: Награды за завершения на основе эталонного

Ниже приведен пример функции вознаграждения, которая проверяет правильность завершения. Этот пример вдохновлен функцией accuracy reward, используемой в статье DeepSeek-R1: Incentivizing Reasoning Capability in LLMs via Reinforcement Learning. Этот пример предназначен для стандартного формата, в котором набор данных содержит столбец с именем ground_truth.

import re

def reward_func(completions, ground_truth, **kwargs):
    # Regular expression to capture content inside \boxed{}
    matches = [re.search(r"\\boxed\{(.*?)\}", completion) 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 = ["Problem: Solve the equation $2x + 3 = 7$. Solution:", "Problem: Solve the equation $3x - 5 = 10$."]
>>> completions = [r" The solution is \boxed{2}.", 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: Многозадачные функции вознаграждения

Ниже приведен пример использования нескольких функций вознаграждения в GRPOTrainer. В этом примере мы определяем две функции вознаграждения, специфичные для задач: math_reward_func и coding_reward_func. Функция math_reward_func оценивает математические задачи на основе их правильности, а coding_reward_func — задачи по программированию на основе того, работает ли решение.

from datasets import Dataset
from trl import GRPOTrainer

# Define a dataset that contains both math and coding problems
dataset = Dataset.from_list(
    [
        {"prompt": "What is 2+2?", "task": "math"},
        {"prompt": "Write a function that returns the sum of two numbers.", "task": "code"},
        {"prompt": "What is 3*4?", "task": "math"},
        {"prompt": "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
trainer = GRPOTrainer(
    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, и GRPOTrainer продолжит работу с валидными функциями и задачами. Это позволяет GRPOTrainer обрабатывать несколько функций вознаграждения с разной областью применения.

Обратите внимание, что GRPOTrainer игнорирует вознаграждения None, возвращаемые функциями вознаграждения, и учитывает только вознаграждения, возвращаемые соответствующими функциями. Это гарантирует, что модель обучается на релевантных задачах и игнорирует те, для которых нет соответствующей функции вознаграждения.

Пример 5: Асинхронные функции вознаграждения

Пользовательские функции вознаграждения также можно определять как корутины async def. Это полезно, если ваше вознаграждение зависит от медленного ввода-вывода (например, вызова удалённого сервиса). При передаче нескольких асинхронных функций вознаграждения GRPOTrainer выполняет их параллельно, чтобы их задержки перекрывались.

Ниже приведен минимальный пример асинхронной функции вознаграждения, имитирующей операцию, ограниченную вводом-выводом:

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]

Пример 6: Логирование дополнительных столбцов и метрик

Ниже приведен пример функции вознаграждения, которая записывает дополнительные столбцы в таблицу завершений и скалярные метрики в виде графиков.

import re

def reward_func(completions, ground_truth, log_extra=None, log_metric=None, **kwargs):
    extracted = [re.search(r"\\boxed\{(.*?)\}", c) for c in completions]
    extracted = [m.group(1) if m else None for m in extracted]
    rewards = [1.0 if e == gt else 0.0 for e, gt in zip(extracted, ground_truth)]

    if log_extra:
        log_extra("golden_answer", list(ground_truth))
        log_extra("extracted_answer", [e or "[none]" for e in extracted])

    if log_metric:
        log_metric("accuracy", sum(rewards) / len(rewards))

    return rewards

Передача функции вознаграждения в тренер

Чтобы использовать собственную функцию вознаграждения, передайте её в GRPOTrainer следующим образом:

from trl import GRPOTrainer

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

Можно передать несколько функций вознаграждения в виде списка; этот список может включать как синхронные, так и асинхронные функции:

from trl import GRPOTrainer

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

а награда будет вычисляться как сумма наград от каждой функции или как взвешенная сумма, если в конфигурации указано reward_weights.

Обратите внимание, что GRPOTrainer поддерживает несколько функций вознаграждения разных типов. Подробности см. в документации по параметрам.

Регуляризация энтропии

Чтобы стимулировать исследование и предотвратить схлопывание политики к почти детерминированным выводам, можно добавить бонус за энтропию в целевую функцию обучения. Регуляризация энтропии дополняет потерю GRPO следующим образом: L(θ)=LGRPO(θ)−α⋅H(πθ), \mathcal{L}(\theta) = \mathcal{L}_{\text{GRPO}}(\theta) - \alpha \cdot \mathcal{H}(\pi_\theta),

гдеH(πθ)\mathcal{H}(\pi_\theta) — средняя энтропия на токен для текущей политики, аα\alpha — коэффициент энтропии. Бонус всегда равен средней энтропии на токен, независимо от loss_type; он не масштабируется под нормализацию политики, соответствующую типу потерь (например, знаменатель batch_size * max_completion_length в Dr. GRPO), поэтому entropy_coef имеет одинаковый смысл для всех типов потерь.

Статическая энтропия — фиксированный коэффициент на протяжении всего обучения:

from trl import GRPOConfig, GRPOTrainer

training_args = GRPOConfig(entropy_coef=0.05, ...)

Адаптивная энтропия — коэффициент обновляется на каждом шаге оптимизатора на основе целевой энтропии, как предложено в Skywork-OR1. Если текущая энтропия равна entropy_target или меньше, коэффициент увеличивается на entropy_coef_delta; в противном случае он уменьшается. Коэффициент применяется (т. е. не равен нулю) только тогда, когда энтропия равна целевому значению или меньше:

training_args = GRPOConfig(
    entropy_coef=0.01,          # initial coefficient
    use_adaptive_entropy=True,
    entropy_target=5.0,         # target mean per-token entropy (nats); tune for your model
    entropy_coef_delta=0.005,   # step size per optimizer step
    entropy_coef_min=0.0,
    entropy_coef_max=1.0,
    ...
)

Типичные языковые модели имеют энтропию на токен в диапазоне 2–10 натов, поэтому значение по умолчанию entropy_target=0.2 почти никогда не активирует регуляризацию — бонус срабатывает только тогда, когда энтропия равна целевому значению или ниже, то есть при практически полном коллапсе. Установите значение, имеющее смысл для вашей модели, например, близкое к энтропии, наблюдаемой на ранних этапах обучения (логгируется как метрика entropy). При использовании top_entropy_quantile < 1.0 параметр entropy_target применяется к подмножеству токенов с высокой энтропией — энтропия этого подмножества будет выше, чем логгируемая энтропия по всем токенам (entropy), поэтому калибруйте значение соответственно.

При use_adaptive_entropy=True текущий коэффициент энтропии entropy_coef сохраняется вместе с каждой контрольной точкой и восстанавливается при возобновлении, что делает обучение полностью возобновляемым.

Быстрая экспериментальная работа с GRPO

RapidFire AI — это экспериментальный движок с открытым исходным кодом, работающий поверх TRL и позволяющий запускать несколько конфигураций GRPO одновременно, даже на одном GPU. Вместо последовательного перебора конфигураций RapidFire позволяет ранее увидеть все их кривые обучения, остановить низкоэффективные запуски и клонировать перспективные с новыми настройками на лету без перезапуска. Подробнее см. RapidFire AI Integration.

Обучение агента

GRPO поддерживает обучение агентов: модель вызывает инструменты в процессе генерации и учится на полученных результатах.

  • Инструмент — это обычная функция Python (синхронная или асинхронная), доступная модели. Используйте tools для вызовов без состояния (калькулятор, веб-поиск).
  • Environment — более общая форма: объектом с состоянием, создаваемым заново для каждого rollout, публичные методы которого доступны как инструменты, плюс хук жизненного цикла reset и необязательный get_reward, позволяющий среде самостоятельно определять награду. Используйте environment_factory, если вам нужно состояние для каждого rollout, хук сброса или награда, управляемая средой.

Они комбинируются — вы можете передать автономные tools вместе с environment_factory.

Инструменты

Аргумент tools принимает список функций Python (синхронных или асинхронных), которые определяют инструменты, доступные агенту:

from trl import GRPOTrainer

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

Каждый инструмент должен быть стандартной функцией Python с аргументами и типом возвращаемого значения, указанными через type hints, а также документирующей строкой в стиле Google, описывающей его назначение, аргументы и возвращаемое значение. Подробнее см. в руководстве по передаче инструментов.

Цикл вызова инструментов GRPO требует, чтобы шаблон чата был сохраняющим префикс (добавление сообщения инструмента не должно изменять отображение предыдущих сообщений). Для известных семейств моделей (например, Qwen3, DeepSeek-V3) TRL автоматически подставляет исправленный шаблон обучения, когда инструменты включены. Полный список см. в разделе Chat Templates.

Используйте max_tool_calling_iterations в GRPOConfig, чтобы ограничить количество ходов вызова инструментов. По умолчанию ограничение отсутствует, и генерация останавливается, когда модель выдаёт ответный ход без вызовов инструментов.

Пример:

from trl import GRPOTrainer

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 = GRPOTrainer(
    tools=[multiply, async_add],
    ...,
)

Окружения

Вы также можете предоставить инструменты через environment_factory. В этом режиме GRPOTrainer создаёт один экземпляр среды на каждый rollout и предоставляет публичные методы среды в качестве инструментов.

environment_factory требует transformers>=5.2.0.

При использовании environment_factory среда владеет данными: внешнего train_dataset нет. На каждом rollout reset() формирует задачу — самообразец из корпуса, которым владеет среда, или процедурная генерация состояния — и возвращает промпт. max_steps задаёт длительность обучения. Ниже приведён минимальный пример среды, которая самообразует целевое значение и предоставляет метод increment (представленный как инструмент).

import random

from trl import GRPOConfig, GRPOTrainer

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

trainer = GRPOTrainer(
    model="Qwen/Qwen3-0.6B",
    args=GRPOConfig(max_steps=1000, chat_template_kwargs={"enable_thinking": False}),
    environment_factory=IncrementEnv,
)
trainer.train()

Класс окружения имеет два зарезервированных метода: reset и get_reward. В отличие от любых других публичных методов, они не предоставляются модели в качестве инструментов.

  • reset (обязательный) вызывается при начале rollout. Он может возвращать либо None, либо строку. В GRPO, если возвращается строка, она является пользовательским запросом.
  • get_reward (необязательный, синхронный или асинхронный) не принимает аргументов и возвращает float: среда оценивает только что завершённый эпизод на основе своего внутреннего состояния (завершилась ли игра победой? было ли угадано слово?). Вызывается один раз за каждый завершённый rollout и служит источником вознаграждения.

Поскольку среда выполняет самоотборку при каждом вызове reset(), G членов группы GRPO могут не разделять одно и то же начальное состояние, что делает базовую линию группы немного более шумной. Для идентичных состояний внутри группы убедитесь, что reset() детерминированно выводит состояние из общего ключа.

Предоставление внешнего набора данных (необязательно)

Вместо того чтобы позволять среде самостоятельно генерировать примеры, вы можете передать внешний train_dataset. Например, если ваши задачи уже хранятся в датасете, или для маршрутизации между несколькими средами. Для каждого rollout тренер выбирает одну строку, использует её столбец "prompt" как промпт и передаёт остальные столбцы этой строки в reset() в виде именованных аргументов (таким образом, среда считывает задачу из датасета).

from datasets import Dataset
from trl import GRPOTrainer

# 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

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

Награды

Награды, управляемые средой, и награды, управляемые тренером, не являются взаимоисключающими. Передавайте reward_funcs для наград, которые естественно вычисляются по завершению (например, проверка формата текста) и позволяйте среде возвращать свою зависящую от состояния награду через get_reward. Все источники суммируются; reward_weights применяется только к reward_funcs (среда сама управляет своим масштабом).

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

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

Функция reward_func также может напрямую читать состояние среды: если задан environment_factory, тренер передаёт аргумент environments (по одному экземпляру на каждое завершение). Это бывает полезно, но для наград, зависящих от состояния, предпочтительнее использовать get_reward.

Это работает идентично для AsyncGRPOTrainer.

Несколько сред

Чтобы обучать модель на смеси задач в одном прогоне (например, на задаче программирования и игре), передайте словарь, сопоставляющий имена сред с фабриками, вместо единой вызываемой функции. Каждый rollout выбирает свою среду через поле environment в наборе данных, и доступны только инструменты этой среды. Это предотвращает утечку нерелевантных инструментов (инструмент move из игры в пример с кодом и наоборот). Каждая среда по-прежнему владеет своими данными и возвращает промпт из reset(), поэтому в наборе данных достаточно столбца environment для маршрутизации между средами.

import random

from datasets import Dataset
from trl import GRPOConfig, GRPOTrainer


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
dataset = Dataset.from_dict({"environment": ["coding", "game"] * 500})

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

Функция вознаграждения по-прежнему получает окружение каждого примера через reward_kwargs["environments"], поэтому она может ветвиться в зависимости от типа окружения (например, isinstance(env, CodingEnv)). Экземпляры окружений переиспользуются между шагами (сбрасываются между эпизодами), поэтому дорогостоящий __init__ выполняется один раз, а не на каждом шаге. Поле environment используется тренером и не передаётся в reset.

Ответы мультимодальных инструментов

Инструменты могут возвращать изображения вместе с текстом, возвращая список блоков контента. Это полезно для обучения агентов VLM, где инструмент предоставляет визуальную обратную связь (например, скриншоты, графики, снимки с камеры).

from PIL import Image

def take_screenshot() -> list:
    """
    Takes a screenshot of the current screen.

    Returns:
        The screenshot image with a description.
    """
    img = Image.open("screenshot.png")
    return [{"type": "image", "image": img}, {"type": "text", "text": "Here is the screenshot."}]

Возвращаемые изображения автоматически добавляются в диалог и передаются в VLM для последующих шагов генерации.

Поддерживаемые модели

Проверено с:

  • Beam — например, reflection/Beam-1.0-501B-A23B
  • DeepSeek-R1 — например, deepseek-ai/DeepSeek-R1
  • Gemma4 — например, google/gemma-4-E2B-it
  • GLM-4-MoE (4.5, 4.6 или 4.7) — например, zai-org/GLM-4.7
  • GPT-OSS — например, openai/gpt-oss-20b
  • Llama 3.1 — например, meta-llama/Llama-3.1-8B-Instruct
  • Llama 3.2 — например, meta-llama/Llama-3.2-3B-Instruct
  • Qwen2.5 — например, Qwen/Qwen2.5-0.5B-Instruct
  • Qwen3 — например, Qwen/Qwen3-0.6B
  • Qwen3-VL — например, Qwen/Qwen3-VL-2B-Instruct
  • Qwen3.5 — например, Qwen/Qwen3.5-2B
  • Qwen3.6 — например, Qwen/Qwen3.6-35B-A3B

Совместимость со всеми LLM не гарантируется. Если вы считаете, что модель должна поддерживаться, не стесняйтесь открыть issue на GitHub — или, что ещё лучше, отправить pull request с необходимыми изменениями.

Интеграции с окружениями

Все среды подключаются к одному и тому же слоту environment_factory, поэтому на уровне TRL они взаимозаменяемы — выберите ту, чья экосистема лучше подходит для вашей задачи:

ИнтеграцияЧто этоИспользуйте, когда
OpenEnvОткрытый стандарт среды (API в стиле Gymnasium, работающий через WebSocket или в контейнеризованном выполнении), поддерживаемый Hugging Face и сообществом.Вы используете готовую среду OpenEnv из Hub или определяете собственную в соответствии с открытым стандартом (например, Wordle, Sudoku, Catch).
OpenRewardИнтеграция с ORS-совместимыми средами (каталог openreward.ai или собственный ORS-сервер); задачи и вознаграждения предоставляются по HTTP.Вы хотите обучать модель в среде ORS: каталог (например, Eigent/SETA), собственный хостинг на вашей инфраструктуре или локальный сервер, над которым вы работаете.
HarborИнтеграция с наборами задач Harbor: каждая задача представляет собой инструкцию, реальный образ песочницы (docker, e2b, …) и верификатор внутри песочницы.Вы хотите обучать модель на наборе задач Harbor: это дерево задач, каждая из которых представляет собой автономный песочный контейнер и верификатор (например, агент по анализу данных, который исследует файлы в песочнице и записывает ответ, который проверяет оценщик).

Обучение моделей «зрение-язык»

GRPO поддерживает обучение моделей Vision-Language (VLM) на мультимодальных наборах данных, содержащих как текст, так и изображения.

Поддерживаемые модели

Проверено с:

  • Gemma3 — например, google/gemma-3-4b-it
  • LLaVA-NeXT — например, llava-hf/llava-v1.6-mistral-7b-hf
  • Qwen2-VL — например, Qwen/Qwen2-VL-2B-Instruct
  • Qwen2.5-VL — например, Qwen/Qwen2.5-VL-3B-Instruct
  • SmolVLM2 — например, HuggingFaceTB/SmolVLM2-2.2B-Instruct

Совместимость со всеми VLM не гарантируется. Если вы считаете, что модель должна поддерживаться, не стесняйтесь открыть issue на GitHub — или, что ещё лучше, отправить pull request с необходимыми изменениями.

Быстрый старт

Используйте grpo_vlm.py для дообучения VLM. Пример команды для обучения на lmms-lab/multimodal-open-r1-8k-verified:

accelerate launch \
  --config_file=examples/accelerate_configs/deepspeed_zero3.yaml \
  examples/grpo_visual_math/grpo_visual_math.py \
  --model_name_or_path Qwen/Qwen2.5-VL-3B-Instruct \
  --output_dir grpo-Qwen2.5-VL-3B-Instruct \
  --learning_rate 1e-5 \
  --dtype bfloat16 \
  --max_completion_length 1024 \
  --use_vllm \
  --vllm_mode colocate \
  --use_peft \
  --lora_target_modules "q_proj", "v_proj" \
  --log_completions

Советы по конфигурации

  • Использование LoRA на проекционных слоях зрительно-языковой модели
  • Включите 4-битное квантование для снижения потребления памяти
  • VLMs требуют много памяти — начните с меньших размеров батчей
  • Большинство моделей совместимы с vLLM (режимы server и colocate)

Формат набора данных

Каждая обучающая выборка должна включать:

  • prompt: Текст, отформатированный через шаблон чата процессора
  • image/images: изображение PIL или список изображений PIL

Тренер автоматически обрабатывает преобразование изображений в тензоры с помощью процессора изображений модели.

GRPOTrainer

класс trl.GRPOTrainer

< >

( model: str | PreTrainedModel | PeftModelreward_funcs: str | transformers.modeling_utils.PreTrainedModel | collections.abc.Callable[..., list[float | None]] | list[str | transformers.modeling_utils.PreTrainedModel | collections.abc.Callable[..., list[float | None]]] | None = Noneargs: trl.trainer.grpo_config.GRPOConfig | None = Nonetrain_dataset: datasets.arrow_dataset.Dataset | datasets.iterable_dataset.IterableDataset | None = Noneeval_dataset: datasets.arrow_dataset.Dataset | datasets.iterable_dataset.IterableDataset | datasets.dataset_dict.DatasetDict | datasets.dataset_dict.IterableDatasetDict | dict[str, datasets.arrow_dataset.Dataset | datasets.iterable_dataset.IterableDataset] | None = Noneprocessing_class: transformers.tokenization_utils_base.PreTrainedTokenizerBase | transformers.processing_utils.ProcessorMixin | None = Nonereward_processing_classes: transformers.tokenization_utils_base.PreTrainedTokenizerBase | list[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)quantization_config: BitsAndBytesConfig | None = Nonepeft_config: PeftConfig | None = Nonetools: list[collections.abc.Callable] | None = Nonerollout_func: collections.abc.Callable[[list[str], 'GRPOTrainer'], dict[str, typing.Any]] | None = Noneenvironment_factory: collections.abc.Callable[[], trl.trainer.grpo_trainer._SupportsReset] | dict[str, collections.abc.Callable[[], trl.trainer.grpo_trainer._SupportsReset]] | None = None )

Параметры

  • model (str или PreTrainedModel или PeftModel) — Модель, подлежащая обучению. Может быть одним из следующих:
    • Строка, являющаяся model id предобученной модели, размещённой в репозитории моделей на huggingface.co, или путь к каталогу, содержащему веса модели, сохранённые с помощью save_pretrained, например './my_model_directory/'. Модель загружается с помощью <ModelArchitecture>.from_pretrained (где <ModelArchitecture> определяется из конфигурации модели) с использованием именованных аргументов из args.model_init_kwargs. Если dtype не указан в args.model_init_kwargs, по умолчанию используется float32. Это отличается от from_pretrained, где (начиная с Transformers v5) тип данных выводится из конфигурации модели.
    • Объект PreTrainedModel. Поддерживаются только каузальные языковые модели.
    • Объект PeftModel. Поддерживаются только каузальные языковые модели.
  • reward_funcs (RewardFunc | list[RewardFunc], необязательный) — Функции вознаграждения, используемые для вычисления наград. Для вычисления наград мы вызываем все функции вознаграждения с промптами и завершениями и суммируем награды. Может быть опущено, если вознаграждение предоставляется средой через environment_factory (см. ниже). Может быть одним из следующих:
    • Одна функция вознаграждения, например:

      • A string: The model ID of a pretrained model hosted inside a model repo on huggingface.co, or a path to a directory containing model weights saved using save_pretrained, e.g., './my_model_directory/'. The model is loaded using from_pretrained with num_labels=1 and the keyword arguments in args.model_init_kwargs.

      • Объект PreTrainedModel: поддерживаются только модели классификации последовательностей.

      • Пользовательская функция вознаграждения: функция получает промпты и сгенерированные завершения, а также любые дополнительные столбцы в наборе данных. Она должна возвращать список вознаграждений. Пользовательские функции вознаграждения могут быть как синхронными, так и асинхронными, а также возвращать None, если вознаграждение неприменимо к данным образцам. Это полезно для обучения на нескольких задачах, где разные функции вознаграждения применяются к разным типам образцов. Если функция вознаграждения возвращает None для образца, эта функция вознаграждения исключается из расчёта вознаграждения для данного образца. Дополнительные сведения см. в разделе Использование пользовательской функции вознаграждения.

        Состояние тренера также передается в функцию вознаграждения. Состояние тренера представляет собой экземпляр TrainerState и может быть получено через аргумент trainer_state в сигнатуре функции вознаграждения.

    • Список функций вознаграждения, где каждый элемент может независимо быть любым из перечисленных выше типов. Смешивание разных типов внутри списка (например, строкового идентификатора модели и пользовательской функции вознаграждения) допускается.

  • args (GRPOConfig, необязательный) — Конфигурация для этого тренера. Если None, используется конфигурация по умолчанию.
  • train_dataset (Dataset или IterableDataset, необязательный) — Набор данных для обучения. Он должен содержать столбец "prompt". Любые дополнительные столбцы в наборе данных игнорируются. Формат образцов может быть следующим:
    • Standard: каждая выборка содержит обычный текст.
    • Диалоговый: каждая выборка содержит структурированные сообщения (например, роль и содержимое).

    Можно опустить только в том случае, если предоставлен environment_factory и среда владеет данными (или генерирует их процедурно), возвращая промпт из метода reset(). В этом случае необходимо задать max_steps, чтобы определить длительность обучения.

    Если train_dataset является IterableDataset (например, потоковым набором данных), то max_steps необходимо задать в аргументах обучения, поскольку его длину невозможно определить, а общее количество шагов обучения требуется для ограничения цикла обучения и настройки планировщика скорости обучения.

  • eval_dataset (Dataset, IterableDataset, DatasetDict, IterableDatasetDict или dict[str, Dataset | IterableDataset]) — Набор данных для оценки. Он должен соответствовать тем же требованиям, что и train_dataset.
  • processing_class (PreTrainedTokenizerBase, ProcessorMixin, optional) — Processing class used to process the data. The padding side must be set to “left”. If None, the processing class is loaded from the model’s name with from_pretrained. A padding token, tokenizer.pad_token, must be set. If the processing class has not set a padding token, tokenizer.eos_token will be used as the default.
  • reward_processing_classes (PreTrainedTokenizerBase или list[PreTrainedTokenizerBase], необязательный) — Классы обработки, соответствующие функциям вознаграждения, указанным в reward_funcs. Может быть:
    • Один класс обработки: используется, когда reward_funcs содержит только одну функцию вознаграждения.
    • Список классов обработки: должен соответствовать порядку и длине функций вознаграждения в reward_funcs. Если установлено значение None, или если элемент списка, соответствующий PreTrainedModel, равен None, то токенизатор для модели загружается автоматически с помощью from_pretrained. Для элементов в reward_funcs, которые являются пользовательскими функциями вознаграждения (не PreTrainedModel), соответствующие записи в reward_processing_classes игнорируются.
  • callbacks (список TrainerCallback, необязательный) — Список callback'ов для настройки цикла обучения. Они будут добавлены к списку callback'ов по умолчанию, описанных здесь.

    Если вы хотите удалить один из используемых по умолчанию колбэков, воспользуйтесь методом remove_callback.

  • optimizers (tuple[torch.optim.Optimizer | None, torch.optim.lr_scheduler.LambdaLR | None], необязательный, по умолчанию (None, None)) — Кортеж, содержащий оптимизатор и планировщик, которые будут использоваться. По умолчанию будет создан экземпляр AdamW для вашей модели и планировщик, заданный функцией get_linear_schedule_with_warmup и управляемый параметрами args.
  • quantization_config (BitsAndBytesConfig, optional) — Конфигурация квантования, используемая при загрузке модели по идентификатору модели. Используйте в сочетании с peft_config для обучения QLoRA. Игнорируется, если модель уже инициализирована.
  • peft_config (PeftConfig, необязательный) — Конфигурация PEFT, используемая для обёртки модели. Если None, модель не оборачивается.
  • tools (список Callable, необязательный) — Список вызываемых функций-инструментов (синхронных или асинхронных), которые модель может вызывать во время генерации. Каждый инструмент должен быть стандартной функцией Python с корректно типизированными аргументами и значениями возвращаемых значений, а также документирующей строкой в стиле Google, описывающей его назначение, аргументы и возвращаемое значение. Дополнительные сведения см. по адресу: https://huggingface.co/docs/transformers/en/chat_extras#passing-tools. Модель использует имя функции, типизацию аргументов и документирующую строку, чтобы определить, как её вызвать. Убедитесь, что шаблон чата модели поддерживает использование инструментов и что модель была дообучена для вызова инструментов.
  • rollout_func (RolloutFunc, необязательный) — Функция, используемая для генерации завершений. Она принимает список промптов, выделенных текущему процессу, и экземпляр тренера. Она должна возвращать словарь с полями "prompt_ids", "completion_ids" и "logprobs", а также может необязательно возвращать "logprob_token_ids" (с той же формой, что и "logprobs"). Любые другие поля передаются функциям вознаграждения. Функция получает исходный срез промптов для процесса без дублирования; она отвечает за возврат правильного количества завершений на каждый промпт (см. num_generations / num_generations_eval в тренере). Эта функция является экспериментальной и может быть изменена или удалена в любой момент без предварительного уведомления.
  • environment_factory (EnvironmentFactory или dict[str, EnvironmentFactory], необязательный) — Вызываемый объект, создающий и возвращающий экземпляр среды, или словарь, сопоставляющий имена сред с такими вызываемыми объектами. Класс среды должен определять методы, которые могут вызываться как инструменты в процессе генерации. Каждый метод должен соответствовать тем же требованиям, что и tools описанные выше. Среда также должна реализовывать вызываемый метод reset который можно использовать для сброса состояния между генерациями. Метод reset должен возвращать None или строку: если возвращается строка, она добавляется к последнему сообщению пользователя перед генерацией. Среда также может определять метод get_reward не принимающий аргументов и возвращающий float: при наличии которого среда управляет вознаграждением, а get_reward вызывается один раз за каждый завершённый прогон для оценки на основе внутреннего состояния среды. Он действует как дополнительный источник вознаграждения (с весом 1, логируется под именем класса среды) наряду с reward_funcs, который в этом случае становится необязательным.

    С использованием единого вызываемого объекта каждый пример использует одну и ту же среду, при этом на каждый rollout выделяется отдельный экземпляр, что обеспечивает изоляцию их взаимодействий. При использовании словаря каждый пример должен содержать поле environment, указывающее имя среды, и в его prompt будут доступны только инструменты этой среды — это позволяет в одном запуске смешивать задачи (например, среду для программирования и игру). Эта функция является экспериментальной и может быть изменена или удалена в любой момент без предварительного уведомления.

Trainer для метода Group Relative Policy Optimization (GRPO). Этот алгоритм был впервые предложен в статье DeepSeekMath: Pushing the Limits of Mathematical Reasoning in Open Language Models.

Пример:

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

>>> 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()

обучение

< >

( 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, загружается последняя контрольная точка из args.output_dir, сохранённая предыдущим экземпляром Trainer. Если параметр указан, обучение возобновляется из состояний модели/оптимизатора/планировщика, загруженных из этой контрольной точки.
  • 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().

Сохранение будет выполняться только из основного процесса.

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.
  • revision (str, необязательный) — Git-ревизия, от которой выполняется коммит. По умолчанию используется head ветки “main”.
  • kwargs (dict[str, Any], необязательный) — Дополнительные именованные аргументы, передаваемые в ~Trainer.create_model_card.

Загрузите self.model и self.processing_class в модельный хаб 🤗 в репозиторий self.args.hub_model_id.

GRPOConfig

класс trl.GRPOConfig

< >

( 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: transformers.trainer_utils.SchedulerType | str = 'linear'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 = 10logging_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 = Falserestore_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 | None = 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 = Nonetrust_remote_code: bool = Falserouter_aux_loss_coef: float | None = Nonedisable_dropout: bool = Falsecast_lm_head_to_fp32: bool = Falsenum_generations: int | None = 8num_generations_eval: int | None = Nonemax_completion_length: int | None = 512ds3_gather_for_generation: bool = Trueshuffle_dataset: bool | None = Truepad_to_multiple_of: int | str | None = 'auto'generation_batch_size: int | None = Nonesteps_per_generation: int | None = Nonetemperature: float = 1.0top_p: float = 1.0top_k: int = 0min_p: float | None = Nonegeneration_kwargs: dict | str | None = Nonechat_template_kwargs: dict | str | None = Nonerepetition_penalty: float = 1.0cache_implementation: str | None = Noneuse_vllm: bool = Falsevllm_mode: str = 'colocate'vllm_model_impl: str = 'vllm'vllm_enable_sleep_mode: bool = Falsevllm_structured_outputs_regex: str | None = Nonevllm_server_base_url: str | None = Nonevllm_server_host: str = '0.0.0.0'vllm_server_port: int = 8000vllm_server_timeout: float = 240.0vllm_group_port: int = 51216vllm_gpu_memory_utilization: float = 0.3vllm_max_model_length: int | None = Nonevllm_tensor_parallel_size: int = 1beta: float = 0.0num_iterations: int = 1epsilon: float = 0.2delta: float | None = Noneepsilon_high: float | None = Nonesapo_temperature_neg: float = 1.05sapo_temperature_pos: float = 1.0vespo_k_pos: float = 2.0vespo_lambda_pos: float = 3.0vespo_k_neg: float = 3.0vespo_lambda_neg: float = 2.0importance_sampling_level: str = 'token'reward_weights: list[float] | None = Nonemulti_objective_aggregation: str = 'sum_then_normalize'scale_rewards: str = 'group'loss_type: str = 'dapo'mask_truncated_completions: bool = Falsesync_ref_model: bool = Falseref_model_mixup_alpha: float = 0.6ref_model_sync_steps: int = 512top_entropy_quantile: float = 1.0entropy_coef: float = 0.0use_adaptive_entropy: bool = Falseentropy_coef_min: float = 0.0entropy_coef_max: float = 1.0entropy_coef_delta: float = 0.005entropy_target: float = 0.2max_tool_calling_iterations: int | None = Nonevllm_importance_sampling_correction: bool = Truevllm_importance_sampling_mode: str = 'sequence_mask'vllm_importance_sampling_clip_max: float | None = 3.0vllm_importance_sampling_clip_min: float | None = Noneoff_policy_mask_threshold: float | None = Noneuse_bias_correction_kl: bool = Truelog_completions: bool = Falselog_multimodal: bool = Truenum_completions_to_print: int | None = Nonelog_unique_prompts: bool = Falselog_completions_hub_repo: str | None = Noneuse_transformers_continuous_batching: bool = Falsetransformers_continuous_batching_config: dict | str | None = Noneuse_transformers_paged: bool = Falsevllm_importance_sampling_cap: float | None = None )

Параметры, управляющие моделью и эталонной моделью

  • model_init_kwargs (str или dict[str, Any], необязательный) — Параметры с ключами для from_pretrained, используемые, когда аргумент model в GRPOTrainer передан в виде строки. Значение revision также используется при загрузке классов обработки.
  • 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. Also applied to reward-model and reward-tokenizer loads.
  • router_aux_loss_coef (float, необязательный) — Коэффициент вспомогательной функции потерь для балансировки нагрузки в моделях Mixture-of-Experts (MoE), добавляемой к функции потерь обучения с этим весом. Если значение не задано, используется значение, объявленное в конфигурации модели. Установите 0.0, чтобы отключить её. Вызывает ошибку при использовании с моделью, не являющейся MoE.
  • disable_dropout (bool, необязательный, по умолчанию False) — Определяет, следует ли отключить dropout в модели. Это полезно при обучении с опорной моделью, так как предотвращает генерацию моделью различных logprobs для одного и того же входа.
  • cast_lm_head_to_fp32 (bool, необязательный, по умолчанию False) — Определяет, следует ли приводить слой language modeling head моделей policy и reference к типу float32. Рекомендуется в соответствии с рецептом ScaleRL. Этот флаг поддерживается только в том случае, если у модели слои word embedding и language modeling head не связаны, то есть tie_word_embeddings в конфигурации модели равно False.

Параметры, управляющие предобработкой данных

  • remove_unused_columns (bool, необязательный, по умолчанию False) — Определяет, следует ли в наборе данных оставлять только столбец "prompt". Если вы используете пользовательскую функцию вознаграждения, которая требует столбец, отличный от "prompts" и "completions", оставьте это значение равным False.
  • num_generations (int, необязательный, по умолчанию 8) — Количество генераций на промпт для выборки. Эффективный размер батча (num_processes * per_device_batch_size * gradient_accumulation_steps) должен делиться на это значение без остатка.
    • gradient_accumulation_steps) должно делиться на это значение без остатка.
  • num_generations_eval (int, необязательный) — Количество генераций для выборки во время оценки. Это позволяет использовать меньшее количество генераций при оценке, чтобы сэкономить вычислительные ресурсы. Если None, используется значение num_generations.
  • max_completion_length (int или None, необязательный, по умолчанию 512) — Максимальная длина сгенерированного завершения.
  • ds3_gather_for_generation (bool, необязательный, по умолчанию True) — Этот параметр относится к DeepSpeed ZeRO-3. Если включен, веса модели политики собираются для генерации, что повышает скорость генерации. Однако отключение этого параметра позволяет обучать модели, превышающие VRAM-емкость одного GPU, хотя и за счет более медленной генерации. Отключение этого параметра несовместимо с генерацией vLLM.
  • shuffle_dataset (bool, необязательный, по умолчанию True) — Определяет, следует ли перемешивать обучающий набор данных.
  • pad_to_multiple_of (int или str, необязательный, по умолчанию "auto") — Если задано, идентификаторы промптов и завершений будут дополнены до кратного этого значения. "auto" дополняет до кратного 128 на Neuron (AWS Trainium), который компилируется один раз для каждой формы входных данных, и не выполняет дополнения в других случаях.

Параметры, управляющие генерацией

  • generation_batch_size (int, необязательный) — Размер батча, используемый для генерации. Если None, по умолчанию используется эффективный размер обучающего батча: per_device_train_batch_size * num_processes * steps_per_generation. Иными словами, на каждый шаг оптимизации обрабатывается один батч генерации. Взаимоисключаемый с steps_per_generation.
  • steps_per_generation (int, необязательный) — Количество шагов на генерацию. Если None, по умолчанию используется gradient_accumulation_steps. Взаимоисключаемый с generation_batch_size.
  • temperature (float, необязательный, по умолчанию 1.0) — Температура для выборки. Чем выше температура, тем более случайными будут завершения.
  • top_p (float, необязательный, по умолчанию 1.0) — Число с плавающей точкой, управляющее накопительной вероятностью верхних токенов, которые следует учитывать. Должно находиться в интервале (0, 1]. Установите значение 1.0, чтобы учитывать все токены.
  • top_k (int, необязательный, по умолчанию 0) — Количество токенов словаря с наивысшей вероятностью, которые сохраняются для фильтрации top-k. Если 0, фильтрация top-k отключается и учитываются все токены.
  • min_p (float, необязательный) — Минимальная вероятность токена, которая масштабируется вероятностью наиболее вероятного токена. Значение должно находиться в диапазоне от 0.0 до 1.0. Типичные значения лежат в диапазоне 0.01-0.2.
  • generation_kwargs (dict[str, Any], необязательный) — Дополнительные именованные аргументы для передачи в GenerationConfig (при использовании transformers) или SamplingParams (при использовании vLLM) при выборке завершений. Это позволяет дополнительно настраивать поведение генерации, например, задавать suppress_tokens, num_beams и т. д. Если в словаре содержатся ключи, конфликтующие с другими параметрами генерации (например, min_p, top_p и т. д.), они будут иметь приоритет.
  • chat_template_kwargs (dict[str, Any], необязательный) — Дополнительные именованные аргументы для передачи в функцию apply_chat_template при генерации ответов.
  • repetition_penalty (float, необязательный, по умолчанию 1.0) — Число с плавающей точкой, которое штрафует новые токены в зависимости от того, встречаются ли они в исходном запросе и в уже сгенерированном тексте. Значения > 1.0 побуждают модель использовать новые токены, а значения < 1.0 — повторять токены.
  • cache_implementation (str, необязательный) — Реализация метода кэширования для более быстрого генерирования, когда use_vllm установлен в False.

Параметры, управляющие ускорением генерации на базе vLLM

  • use_vllm (bool, необязательный, по умолчанию False) — Использовать ли vLLM для генерации завершений. Если установлено в True, тренер будет использовать vLLM для генерации вместо стандартного model.generate(). Требуется установка vllm.
  • vllm_mode (str, необязательный, по умолчанию "colocate") — Режим для интеграции с vLLM, когда use_vllm установлено в значение True. Допустимые значения: "server" или "colocate".
    • "server": тренер будет отправлять запросы на генерацию отдельному серверу vLLM. Убедитесь, что сервер vLLM запущен (запустите с помощью vllm serve).
    • "colocate": vLLM будет работать в том же процессе и использовать те же GPU, что и обучение. Это избавляет от необходимости запускать отдельный сервер, но может привести к конкуренции за ресурсы с процессом обучения.
  • vllm_model_impl (str, необязательный, по умолчанию "vllm") — Реализация модели для vLLM. Должно быть одним из "transformers" или "vllm". "transformers": использовать бэкенд transformers для реализации модели. "vllm": использовать библиотеку vllm для реализации модели.
  • vllm_enable_sleep_mode (bool, необязательный, по умолчанию False) — Включает режим сна vLLM для выгрузки весов/кэша во время шага оптимизатора. Держит использование памяти GPU на низком уровне, но пробуждение движка добавляет задержку на передачу данных между хостом и устройством.
  • vllm_structured_outputs_regex (str, необязательный) — Регулярное выражение для структурированных выходов vLLM. Если None (по умолчанию), структурированные выходы отключены.

Параметры, управляющие сервером vLLM (используются только при `vllm_mode` = `"server"`)

  • vllm_server_base_url (str, необязательный) — Базовый URL сервера vLLM (например, "http://localhost:8000"). Если указан, vllm_server_host и vllm_server_port игнорируются.
  • vllm_server_host (str, необязательный, по умолчанию "0.0.0.0") — Хост сервера vLLM, к которому нужно подключиться. Игнорируется, если указано vllm_server_base_url.
  • vllm_server_port (int, необязательный, по умолчанию 8000) — Порт сервера vLLM для подключения. Игнорируется, если указано vllm_server_base_url.
  • vllm_server_timeout (float, необязательный, по умолчанию 240.0) — Общее время ожидания в секундах, пока сервер vLLM не станет доступным. Если сервер не запустится по истечении указанного времени, будет выброшено исключение ConnectionError.
  • vllm_group_port (int, необязательный, по умолчанию 51216) — Номер порта для группы обновления весов. Используется для связи с сервером vLLM. Если порт свободен, менять его не нужно.

Параметры, управляющие выполнением vLLM в режиме colocation (используются только при `vllm_mode` = `"colocate"`)

  • vllm_gpu_memory_utilization (float, необязательный, по умолчанию 0.3) — Управляет использованием памяти GPU в vLLM. Этот параметр применяется только при установке vllm_mode в значение "colocate". Если вы используете vllm_mode="server", этот параметр необходимо передавать отдельно при запуске сервера vLLM с помощью флага --vllm_gpu_memory_utilization.
  • vllm_max_model_length (int, необязательный) — Оконно контекста для vLLM. Установите значение не менее максимальной длины промпта в наборе данных плюс max_completion_length; если параметр не указан, он вычисляется из конфигурации модели.
  • vllm_tensor_parallel_size (int, необязательный, по умолчанию 1) — Управляет размером тензорного параллелизма для vLLM. Этот параметр применяется только при установке vllm_mode в значение "colocate". Если вы используете vllm_mode="server", этот параметр необходимо передавать отдельно при запуске сервера vLLM с помощью флага --vllm_tensor_parallel_size.

Параметры, управляющие обучением

  • beta (float, необязательный, по умолчанию 0.0) — коэффициент KL. Если 0.0 (по умолчанию), референсная модель не загружается, что снижает потребление памяти и повышает скорость обучения. DeepSeek-R1 incentivizes reasoning in LLMs through reinforcement learning используют значение 0.001.
  • num_iterations (int, необязательный, по умолчанию 1) — Количество итераций на каждый пакет (обозначается как μ в алгоритме).
  • epsilon (float, необязательный, по умолчанию 0.2) — Значение эпсилона для обрезания.
  • delta (float, необязательный) — Включает верхнюю границу обрезки в двухсторонней функции потерь GRPO, если задано значение типа float. Если None (по умолчанию), используется стандартная обрезка GRPO. Рекомендуется устанавливать значение больше 1 + ε, если эта опция включена. Этот метод представлен в техническом отчете INTELLECT-2.
  • epsilon_high (float, необязательный) — Верхнее значение epsilon для обрезки. Если не указано, по умолчанию используется то же значение, что и нижняя граница, заданная в аргументе epsilon. Статья DAPO рекомендует 0.28. При использовании с loss_type='cispo' это соответствует параметру ε_max, указанному в статье ScaleRL, и по умолчанию принимает рекомендуемое значение 5.0.
  • sapo_temperature_neg (float, необязательный, по умолчанию 1.05) — Температура для токенов с неположительными оценками преимущества, используемая в функции потерь sapo. Этот параметр представлен в статье Soft Adaptive Policy Optimization.
  • sapo_temperature_pos (float, необязательный, по умолчанию 1.0) — Температура для токенов с положительными оценками преимущества, используемая в функции потерь sapo. Этот параметр представлен в статье Soft Adaptive Policy Optimization.
  • vespo_k_pos (float, необязательный, по умолчанию 2.0) — параметр k для положительных преимуществ, он является степенью в функции потерь VESPO. Определяет, насколько агрессивно мы снижаем вес образцов с низкими весами важности (когда отношение важности выборки < 1).
  • vespo_lambda_pos (float, необязательный, по умолчанию 3.0) — параметр lambda для положительных преимуществ, он является коэффициентом затухания в функции потерь VESPO. Управляет тем, насколько агрессивно мы снижаем вес образцов с высокими весами важности (когда отношение выборки по важности > 1).
  • vespo_k_neg (float, необязательный, по умолчанию 3.0) — параметр k для отрицательных преимуществ, он является степенью в функции потерь VESPO. Определяет, насколько агрессивно мы снижаем вес образцов с низкими весами важности (когда отношение важности выборки < 1).
  • vespo_lambda_neg (float, необязательный, по умолчанию 2.0) — параметр lambda для отрицательных преимуществ, представляет собой коэффициент экспоненциального затухания в функции потерь VESPO. Управляет насколько агрессивно мы снижаем вес образцов с высокими весами важности (когда отношение важности выборки > 1).
  • importance_sampling_level (str, необязательный, по умолчанию "token") — Управляет тем, на каком уровне вычисляются коэффициенты importance sampling: на уровне "token" или "sequence". "token" сохраняет исходные отношения лог-вероятностей для каждого токена (один вес на токен). "sequence" усредняет отношения лог-вероятностей по всем валидным токенам, чтобы получить одно отношение на последовательность. В статье GSPO показано, что выборка на уровне последовательности часто обеспечивает более стабильное обучение и лучшее согласование с наградами на уровне последовательности.
  • reward_weights (list[float], необязательный) — Веса для каждой функции вознаграждения. Количество должно совпадать с числом функций вознаграждения. Если None, все вознаграждения взвешиваются одинаково с весом 1.0.
  • multi_objective_aggregation (str, необязательный, по умолчанию "sum_then_normalize") — Метод агрегации нескольких функций вознаграждения. Поддерживаемые значения:
    • "sum_then_normalize" (по умолчанию): сначала суммирует взвешенные вознаграждения от каждой функции вознаграждения, затем применяет масштабирование/нормализацию вознаграждений, как указано в scale_rewards (см. scale_rewards для подробностей).
    • "normalize_then_sum": Сначала нормализует/масштабирует каждую функцию вознаграждения по поколениям (внутри каждой группы), затем суммирует нормализованные вознаграждения с использованием указанных весов. Затем агрегированное вознаграждение нормализуется на уровне батча при формировании преимуществ. Это рекомендуемый подход из статьи GDPO: Group reward-Decoupled Normalization Policy Optimization for Multi-reward RL Optimization.
  • scale_rewards (str или bool, необязательный, по умолчанию "group") — Определяет стратегию масштабирования наград. Поддерживаемые значения:
    • True или "group" (по умолчанию): вознаграждения масштабируются стандартным отклонением внутри каждой группы, что обеспечивает единичную дисперсию внутри группы.
    • "batch": вознаграждения масштабируются стандартным отклонением по всей партии, как рекомендуется в статье PPO Lite.
    • False или "none": масштабирование не применяется. В статье Dr. GRPO рекомендуется не масштабировать вознаграждения, так как масштабирование по стандартному отклонению вносит смещение, связанное со сложностью на уровне вопроса.
  • loss_type (str, необязательный, по умолчанию "dapo") — Определяет формулу потерь, которую следует использовать. Поддерживаемые значения:
    • "grpo": агрегирует потери на уровне токенов, нормализуя их по длине последовательности. Не рекомендуется из-за смещения по длине: этот подход склонен отдавать предпочтение более коротким завершениям с положительными преимуществами и более длинным — с отрицательными.
    • "dr_grpo": агрегирует потери на уровне токенов, нормализуя их глобальной константой. Этот метод был предложен в статье Dr. GRPO для устранения смещения по длине. Значение константы соответствует max_completion_length.
    • "dapo" (по умолчанию): агрегирует потери на уровне токенов, нормализуя их на количество активных токенов в глобальной накопленной выборке. Этот метод был предложен в статье DAPO для устранения смещения, связанного с длиной.
    • "bnpo": агрегирует потери на уровне токенов, нормализуя их по количеству активных токенов в локальном батче. Обратите внимание, что нормализация выполняется только по локальному батчу, поэтому результаты могут незначительно различаться в зависимости от размера локального батча, даже при постоянном эффективном размере батча. При использовании per_device_train_batch_size==1 потеря эквивалентна потере GRPO.
    • "cispo": Обрезает веса importance sampling, а не веса importance sampling, масштабированные преимуществом. Затем обрезанные веса умножаются на преимущества и логарифмические вероятности модели политики. Потери отдельных токенов агрегируются путем нормализации на количество активных токенов в глобально накопленной выборке. Этот метод был предложен в статье MiniMax-M1.
    • "sapo": функция потерь Soft Adaptive Policy Optimization, предложенная в статьи Soft Adaptive Policy Optimization. Заменяет жёсткое обрезание (hard clipping) на плавный, управляемый температурой механизм, который адаптивно ослабляет обновления вне политики (off-policy), сохраняя при этом полезные сигналы обучения.
    • "luspo": Потери Length-Unbiased Sequence Policy Optimization. Потери на уровне последовательности, масштабирующие потерю каждой последовательности по её длине. Это модификация GSPO, требующая importance_sampling_level="sequence". Введено в статье LUSPO.
    • "vespo": Variational Sequence-Level Soft Policy Optimization. Заменяет жёсткое обрезание (hard clipping) на гладкую асимметричную функцию взвешивания Gamma, применяемую непосредственно к весам важности на уровне последовательности. Представлена в статьи VESPO.
  • mask_truncated_completions (bool, необязательный, по умолчанию False) — Если включено, усечённые завершения исключаются из расчёта функции потерь, что предотвращает их некорректное наказание и появление шума в процессе обучения. Согласно статье DAPO, это хорошая практика для обеспечения стабильности обучения.
  • sync_ref_model (bool, необязательный, по умолчанию False) — Определяет, следует ли синхронизировать эталонную модель с активной моделью каждые ref_model_sync_steps шагов, используя параметр ref_model_mixup_alpha. Эта синхронизация описана в статье TR-DPO.
  • ref_model_mixup_alpha (float, необязательный, по умолчанию 0.6) — параметр α из статьи TR-DPO, который управляет смесью текущей политики и предыдущей опорной политики при обновлениях. Опорная политика обновляется по формуле: π_ref = α * π_θ + (1 - α) * π_ref_prev. Чтобы использовать этот параметр, необходимо установить sync_ref_model=True.
  • ref_model_sync_steps (int, необязательный, по умолчанию 512) — параметр τ из статьи TR-DPO, определяющий, как часто текущая политика синхронизируется с эталонной политикой. Чтобы использовать этот параметр, необходимо установить sync_ref_model=True.
  • top_entropy_quantile (float, необязательный, по умолчанию 1.0) — параметр ρ из статьи Beyond the 80/20 Rule. В члене функции потерь политики сохраняются только токены из верхнего ρ-квантиля по энтропии распределения вероятностей на каждой позиции последовательности, что улучшает результаты. Диапазон: [0.0-1.0]. Значение 0.0 маскирует все токены, кроме того, у которого энтропия максимальна; 1.0 сохраняет все токены. В статье рекомендуется значение 0.2. Если используется вместе с mask_truncated_completions=True, учитываются только токены из неотсечённых завершений.
  • entropy_coef (float, необязательный, по умолчанию 0.0) — Коэффициент слагаемого энтропийной регуляризации в функции потерь. Положительное значение добавляет энтропийный бонус, который стимулирует исследование, предотвращая схлопывание политики к почти детерминированным выводам. Бонус всегда равен средней энтропии на токен независимо от loss_type; он не масштабируется для соответствия нормализации политики конкретного типа потерь, поэтому entropy_coef имеет одинаковый смысл для всех типов потерь. Если use_adaptive_entropy=True, это значение служит начальным коэффициентом и обновляется на каждом шаге оптимизатора. Не оказывает влияния, если установлено в 0.0 (по умолчанию).
  • use_adaptive_entropy (bool, необязательный, по умолчанию False) — Использовать ли адаптивное управление энтропией, представленное в Skywork-OR1. При включении коэффициент энтропии entropy_coef обновляется на каждом шаге оптимизатора: увеличивается на entropy_coef_delta, если текущая энтропия ниже entropy_target, и уменьшается в противном случае. Коэффициент применяется только тогда, когда энтропия равна entropy_target или ниже.
  • entropy_coef_min (float, необязательный, по умолчанию 0.0) — Нижняя граница для коэффициента энтропии при использовании адаптивного управления энтропией.
  • entropy_coef_max (float, необязательный, по умолчанию 1.0) — Верхняя граница для коэффициента энтропии при использовании адаптивного управления энтропией.
  • entropy_coef_delta (float, необязательный, по умолчанию 0.005) — Шаг изменения коэффициента энтропии на каждом шаге оптимизатора при адаптивном контроле энтропии.
  • entropy_target (float, необязательный, по умолчанию 0.2) — Целевое среднее значение энтропии на токен (в натах), используемое адаптивным управлением энтропией. Коэффициент применяется только в том случае, если текущая энтропия равна этому значению или ниже. Измеряется на том же наборе токенов, что и потеря политики: по умолчанию — все токены завершения, либо только подмножество с высокой энтропией, если top_entropy_quantile < 1.0. Типичные языковые модели имеют энтропию на токен в диапазоне 2–10 натов, поэтому значение по умолчанию 0.2 почти никогда не вызывает регуляризацию (только при почти полном коллапсе энтропии); установите его близким к энтропии, которую вы наблюдаете на ранних этапах обучения (логгируется как метрика entropy), чтобы бонус начал действовать до того, как политика коллапсирует (и учитывайте подмножество токенов при использовании top_entropy_quantile).
  • max_tool_calling_iterations (int, необязательный) — Максимальное количество итераций вызова инструментов при обучении агента. Если None, ограничение отсутствует, и генерация останавливается, когда модель генерирует ответ без вызовов инструментов или когда общая длина ответа достигает max_model_length.
  • vllm_importance_sampling_correction (bool, optional, defaults to True) — Whether to apply Importance Sampling (IS) to correct for the mismatch between vLLM completion logprobs and recomputed training logprobs. If set to False, no IS is applied regardless of vllm_importance_sampling_mode. When True, the selected mode determines how the IS ratios are computed and constrained. With top_p < 1, top_k > 0 or min_p > 0, the recomputed logprobs are normalized over the candidate set each token was sampled from, which requires vllm_mode="colocate" and vLLM 0.28 or later; otherwise, the IS ratios are biased. vLLM bounds that candidate set with top_k, so top_p < 1 and min_p > 0 require top_k > 0 (e.g. top_k=512). vLLM also applies repetition_penalty to the logprobs it returns, so repetition_penalty != 1.0 requires vllm_importance_sampling_correction=False.
  • vllm_importance_sampling_mode (str, необязательный, по умолчанию "sequence_mask") — Определяет, как выполняется Importance Sampling, когда vllm_importance_sampling_correction=True. Возможные значения:
    • "token_truncate": усечённый IS на уровне токенов. Соотношения для каждого токена ограничиваются диапазоном [C_min, C_max].
    • "token_mask": Маскированное IS на уровне токенов. Соотношения для отдельных токенов вне диапазона [C_min, C_max] обнуляются.
    • "sequence_truncate": усечение IS на уровне последовательности. Отношение для одной последовательности ограничивается диапазоном [C_min, C_max] и применяется ко всем токенам в последовательности.
    • "sequence_mask": Маскировка на уровне последовательности. Последовательности с коэффициентами вне диапазона [C_min, C_max] маскируются.
  • vllm_importance_sampling_clip_max (float, необязательный, по умолчанию 3.0) — Верхняя граница C_max для importance sampling, используемая в vllm_importance_sampling_mode. Для режимов *_truncate соотношения importance обрезаются сверху по значению C_max. Для режимов *_mask соотношения, превышающие C_max, приводятся к нулю.
  • vllm_importance_sampling_clip_min (float, необязательный) — Нижняя граница C_min для importance sampling, используемая в vllm_importance_sampling_mode. Для режимов *_truncate соотношения обрезаются снизу по C_min. Для режимов *_mask соотношения ниже C_min обнуляются. Чтобы строго маскировать соотношения ниже C_min без верхней границы, установите vllm_importance_sampling_clip_max=None.
  • off_policy_mask_threshold (float, необязательный) — Порог для маскирования off-policy последовательностей. Если None, маскирование off-policy последовательностей отключено. При заданном значении последовательности с отрицательными преимуществами и высоким расхождением KL маскируются для стабилизации обучения. Этот параметр соответствует порогу delta в уравнении 9 статьи DeepSeek-V3.2. Ожидается положительное значение (например, 0.5).
  • use_bias_correction_kl (bool, необязательный, по умолчанию True) — Определяет, следует ли умножать член KL на отношение важности выборки (importance sampling ratio), чтобы градиент KL стал непредвзятым градиентом обратного KL, как описано в статье DeepSeek-V3.2. Это изменяет градиент KL при beta != 0, в том числе в on-policy режиме: отношение дифференцируемо, поэтому оно влияет на градиент даже там, где его значение строго равно 1. Свойство непредвзятости обратного KL выполняется для importance_sampling_level="token"; при "sequence" вес на уровне последовательности распространяется на KL для каждого токена.

Параметры, управляющие ведением журнала

  • log_completions (bool, необязательный, по умолчанию False) — Определяет, следует ли каждые logging_steps шагов записывать в журнал выборку пар (prompt, completion). Если установлен пакет rich, выборка выводится на экран. Если включено логирование в wandb и/или trackio, выборка записывается в wandb и/или trackio.
  • log_multimodal (bool, необязательный, по умолчанию True) — Определяет, следует ли записывать в журнал мультимодальное содержимое (изображения, видео и т. д.) вместе с ответами. Отключите этот параметр, чтобы уменьшить размер журнала при работе с мультимодальными данными высокого разрешения.
  • num_completions_to_print (int, необязательный) — Количество завершений, которые нужно вывести с помощью rich. Если None, в журнал записываются все завершения.
  • log_unique_prompts (bool, необязательный, по умолчанию False) — Флаг, определяющий, следует ли записывать в журнал только уникальные промпты. Если True, в журнал записываются только уникальные промпты. Если False, записываются все промпты.
  • log_completions_hub_repo (str, необязательный) — репозиторий Hugging Face Hub для сохранения завершений. Должно быть полным именем репозитория, например 'username/reponame' или 'orgname/reponame', или просто 'reponame', в этом случае репозиторий будет создан в пространстве имён текущего пользователя Hugging Face. Обратите внимание, что этот репозиторий будет публичным, если вы не установите hub_private_repo=True или по умолчанию в вашей организации не создаются приватные репозитории.

Параметры, управляющие ускорением генерации на основе непрерывного батчинга в transformers

  • use_transformers_continuous_batching (bool, необязательный, по умолчанию False) — Использовать ли движок непрерывного батчинга transformers для генерации завершений. Требует transformers>=5.8.0.
  • transformers_continuous_batching_config (dict, необязательный) — Именованные аргументы для ContinuousBatchingConfig.

Устаревшие параметры

  • use_transformers_paged —

    Параметр use_transformers_paged устарел и будет удален в версии v2.0.0. Используйте вместо него use_transformers_continuous_batching.

  • vllm_importance_sampling_cap —

    Параметр vllm_importance_sampling_cap устарел и будет удалён в версии v2.0.0. Используйте вместо него vllm_importance_sampling_clip_max.

Класс конфигурации для GRPOTrainer.

Этот класс содержит только параметры, специфичные для обучения GRPO. Полный список аргументов обучения см. в документации TrainingArguments. Обратите внимание, что значения по умолчанию в этом классе могут отличаться от значений в TrainingArguments.

С помощью HfArgumentParser мы можем превратить этот класс в аргументы argparse, которые можно указать в командной строке.

Эти параметры имеют значения по умолчанию, отличные от TrainingArguments:

  • logging_steps: по умолчанию 10, а не 500.
  • gradient_checkpointing: по умолчанию True, а не False.
  • bf16: по умолчанию True, если не задан fp16, а не False.
  • learning_rate: по умолчанию 1e-6, а не 5e-5.
Update on GitHub