- Ein Tool zur Ausführung von Diffusion-Modell-Inferenz in reinem C/C++, einschließlich der SD-, Flux- und Wan-Familien, mit dem Ziel einer schlanken Implementierung ohne externe Abhängigkeiten
- Die Implementierung basiert auf ggml und ist als Plain C/C++-Struktur aufgebaut, die ähnlich wie llama.cpp funktioniert
- Der unterstützte Modellumfang ist in Bildmodelle, Bildbearbeitungsmodelle und Videomodelle unterteilt und umfasst SD1.x, SD2.x, SDXL, SD3/SD3.5, FLUX, Qwen Image, Wan2.1/Wan2.2, LTX-2.3 usw.
- Zum Funktionsumfang gehören PhotoMaker, Control Net für SD 1.5, LoRA im Stil von stable-diffusion-webui, LCM/LCM-LoRA, latent decoding auf Basis von TAESD, ESRGAN-Upscaling, negative prompts sowie Unterstützung für Token-Gewichtung im Tokenizer
- Als Laufzeit-Backends werden CPU, CUDA, Vulkan, Metal, OpenCL und SYCL unterstützt; bei der CPU einschließlich Unterstützung für AVX, AVX2 und AVX512 auf x86-Architekturen
- Unterstützte Plattformen sind Linux, Mac OS, Windows und Android; unter Android erfolgt die Ausführung über Termux und Local Diffusion
- Unterstützte Gewichtsformate sind
.ckpt,.pth,.pt,.safetensorsund.gguf; der Konvertierungsmodus wandelt Modellgewichte in.ggufoder.safetensorsum - Der grundlegende Nutzungsablauf besteht darin, vorkompilierte Binärdateien von der releases page herunterzuladen oder aus dem Quellcode zu bauen, anschließend die Modellgewichte zu laden und die Bildgenerierung in der Form
./bin/sd-cli -m ../models/v1-5-pruned-emaonly.safetensors -p "a lovely cat"auszuführen - Zur Optimierung des Speicherverbrauchs werden Flash Attention und VAE tiling processing bereitgestellt; Backend-Zuweisung zur Laufzeit, Parameterabstimmung und Performance-Verbesserungen sind Gegenstand separater Anleitungen
- Die Reproduzierbarkeitsoptionen sind in
--rng cudaund--rng cpuunterteilt und zielen jeweils auf Konsistenz mit dem GPU-RNG vonstable-diffusion-webuibzw. dem RNG von ComfyUI ab - In die PNG-Ausgabe werden Generierungsparameter als mit webui kompatible Textzeichenfolge eingebettet
- Es gibt Wrapper-Projekte für Golang, C#, Python, Rust und Flutter/Dart; Jellybox, Local Diffusion, LocalAI, KoboldCpp und weitere verwenden
stable-diffusion.cppals Backend für die Bildgenerierung - Das Projekt wird aktiv weiterentwickelt, und API sowie Kommandozeilenoptionen können sich häufig ändern
1 Kommentare
Meinungen auf Hacker News
Llama.cpp/ggml passt ungewöhnlich gut zu LLMs.
Der Speicherbedarf ist groß, Quantisierung ist effektiv, die Token-Erzeugung ist überraschend seriell und an die Speicherbandbreite gebunden, was gut zu CPUs passt – und noch besser zu ggmls ungewöhnlicher CPU/GPU-Pipeline für Inferenz.
Stable Diffusion ist dagegen anders. Quantisierung funktioniert dort nicht ganz so gut, UNet ist extrem rechenintensiv, und Batch-Bilderzeugung ist selbst für einzelne Nutzer effektiv und nützlich. Daher passt es besser zu GPUs/integrierten GPUs und profitiert stark von der Hackbarkeit der Python-Implementierung.
Für Stable Diffusion halte ich den Ansatz, per Machine-Learning-Compiler ausführbare Dateien zu erzeugen, für richtig. AITemplate ist bereits sehr schnell https://github.com/VoltaML/voltaML-fast-stable-diffusion, und TVM Vulkan ist ebenfalls sehr vielversprechend, falls jemand eine Demo-Implementierung sauber fertigstellt https://github.com/mlc-ai/web-stable-diffusion.
Außerdem bleibt der Großteil der Hackbarkeit einer reinen PyTorch-Implementierung erhalten.
Zum Beispiel wird beim Kompilieren
GGML_CUBLASunterstützt, und gegenüber reinem C/C++ erzielt man eine ziemlich ordentliche Beschleunigung.Selbst wenn es etwas dauert, kann man es auf einem alten Laptop ausführen.
torch.compileeine recht gute Beschleunigung, und ich meine, selbst daran gearbeitet zu haben.Ich werde prüfen, ob ich die Zahlen finden kann.
Dass sogar CLIP implementiert wurde, ist großartig.
Es wäre schon cool, allein das herauszulösen und als WebAssembly-Implementierung zu kompilieren.
Edit: Offenbar hat bereits jemand https://github.com/monatis/clip.cpp gebaut. Jetzt muss es nur noch zu WebAssembly gemacht werden.
Es ist schade, wenn man daran denkt, dass irgendwo in einem geheimen Tresor vielleicht bereits ein weiterentwickeltes Modell auf CLIP-Niveau liegt.
Edit: Ich meine nicht CLIP-2, sondern einen Fortschritt von ähnlich großer Bedeutung wie CLIP.
Die Einrichtung war unglaublich einfach, daher habe ich es zum ersten Mal direkt ausprobiert.
Ich frage mich, welche Geschwindigkeit ungefähr normal sein sollte.
Unter Linux mit
cmake .. -DGGML_OPENBLAS=ONauf einem AMD Ryzen 7 5700G ausgeführt, ohne dedizierte GPU, nur mit integrierter Grafik.Bei
./bin/sd -m ../models/sd-v1-4-ggml-model-f32.bin -p "a lovely cat"dauerte jeder Sampling-Schritt etwa 12 Sekunden, das gesamte Sampling dauerte 246,40 Sekunden.Ich frage mich, ob das die erwartbare Leistung ist.
Edit: OpenBLAS war nicht installiert, daher hatte das Flag keine Wirkung.
Damals erforderten fast alle Lösungen einen Haufen Python-Abhängigkeiten, die Installation dauerte viel zu lange und scheiterte am Ende, weil der Speicherplatz ausging.
Im Ernst: Es ersetzt buchstäblich mehrere Gigabyte Speicherplatz durch eine einzige 799-KB-Binärdatei. Als Bonus spart man mit dem offenbar schnellsten Q8_0-Format auch noch etwa 2,3 GB Daten.
Allerdings scheint es außerhalb der Standardbildgröße 512x512 Bugs zu geben. Einige Größen wie 544x544 neigen zu Assert-Fehlern, Größen unter 512x512 erzeugen manchmal Schrottbilder, und unter 384x384 passiert das fast immer.
[0] https://news.ycombinator.com/item?id=32555608
C/C++-Implementierungen im KI-Bereich haben einen besonderen Reiz.
Der Code wirkt sauber und intuitiv, und er lässt das ganze KI-Feld greifbar und erlernbar erscheinen.
Liegt das daran, dass das Python-Ökosystem so chaotisch ist?
Auch die Python-Version verwendet aus Geschwindigkeitsgründen C- und C++-Code, aber hier ist alles in einer einzigen Sprache geschrieben.
Damit wirken drei Faktoren zusammen, die sauberen Code ermöglichen.
Es ist schön zu sehen, dass Leute aus dem Machine-Learning-Bereich sich von Python lösen und Sprachen verwenden, die Hardware optimal ausnutzen und keine spezielle Umgebung fürs Bauen und Ausführen erfordern
Zunächst einmal nutzt das Projekt im Originalbeitrag, ähnlich wie llama.cpp, keine GPU, während der Großteil des Python-Codes für Machine Learning GPUs nutzt. Es ist nicht schwer, Python-Code zu schreiben, der GPUs optimal ausnutzt. Man könnte eine GPU zwar als spezielle Umgebung fürs Bauen und Ausführen bezeichnen, aber für dieses Problem passt eine GPU deutlich besser.
Zweitens wurde auch das Projekt im Originalbeitrag, ähnlich wie llama.cpp, erst dann mit effizientem und hochspezialisiertem Code umgesetzt, nachdem bestätigt war, dass bestimmte Modelle wie Stable Diffusion/LLaMA gut funktionieren. Python glänzt dagegen in der Prototyping-Phase, in der man das passende Modell noch nicht gefunden hat. Ein so einfaches und bequemes Prototyping habe ich in C++ bisher nicht gesehen.
Ich will damit nicht die hervorragende Arbeit schmälern, die die Leute rund um llama.cpp im Bereich Machine Learning auf der CPU leisten. Die gelösten Probleme sind aber völlig unterschiedlich.
Intern war das schon lange alles CUDA, C und C++.
Python ist nur ein sehr effektiver Klebstoff, der all das zusammenhält.
Das ist die einzige Methode, mit der ich diese Modelle ohne Kopfschmerzen zum Laufen gebracht habe. Der Unterschied ist riesig. CUDA und Linux sind schon keine tolle Kombination, und AMD mit Windows ist erbärmlich. Vermutlich bin ich damit nicht allein.
War es am Ende alles nur ein Problem der Speicherbandbreite?
Die GPU-Architektur besteht nicht nur aus Rechenleistung, sondern auch daraus, Arbeitsspeicher nahe an den Recheneinheiten zu platzieren. Jede Einheit hat lokalen Speicher, der mit dem globalen Speicher synchronisiert wird. Ist das ein wichtiger Grund, warum GPUs bei solchen Aufgaben so stark sind?
Es sieht nach C++ aus, warum wird es also als C/C++ bezeichnet?
Ich habe mir dieses Repository heute angesehen, es heruntergezogen und auf dem Mac eine
.dylibgebaut, dann mit Darts ffi-gen-Tool Bindings aus der bereitgestellten Header-Datei erzeugt.Ich experimentiere damit zusammen mit Flutter und nutze FFI, um keinen Subprozess starten zu müssen.
Am Ende blieben starke Kopfschmerzen und eine kaputte App übrig. Morgen versuche ich es mit klarem Kopf noch einmal.
Trotzdem ist das Repository selbst großartig, und auf einem M1 läuft es mit f16 in unter 10 Minuten.
Die Beispiele für verschiedene Quantisierungsstufen sind ziemlich beeindruckend.
Der Wechsel von f16 zu q8_0 wirkt eher wie eine Änderung der Richtung als wie ein Qualitätsverlust. Das Ergebnis von q5_1 scheint kaum von q8_0 zu unterscheiden zu sein.
Bei hochpräzisen Modellen verliert man zwar Determinismus, aber praktisch könnte es durchaus brauchbar sein.
Gibt es Benchmarks?
https://github.com/leejet/stable-diffusion.cpp/issues/1
cmake .. -DGGML_CUBLAS=ON -DCMAKE_CUDA_COMPILER=/opt/cuda/bin/nvcckompiliert und eine NVIDIA GeForce RTX 2060 SUPER verwendet.Das Modell habe ich nach FP16 konvertiert.
Mit dieser Option liegt die Zeit pro Iteration zwischen 8,5 und 9 Sekunden, und die Gesamtzeit zum Erzeugen eines Bildes beträgt etwa 200 Sekunden.