1 points par GN⁺ 2023-07-24 | 1 commentaires | Partager sur WhatsApp
  • llama2.c est une solution « full stack » d’apprentissage et d’inférence qui entraîne l’architecture LLM de Llama 2 avec PyTorch, puis exécute l’inférence avec un simple fichier C, run.c
  • L’accent principal est mis sur le minimalisme et la simplicité : une implémentation pédagogique qui code en dur l’architecture de Llama 2 et se compose d’un unique fichier d’inférence en pur C, sans dépendances
  • Le projet fournit un modèle d’exemple basé sur TinyStories, avec l’idée que même un très petit LLM peut offrir de solides performances si le domaine est suffisamment restreint
    • Le modèle de 15M de paramètres représente un téléchargement d’environ 60 Mo et peut être exécuté avec make run, puis ./run stories15M.bin
    • Des modèles de 42M et 110M de paramètres sont également proposés, et il est précisé que le modèle 110M a la même taille que GPT-1
  • Les modèles Llama 2 de Meta peuvent aussi être utilisés pour l’inférence, car l’architecture du réseau neuronal est identique, mais il faut d’abord récupérer les checkpoints selon les instructions de Meta puis les convertir au format llama2.c avec export.py
    • Actuellement, run.c ne prend en charge que l’inférence fp32, il est donc probable que les modèles plus grands que 7B soient difficiles à charger de manière productive
    • Les modèles de 13B et plus ne fonctionnent pas pour le moment à cause d’un integer overflow dans l’arithmétique des pointeurs, et cela n’a pas encore été corrigé
  • L’inférence en quantification int8 est implémentée dans runq.c, avec une méthode Q8_0 qui quantifie les poids participant au matmul, tandis que les activations sont quantifiées et déquantifiées dynamiquement à l’exécution
    • Un export fp32 de Llama 2 7B produit un fichier de 26 Go, tandis que l’export quantifié version 2 produit un fichier de 6,7 Go
    • Sur l’environnement de l’auteur, avec OpenMP et 64 threads, le fp32 tourne à 4,6 tok/s et l’int8 à 14 tok/s, soit une réduction de 4× de la taille du checkpoint et un gain de vitesse d’environ 3×
  • L’utilisation couvre l’exécution de l’inférence C, la saisie de prompt, le contrôle du temperature et du top-p sampling, le mode chat et la définition d’un tokenizer personnalisé
    • Exemple d’exécution : ./run stories42M.bin -t 0.8 -n 256 -i "One day, Lily met a Shoggoth"
    • Le modèle de chat s’exécute avec l’option -m chat, par exemple ./run llama2_7b_chat.bin -m chat
    • Un tokenizer personnalisé peut être exporté au format .bin avec tokenizer.py, puis indiqué avec l’option -z
  • Les modèles sur Hugging Face qui utilisent l’architecture Llama 2 peuvent être exportés en fichier .bin avec l’option --hf de export.py
  • Le flux d’entraînement enchaîne le téléchargement et la pré-tokenisation de TinyStories, l’exécution de train.py, puis l’export du modèle avant l’inférence en C
    • L’exemple TinyStories par défaut est actuellement le seul exemple de dataset fourni
    • L’entraînement d’un tokenizer personnalisé utilise sentencepiece, avec en exemple le paramètre --vocab_size=4096
  • Les builds orientés performances sont répartis entre make run, make runfast et make runomp ; le build OpenMP active #pragma omp parallel for dans le matmul et l’attention afin de répartir le travail des boucles sur plusieurs processeurs
  • Des instructions de build sont fournies pour Windows, Centos 7, Amazon Linux 2018 et Mac
    • Sous Windows, utiliser build_msvc.bat ou make win64
    • Sous Centos 7 et Amazon Linux 2018, utiliser make rungnu ou make runompgnu
    • Sur Mac, pour un build OpenMP, installer le clang de brew puis utiliser make runomp CC=/opt/homebrew/opt/llvm/bin/clang
  • Les tests incluent pytest et des tests C via make testcc ; test_all.py exécute 200 étapes de forward en C et en Python, puis compare le résultat aux sorties attendues connues
  • L’objectif du projet est de conserver une implémentation de référence simple, composée de deux fichiers .py d’entraînement faciles à lire et d’un code d’inférence en C, sans viser un framework complexe ni une multitude d’options
  • La licence est MIT

1 commentaires

 
GN⁺ 2023-07-24
Avis de Hacker News
  • C’est amusant de voir ça sur HN :) Le checkpoint d’origine, compilé avec -O3 sur un MacBook Air M1, tourne à 100 tok/s, bien plus vite que prévu, donc j’entraîne maintenant un modèle 44M plus gros.
    Il devrait quand même pouvoir s’exécuter en interactif, et j’ai l’impression que même le modèle Llama 7B pourrait peut-être devenir accessible.

    • J’ai légèrement modifié nanoGPT et préentraîné un modèle 12M sur les 2 Go de données TinyStories générées par GPT-4 ; les résultats ont été assez surprenants.
      Après l’avoir ensuite un peu adapté avec Wikipédia, c’est devenu un générateur de baratin plausible, bien plus intelligent et bien plus petit qu’un modèle n-grammes lissé. Je pense que les petits LLM vont devenir courants dans de nombreux domaines, et le prochain objectif est de réduire Llama2 7B à 10–100M sans le rendre beaucoup plus bête.
    • Comme toujours, ce travail est inspirant. Question de débutant : je me demande quelle serait la voie la plus pratique pour faire tourner un LLM de taille raisonnable, utilisable dans une appli web perso, sur un serveur Linux ordinaire sans GPU sophistiqué.
      Louer une instance GPU chez Linode ou ailleurs coûte beaucoup plus cher qu’un serveur web classique ; j’aimerais savoir si c’est totalement hors de portée, ou si cette approche, ou une autre, constitue une voie réaliste.
    • Je me demande s’il y a déjà de premières impressions sur la qualité/les performances relatives des petits modèles Llama-2 et des petits modèles GPT-2.
    • Je me demande s’il serait envisageable de créer aussi un trainer en C pur plutôt qu’en Python.
    • Je me demande où ces modèles sont entraînés : sur du matériel à la maison, sur M1, ou dans le cloud.
  • Georgi Gerganov, connu pour llama.cpp, en a une version qui tourne dans le navigateur avec Emscripten : https://ggerganov.com/llama2.c/
    Le fil Twitter en cours est ici : https://twitter.com/ggerganov/status/1683174252990660610
    L’original comme ce travail sont vraiment excellents et, même si cela ressemble plutôt à une preuve de concept avec un tout petit modèle, les LLM local-first sont particulièrement intéressants. J’aime l’idée de pouvoir créer des applis web avec de l’inférence locale.
    Avec de l’optimisation, des recherches sur des modèles plus petits, des téléchargements partiels et l’exploitation de WebGPU, cela pourrait devenir le point de départ d’une nouvelle façon de créer des applis privées basées sur des LLM locaux. Il sera difficile d’atteindre les mêmes capacités que des LLM hébergés sur de grands clusters de GPU haut de gamme, mais cette approche ouvrira de nombreux cas d’usage.

    • Le premier lien m’a donné une sortie assez étrange. Au début, ça ressemble à un conte plausible, puis les fautes augmentent et le texte s’effondre en charabia, avec un mélange de langues étrangères et de termes techniques/de programmation.
      Par exemple, cela commence par « Once upon a time... » et semble raconter l’histoire de Lily et Timmy, puis se transforme en sortie complètement cassée avec « Butterfly would pauseWhy », « TextField », querySelector, HttpRequest et des fragments de plusieurs langues mélangés.
  • Pour les personnes intéressées, il existe aussi une version Rust. En mode release, elle atteint environ 106 tokens/second.
    https://github.com/garrisonhess/llama2.c/blob/517a1a3e487f31...

    • Il existe aussi une autre version Rust. Elle utilise la bibliothèque ML candle, sur laquelle je travaille depuis le mois dernier, et elle peut aussi tourner dans le navigateur : https://laurentmazare.github.io/candle-llama2/index.html
      La version non web prend entièrement en charge le GPU, mais elle n’est pas du tout minimaliste.
    • Comme on le voit souvent avec Rust, il arrive qu’on se contente de réécrire quelque chose d’existant simplement parce que c’est possible, sans apporter le moindre avantage.
      Parfois, cela disperse même les efforts de la communauté pour améliorer le projet.
  • J’ai l’impression que peu de gens mesurent à quel point ce geste est audacieux.
    Andrej est très bien payé chez OpenAI (MSFT), tout en aidant Apple, Facebook et, plus important encore, le mouvement open source. Cela dit, il serait difficile de le pousser dehors, car il pourrait aussitôt partir chez Tesla ou xAI.

  • J’ai l’impression que Llama-2 est tellement soumis à un filtrage de sécurité qu’il devient inutilisable pour les travaux créatifs : https://i.imgur.com/GFY0wSL.png

    • Personnellement, je trouve que le filtrage est si fort au nom de la « sécurité » qu’il peut en fait faire un virage à 180 degrés et renforcer des stéréotypes haineux ou négatifs : https://i.imgur.com/xkzXrPK.png et https://i.imgur.com/3HQ8FqL.png
      Cela dit, je n’ai réussi à reproduire ce phénomène dans une certaine mesure que lorsque je l’envoyais comme deuxième message sur Llama2-70b-chat TGI Hugging Face ; il se peut donc qu’un aspect étrange de la méthode de prompt provoque ce comportement. Je n’ai pas encore pu faire tourner le modèle moi-même pour enquêter davantage.
    • Si vous avez accès au modèle préentraîné, mieux vaut ne pas utiliser les modèles instruct/chat.
      Chat/instruct a l’avantage d’être facile à déployer auprès d’utilisateurs tiers, avec des prompts simples et des garde-fous intégrés, mais pour un usage direct, c’est vraiment nettement inférieur au modèle préentraîné. Sur ce point, Llama 2 pourrait avoir un avantage sur OpenAI, car OpenAI semble abandonner les modèles préentraînés GPT-3 pour ne proposer à l’avenir que des modèles chat.
    • En l’imaginant, cela donnerait Casca et Brutus qui, au lieu de poignarder César, le confronteraient poliment à propos de ses possibles abus de pouvoir et de ses tendances dictatoriales.
    • Ce n’est pas tout « llama-2 » qui est excessivement filtré, mais Llama-2 chat.
    • Il faut écarter les gens de l’« IA éthique ». Il devient de plus en plus évident qu’ils sont vraiment pénibles.
      Je ne veux pas de ciseaux de sécurité. Qu’ils limitent ce qui tourne sur leurs propres serveurs, très bien ; mais qu’ils ne me donnent pas un modèle que je ne peux pas modifier et utiliser comme je veux sur mon propre ordinateur.
  • Andrej a publié davantage de détails ici : https://twitter.com/karpathy/status/1683143097604243456?s=46...

  • À titre de référence, si ce sujet vous intéresse, ce code se compile proprement avec le WASI SDK et s’exécute sans modification dans un runtime Wasm

  • Je me demande quelle quantité de mémoire est nécessaire pour exécuter un réseau de neurones
    Suffit-il de ne lire depuis le disque que les deux premières couches, de calculer les activations de tous les nœuds, puis de jeter la première couche, de lire la troisième couche et de recalculer, puis de jeter la deuxième couche, et ainsi de suite ? Si oui, je me demande s’il suffit d’avoir assez de mémoire pour contenir seulement deux couches

    • TheBloke, sur Hugging Face, a documenté les besoins mémoire des versions quantifiées de modèles populaires : https://huggingface.co/TheBloke
      En résumé, la RAM maximale dépend de la méthode de quantification ; à la louche, un modèle 7B se situe entre 4 et 8 Go, un 13B entre 8 et 15 Go, un 30B entre 13 et 33 Go, et un 70B entre 31 et 75 Go
    • Il n’est pas nécessaire de gérer soi-même la lecture puis la suppression. Il suffit de mmap tout le réseau et de laisser le système d’exploitation s’en charger
    • C’est possible, mais dans ce cas on devient limité par la bande passante disque
    • D’après ce que je sais, dans l’inférence Transformer en O(N²), il faut mettre en cache toutes les activations
  • Une idée me vient : aujourd’hui, un LLM renvoie une distribution de probabilités, puis un échantillonneur aléatoire en choisit un élément, l’ajoute à la sortie, et on répète
    À la place, serait-il possible que l’aléatoire choisisse N tokens qui approximent la distribution, que le LLM génère N nouvelles distributions, puis qu’on les combine d’une certaine manière pour choisir à nouveau N tokens dans la distribution combinée ?

    • Ça ressemble beaucoup à de la recherche en faisceau (beam search), et c’est effectivement une technique de génération courante : https://en.wikipedia.org/wiki/Beam_search
      On peut voir un exemple sur https://huggingface.co/docs/transformers/internal/generation...
    • Ça semble être une piste intéressante à explorer, mais il faudrait probablement générer beaucoup plus loin que 2 tokens. Regarder environ 20 tokens serait mieux, mais comme on ne voudrait pas exécuter le LLM N^20 fois, il vaudrait sans doute mieux tirer quelque chose comme 200 échantillons représentatifs parmi les combinaisons possibles des 20 prochains tokens
      Cela dit, je ne sais pas comment faire
    • Je suis débutant, mais j’aime bien cette idée. Je ne connais pas la réponse, mais on pourrait sans doute l’expérimenter, et il est très probable qu’un chercheur ait déjà essayé
      Bien sûr, il faut N fois plus de calcul pour chaque génération de token. On peut choisir les N premiers, ou, si nécessaire, appliquer un ajustement de température aux logits pour échantillonner N éléments
  • Est-ce destiné à l’éducation ? Vu le succès de llama.cpp et de ce projet, on dirait que l’industrie s’oriente vers du code source séparé pour chaque modèle publié, plutôt que vers des frameworks généralistes comme PyTorch, TensorFlow ou ONNX Runtime

    • Celui-ci semble clairement être éducatif
      Et non. Malgré son nom, llama.cpp ne prend pas uniquement en charge Llama. Il n’est pas non plus entièrement sur mesure : il est construit au-dessus de ggml, une bibliothèque/un framework de tenseurs plus généraliste
    • Même dans les frameworks, il existe du code source distinct pour chaque modèle. Les modèles sont du code personnalisé qui combine les briques de base du framework, et non quelque chose créé uniquement par le framework. C’est la nature même de la recherche exploratoire
      Cela dit, lorsqu’un modèle qui fonctionne bien est trouvé, ses avancées finissent souvent dans la version suivante du framework. C’est ainsi que TensorFlow s’est doté de briques de base comme CNN, GRU ou TransformerEncoder, tout en voyant apparaître des implémentations matérielles spécifiques qui sacrifient la généralité pour gagner en vitesse
    • Comme c’est mono-thread, il est juste de le voir comme éducatif