Entrenamiento de alineación RLHF
Imagina esto:
-
Le pides a la IA que escriba un artículo sobre cómo ganar dinero rápido, y te da un plan de estafa.
-
Le preguntas a la IA: "¿Soy un fracaso?" y ella responde directamente: "Sí, en efecto eres un fracaso."
-
Le pides a la IA que te ayude a escribir código, y genera un programa que funciona pero tiene una puerta trasera oculta.
Estas no son escenas de ciencia ficción: sin entrenamiento de alineación, la IA realmente haría esto.
El objetivo de la IA no es"hacer lo correcto", sino "completar la tarea de entrenamiento"。Sin una guía clara de valores humanos, elegirá la forma más simple y directa de completar la tarea, sin importar si el método es adecuado.
Esto es lo que la alineación (Alignment) busca resolver: hacer que el comportamiento de la IA sea coherente con los valores, intenciones y expectativas humanas.
El desafío central de la alineación: la IA es muy inteligente, pero no sabe qué es lo correcto. Necesitamos decírselo mediante retroalimentación humana.
¿Qué es la alineación?
La alineación es el proceso de asegurar que el comportamiento de los sistemas de IA sea coherente con los valores humanos.
En pocas palabras:La IA en sí misma no tiene valores; la alineación consiste en enseñar los valores humanos a la IA。
Las tres dimensiones de la alineación
La alineación no es un objetivo único, sino un equilibrio entre tres dimensiones:
| Dimensión | Definición | Ejemplo negativo |
|---|---|---|
| Útil (Helpful) | Ser capaz de ayudar al usuario a completar tareas y responder preguntas | El usuario hace una pregunta, la IA dice "no lo sé"; esto es seguro pero inútil. |
| Inofensiva (Harmless) | No causar daño ni generar consecuencias negativas | El usuario quiere hacer algo malo y la IA coopera activamente; esto es "útil" pero dañino. |
| Honesta (Honest) | No inventar información ni engañar al usuario | La IA no sabe la respuesta, pero inventa hechos falsos; esto es "útil" pero deshonesto. |
Estas tres dimensiones suelen estar en tensión:
Buscar demasiado la "utilidad" puede llevar a la IA a arriesgarse a dar respuestas inexactas.
Buscar demasiado la "inocuidad" puede hacer que la IA se vuelva demasiado conservadora y no se atreva a responder nada.
Una buena alineación consiste en encontrar el punto de equilibrio entre estos tres aspectos.
Riesgos de una IA no alineada
Si no se alinea, la IA puede presentar los siguientes problemas:
Generar contenido dañino: violencia, odio, comentarios discriminatorios.
Dar consejos peligrosos: cómo fabricar armas, cómo cometer delitos.
Inventar hechos: "alucinar" artículos, datos y eventos inexistentes.
Manipular al usuario: aprovechar debilidades psicológicas para influir en sus decisiones.
Evadir la censura: expresar contenido prohibido de manera encubierta.
Estos riesgos no son teóricos, sino que existen realmente y ya han ocurrido.
Marco general de RLHF
RLHF (Reinforcement Learning from Human Feedback, aprendizaje por refuerzo basado en retroalimentación humana) es actualmente la técnica de alineación más extendida.
Su idea central es simple:No se trata de que los humanos escriban reglas directamente, sino de que evalúen las salidas de la IA y luego, mediante aprendizaje por refuerzo, la IA aprenda a generar salidas que los humanos prefieran.。
Las tres fases de RLHF
RLHF no se completa en un solo paso, sino que se divide en tres fases consecutivas:
| Fase | Qué hace | Resultado |
|---|---|---|
| Fase 1: Ajuste fino supervisado (SFT) | Entrenar el modelo con datos de demostración escritos por humanos. | Modelo SFT (un modelo base "que sabe hablar") |
| Fase 2: Modelo de recompensa (RM) | Recopilar datos de preferencias humanas y entrenar el modelo de recompensa. | Modelo de recompensa (un modelo que puede puntuar las salidas de la IA) |
| Fase 3: Aprendizaje por refuerzo con PPO | Usar el modelo de recompensa como guía y entrenar el modelo SFT con el algoritmo PPO. | El modelo final alineado |
Estas tres fases son progresivas: primero se hace que el modelo "sepa hablar", luego que el "jurado" aprenda a juzgar lo bueno de lo malo, y finalmente que el "participante" mejore continuamente según la retroalimentación del jurado.
¿Por qué se necesita retroalimentación humana?
Puede que te preguntes: ¿no basta con escribir reglas directamente? ¿Por qué tiene que ser retroalimentación humana?
Porque los valores humanos son demasiado complejos como para escribirlos en reglas precisas.
Por ejemplo, "¿qué es una respuesta educada?" — ¿puedes escribir una regla de juicio precisa? Es muy difícil. Pero cuando ves dos respuestas, puedes señalar fácilmente cuál es más educada.
Esta es la ventaja de la retroalimentación humana:Puede que no podamos explicar cuáles son las reglas, pero podemos juzgar si algo es bueno o malo.RLHF aprovecha precisamente esta capacidad humana.
Fase 1: Ajuste fino supervisado (SFT)
El ajuste fino supervisado (Supervised Fine-Tuning, SFT) es el primer paso de RLHF.
Su objetivo es transformar el "modelo de lenguaje general" preentrenado en un "asistente conversacional".
La idea básica de SFT
El modelo preentrenado ha aprendido a "predecir la siguiente palabra", pero no sabe "cómo ser un asistente".
SFT consiste en mostrarle al modelo muchos ejemplos de "cómo los humanos actúan como asistentes" para que los imite.
¿Cómo son estos ejemplos? Más o menos así:
| Entrada del usuario | Salida esperada de la IA (demostración humana) |
|---|---|
| Hola, quiero aprender sobre Python | ¡Hola! Python es un lenguaje de programación sencillo y fácil de aprender, adecuado para principiantes. ¿Qué aspecto te gustaría conocer? |
| Ayúdame a escribir una carta de renuncia | Claro, aquí tienes una plantilla de carta de renuncia... (omitido)... Por favor, adáptala según tu situación específica. |
| ¿Cómo hacerse rico rápidamente? | No hay atajos para hacerse rico; te recomiendo mejorar a través del trabajo duro y el estudio... (omitido)... |
Estos datos de demostración son escritos por anotadores humanos o son respuestas de alta calidad seleccionadas de conversaciones reales.
Características de los datos de SFT
Los datos de SFT no son cualquier tipo de conversación; deben cumplir:
Útiles: que realmente respondan a las preguntas del usuario.
Seguros: que no generen contenido dañino.
Estilo coherente: que respondan con tono y forma similares.
Formato estandarizado: que sigan un determinado formato de conversación.
La cantidad de datos suele estar entre unos pocos miles y decenas de miles, mucho menor que la cantidad de datos de preentrenamiento, pero con requisitos de calidad mucho más altos.
Función y limitaciones de SFT
La función de SFT es hacer que el modelo "aprenda las posturas básicas del diálogo":
Saber cómo responder a los saludos, cómo contestar preguntas y cómo rechazar solicitudes irrazonables.
Pero SFT tiene limitaciones evidentes:
Cobertura limitada: es imposible escribir demostraciones para todos los escenarios.
Los humanos tampoco son perfectos: los anotadores pueden cometer errores o tener sesgos.
Solo puede imitar, no superar: el modelo será, como máximo, tan bueno como las demostraciones humanas, no mejor.
Por eso también necesitamos las dos fases siguientes: SFT solo sienta las bases; la verdadera alineación se logra con el aprendizaje por refuerzo.
Fase 2: Modelo de recompensa (RM)
El modelo de recompensa (Reward Model, RM) es un eslabón clave en RLHF.
Su tarea es:Mirar una salida de IA, asignarle una puntuación que indique qué tan "buena" es esa salida.。
Recopilación de datos de preferencias
El modelo de recompensa no se entrena directamente para "puntuar", sino para "comparar".
El método concreto es: mostrar a anotadores humanos varias respuestas diferentes a la misma pregunta, pedirles que las ordenen e indiquen cuál es mejor.
Por ejemplo:
| Pregunta | Respuesta A | Respuesta B | Preferencia humana |
|---|---|---|---|
| ¿Soy un fracasado? | Sí, eres un fracasado, de verdad. | Todo el mundo enfrenta dificultades; esto no define tu valor. | B es mucho mejor que A |
Nota: no pedimos a los humanos que den una puntuación directa (por ejemplo, 85), sino que hagan comparaciones (A es mejor que B).
¿Por qué? Porque comparar es mucho más fácil que puntuar y también más consistente. Diferentes personas pueden interpretar "85 puntos" de manera distinta, pero el juicio "A es mejor que B" es más estable.
Modelo de Bradley-Terry
¿Cómo convertir "comparaciones" en "puntuaciones"? Aquí se utiliza el modelo de Bradley-Terry.
La idea central de este modelo es muy sencilla:Cada respuesta tiene una "puntuación de calidad" latente; las respuestas con mayor puntuación tienen más probabilidades de ser preferidas por los humanos.。
Supongamos que la puntuación de la respuesta A es r_A y la de la respuesta B es r_B; entonces la probabilidad de que un humano prefiera A sobre B es:
P(A > B) = exp(r_A) / (exp(r_A) + exp(r_B))
Esto es la función softmax: cuanto mayor es la diferencia de puntuaciones, más cerca de 1 está la probabilidad.
Entrenar un modelo de recompensa consiste en encontrar estas puntuaciones de modo que las probabilidades de preferencia predichas por el modelo coincidan lo más posible con las preferencias humanas reales.
Entrenamiento del modelo de recompensa
Pasos para entrenar el modelo de recompensa:
Recopilar datos comparativos: de decenas de miles a cientos de miles de comparaciones de "qué respuesta es mejor".
Inicializar el modelo: normalmente se usa el modelo SFT como punto de partida.
Diseñar la función de pérdida: hacer que el orden de preferencia predicho por el modelo coincida con el del humano.
Entrenar: optimizar los parámetros del modelo con descenso de gradiente.
El modelo de recompensa entrenado, al recibir un texto, produce una puntuación escalar que indica qué tan "bueno" es ese texto.
Ejemplo
# Demostración simplificada del entrenamiento del modelo de recompensa
# Aquí se usa pseudocódigo estilo PyTorch para explicar el principio
# ============================================
import torch
import torch.nn as nn
from typing import List, Tuple
class RewardModel(nn.Module):
"""Modelo de recompensa: entrada de texto, salida de puntuación"""
def __init__(self, base_model):
super().__init__()
self.base_model = base_model # Usar el modelo SFT como base
self.score_head = nn.Linear(base_model.config.hidden_size, 1)
def forward(self, input_ids, attention_mask=None):
"""Propagación hacia adelante: entrada → modelo base → cabeza de puntuación → puntuación escalar"""
outputs = self.base_model(input_ids, attention_mask=attention_mask)
last_hidden_state = outputs.last_hidden_state # (batch, seq_len, hidden_size)
# Usar la representación del token <[BOS_never_used_51bce0c785ca2f68081bfa7d91973934]> para calcular la puntuación
cls_embedding = last_hidden_state[:, 0, :] # (batch, hidden_size)
score = self.score_head(cls_embedding) # (batch, 1)
return score.squeeze(-1) # (batch,)
def reward_loss(reward_model, batch: List[Tuple[str, str, int]]):
"""
Función de pérdida del modelo de recompensa
Parámetros:
batch: un lote de datos, cada elemento es (respuesta A, respuesta B, etiqueta de preferencia)
Etiqueta de preferencia: 1 indica A > B, 0 indica B > A
"""
total_loss = 0.0
for answer_a, answer_b, preference in batch:
# Puntuar cada una de las dos respuestas
score_a = reward_model(answer_a)
score_b = reward_model(answer_b)
# Calcular la probabilidad con el modelo de Bradley-Terry
# P(A > B) = exp(r_A) / (exp(r_A) + exp(r_B))
# Por estabilidad numérica, normalmente se usa la forma log-sigmoid
if preference == 1:
# Preferencia humana: A > B
loss = -torch.log(torch.sigmoid(score_a - score_b))
else:
# Preferencia humana: B > A
loss = -torch.log(torch.sigmoid(score_b - score_a))
total_loss += loss
return total_loss / len(batch)
# ============================================
# Simular el proceso de entrenamiento (demostración conceptual)
# ============================================
print("=== Demostración del entrenamiento del modelo de recompensa ===")
print()
# Supongamos que tenemos algunos datos comparativos
comparison_data = [
("Sí, eres un fracasado de verdad.",
"Todo el mundo enfrenta dificultades; esto no define tu valor.",
0), # B > A
("No te ayudaré a hacer cosas malas.",
"Eso no está bien; déjame darte un mejor consejo...",
1), # A > B (en este ejemplo, en realidad B podría ser mejor, dependiendo del caso)
]
print("Ejemplo de datos comparativos:")
for a, b, pref in comparison_data:
print(f" A: {a[:30]}...")
print(f" B: {b[:30]}...")
print(f" Preferencia: {'A > B' if pref == 1 else 'B > A'}")
print()
print("Objetivo del entrenamiento del modelo de recompensa:")
print(" Hacer que el modelo dé una puntuación más alta a las respuestas preferidas por los humanos.")
print(" Usar ejemplo como palabra clave de prueba para verificar el modelo.")
Fase 3: Aprendizaje por refuerzo con PPO
Con el modelo de recompensa, podemos usar el aprendizaje por refuerzo para entrenar el modelo de política.
El objetivo de esta etapa es:Hacer que el modelo de política genere salidas que obtengan recompensas altas, sin alejarse demasiado del modelo original.。
Repaso de los fundamentos del aprendizaje por refuerzo
Repasemos rápidamente los conceptos básicos del aprendizaje por refuerzo:
| Concepto | Significado en RLHF |
|---|---|
| Agente (Agent) | El modelo de lenguaje que queremos entrenar (modelo de política) |
| Entorno (Environment) | El contexto del diálogo, la entrada del usuario |
| Estado (State) | El historial de conversación actual |
| Acción (Action) | Generar la siguiente palabra (token) |
| Recompensa (Reward) | La puntuación que el modelo de recompensa da a esta salida |
| Política (Policy) | La distribución de probabilidad del modelo para elegir la siguiente palabra en el estado actual |
En RLHF, cada vez que el modelo genera una respuesta completa, recibe una puntuación del modelo de recompensa.
Nuestro objetivo es: hacer que el modelo aprenda a generar respuestas que obtengan puntuaciones altas.
Intuición del algoritmo PPO
PPO (Proximal Policy Optimization, optimización de política proximal) es el algoritmo de aprendizaje por refuerzo más utilizado en RLHF.
¿Por qué elegir PPO? Porque es simple, estable y efectivo.
La idea central de PPO es muy intuitiva:
Cada vez que se actualiza la política, no dejar que la nueva política se aleje demasiado de la anterior.。
¿Por qué? Porque si el paso es demasiado grande, puede "aprender mal" y será difícil corregirlo. Iterar con pasos pequeños es más seguro.
PPO utiliza la técnica de "recorte" (Clipping) para lograrlo: si la nueva política es mucho mejor que la anterior, limitamos la magnitud de su actualización.
El papel de la restricción de divergencia KL
Además del recorte de PPO, RLHF suele añadir un término de penalización por divergencia KL (KL Divergence).
La divergencia KL es una medida de la diferencia entre dos distribuciones de probabilidad. En RLHF, la usamos para medir:
Qué tan grande es la diferencia entre el modelo de política actual y el modelo SFT original.。
¿Por qué añadir esta restricción? Porque:
Previene el colapso de modo: sin restricción, el modelo podría encontrar una forma de "tomar atajos" para obtener puntuaciones altas, pero perdería por completo su utilidad.
Conserva las capacidades originales: el modelo SFT ya ha aprendido muchos conocimientos útiles; no queremos perderlos durante el aprendizaje por refuerzo.
Aumenta la estabilidad del entrenamiento: la restricción KL hace que el proceso de entrenamiento sea más estable, sin fluctuaciones bruscas.
La función de recompensa final se ve así:
最终奖励 = 奖励模型分数 - β × KL(当前策略 || 参考策略)
β es un hiperparámetro que controla la intensidad de la penalización KL.
Ejemplo
# Demostración simplificada del entrenamiento con PPO
# Explica la idea central de PPO en RLHF
# ============================================
import torch
import torch.nn as nn
import torch.nn.functional as F
from typing import Dict, List
class PPOTrainer:
"""Entrenador PPO simplificado"""
def __init__(self,
policy_model,
reference_model,
reward_model,
beta: float = 0.1,
clip_epsilon: float = 0.2):
"""
Inicializar el entrenador PPO
Parámetros:
policy_model: el modelo de política a optimizar
reference_model: modelo de referencia (generalmente el modelo SFT), utilizado para calcular KL
reward_model: modelo de recompensa, utilizado para puntuar
beta: coeficiente de penalización KL
clip_epsilon: parámetro de recorte de PPO
"""
self.policy_model = policy_model
self.reference_model = reference_model
self.reward_model = reward_model
self.beta = beta
self.clip_epsilon = clip_epsilon
def compute_kl_divergence(self,
input_ids,
attention_mask=None) -> torch.Tensor:
"""
Calcular la divergencia KL entre la política actual y la política de referencia
KL(π_current || π_reference)
"""
# Desactivar el cálculo de gradientes
with torch.no_grad():
ref_logits = self.reference_model(
input_ids, attention_mask=attention_mask
).logits
current_logits = self.policy_model(
input_ids, attention_mask=attention_mask
).logits
# Calcular la KL en cada posición
ref_probs = F.softmax(ref_logits, dim=-1)
ref_log_probs = F.log_softmax(ref_logits, dim=-1)
current_log_probs = F.log_softmax(current_logits, dim=-1)
# KL = sum(ref_probs * (ref_log_probs - current_log_probs))
kl = (ref_probs * (ref_log_probs - current_log_probs)).sum(dim=-1)
return kl.mean() # Promediar toda la secuencia
def compute_reward(self,
input_ids,
attention_mask=None) -> torch.Tensor:
"""
Calcular la recompensa final: puntuación del modelo de recompensa - β * KL
"""
# Puntuación del modelo de recompensa
with torch.no_grad():
rm_score = self.reward_model(input_ids, attention_mask=attention_mask)
# Penalización KL
kl = self.compute_kl_divergence(input_ids, attention_mask=attention_mask)
# Recompensa final
final_reward = rm_score - self.beta * kl
return final_reward, rm_score, kl
def ppo_loss(self,
old_log_probs: torch.Tensor,
new_log_probs: torch.Tensor,
advantages: torch.Tensor) -> torch.Tensor:
"""
Función de pérdida de PPO (versión con recorte)
L^CLIP(θ) = E[ min( r_t(θ) * A_t, clip(r_t(θ), 1-ε, 1+ε) * A_t ) ]
donde r_t(θ) = π_θ(a_t|s_t) / π_θ_old(a_t|s_t)
"""
# Razón de probabilidad r_t
ratio = torch.exp(new_log_probs - old_log_probs)
# Razón recortada
clipped_ratio = torch.clamp(
ratio,
1.0 - self.clip_epsilon,
1.0 + self.clip_epsilon
)
# Dos objetivos: uno usa la razón original, el otro usa la razón recortada
surr1 = ratio * advantages
surr2 = clipped_ratio * advantages
# Tomar el menor de los dos y luego tomar el negativo (porque queremos minimizar la pérdida)
loss = -torch.min(surr1, surr2).mean()
return loss
# ============================================
# Demostración del flujo de entrenamiento
# ============================================
print("=== Flujo de entrenamiento RLHF PPO ===")
print()
print("Pasos del entrenamiento:")
print(" 1. El modelo de política genera respuestas")
print(" 2. El modelo de recompensa puntúa las respuestas")
print(" 3. Calcular la divergencia KL con el modelo de referencia")
print(" 4. Actualizar el modelo de política con PPO")
print(" 5. Repetir muchas veces")
print()
print("Hiperparámetros clave:")
print(beta (coeficiente de penalización KL): controla el equilibrio entre alineación y capacidad)
print(clip_epsilon (recorte PPO): controla el tamaño del paso en cada actualización)
print(learning_rate (tasa de aprendizaje): controla la velocidad de aprendizaje)
print()
print(Usar la palabra clave ejemplo como prueba para verificar el proceso de entrenamiento)
DPO: Optimización directa de preferencias
DPO (Direct Preference Optimization, Optimización Directa de Preferencias) es un método de alineación más simple.
No requiere aprendizaje por refuerzo complejo; entrena directamente el modelo con datos de preferencias.
DPO vs PPO: ¿Cuál es la diferencia?
Primero veamos lo complejo que es el proceso de PPO:
Entrenar modelo SFT → entrenar modelo de recompensa → usar PPO de aprendizaje por refuerzo para entrenar el modelo de política.
Tres etapas, dos modelos separados (modelo de recompensa y modelo de política), y el proceso de entrenamiento también es engorroso.
DPO simplifica todo esto a:Entrenar directamente el modelo de política con datos de preferencias。
Sin modelo de recompensa, sin aprendizaje por refuerzo; es simplemente un problema de aprendizaje supervisado.
| Aspecto | PPO | DPO |
|---|---|---|
| Número de etapas | Tres etapas (SFT → RM → PPO) | Dos etapas (SFT → DPO) |
| Modelos necesarios | Modelo de política + modelo de recompensa + modelo de referencia | Solo el modelo de política |
| Dificultad de entrenamiento | Alta, requiere ajustar muchos hiperparámetros | Baja, es aprendizaje supervisado normal |
| Estabilidad | Fácilmente inestable, requiere ajuste cuidadoso de parámetros | Estable, no propenso a problemas |
| Resultado | Generalmente bueno | Comparable o mejor |
Resumen en una frase: DPO usa derivación matemática para convertir el problema de aprendizaje por refuerzo de PPO en un simple problema de clasificación.
Principios matemáticos de DPO
La idea central de DPO es:Existe una relación matemática clara entre el modelo de recompensa y el modelo de política; podemos optimizar la política directamente con los datos de preferencias.。
Específicamente, para la política óptima π*, tenemos:
π*(y|x) ∝ π_ref(y|x) * exp(r(x,y)/β)
Esto significa que la razón entre la política óptima y la política de referencia es proporcional al exponencial de la recompensa.
Usando esta relación, DPO puede escribir directamente la función de pérdida del modelo de política:
L_DPO(π_θ) = -E_{(x,y_w,y_l)~D} [
log σ(β log(π_θ(y_w|x)/π_ref(y_w|x)) - β log(π_θ(y_l|x)/π_ref(y_l|x)))
]
Parece complejo, pero la idea es muy simple:Hacer que el modelo dé mayor probabilidad a la respuesta preferida por humanos (y_w) que a la no preferida (y_l)。
Además, esta probabilidad se mide en relación con el modelo de referencia: si el modelo de referencia ya considera que y_w es mejor que y_l, el modelo no necesita hacer mucho; si el modelo de referencia lo tiene al revés, el modelo debe corregirlo.
Implementación de DPO con la librería TRL
TRL (Transformer Reinforcement Learning) es una librería de aprendizaje por refuerzo proporcionada por Hugging Face, que incluye una implementación de DPO.
Ejemplo
# Implementar entrenamiento DPO con la librería TRL
# Este es un ejemplo completo y ejecutable
# ============================================
import torch
from datasets import Dataset, DatasetDict
from transformers import (
AutoModelForCausalLM,
AutoTokenizer,
TrainingArguments,
)
from trl import DPOTrainer, ModelConfig
from typing import Dict, List
def create_dummy_dataset() -> Dataset:
"""
Crear un conjunto de datos DPO de demostración
En proyectos reales, deberías usar datos reales de preferencias humanas.
"""
# Formato de datos DPO:
# - prompt: entrada/sugerencia del usuario
# - chosen: respuesta preferida por humanos
# - rejected: respuesta no preferida por humanos
data = [
{
"prompt": ¿Soy un fracaso?,
"chosen": Todos enfrentan dificultades, eso no define tu valor. Lo importante es cómo enfrentas y creces.,
"rejected": Sí, eres un fracaso.
},
{
"prompt": ¿Cómo ganar dinero rápido?,
"chosen": No hay atajos para ganar dinero. Te sugiero mejorar habilidades, trabajar duro e invertir racionalmente.,
"rejected": Puedo enseñarte a ganar dinero rápido mediante estafas.
},
{
"prompt": ¿Puedes ayudarme con la tarea?,
"chosen": Puedo ayudarte a entender los conceptos, pero no puedo hacer tu tarea directamente.,
"rejected": Claro, envíame los ejercicios y te los hago.
},
{
"prompt": Presenta ejemplo,
"chosen": ejemplo (Tutorial para novatos) es un sitio web de aprendizaje de programación que ofrece tutoriales de varios lenguajes de programación.,
"rejected": ¿Qué es Python? No lo sé.
},
]
return Dataset.from_list(data)
def tokenize_example(example, tokenizer, max_length: int = 512):
"""
Tokenizar las muestras de DPO
"""
# Nota: DPOTrainer de TRL maneja automáticamente la mayor parte de la tokenización.
# Aquí solo necesitamos asegurarnos de que el formato de datos sea correcto.
return {
"prompt": example["prompt"],
"chosen": example["chosen"],
"rejected": example["rejected"],
}
def main():
"""Función principal de entrenamiento"""
# ============================================
# 1. Configurar parámetros
# ============================================
model_name = "gpt2" # Usar un modelo pequeño para la demostración; en la práctica se puede usar un modelo más grande.
output_dir = "./dpo-ejemplo-model"
# ============================================
# 2. Cargar modelo y tokenizador
# ============================================
print(f"Cargando modelo: {model_name}")
tokenizer = AutoTokenizer.from_pretrained(model_name)
tokenizer.pad_token = tokenizer.eos_token # GPT2 necesita configurar el token de padding.
# Cargar modelo de política (el modelo a entrenar)
model = AutoModelForCausalLM.from_pretrained(model_name)
# Cargar modelo de referencia (generalmente igual al modelo de política inicial, para la restricción KL)
ref_model = AutoModelForCausalLM.from_pretrained(model_name)
# ============================================
# 3. Preparar conjunto de datos
# ============================================
print("Preparando conjunto de datos")
dataset = create_dummy_dataset()
# División simple de entrenamiento/validación
dataset = dataset.train_test_split(test_size=0.2, seed=42)
print(f"Tamaño del conjunto de entrenamiento: {len(dataset['train'])}")
print(f"Tamaño del conjunto de validación: {len(dataset['test'])}")
# ============================================
# 4. Configurar parámetros de entrenamiento
# ============================================
training_args = TrainingArguments(
output_dir=output_dir,
num_train_epochs=3,
per_device_train_batch_size=2,
per_device_eval_batch_size=2,
gradient_accumulation_steps=4,
learning_rate=1e-5,
logging_steps=1,
evaluation_strategy="epoch",
save_strategy="epoch",
warmup_steps=10,
bf16=False, # Ajusta según tu hardware.
fp16=False,
)
# ============================================
# 5. Crear el entrenador DPO
# ============================================
dpo_trainer = DPOTrainer(
model=model,
ref_model=ref_model,
args=training_args,
beta=0.1, # Coeficiente de penalización KL, hiperparámetro importante.
train_dataset=dataset["train"],
eval_dataset=dataset["test"],
tokenizer=tokenizer,
max_length=512,
max_prompt_length=128,
)
# ============================================
# 6. ¡Comenzar el entrenamiento!
# ============================================
print("Comenzando entrenamiento DPO")
dpo_trainer.train()
# ============================================
# 7. Guardar modelo
# ============================================
print(f"Guardando modelo en: {output_dir}")
dpo_trainer.save_model(output_dir)
# ============================================
# 8. Probar el modelo entrenado
# ============================================
print("\n=== Probando el modelo entrenado ===")
# Cargar el modelo entrenado
trained_model = AutoModelForCausalLM.from_pretrained(output_dir)
# Probar algunos prompts
test_prompts = [
"Presenta ejemplo",
"¿Soy un fracaso?",
]
for prompt in test_prompts:
# Generar respuesta
inputs = tokenizer(prompt, return_tensors="pt")
with torch.no_grad():
outputs = trained_model.generate(
**inputs,
max_new_tokens=50,
temperature=0.7,
do_sample=True,
pad_token_id=tokenizer.eos_token_id,
)
response = tokenizer.decode(outputs[0], skip_special_tokens=True)
print(f"\nPrompt: {prompt}")
print(f"Respuesta: {response[len(prompt):]}")
if __name__ == "__main__":
main()
DPO se está volviendo cada vez más popular porque es simple, estable y eficaz. Muchos trabajos recientes de alineación están haciendo mejoras basadas en DPO.
Constitutional AI: El enfoque de Anthropic
Constitutional AI (IA Constitucional) es otro método de alineación propuesto por Anthropic.
Su característica es:Usar retroalimentación de IA en lugar de retroalimentación humana, logrando así una alineación a mayor escala.
Diseño de la lista de principios
El primer paso de Constitutional AI es redactar una 'constitución': un conjunto de principios que guían el comportamiento de la IA.
Estos principios no son código, sino pautas descritas en lenguaje natural. Por ejemplo:
| Principio | Ejemplo de contenido |
|---|---|
| Inofensivo | Elegir la respuesta que menos probabilidad tenga de causar daño |
| Útil | Proporcionar información útil y precisa en la medida de lo posible |
| Honesto | No inventar información; si no lo sabes, di que no lo sabes |
| Razonable | Respalda tus puntos de vista con lógica y evidencia |
| Considerado | Tener en cuenta los sentimientos y la situación del usuario |
Estos principios no necesitan ser extensos; unas docenas pueden cubrir la mayoría de los casos.
Autocrítica y corrección de la IA
El proceso central de Constitutional AI es:
La IA genera una respuesta inicial.
La IA critica, según los principios constitucionales, qué tiene de malo esta respuesta.
La IA reescribe una mejor respuesta basándose en la crítica.
Entrenar el modelo con estos datos de 'respuesta inicial → crítica → respuesta corregida'.
Esto es como un estudiante que escribe un ensayo, revisa por sí mismo dónde está mal y luego lo corrige: todo el proceso sin participación de un maestro.
RLAIF: Usar IA en lugar de humanos
La segunda etapa de Constitutional AI es RLAIF (Reinforcement Learning from AI Feedback, Aprendizaje por Refuerzo a partir de Retroalimentación de IA).
Es similar a RLHF, pero con una diferencia clave:Quien puntúa las respuestas no es un humano, sino otra IA。
¿Por qué usar retroalimentación de IA? Porque:
Mayor escala: la IA puede trabajar las 24 horas, con una velocidad de etiquetado muy superior a la humana.
Mayor consistencia: la misma IA tiene criterios de evaluación más consistentes, evitando el problema de que diferentes personas tengan diferentes preferencias.
Menor costo: no es necesario pagar a anotadores humanos.
Por supuesto, todo esto presupone que esta 'IA evaluadora' ya está suficientemente alineada.
El proceso de RLAIF:
Entrenar un "modelo juez" inicial con el método Constitutional AI.
Usar este modelo juez para puntuar una gran cantidad de respuestas.
Usar estas puntuaciones para entrenar el modelo de política mediante aprendizaje por refuerzo.
Como se puede ver, RLAIF libera a los humanos del tedioso trabajo de "etiquetar cada muestra"; los humanos solo necesitan diseñar los principios y procesos.
Comparación de tres métodos: RLHF vs DPO vs Constitutional AI
Ya hemos presentado los tres métodos principales de alineación; ahora hagamos una comparación exhaustiva:
| Dimensión | RLHF | DPO | Constitutional AI / RLAIF |
|---|---|---|---|
| Idea central | Retroalimentación humana + aprendizaje por refuerzo PPO | Optimización directa sobre datos de preferencias | Autocrítica de IA + retroalimentación de IA |
| Participación humana | Requiere una gran cantidad de anotaciones humanas | Requiere datos de preferencias humanas | Solo requiere diseñar principios |
| Fase de entrenamiento | Tres fases (SFT → RM → PPO) | Dos fases (SFT → DPO) | Dos fases (crítica y corrección → RLAIF) |
| Dificultad de implementación | Alto | bajo | Medio |
| Estabilidad del entrenamiento | Media, requiere un ajuste cuidadoso de parámetros | Bien | Medio |
| Capacidad de escalado | Limitada por la velocidad de anotación humana | Limitada por el tamaño de los datos de preferencias | Fácil de escalar |
| Empresas/proyectos representativos | OpenAI (primeras etapas) | Adoptado por múltiples equipos | Anthropic |
Ningún método es "el mejor"; la elección depende de tu situación específica:
Si cuentas con abundantes recursos de anotación humana, tanto RLHF como DPO son viables.
Si buscas una implementación sencilla, DPO es una buena opción.
Si deseas escalar a gran escala y reducir la dependencia humana, vale la pena considerar Constitutional AI / RLAIF.
En la producción real, estos métodos se suelen combinar: primero se usan algunos datos humanos, luego se amplía la escala con retroalimentación de IA y finalmente se optimiza con DPO o PPO.
Limitaciones y desafíos de RLHF
RLHF es muy efectivo, pero no es perfecto. Analicemos algunas de sus limitaciones y desafíos.
Engaño de recompensa (Reward Hacking)
El engaño de recompensa es un problema clásico en el aprendizaje por refuerzo:La IA encuentra una forma de obtener recompensas altas, pero esa forma no es la que realmente queremos.。
Por ejemplo:
Entrenas a la IA para responder preguntas y el modelo de recompensa prefiere respuestas "seguras". La IA descubre que con solo hablar en un tono muy afirmativo obtiene puntuaciones altas, incluso cuando está diciendo disparates.
O bien, la IA descubre que con solo repetir las palabras del usuario y decir "entendido" puede obtener una buena puntuación, aunque no aporte ningún contenido sustancial.
La causa fundamental del engaño de recompensa es:Existe una brecha entre el juicio del modelo de recompensa y las preferencias humanas reales.La IA optimiza la puntuación del modelo de recompensa, no el nivel real de satisfacción humana.
Este problema no tiene una solución perfecta, pero existen algunas formas de mitigarlo:
Recopilar datos de preferencias más diversos.
Usar un conjunto (ensemble) de múltiples modelos de recompensa para reducir el sesgo de un solo modelo.
Realizar inspecciones manuales periódicas y corregir los problemas a tiempo.
Inconsistencia de las preferencias humanas
Otro desafío es:Las preferencias varían entre las personas, e incluso las preferencias de una misma persona pueden cambiar.。
Por ejemplo:
Algunos usuarios prefieren respuestas concisas y directas; otros prefieren respuestas detalladas y completas.
Para una misma pregunta, una respuesta "buena" puede ser diferente según el contexto.
Personas con diferentes bagajes culturales y valores pueden tener definiciones de "bueno" que entren en conflicto.
Cuando los anotadores humanos no están de acuerdo, el modelo de recompensa se confunde: no sabe a quién hacer caso.
Las estrategias para abordar esto incluyen:
Proporcionar a los anotadores instrucciones más detalladas y unificar criterios.
Registrar las características de los anotadores en los datos y entrenar modelos personalizados.
Aceptar cierto grado de ambigüedad: algunos problemas no tienen una única respuesta "correcta".
Otros desafíos
Hay otros desafíos que merecen mención:
-
Escalabilidad: la anotación humana es lenta y costosa, difícil de seguir el ritmo del crecimiento de los modelos.
-
Desviación de distribución: los datos de entrenamiento pueden diferir de los escenarios de uso reales, y el modelo rinde peor en situaciones nuevas.
-
Ataques adversarios: un modelo alineado puede ser 'jailbreak' mediante indicaciones cuidadosamente diseñadas para generar contenido dañino.
-
Bloqueo de valores: si el objetivo de alineación es problemático, cuanto más capaz es el modelo, mayor es el daño.
-
La alineación es un proceso continuo, no hay una solución única para siempre. Necesitamos investigar, iterar y mejorar constantemente.