El problema fundamental que aborda este trabajo es la brecha entre los requisitos de hardware de los modelos de lenguaje grandes (LLMs) modernos y la capacidad de cómputo de la infraestructura legacy. Mientras que la tendencia actual se inclina hacia el uso de GPUs y CPUs con conjuntos de instrucciones avanzados (AVX2, FMA3) para la inferencia de LLMs, existe una vasta cantidad de hardware x86 pre-AVX2 que, aunque obsoleto para cargas de trabajo intensivas, podría ser reutilizado para tareas de inferencia de menor escala. Este proyecto demuestra que, con una comprensión profunda de la microarquitectura y el código de los modelos, es posible extender la vida útil de dicho hardware, democratizando el acceso a la inferencia de LLMs y ofreciendo alternativas económicas a los servicios en la nube.
La relevancia de este enfoque radica en la eficiencia de recursos y la resiliencia. Al permitir la ejecución de LLMs en hardware local y de bajo costo, se reduce la dependencia de infraestructuras de nube costosas y se habilita la inferencia offline, útil para escenarios de baja latencia o cuando la conectividad es limitada. Este esfuerzo subraya que la optimización a nivel de instrucción y la adaptación de algoritmos son cruciales para maximizar el rendimiento en arquitecturas heterogéneas y con restricciones de recursos, un desafío recurrente en la ingeniería de sistemas distribuidos a gran escala.
Arquitectura del Sistema
La solución se centra en la adaptación de ik_llama.cpp, un fork de llama.cpp optimizado para la inferencia de modelos MoE como Gemma 4. El problema principal surgió de la dependencia de ik_llama.cpp en los conjuntos de instrucciones AVX2 y FMA3, ausentes en las CPUs Ivy Bridge (AVX1). La arquitectura de la solución implicó modificar las rutas de ejecución condicionales (#if GGML_USE_IQK_MULMAT) dentro del código base para asegurar que, cuando AVX2 no esté disponible, el sistema recurra a implementaciones de kernels que utilicen AVX1 o bucles escalares.
Específicamente, se identificaron dos operaciones críticas en la red de feed-forward de Gemma 4 MoE: MOE_FUSED_UP_GATE y FUSED_UP_GATE. Estas operaciones, que realizan una multiplicación de matrices fusionada (matmul) con una función de activación SwiGLU, caían en un caso por defecto en el dispatcher de ggml cuando GGML_USE_IQK_MULMAT estaba deshabilitado, lo que resultaba en tensores no computados y salida corrupta. La solución consistió en modificar el constructor del grafo para que, en ausencia de AVX2, dividiera el tensor combinado up_gate_exps en dos ggml_view_3d y ejecutara dos llamadas separadas a ggml_mul_mat_id, combinando los resultados con ggml_fused_mul_unary(gate, up, SILU). Estas operaciones (mul_mat_id y fused_mul_unary) ya contaban con implementaciones funcionales no-IQK (es decir, sin dependencia de AVX2). Además, se corrigieron errores de compilación en las ramas #else de los kernels de cuantificación (quantize_row_q8_0_x4, quantize_row_q8_1_x4_T) y se actualizaron los stubs de CI para garantizar la compilación en hardware sin AVX2. Finalmente, se deshabilitó la opción --run-time-repack que reordena los pesos cuantificados a un formato entrelazado (Q8_0_R8) específico de AVX2.
Flujo de Inferencia de Gemma 4 en CPU Legacy
- 1 Carga de Modelo Carga de Gemma 4 26B-A4B (Q8_0) en memoria.
- 2 Pre-procesamiento Tokenización del prompt de entrada.
- 3 Construcción de Grafo El constructor de grafo `ggml` genera operaciones adaptadas a AVX1 (sin `MOE_...
- 4 Ejecución de Kernels Ejecución de `ggml_mul_mat_id` y `ggml_fused_mul_unary` para las operaciones ...
- 5 Cálculo de Logits Propagación de tensores a través de las capas del modelo.
- 6 Muestreo de Tokens Selección del siguiente token basado en los logits.
- 7 Post-procesamiento Decodificación del token a texto legible.
- 8 Salida Generación de texto a 5.2 tokens/segundo.
| Capa | Tecnología | Justificación |
|---|---|---|
| compute | Intel Xeon E5-2690 v2 (Ivy Bridge) | Hardware de CPU subyacente para la inferencia del modelo, con soporte AVX1 pero sin AVX2. Dual CPU, DDR3 RAM, sin GPU. |
| data-processing | Gemma 4 26B-A4B (MoE) | Modelo de lenguaje grande (LLM) Mixture-of-Experts, cuantificado a Q8_0, objetivo de la inferencia. 26 mil millones de parámetros, 8 expertos activos por token. |
| data-processing | llama.cpp / ik_llama.cpp | Framework de inferencia de LLMs en CPU. `ik_llama.cpp` es un fork optimizado para MoE, adaptado para AVX1. Uso de `GGML_USE_IQK_MULMAT` para control de kernels AVX2, deshabilitado en este caso. |
| observability | Instrumentación de Logits | Técnica de depuración para inspeccionar los valores intermedios del modelo (logits) y diagnosticar la corrupción de datos. Impresión de top-5 tokens, rango, media y conteo de NaNs. |
Trade-offs
Ganancias
- ▲▲ Costo de inferencia
- ▲ Reutilización de hardware legacy
- ▲ Acceso offline a LLMs
Costes
- △ Rendimiento (throughput)
- ▲ Complejidad de desarrollo/mantenimiento
#if GGML_USE_IQK_MULMAT
// AVX2 optimized kernel
#else
// Scalar or AVX1 fallback kernel
#endifif (!GGML_USE_IQK_MULMAT) {
// Split combined tensor into two views
struct ggml_tensor *gate_view = ggml_view_3d(...);
struct ggml_tensor *up_view = ggml_view_3d(...);
// Perform two separate matrix multiplications
struct ggml_tensor *gate_out = ggml_mul_mat_id(ctx, gate_view, x);
struct ggml_tensor *up_out = ggml_mul_mat_id(ctx, up_view, x);
// Combine results with fused activation
res = ggml_fused_mul_unary(ctx, gate_out, up_out, GGML_OP_SILU);
} else {
// Original fused kernel for AVX2
}Fundamentos Teóricos
Este trabajo se conecta directamente con los principios de la optimización de compiladores y la microarquitectura de procesadores, temas fundamentales en la informática. La necesidad de adaptar el código a conjuntos de instrucciones específicos (AVX1 vs. AVX2) y la gestión de fallbacks eficientes resuenan con los conceptos de "Instruction Set Architecture (ISA)" y "micro-ops" que se estudian en cursos de arquitectura de computadores. La optimización de operaciones de multiplicación de matrices, que son el corazón de los modelos de aprendizaje profundo, ha sido un campo activo de investigación desde los trabajos pioneros en álgebra lineal numérica, como el algoritmo de Strassen (1969) para la multiplicación de matrices, que buscaba reducir la complejidad computacional.
La detección del problema de tensores no inicializados que conducía a "gibberish" determinista, y su posterior diagnóstico mediante la instrumentación de logits, es un ejemplo práctico de la aplicación de técnicas de depuración y análisis de rendimiento que se enseñan en la academia. La comprensión de cómo la corrupción de datos en una etapa intermedia (el "hidden state") puede propagarse y manifestarse en la salida final es crucial para el diseño de sistemas robustos. Este caso también ilustra la importancia de la portabilidad del código y la necesidad de considerar diferentes arquitecturas de hardware durante el desarrollo de software de alto rendimiento, un desafío que ha sido abordado en papers sobre optimización de kernels para diferentes plataformas, como los trabajos de ATLAS o BLIS para bibliotecas de álgebra lineal.