1 Punkte von GN⁺ 2023-07-24 | 1 Kommentare | Auf WhatsApp teilen
  • llama2.c ist eine „Full-Stack“-Trainings- und Inferenzlösung, die die Llama-2-LLM-Architektur in PyTorch trainiert und die Inferenz mit der einfachen C-Datei run.c ausführt
  • Der zentrale Fokus liegt auf Minimalismus und Einfachheit; es handelt sich um eine Lehr-Implementierung, die die Llama-2-Architektur fest einkodiert und aus einer einzigen reinen C-Inferenzdatei ohne Abhängigkeiten besteht
  • Aus der Perspektive, dass selbst sehr kleine LLMs starke Leistung liefern können, wenn die Domäne ausreichend eingegrenzt ist, wird ein Beispielmodell auf Basis von TinyStories bereitgestellt
    • Das 15M-Parameter-Modell ist ein Download von etwa 60 MB und kann nach make run mit ./run stories15M.bin ausgeführt werden
    • Es werden auch Modelle mit 42M und 110M Parametern angeboten; das 110M-Modell wird als gleich groß wie GPT-1 bezeichnet
  • Auch Metas Llama-2-Modelle können inferiert werden, da die neuronale Netzwerkarchitektur identisch ist. Allerdings müssen die Checkpoints gemäß den Meta-Richtlinien bezogen und anschließend mit export.py in das llama2.c-Format umgewandelt werden
    • Derzeit führt run.c nur fp32-Inferenz aus, daher lassen sich Modelle größer als 7B wahrscheinlich nicht produktiv laden
    • 13B und größer funktionieren derzeit wegen Integer-Overflow in der Pointer-Arithmetik nicht; das ist noch nicht behoben
  • int8-quantisierte Inferenz ist in runq.c implementiert; dabei werden mit der Q8_0-Methode die an der Matmul beteiligten Gewichte quantisiert, und Aktivierungswerte werden zur Laufzeit dynamisch quantisiert und dequantisiert
    • Ein fp32-Export von Llama 2 7B erzeugt eine 26-GB-Datei, ein quantisierter Export der Version 2 eine 6,7-GB-Datei
    • In der Umgebung des Autors lief fp32 mit OpenMP und 64 Threads mit 4,6 tok/s, int8 mit 14 tok/s, was einer 4-fachen Reduktion der Checkpoint-Größe und einem Geschwindigkeitsgewinn von etwa dem 3-Fachen entspricht
  • Die Nutzung umfasst das Ausführen der C-Inferenz, die Eingabe eines Prompts, die Steuerung von Temperature- und Top-p-Sampling, das Starten des Chat-Modus und die Angabe eines benutzerdefinierten Tokenizers
    • Ein Beispielaufruf hat die Form ./run stories42M.bin -t 0.8 -n 256 -i "One day, Lily met a Shoggoth"
    • Chat-Modelle werden mit dem Flag -m chat gestartet, etwa ./run llama2_7b_chat.bin -m chat
    • Ein benutzerdefinierter Tokenizer wird mit tokenizer.py in das .bin-Format exportiert und dann über das Flag -z angegeben
  • Modelle auf Hugging Face, die die Llama-2-Architektur verwenden, können mit dem Flag --hf von export.py in eine .bin-Datei exportiert werden
  • Der Trainingsablauf reicht vom Herunterladen und Vor-Tokenisieren von TinyStories über das Ausführen von train.py bis zum Export des Modells und anschließender C-Inferenz
    • Das standardmäßige TinyStories-Beispiel ist derzeit das einzige bereitgestellte Datensatzbeispiel
    • Für das Training eines benutzerdefinierten Tokenizers wird sentencepiece verwendet; im Beispiel kommt die Einstellung --vocab_size=4096 zum Einsatz
  • Performance-bezogene Builds sind in make run, make runfast und make runomp aufgeteilt; der OpenMP-Build aktiviert #pragma omp parallel for innerhalb von Matmul und Attention, um Schleifenarbeit auf mehrere Prozessoren zu verteilen
  • Build-Anleitungen für verschiedene Plattformen werden für Windows, Centos 7, Amazon Linux 2018 und Mac bereitgestellt
    • Unter Windows werden build_msvc.bat oder make win64 verwendet
    • Unter Centos 7 und Amazon Linux 2018 werden make rungnu oder make runompgnu verwendet
    • Für den OpenMP-Build auf dem Mac wird nach der Installation von clang über brew make runomp CC=/opt/homebrew/opt/llvm/bin/clang verwendet
  • Für Tests stehen pytest und der C-Test make testcc zur Verfügung; test_all.py führt 200 Forward-Schritte in C und Python aus und vergleicht sie mit bekannten erwarteten Ausgaben
  • Das Projektziel ist, eine einfache Referenzimplementierung zu bewahren, die aus zwei gut lesbaren .py-Dateien für das Training und C-Inferenzcode besteht, und nicht auf komplexe Frameworks oder viele Optionen abzuzielen
  • Die Lizenz ist MIT

1 Kommentare

 
GN⁺ 2023-07-24
Hacker-News-Kommentare
  • Als ich sah, dass es auf HN gepostet wurde, fand ich es interessant :) Der ursprüngliche Checkpoint läuft auf einem MacBook Air M1, mit -O3 kompiliert, mit unerwartet schnellen 100 tok/s, daher wird jetzt ein größeres 44M-Modell trainiert
    Es dürfte trotzdem interaktiv ausführbar sein, und vielleicht könnte sogar ein 7B-Llama-Modell in Reichweite kommen

    • Ich habe nanoGPT ein wenig angepasst und versucht, ein 12M-Modell mit 2 GB von GPT-4-generierten Daten aus TinyStories vorzutrainieren, und das Ergebnis war ziemlich überraschend
      Danach habe ich es noch etwas an Wikipedia angepasst, und es wurde zu einem deutlich klügeren und deutlich kleineren plausiblen Unsinnsgenerator als ein geglättetes n-Gramm-Modell. Kleine LLMs werden in vielen Bereichen wohl Mainstream, und das nächste Ziel ist, Llama2 7B auf 10~100M zu verkleinern, ohne dass es dabei wesentlich dümmer wird
    • Wie immer inspiriert die Arbeit. Anfängerfrage: Was wäre der praktischste Weg, ein LLM in vernünftiger Größe auf einem normalen Linux-Server ohne schicke GPU für eine Hobby-Web-App zu betreiben?
      Eine GPU-Instanz bei etwas wie Linode zu mieten ist viel teurer als ein normaler Web-App-Server, daher würde ich gern wissen, ob das völlig unrealistisch ist oder ob so ein Ansatz oder andere Methoden ein realistischer Weg sind
    • Ich würde gern einen ersten Eindruck zur relativen Qualität/Leistung kleiner Llama-2-Modelle im Vergleich zu kleinen GPT-2-Modellen hören
    • Ich frage mich, ob du es für möglich hältst, auch einen reinen C-Trainer statt Python zu bauen
    • Ich würde gern wissen, wo diese Modelle trainiert werden: auf Heimhardware, M1 oder in der Cloud
  • Es gibt eine Version von Georgi Gerganov, bekannt durch llama.cpp, die mit Emscripten im Browser läuft: https://ggerganov.com/llama2.c/
    Der laufende Twitter-Thread ist hier: https://twitter.com/ggerganov/status/1683174252990660610
    Sowohl das Original als auch diese Arbeit sind wirklich großartig, und auch wenn es eher ein Proof of Concept mit sehr kleinen Modellen ist, sind Local-first-LLMs besonders spannend. Die Idee, mit lokaler Inferenz Web-Apps zu bauen, gefällt mir
    Wenn das zu Optimierungen, Forschung an kleineren Modellen, Teil-Downloads und der Nutzung von WebGPU führt, könnte es der Ausgangspunkt für eine neue Art sein, private lokale LLM-basierte Apps zu bauen. Die gleichen Fähigkeiten wie bei LLMs, die auf riesigen Clustern mit High-End-GPUs gehostet werden, dürften schwer sein, aber es gibt viele Anwendungsfälle, die dieser Ansatz eröffnen kann

    • Im ersten Link kam eine ziemlich seltsame Ausgabe heraus. Zuerst beginnt es wie ein plausibles Märchen, aber dann nehmen die Tippfehler zu und es zerfällt in wirres Gerede, in das fremdsprachige und technische/Programmierbegriffe eingemischt sind
      Zum Beispiel beginnt es mit „Once upon a time...“ und wirkt wie eine Geschichte über Lily und Timmy, dann tauchen „Butterfly would pauseWhy“, „TextField“, querySelector, HttpRequest und Fragmente aus verschiedenen Sprachen auf, bis die Ausgabe völlig auseinanderfällt
  • Für Interessierte gibt es auch eine Rust-Version. Im Release-Modus erreicht sie etwa 106 tokens/second
    https://github.com/garrisonhess/llama2.c/blob/517a1a3e487f31...

    • Es gibt auch noch eine andere Rust-Version. Sie verwendet die candle-ML-Bibliothek, an der seit letztem Monat gearbeitet wird, und kann ebenfalls im Browser laufen: https://laurentmazare.github.io/candle-llama2/index.html
      Die Nicht-Web-Version unterstützt GPUs vollständig, ist aber überhaupt nicht minimalistisch
    • Wie man in Rust oft sieht, wird etwas bereits Vorhandenes manchmal einfach nur deshalb übertragen, weil es möglich ist, ohne irgendeinen Vorteil zu bringen
      Manchmal zersplittert das sogar die Bemühungen der Community, ein Projekt zu verbessern
  • Viele scheinen nicht zu verstehen, wie kühn dieser Schritt ist
    Andrej bekommt bei OpenAI (MSFT) eine hohe Vergütung und hilft trotzdem Apple, Facebook und vor allem der Open-Source-Bewegung. Es wäre aber wohl schwer, ihn zu verdrängen, denn dann könnte er sofort zu Tesla oder xAI gehen

  • Ich habe den Eindruck, dass Llama-2 für kreative Arbeiten wegen des starken Safety-Filterings praktisch unbrauchbar ist: https://i.imgur.com/GFY0wSL.png

    • Meiner persönlichen Ansicht nach ist das Filtern unter dem Namen „Sicherheit“ sogar so stark, dass es sich um 180 Grad drehen und hasserfüllte oder negative Stereotype eher verstärken kann: https://i.imgur.com/xkzXrPK.png und https://i.imgur.com/3HQ8FqL.png
      Dieses Verhalten ließ sich allerdings nur teilweise reproduzieren, wenn es bei Llama2-70b-chat TGI Hugging Face als zweite Nachricht gesendet wurde; möglicherweise gibt es etwas Merkwürdiges an der Art des Promptings, das dieses Verhalten verursacht. Ich konnte das Modell selbst noch nicht ausführen, um weiter nachzuforschen
    • Wenn ein vortrainiertes Modell verfügbar ist, sollte man besser kein instruct/chat-Modell verwenden
      Chat/instruct hat Vorteile wie leichtere Verteilung an Drittanwender, einfachere Prompts und eingebaute Sicherheitsvorkehrungen, aber für den eigenen Gebrauch ist es dem vortrainierten Modell wirklich deutlich unterlegen. An diesem Punkt könnte Llama 2 gegenüber OpenAI im Vorteil sein, weil OpenAI die vortrainierten GPT-3-Modelle eingestellt hat und sich offenbar künftig nur noch auf Chat-Modelle konzentrieren will
    • Wenn man es sich vorstellt, wäre es so, als würden Casca und Brutus Caesar nicht erstechen, sondern ihn höflich mit seinem möglichen Machtmissbrauch und seinen diktatorischen Neigungen konfrontieren
    • Das übermäßige Filtern betrifft nicht ganz „llama-2“, sondern Llama-2 chat
    • Man muss die Leute vom Typ „ethische KI“ zurückdrängen. Es wird immer klarer, dass sie wirklich lästig sind
      Ich will keine Sicherheits-Schere. Es ist in Ordnung, Dinge einzuschränken, die auf dem eigenen Server laufen, aber man sollte mir keine Modelle geben, die ich auf meinem Computer nicht nach Belieben ändern und verwenden kann
  • Andrej hat hier ausführlicher dazu gepostet: https://twitter.com/karpathy/status/1683143097604243456?s=46...

  • Falls man sich für solche Themen interessiert: Dieser Code lässt sich sauber mit dem WASI SDK bauen und läuft ohne Änderungen in einer Wasm-Runtime

  • Ich frage mich, wie viel Speicher man braucht, um ein neuronales Netz auszuführen
    Reicht es, zunächst nur die ersten beiden Schichten von der Festplatte zu lesen und die Aktivierungswerte aller Knoten zu berechnen, dann die erste Schicht zu verwerfen, die dritte Schicht zu lesen und erneut zu berechnen, dann die zweite Schicht zu verwerfen usw.? Wenn ja, würde das bedeuten, dass der Speicher nur groß genug für zwei Schichten sein muss?

    • TheBloke von Hugging Face hat den Speicherbedarf nach quantisierter Version beliebter Modelle dokumentiert: https://huggingface.co/TheBloke
      Kurz gesagt hängt das maximale RAM von der Quantisierungsmethode ab, und grob liegen 7B-Modelle bei 4–8 GB, 13B-Modelle bei 8–15 GB, 30B-Modelle bei 13–33 GB und 70B-Modelle bei 31–75 GB
    • Man muss das Einlesen-und-Verwerfen nicht selbst umsetzen. Man kann das gesamte Netzwerk per mmap einbinden und das Betriebssystem die Arbeit erledigen lassen
    • Möglich ist es, aber dann ist man durch die Datenträgerbandbreite begrenzt
    • Soweit ich weiß, muss man bei O(N²)-Transformer-Inferenz alle Aktivierungswerte cachen
  • Mir kam gerade der Gedanke: Aktuelle LLMs geben eine Wahrscheinlichkeitsverteilung zurück, ein Zufalls-Sampler wählt eines aus und hängt es an die Ausgabe an, dann wiederholt sich der Vorgang
    Wäre es stattdessen möglich, dass der Zufallsgenerator N Token auswählt, die die Verteilung annähern, das LLM daraus N neue Verteilungen erzeugt und man diese dann irgendwie kombiniert, um aus der kombinierten Verteilung wieder N Token auszuwählen?

    • Das klingt fast wie Beam Search und ist tatsächlich eine gängige Generierungstechnik: https://en.wikipedia.org/wiki/Beam_search
      Beispiele gibt es unter https://huggingface.co/docs/transformers/internal/generation...
    • Klingt nach einem lohnenden Forschungsansatz, aber wahrscheinlich müsste man viel weiter als 2 Token vorausgenerieren. Vielleicht eher 20 Token im Blick behalten, aber man möchte das LLM ja nicht N^20-mal ausführen, also wäre es womöglich besser, etwa 200 repräsentative Samples aus den möglichen Kombinationen der nächsten 20 Token zu ziehen
      Wie genau man das machen würde, weiß ich allerdings nicht
    • Ich bin Anfänger, aber mir gefällt die Idee. Ich kenne die Antwort nicht, aber man könnte damit experimentieren, und vermutlich haben Forschende es schon ausprobiert
      Natürlich braucht man dabei pro Tokengenerierung N-mal so viel Rechenaufwand. Man könnte die Top-N auswählen oder, falls nötig, Temperature Scaling auf die Logits anwenden und daraus N sampeln
  • Ist das für Lehrzwecke gedacht? Wenn man den Erfolg von llama.cpp und diesem Projekt sieht, wirkt es so, als würde sich die Branche statt auf allgemeine Frameworks wie PyTorch, TensorFlow oder ONNX Runtime eher in Richtung separater Quellcode pro veröffentlichtem Modell bewegen

    • Das wirkt vollständig auf Lehrzwecke ausgerichtet
      Und nein: Trotz des Namens unterstützt llama.cpp nicht nur llama. Es ist auch nicht vollständig maßgeschneidert, sondern baut auf der allgemeineren Tensor-Bibliothek bzw. dem Framework ggml auf
    • Auch innerhalb von Frameworks gibt es getrennten Quellcode pro Modell. Modelle sind maßgeschneiderter Code, der die Grundbausteine des Frameworks kombiniert; sie entstehen nicht rein aus dem Framework selbst. So funktioniert explorative Forschung nun einmal
      Wenn man dann ein Modell findet, das gut funktioniert, fließt diese Weiterentwicklung oft in die nächste Framework-Version ein. Deshalb gibt es in TensorFlow Grundbausteine wie CNN, GRU und TransformerEncoder, und zugleich entstehen hardware-spezifische Implementierungen, die Allgemeingültigkeit zugunsten von Geschwindigkeit opfern
    • Da es Single-Threaded ist, kann man es wohl als lehrorientiert ansehen