- Motor de inferencia basado en C/Metal que ejecuta un modelo Mixture-of-Experts de 397B parámetros en una MacBook Pro (48GB RAM) a más de 4.4 tokens por segundo
- Implementado únicamente con C y shaders de Metal, sin Python ni frameworks, mientras transmite por streaming el modelo completo de 209GB desde el SSD
- Maximiza la eficiencia paralela de GPU·SSD·CPU con SSD Expert Streaming, kernels optimizados con FMA y Deferred GPU Compute
- La configuración con cuantización de 4-bit logra un equilibrio entre calidad y velocidad, con generación de salida de nivel de producción, incluida la función de llamadas a herramientas
- Un caso de reducción y optimización que hace posible la inferencia en tiempo real de modelos MoE gigantes incluso en una laptop
Resultados de rendimiento
- La configuración de expertos de 4-bit (kernel FMA) alcanza 4.36 tok/s, con buena calidad, usando los 209GB completos en disco
- La configuración base de 4-bit logra 3.90 tok/s, como etapa previa a la optimización con FMA
- La configuración de expertos de 2-bit (trust the OS) alcanza 5.74 tok/s y es más rápida, pero los errores en la salida JSON impiden las llamadas a herramientas
- El pico de un solo token en 2-bit llega hasta 7.05 tok/s, pero no es adecuado para uso real
- La cuantización de 4-bit es la configuración más adecuada para operación real
Entorno de hardware
- MacBook Pro (Apple M3 Max), CPU de 16 núcleos (12P+4E), GPU de 40 núcleos, ANE de 16 núcleos
- 48GB de memoria unificada, con un ancho de banda de aproximadamente 400GB/s
- SSD Apple Fabric de 1TB, con 17.5GB/s de lectura secuencial
- Entorno macOS 26.2 (Darwin 25.2.0)
Arquitectura del modelo
- Un total de 60 capas transformer: 45 de GatedDeltaNet (atención lineal) + 15 de atención completa
- Cada capa tiene 512 expertos, y se activan K=4 por token (incluido 1 experto compartido)
- Dimensión oculta 4096
-
Tecnologías clave
-
SSD Expert Streaming
- Carga los pesos de los expertos (209GB en 4-bit) desde NVMe SSD según se necesitan mediante
pread() en paralelo
- En cada capa solo se cargan los 4 expertos activos (aprox. 6.75MB cada uno)
- La page cache del sistema operativo gestiona automáticamente el caché, sin necesidad de uno adicional
- Arquitectura inspirada en el paper de Apple “LLM in a Flash”
-
Kernel de dequantización optimizado con FMA
- Reorganiza la operación
(nibble * scale + bias) * x a la forma fma(nibble, scale*x, bias*x)
- Precalcula
scale*x y bias*x para que las unidades FMA de la GPU lo ejecuten en una sola instrucción
- 12% de mejora de velocidad frente a una implementación simple
-
Metal Compute Shaders
- Implementa con kernels Metal escritos a mano operaciones como producto matriz-vector de dequantización 4-bit/2-bit, activación SwiGLU, normalización RMS, atención en GPU (Q@Kᵀ, softmax, scores@V), RoPE y combinación MoE + residual + gate
-
Deferred GPU Expert Compute
- Envía de forma asíncrona el comando CMD3 (forward pass de expertos) para que la CPU prepare la siguiente capa mientras la GPU ejecuta
- Las operaciones de combinación + normalización + residual también se ejecutan en la GPU y se pasan directamente a la siguiente capa
-
Uso de Accelerate BLAS
- Usa
cblas_sscal, cblas_sgemv, cblas_sger para el cálculo recurrente de GatedDeltaNet
- 64% más rápido que el código escalar
-
Trust the OS
- Elimina el caché personalizado y deja el caché de los datos de expertos a la page cache del sistema operativo (basada en LRU, aprox. 35GB)
- Resultó más rápido que un LRU propio en Metal, un caché con malloc o un caché comprimido con LZ4
- Logra una tasa natural de aciertos de caché del 71%
-
Restricciones de memoria unificada
- En Apple Silicon, el DMA del SSD y el cómputo de la GPU comparten el mismo controlador de memoria
- En ejecución paralela, la saturación del ancho de banda de la GPU provoca un fuerte aumento de latencia
- Un pipeline secuencial GPU → SSD → GPU es la forma óptima para este hardware
1 comentarios
Comentarios en Hacker News
Hay otra forma de ejecutar Qwen 3.5 397B incluso en dispositivos de consumo
Existe una versión con cuantización de aproximadamente 2.5 BPW (quant), así que también es totalmente posible en equipos con 128 GB de memoria
Yo lo corrí bien en un M1 Ultra a unos 20 tok/s, manteniendo un contexto de 256k
Los resultados de lm-evaluation-harness fueron más o menos: mmlu 87.86%, gpqa diamond 82.32%, gsm8k 86.43%, ifeval 75.90%
Dejé una explicación más detallada de mi experiencia en enlace 1 de la discusión en Hugging Face y enlace 2
Es un excelente modelo para inferencia offline
Reduce la cantidad de expertos por token de 10 a 4, así que la calidad baja todavía más
Para prompts cortos está bien, pero en sesiones largas ya no sirve
También tiene el problema de generar
"name"en vez de\name\en la salida JSON, lo que vuelve inestable la llamada de herramientasTambién quisiera saber si sigue funcionando bien con contextos largos
Y qué gusto ver tu apodo después de tanto tiempo: fuiste quien creó Neovim, qué éxito tan impresionante
Yo también lo uso todos los días
Tal vez se podría estimar con CoconutBattery
Viendo los detalles, parece que lograron alrededor de 5 tok/s usando cuantización de 2 bits y reduciendo los expertos de 10 a 4
Es una prueba de concepto interesante, pero está bastante lejos de la calidad del modelo 397B original
Este tipo de optimizaciones extremas termina causando una pérdida de inteligencia en el modelo
También está el problema de que genera
"name"en vez de\name\en la salida JSON, así que no sirve para uso realReconozco que demuestra que este tipo de experimento es técnicamente posible, pero no está en un nivel realmente utilizable
Últimamente ya me cansé de ver tantos papers escritos por IA
Pero he escuchado que incluso los LLM comerciales tienen baja precisión en tool calling
Supongo que debe de ser algo difícil de implementar o estructuralmente imposible en alguna parte
También hubo discusión relacionada en r/LocalLLaMA
Según la página de GitHub, el acceso simple por mmap se vuelve un cuello de botella por la sobrecarga a nivel de página
Me pregunto si en macOS se podría mejorar configurando huge page o haciendo prefetch con
posix_fadviseLa pérdida de calidad con cuantización de 2 bits sí es un problema serio
En tareas reales, he visto que un modelo 30B de 4 bits bien afinado rinde mejor que uno de 70B+ a 2 bits
Si reduces la cantidad de expertos, en la práctica termina siendo otro modelo
Aun así, es interesante que estén poniendo a prueba los límites del hardware de consumo
Cansa que el título “ejecutarlo en una laptop” casi siempre termine significando una MacBook de $3000
La tecnología de compresión es impresionante, pero no es una opción realista para el usuario común
Pero al ver el título no espero que vaya a correr en cualquier laptop
Prefiero disfrutar estos experimentos en vez de reaccionar con demasiado cinismo
También hay mucha gente que ya tiene MacBooks potentes así por edición de video y otros usos
La ventaja es poder experimentar con la laptop que ya tienes, sin equipo adicional
Me dio alrededor de 20 tok/s, y me parece un nivel bastante accesible incluso para una persona
Incluso valió la pena como inversión de trabajo
“No Python. No frameworks. Just C, Objective-C, and hand-tuned Metal shaders.”
Apenas leí esa frase, enseguida me imaginé de dónde habían salido los tokens
Dicen “Hand-written Metal kernels”, pero ¿no habrá sido GPT quien los escribió? 😉
Es un resultado realmente impresionante
Me pregunto si en Linux se podría hacer algo parecido, usando acceso basado en memoria del sistema en vez de SSD
O incluso suena interesante la idea de guardar los pesos en una especie de ROM
Solo que este proyecto usa Metal, así que está limitado a macOS
Pero los modelos MoE siguen teniendo una limitación fuerte de ancho de banda
Pero en la etapa de decodificación, la sobrecarga de transferir desde CPU termina siendo mayor que usar GPU, así que la ganancia es poca
Lo más eficiente es usar la GPU solo para acelerar la parte compartida
cuando el modelo se va a la RAM del sistema o al disco, el rendimiento cae de forma drástica
Se mencionó que el SSD era el cuello de botella, pero el autor dijo que obtuvo 15 GB/s
Según yo, el ancho de banda máximo era de unos 8 GB/s. ¿Qué se me está escapando?
Cuando sale el resultado del router, se cargan los expertos desde el SSD y en ese momento el SSD se satura
El IO promedio ronda los 2970 MB/s, bastante por debajo del límite del SSD
Quizá sería mejor paralelizar algunos tensores con lecturas asíncronas
Cuando experimenté con io_uring en Linux, cerca de un 20% de las lecturas terminaban en paralelo mientras se hacía el cómputo