Eine Frage haben? Verbinden Sie sich mit der Community im TensorFlow Forum Visit Forum

Ganzzahlquantisierung nach dem Training

Ansicht auf TensorFlow.org In Google Colab ausführen Quelle auf GitHub anzeigen Notizbuch herunterladen

Überblick

Die Ganzzahlquantisierung ist eine Optimierungsstrategie, die 32-Bit-Gleitkommazahlen (wie Gewichte und Aktivierungsausgaben) in die nächsten 8-Bit-Festkommazahlen konvertiert. Dies führt zu einem kleineren Modell und einer erhöhten Inferenzgeschwindigkeit, was für Geräte mit geringem Stromverbrauch wie Mikrocontroller von Nutzen ist . Dieses Datenformat wird auch von Nur-Ganzzahl-Beschleunigern wie der Edge-TPU benötigt .

In diesem Tutorial trainieren Sie ein MNIST-Modell von Grund auf neu, konvertieren es in eine Tensorflow Lite-Datei und quantisieren es mithilfe der Quantisierung nach dem Training . Schließlich überprüfen Sie die Genauigkeit des konvertierten Modells und vergleichen es mit dem ursprünglichen Float-Modell.

Sie haben tatsächlich mehrere Möglichkeiten, wie viel Sie ein Modell quantisieren möchten. In diesem Lernprogramm führen Sie eine "vollständige Ganzzahlquantisierung" durch, bei der alle Gewichte und Aktivierungsausgaben in 8-Bit-Ganzzahldaten konvertiert werden. Bei anderen Strategien verbleiben möglicherweise einige Datenmengen im Gleitkommawert.

Weitere Informationen zu den verschiedenen Quantisierungsstrategien finden Sie unter TensorFlow Lite-Modelloptimierung .

Einrichten

Um sowohl den Eingabe- als auch den Ausgabe-Tensor zu quantisieren, müssen APIs verwendet werden, die in TensorFlow r2.3 hinzugefügt wurden:

import logging
logging.getLogger("tensorflow").setLevel(logging.DEBUG)

import tensorflow as tf
import numpy as np
assert float(tf.__version__[:3]) >= 2.3

Generieren Sie ein TensorFlow-Modell

Wir werden ein einfaches Modell erstellen , um Zahlen aus dem MNIST-Datensatz zu klassifizieren.

Dieses Training dauert nicht lange, da Sie das Modell nur für 5 Epochen trainieren, was mit einer Genauigkeit von ca. 98% trainiert.

# Load MNIST dataset
mnist = tf.keras.datasets.mnist
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()

# Normalize the input image so that each pixel value is between 0 to 1.
train_images = train_images.astype(np.float32) / 255.0
test_images = test_images.astype(np.float32) / 255.0

# Define the model architecture
model = tf.keras.Sequential([
  tf.keras.layers.InputLayer(input_shape=(28, 28)),
  tf.keras.layers.Reshape(target_shape=(28, 28, 1)),
  tf.keras.layers.Conv2D(filters=12, kernel_size=(3, 3), activation='relu'),
  tf.keras.layers.MaxPooling2D(pool_size=(2, 2)),
  tf.keras.layers.Flatten(),
  tf.keras.layers.Dense(10)
])

# Train the digit classification model
model.compile(optimizer='adam',
              loss=tf.keras.losses.SparseCategoricalCrossentropy(
                  from_logits=True),
              metrics=['accuracy'])
model.fit(
  train_images,
  train_labels,
  epochs=5,
  validation_data=(test_images, test_labels)
)
Epoch 1/5
1875/1875 [==============================] - 6s 2ms/step - loss: 0.2721 - accuracy: 0.9240 - val_loss: 0.1264 - val_accuracy: 0.9648
Epoch 2/5
1875/1875 [==============================] - 4s 2ms/step - loss: 0.1030 - accuracy: 0.9708 - val_loss: 0.0800 - val_accuracy: 0.9764
Epoch 3/5
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0763 - accuracy: 0.9780 - val_loss: 0.0706 - val_accuracy: 0.9787
Epoch 4/5
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0652 - accuracy: 0.9804 - val_loss: 0.0673 - val_accuracy: 0.9786
Epoch 5/5
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0559 - accuracy: 0.9834 - val_loss: 0.0654 - val_accuracy: 0.9785
<tensorflow.python.keras.callbacks.History at 0x7f41a4081e10>

Konvertieren Sie in ein TensorFlow Lite-Modell

Jetzt können Sie das trainierte Modell mithilfe der TFLiteConverter API in das TensorFlow Lite-Format TFLiteConverter und unterschiedliche Quantisierungsgrade anwenden.

Beachten Sie, dass einige Quantisierungsversionen einige Daten im Float-Format belassen. Die folgenden Abschnitte zeigen also jede Option mit zunehmendem Quantisierungsaufwand, bis wir ein Modell erhalten, das vollständig aus int8- oder uint8-Daten besteht. (Beachten Sie, dass wir in jedem Abschnitt Code duplizieren, damit Sie alle Quantisierungsschritte für jede Option sehen können.)

Hier ist zunächst ein konvertiertes Modell ohne Quantisierung:

converter = tf.lite.TFLiteConverter.from_keras_model(model)

tflite_model = converter.convert()
INFO:tensorflow:Assets written to: /tmp/tmppx_swx9x/assets

Es ist jetzt ein TensorFlow Lite-Modell, verwendet jedoch weiterhin 32-Bit-Float-Werte für alle Parameterdaten.

Konvertieren mit Dynamikbereichsquantisierung

Nun ermöglichen wir die Standard - optimizations Flag alle festen Parameter (wie Gewichte) quantisiert:

converter = tf.lite.TFLiteConverter.from_keras_model(model)
converter.optimizations = [tf.lite.Optimize.DEFAULT]

tflite_model_quant = converter.convert()
INFO:tensorflow:Assets written to: /tmp/tmprvhou1cn/assets
INFO:tensorflow:Assets written to: /tmp/tmprvhou1cn/assets

Das Modell ist jetzt mit quantisierten Gewichten etwas kleiner, aber andere variable Daten sind immer noch im Float-Format.

Konvertieren Sie mithilfe der Float-Fallback-Quantisierung

Um die variablen Daten (z. B. Modelleingabe / -ausgabe und Zwischenprodukte zwischen Ebenen) zu quantisieren, müssen Sie ein RepresentativeDataset bereitstellen. Dies ist eine Generatorfunktion, die eine Reihe von Eingabedaten bereitstellt, die groß genug sind, um typische Werte darzustellen. Damit kann der Konverter einen Dynamikbereich für alle variablen Daten schätzen. (Der Datensatz muss im Vergleich zum Trainings- oder Bewertungsdatensatz nicht eindeutig sein.) Um mehrere Eingaben zu unterstützen, ist jeder repräsentative Datenpunkt eine Liste, und Elemente in der Liste werden dem Modell gemäß ihren Indizes zugeführt.

def representative_data_gen():
  for input_value in tf.data.Dataset.from_tensor_slices(train_images).batch(1).take(100):
    # Model has only one input so each data point has one element.
    yield [input_value]

converter = tf.lite.TFLiteConverter.from_keras_model(model)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.representative_dataset = representative_data_gen

tflite_model_quant = converter.convert()
INFO:tensorflow:Assets written to: /tmp/tmp978fps3o/assets
INFO:tensorflow:Assets written to: /tmp/tmp978fps3o/assets

Jetzt werden alle Gewichte und variablen Daten quantisiert und das Modell ist im Vergleich zum ursprünglichen TensorFlow Lite-Modell erheblich kleiner.

Um die Kompatibilität mit Anwendungen zu gewährleisten, die traditionell Float-Modelleingabe- und -ausgangstensoren verwenden, belässt der TensorFlow Lite Converter die Modelleingabe- und -ausgangstensoren in float:

interpreter = tf.lite.Interpreter(model_content=tflite_model_quant)
input_type = interpreter.get_input_details()[0]['dtype']
print('input: ', input_type)
output_type = interpreter.get_output_details()[0]['dtype']
print('output: ', output_type)
input:  <class 'numpy.float32'>
output:  <class 'numpy.float32'>

Dies ist normalerweise gut für die Kompatibilität, aber nicht kompatibel mit Geräten, die nur ganzzahlige Vorgänge ausführen, wie z. B. der Edge-TPU.

Darüber hinaus kann der obige Prozess eine Operation im Float-Format belassen, wenn TensorFlow Lite keine quantisierte Implementierung für diese Operation enthält. Mit dieser Strategie kann die Konvertierung abgeschlossen werden, sodass Sie ein kleineres und effizienteres Modell haben. Auch hier ist es nicht mit nur ganzzahliger Hardware kompatibel. (Alle Operationen in diesem MNIST-Modell haben eine quantisierte Implementierung.)

Um ein End-to-End-Modell nur für Ganzzahlen zu gewährleisten, benötigen Sie einige weitere Parameter ...

Konvertieren Sie mit einer Nur-Ganzzahl-Quantisierung

Um die Eingangs- und Ausgangstensoren zu quantisieren und den Konverter einen Fehler auslösen zu lassen, wenn er auf eine Operation stößt, die er nicht quantisieren kann, konvertieren Sie das Modell erneut mit einigen zusätzlichen Parametern:

def representative_data_gen():
  for input_value in tf.data.Dataset.from_tensor_slices(train_images).batch(1).take(100):
    yield [input_value]

converter = tf.lite.TFLiteConverter.from_keras_model(model)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.representative_dataset = representative_data_gen
# Ensure that if any ops can't be quantized, the converter throws an error
converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]
# Set the input and output tensors to uint8 (APIs added in r2.3)
converter.inference_input_type = tf.uint8
converter.inference_output_type = tf.uint8

tflite_model_quant = converter.convert()
INFO:tensorflow:Assets written to: /tmp/tmp2w6dvllb/assets
INFO:tensorflow:Assets written to: /tmp/tmp2w6dvllb/assets
WARNING:absl:For model inputs containing unsupported operations which cannot be quantized, the `inference_input_type` attribute will default to the original type.

Die interne Quantisierung bleibt die gleiche wie oben, aber Sie können sehen, dass die Eingabe- und Ausgabe-Tensoren jetzt ein ganzzahliges Format haben:

interpreter = tf.lite.Interpreter(model_content=tflite_model_quant)
input_type = interpreter.get_input_details()[0]['dtype']
print('input: ', input_type)
output_type = interpreter.get_output_details()[0]['dtype']
print('output: ', output_type)
input:  <class 'numpy.uint8'>
output:  <class 'numpy.uint8'>

Jetzt haben Sie ein ganzzahliges quantisiertes Modell, das ganzzahlige Daten für die Eingangs- und Ausgangstensoren des Modells verwendet, sodass es mit nur ganzzahliger Hardware wie der Edge-TPU kompatibel ist.

Speichern Sie die Modelle als Dateien

Sie benötigen eine .tflite Datei, um Ihr Modell auf anderen Geräten bereitzustellen. Speichern wir also die konvertierten Modelle in Dateien und laden sie dann, wenn wir die folgenden Schlussfolgerungen ziehen.

import pathlib

tflite_models_dir = pathlib.Path("/tmp/mnist_tflite_models/")
tflite_models_dir.mkdir(exist_ok=True, parents=True)

# Save the unquantized/float model:
tflite_model_file = tflite_models_dir/"mnist_model.tflite"
tflite_model_file.write_bytes(tflite_model)
# Save the quantized model:
tflite_model_quant_file = tflite_models_dir/"mnist_model_quant.tflite"
tflite_model_quant_file.write_bytes(tflite_model_quant)
24328

Führen Sie die TensorFlow Lite-Modelle aus

Jetzt führen wir Schlussfolgerungen mit dem TensorFlow Lite Interpreter , um die Modellgenauigkeiten zu vergleichen.

Zuerst benötigen wir eine Funktion, die eine Inferenz mit einem bestimmten Modell und bestimmten Bildern ausführt und dann die Vorhersagen zurückgibt:

# Helper function to run inference on a TFLite model
def run_tflite_model(tflite_file, test_image_indices):
  global test_images

  # Initialize the interpreter
  interpreter = tf.lite.Interpreter(model_path=str(tflite_file))
  interpreter.allocate_tensors()

  input_details = interpreter.get_input_details()[0]
  output_details = interpreter.get_output_details()[0]

  predictions = np.zeros((len(test_image_indices),), dtype=int)
  for i, test_image_index in enumerate(test_image_indices):
    test_image = test_images[test_image_index]
    test_label = test_labels[test_image_index]

    # Check if the input type is quantized, then rescale input data to uint8
    if input_details['dtype'] == np.uint8:
      input_scale, input_zero_point = input_details["quantization"]
      test_image = test_image / input_scale + input_zero_point

    test_image = np.expand_dims(test_image, axis=0).astype(input_details["dtype"])
    interpreter.set_tensor(input_details["index"], test_image)
    interpreter.invoke()
    output = interpreter.get_tensor(output_details["index"])[0]

    predictions[i] = output.argmax()

  return predictions

Testen Sie die Modelle an einem Bild

Jetzt vergleichen wir die Leistung des Float-Modells und des quantisierten Modells:

  • tflite_model_file ist das ursprüngliche TensorFlow Lite-Modell mit Gleitkommadaten.
  • tflite_model_quant_file ist das letzte Modell, das wir mithilfe der Nur-Ganzzahl-Quantisierung konvertiert haben (es verwendet Uint8-Daten für die Eingabe und Ausgabe).

Erstellen wir eine weitere Funktion, um unsere Vorhersagen auszudrucken:

import matplotlib.pylab as plt

# Change this to test a different image
test_image_index = 1

## Helper function to test the models on one image
def test_model(tflite_file, test_image_index, model_type):
  global test_labels

  predictions = run_tflite_model(tflite_file, [test_image_index])

  plt.imshow(test_images[test_image_index])
  template = model_type + " Model \n True:{true}, Predicted:{predict}"
  _ = plt.title(template.format(true= str(test_labels[test_image_index]), predict=str(predictions[0])))
  plt.grid(False)

Testen Sie nun das Float-Modell:

test_model(tflite_model_file, test_image_index, model_type="Float")

png

Und testen Sie das quantisierte Modell:

test_model(tflite_model_quant_file, test_image_index, model_type="Quantized")

png

Bewerten Sie die Modelle auf allen Bildern

Lassen Sie uns nun beide Modelle mit allen Testbildern ausführen, die wir zu Beginn dieses Tutorials geladen haben:

# Helper function to evaluate a TFLite model on all images
def evaluate_model(tflite_file, model_type):
  global test_images
  global test_labels

  test_image_indices = range(test_images.shape[0])
  predictions = run_tflite_model(tflite_file, test_image_indices)

  accuracy = (np.sum(test_labels== predictions) * 100) / len(test_images)

  print('%s model accuracy is %.4f%% (Number of test samples=%d)' % (
      model_type, accuracy, len(test_images)))

Bewerten Sie das Float-Modell:

evaluate_model(tflite_model_file, model_type="Float")
Float model accuracy is 97.8500% (Number of test samples=10000)

Bewerten Sie das quantisierte Modell:

evaluate_model(tflite_model_quant_file, model_type="Quantized")
Quantized model accuracy is 97.8500% (Number of test samples=10000)

Sie haben jetzt eine Ganzzahl, die ein Modell mit fast keinem Unterschied in der Genauigkeit im Vergleich zum Float-Modell quantisiert.

Weitere Informationen zu anderen Quantisierungsstrategien finden Sie unter TensorFlow Lite-Modelloptimierung .