Durante años, la inteligencia artificial en un ESP32 se ha limitado a tareas muy acotadas: detectores de palabras clave, clasificadores de vibración o sistemas capaces de distinguir un gato de un mapache en una cámara de seguridad. Es el terreno del TinyML, útil pero modesto. La idea de ejecutar un modelo de lenguaje real en un microcontrolador de pocos dólares parecía, hasta hace poco, una demostración académica sin recorrido práctico. Un desarrollador identificado como slvDev ha cambiado esa percepción al lograr que un ESP32 de gama básica ejecute un modelo de 28,9 millones de parámetros de forma local, sin enviar un solo dato a un servidor externo. El hallazgo no reside en la potencia del chip, que sigue siendo la misma de siempre, sino en cómo se organiza la memoria disponible. El resultado multiplica por cien la capacidad que se consideraba el límite razonable para este tipo de hardware y abre una vía distinta para pensar el edge computing en dispositivos embebidos de bajo coste.
El límite que existía hasta ahora
En 2024, el desarrollador Dave Bennett consiguió ejecutar un modelo de lenguaje en un ESP32-S3 usando un checkpoint de 260.000 parámetros entrenado con el conjunto de datos TinyStories, apoyándose en el runtime llama2.c de Andrej Karpathy. Aquel proyecto exigía una placa con 2 MB de PSRAM, ya que incluso un modelo tan reducido necesitaba cerca de 1 MB de RAM solo para almacenar los pesos. Gracias a las instrucciones SIMD del chip, ambos núcleos alcanzaban unos 19 tokens por segundo, una cifra respetable para la época. Escribía pequeñas historias con cierta coherencia, pero representaba un techo difícil de superar: cada parámetro debía residir en memoria rápida, y los 512 KB de SRAM junto con un par de megabytes de PSRAM marcaban un límite físico claro sobre el tamaño posible del modelo.
Para qué sirve realmente un modelo pequeño
Conviene situar este experimento dentro de un debate más amplio: qué se puede esperar honestamente de un modelo de lenguaje reducido, ya corra en un microcontrolador o en un portátil modesto. La objeción habitual es que un modelo pequeño «sabe poco», pero esa crítica está mal calibrada, porque ningún modelo, grande o pequeño, es una fuente fiable de datos factuales, y las puntuaciones de los benchmarks de capacidad no predicen bien la fiabilidad del conocimiento almacenado. Si la capacidad bruta no es el motivo para ejecutar un modelo en el propio hardware, entonces hay que buscar otra razón, y suelen ser tres: datos que no pueden salir del dispositivo, un volumen de trabajo ya asumido de antemano, o una latencia que forma parte del propio producto. Un modelo de menos de ocho mil millones de parámetros, el techo aproximado que suele manejarse para hardware no especializado, cubre bien esos escenarios sin necesidad de ajuste fino adicional.
Los límites reales de estos modelos también están bien delimitados. El primero es el razonamiento extendido: un modelo pequeño que pierde el hilo en el séptimo paso de un plan de doce no se salva con un mejor prompt. El segundo es la memoria paramétrica, el conocimiento aprendido durante el entrenamiento, que queda congelado en una fecha de corte y no se puede actualizar de forma selectiva; cuanto más pequeño el modelo, menos conocimiento de partida y más facilidad para alucinar en preguntas sobre temas poco representados en sus datos de entrenamiento. El tercero es el contexto efectivo, que suele ser bastante inferior al que anuncia la ficha técnica del modelo; los sistemas empiezan a fallar de forma notable al superar apenas el cuarenta por ciento de esa ventana anunciada, y la degradación llega de golpe, no de forma gradual. El contenido situado en la zona intermedia de una entrada larga es el que peor sale parado, un fenómeno conocido como el problema de «perderse en el medio».
Aceptando esos límites, hay tareas donde un modelo pequeño y local resulta la opción más razonable, y el experimento del ESP32 encaja de lleno en dos de ellas. La primera es el trabajo que no puede salir del dispositivo: cuando los datos no pueden viajar a un tercero, ya sea por regulación o por sensibilidad, la comparación no es entre un modelo pequeño y uno grande, sino entre un modelo pequeño y ninguno. La segunda es la latencia como parte del producto: un modelo que responde en cuestión de milisegundos desde memoria local no es simplemente una versión más rápida de uno que responde en dos segundos a través de la red, es una categoría distinta de herramienta, útil para tareas pequeñas, repetidas muchas veces por hora, donde el usuario lee el resultado en el momento y detecta cualquier fallo de inmediato. Un microcontrolador que genera texto local sin depender de un servidor es, en cierto modo, la expresión más extrema de esa filosofía: nunca se le pide al modelo que sepa algo, solo que produzca algo con lo que ya tiene delante. El propio análisis de KDnuggets sobre este tipo de despliegues insiste en que la regla de selección es sencilla: si la tarea exige que el modelo aporte hechos desde sus propios pesos, conviene recurrir a un modelo grande remoto; si la tarea trae su propio material, el modelo pequeño alojado en el propio hardware puede ser suficiente.
Cómo se ha movido el límite
El proyecto de slvDev parte de una premisa distinta: no todos los parámetros necesitan vivir en memoria rápida. La mayor parte de los pesos de un modelo de lenguaje se concentran en una tabla de embeddings, una estructura de consulta más que de cálculo, de la que normalmente solo se necesitan las filas asociadas al token que se está procesando en cada momento. En lugar de forzar 25 millones de esos parámetros dentro de la SRAM, el proyecto los deja en la memoria flash, mapeados en memoria, y recupera solo unas seis filas por token, unos 450 bytes de datos. El núcleo denso, la parte que realmente ejecuta las operaciones matemáticas en cada paso, se reduce a apenas 559.000 parámetros, un tamaño que cabe sin problema en memoria rápida. Google emplea una idea similar, conocida como per-layer embeddings, en la arquitectura que permite ejecutar Gemma 3n y Gemma 4 en teléfonos móviles; aquí se adapta al mapa de memoria propio de un microcontrolador.
No se trata de un simple truco de ingeniería sin sustento. El autor comparó el sistema con una línea base sin tabla, una alternativa que reparte el mismo presupuesto de parámetros de otra manera, y un control con la misma arquitectura pero sin tabla real detrás. La tabla completa redujo la perplejidad, la métrica que mide la calidad de las predicciones del modelo, en aproximadamente un 9 por ciento respecto a la línea base, mientras que el control rindió peor que no tener tabla en absoluto. Esa ventaja se mantiene incluso tras aplicar la cuantización a 4 bits necesaria para que todo quepa en la memoria flash disponible, un ajuste que documenta bien Ars Technica en su cobertura sobre cuantización de modelos y las técnicas para reducir el tamaño de redes neuronales sin sacrificar demasiada precisión.
El proyecto llevado a otra placa
El propio autor del artículo original replicó el experimento en un ESP32-S3 N8R8, una variante con la mitad de flash que el modelo N16R8 usado originalmente en el proyecto. El modelo de referencia pesa 14,9 MB y necesita 16 MB para alojar firmware y pesos juntos, así que la build publicada no encajaba directamente en esa placa. La solución pasó por reducir el vocabulario del modelo, ya que un vocabulario más pequeño implica una tabla de consulta y una cabeza de salida más ligeras. Esto obligó a reentrenar una versión con vocabulario reducido usando el propio pipeline de entrenamiento del proyecto, redimensionar la tabla de particiones para 8 MB de flash y recompilar el firmware con el flag de tamaño de flash correspondiente antes de escribir el nuevo modelo en la partición personalizada.
El sistema arrancó sin problemas y mantuvo la misma división en tres niveles: núcleo denso en SRAM, cabeza de salida en PSRAM y tabla de consulta leída en fragmentos de pocos cientos de bytes desde la flash. La placa alcanzó 22,3 tokens por segundo, una cifra superior a la del modelo original, gracias a que el vocabulario de 4.096 palabras reduce el coste de la cabeza de salida hasta seis veces frente al vocabulario de 32.768 palabras del modelo de referencia. La técnica no exige, por tanto, la placa más grande disponible para demostrar su validez; basta con respetar la jerarquía de memoria del chip.
Producto en el centro: el ESP32-S3, protagonista inesperado
El verdadero protagonista de esta historia sigue siendo el ESP32-S3, un microcontrolador de Espressif que ronda los 8 dólares y que hasta ahora se asociaba casi en exclusiva con proyectos de domótica, sensores IoT y automatización doméstica. Su combinación de doble núcleo, soporte de instrucciones vectoriales SIMD y acceso a memoria flash externa mapeada resulta clave para que este enfoque funcione. La clave técnica está en tratar la memoria flash como un recurso de lectura activo durante la inferencia, y no solo como almacenamiento pasivo de firmware, algo que hasta ahora se evitaba por su velocidad limitada frente a la SRAM. Esta reinterpretación del chip amplía notablemente su rango de aplicaciones potenciales, desde asistentes de voz completamente locales hasta generadores de texto embebidos en dispositivos sin conexión, sin necesidad de recurrir a un servidor en la nube ni a hardware más caro como un Raspberry Pi.
Dónde sigue estando el muro
El hardware, evidentemente, no ha cambiado: sigue siendo tan limitado como siempre. Un análisis de rendimiento muestra que más de la mitad del presupuesto de tiempo por token, unos 105 milisegundos en total, se destina a la cabeza de salida alojada en PSRAM, cuyo cuello de botella es la velocidad de escaneo y no la lectura de la memoria flash. La tabla de 25 millones de parámetros que tanta preocupación generaba en un primer momento solo añade unos 8,5 milisegundos al proceso. El problema, por tanto, no ha desaparecido: simplemente se ha desplazado de la falta de memoria disponible a la falta de ancho de banda de memoria, una limitación distinta y, en la práctica, más manejable.
El modelo en sí sigue siendo una prueba de concepto y está muy lejos de lo que ofrecen modelos de lenguaje locales ejecutados en un portátil, un PC o incluso una Raspberry Pi según documenta el propio fabricante en sus recursos técnicos sobre proyectos de IA en placas de bajo coste. Entrenado únicamente con el conjunto TinyStories, el sistema escribe relatos breves con cierta coherencia narrativa y estilo, pero carece de conocimiento factual y de capacidad de razonamiento. No responde preguntas complejas ni resuelve problemas: solo genera texto con estructura reconocible.
Reflexiones finales
Lo interesante de este experimento no es tanto el resultado final, un generador de microcuentos en un chip de bolsillo, como el cambio de perspectiva que propone. Durante mucho tiempo se ha dado por hecho que la memoria rápida es el único lugar razonable para alojar los parámetros de un modelo, y que la flash sirve solo como almacén estático de firmware. Este proyecto demuestra que esa suposición no es universal y que, con el diseño adecuado, se puede aprovechar la jerarquía de memoria de un microcontrolador de forma mucho más eficiente de lo que se pensaba. Conviene seguir de cerca este tipo de iniciativas documentadas en repositorios abiertos como el proyecto original en GitHub, porque el patrón de per-layer embeddings adaptado a hardware embebido podría trasladarse a otros chips de la familia ESP32 o a microcontroladores de gama similar, ampliando el catálogo de tareas que hoy se consideran exclusivas de placas más potentes como la Raspberry Pi. No estamos ante un asistente conversacional de bolsillo, pero sí ante una prueba sólida de que los límites de estos chips dependen más de las decisiones de diseño que de las especificaciones técnicas sobre el papel.
57