KI-Modelle und Plattformen
Microsofts Inferenzframework bringt 1-Bit-Großsprachmodelle auf lokale Geräte
Am 17. Oktober 2024 kündigte Microsoft (MSFT ) BitNet.cpp an, ein Inferenzframework, das für die Ausführung von 1-Bit-quantifizierten Großsprachmodellen (LLMs) konzipiert ist. BitNet.cpp ist ein bedeutender Fortschritt im Bereich der künstlichen Intelligenz, da es die effiziente Ausführung von 1-Bit-LLMs auf Standard-CPUs ermöglicht, ohne dass teure GPUs erforderlich sind. Diese Entwicklung demokratisiert den Zugang zu LLMs und macht sie auf einer breiten Palette von Geräten verfügbar, wodurch neue Möglichkeiten für On-Device-KI-Anwendungen entstehen.
Verständnis von 1-Bit-Großsprachmodellen
Großsprachmodelle (LLMs) erforderten traditionell aufgrund ihrer Verwendung von Hochpräzisions-Gleitkommazahlen (in der Regel FP16 oder BF16) für Modellgewichte erhebliche Rechenressourcen. Diese Notwendigkeit hat die Bereitstellung von LLMs teuer und energieintensiv gemacht.
Im Kern verwenden 1-Bit-LLMs extreme Quantisierungstechniken, um Modellgewichte mit nur drei möglichen Werten darzustellen: -1, 0 und 1, daher der Begriff “1,58-Bit” (da er slightly mehr als ein Bit benötigt, um drei Zustände zu kodieren).
Ternäres Gewichtssystem
Das Konzept
Die 1-Bit-Quantisierung in BitNet.cpp ist ein ternäres Gewichtssystem. BitNet arbeitet mit nur drei möglichen Werten für jeden Parameter:
- -1 (negativ)
- 0 (neutral)
- 1 (positiv)
Dies führt zu einem Speicherbedarf von etwa 1,58 Bits pro Parameter, daher der Name BitNet b1.58. Diese drastische Reduzierung der Parameter-Bitbreite führt zu einer beeindruckenden Reduzierung des Speicherbedarfs und der Rechenkomplexität, da die meisten Gleitkommamultiplikationen durch einfache Additionen und Subtraktionen ersetzt werden.
Mathematische Grundlage
1-Bit-Quantisierung beinhaltet die Transformation von Gewichten und Aktivierungen in ihre ternäre Darstellung durch die folgenden Schritte:
1. Gewichtsbinarisierung
Die Binarisierung der Gewichte beinhaltet die Zentrierung um den Mittelwert (α), was zu einer ternären Darstellung führt. Die Transformation wird mathematisch wie folgt ausgedrückt:
Wf=Sign(W−α)
Wo:
- W ist die ursprüngliche Gewichtsmatrix.
- α ist der Mittelwert der Gewichte.
- Sign(x) gibt +1 zurück, wenn x > 0 und -1 sonst.
2. Aktivierungsquantisierung
Die Quantisierung der Aktivierungen stellt sicher, dass die Eingaben auf eine bestimmte Bitbreite beschränkt sind:
x^e=Quant(x)=Clip(γx×Qb,−Q+ϵ,Q−ϵ)
Wo:
- Qb = 2(b−1)2^{(b-1)} ist der maximale Quantisierungsgrad für die b-Bit-Breite.
- γ ist der maximale absolute Wert von x (bezeichnet als ∣∣x∣∣∞).
- ε ist eine kleine Zahl, um Überläufe während der Berechnungen zu vermeiden.
3. BitLinear-Operation
Die BitLinear-Schicht ersetzt traditionelle Matrixmultiplikationen durch eine vereinfachte Operation:
y=Wf×x^e×(Qbβγ)
Wo:
- β ist ein Skalierungsfaktor, der verwendet wird, um Approximationsfehler zu minimieren.
- γ skaliert die Aktivierungen.
- Q_b ist der Quantisierungsfaktor.
Diese Transformation ermöglicht effiziente Berechnungen, während die Modellleistung erhalten bleibt.
Leistungsimplikationen
Speichereffizienz
Das ternäre Gewichtssystem reduziert den Speicherbedarf erheblich:
- Traditionelle LLMs: 16 Bits pro Gewicht
- BitNet.cpp: 1,58 Bits pro Gewicht
Diese Reduzierung entspricht einer Speicherersparnis von etwa 90% im Vergleich zu traditionellen 16-Bit-Modellen, wodurch größere Modelle innerhalb der gleichen Hardware-Beschränkungen untergebracht werden können.

Inferenzgeschwindigkeit, Energieeffizienz (Apple [securities_stock_price_tag symbol="AAPL" exchange="NASDAQ"] M2)
1. Inferenzgeschwindigkeit: Schneller auf beiden CPUs
Die Inferenzgeschwindigkeit wird als Anzahl der pro Sekunde verarbeiteten Token dargestellt. Hier ist eine Zusammenfassung der Beobachtungen:
- Auf Apple M2 Ultra: BitNet.cpp erreicht bis zu 5,07-fache Geschwindigkeitssteigerung für größere Modelle (30B) im Vergleich zu Llama.cpp, mit einer Spitzenleistung von 593,43 Token pro Sekunde für ein 125M-Modell, was eine 1,37-fache Steigerung darstellt. Für größere Modelle wie 3,8B und 7B hält BitNet.cpp eine Geschwindigkeit von über 84,77 Token pro Sekunde, was seine Effizienz über verschiedene Größen hinweg zeigt.
- Auf Intel (INTC ) i7-13700H: BitNet.cpp erreicht noch dramatischere Geschwindigkeitssteigerungen. Bei einer Modellgröße von 7B liefert BitNet.cpp eine atemberaubende 5,68-fache Steigerung im Vergleich zu Llama.cpp. Für kleinere Modelle wie 125M verarbeitet es 389,08 Token pro Sekunde, was 2,37-mal schneller ist als Llama.cpp.
2. Energieeffizienz: Ein Game-Changer für Edge-Geräte
Die bereitgestellten Grafiken enthalten auch Energiekostenvergleiche, die eine signifikante Reduzierung des Energieverbrauchs pro verarbeitetem Token zeigen:
- Auf Apple M2 Ultra: Die Energieeinsparungen von BitNet.cpp sind erheblich. Für das 700M-Modell verbraucht es 55,4% weniger Energie pro Token im Vergleich zu Llama.cpp, von 0,314 auf 0,140. Diese Tendenz setzt sich für größere Modelle fort, wobei das 70B-Modell eine 70,0-prozentige Reduzierung des Energieverbrauchs zeigt.
- Auf Intel i7-13700H: BitNet.cpp liefert 71,9-prozentige Energieeinsparungen für das 700M-Modell, wobei der Verbrauch von 1,367 auf 0,384 sinkt. Obwohl Energie-Daten für das 70B-Modell in Llama.cpp nicht verfügbar sind, bleibt BitNet.cpp effizient, mit einem Energieverbrauch von 17,33 für das 70B-Modell.
3. Überschreitung der menschlichen Lesegeschwindigkeits-Benchmark
Eine der interessantesten Erkenntnisse aus diesen Grafiken ist der Verweis auf die menschliche Lesegeschwindigkeit, die bei 5-7 Token pro Sekunde markiert ist. Diese rote Linie zeigt, dass beide Implementierungen, insbesondere BitNet.cpp, die menschliche Lesegeschwindigkeit für die größten Modelle mühelos überschreiten:
- Auf Apple M2 Ultra überschreitet BitNet.cpp die menschliche Lesegeschwindigkeit für alle Modellgrößen, wobei die niedrigste Geschwindigkeit 8,67 Token pro Sekunde für ein 70B-Modell beträgt.
- Auf Intel i7-13700H erreicht das 100B-Modell immer noch 1,70 Token pro Sekunde, was fast den unteren Bereich der menschlichen Lesegeschwindigkeit erreicht, während alle kleineren Modelle diese Benchmark überschreiten.
Trainingsüberlegungen
Straight-Through-Estimator (STE)
Da die 1-Bit-Quantisierung nicht differenzierbare Funktionen einführt, beinhaltet das Training eine spezielle Technik, die als Straight-Through-Estimator (STE) bekannt ist. Bei diesem Ansatz fließen die Gradienten unverändert durch nicht differenzierbare Punkte. Hier ist eine vereinfachte Implementierung in Python:
class StraightThroughEstimator(Function): @staticmethod def forward(ctx, input): return input.sign() <p>@staticmethod def backward(ctx, grad_output): return grad_output
Mixed-Precision-Training
Um die Stabilität während des Trainings zu erhalten, wird Mixed Precision eingesetzt:
- Gewichte und Aktivierungen: Quantisiert auf 1-Bit-Präzision.
- Gradienten und Optimiererzustände: In höherer Präzision gespeichert.
- Latente Gewichte: In hoher Präzision beibehalten, um genaue Updates während des Trainings zu ermöglichen.
Große Lernrate-Strategie
Eine besondere Herausforderung bei 1-Bit-Modellen ist, dass kleine Updates die binarisierten Gewichte möglicherweise nicht beeinflussen. Um dies zu überwinden, wird die Lernrate erhöht, um eine schnellere Konvergenz und bessere Optimierung im Vergleich zu herkömmlichen Ansätzen zu gewährleisten.
Gruppenquantisierung und -normalisierung
BitNet.cpp führt Gruppenquantisierung und -normalisierung ein, um die Modellparallelisierung zu verbessern. Anstatt Parameter für die gesamte Gewichtsmatrix zu berechnen, teilt BitNet die Gewichte und Aktivierungen in mehrere Gruppen (G) auf.
Dieses Gruppieren ermöglicht eine effiziente parallele Verarbeitung ohne zusätzliche Kommunikation zwischen den Gruppen, wodurch das Training und die Inferenz großer Modelle ermöglicht werden.
Implementierungsnotizen und Optimierungen
CPU-Optimierung
BitNet.cpp nutzt mehrere niedrigstufige Optimierungen, um die Spitzenleistung auf CPUs zu erzielen:
- Vektorisierte Operationen: Nutzt SIMD-Anweisungen, um Bit-Manipulationen effizient durchzuführen.
- Cache-freundlicher Speicherzugriff: Strukturiert Daten, um Cache-Verfehlungen zu minimieren.
- Parallele Verarbeitung: Verteilt die Arbeitslast effektiv auf mehrere CPU-Kerne.
Hier ist ein Beispiel für eine Schlüsseleigenschaft, die die Quantisierung und Inferenz in BitNet implementiert:













