RLVR: Optimización de Modelos de Lenguaje mediante Recompensas Verificables

Análisis de la transición de RLHF a RLVR (Reinforcement Learning with Verifiable Rewards) para tareas de razonamiento complejo. Se examina la formulación matemática de funciones de recompensa, la implementación de entornos de verificación de código/matemáticas y el impacto en la precisión técnica.

Hasta 2023-2024, el estándar para alinear modelos de lenguaje (LLMs) fue RLHF (Reinforcement Learning from Human Feedback). Este enfoque entrena un Reward Model basado en preferencias humanas para guiar la política del modelo. Sin embargo, RLHF presenta problemas críticos en tareas de razonamiento: el ruido en el etiquetado humano y la dificultad de los anotadores para verificar cadenas de pensamiento complejas (math/coding errors).

RLVR (Reinforcement Learning with Verifiable Rewards) aborda este problema eliminando el proxy humano en dominios donde existe una "verdad fundamental" (ground truth). En lugar de predecir qué respuesta "parece" mejor, el sistema ejecuta el código generado o verifica la solución matemática contra un solver formal.

RLVR se ha convertido en el mecanismo estándar para entrenar modelos de "Sistema 2" (modelos de razonamiento lento), permitiendo que la señal de recompensa provenga directamente de la correctitud del resultado, mitigando la alucinación en lógica y sintaxis.


Fundamentos matemáticos

El objetivo fundamental de RLVR es maximizar la recompensa esperada, sujeta a una restricción de divergencia KL para evitar que el modelo se aleje excesivamente de su distribución base (pre-entrenada o SFT).

La función objetivo se define como:

$$J(\theta) = \mathbb{E}_{x \sim D, y \sim \pi_\theta(\cdot|x)} \left[ R(x, y) - \beta \log \frac{\pi_\theta(y|x)}{\pi_{\text{ref}}(y|x)} \right]$$

Donde:

  • $\pi_\theta$: Política del modelo que se está optimizando.
  • $\pi_{\text{ref}}$: Modelo de referencia (generalmente el modelo tras Supervised Fine-Tuning).
  • $D$: Dataset de prompts (problemas matemáticos o especificaciones de código).
  • $\beta$: Coeficiente de penalización KL.

La diferencia crítica respecto a RLHF radica en la función de recompensa $R(x, y)$. En RLHF, $R$ es una red neuronal que aproxima la preferencia humana. En RLVR, $R$ es una función determinista o semi-determinista definida por un oráculo de verificación:

$$R(x, y) = \begin{cases} 1 & \text{si } \text{verify}(y, \text{solution}_x) = \text{True} \\ 0 & \text{si } \text{verify}(y, \text{solution}_x) = \text{False} \end{cases}$$

Para tareas complejas que requieren múltiples pasos de razonamiento (Chain of Thought), la recompensa suele ser dispersa (sparse). Para mitigar esto, se utilizan estimadores de valor o Outcome Reward Models (ORM) combinados con Process Reward Models (PRM) verificables, donde la ventaja $A_t$ en el algoritmo PPO se calcula como:

$$A_t = \sum_{k=0}^{K} \gamma^k r_{t+k} - V_\phi(s_t)$$

En RLVR puro, $r_t$ suele ser 0 para todos los pasos intermedios excepto el final, lo que fuerza la necesidad de exploración eficiente (temperatura alta o search trees durante el entrenamiento).


Implementación práctica

La implementación de un ciclo RLVR requiere un entorno de ejecución (sandbox) para validar las respuestas. A continuación se presenta un esquema de implementación en Python utilizando una lógica simplificada de PPO con un verificador de código.

Componentes:

  1. Generator (Actor): LLM a optimizar.
  2. Environment: Sandbox que ejecuta código Python generado.
  3. Algorithm: PPO loop.
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from trl import PPOTrainer, PPOConfig

# 1. Configuración del modelo y referencia
model_id = "modelo-reasoning-base-2025"
model = AutoModelForCausalLM.from_pretrained(model_id, device_map="auto")
ref_model = AutoModelForCausalLM.from_pretrained(model_id, device_map="auto")
tokenizer = AutoTokenizer.from_pretrained(model_id)

# 2. Función de Recompensa Verificable (Oráculo)
def verifiable_reward(generated_code, expected_output):
    """
    Ejecuta el código generado en un entorno aislado y compara la salida.
    Retorna 1.0 si es correcto, -0.5 si hay error de sintaxis, 0.0 si es incorrecto.
    """
    try:
        # Nota: En producción usar sandbox robusto (e.g., gVisor, Docker)
        exec_globals = {}
        exec(generated_code, {}, exec_globals)
        result = exec_globals.get('result', None)
        
        if abs(result - expected_output) < 1e-5:
            return 1.0
        else:
            return 0.0
    except SyntaxError:
        return -0.5
    except Exception:
        return 0.0

# 3. Loop de Entrenamiento (Simplificado)
ppo_config = PPOConfig(batch_size=16, learning_rate=1.4e-5)
ppo_trainer = PPOTrainer(ppo_config, model, ref_model, tokenizer)

# Datos de ejemplo: problema y solución numérica esperada
prompts = ["Calcula la raíz cuadrada de 144 más 10.", ...]
targets = [22.0, ...]

for epoch in range(ppo_config.ppo_epochs):
    # Generación de rollouts
    query_tensors = [tokenizer(p, return_tensors="pt").input_ids[0] for p in prompts]
    response_tensors = ppo_trainer.generate(query_tensors, max_new_tokens=128)
    
    batch_rewards = []
    for q, r, target in zip(prompts, response_tensors, targets):
        # Decodificar respuesta y extraer código (parsing)
        resp_text = tokenizer.decode(r)
        code_block = extract_code(resp_text) # Función auxiliar de parsing
        
        # Calcular recompensa determinista
        reward_score = verifiable_reward(code_block, target)
        batch_rewards.append(torch.tensor(reward_score))
    
    # Paso de optimización PPO
    stats = ppo_trainer.step(query_tensors, response_tensors, batch_rewards)
    print(f"Epoch {epoch}: Mean Reward {stats['ppo/mean_scores']}")

Aquí podemos observar el diagrama del algoritmo PPO loop:


Análisis de comportamiento

Al desplegar RLVR en entornos de producción, se observan patrones distintos a los de RLHF:

  • Problema de "Cold Start": Si el modelo base no tiene capacidad suficiente para generar una respuesta correcta ocasionalmente, la recompensa será constantemente 0 (o negativa). El gradiente no provee dirección útil. Es necesario un Warmup mediante Supervised Fine-Tuning (SFT) fuerte en trazas de razonamiento correctas (CoT).
  • Reward Hacking Sintáctico: El modelo puede aprender a explotar debilidades del verificador. Por ejemplo, si el verificador chequea la presencia de una variable final_answer, el modelo podría definir la variable con el valor correcto "hardcodeado" sin realizar el razonamiento lógico, si los casos de prueba no son suficientemente variados.
  • Estabilidad Numérica: Debido a la naturaleza binaria de la recompensa (correcto/incorrecto), la varianza en la estimación de la ventaja es alta. El uso de Group Relative Policy Optimization (GRPO) ayuda a estabilizar el entrenamiento normalizando las recompensas dentro de un grupo de generaciones para el mismo prompt.

Comparativas técnicas

A continuación se compara RLVR contra el enfoque clásico de RLHF para tareas de generación de código (benchmarks tipo HumanEval+ o MBPP).

Métrica RLHF (Preference based) RLVR (Verifiable based)
Señal de Recompensa Ruidosa (modelo aproximado) Exacta (ejecución real)
Coste de Anotación Alto (requiere humanos/LLM jueces) Bajo (computacional)
Pass@1 (Code) ~45-60% (estancamiento) ~75-85% (mejora continua)
Robustez Tiende a favorecer respuestas "convincentes" pero erróneas. Favorece respuestas funcionalmente correctas.
Compute Cost Medio (Inferencia RM) Alto (Ejecución de código en loop)

Limitaciones y casos donde no conviene usarlo

RLVR no es una solución universal. Su aplicación es contraproducente en los siguientes escenarios:

  1. Tareas Subjetivas: En escritura creativa, resumen de textos o chat general, no existe una función verify() objetiva. Intentar aplicar RLVR aquí requiere definir métricas heurísticas (longitud, palabras clave) que degradan rápidamente la calidad del texto (Goodhart’s Law).
  2. Verificación Costosa: Si la función de verificación tarda segundos o minutos en ejecutarse (ej. simulaciones físicas complejas), el ciclo de entrenamiento se vuelve computacionalmente inviable.
  3. Especificación Incompleta: Si los casos de prueba (unit tests) no cubren todos los edge cases, RLVR sobreajustará el modelo para pasar esos tests específicos, rompiendo la generalización para inputs no vistos (overfitting a la suite de tests).