KVSplit - Ejecuta contextos 2-3 veces más largos en Apple Silicon
(github.com/dipampaul17)- KVSplit es un proyecto open source que permite ejecutar LLMs grandes y ventanas de contexto largas en Apple Silicon
- Mediante una asignación separada de precisión para keys y values, logra hasta 72% de reducción de memoria con una caída de calidad menor al 1%
- Está optimizado para chips M1/M2/M3 y el framework Metal
- Demuestra con benchmarks medidos y herramientas de visualización mejoras de velocidad de ejecución y ahorro de memoria
- Ofrece instalación sencilla, comparación con un solo comando y diversas herramientas de benchmark y análisis
Introducción: por qué KVSplit importa
KVSplit es una herramienta open source que hace posible ejecutar LLMs de gran tamaño y ventanas de contexto mucho más largas en entornos Apple Silicon (M1/M2/M3) al aplicar cuantización con distinta precisión a las keys y values dentro del KV cache. Supera la limitación de proyectos existentes que cuantizan keys y values por igual, y reduce drásticamente el uso de memoria mientras mantiene la degradación de calidad en un nivel casi imperceptible. Además, publica benchmarks reales, velocidad y métricas de calidad, lo que le da credibilidad, y mejora la eficiencia de desarrollo con soporte para Metal y herramientas intuitivas de comparación y visualización.
Sus principales ventajas frente a proyectos similares son:
- Separación de precisión entre key y value para una gestión de memoria más eficiente
- Especialización para Apple Silicon y soporte de optimización total con el framework Metal
- Integración de benchmarks, perplejidad, medición y visualización de memoria/velocidad/calidad
- Instalación con un solo comando, compatibilidad con modelos e integración con llama.cpp
- Visualización en tiempo real del ahorro de memoria y varias herramientas de pruebas comparativas
Características principales y puntos clave
Resumen
- Con KVSplit es posible ejecutar en Apple Silicon LLMs mucho más grandes y longitudes de contexto más extensas que antes
- Al asignar distinta precisión de cuantización a keys y values, consigue tanto ahorro de memoria como mejora de velocidad
- Se confirmó hasta 72% de ahorro de memoria, mejoras de velocidad (5-15%↑) y una degradación de calidad menor al 1%
- Soporte completo para Metal, con aceleración óptima en Apple Silicon
Principales resultados de benchmarks
- En la configuración K8V4 (keys de 8 bits, values de 4 bits)
- 59% de ahorro de memoria y 0.86% de degradación de calidad (según perplejidad)
- 5.7% más rápido que FP16
- En la configuración K4V4 (keys/values ambos de 4 bits)
- Hasta 72% de ahorro de memoria
- Pérdida de calidad de alrededor de 6%. Recomendado para usos menos sensibles a la calidad
Comparación del efecto de ahorro de memoria
- Desde una base de FP16 con 176MB (8K tokens)
- K8V8 (keys/values de 8 bits): 93.5MB (47%)
- K8V4 (keys de 8 bits, values de 4 bits): 71.5MB (41%)
- K4V4 (keys/values de 4 bits): 49.5MB (28%)
Funciones principales
- Cuantización individual de keys y values del KV cache
- Optimización completa para Apple Silicon y Metal
- Scripts de análisis para benchmark/calidad (perplejidad)/uso de memoria
- Herramientas de visualización y generación de gráficas con calidad de publicación
- Configuración con un solo comando y comparación en tiempo real
Estructura de carpetas del proyecto
- llama.cpp: incluye build optimizado para Metal
- models: almacenamiento de archivos de modelos
- scripts: incluye scripts de benchmark/instalación/comparación/visualización
- results, plots: almacenamiento de resultados de benchmarks y archivos de visualización
- README.md
Insights científicos y resultados experimentales
Fenómeno clave del KV cache
- Los vectores key son mucho más sensibles a la cuantización que los vectores value → para mantener la calidad, hay que asignar mayor precisión a las keys
- K8V4 es el sweet spot: la distribución keys de 8 bits / values de 4 bits ofrece el mejor equilibrio entre calidad y memoria
- 59% de ahorro de memoria, solo 0.86% de empeoramiento en perplejidad y velocidad superior a FP16
- K4V8, pese a usar la misma cantidad de bits que K8V4, produce una degradación de calidad más de 7 veces mayor → confirma la importancia de la precisión en las keys
Implicaciones generales
- Logra tanto eficiencia de memoria como preservación de la calidad del modelo → permite usar contextos mucho más largos y modelos más grandes en hardware de consumo
Ejemplos de uso y recomendaciones de configuración
Ejemplos de ejecución con distintas precisiones de cuantización
- Base (FP16): ./llama.cpp/build/bin/llama-cli -m models/your-model.gguf -p "prompt" -t 8 --flash-attn
- Recomendado K8V4: --kvq 8
- K4V8 (DEMO): --kvq-key 4 --kvq-val 8
- K4V4 (máximo ahorro): --kvq 4
Ejemplo de contexto largo
- Contexto de 32K: FP16 requiere ~1.4GB, pero K8V4 puede ejecutarlo con ~400MB
Explicación de flags de línea de comandos
-t 8: cantidad de hilos; se recomiendan 8 para M1/M2/M3--flash-attn: optimización para Apple Silicon--kvq N: configura tanto keys como values en N bits--kvq-key,--kvq-val: permiten configuración individual-c N: cantidad de tokens de contexto (mientras más largo, mayor el efecto de KVSplit)-n N: cantidad de tokens a generar-f FILE: archivo de entrada del documento-m MODEL: ruta del modelo
Benchmarking avanzado y visualización
- Con benchmark_kvsplit.py se miden por configuración y longitud de secuencia las características de memoria/velocidad/perplejidad/escala
- Con visualize_results.py se generan gráficas de nivel paper
- Los resultados se guardan automáticamente en CSV/JSON y se ofrece un resumen
Optimización para Apple Silicon y visualización de memoria
- Aprovechamiento completo del framework Metal
- Efecto decisivo en equipos M1/M2/M3 con alta presión de memoria
- Con capture_memory.sh se puede visualizar en tiempo real el ahorro de memoria
- Por la alineación personalizada de páginas, la capacidad real ahorrada puede diferir ligeramente del valor teórico
Resumen de funciones
- Precisión de bits independiente para keys/values y cuantización personalizada
- Optimización total para Apple Silicon y Metal
- Benchmarks integrales de memoria/velocidad/calidad
- Visualización con calidad de paper, comparación en tiempo real y captura de memoria
- Interfaz de instalación/uso ultra simple
Citas e investigación de referencia
- "More for Keys, Less for Values: Adaptive KV Cache Quantization" (2024)
- "Unifying KV Cache Compression for Large Language Models with LeanKV" (2025)
- Implementación base: [llama.cpp], modelo de prueba: [TinyLlama]
Recomendaciones de configuración y planes futuros
- K8V4 (keys de 8 bits / values de 4 bits): 0.86% de pérdida de calidad, 59% de ahorro de memoria y +5.7% de velocidad, el mejor equilibrio
- K4V4: máximo ahorro de memoria (72%), con una caída de calidad de alrededor de 6%. Adecuado para usos donde la memoria es la prioridad
- Destaca especialmente en ejecución de contextos largos, con capacidad para manejar contextos 2-3 veces más largos
Hoja de ruta futura
- Precisión adaptativa basada en la importancia del token
- Cuantización individual por capa
- Optimización personalizada por modelo (Mistral, Phi-3, etc.)
- Próximo soporte para demo web y móvil (iOS/iPadOS)
Licencia y guía de contribución
- Licencia MIT
- Cualquier desarrollador o investigador de IA puede contribuir mediante Issues y PRs
1 comentarios
Comentarios de Hacker News
Expresión de interés diciendo que parece interesante, preguntas sobre la intuición de por qué aparece este fenómeno y cómo se llegó al hallazgo, sugerencias de mejora de usabilidad como que la etapa de aplicar el parche en el script de instalación está incompleta y usar
git submodule, y propuesta de separarllama.cppde las dependencias de Python para contemplar distintos entornos de Pythonllama.cpp, que el código de parsing de argumentos ya fue movido aarg.cppy por eso no tiene sentido, y que las opciones de cuantización K/V ya se habían agregado allama.cppen 2023; cuestionan para qué existe el parche y opinan que parece que solo cambia los argumentos de línea de comandos; fuerte recomendación de no ejecutar innecesariamente un archivoinstall.shde un repositorio nuevo para aplicar un parche tan simplePregunta sobre si este parche podría ser posible también en MLX, expectativa de que en MLX la velocidad sea mejor y de que este enfoque ayude a usuarios de Mac con conversaciones largas a velocidad utilizable
Pregunta sobre si hay una diferencia real frente a las opciones
--cache-type-k,--cache-type-vbf16se añadió hace poco; en el pasado, en GPU de Apple con el enfoquetype_k/vsolo se podía llegar a 16 bits como mínimo (f16/bf16), así que aunque no conoce con claridad el interior dellama.cpp, especula que podría ser un enfoque algo distintoTras leer el código, concluyen que el parche es innecesario, y confirman con un enlace al PR que esta función ya se incorporó a
llama.cppen 2023; advierten que resulta sospechoso que se induzca a ejecutarinstall.shaplicando un parche en lugar de usar simplemente un repositorio fork; señalan una estructura confusa con varios archivos de parche, código duplicado y sobrescritura de parches; en la práctica solo agrega una opción--kvq, cuando ya existen opciones separadas de cuantización K/V; sospechan que el autor no puede desconocer esas funciones previas; no recomiendan ejecutar scripts de repositorios que ofrecen scripts complejos; critican que aunque el post en HN y las estrellas en GitHub sean muchas, el contenido es engañoso; también preocupa que el autor siga esquivando las preguntas; añaden como conclusión que tanto el repositorio como los scripts mezclan código viejo dellama.cppcon la estructura más reciente, lo que genera aún más confusiónPregunta sobre si es posible aplicar cuantización KV diferenciada (como K8V4) también a modelos ya convertidos al formato
.gguf, y si hay restricciones por tipo de modelo o configuración de tokenizer.ggufexistentes sin conversión especial; la cuantización se aplica solo a la caché KV en tiempo de ejecución y no depende de los pesos del modelo; con las banderas--kvq-keyy--kvq-valsolo se define el formato de almacenamiento en memoria; comenta que lo probó con éxito en modelos como LLama-3, Mistral, Phi-2/Phi-3, TinyLlama y Qwen; eso sí, solo funciona en el backend Metal dellama.cpp, y como Flash Attention actualmente evita los formatos personalizados de caché KV, hace falta la opción-fa 0; fuera de eso, debería funcionar con cualquier arquitectura Transformer que use atenciónPregunta sobre si este parche es más rápido o mejor en Apple Silicon de gran capacidad como 64GB o 128GB, menciona rumores de que ampliar la ventana de contexto en Apple Silicon en realidad es lento, y expresa curiosidad por si tiene utilidad práctica con mucha memoria
Expresión de interés y solicitud de una explicación un poco más de alto nivel: si un modelo de 2048 tokens puede usarse ampliado a 4~6k, si un modelo con contexto de 128k puede usarse con ventana de 256k+, y preguntas sobre casos de uso ideales de modelos locales
Elogio diciendo que es una muy buena idea e intento, y preguntas adicionales sobre si puede aplicarse también a GPU y si puede combinarse con otras técnicas de cuantización
llama.cppya admite configuración separada con--cache-type-ky--cache-type-v; el parche actual está especializado para Metal, pero el principio puede portarse tal cual; también puede combinarse con otras técnicas de cuantización, y como la cuantización de caché KV solo se aplica durante la ejecución, no entra en conflicto con la cuantización de pesos; es una etapa separada dentro del pipeline; eso sí, motores comovLLMoTensorRT-LLM, que usan otras estructuras de caché, necesitarían implementación aparte; el mayor efecto en GPU vendría de integrarlo directamente en la arquitectura de FlashAttention, donde el ahorro de memoria podría traducirse en mejora de velocidadComenta que hay partes que no entiende bien y que le resultan extrañas, recomienda no ejecutar ese script e informa que ya lo reportó
Pregunta cómo cambia el rendimiento, y si aunque quepa un contexto más largo en memoria al final la velocidad de cómputo no seguirá siendo la misma
fp16,q8yq4, la velocidad de iteración se siente parecida; no verificó el funcionamiento interno, pero esperaba que los vectores se empaquetaran con procesamiento SIMD por lotes de 4 a 8 bits, y le queda la impresión de que en realidad no se están empaquetando