1 puntos por GN⁺ 2023-07-24 | 1 comentarios | Compartir por WhatsApp
  • 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.bin después de make 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
  • 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.c solo 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
  • La inferencia con cuantización int8 está implementada en runq.c; usa el esquema Q8_0 para cuantizar los pesos que participan en matmul, 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 .bin con tokenizer.py y luego se indica con la bandera -z
  • Los modelos de Hugging Face que usan la arquitectura Llama 2 pueden exportarse a archivos .bin con la bandera --hf de export.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 runfast y make runomp; la compilación con OpenMP activa #pragma omp parallel for dentro de matmul y attention para 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.bat o make win64
    • En Centos 7 y Amazon Linux 2018 se usa make rungnu o make 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
  • Las pruebas incluyen pytest y la prueba en C make testcc; test_all.py ejecuta 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 .py de 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

 
GN⁺ 2023-07-24
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 -O3 en una MacBook Air M1, así que ahora están entrenando un modelo más grande de 44M
    Aun así, parece que podría ejecutarse de forma interactiva, y quizá hasta un modelo Llama de 7B podría estar al alcance

    • Modifiqué un poco nanoGPT para preentrenar un modelo de 12M con 2 GB de datos de TinyStories generados por GPT-4, y el resultado fue bastante sorprendente
      Luego 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
    • Como siempre, este trabajo inspira. Pregunta de principiante: me pregunto cuál sería la ruta más práctica para correr un LLM de tamaño razonable en un servidor Linux común, sin GPUs llamativas, para conectarlo a una webapp de hobby
      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
    • Me pregunto si ya hay alguna impresión inicial sobre la calidad/rendimiento relativo entre modelos pequeños de Llama-2 y modelos pequeños de GPT-2
    • Me pregunto si creen que también se podría hacer un entrenador en C puro en lugar de Python
    • Me pregunto dónde entrenan estos modelos: en equipo casero, en M1 o en la nube
  • 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

    • En el primer enlace salió una salida bastante rara. Al principio parece arrancar como un cuento plausible, pero luego empiezan a aumentar los errores tipográficos y se desmorona en divagaciones, mezclando idiomas extranjeros y términos técnicos/de programación
      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 rota
  • Para 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...

    • También hay otra versión en Rust. Usa la biblioteca candle ML, en la que han estado trabajando desde el mes pasado, y también puede correr en el navegador: https://laurentmazare.github.io/candle-llama2/index.html
      La versión no web soporta GPU por completo, pero no es nada minimalista
    • Como suele pasar en Rust, a veces ya existe algo y alguien simplemente lo reescribe porque puede, sin aportar ninguna ventaja
      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

    • Personalmente, creo que el filtrado es tan fuerte en nombre de la “seguridad” que puede terminar dando un giro de 180 grados y reforzando estereotipos odiosos o negativos: https://i.imgur.com/xkzXrPK.png y https://i.imgur.com/3HQ8FqL.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
    • Si tienes el modelo preentrenado, es mejor no usar un modelo instruct/chat
      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
    • Si lo imaginas, sería como si Casca y Brutus no apuñalaran a Caesar, sino que lo confrontaran cortésmente sobre su posible abuso de poder y sus tendencias dictatoriales
    • El filtrado excesivo no corresponde a todo “llama-2”, sino a Llama-2 chat
    • Hay que apartar a la gente de la “IA ética”. Cada vez queda más claro que se están volviendo realmente molestos
      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

    • TheBloke de Hugging Face documentó los requisitos de memoria por cada versión cuantizada de modelos populares: https://huggingface.co/TheBloke
      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
    • No hace falta implementar manualmente la lógica de leer y descartar. Puedes hacer mmap de toda la red y dejar que el sistema operativo se encargue
    • Es posible, pero entonces quedarías limitado por el ancho de banda del disco
    • Tengo entendido que en la inferencia de transformers O(N²) hay que cachear todas las activaciones
  • 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?

    • Suena casi como beam search, y de hecho es una técnica de generación bastante común: https://en.wikipedia.org/wiki/Beam_search
      Puedes ver ejemplos en https://huggingface.co/docs/transformers/internal/generation...
    • Suena como una línea de investigación interesante, pero probablemente habría que generar mucho más allá de 2 tokens. Tal vez mirar unos 20 tokens, aunque no querrías ejecutar el LLM N^20 veces, así que quizás sería mejor tomar unas 200 muestras representativas de las posibles combinaciones de los siguientes 20 tokens
      Pero no sé cómo hacerlo
    • Soy principiante, pero me gusta la idea. No sé la respuesta, pero parece algo que se podría probar, y probablemente algún investigador ya lo intentó
      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

    • Esto parece ser totalmente con fines educativos
      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 ggml
    • Incluso dentro de los frameworks hay código fuente separado por modelo. Los modelos son código personalizado que combina los bloques básicos del framework; no se construyen solo con el framework puro. Así es la naturaleza de la investigación exploratoria
      Pero 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
    • Como es de un solo hilo, tiene sentido verlo como algo educativo