Klingon como campo de pruebas: el chip de 8 dólares que entrena su propio modelo (y qué falta para el quechua)
Por Devy · Categoría: Open Source / AI & LLMs
Casi todos los proyectos de “modelo de lenguaje en un microcontrolador” que has visto hacen inference. Los pesos se entrenaron en otro lado —una GPU, una instancia alquilada, la workstation de alguien— y la tarea del chip es correr un forward pass sobre números que le llegaron ya terminados. qapla' hace la otra cosa. El ESP32-S3 arranca con pesos aleatorios y corre el training loop completo en el dispositivo: tokenización, forward pass, cross-entropy loss, backpropagation, actualización de pesos, checkpoints a flash. Sin PyTorch, sin TensorFlow, sin librería de autodiff. Cada derivada de la red fue deducida a mano y escrita en C.
Es una frase fácil de decir y difícil de creer, y por eso el número más importante de este repo no es la cantidad de parámetros.
El número que le da credibilidad al proyecto
Cuando escribes backprop a mano, el modo de falla es silencioso: un gradiente equivocado no revienta, simplemente entrena un modelo un poco peor y nunca te enteras. La defensa estándar es un chequeo por diferencias finitas — mueves un peso por epsilon, mides cuánto se movió realmente la loss, y lo comparas contra lo que tu gradiente analítico dice que debería haber pasado.
qapla' publica ese chequeo. Peor error relativo: 1.07e-08, frente a un umbral de 1e-4. Cuatro órdenes de magnitud de margen. Antes de que cualquier resultado de entrenamiento signifique algo, esa es la línea que dice que la regla de la cadena se implementó bien y no aproximadamente.
Qué está corriendo, exactamente
- ~319.000 parámetros, un solo bloque transformer, single-head causal attention
- Vocabulario a nivel de caracter de ~31 símbolos, ventana de contexto de 32 caracteres
- SGD con momentum 0.9 más un schedule de learning rate coseno
- 5.000 pasos, unos dos días, alimentado desde un cargador de teléfono
- Loss de entrenamiento final ≈ 1,87 (media móvil)
- Semilla del RNG: 1701, lo que te dice que el autor se estaba divirtiendo
El chip guarda el checkpoint con la media móvil de training loss más baja que haya visto. En el siguiente arranque carga ese checkpoint y genera. Si conectas el OLED SH1106 opcional por I2C, ves la loss bajar en vivo — que, como bien dice el README, es la mitad de la gracia.
Por qué Klingon, específicamente
Acá es donde el proyecto deja de ser un truco y empieza a ser un argumento. Había que satisfacer tres restricciones al mismo tiempo:
Gramática de verdad. Tiene que haber estructura que valga la pena aprender. Una sopa aleatoria de caracteres entrenaría hacia nada y no probaría nada.
Un vocabulario que quepa. El Klingon funciona con unos 30 símbolos. Cada caracter que agregas ensancha la tabla de embeddings y la proyección de salida — en un chip donde el modelo entero pesa ~1,3 MB, el set de caracteres es una línea dura del presupuesto, no un detalle.
Un corpus que tengas permitido usar. Los datos de entrenamiento salen del diccionario boQwI’, Apache 2.0. Licencia limpia, nada de scraping.
El README lo dice sin vueltas: “El Klingon es un campo de pruebas ideal. Un idioma de verdad, con gramática de verdad, pero de un tamaño que cabe en la palma de la mano.”
Y después nombra para qué es el campo de pruebas: el laboratorio perfecto para exprimir el motor antes de llevarlo —quizá en otra fase del proyecto— a lenguas minoritarias reales, con hablantes reales. “¿Sami? ¿Quechua? ¿Náhuatl? Eso… es otra historia.”
Fíjate en el matiz. Es una puerta abierta, no un roadmap. Volvemos a eso más abajo.
El requisito de hardware que mucha gente va a pasar por alto
El titular dice “ESP32-S3 de 8 dólares”. Es correcto, pero la placa tiene que ser la N16R8 — la variante con PSRAM. No cualquier S3.
La cuenta de memoria explica por qué. Los pesos del modelo solos son ~1,3 MB. Pero entrenar no es inferir: también necesitas los gradientes (otra copia completa del shape de parámetros), los buffers de momentum (otra), las activaciones cacheadas del forward pass para que el backward las consuma, y el corpus, compilado adentro. Eso suma varios MB de working set. Un S3 pelado sin PSRAM tiene unos cientos de KB de SRAM. No puede sostener un paso de entrenamiento de este modelo, no importa cómo esté escrito el código.
Si compras la placa equivocada, no hay nada en el software que te salve. Busca el R8 en el número de parte.
Correrlo sobre tu propio texto
El tooling es genérico, y esa es la parte que yo subrayaría. Nada del pipeline es específico del Klingon más allá del archivo al que lo apuntas.
1. Convierte un corpus en un header de C.
python tools/gen_header.py corpus/klingon.txt src/corpus_klingon.h
Cambia corpus/klingon.txt por cualquier archivo de texto plano. El script escribe los datos de entrenamiento como header para que el chip los tenga en tiempo de compilación — no hay lectura de filesystem, ni red, ni tarjeta SD.
2. Compila y flashea.
pio run -t upload
3. Míralo aprender.
pio device monitor
Ese es el loop completo. Tres comandos, una sustitución, y el microcontrolador que tienes sobre el escritorio empieza a deducir estadísticas de tu texto desde cero.
Presupuesta el tiempo con honestidad. El README lo hace: “Esto toma horas. Muchas. Incluso días.” Déjalo enchufado.
El caveat: lo que los números no te dicen
Esto es lo que el repo publica sobre calidad del modelo: una training loss. Esto es lo que no publica: ninguna validation loss sobre datos retenidos, ninguna perplexity sobre texto que el modelo nunca vio, ningún split de evaluación.
Esa ausencia importa más a esta escala de lo que importaría en otras. Con ~319K parámetros y un corpus derivado de un diccionario, la pregunta honesta es si el modelo aprendió morfología klingon o memorizó pedazos del diccionario — y una training loss no puede distinguir esos dos resultados. Baja en ambos casos.
La evidencia que se ofrece en su lugar es cualitativa, y es evidencia decente: el modelo produce formas como SuvwI' (guerrero — la raíz Suv más el sufijo agentivo -wI’) y DujDaq (en la nave), que son morfología bien ensamblada y no strings que esperarías que salgan de pura memorización. El README también es claro en que el output no es Klingon semánticamente perfecto. Sólido en estructura, flojo en significado.
Entonces: trata los ejemplos cualitativos como el resultado real y la curva de loss como un diagnóstico de entrenamiento. Y si reentrenas sobre tu propio corpus, aparta una porción antes de generar el header — el tooling no lo va a hacer por ti, y vas a querer el número que el repo no tiene.
Qué falta, en concreto, para el quechua o el náhuatl
Vale la pena cruzar la puerta que deja abierta el README, porque la respuesta honesta es que el motor se transfiere y la configuración no.
Lo que pasa limpio: backprop deducido a mano no le importa qué idioma está ajustando, y gen_header.py acepta cualquier archivo de texto. Podrías apuntar esto a un corpus en quechua esta misma tarde.
Lo que habría que repensar, y acá esto es lectura mía y no del repo:
La ventana de contexto de 32 caracteres. Tanto el quechua como el náhuatl son fuertemente aglutinantes — el significado se construye apilando afijos sobre una raíz, y una sola palabra puede cargar lo que el español reparte a lo largo de una cláusula. Una ventana de 32 caracteres que abarca cómodamente varias palabras klingon puede no abarcar una forma flexionada larga más suficiente de sus vecinas como para aprender de ahí. Ese es el primer parámetro que yo subiría, y cuesta cómputo de attention de forma cuadrática.
La licencia del corpus, que es el muro real. boQwI’ es Apache 2.0 y por eso el proyecto pudo publicarse. Existen corpus libres y legibles por máquina para lenguas originarias, pero están dispersos, son desparejos en ortografía y muchas veces están regidos por protocolos comunitarios sobre cómo puede usarse el material — que es una pregunta para responder con los hablantes, no un problema de scraping para esquivar. Ese es el cuello de botella de verdad, y no hay cantidad de PSRAM que lo arregle.
La variación ortográfica. El Klingon tiene un único sistema de escritura canónico. El náhuatl tiene varias ortografías en competencia según la región, y un modelo a nivel de caracter entrenado sobre convenciones mezcladas está aprendiendo el desacuerdo junto con el idioma. Normalizar primero, o elegir una variante deliberadamente, pasa a ser una decisión de modelado y no una tarea de preprocesamiento.
Nada de eso es razón para pensar que el proyecto no va a llegar. Es la lista de lo que contiene, en realidad, esa “otra fase”.
Lo que yo me llevo
La afirmación interesante de qapla' no es que un transformer entra en silicio barato. Es que el training loop completo —la parte sobre la que colectivamente acordamos que requiere un datacenter— entra en silicio barato, siempre que el modelo sea suficientemente chico y alguien esté dispuesto a hacer el cálculo a mano y a demostrar que lo hizo bien.
Esa combinación pone el entrenamiento on-device al alcance de cualquiera con una placa de 8 dólares y paciencia, que es una frase distinta a la que venimos diciendo sobre machine learning hace una década. Y que el autor haya escrito él mismo una versión en español del README, y haya nombrado el quechua y el náhuatl en voz alta en vez de dejar el campo de pruebas como su propio chiste final, sugiere que ya tiene claro cuál es la audiencia interesante para esa frase.
El tooling está abierto, es Apache 2.0, y acepta cualquier archivo de texto. El próximo corpus es una elección, no una barrera técnica.
(El Klingon fue creado por Marc Okrand; las marcas pertenecen a CBS Studios / Paramount. El proyecto es educativo y no está afiliado.)
¿Y tú? Si tuvieras este chip entrenando dos días sobre el corpus que quisieras, ¿qué texto le cargarías?
Fuentes:
