Quantização de faixa dinâmica pós-treinamento

Ver no TensorFlow.org Executar no Google Colab Ver fonte no GitHub Baixar caderno Veja o modelo do TF Hub

Visão geral

TensorFlow Lite agora suporta a conversão de pesos para precisão de 8 bits como parte da conversão do modelo de graphdefs tensorflow para o formato tampão plana de TensorFlow Lite. A quantização de faixa dinâmica atinge uma redução de 4x no tamanho do modelo. Além disso, o TFLite suporta a quantização e desquantização em tempo real de ativações para permitir:

  1. Usando kernels quantizados para implementação mais rápida, quando disponível.
  2. Mistura de kernels de ponto flutuante com kernels quantizados para diferentes partes do gráfico.

As ativações são sempre armazenadas em ponto flutuante. Para ops que suportam kernels quantizados, as ativações são quantizadas para 8 bits de precisão dinamicamente antes do processamento e são dequantizadas para flutuar com precisão após o processamento. Dependendo do modelo que está sendo convertido, isso pode fornecer uma aceleração sobre o cálculo puro de ponto flutuante.

Em contraste com a formação ciente quantização , os pesos são formação pós quantizado e as ativações são quantificados dinamicamente durante a inferência neste método. Portanto, os pesos do modelo não são retreinados para compensar os erros induzidos pela quantização. É importante verificar a precisão do modelo quantizado para garantir que a degradação seja aceitável.

Este tutorial treina um modelo MNIST do zero, verifica sua precisão no TensorFlow e, em seguida, converte o modelo em um flatbuffer Tensorflow Lite com quantização de faixa dinâmica. Finalmente, ele verifica a precisão do modelo convertido e o compara com o modelo flutuante original.

Construir um modelo MNIST

Configurar

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

import tensorflow as tf
from tensorflow import keras
import numpy as np
import pathlib

Treine um modelo TensorFlow

# 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 to 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=tf.nn.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=keras.losses.SparseCategoricalCrossentropy(from_logits=True),
              metrics=['accuracy'])
model.fit(
  train_images,
  train_labels,
  epochs=1,
  validation_data=(test_images, test_labels)
)
1875/1875 [==============================] - 6s 2ms/step - loss: 0.3260 - accuracy: 0.9063 - val_loss: 0.1721 - val_accuracy: 0.9499
<keras.callbacks.History at 0x7fb7a1c4ed90>

Para o exemplo, como você treinou o modelo apenas para uma única época, ele treina apenas com aproximadamente 96% de precisão.

Converter para um modelo TensorFlow Lite

Usando o Python TFLiteConverter , agora você pode converter o modelo treinado em um modelo TensorFlow Lite.

Agora carregar o modelo usando o TFLiteConverter :

converter = tf.lite.TFLiteConverter.from_keras_model(model)
tflite_model = converter.convert()
2021-11-02 11:23:32.211024: W tensorflow/python/util/util.cc:348] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them.
INFO:tensorflow:Assets written to: /tmp/tmpua453ven/assets
2021-11-02 11:23:32.640259: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:351] Ignored output_format.
2021-11-02 11:23:32.640302: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:354] Ignored drop_control_dependency.

Grave em um arquivo tflite:

tflite_models_dir = pathlib.Path("/tmp/mnist_tflite_models/")
tflite_models_dir.mkdir(exist_ok=True, parents=True)
tflite_model_file = tflite_models_dir/"mnist_model.tflite"
tflite_model_file.write_bytes(tflite_model)
84500

Para quantificar o modelo de exportação, defina a optimizations bandeira para otimizar o tamanho:

converter.optimizations = [tf.lite.Optimize.DEFAULT]
tflite_quant_model = converter.convert()
tflite_model_quant_file = tflite_models_dir/"mnist_model_quant.tflite"
tflite_model_quant_file.write_bytes(tflite_quant_model)
INFO:tensorflow:Assets written to: /tmp/tmpaw0wsb_y/assets
INFO:tensorflow:Assets written to: /tmp/tmpaw0wsb_y/assets
2021-11-02 11:23:33.235475: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:351] Ignored output_format.
2021-11-02 11:23:33.235512: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:354] Ignored drop_control_dependency.
23904

Note-se como o arquivo resultante, é de aproximadamente 1/4 do tamanho.

ls -lh {tflite_models_dir}
total 136K
-rw-rw-r-- 1 kbuilder kbuilder 83K Nov  2 11:23 mnist_model.tflite
-rw-rw-r-- 1 kbuilder kbuilder 24K Nov  2 11:23 mnist_model_quant.tflite
-rw-rw-r-- 1 kbuilder kbuilder 25K Nov  2 11:20 mnist_model_quant_16x8.tflite

Execute os modelos TFLite

Execute o modelo TensorFlow Lite usando o Python TensorFlow Lite Interpreter.

Carregue o modelo em um intérprete

interpreter = tf.lite.Interpreter(model_path=str(tflite_model_file))
interpreter.allocate_tensors()
interpreter_quant = tf.lite.Interpreter(model_path=str(tflite_model_quant_file))
interpreter_quant.allocate_tensors()

Teste o modelo em uma imagem

test_image = np.expand_dims(test_images[0], axis=0).astype(np.float32)

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

interpreter.set_tensor(input_index, test_image)
interpreter.invoke()
predictions = interpreter.get_tensor(output_index)
import matplotlib.pylab as plt

plt.imshow(test_images[0])
template = "True:{true}, predicted:{predict}"
_ = plt.title(template.format(true= str(test_labels[0]),
                              predict=str(np.argmax(predictions[0]))))
plt.grid(False)

png

Avalie os modelos

# A helper function to evaluate the TF Lite model using "test" dataset.
def evaluate_model(interpreter):
  input_index = interpreter.get_input_details()[0]["index"]
  output_index = interpreter.get_output_details()[0]["index"]

  # Run predictions on every image in the "test" dataset.
  prediction_digits = []
  for test_image in test_images:
    # 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)

  # Compare prediction results with ground truth labels to calculate accuracy.
  accurate_count = 0
  for index in range(len(prediction_digits)):
    if prediction_digits[index] == test_labels[index]:
      accurate_count += 1
  accuracy = accurate_count * 1.0 / len(prediction_digits)

  return accuracy
print(evaluate_model(interpreter))
0.9499

Repita a avaliação no modelo quantizado de faixa dinâmica para obter:

print(evaluate_model(interpreter_quant))
0.95

Neste exemplo, o modelo compactado não tem diferença na precisão.

Otimizando um modelo existente

Resnets com camadas de pré-ativação (Resnet-v2) são amplamente utilizadas para aplicações de visão. Pré-treinado gráfico congelado por ResNet-v2-101 é acessível em Tensorflow Hub .

Você pode converter o gráfico congelado em um flatbuffer TensorFLow Lite com quantização:

import tensorflow_hub as hub

resnet_v2_101 = tf.keras.Sequential([
  keras.layers.InputLayer(input_shape=(224, 224, 3)),
  hub.KerasLayer("https://tfhub.dev/google/imagenet/resnet_v2_101/classification/4")
])

converter = tf.lite.TFLiteConverter.from_keras_model(resnet_v2_101)
# Convert to TF Lite without quantization
resnet_tflite_file = tflite_models_dir/"resnet_v2_101.tflite"
resnet_tflite_file.write_bytes(converter.convert())
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/tmpxtji1amp/assets
INFO:tensorflow:Assets written to: /tmp/tmpxtji1amp/assets
2021-11-02 11:23:57.616139: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:351] Ignored output_format.
2021-11-02 11:23:57.616201: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:354] Ignored drop_control_dependency.
178509352
# Convert to TF Lite with quantization
converter.optimizations = [tf.lite.Optimize.DEFAULT]
resnet_quantized_tflite_file = tflite_models_dir/"resnet_v2_101_quantized.tflite"
resnet_quantized_tflite_file.write_bytes(converter.convert())
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/tmpg169iato/assets
INFO:tensorflow:Assets written to: /tmp/tmpg169iato/assets
2021-11-02 11:24:12.965799: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:351] Ignored output_format.
2021-11-02 11:24:12.965851: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:354] Ignored drop_control_dependency.
46256864
ls -lh {tflite_models_dir}/*.tflite
-rw-rw-r-- 1 kbuilder kbuilder  83K Nov  2 11:23 /tmp/mnist_tflite_models/mnist_model.tflite
-rw-rw-r-- 1 kbuilder kbuilder  24K Nov  2 11:23 /tmp/mnist_tflite_models/mnist_model_quant.tflite
-rw-rw-r-- 1 kbuilder kbuilder  25K Nov  2 11:20 /tmp/mnist_tflite_models/mnist_model_quant_16x8.tflite
-rw-rw-r-- 1 kbuilder kbuilder 171M Nov  2 11:23 /tmp/mnist_tflite_models/resnet_v2_101.tflite
-rw-rw-r-- 1 kbuilder kbuilder  45M Nov  2 11:24 /tmp/mnist_tflite_models/resnet_v2_101_quantized.tflite

O tamanho do modelo é reduzido de 171 MB para 43 MB. A precisão deste modelo em IMAGEnet pode ser avaliada utilizando os scripts fornecidos para medição de precisão TFLite .

A precisão do modelo top-1 otimizado é de 76,8, a mesma do modelo de ponto flutuante.