Beschneiden im Keras-Beispiel

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

Überblick

Willkommen zu einem End-to-End-Beispiel für das Beschneiden auf Gewichtsbasis .

Andere Seiten

Eine Einführung in das Beschneiden und eine Entscheidung, ob Sie es verwenden sollten (einschließlich der unterstützten Funktionen), finden Sie auf der Übersichtsseite .

Informationen zum schnellen Auffinden der für Ihren Anwendungsfall erforderlichen APIs (über das vollständige Beschneiden eines Modells mit 80% Sparsity hinaus) finden Sie im umfassenden Handbuch .

Zusammenfassung

In diesem Tutorial werden Sie:

  1. Trainieren Sie ein tf.keras Modell für MNIST von Grund auf neu.
  2. Optimieren Sie das Modell, indem Sie die Bereinigungs-API anwenden, und überprüfen Sie die Genauigkeit.
  3. Erstellen Sie 3x kleinere TF- und TFLite-Modelle aus dem Beschneiden.
  4. Erstellen Sie ein 10x kleineres TFLite-Modell aus der Kombination von Beschneiden und Quantisierung nach dem Training.
  5. Sehen Sie die Beständigkeit der Genauigkeit von TF bis TFLite.

Einrichten

 pip install -q tensorflow-model-optimization
import tempfile
import os

import tensorflow as tf
import numpy as np

from tensorflow import keras

%load_ext tensorboard

Trainieren Sie ein Modell für MNIST, ohne es zu beschneiden

# Load MNIST dataset
mnist = 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 and 1.
train_images = train_images / 255.0
test_images = test_images / 255.0

# Define the model architecture.
model = keras.Sequential([
  keras.layers.InputLayer(input_shape=(28, 28)),
  keras.layers.Reshape(target_shape=(28, 28, 1)),
  keras.layers.Conv2D(filters=12, kernel_size=(3, 3), activation='relu'),
  keras.layers.MaxPooling2D(pool_size=(2, 2)),
  keras.layers.Flatten(),
  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=4,
  validation_split=0.1,
)
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/mnist.npz
11493376/11490434 [==============================] - 0s 0us/step
Epoch 1/4
1688/1688 [==============================] - 10s 6ms/step - loss: 0.2785 - accuracy: 0.9220 - val_loss: 0.1031 - val_accuracy: 0.9740
Epoch 2/4
1688/1688 [==============================] - 9s 5ms/step - loss: 0.1063 - accuracy: 0.9691 - val_loss: 0.0782 - val_accuracy: 0.9790
Epoch 3/4
1688/1688 [==============================] - 9s 5ms/step - loss: 0.0815 - accuracy: 0.9765 - val_loss: 0.0788 - val_accuracy: 0.9775
Epoch 4/4
1688/1688 [==============================] - 9s 5ms/step - loss: 0.0689 - accuracy: 0.9797 - val_loss: 0.0633 - val_accuracy: 0.9840
<tensorflow.python.keras.callbacks.History at 0x7f146fbd8bd0>

Bewerten Sie die Genauigkeit des Basistests und speichern Sie das Modell für die spätere Verwendung.

_, baseline_model_accuracy = model.evaluate(
    test_images, test_labels, verbose=0)

print('Baseline test accuracy:', baseline_model_accuracy)

_, keras_file = tempfile.mkstemp('.h5')
tf.keras.models.save_model(model, keras_file, include_optimizer=False)
print('Saved baseline model to:', keras_file)
Baseline test accuracy: 0.9775999784469604
Saved baseline model to: /tmp/tmpjj6swf59.h5

Feinabstimmung des vorgefertigten Modells mit Schnitt

Definieren Sie das Modell

Sie wenden das Bereinigen auf das gesamte Modell an und sehen dies in der Modellzusammenfassung.

In diesem Beispiel starten Sie das Modell mit 50% Sparsity (50% Nullen in Gewichten) und enden mit 80% Sparsity.

In der umfassenden Anleitung erfahren Sie, wie Sie einige Ebenen für Verbesserungen der Modellgenauigkeit beschneiden.

import tensorflow_model_optimization as tfmot

prune_low_magnitude = tfmot.sparsity.keras.prune_low_magnitude

# Compute end step to finish pruning after 2 epochs.
batch_size = 128
epochs = 2
validation_split = 0.1 # 10% of training set will be used for validation set. 

num_images = train_images.shape[0] * (1 - validation_split)
end_step = np.ceil(num_images / batch_size).astype(np.int32) * epochs

# Define model for pruning.
pruning_params = {
      'pruning_schedule': tfmot.sparsity.keras.PolynomialDecay(initial_sparsity=0.50,
                                                               final_sparsity=0.80,
                                                               begin_step=0,
                                                               end_step=end_step)
}

model_for_pruning = prune_low_magnitude(model, **pruning_params)

# `prune_low_magnitude` requires a recompile.
model_for_pruning.compile(optimizer='adam',
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
              metrics=['accuracy'])

model_for_pruning.summary()
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/keras/engine/base_layer.py:2191: UserWarning: `layer.add_variable` is deprecated and will be removed in a future version. Please use `layer.add_weight` method instead.
  warnings.warn('`layer.add_variable` is deprecated and '
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
prune_low_magnitude_reshape  (None, 28, 28, 1)         1         
_________________________________________________________________
prune_low_magnitude_conv2d ( (None, 26, 26, 12)        230       
_________________________________________________________________
prune_low_magnitude_max_pool (None, 13, 13, 12)        1         
_________________________________________________________________
prune_low_magnitude_flatten  (None, 2028)              1         
_________________________________________________________________
prune_low_magnitude_dense (P (None, 10)                40572     
=================================================================
Total params: 40,805
Trainable params: 20,410
Non-trainable params: 20,395
_________________________________________________________________

Trainieren und bewerten Sie das Modell anhand der Basislinie

Feinabstimmung mit Schnitt für zwei Epochen.

tfmot.sparsity.keras.UpdatePruningStep ist während des Trainings erforderlich, und tfmot.sparsity.keras.PruningSummaries bietet Protokolle zum Verfolgen des Fortschritts und zum Debuggen.

logdir = tempfile.mkdtemp()

callbacks = [
  tfmot.sparsity.keras.UpdatePruningStep(),
  tfmot.sparsity.keras.PruningSummaries(log_dir=logdir),
]

model_for_pruning.fit(train_images, train_labels,
                  batch_size=batch_size, epochs=epochs, validation_split=validation_split,
                  callbacks=callbacks)
Epoch 1/2
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/ops/array_ops.py:5049: calling gather (from tensorflow.python.ops.array_ops) with validate_indices is deprecated and will be removed in a future version.
Instructions for updating:
The `validate_indices` argument has no effect. Indices are always validated on CPU and never validated on GPU.
  3/422 [..............................] - ETA: 12s - loss: 0.0628 - accuracy: 0.9896  WARNING:tensorflow:Callback method `on_train_batch_end` is slow compared to the batch time (batch time: 0.0075s vs `on_train_batch_end` time: 0.0076s). Check your callbacks.
422/422 [==============================] - 5s 9ms/step - loss: 0.0797 - accuracy: 0.9771 - val_loss: 0.0828 - val_accuracy: 0.9790
Epoch 2/2
422/422 [==============================] - 3s 8ms/step - loss: 0.0971 - accuracy: 0.9741 - val_loss: 0.0839 - val_accuracy: 0.9775
<tensorflow.python.keras.callbacks.History at 0x7f12e4502910>

In diesem Beispiel tritt nach dem Beschneiden im Vergleich zur Basislinie nur ein minimaler Verlust an Testgenauigkeit auf.

_, model_for_pruning_accuracy = model_for_pruning.evaluate(
   test_images, test_labels, verbose=0)

print('Baseline test accuracy:', baseline_model_accuracy) 
print('Pruned test accuracy:', model_for_pruning_accuracy)
Baseline test accuracy: 0.9775999784469604
Pruned test accuracy: 0.972100019454956

Die Protokolle zeigen das Fortschreiten der Sparsity pro Schicht.

%tensorboard --logdir={logdir}

Für Nicht-Colab-Benutzer können Siedie Ergebnisse einer früheren Ausführung dieses Codeblocks auf TensorBoard.dev anzeigen .

Erstellen Sie 3x kleinere Modelle aus dem Beschneiden

Sowohl tfmot.sparsity.keras.strip_pruning als auch die Anwendung eines Standardkomprimierungsalgorithmus (z. B. über gzip) sind erforderlich, um die Komprimierungsvorteile des Bereinigens zu erkennen.

  • strip_pruning ist erforderlich, da es alle tf.Variable entfernt, die das Bereinigen nur während des Trainings benötigt, was sonst die Modellgröße während der Inferenz erhöhen würde
  • Die Anwendung eines Standardkomprimierungsalgorithmus ist erforderlich, da die serialisierten Gewichtsmatrizen dieselbe Größe haben wie vor dem Beschneiden. Beim Bereinigen werden jedoch die meisten Gewichte auf Null gesetzt, was zu einer zusätzlichen Redundanz führt, die Algorithmen verwenden können, um das Modell weiter zu komprimieren.

Erstellen Sie zunächst ein komprimierbares Modell für TensorFlow.

model_for_export = tfmot.sparsity.keras.strip_pruning(model_for_pruning)

_, pruned_keras_file = tempfile.mkstemp('.h5')
tf.keras.models.save_model(model_for_export, pruned_keras_file, include_optimizer=False)
print('Saved pruned Keras model to:', pruned_keras_file)
WARNING:tensorflow:Compiled the loaded model, but the compiled metrics have yet to be built. `model.compile_metrics` will be empty until you train or evaluate the model.
Saved pruned Keras model to: /tmp/tmp22u333hk.h5

Erstellen Sie dann ein komprimierbares Modell für TFLite.

converter = tf.lite.TFLiteConverter.from_keras_model(model_for_export)
pruned_tflite_model = converter.convert()

_, pruned_tflite_file = tempfile.mkstemp('.tflite')

with open(pruned_tflite_file, 'wb') as f:
  f.write(pruned_tflite_model)

print('Saved pruned TFLite model to:', pruned_tflite_file)
WARNING:tensorflow:Compiled the loaded model, but the compiled metrics have yet to be built. `model.compile_metrics` will be empty until you train or evaluate the model.
INFO:tensorflow:Assets written to: /tmp/tmp51falze0/assets
Saved pruned TFLite model to: /tmp/tmpehx5la2i.tflite

Definieren Sie eine Hilfsfunktion, um die Modelle tatsächlich über gzip zu komprimieren und die Größe des Reißverschlusses zu messen.

def get_gzipped_model_size(file):
  # Returns size of gzipped model, in bytes.
  import os
  import zipfile

  _, zipped_file = tempfile.mkstemp('.zip')
  with zipfile.ZipFile(zipped_file, 'w', compression=zipfile.ZIP_DEFLATED) as f:
    f.write(file)

  return os.path.getsize(zipped_file)

Vergleichen Sie und sehen Sie, dass die Modelle vom Beschneiden 3x kleiner sind.

print("Size of gzipped baseline Keras model: %.2f bytes" % (get_gzipped_model_size(keras_file)))
print("Size of gzipped pruned Keras model: %.2f bytes" % (get_gzipped_model_size(pruned_keras_file)))
print("Size of gzipped pruned TFlite model: %.2f bytes" % (get_gzipped_model_size(pruned_tflite_file)))
Size of gzipped baseline Keras model: 78211.00 bytes
Size of gzipped pruned Keras model: 25797.00 bytes
Size of gzipped pruned TFlite model: 24995.00 bytes

Erstellen Sie ein 10x kleineres Modell aus der Kombination von Bereinigung und Quantisierung

Sie können die Quantisierung nach dem Training auf das beschnittene Modell anwenden, um zusätzliche Vorteile zu erzielen.

converter = tf.lite.TFLiteConverter.from_keras_model(model_for_export)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
quantized_and_pruned_tflite_model = converter.convert()

_, quantized_and_pruned_tflite_file = tempfile.mkstemp('.tflite')

with open(quantized_and_pruned_tflite_file, 'wb') as f:
  f.write(quantized_and_pruned_tflite_model)

print('Saved quantized and pruned TFLite model to:', quantized_and_pruned_tflite_file)

print("Size of gzipped baseline Keras model: %.2f bytes" % (get_gzipped_model_size(keras_file)))
print("Size of gzipped pruned and quantized TFlite model: %.2f bytes" % (get_gzipped_model_size(quantized_and_pruned_tflite_file)))
WARNING:tensorflow:Compiled the loaded model, but the compiled metrics have yet to be built. `model.compile_metrics` will be empty until you train or evaluate the model.
WARNING:tensorflow:Compiled the loaded model, but the compiled metrics have yet to be built. `model.compile_metrics` will be empty until you train or evaluate the model.
INFO:tensorflow:Assets written to: /tmp/tmp6tzu3z87/assets
INFO:tensorflow:Assets written to: /tmp/tmp6tzu3z87/assets
Saved quantized and pruned TFLite model to: /tmp/tmp0mvlkin1.tflite
Size of gzipped baseline Keras model: 78211.00 bytes
Size of gzipped pruned and quantized TFlite model: 8031.00 bytes

Siehe Beständigkeit der Genauigkeit von TF bis TFLite

Definieren Sie eine Hilfsfunktion, um das TF Lite-Modell im Testdatensatz auszuwerten.

import numpy as np

def evaluate_model(interpreter):
  input_index = interpreter.get_input_details()[0]["index"]
  output_index = interpreter.get_output_details()[0]["index"]

  # Run predictions on ever y image in the "test" dataset.
  prediction_digits = []
  for i, test_image in enumerate(test_images):
    if i % 1000 == 0:
      print('Evaluated on {n} results so far.'.format(n=i))
    # Pre-processing: add batch dimension and convert to float32 to match with
    # the model's input data format.
    test_image = np.expand_dims(test_image, axis=0).astype(np.float32)
    interpreter.set_tensor(input_index, test_image)

    # Run inference.
    interpreter.invoke()

    # Post-processing: remove batch dimension and find the digit with highest
    # probability.
    output = interpreter.tensor(output_index)
    digit = np.argmax(output()[0])
    prediction_digits.append(digit)

  print('\n')
  # Compare prediction results with ground truth labels to calculate accuracy.
  prediction_digits = np.array(prediction_digits)
  accuracy = (prediction_digits == test_labels).mean()
  return accuracy

Sie bewerten das beschnittene und quantisierte Modell und stellen fest, dass die Genauigkeit von TensorFlow für das TFLite-Backend erhalten bleibt.

interpreter = tf.lite.Interpreter(model_content=quantized_and_pruned_tflite_model)
interpreter.allocate_tensors()

test_accuracy = evaluate_model(interpreter)

print('Pruned and quantized TFLite test_accuracy:', test_accuracy)
print('Pruned TF test accuracy:', model_for_pruning_accuracy)
Evaluated on 0 results so far.
Evaluated on 1000 results so far.
Evaluated on 2000 results so far.
Evaluated on 3000 results so far.
Evaluated on 4000 results so far.
Evaluated on 5000 results so far.
Evaluated on 6000 results so far.
Evaluated on 7000 results so far.
Evaluated on 8000 results so far.
Evaluated on 9000 results so far.


Pruned and quantized TFLite test_accuracy: 0.9722
Pruned TF test accuracy: 0.972100019454956

Fazit

In diesem Tutorial haben Sie gesehen, wie Sie spärliche Modelle mit der TensorFlow Model Optimization Toolkit-API für TensorFlow und TFLite erstellen. Anschließend haben Sie das Beschneiden mit der Quantisierung nach dem Training kombiniert, um zusätzliche Vorteile zu erzielen.

Sie haben ein 10x kleineres Modell für MNIST mit minimalem Genauigkeitsunterschied erstellt.

Wir empfehlen Ihnen, diese neue Funktion auszuprobieren, die für die Bereitstellung in Umgebungen mit eingeschränkten Ressourcen besonders wichtig sein kann.