Saltar al contenido
Lección 3 de 12

Ingeniería de Datasets

7 min read

La Calidad de los Datos Supera a la Cantidad

Si hay una lección que la comunidad de fine-tuning ha aprendido por las malas, es esta: un dataset pequeño de ejemplos de alta calidad superará a un dataset grande de ejemplos mediocres. La investigación de LIMA (Less Is More for Alignment) mostró que solo 1,000 ejemplos cuidadosamente curados podían producir un modelo competitivo con aquellos entrenados con 50,000+ ejemplos. Tu dataset no es solo una entrada — es el factor individual más importante que determina si tu modelo fine-tuned tiene éxito o fracasa.

Esta lección cubre todo el pipeline de datos: recolectar ejemplos en bruto, limpiarlos hasta convertirlos en muestras listas para entrenamiento, elegir el formato correcto y entender cuántos ejemplos realmente necesitas.

Recopilando Datos de Entrenamiento

Curación Manual

El estándar de oro. Los expertos del dominio crean pares de entrada-salida que representan exactamente lo que el modelo debería producir. Esto es intensivo en trabajo pero produce los datos de mayor calidad.

Proceso:

  1. Define tu tarea claramente con 3-5 ejemplos de comportamiento ideal
  2. Crea una rúbrica que explique qué hace que un ejemplo sea "bueno"
  3. Haz que los expertos del dominio escriban 50-100 ejemplos siguiendo la rúbrica
  4. Revisa cada ejemplo para consistencia y calidad
  5. Itera sobre la rúbrica basándote en los patrones que encuentres

Consejo: Comienza escribiendo 20 ejemplos tú mismo. Esto te obliga a confrontar casos extremos y ambigüedades en tu definición de tarea antes de escalar a más contribuidores.

Logs Existentes y Datos de Producción

Si tu aplicación ya existe (incluso con ingeniería de prompts), tus logs de producción son un dataset esperando a ser creado. Las consultas de usuarios emparejadas con respuestas del modelo que fueron calificadas positivamente por usuarios o verificadas por humanos se convierten en ejemplos de entrenamiento.

# Ejemplo: extrayendo datos de entrenamiento de logs de produccion
import json

training_examples = []
for log in production_logs:
    if log["user_rating"] >= 4 and log["human_verified"]:
        training_examples.append({
            "instruction": log["user_query"],
            "output": log["model_response"]
        })

# Filtrar por diversidad — evitar ejemplos casi duplicados
# que causarian sobreajuste

Advertencia: Los datos de producción a menudo tienen un sesgo hacia consultas comunes. Asegúrate de incluir ejemplos de la cola de la distribución — las solicitudes inusuales que confunden a tu sistema actual.

Entrevistas con Expertos del Dominio

Para dominios especializados, las entrevistas estructuradas con expertos pueden generar ejemplos de alta calidad. Pregunta al experto que recorra escenarios reales: "¿Qué le dirías a un paciente que pregunta sobre X?" o "¿Cómo clasificarías esta transacción financiera?"

Graba la conversación, extrae los pares de entrada-salida y haz que el experto valide los ejemplos formateados finales.

Datos Sintéticos de Modelos Más Potentes

Usar un modelo más capaz (GPT-4o, Claude) para generar datos de entrenamiento para un modelo más pequeño es una estrategia común y efectiva. La clave es generar ejemplos diversos y de alta calidad que valides antes de entrenar.

import openai

client = openai.OpenAI()

# Generar ejemplos de entrenamiento diversos
seed_topics = ["revision de contratos", "analisis de NDA", "clausula de responsabilidad"]

for topic in seed_topics:
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[{
            "role": "system",
            "content": "Eres un analista de documentos legales. Genera una consulta "
                       "realista de usuario y una respuesta ideal para el siguiente tema."
        }, {
            "role": "user",
            "content": f"Tema: {topic}. Genera un ejemplo especifico y realista."
        }],
        temperature=0.9  # Mayor temperatura para diversidad
    )
    # Siempre valida los ejemplos generados manualmente

Regla crítica: Siempre valida los datos sintéticos. Un modelo más potente producirá salidas que parecen plausibles pero contienen errores sutiles. Presupuesta tiempo para revisión humana de cada ejemplo sintético.

Limpiando tus Datos

Los datos en bruto nunca están listos para entrenamiento. Aquí está el pipeline de limpieza que deberías aplicar:

Deduplicación

Los ejemplos casi duplicados hacen que el modelo memorice en lugar de generalizar. Usa tanto coincidencia exacta como deduplicación por similitud semántica.

from sentence_transformers import SentenceTransformer
from sklearn.metrics.pairwise import cosine_similarity
import numpy as np

model = SentenceTransformer("all-MiniLM-L6-v2")

# Calcular embeddings para todos los ejemplos
texts = [ex["instruction"] + " " + ex["output"] for ex in examples]
embeddings = model.encode(texts)

# Encontrar casi-duplicados (similitud coseno > 0.95)
sim_matrix = cosine_similarity(embeddings)
duplicates = set()
for i in range(len(sim_matrix)):
    for j in range(i + 1, len(sim_matrix)):
        if sim_matrix[i][j] > 0.95:
            duplicates.add(j)  # Mantener el primero, marcar el posterior como duplicado

cleaned = [ex for i, ex in enumerate(examples) if i not in duplicates]
print(f"Eliminados {len(duplicates)} casi-duplicados de {len(examples)} ejemplos")

Filtrado de Muestras de Baja Calidad

Elimina ejemplos que son demasiado cortos, demasiado largos, contienen errores de formato o son inconsistentes con tu definición de tarea.

def quality_filter(example):
    output = example["output"]

    # Demasiado corto para ser util
    if len(output.split()) < 20:
        return False

    # Demasiado largo (podria ser ruidoso o fuera de tema)
    if len(output.split()) > 2000:
        return False

    # Contiene errores obvios de formato
    if output.count("```") % 2 != 0:  # Bloques de codigo sin cerrar
        return False

    # Comienza con patrones de rechazo que no queremos
    refusal_patterns = ["No puedo", "Lo siento", "Como IA"]
    if any(output.startswith(p) for p in refusal_patterns):
        return False

    return True

cleaned = [ex for ex in examples if quality_filter(ex)]

Verificaciones de Consistencia

Todos los ejemplos deben seguir las mismas convenciones. Si algunos ejemplos usan encabezados markdown y otros no, si algunos terminan con punto y otros no — estas inconsistencias confunden al modelo.

Escribe una guía de estilo para tu dataset y aplícala programáticamente donde sea posible, manualmente donde sea necesario.

Formatos de Datos

Diferentes objetivos de entrenamiento requieren diferentes formatos de datos. Aquí están los tres principales:

Formato de Instrucción (Supervised Fine-Tuning)

El formato más simple. Cada ejemplo es una instrucción (entrada) y una completación (salida). Se usa para enseñar al modelo a seguir instrucciones específicas.

{
  "instruction": "Resume esta clausula legal en lenguaje sencillo",
  "input": "La parte indemnizante debera mantener indemne e indemnizar...",
  "output": "Esta clausula significa que una parte acepta cubrir cualquier perdida..."
}

Formato de Chat (Conversaciones Multi-Turno)

Para modelos conversacionales, cada ejemplo contiene una conversación completa con mensajes de sistema, usuario y asistente.

{
  "conversations": [
    {"role": "system", "content": "Eres un asistente de triaje medico..."},
    {"role": "user", "content": "Tengo dolor de cabeza y fiebre leve..."},
    {"role": "assistant", "content": "Basandome en tus sintomas..."},
    {"role": "user", "content": "Deberia ir a urgencias?"},
    {"role": "assistant", "content": "Dada la naturaleza leve de tus sintomas..."}
  ]
}

Formato de Preferencia (DPO/RLHF)

Para entrenamiento de alineación, cada ejemplo incluye un prompt, una respuesta elegida (preferida) y una respuesta rechazada (peor).

{
  "prompt": "Explica la computacion cuantica a un nino de 10 anos",
  "chosen": "Imagina que tienes una moneda magica que puede ser cara Y cruz...",
  "rejected": "La computacion cuantica aprovecha fenomenos de mecanica cuantica como la superposicion y el entrelazamiento para realizar calculos en qubits..."
}

¿Cuántos Datos Necesitas?

No hay una respuesta universal, pero aquí hay guías prácticas basadas en experiencia del mundo real:

| Tipo de Tarea | Ejemplos Mínimos | Recomendado | Notas | |---------------|-----------------|-------------|-------| | Adaptación de estilo/tono | 100-200 | 500-1,000 | La consistencia es clave | | Formato de salida | 200-500 | 1,000-2,000 | Cubrir todos los casos extremos | | Conocimiento de dominio | 500-1,000 | 2,000-5,000 | La diversidad importa | | Razonamiento complejo | 1,000-2,000 | 5,000-10,000 | Chain-of-thought ayuda | | Multi-tarea | 500+ por tarea | 1,000+ por tarea | Balance entre tareas |

Importante: Estos números asumen ejemplos de alta calidad y diversos. 200 ejemplos cuidadosamente curados superarán a 2,000 ruidosos. Cuando tengas dudas, invierte en calidad sobre cantidad.

Consejo Práctico

Antes de comenzar cualquier esfuerzo de recolección de datos, crea 10 "ejemplos dorados" — pares de entrada-salida perfectos que representan exactamente lo que quieres que el modelo haga. Úsalos como tu estrella del norte durante todo el proceso. Cada nuevo ejemplo debería ser tan bueno como tu conjunto dorado. Si no lo es, arréglalo o descártalo.

En la próxima lección, tomaremos tus datos limpios y los formatearemos para frameworks de entrenamiento específicos — Hugging Face, Axolotl y Unsloth — con ejemplos de código completos.