Quantisierung nach dem Training

Die Quantisierung nach dem Training ist eine Konvertierungstechnik, mit der die Modellgröße reduziert und gleichzeitig die Latenz von CPU und Hardwarebeschleuniger verbessert wird. Die Modellgenauigkeit wird dabei kaum beeinträchtigt. Sie können ein bereits trainiertes Float-TensorFlow-Modell quantisieren, wenn Sie es mit dem TensorFlow Lite Converter in das TensorFlow Lite-Format konvertieren.

Optimierungsmethoden

Nach dem Training können Sie aus mehreren Optionen für die Quantisierung auswählen. Hier ist eine Übersichtstabelle der Auswahlmöglichkeiten und ihrer Vorteile:

Verfahren Vorteile Hardware
Quantisierung des dynamischen Bereichs 4-mal kleiner, 2- bis 3-mal schneller CPU
Quantisierung nach vollständiger Ganzzahl 4-mal kleiner, mehr als 3-mal schneller CPU, Edge TPU, Mikrocontroller
Float16-Quantisierung 2-mal kleiner, GPU-Beschleunigung CPU, GPU

Mit dem folgenden Entscheidungsbaum können Sie ermitteln, welche Quantisierungsmethode nach dem Training für Ihren Anwendungsfall am besten geeignet ist:

Optimierungsoptionen nach dem Training

Keine Quantisierung

Es wird empfohlen, als Ausgangspunkt ein TFLite-Modell ohne Quantisierung zu konvertieren. Dadurch wird ein Float-TFLite-Modell generiert.

import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
tflite_quant_model = converter.convert()

Wir empfehlen, dies als einen ersten Schritt zu tun, um zu prüfen, ob die Operatoren des ursprünglichen TF-Modells mit TFLite kompatibel sind und auch als Ausgangsbasis zum Beheben von Quantisierungsfehlern verwendet werden können, die durch nachfolgende Quantisierungsmethoden nach dem Training verursacht werden. Wenn beispielsweise ein quantisiertes TFLite-Modell unerwartete Ergebnisse liefert, während das Float-TFLite-Modell korrekt ist, können wir das Problem auf Fehler eingrenzen, die durch die quantisierte Version der TFLite-Operatoren verursacht werden.

Quantisierung des dynamischen Bereichs

Die dynamische Bereichsquantisierung ermöglicht eine reduzierte Arbeitsspeichernutzung und eine schnellere Berechnung, ohne dass Sie ein repräsentatives Dataset für die Kalibrierung bereitstellen müssen. Bei dieser Art der Quantisierung werden zum Zeitpunkt der Konvertierung nur die Gewichtungen von Gleitkomma zu Ganzzahl statisch quantisiert, wodurch eine Genauigkeit von 8 Bit ermöglicht wird:

import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
tflite_quant_model = converter.convert()

Um die Latenz während der Inferenz weiter zu reduzieren, quantisieren Operatoren vom Typ „Dynamic-Range“ die Aktivierungen dynamisch anhand ihres Bereichs auf 8 Bit und führen Berechnungen mit 8-Bit-Gewichtungen und -Aktivierungen durch. Diese Optimierung bietet Latenzen, die nahezu vollständig festgelegten Inferenzen entsprechen. Die Ausgaben werden jedoch weiterhin mit Gleitkommazahlen gespeichert, sodass die höhere Geschwindigkeit von Operationen im dynamischen Bereich geringer ist als bei einer vollständigen Festpunktberechnung.

Quantisierung nach vollständiger Ganzzahl

Sie können die Latenz weiter verbessern, die maximale Arbeitsspeichernutzung reduzieren und die Kompatibilität mit Hardwaregeräten oder Beschleunigern, die nur Ganzzahlen enthalten, erzielen, wenn Sie dafür sorgen, dass alle Modellberechnungen durch Ganzzahlen quantisiert sind.

Für die Quantisierung der vollständigen Ganzzahl müssen Sie den Bereich kalibrieren oder schätzen, d.h. (min, max) aller Gleitkomma-Tensoren im Modell an. Im Gegensatz zu konstanten Tensoren wie Gewichtungen und Verzerrungen können variable Tensoren wie Modelleingaben, Aktivierungen (Ausgaben von Zwischenschichten) und Modellausgabe nur kalibriert werden, wenn einige Inferenzzyklen ausgeführt werden. Daher benötigt der Konverter ein repräsentatives Dataset, um sie zu kalibrieren. Bei diesem Dataset kann es sich um eine kleine Teilmenge (ca. 100–500 Beispiele) der Trainings- oder Validierungsdaten handeln. Sehen Sie sich dazu die Funktion representative_dataset() unten an.

Ab TensorFlow 2.7 können Sie das repräsentative Dataset über eine Signatur wie im folgenden Beispiel angeben:

def representative_dataset():
  for data in dataset:
    yield {
      "image": data.image,
      "bias": data.bias,
    }

Wenn das gegebene TensorFlow-Modell mehr als eine Signatur enthält, können Sie die verschiedenen Datasets durch Angabe der Signaturschlüssel angeben:

def representative_dataset():
  # Feed data set for the "encode" signature.
  for data in encode_signature_dataset:
    yield (
      "encode", {
        "image": data.image,
        "bias": data.bias,
      }
    )

  # Feed data set for the "decode" signature.
  for data in decode_signature_dataset:
    yield (
      "decode", {
        "image": data.image,
        "hint": data.hint,
      },
    )

Sie können das repräsentative Dataset generieren, indem Sie eine Eingabetensorenliste bereitstellen:

def representative_dataset():
  for data in tf.data.Dataset.from_tensor_slices((images)).batch(1).take(100):
    yield [tf.dtypes.cast(data, tf.float32)]

Seit der TensorFlow 2.7-Version empfehlen wir, den signaturbasierten Ansatz gegenüber dem auf der Liste der Eingabetensoren basierenden Ansatz zu verwenden, da die Reihenfolge der Eingabetensoren einfach umgedreht werden kann.

Zu Testzwecken können Sie ein Dummy-Dataset wie folgt verwenden:

def representative_dataset():
    for _ in range(100):
      data = np.random.rand(1, 244, 244, 3)
      yield [data.astype(np.float32)]
 

Ganzzahl mit Gleitkommazahl-Fallback (mit Standardeingabe/-ausgabe für Gleitkommazahl)

Gehen Sie so vor, um ein Modell vollständig als Ganzzahl zu quantisieren, aber Gleitkommazahlen-Operatoren zu verwenden, wenn sie keine Ganzzahlimplementierung haben (damit die Konvertierung reibungslos abläuft):

import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.representative_dataset = representative_dataset
tflite_quant_model = converter.convert()

Nur Ganzzahl

Das Erstellen von Modellen mit ausschließlich Ganzzahlen ist ein häufiger Anwendungsfall für TensorFlow Lite für Mikrocontroller und Coral Edge-TPUs.

Um die Kompatibilität mit Geräten, die ausschließlich Ganzzahlen enthalten (z. B. 8-Bit-Mikrocontroller) und Beschleuniger (z. B. Coral Edge TPU), zu gewährleisten, können Sie die vollständige Ganzzahlquantisierung für alle Vorgänge einschließlich der Ein- und Ausgabe erzwingen. Gehen Sie dazu so vor:

import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.representative_dataset = representative_dataset
converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]
converter.inference_input_type = tf.int8  # or tf.uint8
converter.inference_output_type = tf.int8  # or tf.uint8
tflite_quant_model = converter.convert()

Float16-Quantisierung

Sie können die Größe eines Gleitkommamodells reduzieren, indem Sie die Gewichtungen mit float16 quantisieren, dem IEEE-Standard für 16-Bit-Gleitkommazahlen. Führen Sie die folgenden Schritte aus, um die FLOAT16-Quantisierung von Gewichtungen zu aktivieren:

import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.target_spec.supported_types = [tf.float16]
tflite_quant_model = converter.convert()

Die FLOAT16-Quantisierung bietet folgende Vorteile:

  • Damit wird die Modellgröße um bis zu der Hälfte reduziert, da alle Gewichtungen zur Hälfte ihrer ursprünglichen Größe werden.
  • Dies führt zu minimalen Genauigkeitsverlusten.
  • Sie unterstützt einige Bevollmächtigte (z.B. den GPU-Delegaten), die direkt mit float16-Daten arbeiten können, was eine schnellere Ausführung als float32-Berechnungen ermöglicht.

Die float16-Quantisierung hat folgende Nachteile:

  • Sie reduziert die Latenz nicht so sehr wie eine Quantisierung bei der Fixpunktberechnung.
  • Standardmäßig „dequantisiert“ ein mit float16 quantisiertes Modell die Gewichtungswerte auf „float32“, wenn es auf der CPU ausgeführt wird. (Beachten Sie, dass der GPU-Delegate diese Dequantisierung nicht durchführt, da er mit float16-Daten arbeiten kann.)

Nur Ganzzahl: 16-Bit-Aktivierungen mit 8-Bit-Gewichtungen (experimentell)

Dies ist ein experimentelles Quantisierungsschema. Es ähnelt dem Schema "Nur Ganzzahl", aber Aktivierungen werden anhand ihres Bereichs auf 16 Bit quantisiert, Gewichtungen werden mit einer 8-Bit-Ganzzahl quantisiert und die Verzerrung wird in eine 64-Bit-Ganzzahl quantisiert. Dies wird als 16x8-Quantisierung bezeichnet.

Der Hauptvorteil dieser Quantisierung besteht darin, dass sie die Genauigkeit erheblich verbessern, aber die Modellgröße nur geringfügig erhöhen kann.

import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.representative_dataset = representative_dataset
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.target_spec.supported_ops = [tf.lite.OpsSet.EXPERIMENTAL_TFLITE_BUILTINS_ACTIVATIONS_INT16_WEIGHTS_INT8]
tflite_quant_model = converter.convert()

Wenn die 16:8-Quantisierung für einige Operatoren im Modell nicht unterstützt wird, kann das Modell zwar quantisiert werden, nicht unterstützte Operatoren bleiben jedoch als Gleitkommazahl erhalten. Fügen Sie „target_spec“ die folgende Option hinzu, um dies zu ermöglichen.

import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.representative_dataset = representative_dataset
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.target_spec.supported_ops = [tf.lite.OpsSet.EXPERIMENTAL_TFLITE_BUILTINS_ACTIVATIONS_INT16_WEIGHTS_INT8,
tf.lite.OpsSet.TFLITE_BUILTINS]
tflite_quant_model = converter.convert()

Beispiele für Anwendungsfälle, in denen durch dieses Quantisierungsschema verbesserte Genauigkeiten erzielt werden:

  • super-resolution,
  • Audiosignalverarbeitung wie Geräuschunterdrückung und Beamforming,
  • Rauschen entfernen,
  • HDR-Rekonstruktion aus einem einzelnen Bild.

Diese Quantisierung hat folgenden Nachteil:

  • Derzeit ist die Inferenz aufgrund der fehlenden optimierten Kernelimplementierung deutlich langsamer als eine 8-Bit-Ganzzahl.
  • Derzeit ist es nicht mit den vorhandenen hardwarebeschleunigten TFLite-Delegierungen kompatibel.

Eine Anleitung für diesen Quantisierungsmodus finden Sie hier.

Modellgenauigkeit

Da die Gewichtungen nach dem Training quantisiert werden, kann es zu einem Verlust an Genauigkeit kommen, insbesondere bei kleineren Netzwerken. Für bestimmte Netzwerke auf TensorFlow Hub werden vortrainierte, vollständig quantisierte Modelle bereitgestellt. Es ist wichtig, die Genauigkeit des quantisierten Modells zu überprüfen, um sicherzustellen, dass jede Verschlechterung der Genauigkeit innerhalb akzeptabler Grenzen liegt. Es gibt Tools zur Bewertung der Genauigkeit des TensorFlow Lite-Modells.

Wenn der Rückgang der Genauigkeit zu hoch ist, können Sie alternativ ein quantisierungsbewusstes Training verwenden. Dies erfordert jedoch Änderungen während des Modelltrainings, um fiktive Quantisierungsknoten hinzuzufügen. Für die Quantisierungsverfahren nach dem Training auf dieser Seite wird hingegen ein vorhandenes vortrainiertes Modell verwendet.

Darstellung für quantisierte Tensoren

Bei der 8-Bit-Quantisierung werden Gleitkommawerte mithilfe der folgenden Formel annäherungsweise angegeben.

\[real\_value = (int8\_value - zero\_point) \times scale\]

Die Darstellung besteht aus zwei Hauptteilen:

  • Gewichtungen pro Achse (auch pro Kanal genannt) oder Pro Tensor, die durch die Int8-Zweier-Komplementwerte im Bereich [-127, 127] mit einem Nullpunkt gleich 0 dargestellt werden.

  • Aktivierungen/Eingaben pro Tensor, dargestellt durch die Int8-Zweierkomplementwerte im Bereich [-128, 127] mit einem Nullpunkt im Bereich [-128, 127].

Eine detaillierte Ansicht unseres Quantisierungsschemas finden Sie in unserer Quantisierungsspezifikation. Hardwareanbieter, die sich in die Delegatschnittstelle von TensorFlow Lite einbinden möchten, sollten das dort beschriebene Quantisierungsschema implementieren.