Entrenando a Prize (Parte 2): Creando un Dataset de 5,500 líneas por $0.08 USD

Published: (December 6, 2025 at 07:32 PM EST)
5 min read
Source: Dev.to

Source: Dev.to

Introducción: El ritmo de un “Weekend Project”

Bienvenidos a la segunda entrega de mi viaje construyendo Prize, mi propia red neuronal para clasificación de texto. Antes de entrar en materia, tengo que aclarar que Prize es oficialmente un proyecto de fin de semana. Como muchos de ustedes, tengo un trabajo diario y responsabilidades, así que solo puedo ponerme la gorra de “Ingeniero de Machine Learning” los sábados y domingos. El progreso será constante, pero a su propio ritmo.

En el post anterior definí la arquitectura. Hoy les contaré cómo resolví el problema más grande de cualquier proyecto de IA: conseguir los datos.

Fase 1: La limpieza manual

Mi primera fuente de datos es el inventario de una cadena de farmacias con 6 000 ítems. Suena genial, hasta que abres el archivo.

Una red neuronal aprende lo que le enseñas. Si le enseño que una “Coca‑Cola” es una medicina, la red fallará. Me di cuenta de que mi inventario estaba contaminado con productos que no tienen nada que ver con salud. Así que me tocó hacer el trabajo sucio. En varias sesiones a lo largo del fin de semana, filtré la lista manualmente y borré cientos de filas que contenían refrescos, chocolates, detergentes, escobas y araganes.

El resultado final es un archivo limpio: inventarioSoloMedicinas.txt. Es un trabajo tedioso, pero vital. Sin esta limpieza, Prize no tendría oportunidad.

Fase 2: La fábrica de datos sintéticos ($0.08 de inversión)

Aquí vino el reto real. Mientras que de Farmacia tenía miles de ítems, del “Laboratorio Dental” apenas tenía unos 50 ejemplos. Un desbalance total. Necesitaba convertir esas 50 líneas en 5 500 para igualar a la farmacia. ¿La solución? Usar IA para entrenar IA.

Con la ayuda de Google Gemini, escribí un script en Python que se conecta a la API de OpenRouter (usando modelos Llama 3). La lógica fue sencilla:

  1. Tomar 5 ejemplos reales de mis servicios dentales.
  2. Pedirle a la IA que genere 20 variaciones de cómo un usuario pediría esos servicios (con jerga, errores de dedo, diferentes tonos).
  3. Repetir hasta llegar a la meta.

Script de generación

import requests
import json
import random
import time
import os

# --- CONFIGURACIÓN ---
API_KEY = "XXXXXXXXXX"
OUTPUT_FILE = "dataset_laboratorio_sintetico.txt"
TARGET_COUNT = 5500
BATCH_SIZE = 20  # Cuántas frases pedimos por llamada

MODEL_ID = "meta-llama/llama-3.1-70b-instruct"

semillas_laboratorio = [
    "protesis total superior acrilico",
    "reparacion de puente fijo",
    "ferula de descarga rigida",
    "corona de zirconio sobre implante",
    # ... Aquí va el resto de los 50 items ...
]

def generate_variations(seeds):
    seeds_text = "\n".join([f"- {s}" for s in seeds])

    prompt = f"""
    Actúa como un generador de datos para entrenar una IA.
    Tu tarea es generar {BATCH_SIZE} frases de búsqueda DISTINTAS basadas en los servicios de un laboratorio dental.

    Aquí tienes algunos ejemplos reales (semillas):
    {seeds_text}

    INSTRUCCIONES:
    1. Genera {BATCH_SIZE} variaciones nuevas. NO copies las semillas exactamente.
    2. Contexto: Usuarios en Venezuela/Latinoamérica buscando estos servicios.
    3. Variedad:
       - Usa sinónimos (ej: "plancha" en vez de "prótesis", "férula" en vez de "placa").
       - Mezcla tonos: Formal ("necesito una cotización..."), Informal ("cuanto cuesta la plancha..."), Directo ("precio corona").
       - Incluye ocasionalmente errores leves de ortografía o falta de tildes (como escribe la gente en WhatsApp).
    4. FORMATO DE SALIDA: Únicamente una lista JSON pura de strings. Sin texto extra antes ni después.
    Ejemplo: ["frase 1", "frase 2", "frase 3"]
    """

    headers = {
        "Authorization": f"Bearer {API_KEY}",
        "Content-Type": "application/json"
    }

    data = {
        "model": MODEL_ID,
        "messages": [
            {"role": "system", "content": "Eres un asistente útil que responde SOLO en formato JSON válido."},
            {"role": "user", "content": prompt}
        ],
        "temperature": 0.8
    }

    try:
        response = requests.post(
            "https://openrouter.ai/api/v1/chat/completions",
            headers=headers,
            json=data
        )
        response.raise_for_status()
        result = response.json()
        content = result['choices'][0]['message']['content']
        return json.loads(content)
    except Exception as e:
        print(f"Error en la llamada a la API: {e}")
        return []

def main():
    print("--- Iniciando Generación para Proyecto Prize ---")
    print(f"Meta: {TARGET_COUNT} frases.")

    current_count = 0
    if os.path.exists(OUTPUT_FILE):
        with open(OUTPUT_FILE, 'r', encoding='utf-8') as f:
            current_count = len(f.readlines())

    print(f"Progreso actual: {current_count} frases encontradas en {OUTPUT_FILE}")

    while current_count < TARGET_COUNT:
        mis_semillas = random.sample(semillas_laboratorio, k=min(5, len(semillas_laboratorio)))
        print(f"Generando lote... (Total actual: {current_count})")
        nuevas_frases = generate_variations(mis_semillas)

        if not nuevas_frases:
            print("Fallo en este lote, reintentando en 5 segundos...")
            time.sleep(5)
            continue

        with open(OUTPUT_FILE, 'a', encoding='utf-8') as f:
            for frase in nuevas_frases:
                f.write(frase + "\n")

        current_count += len(nuevas_frases)
        time.sleep(1)

    print("\n¡ÉXITO! Generación completada.")
    print(f"Archivo guardado en: {OUTPUT_FILE}")

if __name__ == "__main__":
    main()

Los resultados: datos duros

  • Tiempo de ejecución: 2 horas.
  • Volumen generado: 5 500 líneas de texto único y variado.
  • Costo total de la API: $0.08 USD.

Sí, por menos de 10 centavos de dólar, generé un dataset robusto y equilibrado que me hubiera tomado semanas escribir a mano. Misión cumplida. El dataset sintético está listo.

Conclusión

Ahora tengo dos archivos en mi disco duro que valen su peso en oro:

  • inventarioSoloMedicinas.txt – datos reales, limpios.
  • dataset_laboratorio_sintetico.txt – datos generados, variados.

La balanza está equilibrada: ~11 000 ejemplos de alta calidad listos para ser procesados. En el próximo fin de semana, haremos la magia matemática: usaremos nuevamente la API de OpenRouter y convertiremos todo este texto a números (embeddings), luego transformaremos los vectores fila en vectores columna (lo que espera el script network2.py) y, finalmente, encenderemos a Prize para su primer entrenamiento.

¡Hasta el próximo sábado!

Back to Blog

Related posts

Read more »