TRL documentation

RLOO Trainer

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

and get access to the augmented documentation experience

to get started

RLOO Trainer

model badge

Обзор

TRL поддерживает RLOO Trainer для обучения языковых моделей, как описано в статье Back to Basics: Revisiting REINFORCE Style Optimization for Learning from Human Feedback in LLMs авторов Arash Ahmadian, Chris Cremer, Matthias Gallé, Marzieh Fadaee, Julia Kreutzer, Ahmet Üstün и Sara Hooker.

Аннотация из статьи следующая:

Выравнивание ИИ в форме обучения с подкреплением на основе обратной связи от человека (RLHF) всё чаще рассматривается как ключевой компонент для высокопроизводительных больших языковых моделей. В недавней литературе метод проксимальной оптимизации политики (PPO) позиционируется как канонический подход для части RL в RLHF. Однако он связан с высокими вычислительными затратами и чувствительной настройкой гиперпараметров. Мы утверждаем, что большинство мотивационных принципов, приведших к разработке PPO, имеют меньшее практическое значение в контексте RLHF, и предлагаем менее вычислительно затратный метод, который сохраняет и даже повышает производительность. Мы пересматриваем формулировку выравнивания на основе человеческих предпочтений в контексте RL. Простота как руководящий принцип позволяет нам показать, что многие компоненты PPO не нужны в контексте RLHF, и что гораздо более простые варианты оптимизации в стиле REINFORCE превосходят как PPO, так и недавно предложенные методы «без RL», такие как DPO и RAFT. Наша работа показывает, что тщательная адаптация к характеристикам выравнивания LLM позволяет извлекать выгоду из онлайн-оптимизации RL при низких затратах.

Этот метод постобучения был предложен Costa Huang и впоследствии переписан Shirin Yamani.

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

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

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

# train_rloo.py
from datasets import load_dataset
from trl import RLOOTrainer
from trl.rewards import accuracy_reward

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

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

Выполните скрипт с помощью следующей команды:

torchrun --nproc_per_node 8 train_rloo.py

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

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

RLOO

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

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

Вычисление вознаграждения

В RLOO награда состоит из двух компонентов: награды, предоставляемой моделью наград (или функцией наград), и штрафного члена KL, который не позволяет политике отклоняться слишком сильно от фиксированной опорной политики

  1. Для каждой из G G сгенерированных последовательностей oi=(oi,1,…,oi,T) o_i = (o_{i,1}, \dots, o_{i,T}) в условиях запроса q q , мы вычисляем скалярное вознаграждение с помощью модели вознаграждения R(oi,q) R(o_i, q) .
  2. Одновременно мы оцениваем расхождение Кульбака–Лейблера между текущей политикой πθ \pi_\theta и фиксированной опорной политикой πref \pi_{\text{ref}} на последовательности. Оценка KL для последовательности oi o_i имеет вид: DKL ⁣[πθ∥πref]=∑t=1Tlog⁡πθ(oi,t∣q,oi,<t)πref(oi,t∣q,oi,<t). \mathbb{D}_{\mathrm{KL}}\!\left[\pi_\theta\|\pi_{\mathrm{ref}}\right] = \sum_{t=1}^T \log \frac{\pi_\theta(o_{i,t} \mid q, o_{i,<t})}{\pi_{\mathrm{ref}}(o_{i,t} \mid q, o_{i,<t})}.

Итоговое вознаграждение, назначенное последовательности oi o_i затем равно: ri=R(oi,q)−β DKL ⁣[πθ∥πref], r_i = R(o_i, q) - \beta \, \mathbb{D}_{\mathrm{KL}}\!\left[\pi_\theta \|\pi_{\mathrm{ref}}\right],

где β>0 \beta > 0 управляет силой штрафного члена KL.

В чисто онлайн-настройке (num_iterations = 1, значение по умолчанию) данные генерируются текущей политикой. В этом случае штраф за KL вычисляется непосредственно с использованием текущей политики.

В более общем случае (например, несколько шагов градиента на батч) данные генерируются более ранним снимком πold \pi_{\text{old}} . Чтобы штраф оставался согласованным с распределением выборки, KL определяется относительно этой политики:

DKL ⁣[πold ∥ πref]. \mathbb{D}_{\mathrm{KL}}\!\left[\pi_{\text{old}} \,\|\, \pi_{\text{ref}}\right].

Эквивалентно, для выборочной последовательности o o , оценка Монте-Карло равна:

DKL ⁣[πold∥πref]=∑t=1Tlog⁡πold(oi,t∣q,oi,<t)πref(oi,t∣q,oi,<t). \mathbb{D}_{\mathrm{KL}}\!\left[\pi_{\text{old}} \|\pi_{\mathrm{ref}}\right] = \sum_{t=1}^T \log \frac{\pi_{\text{old}}(o_{i,t} \mid q, o_{i,<t})}{\pi_{\mathrm{ref}}(o_{i,t} \mid q, o_{i,<t})}.

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

После того как вознаграждения для каждого завершения вычислены, мы рассчитываем базовую линию (baseline) как среднее вознаграждение всех остальных образцов в том же батче, исключая текущий образец. Эта базовая линия используется для снижения дисперсии оценки градиента политики. Затем преимущество (advantage) для каждого завершения получается как разница между его собственным вознаграждением и этой базовой линией, исключающей текущий образец (leave-one-out).

Формально, для батча из G завершений базовая линия для завершения i:bi=1G−1∑j≠irj b_i = \frac{1}{G-1} \sum_{j \neq i} r_j

а затем преимущество для каждого завершения вычисляется как разница между его наградой и базовой линией: Ai=ri−bi A_i = r_i - b_i

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

Потеря REINFORCE определяется следующим образом: LRLOO(θ)=−1G∑i=1GA^i log⁡πθ(oi∣q) \mathcal{L}_{\text{RLOO}}(\theta) = - \frac{1}{G} \sum_{i=1}^G \hat{A}_i \, \log \pi_\theta(o_i \mid q)

На практике выполнение нескольких шагов градиента на одной и той же партии делает действия фактически off-policy относительно текущих параметров. Для исправления этого мы вводим коэффициент важности выборки (importance sampling ratio). Чтобы предотвратить чрезмерно большие обновления, когда политика меняется между выборкой и шагами градиента, мы ограничиваем (clip) этот коэффициент: LRLOO(θ)=−1G∑i=1Gmin⁡(πθ(oi∣q)πθold(oi∣q)A^i, clip(πθ(oi∣q)πθold(oi∣q),1−ϵ,1+ϵ)A^i) \mathcal{L}_{\text{RLOO}}(\theta) = - \frac{1}{G} \sum_{i=1}^G \min \left( \frac{\pi_\theta(o_i \mid q)}{\pi_{\theta_\text{old}}(o_i \mid q)} \hat{A}_i, \, \text{clip}\left(\frac{\pi_\theta(o_i \mid q)}{\pi_{\theta_\text{old}}(o_i \mid q)}, 1-\epsilon, 1+\epsilon\right) \hat{A}_i \right)

В полностью онлайн-настройке с одним шагом (по умолчанию), πθ(oi∣q)πθold(oi∣q)=1 \frac{\pi_\theta(o_i \mid q)}{\pi_{\theta_\text{old}}(o_i \mid q)} = 1 и это сводится к стандартному REINFORCE.

В отличие от GRPO, RLOO не выполняет обратное распространение градиентов через член KL. Здесь KL используется исключительно для формирования вознаграждения: он вычисляется в режиме no_grad и включается в скалярное вознаграждение ri r_i , которое становится отсоединённым преимуществом A^i \hat{A}_i .

Иными словами, единственный путь, по которому градиент поступает в политику, — это член отношения важности πθ(oi∣q)πθold(oi∣q) \frac{\pi_\theta(o_i \mid q)}{\pi_{\theta_\text{old}}(o_i \mid q)} , а член KL не распространяется на политику при обратном распространении ошибки.

В отличие от этого, GRPO добавляет в свою целевую функцию явный дифференцируемый член KL, вычисляемый на лету с использованием текущей политики πθ \pi_\theta , поэтому её градиент проходит и через член отношения, и через штраф KL.

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

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

  • 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: Доля обрезанных (усечённых) завершений.
  • rewards/{reward_func_name}/mean: среднее значение вознаграждения от конкретной функции вознаграждения.
  • rewards/{reward_func_name}/std: стандартное отклонение вознаграждения от конкретной функции вознаграждения.
  • reward: Общая средняя награда после суммирования наград по функциям (с весами reward_weights).
  • reward_std: стандартное отклонение суммарных наград по функциям (с учётом весов reward_weights), вычисленное для всей выборки.
  • frac_reward_zero_std: доля образцов в батче генерации, у которых стандартное отклонение награды равно нулю, что указывает на малое разнообразие для данного промпта (все ответы верные или неверные).
  • entropy: Средняя энтропия предсказаний токенов по всем сгенерированным завершениям. (Если mask_truncated_completions=True, токены замаскированных последовательностей исключаются.)
  • aux_loss: вспомогательная функция потерь для балансировки нагрузки в модели Mixture-of-Experts, до её масштабирования коэффициентом router_aux_loss_coef и добавления к общей функции потерь. Записывается в журнал только в том случае, если модель является MoE и router_aux_loss_coef не равен нулю.
  • kl: средняя дивергенция Кульбака–Лейблера между моделью и эталонной моделью, рассчитанная по сгенерированным завершениям. Записывается в журнал только если beta не равно нулю.
  • clip_ratio/region_mean: Соотношение вероятностей последовательностей, для которых целевая функция RLOO обрезается, чтобы оставаться в области доверия: clip(ri(θ),1−ϵlow,1+ϵhigh) ,ri(θ)=πθ(oi∣q)πθold(oi∣q) \text{clip}\left( r_{i}(\theta), 1 - \epsilon_\mathrm{low}, 1 + \epsilon_\mathrm{high} \right)\,, \quad r_{i}(\theta) = \frac{\pi_\theta(o_{i} \mid q)}{\pi_{\theta_{\text{old}}}(o_{i} \mid q)} . Более высокое значение означает, что обрезается больше выборок, что ограничивает степень изменения политики πθ\pi_\theta .
  • clip_ratio/low_mean: Среднее отношение вероятностей последовательностей, обрезанных по нижней границе области доверия: ri,t(θ)<1−ϵlowr_{i,t}(\theta) < 1 - \epsilon_\mathrm{low}.
  • clip_ratio/low_min: Наименьший индикатор обрезки на нижнюю границу области доверия для каждого завершения: ri,t(θ)<1−ϵlowr_{i,t}(\theta) < 1 - \epsilon_\mathrm{low}.
  • clip_ratio/high_mean: Среднее отношение вероятностей последовательностей, обрезанных по верхней границе области доверия: ri,t(θ)>1+ϵhighr_{i,t}(\theta) > 1 + \epsilon_\mathrm{high}.
  • clip_ratio/high_max: Наибольший индикатор обрезки на верхнюю границу области доверия для каждого завершения: ri,t(θ)>1+ϵhighr_{i,t}(\theta) > 1 + \epsilon_\mathrm{high}.

Настройка

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

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

pip install trl[vllm]

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

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

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

from trl import RLOOConfig

training_args = RLOOConfig(
    ...,
    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 RLOOConfig
    
    training_args = RLOOConfig(
        ...,
        use_vllm=True,
        vllm_mode="server",
    )

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

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

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

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

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

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

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

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

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

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

Ниже приведён пример SLURM-скрипта для обучения модели 70B с использованием RLOO на нескольких узлах. Этот скрипт обучает модель на 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}" torchrun \
     --nnodes 4 \
     --nproc_per_node 8 \
     --node_rank $SLURM_PROCID \
     --rdzv_backend c10d \
     --rdzv_endpoint ${NODELIST[0]}:29500 \
     train_rloo.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 RLOOTrainer, RLOOConfig

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

    # Example dataset from TLDR
    dataset = load_dataset("trl-lib/tldr", split="train")

    # Dummy reward function: count the number of unique characters in the completions
    def reward_num_unique_chars(completions, **kwargs):
        return [len(set(c)) for c in completions]

    training_args = RLOOConfig(
        output_dir="Qwen2.5-72B-RLOO",
        per_device_train_batch_size=4,
        bf16=True,
        deepspeed="examples/deepspeed_configs/zero3.json",
        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 = RLOOTrainer(model="Qwen/Qwen2.5-72B", args=training_args, reward_funcs=reward_num_unique_chars, train_dataset=dataset)
    trainer.train()

if __name__=="__main__":
    main()

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

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

Функции вознаграждения могут быть как синхронными вызываемыми объектами 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.
      • Все имена столбцов (кроме 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: Многозадачные функции вознаграждения

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

from datasets import Dataset
from trl import RLOOTrainer

# 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 = RLOOTrainer(
    model="Qwen/Qwen2-0.5B-Instruct",
    reward_funcs=[math_reward_func, coding_reward_func],
    train_dataset=dataset,
)

trainer.train()

В этом примере math_reward_func и coding_reward_func разработаны для работы со смешанным набором данных, содержащим как математические, так и программные задачи. Колонка task в наборе данных используется для определения, какую функцию вознаграждения применить к каждой задаче. Если для образца в наборе данных нет соответствующей функции вознаграждения, функция вернёт None, и RLOOTrainer продолжит работу с валидными функциями и задачами. Это позволяет RLOOTrainer обрабатывать несколько функций вознаграждения с разной областью применения.

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

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

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

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

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

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

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

from trl import RLOOTrainer

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

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

from trl import RLOOTrainer

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

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

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

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

RLOO поддерживает обучение моделей «зрение-язык» (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 с необходимыми изменениями.

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

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

torchrun --nproc_per_node 8 examples/rloo_visual_math/rloo_visual_math.py \
  --deepspeed examples/deepspeed_configs/zero3.json \
  --model_name_or_path Qwen/Qwen2.5-VL-3B-Instruct \
  --output_dir rloo-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

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

RLOOTrainer

класс trl.RLOOTrainer

< >

( 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]]]args: trl.trainer.rloo_config.RLOOConfig | 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 = 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]) — Функции вознаграждения, используемые для вычисления наград. Для вычисления наград мы вызываем все функции вознаграждения с промптами и завершениями и суммируем награды. Допустимые варианты:
    • Одна функция вознаграждения, например:

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

    Если 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, модель не оборачивается.

Trainer for the Reinforce Leave One Out (RLOO) method. This algorithm was initially proposed in the paper Back to Basics: Revisiting REINFORCE Style Optimization for Learning from Human Feedback in LLMs.

Пример:

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

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

>>> trainer = RLOOTrainer(
...     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.

RLOOConfig

класс trl.RLOOConfig

< >

( 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 = Falsenum_generations: int | None = 2num_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.05num_iterations: int = 1epsilon: float = 0.2epsilon_high: float | None = Nonereward_weights: list[float] | None = Nonenormalize_advantages: bool = Falsereward_clip_range: tuple[float, float] | None = Nonemask_truncated_completions: bool = Falsesync_ref_model: bool = Falseref_model_mixup_alpha: float = 0.6ref_model_sync_steps: int = 512log_completions: bool = Falselog_multimodal: bool = Truenum_completions_to_print: int | None = Nonelog_unique_prompts: bool = Falseuse_transformers_continuous_batching: bool = Falsetransformers_continuous_batching_config: dict | str | None = Noneuse_transformers_paged: bool = False )

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

  • model_init_kwargs (str или dict[str, Any], необязательный) — Параметры с ключами для from_pretrained, используемые, когда аргумент model в RLOOTrainer передан в виде строки. Значение 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 для одного и того же входа.

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

  • remove_unused_columns (bool, необязательный, по умолчанию False) — Определяет, следует ли в наборе данных оставлять только столбец "prompt". Если вы используете пользовательскую функцию вознаграждения, которая требует столбец, отличный от "prompts" и "completions", оставьте это значение равным False.
  • num_generations (int, необязательный, по умолчанию 2) — Количество генераций на промпт для выборки. Эффективный размер батча (num_processes * per_device_batch_size
    • 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.05) — коэффициент KL. Если 0.0, референсная модель не загружается, что снижает потребление памяти и ускоряет обучение.
  • num_iterations (int, необязательный, по умолчанию 1) — Количество итераций на каждый пакет (обозначается как μ в алгоритме).
  • epsilon (float, необязательный, по умолчанию 0.2) — Значение эпсилона для обрезания.
  • epsilon_high (float, необязательный) — Верхнее значение epsilon для обрезки. Если не указано, по умолчанию используется то же значение, что и нижняя граница, заданная в аргументе epsilon. Статья DAPO рекомендует 0.28.
  • reward_weights (list[float], необязательный) — Веса для каждой функции вознаграждения. Количество должно совпадать с числом функций вознаграждения. Если None, все вознаграждения взвешиваются одинаково с весом 1.0.
  • normalize_advantages (bool, необязательный, по умолчанию False) — Нужно ли нормализовать преимущества. Нормализация выполняется для каждой генерационной партии, чтобы среднее значение составляло 0.0, а стандартное отклонение — 1.0.
  • reward_clip_range (tuple[float, float], необязательный) — Диапазон обрезки наград в виде (min, max). Если None, обрезка не применяется.
  • 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.

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

  • 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, записываются все промпты.

Параметры, управляющие ускорением генерации на основе непрерывного батчинга в 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.

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

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

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

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

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

Ссылки

  1. Статья RLOO
  2. Статья Back to Basics: Пересмотр оптимизации в стиле REINFORCE для обучения по обратной связи от человека в LLM
  3. Статья - REINFORCE++: простой и эффективный подход к выравниванию больших языковых моделей
  4. Статья в блоге — Возвращаем RL в RLHF
  5. Статья в блоге — Разбираемся с RLHF и его вариантами: прогресс и практические инженерные наблюдения
  6. YouTube - RLOO: экономичная оптимизация для обучения с обратной связью от человека в LLM

Руководство по миграции со старой реализации (0.21 и ниже)

С выходом версии 0.22.0 мы переработали RLOOTrainer, чтобы он лучше соответствовал другим онлайн-тренажерам в библиотеке, таким как GRPOTrainer. Эта новая реализация вносит несколько изменений в параметры конфигурации и общую структуру тренажера. Ниже приведено краткое описание ключевых изменений для RLOOConfig:

TRL ≤ 0.21.xTRL ≥ 0.22.0
rloo_kпереименован в num_generations
cliprangeпереименован в epsilon
kl_coefпереименован в beta
exp_nameпереименован в run_name. Используйте run_name = f"{exp_name}__{seed}__{int(time.time())}", чтобы воспроизвести прежнее поведение
normalize_rewardпереименован в normalize_advantages. Примечание: этот метод всегда нормализовал преимущества (несмотря на старое название)
num_ppo_epochsпереименован в num_iterations (по умолчанию: 1)
token_level_klудалено – KL теперь вычисляется только на уровне последовательности
dataset_num_procremoved – не использовался
num_mini_batchesпереименован в steps_per_generation
total_episodesиспользуйте max_steps=total_episodes / gradient_accumulation_steps
local_rollout_forward_batch_sizeудалён – теперь автоматически устанавливается в значение per_device_train_batch_size (или per_device_eval_batch_size во время оценки)
num_sample_generationsудалено – используйте logging_steps для управления частотой логирования генерации
response_lengthпереименован в max_completion_length (по умолчанию: 512)
stop_tokenудалено
stop_token_idудалено – используйте processing_class.eos_token_id
missing_eos_penaltyудалено – дублируется с помощью пользовательской функции вознаграждения, проверяющей, входит ли eos_token_id в completion_ids

Ниже приведено краткое описание ключевых изменений для RLOOTrainer:

TRL ≤ 0.21.xTRL ≥ 0.22.0
configпереименован в args
reward_modelпереименован в reward_funcs, который теперь поддерживает как модели вознаграждения, так и пользовательские функции вознаграждения
policyпереименован в model
ref_policyудалено – модель-референс теперь создаётся автоматически из model
data_collatorудалено
Update on GitHub