- llama2.c es una solución “fullstack” de entrenamiento e inferencia que entrena la arquitectura Llama 2 LLM con PyTorch y realiza inferencia con un archivo C simple,
run.c - El enfoque principal es el minimalismo y la simplicidad; es una implementación educativa que codifica de forma rígida la arquitectura de Llama 2 y está compuesta por un único archivo de inferencia en C puro, sin dependencias
- Desde la idea de que incluso un LLM muy pequeño puede rendir muy bien si el dominio se acota lo suficiente, ofrece modelos de ejemplo basados en TinyStories
- El modelo de 15M parámetros requiere una descarga de unos 60MB y se puede ejecutar con
./run stories15M.bindespués demake run - También se ofrecen modelos de 42M y 110M parámetros, y se indica que el modelo de 110M tiene el mismo tamaño que GPT-1
- El modelo de 15M parámetros requiere una descarga de unos 60MB y se puede ejecutar con
- Los modelos Llama 2 de Meta también pueden usarse para inferencia porque la arquitectura de red neuronal es la misma, pero hay que obtener el checkpoint siguiendo las directrices de Meta y luego convertirlo al formato de llama2.c con
export.py- Actualmente,
run.csolo realiza inferencia fp32, por lo que es probable que cargar modelos mayores que 7B no sea práctico en producción - Los modelos de 13B o más no funcionan actualmente debido a un integer overflow en la aritmética de punteros, y sigue sin corregirse
- Actualmente,
- La inferencia con cuantización int8 está implementada en
runq.c; usa el esquema Q8_0 para cuantizar los pesos que participan enmatmul, y también cuantiza y de-cuantiza dinámicamente los valores de activación en tiempo de ejecución- La exportación fp32 de Llama 2 7B genera un archivo de 26GB, mientras que la exportación cuantizada version 2 genera un archivo de 6.7GB
- En el entorno del autor, con OpenMP y 64 hilos, fp32 corre a 4.6 tok/s e int8 a 14 tok/s, lo que implica una reducción de 4x en el tamaño del checkpoint y una mejora de velocidad de alrededor de 3x
- El modo de uso incluye ejecutar la inferencia en C, ingresar prompts, controlar el muestreo con temperature y top-p, ejecutar en modo chat y especificar un tokenizer personalizado
- Un ejemplo de ejecución es
./run stories42M.bin -t 0.8 -n 256 -i "One day, Lily met a Shoggoth" - Los modelos chat se ejecutan con la bandera
-m chat, como en./run llama2_7b_chat.bin -m chat - Un tokenizer personalizado se exporta en formato
.bincontokenizer.pyy luego se indica con la bandera-z
- Un ejemplo de ejecución es
- Los modelos de Hugging Face que usan la arquitectura Llama 2 pueden exportarse a archivos
.bincon la bandera--hfdeexport.py - El flujo de entrenamiento continúa desde la descarga y pretokenización de TinyStories, la ejecución de
train.py, la exportación del modelo y luego la inferencia en C- El ejemplo base de TinyStories es, por ahora, el único ejemplo de dataset disponible
- El entrenamiento de un tokenizer personalizado usa
sentencepiece, y en el ejemplo se usa la configuración--vocab_size=4096
- Las compilaciones relacionadas con rendimiento se dividen en
make run,make runfastymake runomp; la compilación con OpenMP activa#pragma omp parallel fordentro dematmulyattentionpara dividir el trabajo de los bucles entre varios procesadores - Se ofrecen instrucciones de compilación para Windows, Centos 7, Amazon Linux 2018 y Mac
- En Windows se usa
build_msvc.batomake win64 - En Centos 7 y Amazon Linux 2018 se usa
make rungnuomake runompgnu - Para la compilación con OpenMP en Mac, después de instalar clang con brew, se usa
make runomp CC=/opt/homebrew/opt/llvm/bin/clang
- En Windows se usa
- Las pruebas incluyen
pytesty la prueba en Cmake testcc;test_all.pyejecuta 200 pasos de forward tanto en C como en Python y los compara con salidas esperadas conocidas - El objetivo del proyecto es mantener una implementación de referencia simple, compuesta por 2 archivos
.pyde entrenamiento fáciles de leer y código de inferencia en C, sin apuntar a frameworks complejos ni a una gran cantidad de opciones - La licencia es MIT
1 comentarios
Comentarios de Hacker News
Vi esto en HN y está divertido :) El checkpoint original corría a unos 100 tok/s, mucho más rápido de lo esperado, compilado con
-O3en una MacBook Air M1, así que ahora están entrenando un modelo más grande de 44MAun así, parece que podría ejecutarse de forma interactiva, y quizá hasta un modelo Llama de 7B podría estar al alcance
nanoGPTpara preentrenar un modelo de 12M con 2 GB de datos de TinyStories generados por GPT-4, y el resultado fue bastante sorprendenteLuego lo adapté un poco con Wikipedia, y terminó siendo un generador de disparates plausibles mucho más inteligente y mucho más pequeño que un modelo n-gram suavizado. Creo que los LLM pequeños se volverán algo común en varios ámbitos, y el siguiente objetivo es reducir Llama2 7B a 10~100M sin que se vuelva demasiado tonto
Alquilar una instancia con GPU en algo como Linode sale muchísimo más caro que un servidor normal para webapps, así que quisiera saber si esto está completamente fuera de alcance o si este enfoque u otros podrían ser una vía realista
Georgi Gerganov, famoso por llama.cpp, tiene una versión que corre en el navegador con Emscripten: https://ggerganov.com/llama2.c/
El hilo de Twitter en curso está aquí: https://twitter.com/ggerganov/status/1683174252990660610
Tanto el original como este trabajo son realmente geniales, y aunque se parece más a una prueba de concepto con modelos muy pequeños, la idea de los LLM locales primero es especialmente interesante. Me gusta la noción de poder crear una webapp con inferencia local
Si esto lleva a optimización, investigación de modelos más pequeños, descargas parciales y uso de WebGPU, podría ser el inicio de una nueva forma de crear apps privadas basadas en LLM locales. No tendrá las mismas capacidades que un LLM alojado en grandes clústeres con GPUs de gama alta, pero hay muchos casos de uso que este enfoque podría abrir
Por ejemplo, empieza con “Once upon a time...”, parece la historia de Lily y Timmy, pero luego aparecen cosas como “Butterfly would pauseWhy”, “TextField”,
querySelector,HttpRequest, y fragmentos de varios idiomas mezclados hasta volverse una salida completamente rotaPara quien tenga curiosidad, también hay una versión en Rust. En modo release da alrededor de 106 tokens/second
https://github.com/garrisonhess/llama2.c/blob/517a1a3e487f31...
La versión no web soporta GPU por completo, pero no es nada minimalista
A veces eso también dispersa el esfuerzo de la comunidad por mejorar el proyecto
No creo que mucha gente entienda lo audaz que es este movimiento
Andrej recibe una gran compensación en OpenAI(MSFT), y aun así está ayudando a Apple, Facebook y, más importante aún, al movimiento de código abierto. Igual sería difícil desplazarlo, porque entonces podría irse de inmediato a Tesla o xAI
Siento que Llama-2 tiene un filtrado de seguridad tan fuerte que no sirve para trabajo creativo: https://i.imgur.com/GFY0wSL.png
Aun así, este fenómeno solo se reprodujo hasta cierto punto al enviarlo como segundo mensaje en Llama2-70b-chat TGI de Hugging Face, y podría haber algo raro en la forma del prompt que provoque ese comportamiento. Todavía no he podido correr el modelo yo mismo para investigarlo más
Chat/instruct tiene la ventaja de ser fácil de distribuir a usuarios externos, usar prompts simples e incluir salvaguardas, pero para uso propio está muy por debajo del modelo preentrenado. En este punto, Llama 2 podría tener ventaja sobre OpenAI, porque OpenAI parece haber descartado los modelos preentrenados de GPT-3 y avanzar hacia ofrecer solo modelos chat
No quiero tijeras de seguridad. Está bien limitar las cosas que corren en su propio servidor, pero no deberían darme un modelo que no pueda modificar y usar como quiera en mi propia computadora
Andrej publicó más detalles aquí: https://twitter.com/karpathy/status/1683143097604243456?s=46...
Como referencia, si te interesan este tipo de cosas, este código compila limpiamente con WASI SDK y corre en un runtime de Wasm sin modificaciones
Me pregunto cuánta memoria se necesita para ejecutar una red neuronal
¿Basta con leer del disco solo las primeras dos capas y calcular las activaciones de todos los nodos, luego descartar la primera capa, leer la tercera, volver a calcular y después descartar la segunda? Si es así, me pregunto si basta con tener memoria para guardar solo dos capas
En resumen, el RAM máximo varía según el método de cuantización, y más o menos está en estos rangos: modelos 7B, 4~8GB; 13B, 8~15GB; 30B, 13~33GB; 70B, 31~75GB
Se me ocurrió algo: ahora los LLM devuelven una distribución de probabilidad, un muestreador aleatorio elige una y la agrega a la salida, y luego se repite
En vez de eso, ¿sería posible hacer que el azar elija N tokens que aproximen la distribución, pedirle al LLM que genere N distribuciones nuevas y luego combinarlas de alguna forma para volver a elegir N tokens desde esa distribución combinada?
Puedes ver ejemplos en https://huggingface.co/docs/transformers/internal/generation...
Pero no sé cómo hacerlo
Claro, requeriría N veces más cómputo por cada token generado. Puedes elegir los N más probables o, si hace falta, aplicar temperatura a los logits para muestrear N
¿Esto es con fines educativos? Viendo el éxito de llama.cpp y de este proyecto, parece que la industria se está moviendo hacia tener código fuente separado para cada modelo que sale, en lugar de usar frameworks de propósito general como PyTorch, TensorFlow u ONNX Runtime
Y no, pese al nombre, llama.cpp no soporta solo llama. Tampoco es algo completamente a medida; está construido sobre la biblioteca/framework de tensores más general
ggmlPero cuando se encuentra un modelo que funciona bien, ese avance suele incorporarse a la siguiente versión del framework. Por eso TensorFlow terminó teniendo bloques básicos como CNN, GRU y TransformerEncoder, y al mismo tiempo se crean implementaciones específicas para cierto hardware que sacrifican generalidad para ganar velocidad