训练 Prize(第2部分):以 0.08 美元 创建 5,500 行数据集

发布: (2025年12月7日 GMT+8 08:32)
6 min read
原文: Dev.to

Source: Dev.to

引言:一个“周末项目”的节奏

欢迎阅读我构建 Prize——我的文本分类神经网络的第二篇日志。先说清楚,Prize 官方上是一个周末项目。和你们一样,我有全职工作和其他责任,所以只能在周六、周日戴上“机器学习工程师”的帽子。进度会持续,但会按自己的节奏前进。

在上一篇文章中我定义了网络结构。今天我来讲讲我如何解决任何 AI 项目中最大的问题:获取数据。

第一步:手动清洗

我的第一批数据来源是一个药店连锁的 6 000 条商品库存。听起来很棒,直到你打开文件。

神经网络会学习你教给它的东西。如果我教它把“可口可乐”当作药品,网络就会出错。我发现我的库存被污染了,里面混杂了很多与健康无关的商品。于是我只能动手做脏活。整个周末,我分几次手动筛选列表,删除了数百行包含软饮、巧克力、清洁剂、扫帚和蚂蚁药的记录。

最终得到的干净文件是:inventarioSoloMedicinas.txt。这工作枯燥却至关重要。没有这一步的清洗,Prize 将毫无机会。

第二步:合成数据工厂(投入 $0.08)

真正的挑战来了。药店那边有几千条商品,而“牙科实验室”只有大约 50 条示例,极度不平衡。我需要把这 50 条扩展到 5 500 条,以匹配药店的规模。解决方案?用 AI 训练 AI。

借助 Google Gemini,我写了一个 Python 脚本,调用 OpenRouter 的 API(使用 Llama 3 模型)。思路很简单:

  1. 取 5 条真实的牙科服务示例。
  2. 让 AI 生成 20 条用户可能的搜索表达(包括行话、打字错误、不同语气)。
  3. 重复上述过程,直至达到目标数量。

生成脚本

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

结果:硬数据

  • 运行时间: 2 小时。
  • 生成量: 5 500 条独特且多样的文本行。
  • API 总费用: $0.08 USD

是的,花不到 10 美分,我就生成了一个稳健且平衡的数据集,手工完成需要几周时间。任务完成。合成数据集已经准备好。

结论

现在我的硬盘上有两个价值连城的文件:

  • inventarioSoloMedicinas.txt – 真实、干净的数据。
  • dataset_laboratorio_sintetico.txt – 生成的、多样化的数据。

天平已经平衡:约 11 000 条高质量示例,随时可以进行后续处理。下个周末,我将进行数学魔法:再次调用 OpenRouter API 将所有文本转化为向量(embeddings),再把行向量转为列向量(network2.py 脚本所需的格式),最后启动 Prize 进行首次训练。

下个星期六见!

Back to Blog

相关文章

阅读更多 »