Model Quantization
Bei der Modellquantisierung werden Gewichte und Aktivierungen mit geringerer Präzision, etwa INT8, gespeichert, um Modelle zu verkleinern und die Inferenz zu beschleunigen. Erfahre, wie sie funktioniert und wie sich PTQ und QAT unterscheiden.
Bei der Modellquantisierung werden die Gewichte eines neuronalen Netzes und oft auch seine Aktivierungen von 32-Bit-Gleitkommazahlen (FP32) in Formate mit geringerer Präzision umgewandelt, etwa 16-Bit-Gleitkommazahlen (FP16), 8-Bit-Ganzzahlen (INT8) oder 4-Bit-Ganzzahlen. Jeder Wert benötigt dann weniger Bits zum Speichern und Übertragen. Ganzzahlarithmetik läuft auf den meisten Prozessoren schneller und verbraucht weniger Energie. Ein INT8-Modell ist ein Viertel so groß wie das ursprüngliche FP32-Modell. Dadurch können Modelle zur Objekterkennung auf Smartphones, Kameras und anderen Edge-KI-Geräten in Echtzeit ausgeführt werden. Außerdem passen große Sprachmodelle (LLMs) so auf eine einzelne GPU.
So funktioniert Quantisierung#
Bei der Quantisierung wird ein Bereich reeller Zahlen einer kleinen Menge ganzzahliger Stufen zugeordnet. Beim gängigen affinen Verfahren wird jede Gleitkommazahl x als Ganzzahl q = round(x / scale) + zero_point gespeichert und als x ≈ (q - zero_point) × scale wiederhergestellt. Die Skalierung legt den Abstand zwischen den Stufen fest, und der Nullpunkt sorgt dafür, dass der Gleitkommawert 0 einer exakten Ganzzahl zugeordnet wird. INT8 bietet 256 Stufen, daher muss der Wertebereich sorgfältig gewählt werden: Ein zu weiter Bereich verschwendet Stufen auf Werte, die nie auftreten, während ein zu enger Bereich Ausreißer abschneidet. Die Gewichte sind im Voraus bekannt, daher lassen sich ihre Bereiche direkt aus dem trainierten Modell ableiten. Sie werden häufig separat für jeden Ausgabekanal berechnet. Aktivierungen hängen von der Eingabe ab. Ihre Bereiche werden daher während der Kalibrierung gemessen, indem eine kleine Auswahl repräsentativer Bilder oder Textbeispiele durch das Modell geleitet wird.
import numpy as np
rng = np.random.default_rng(0)
weights = rng.normal(0, 0.05, size=1000).astype(np.float32)
# Affine INT8 quantization maps the observed float range onto 256 integer levels
scale = (weights.max() - weights.min()) / 255
zero_point = np.round(-128 - weights.min() / scale)
q = np.clip(np.round(weights / scale + zero_point), -128, 127).astype(np.int8)
# Dequantize to measure the rounding error the model has to tolerate
restored = (q.astype(np.float32) - zero_point) * scale
print(f"Size: {weights.nbytes} -> {q.nbytes} bytes")
print(f"Max error: {np.abs(weights - restored).max():.5f} (half a step: {scale / 2:.5f})")Es gibt Size: 4000 -> 1000 bytes und einen maximalen Fehler von 0,00068 aus, was der Hälfte eines Quantisierungsschritts entspricht. Die Gewichte werden auf ein Viertel ihrer Größe reduziert, und kein Wert weicht um mehr als einen halben Schritt vom Original ab.
Quantisierung nach dem Training im Vergleich zu quantisierungsbewusstem Training#
- Quantisierung nach dem Training (PTQ): Wandelt ein bereits trainiertes Modell um und verwendet einen kleinen Kalibrierungsdatensatz, um die Wertebereiche der Aktivierungen festzulegen. Der Vorgang dauert Minuten und benötigt außer diesen Beispielen keine Trainingsdaten. Dynamische Quantisierung ist eine PTQ-Variante, bei der die Wertebereiche der Aktivierungen während der Inferenz berechnet werden. Bei der reinen Gewichtsquantisierung bleiben die Aktivierungen Gleitkommazahlen.
- Quantisierungsbewusstes Training (QAT): Simuliert die Quantisierung während des Trainings oder Fine-Tunings, indem Werte im Vorwärtsdurchlauf gerundet werden. So lernen die Gewichte, die Rundung zu verkraften. Dadurch wird der größte Teil der Genauigkeit wiederhergestellt, die PTQ einbüßt, allerdings auf Kosten zusätzlichen Trainings.
Teams beginnen üblicherweise mit PTQ und wechseln nur dann, wenn der Rückgang der Genauigkeit zu groß ist:
LLMs verwenden auch eigene Verfahren. Verfahren zur reinen 4-Bit-Gewichtsquantisierung wie GPTQ und AWQ komprimieren Milliarden von Parametern, während die Aktivierungen bei 16 Bit bleiben. Das Format GGUF speichert quantisierte Modelle für die lokale Inferenz, und neuere GPUs rechnen nativ mit Gleitkommaformaten geringer Präzision wie FP8.
Quantisierung im Vergleich zu verwandten Verfahren#
- Gemischte Präzision: Eine Trainingstechnik, bei der die meisten Operationen mit FP16 oder BF16 ausgeführt werden, während eine Masterkopie der Gewichte in FP32 erhalten bleibt, um das Training zu beschleunigen. Quantisierung zielt auf die Inferenz ab und geht weiter, indem sie oft Ganzzahlen verwendet.
- Modellbeschneidung: Entfernt Gewichte oder ganze Kanäle, um die Zahl der Operationen zu verringern. Häufig wird sie mit Quantisierung kombiniert, durch die jede verbleibende Operation weniger kostet.
- Wissensdestillation: Trainiert ein kleines Schülermodell darauf, ein großes Lehrermodell nachzuahmen. Häufig wird das Schülermodell anschließend für die Bereitstellung quantisiert.
Quantisierung in der Praxis#
Die Beschleunigung hängt von der Hardwareunterstützung ab: Ein INT8-Modell läuft nur auf Prozessoren mit INT8-Kernels schneller, etwa auf NVIDIA-GPUs mit TensorRT, Intel-CPUs mit OpenVINO und den neuronalen Verarbeitungseinheiten (NPUs) in Smartphones. Ultralytics YOLO26 wendet PTQ beim Export mit quantize=8 an und kalibriert dabei anhand von Bildern aus dem Datensatz data. model.train(quantize=8) feinabgestimmt einen Checkpoint stattdessen mit QAT. Dieses Beispiel exportiert ein INT8-Modell für LiteRT, Googles Laufzeitumgebung für Android und eingebettete Geräte:
from ultralytics import YOLO
# Ein vortrainiertes YOLO26-Nano-Modell laden
model = YOLO("yolo26n.pt")
# INT8-Quantisierung nach dem Training; Bilder aus coco8.yaml kalibrieren die Wertebereiche der Aktivierungen
model.export(format="litert", quantize=8, data="coco8.yaml")Gemessen auf COCO mit TensorRT senkt INT8-PTQ den mAP50-95 von YOLO26n nur von 0,403 auf 0,393. Bei YOLO26s fällt er stärker, von 0,479 auf 0,441. QAT bringt YOLO26s wieder auf 0,471.










