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

Visão geral

O TRL oferece suporte ao RLOO Trainer para o treinamento de modelos de linguagem, conforme descrito no artigo Back to Basics: Revisiting REINFORCE Style Optimization for Learning from Human Feedback in LLMs de Arash Ahmadian, Chris Cremer, Matthias Gallé, Marzieh Fadaee, Julia Kreutzer, Ahmet Üstün e Sara Hooker.

O resumo do artigo é o seguinte:

O alinhamento de IA na forma de Aprendizado por Reforço a partir de Feedback Humano (RLHF) é cada vez mais tratado como um ingrediente crucial para modelos de linguagem de grande escala de alto desempenho. A Otimização de Política Próxima (PPO) tem sido posicionada pela literatura recente como o método canônico para a parte de RL do RLHF. No entanto, ela envolve tanto alto custo computacional quanto ajuste sensível de hiperparâmetros. Postulamos que a maioria dos princípios motivacionais que levaram ao desenvolvimento da PPO é menos uma preocupação prática no RLHF e defendemos um método menos custoso computacionalmente que preserva e até aumenta o desempenho. Revisitamos a formulação do alinhamento a partir de preferências humanas no contexto de RL. Mantendo a simplicidade como princípio orientador, mostramos que muitos componentes da PPO são desnecessários em um contexto de RLHF e que variantes de otimização no estilo REINFORCE, muito mais simples, superam tanto a PPO quanto os métodos “livres de RL” recém-propostos, como DPO e RAFT. Nosso trabalho sugere que a adaptação cuidadosa às características de alinhamento de LLMs permite se beneficiar da otimização de RL online a baixo custo.

Este método de pós-treinamento foi contribuído por Costa Huang e posteriormente refatorado por Shirin Yamani.

Início rápido

Este exemplo demonstra como treinar um modelo usando o método RLOO. Treinamos um modelo Qwen 0.5B Instruct com os prompts do conjunto de dados DeepMath-103K. Você pode visualizar os dados do conjunto de dados aqui:

Abaixo está o script para treinar o modelo. accuracy_reward precisa do math-verify, que você pode instalar com 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()

Execute o script usando o seguinte comando:

torchrun --nproc_per_node 8 train_rloo.py

Olhando mais a fundo para o método RLOO

RLOO é um algoritmo de aprendizado online, o que significa que ele melhora iterativamente usando os dados gerados pelo próprio modelo treinado durante o treinamento. A intuição por trás do objetivo do RLOO é maximizar a vantagem das conclusões geradas, garantindo que o modelo permaneça próximo à política de referência. Para entender como o RLOO funciona, ele pode ser dividido em quatro etapas principais: gerar conclusões, calcular a vantagem, estimar a divergência de KL e calcular a perda.

RLOO

Gerando complementos

Em cada etapa de treinamento, amostramos um lote de prompts e geramos um conjunto de G G completions para cada prompt (denotado como oi o_i ).

Calculando a recompensa

No RLOO, a recompensa consiste em dois componentes: a recompensa fornecida pelo modelo de recompensa (ou função de recompensa) e uma penalidade KL que desencoraja a política de se desviar demais de uma política de referência fixa

  1. Para cada uma das G G sequências geradas oi=(oi,1,…,oi,T) o_i = (o_{i,1}, \dots, o_{i,T}) condicionadas a uma consulta q q , calculamos uma recompensa escalar usando um modelo de recompensa R(oi,q) R(o_i, q) .
  2. Concorrentemente, estimamos a divergência de KL entre a política atual πθ \pi_\theta e a política de referência fixa πref \pi_{\text{ref}} ao longo da sequência. A estimativa de KL para a sequência 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})}.

A recompensa final atribuída à sequência oi o_i é a seguinte: ri=R(oi,q)−β DKL ⁣[πθ∥πref], r_i = R(o_i, q) - \beta \, \mathbb{D}_{\mathrm{KL}}\!\left[\pi_\theta \|\pi_{\mathrm{ref}}\right],

onde β>0 \beta > 0 controla a intensidade da penalidade KL.

Em um cenário puramente online (num_iterations = 1, padrão), os dados são gerados pela política atual. Nesse caso, a penalidade KL é calculada diretamente usando a política atual.

No cenário mais geral (por exemplo, múltiplas etapas de gradiente por lote), os dados são gerados por um snapshot anterior πold \pi_{\text{old}} . Para manter a penalidade consistente com a distribuição de amostragem, o KL é definido em relação a esta política:

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

Equivalentemente, para uma sequência amostrada o o , a estimativa de Monte Carlo é:

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})}.

Calculando a vantagem

Uma vez que as recompensas para cada conclusão tenham sido calculadas, calculamos uma linha de base como a recompensa média de todos os outros amostras no mesmo lote, excluindo a amostra atual. Essa linha de base é usada para reduzir a variância da estimativa do gradiente da política. A vantagem para cada conclusão é então obtida como a diferença entre a própria recompensa e essa linha de base de exclusão de um elemento.

Formalmente, para um lote de G conclusões, a linha de base para a conclusão é:bi=1G−1∑j≠irj b_i = \frac{1}{G-1} \sum_{j \neq i} r_j

e em seguida a vantagem para cada conclusão é calculada como a diferença entre sua recompensa e a linha de base: Ai=ri−bi A_i = r_i - b_i

Calculando a perda

A perda REINFORCE é simplesmente definida como: 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)

Na prática, executar múltiplas etapas de gradiente no mesmo lote torna as ações efetivamente off-policy em relação aos parâmetros atuais. Para corrigir isso, introduzimos a razão de amostragem de importância. Para evitar atualizações excessivamente grandes quando a política muda entre a amostragem e as etapas de gradiente, aplicamos um limite (clip) a essa razão: 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)

Em um ambiente totalmente online, de etapa única (padrão), πθ(oi∣q)πθold(oi∣q)=1 \frac{\pi_\theta(o_i \mid q)}{\pi_{\theta_\text{old}}(o_i \mid q)} = 1 e isso se reduz ao REINFORCE padrão.

Diferente do GRPO, o RLOO não faz backpropagation de gradientes através do termo KL. Aqui, o KL é usado puramente para modelagem de recompensa: ele é calculado sob no_grad e incorporado à recompensa escalar ri r_i , que se torna a vantagem destacada A^i \hat{A}_i .

Em outras palavras, o único caminho pelo qual o gradiente entra na política é o termo da razão de importância πθ(oi∣q)πθold(oi∣q) \frac{\pi_\theta(o_i \mid q)}{\pi_{\theta_\text{old}}(o_i \mid q)} , e o termo KL não faz backpropagation para a política.

Em contraste, GRPO adiciona um termo KL explícito e diferenciável ao seu objetivo, calculado em tempo real com a política atual πθ \pi_\theta , de modo que seu gradiente flui tanto pelo termo de razão quanto pela penalidade KL.

Métricas registradas

Durante o treinamento e a avaliação, registramos as seguintes métricas:

  • num_tokens: O número total de tokens processados até o momento, incluindo tanto os prompts quanto as conclusões.
  • step_time: O tempo médio (em segundos) por etapa de treinamento (incluindo a geração).
  • completions/mean_length: O comprimento médio das conclusões geradas.
  • completions/min_length: O comprimento mínimo das conclusões geradas.
  • completions/max_length: O comprimento máximo das conclusões geradas.
  • completions/mean_terminated_length: O comprimento médio das conclusões geradas que terminam com EOS.
  • completions/min_terminated_length: O comprimento mínimo das conclusões geradas que terminam com EOS.
  • completions/max_terminated_length: O comprimento máximo das conclusões geradas que terminam com EOS.
  • completions/clipped_ratio: A proporção de conclusões truncadas (clipped).
  • rewards/{reward_func_name}/mean: A recompensa média de uma função de recompensa específica.
  • rewards/{reward_func_name}/std: O desvio padrão da recompensa de uma função de recompensa específica.
  • reward: A recompensa média geral após somar as recompensas entre as funções (ponderada por reward_weights).
  • reward_std: O desvio padrão dos recompensas somadas entre as funções (ponderado por reward_weights), calculado sobre o lote completo.
  • frac_reward_zero_std: A fração de amostras no lote de geração com desvio padrão de recompensa igual a zero, o que implica que há pouca diversidade para aquele prompt (todas as respostas estão corretas ou incorretas).
  • entropy: Entropia média das previsões de tokens entre as conclusões geradas. (Se mask_truncated_completions=True, os tokens das sequências mascaradas são excluídos.)
  • aux_loss: A perda auxiliar de balanceamento de carga de um modelo Mixture-of-Experts, antes de ser escalada por router_aux_loss_coef e adicionada à perda. Registrada apenas quando o modelo é um modelo MoE e router_aux_loss_coef é diferente de zero.
  • kl: A divergência KL média entre o modelo e o modelo de referência, calculada sobre as conclusões geradas. Registrado apenas se beta for diferente de zero.
  • clip_ratio/region_mean: A proporção de probabilidades de sequência em que o objetivo RLOO é limitado para permanecer dentro da região de confiança: 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)} . Um valor mais alto significa que mais amostras são limitadas, o que restringe o quanto a política πθ\pi_\theta pode mudar.
  • clip_ratio/low_mean: A proporção média das probabilidades de sequência que foram cortadas no limite inferior da região de confiança: ri,t(θ)<1−ϵlowr_{i,t}(\theta) < 1 - \epsilon_\mathrm{low}.
  • clip_ratio/low_min: O menor indicador de recorte por conclusão no limite inferior da região de confiança: ri,t(θ)<1−ϵlowr_{i,t}(\theta) < 1 - \epsilon_\mathrm{low}.
  • clip_ratio/high_mean: A razão média das probabilidades de sequência que foram cortadas no limite superior da região de confiança: ri,t(θ)>1+ϵhighr_{i,t}(\theta) > 1 + \epsilon_\mathrm{high}.
  • clip_ratio/high_max: O maior indicador de recorte por conclusão no limite superior da região de confiança: ri,t(θ)>1+ϵhighr_{i,t}(\theta) > 1 + \epsilon_\mathrm{high}.

Personalização

Acelere o treinamento com geração impulsionada por vLLM

A geração é frequentemente o principal gargalo ao treinar com métodos online. Para acelerar a geração, você pode usar vLLM, um motor de inferência de alto rendimento e baixa latência para LLMs. Para ativá-lo, primeiro instale o pacote com

pip install trl[vllm]

Suportamos duas formas de usar o vLLM durante o treinamento: modo servidor e modo colocalizado.

Opção 1: Modo Colocate

Neste modo, o vLLM é executado dentro do processo do trainer e compartilha a memória da GPU com o modelo de treinamento. Isso evita a inicialização de um servidor separado e pode melhorar a utilização da GPU, mas pode levar a disputas de memória nas GPUs de treinamento. Este é o modo padrão.

from trl import RLOOConfig

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

Opção 2: Modo servidor

Neste modo, o vLLM é executado em um processo separado (e usando GPUs separadas) e se comunica com o treinador via HTTP. Isso é ideal se você tiver GPUs dedicadas para inferência.

  1. Inicie o servidor vLLM:

    VLLM_SERVER_DEV_MODE=1 vllm serve <model_name> \
        --weight-transfer-config '{"backend": "nccl"}' \
        --logprobs-mode processed_logprobs \
        --max-logprobs -1
  2. Ative o modo de servidor no seu script de treinamento:

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

Certifique-se de que o servidor está usando GPUs diferentes das do trainer; caso contrário, você pode encontrar erros do NCCL. Você pode especificar as GPUs a serem usadas com a variável de ambiente CUDA_VISIBLE_DEVICES.

Dependendo do tamanho do modelo e dos requisitos gerais de memória de GPU para o treinamento, você pode precisar ajustar o parâmetro vllm_gpu_memory_utilization em RLOOConfig para evitar subutilização ou erros de memória insuficiente.

Fornecemos um HF Space para ajudar a estimar a utilização recomendada de memória de GPU com base na configuração do seu modelo e nas configurações do experimento. Basta usá-lo da seguinte forma para obter a recomendação de vllm_gpu_memory_utilization:

Se o valor recomendado não funcionar no seu ambiente, sugerimos adicionar uma pequena margem (por exemplo, +0.05 ou +0.1) ao valor recomendado para garantir estabilidade.

Se você ainda estiver recebendo erros de memória insuficiente, defina vllm_enable_sleep_mode como True e os parâmetros e o cache do vllm serão descarregados durante a etapa de otimização. Para mais informações, consulte Reduzindo o uso de memória com o vLLM Sleep Mode.

Por padrão, o RLOO usa MASTER_ADDR=localhost e MASTER_PORT=12345 para o vLLM, mas você pode sobrescrever esses valores definindo as variáveis de ambiente de acordo.

Para mais informações, consulte Aceleração do treinamento com vLLM.

RLOO em escala: treinar um modelo de 70B+ em vários nós

Ao treinar modelos grandes como Qwen2.5-72B, você precisa de várias otimizações-chave para tornar o treinamento eficiente e escalável em várias GPUs e nós. Essas incluem:

  • DeepSpeed ZeRO Stage 3: o ZeRO utiliza paralelismo de dados para distribuir os estados do modelo (pesos, gradientes, estados do otimizador) entre várias GPUs e CPUs, reduzindo os requisitos de memória e computação em cada dispositivo. Como modelos grandes não cabem em uma única GPU, o uso do ZeRO Stage 3 é obrigatório para treinar esse tipo de modelo. Para mais detalhes, consulte DeepSpeed Integration.
  • torchrun: o lançador do PyTorch inicia um processo por GPU em cada nó e os conecta por meio de um ponto de encontro comum. Para mais detalhes, consulte Distributing Training.
  • vLLM: Consulte a seção anterior para saber como usar o vLLM para acelerar a geração.

Abaixo está um exemplo de script SLURM para treinar um modelo de 70B com RLOO em vários nós. Este script treina um modelo em 4 nós e usa o 5º nó para geração com 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()

Usando uma função de recompensa personalizada

O RLOOTrainer suporta o uso de funções de recompensa personalizadas em vez de modelos de recompensa densos. Para garantir compatibilidade, sua função de recompensa deve atender aos seguintes requisitos:

As funções de recompensa podem ser chamadas síncronas em Python ou corrotinas assíncronas async def. Quando você fornece várias funções de recompensa assíncronas, elas são aguardadas de forma concorrente (executadas em paralelo via asyncio.gather), de modo que suas latências se sobrepõem.

  1. Argumentos de entrada:

    • A função deve aceitar os seguintes argumentos como palavras-chave:

      • prompts (contém os prompts),
      • completions (contém as completions geradas),
      • completion_ids (contém as conclusões tokenizadas),
      • trainer_state (TrainerState): O estado atual do trainer. Isso pode ser usado para implementar funções de recompensa dinâmicas, como aprendizado por currículo, em que a recompensa é ajustada com base no progresso do treinamento.
      • log_extra: uma função log_extra(column: str, values: list) para adicionar colunas extras à tabela de completions. Veja o Exemplo 6.
      • log_metric: uma função chamável log_metric(name: str, value: float) para registrar métricas escalares como gráficos ao lado de kl, entropy, etc. Veja o Exemplo 6.
      • Todos os nomes de colunas (exceto prompt) que o conjunto de dados pode ter. Por exemplo, se o conjunto de dados contiver uma coluna chamada ground_truth, a função será chamada com ground_truth como argumento de palavra-chave.

      A maneira mais fácil de atender a esse requisito é usar **kwargs na assinatura da função.

    • Dependendo do formato do conjunto de dados, a entrada variará:

  2. Valor de retorno: A função deve retornar uma lista de floats. Cada float representa a recompensa correspondente a uma única conclusão.

Exemplo 1: Recompensar conclusões mais longas

Abaixo está um exemplo de uma função de recompensa para um formato padrão que recompensa conclusões mais longas:

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]

Você pode testá-lo da seguinte forma:

>>> 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]

Exemplo 1.1: Recompensar conclusões mais longas (com base no número de caracteres)

Mesmo que no exemplo anterior, mas desta vez a função de recompensa é baseada no número de caracteres em vez de tokens.

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]

Você pode testá-lo da seguinte forma:

>>> 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]

Exemplo 2: Recompensar conclusões com um formato específico

Abaixo está um exemplo de uma função de recompensa que verifica se a conclusão possui um formato específico. Este exemplo é inspirado na função format reward usada no artigo DeepSeek-R1: Incentivizing Reasoning Capability in LLMs via Reinforcement Learning. Ele foi projetado para um formato conversacional, em que os prompts e as conclusões consistem em mensagens estruturadas.

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]

Você pode testar esta função da seguinte forma:

>>> 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]

Exemplo 3: Recompensar conclusões com base em uma referência

Abaixo está um exemplo de uma função de recompensa que verifica se a conclusão está correta. Este exemplo é inspirado na função de recompensa de precisão usada no artigo DeepSeek-R1: Incentivizing Reasoning Capability in LLMs via Reinforcement Learning. Este exemplo é projetado para o formato padrão, onde o conjunto de dados contém uma coluna chamada 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)]

Você pode testar esta função da seguinte forma:

>>> 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]

Exemplo 4: Funções de recompensa multitarefa

Abaixo está um exemplo de uso de múltiplas funções de recompensa no RLOOTrainer. Neste exemplo, definimos duas funções de recompensa específicas para tarefas: math_reward_func e coding_reward_func. A math_reward_func recompensa problemas de matemática com base na sua correção, enquanto a coding_reward_func recompensa problemas de programação com base em se a solução funciona.

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

Neste exemplo, o math_reward_func e o coding_reward_func são projetados para funcionar com um conjunto de dados misto que contém problemas de matemática e de programação. A coluna task no conjunto de dados é usada para determinar qual função de recompensa aplicar a cada problema. Se não houver uma função de recompensa relevante para uma amostra no conjunto de dados, a função de recompensa retornará None, e o RLOOTrainer continuará com as funções e tarefas válidas. Isso permite que o RLOOTrainer lide com múltiplas funções de recompensa com diferentes aplicabilidades.

Observe que o RLOOTrainer ignorará as recompensas None retornadas pelas funções de recompensa e considerará apenas as recompensas retornadas pelas funções relevantes. Isso garante que o modelo seja treinado nas tarefas relevantes e ignore as tarefas para as quais não há uma função de recompensa relevante.

Exemplo 5: Funções de recompensa assíncronas

Funções de recompensa personalizadas também podem ser definidas como corrotinas async def. Isso é útil se a sua recompensa depender de I/O lento (por exemplo, chamar um serviço remoto). Quando você passa várias funções de recompensa assíncronas, o RLOOTrainer as executa de forma concorrente, de modo que a latência delas se sobrepõe.

Abaixo está um exemplo mínimo de uma função de recompensa assíncrona que simula uma operação limitada por E/S:

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]

Exemplo 6: Registro de colunas e métricas extras

Abaixo está um exemplo de uma função de recompensa que registra colunas extras na tabela de conclusões e métricas escalares como gráficos.

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

Passando a função de recompensa para o treinador

Para usar sua função de recompensa personalizada, passe-a para o RLOOTrainer da seguinte forma:

from trl import RLOOTrainer

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

Você pode passar várias funções de recompensa como uma lista; essa lista pode incluir tanto funções síncronas quanto assíncronas:

from trl import RLOOTrainer

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

e a recompensa será calculada como a soma das recompensas de cada função, ou como a soma ponderada, se reward_weights for fornecido na configuração.

Observe que o RLOOTrainer suporta múltiplas funções de recompensa de diferentes tipos. Consulte a documentação dos parâmetros para mais detalhes.

Treinando Modelos de Visão e Linguagem

O RLOO suporta o treinamento de Vision-Language Models (VLMs) em conjuntos de dados multimodais que contêm tanto texto quanto imagens.

Modelos Suportados

Testado com:

  • Gemma3 — por exemplo, google/gemma-3-4b-it
  • LLaVA-NeXT — por exemplo, llava-hf/llava-v1.6-mistral-7b-hf
  • Qwen2-VL — por exemplo, Qwen/Qwen2-VL-2B-Instruct
  • Qwen2.5-VL — por exemplo, Qwen/Qwen2.5-VL-3B-Instruct
  • SmolVLM2 — por exemplo, HuggingFaceTB/SmolVLM2-2.2B-Instruct

A compatibilidade com todos os VLMs não é garantida. Se você acredita que um modelo deve ser suportado, sinta-se à vontade para abrir uma issue no GitHub — ou, melhor ainda, enviar um pull request com as alterações necessárias.

Início rápido

Use rloo_vlm.py para fazer o fine-tuning de um VLM. Comando de exemplo para treinamento em 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

Dicas de configuração

  • Use LoRA nas camadas de projeção de visão-linguagem
  • Ative a quantização de 4 bits para reduzir o uso de memória
  • VLMs exigem muita memória — comece com tamanhos de lote menores
  • A maioria dos modelos é compatível com o vLLM (modos server e colocate)

Formato do Conjunto de Dados

Cada amostra de treinamento deve incluir:

  • prompt: Texto formatado por meio do modelo de chat do processador
  • image/images: Imagem PIL ou lista de Imagens PIL

O trainer trata automaticamente a conversão de imagem para tensor por meio do processador de imagens do modelo.

RLOOTrainer

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

Parâmetros

  • model (str ou PreTrainedModel ou PeftModel) — Modelo a ser treinado. Pode ser:
    • Uma string, sendo o model id de um modelo pré-treinado hospedado em um repositório de modelos no huggingface.co, ou um caminho para um diretório contendo pesos de modelo salvos usando save_pretrained, por exemplo, './my_model_directory/'. O modelo é carregado usando <ModelArchitecture>.from_pretrained (onde <ModelArchitecture> é derivado da configuração do modelo) com os argumentos de palavra-chave em args.model_init_kwargs. Se dtype não for especificado em args.model_init_kwargs, o padrão é float32. Isso difere de from_pretrained, onde (desde a versão 5 do Transformers) o dtype é inferido a partir da configuração do modelo.
    • Um objeto PreTrainedModel. Somente modelos de linguagem causais são suportados.
    • Um objeto PeftModel. Somente modelos de linguagem causais são suportados.
  • reward_funcs (RewardFunc | list[RewardFunc]) — Funções de recompensa a serem usadas para calcular as recompensas. Para calcular as recompensas, chamamos todas as funções de recompensa com os prompts e as conclusões e somamos as recompensas. Pode ser:
    • Uma única função de recompensa, como:

      • Uma string: o ID do modelo de um modelo pré-treinado hospedado em um repositório de modelos no huggingface.co, ou um caminho para um diretório contendo pesos de modelo salvos usando save_pretrained, por exemplo, './my_model_directory/'. O modelo é carregado usando from_pretrained com num_labels=1 e os argumentos de palavra-chave em args.model_init_kwargs.

      • Um objeto PreTrainedModel: apenas modelos de classificação de sequência são suportados.

      • Uma função de recompensa personalizada: a função recebe os prompts e as conclusões geradas, além de quaisquer colunas adicionais no conjunto de dados. Ela deve retornar uma lista de recompensas. Funções de recompensa personalizadas podem ser síncronas ou assíncronas e também podem retornar None quando a recompensa não se aplica a essas amostras. Isso é útil para treinamento multitarefa, em que diferentes funções de recompensa se aplicam a diferentes tipos de amostras. Quando uma função de recompensa retorna None para uma amostra, essa função de recompensa é excluída do cálculo da recompensa para aquela amostra. Para mais detalhes, consulte Usando uma função de recompensa personalizada.

        O estado do trainer também é passado para a função de recompensa. O estado do trainer é uma instância de TrainerState e pode ser acessado por meio do argumento trainer_state na assinatura da função de recompensa.

    • Uma lista de funções de recompensa, em que cada item pode ser independentemente qualquer um dos tipos acima. A mistura de diferentes tipos dentro da lista (por exemplo, um ID de modelo em string e uma função de recompensa personalizada) é permitida.

  • args (RLOOConfig, opcional) — Configuração para este treinador. Se None, uma configuração padrão é usada.
  • train_dataset (Dataset ou IterableDataset) — Dataset a ser usado para o treinamento. Ele deve incluir uma coluna "prompt". Colunas adicionais no dataset são ignoradas. O formato das amostras pode ser:
    • Padrão: Cada amostra contém texto simples.
    • Conversacional: cada amostra contém mensagens estruturadas (por exemplo, papel e conteúdo).

    Quando train_dataset é um IterableDataset (por exemplo, um dataset em streaming), max_steps deve ser definido nos argumentos de treinamento, pois seu comprimento não pode ser inferido e o número total de etapas de treinamento é necessário para limitar o loop de treinamento e configurar o agendador de taxa de aprendizado.

  • eval_dataset (Dataset, IterableDataset, DatasetDict, IterableDatasetDict ou dict[str, Dataset | IterableDataset]) — Dataset a ser usado para avaliação. Ele deve atender aos mesmos requisitos que train_dataset.
  • processing_class (PreTrainedTokenizerBase, ProcessorMixin, opcional) — Classe de processamento usada para processar os dados. O lado do padding deve ser definido como “left”. Se None, a classe de processamento é carregada a partir do nome do modelo com from_pretrained. Um token de padding, tokenizer.pad_token, deve ser definido. Se a classe de processamento não tiver definido um token de padding, tokenizer.eos_token será usado como padrão.
  • reward_processing_classes (PreTrainedTokenizerBase ou list[PreTrainedTokenizerBase], opcional) — Classes de processamento correspondentes às funções de recompensa especificadas em reward_funcs. Pode ser:
    • Uma única classe de processamento: usada quando reward_funcs contém apenas uma função de recompensa.
    • Uma lista de classes de processamento: deve corresponder à ordem e ao comprimento das funções de recompensa em reward_funcs. Se definido como None, ou se um elemento da lista correspondente a um PreTrainedModel for None, o tokenizer do modelo é carregado automaticamente usando from_pretrained. Para elementos em reward_funcs que são funções de recompensa personalizadas (não PreTrainedModel), as entradas correspondentes em reward_processing_classes são ignoradas.
  • callbacks (lista de TrainerCallback, opcional) — Lista de callbacks para personalizar o loop de treinamento. Adicionará esses à lista de callbacks padrão detalhada aqui.

    Se você deseja remover um dos callbacks padrão utilizados, use o método remove_callback.

  • optimizers (tuple[torch.optim.Optimizer | None, torch.optim.lr_scheduler.LambdaLR | None], opcional, padrão (None, None)) — Uma tupla contendo o otimizador e o agendador a serem usados. Por padrão, será uma instância de AdamW no seu modelo e um agendador dado por get_linear_schedule_with_warmup controlado por args.
  • quantization_config (BitsAndBytesConfig, opcional) — Configuração de quantização usada ao carregar o modelo a partir de um identificador de modelo. Combine com peft_config para treinamento QLoRA. Ignorado se o modelo já estiver instanciado.
  • peft_config (PeftConfig, opcional) — Configuração PEFT usada para envolver o modelo. Se None, o modelo não é envolvido.

Trainer para o método Reinforce Leave One Out (RLOO). Este algoritmo foi inicialmente proposto no artigo Back to Basics: Revisiting REINFORCE Style Optimization for Learning from Human Feedback in LLMs.

Exemplo:

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

treino

< >

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

Parâmetros

  • resume_from_checkpoint (str ou bool, opcional) — Se for um str, caminho local para um checkpoint salvo por uma instância anterior de Trainer. Se for um bool e for igual a True, carrega o último checkpoint em args.output_dir salvo por uma instância anterior de Trainer. Se presente, o treinamento será retomado a partir dos estados do modelo/otimizador/agendador carregados aqui.
  • trial (optuna.Trial ou dict[str, Any], opcional) — A execução do trial ou o dicionário de hiperparâmetros para a busca de hiperparâmetros.
  • ignore_keys_for_eval (list[str], opcional) — Uma lista de chaves na saída do seu modelo (se for um dicionário) que devem ser ignoradas ao coletar previsões para avaliação durante o treinamento.

Retorna

~trainer_utils.TrainOutput

Objeto contendo a contagem de etapas globais, a perda de treinamento e as métricas.

Ponto de entrada principal do treinamento.

save_model

< >

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

Salvará o modelo, para que você possa recarregá-lo usando from_pretrained().

Salvará apenas a partir do processo principal.

push_to_hub

< >

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

Parâmetros

  • commit_message (str, opcional, padrão "End of training") — Mensagem a ser commitada durante o push.
  • blocking (bool, opcional, padrão True) — Se a função deve retornar apenas quando o git push tiver terminado.
  • token (str, opcional, padrão None) — Token com permissão de escrita para sobrescrever os argumentos originais do Trainer.
  • revision (str, opcional) — A revisão git de onde o commit será feito. O padrão é o topo do ramo “main”.
  • kwargs (dict[str, Any], opcional) — Argumentos de palavra-chave adicionais passados para ~Trainer.create_model_card.

Envie self.model e self.processing_class para o hub de modelos do 🤗 no repositório self.args.hub_model_id.

RLOOConfig

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

Parâmetros que controlam o modelo e o modelo de referência

  • model_init_kwargs (str ou dict[str, Any], opcional) — Argumentos de palavra-chave para from_pretrained, usados quando o argumento model do RLOOTrainer é fornecido como uma string. O valor de revision também é usado ao carregar as classes de processamento.
  • trust_remote_code (bool, opcional, padrão False) — Se permite carregar modelos e tokenizers que incluem código Python personalizado do Hub. Encaminhado para from_pretrained e from_pretrained. Também aplicado a cargas de reward-model e reward-tokenizer.
  • router_aux_loss_coef (float, opcional) — Coeficiente da perda auxiliar de balanceamento de carga para modelos Mixture-of-Experts (MoE), adicionada à perda de treinamento com esse peso. Quando não definido, o valor declarado na configuração do modelo é utilizado. Defina como 0.0 para desativá-la. Falha quando usado com um modelo não-MoE.
  • disable_dropout (bool, opcional, padrão False) — Se deve desabilitar o dropout no modelo. Isso é útil para treinar com um modelo de referência, pois impede que o modelo gere logprobs diferentes para a mesma entrada.

Parâmetros que controlam o pré-processamento dos dados

  • remove_unused_columns (bool, opcional, padrão False) — Se deve manter apenas a coluna "prompt" no conjunto de dados. Se você usar uma função de recompensa personalizada que requer qualquer coluna além de "prompts" e "completions", deve manter isso como False.
  • num_generations (int, opcional, padrão é 2) — Número de gerações por prompt a amostrar. O tamanho efetivo do lote (num_processes * per_device_batch_size * gradient_accumulation_steps) deve ser divisível por este valor.
    • gradient_accumulation_steps) deve ser divisível por este valor.
  • num_generations_eval (int, opcional) — Número de gerações a amostrar durante a avaliação. Isso permite usar menos gerações durante a avaliação para economizar computação. Se None, usa o valor de num_generations.
  • max_completion_length (int ou None, opcional, padrão 512) — Comprimento máximo da conclusão gerada.
  • ds3_gather_for_generation (bool, opcional, padrão True) — Esta configuração se aplica ao DeepSpeed ZeRO-3. Se habilitado, os pesos do modelo de política são reunidos para a geração, melhorando a velocidade de geração. No entanto, desabilitar esta opção permite treinar modelos que excedem a capacidade de VRAM de uma única GPU, embora com o custo de uma geração mais lenta. Desabilitar esta opção não é compatível com a geração do vLLM.
  • shuffle_dataset (bool, opcional, padrão True) — Se deve embaralhar o conjunto de dados de treinamento.
  • pad_to_multiple_of (int ou str, opcional, padrão "auto") — Se definido, os ids dos prompts e dos completions serão preenchidos até um múltiplo deste valor. "auto" preenche até um múltiplo de 128 no Neuron (AWS Trainium), que compila uma vez por forma de entrada, e não preenche em outros ambientes.

Parâmetros que controlam a geração

  • generation_batch_size (int, opcional) — Tamanho do lote a ser usado para a geração. Se for None, o valor padrão é o tamanho efetivo do lote de treinamento: per_device_train_batch_size * num_processes * steps_per_generation. Em outras palavras, há um lote de geração processado por etapa de otimização. Exclusivo mutuamente com steps_per_generation.
  • steps_per_generation (int, opcional) — Número de etapas por geração. Se None, o valor padrão é gradient_accumulation_steps. Exclusivo com generation_batch_size.
  • temperature (float, opcional, padrão 1.0) — Temperatura para amostragem. Quanto maior a temperatura, mais aleatórias são as conclusões.
  • top_p (float, opcional, padrão 1.0) — Float que controla a probabilidade cumulativa dos tokens principais a serem considerados. Deve estar em (0, 1]. Defina como 1.0 para considerar todos os tokens.
  • top_k (int, opcional, padrão 0) — Número de tokens do vocabulário com maior probabilidade a serem mantidos para o filtro top-k. Se 0, o filtro top-k é desativado e todos os tokens são considerados.
  • min_p (float, opcional) — Probabilidade mínima do token, que será escalada pela probabilidade do token mais provável. Deve ser um valor entre 0.0 e 1.0. Valores típicos estão na faixa de 0.01-0.2.
  • generation_kwargs (dict[str, Any], opcional) — Argumentos de palavra-chave adicionais para passar ao GenerationConfig (se estiver usando transformers) ou SamplingParams (se estiver usando vLLM) ao amostrar as conclusões. Isso pode ser usado para personalizar ainda mais o comportamento da geração, como definir suppress_tokens, num_beams, etc. Se contiver chaves que conflitam com os outros parâmetros de geração (como min_p, top_p, etc.), eles os substituirão.
  • chat_template_kwargs (dict[str, Any], opcional) — Argumentos de palavra-chave adicionais para passar à função apply_chat_template ao gerar completions.
  • repetition_penalty (float, opcional, padrão 1.0) — Float que penaliza novos tokens com base em sua presença no prompt e no texto gerado até o momento. Valores > 1.0 incentivam o modelo a usar novos tokens, enquanto valores < 1.0 incentivam o modelo a repetir tokens.
  • cache_implementation (str, opcional) — Implementação do método de cache para uma geração mais rápida quando use_vllm está definido como False.

Parâmetros que controlam a aceleração da geração com vLLM

  • use_vllm (bool, opcional, padrão False) — Se deve usar o vLLM para gerar completions. Se definido como True, o trainer usará o vLLM para geração em vez do padrão model.generate(). Requer que vllm esteja instalado.
  • vllm_mode (str, opcional, padrão é "colocate") — Modo a ser usado para a integração com o vLLM quando use_vllm está definido como True. Deve ser um dos valores "server" ou "colocate".
    • "server": O trainer enviará solicitações de geração para um servidor vLLM separado. Certifique-se de que um servidor vLLM está em execução (inicie com vllm serve).
    • "colocate": o vLLM será executado no mesmo processo e compartilhará as GPUs de treinamento. Isso evita a necessidade de um servidor separado, mas pode causar contenda de recursos com o treinamento.
  • vllm_model_impl (str, opcional, padrão "vllm") — Implementação do modelo a ser usada para o vLLM. Deve ser uma das opções "transformers" ou "vllm". "transformers": Use o backend transformers para a implementação do modelo. "vllm": Use a biblioteca vllm para a implementação do modelo.
  • vllm_enable_sleep_mode (bool, opcional, padrão False) — Ativa o modo de suspensão do vLLM para descarregar pesos/cache durante o passo do otimizador. Mantém o uso de memória da GPU baixo, mas acordar o mecanismo adiciona latência de transferência entre host e dispositivo.
  • vllm_structured_outputs_regex (str, opcional) — Regex para saídas estruturadas do vLLM. Se None (padrão), as saídas estruturadas ficam desativadas.

Parâmetros que controlam o servidor vLLM (usados apenas quando `vllm_mode` é `"server"`)

  • vllm_server_base_url (str, opcional) — URL base para o servidor vLLM (por exemplo, "http://localhost:8000"). Se fornecida, vllm_server_host e vllm_server_port são ignorados.
  • vllm_server_host (str, opcional, padrão "0.0.0.0") — Host do servidor vLLM para conexão. Ignorado se vllm_server_base_url for fornecido.
  • vllm_server_port (int, opcional, padrão 8000) — Porta do servidor vLLM para conexão. Ignorado se vllm_server_base_url for fornecido.
  • vllm_server_timeout (float, opcional, padrão 240.0) — Duração total do tempo limite, em segundos, para aguardar que o servidor vLLM esteja ativo. Se o servidor não estiver ativo após o tempo limite, um ConnectionError será lançado.
  • vllm_group_port (int, opcional, padrão 51216) — Número da porta para o grupo de atualização de pesos. Isso é usado para se comunicar com o servidor vLLM. A menos que a porta esteja ocupada, não há necessidade de alterá-la.

Parâmetros que controlam a execução do vLLM co-localizado (usados apenas quando `vllm_mode` é `"colocate"`)

  • vllm_gpu_memory_utilization (float, opcional, padrão 0.3) — Controla a utilização de memória de GPU para o vLLM. Esta configuração só se aplica quando vllm_mode está definido como "colocate". Se você estiver usando vllm_mode="server", este parâmetro deve ser passado separadamente ao iniciar o servidor vLLM por meio da flag --vllm_gpu_memory_utilization.
  • vllm_max_model_length (int, opcional) — Janela de contexto para o vLLM. Defina-a com pelo menos o comprimento máximo do prompt no conjunto de dados mais max_completion_length; se omitida, ela é inferida a partir da configuração do modelo.
  • vllm_tensor_parallel_size (int, opcional, padrão 1) — Controla o tamanho da paralelização de tensor para o vLLM. Essa configuração só se aplica quando vllm_mode está definido como "colocate". Se você estiver usando vllm_mode="server", este parâmetro deve ser passado separadamente ao iniciar o servidor vLLM por meio da flag --vllm_tensor_parallel_size.

Parâmetros que controlam o treinamento

  • beta (float, opcional, padrão 0.05) — Coeficiente KL. Se for 0.0, o modelo de referência não é carregado, o que reduz o uso de memória e melhora a velocidade de treinamento.
  • num_iterations (int, opcional, padrão 1) — Número de iterações por lote (denotado como μ no algoritmo).
  • epsilon (float, opcional, padrão 0.2) — Valor para o recorte (clipping).
  • epsilon_high (float, opcional) — Valor superior de epsilon para o recorte. Se não for especificado, o valor padrão será o mesmo do limite inferior especificado no argumento epsilon. O paper DAPO recomenda 0.28.
  • reward_weights (list[float], opcional) — Pesos para cada função de recompensa. Deve corresponder ao número de funções de recompensa. Se None, todas as recompensas são ponderadas igualmente com peso 1.0.
  • normalize_advantages (bool, opcional, padrão False) — Se as vantagens devem ser normalizadas. A normalização é feita por lote de geração para ter média 0.0 e desvio padrão de 1.0.
  • reward_clip_range (tuple[float, float], opcional) — Intervalo de recorte para recompensas como (mínimo, máximo). Se None, nenhum recorte é aplicado.
  • mask_truncated_completions (bool, opcional, padrão False) — Quando habilitado, as conclusões truncadas são excluídas do cálculo da perda, evitando que sejam penalizadas incorretamente e introduzam ruído durante o treinamento. De acordo com o DAPO, essa é uma boa prática para a estabilidade do treinamento.
  • sync_ref_model (bool, opcional, padrão False) — Se deve sincronizar o modelo de referência com o modelo ativo a cada ref_model_sync_steps passos, usando o parâmetro ref_model_mixup_alpha. Essa sincronização origina-se do artigo TR-DPO.
  • ref_model_mixup_alpha (float, opcional, padrão 0.6) — parâmetro α do paper TR-DPO, que controla a mistura entre a política atual e a política de referência anterior durante as atualizações. A política de referência é atualizada de acordo com a equação: π_ref = α * π_θ + (1 - α) * π_ref_prev. Para usar este parâmetro, você deve definir sync_ref_model=True.
  • ref_model_sync_steps (int, opcional, padrão 512) — parâmetro τ do paper TR-DPO, que determina a frequência com que a política atual é sincronizada com a política de referência. Para usar este parâmetro, você deve definir sync_ref_model=True.

Parâmetros que controlam o registro de logs

  • log_completions (bool, opcional, padrão False) — Se deve registrar uma amostra de pares (prompt, completion) a cada logging_steps passos. Se o rich estiver instalado, ele imprime a amostra. Se o registro do wandb e/ou do trackio estiver habilitado, ele registra a amostra no wandb e/ou no trackio.
  • log_multimodal (bool, opcional, padrão True) — Se deve registrar conteúdo multimodal (imagens, vídeos, etc.) junto com as conclusões. Desative isso para reduzir o tamanho do log ao usar dados multimodais de alta resolução.
  • num_completions_to_print (int, opcional) — Número de conclusões a serem exibidas com rich. Se None, todas as conclusões são registradas.
  • log_unique_prompts (bool, opcional, padrão False) — Se deve registrar prompts únicos. Se True, apenas prompts únicos são registrados. Se False, todos os prompts são registrados.

Parâmetros que controlam a aceleração da geração com o continuous batching do Transformers

  • use_transformers_continuous_batching (bool, opcional, padrão False) — Se deve usar o motor de continuous batching do transformers para gerar completions. Requer transformers>=5.8.0.
  • transformers_continuous_batching_config (dict, opcional) — Argumentos de palavra-chave para ContinuousBatchingConfig.

Parâmetros obsoletos

  • use_transformers_paged —

    O parâmetro use_transformers_paged está obsoleto e será removido na versão v2.0.0. Use use_transformers_continuous_batching em vez disso.

Classe de configuração para o RLOOTrainer.

Esta classe inclui apenas os parâmetros específicos para o treinamento RLOO. Para a lista completa de argumentos de treinamento, consulte a documentação de TrainingArguments. Observe que os valores padrão nesta classe podem diferir daqueles em TrainingArguments.

Usando HfArgumentParser, podemos transformar essa classe em argumentos argparse que podem ser especificados na linha de comando.

Esses parâmetros possuem valores padrão diferentes de TrainingArguments:

  • logging_steps: O valor padrão é 10 em vez de 500.
  • gradient_checkpointing: O padrão é True em vez de False.
  • bf16: Padrão é True se fp16 não estiver definido, em vez de False.
  • learning_rate: O valor padrão é 1e-6 em vez de 5e-5.

Referências

  1. Artigo RLOO
  2. Artigo Back to Basics: Revisitando a Otimização no Estilo REINFORCE para Aprendizado a partir de Feedback Humano em LLMs
  3. Artigo - REINFORCE++: Uma abordagem simples e eficiente para alinhar grandes modelos de linguagem
  4. Post no blog - Colocando RL de volta no RLHF
  5. Post no blog - Desvendando o RLHF e suas variantes: avanços e insights práticos de engenharia
  6. Youtube - RLOO: Uma otimização de baixo custo para aprendizado com feedback humano em LLMs

Guia de migração da implementação antiga (0.21 e anteriores)

Com o lançamento da versão 0.22.0, reformulamos o RLOOTrainer para que ele esteja mais alinhado com outros treinadores online da biblioteca, como o GRPOTrainer. Esta nova implementação introduz várias alterações nos parâmetros de configuração e na estrutura geral do treinador. Abaixo está um resumo das principais alterações para o RLOOConfig:

TRL ≤ 0.21.xTRL ≥ 0.22.0
rloo_krenomeado para num_generations
cliprangerenomeado para epsilon
kl_coefrenomeado para beta
exp_namerenomeado para run_name. Use run_name = f"{exp_name}__{seed}__{int(time.time())}" para replicar o comportamento antigo
normalize_rewardrenomeado para normalize_advantages. Observação: isso sempre normalizava as vantagens (apesar do nome antigo)
num_ppo_epochsrenomeado para num_iterations (padrão: 1)
token_level_klremovido – o KL agora é calculado apenas no nível da sequência
dataset_num_procremovido – não era utilizado
num_mini_batchesrenomeado para steps_per_generation
total_episodesuse max_steps=total_episodes / gradient_accumulation_steps em vez disso
local_rollout_forward_batch_sizeremovido – agora definido automaticamente como per_device_train_batch_size (ou per_device_eval_batch_size durante a avaliação)
num_sample_generationsremovido – use logging_steps para controlar a frequência de registro de logs da geração
response_lengthrenomeado para max_completion_length (padrão: 512)
stop_tokenremovido
stop_token_idremovido – use processing_class.eos_token_id no lugar
missing_eos_penaltyremovido – replicar com uma função de recompensa personalizada que verifica se eos_token_id está em completion_ids

Abaixo está um resumo das principais alterações para o RLOOTrainer:

TRL ≤ 0.21.xTRL ≥ 0.22.0
configrenomeado para args
reward_modelrenomeado para reward_funcs, que agora suporta tanto modelos de recompensa quanto funções de recompensa personalizadas
policyrenomeado para model
ref_policyremovido – o modelo de referência agora é criado automaticamente a partir de model
data_collatorremovido
Update on GitHub