Llama2.c : inférence de Llama 2 dans un simple fichier C
(github.com/karpathy)- 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
- Le modèle de 15M de paramètres représente un téléchargement d’environ 60 Mo et peut être exécuté avec
- 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.cne 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é
- Actuellement,
- 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
.binavectokenizer.py, puis indiqué avec l’option-z
- Exemple d’exécution :
- Les modèles sur Hugging Face qui utilisent l’architecture Llama 2 peuvent être exportés en fichier
.binavec l’option--hfdeexport.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 runfastetmake runomp; le build OpenMP active#pragma omp parallel fordans 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.batoumake win64 - Sous Centos 7 et Amazon Linux 2018, utiliser
make rungnuoumake runompgnu - Sur Mac, pour un build OpenMP, installer le clang de brew puis utiliser
make runomp CC=/opt/homebrew/opt/llvm/bin/clang
- Sous Windows, utiliser
- Les tests incluent
pytestet des tests C viamake testcc;test_all.pyexé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
.pyd’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
Avis de Hacker News
C’est amusant de voir ça sur HN :) Le checkpoint d’origine, compilé avec
-O3sur 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.
nanoGPTet 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.
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.
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.
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,HttpRequestet 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...
La version non web prend entièrement en charge le GPU, mais elle n’est pas du tout minimaliste.
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
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.
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.
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
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
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 ?
On peut voir un exemple sur https://huggingface.co/docs/transformers/internal/generation...
Cela dit, je ne sais pas comment faire
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
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éralisteCela 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