Eğitim sonrası tamsayı nicemleme

TensorFlow.org'da görüntüleyin Google Colab'da çalıştırın Kaynağı GitHub'da görüntüleyin Not defterini indir

genel bakış

Tamsayı nicemleme, 32 bitlik kayan noktalı sayıları (ağırlıklar ve etkinleştirme çıktıları gibi) en yakın 8 bitlik sabit noktalı sayılara dönüştüren bir optimizasyon stratejisidir. Bu daha küçük bir model ile sonuçlanır ve bu nedenle düşük güç aygıtları için değerlidir artan kestirilmesinde hızı, mikro denetleyici . Bu veri formatı, ayrıca gerekli olan tam sayı sadece gibi hızlandırıcılar Kenar TPU .

Bu eğitimde, sen sıfırdan bir MNIST modelini eğitmek olacak bir Tensorflow Lite dosyası haline dönüştürmek ve kullanarak kuantize eğitim sonrası nicemlemesini . Son olarak, dönüştürülen modelin doğruluğunu kontrol edecek ve orijinal yüzer modelle karşılaştıracaksınız.

Bir modeli ne kadar nicelleştirmek istediğinize dair aslında birkaç seçeneğiniz var. Bu öğreticide, tüm ağırlıkları ve etkinleştirme çıktılarını 8 bitlik tamsayı verilerine dönüştüren "tam tamsayı niceleme" gerçekleştireceksiniz; diğer stratejiler ise bir miktar veriyi kayan noktada bırakabilir.

Hakkında okumak çeşitli nicemleme stratejileri ile ilgili daha fazla bilgi edinmek için TensorFlow Lite modeli optimizasyonu .

Kurmak

Hem giriş hem de çıkış tensörlerini nicelemek için TensorFlow r2.3'e eklenen API'leri kullanmamız gerekir:

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

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

Bir TensorFlow Modeli Oluşturun

Biz gelen sınıfladıkları'nı sayılar için basit bir modelini inşa edeceğiz MNIST veri kümesi .

Bu eğitim uzun sürmez çünkü modeli yalnızca yaklaşık %98 doğrulukla eğiten 5 dönem için eğitiyorsunuz.

# 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 [==============================] - 5s 2ms/step - loss: 0.2519 - accuracy: 0.9311 - val_loss: 0.1106 - val_accuracy: 0.9664
Epoch 2/5
1875/1875 [==============================] - 3s 2ms/step - loss: 0.0984 - accuracy: 0.9724 - val_loss: 0.0828 - val_accuracy: 0.9743
Epoch 3/5
1875/1875 [==============================] - 3s 2ms/step - loss: 0.0746 - accuracy: 0.9785 - val_loss: 0.0640 - val_accuracy: 0.9795
Epoch 4/5
1875/1875 [==============================] - 3s 2ms/step - loss: 0.0620 - accuracy: 0.9814 - val_loss: 0.0620 - val_accuracy: 0.9793
Epoch 5/5
1875/1875 [==============================] - 3s 2ms/step - loss: 0.0540 - accuracy: 0.9837 - val_loss: 0.0624 - val_accuracy: 0.9795
<keras.callbacks.History at 0x7fb44c988c90>

TensorFlow Lite modeline dönüştürün

Şimdi kullanarak TensorFlow Lite formatına eğitilmiş modeli dönüştürebilirsiniz TFLiteConverter API ve Kuantizasyonun değişen derecelerde geçerlidir.

Bazı niceleme sürümlerinin, verilerin bir kısmını kayan biçimli biçimde bıraktığına dikkat edin. Bu nedenle, aşağıdaki bölümler, tamamen int8 veya uint8 verilerinden oluşan bir model elde edene kadar, artan niceleme miktarlarıyla her seçeneği gösterir. (Her bir seçenek için tüm niceleme adımlarını görebilmeniz için her bölümde bazı kodları çoğalttığımıza dikkat edin.)

İlk olarak, nicemleme içermeyen dönüştürülmüş bir model:

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

tflite_model = converter.convert()
2021-10-30 12:04:56.623151: 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/tmp3os2tr3n/assets
2021-10-30 12:04:57.031317: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:351] Ignored output_format.
2021-10-30 12:04:57.031355: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:354] Ignored drop_control_dependency.

Artık bir TensorFlow Lite modelidir, ancak yine de tüm parametre verileri için 32 bit kayan değerler kullanıyor.

Dinamik aralık niceleme kullanarak dönüştürme

Şimdi izin varsayılan sağlayacak optimizations (ağırlıklar gibi) tüm sabit parametreleri nicelemek için bayrağı:

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/tmpi7xibvaj/assets
INFO:tensorflow:Assets written to: /tmp/tmpi7xibvaj/assets
2021-10-30 12:04:57.597982: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:351] Ignored output_format.
2021-10-30 12:04:57.598020: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:354] Ignored drop_control_dependency.

Model artık nicelenmiş ağırlıklarla biraz daha küçüktür, ancak diğer değişken veriler hala kayan formattadır.

Float geri dönüş niceleme kullanarak dönüştürme

(Örneğin, tabakalar arasındaki örnek giriş / çıkış ve ara maddeler olarak) değişken veri kuantize için bir sağlamak için gereken RepresentativeDataset . Bu, tipik değerleri temsil edecek kadar büyük bir girdi verisi seti sağlayan bir üreteç işlevidir. Dönüştürücünün tüm değişken veriler için dinamik bir aralık tahmin etmesine olanak tanır. (Veri kümesinin eğitim veya değerlendirme veri kümesine kıyasla benzersiz olması gerekmez.) Birden çok girişi desteklemek için her temsili veri noktası bir listedir ve listedeki öğeler, endekslerine göre modele beslenir.

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/tmp3gwloj7n/assets
INFO:tensorflow:Assets written to: /tmp/tmp3gwloj7n/assets
2021-10-30 12:04:58.159142: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:351] Ignored output_format.
2021-10-30 12:04:58.159181: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:354] Ignored drop_control_dependency.
fully_quantize: 0, inference_type: 6, input_inference_type: 0, output_inference_type: 0

Artık tüm ağırlıklar ve değişken veriler nicelleştirilmiştir ve model, orijinal TensorFlow Lite modeline kıyasla önemli ölçüde daha küçüktür.

Bununla birlikte, geleneksel olarak kayan noktalı model giriş ve çıkış tensörlerini kullanan uygulamalarla uyumluluğu korumak için, TensorFlow Lite Dönüştürücü, model giriş ve çıkış tensörlerini kayan durumda bırakır:

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'>

Bu genellikle uyumluluk için iyidir, ancak Edge TPU gibi yalnızca tamsayı tabanlı işlemler gerçekleştiren cihazlarla uyumlu olmayacaktır.

Ek olarak, TensorFlow Lite o işlem için nicelleştirilmiş bir uygulama içermiyorsa, yukarıdaki işlem bir işlemi kayan formatta bırakabilir. Bu strateji, dönüştürmenin tamamlanmasını sağlar, böylece daha küçük ve daha verimli bir modele sahip olursunuz, ancak yine, yalnızca tamsayılı donanımla uyumlu olmayacaktır. (Bu MNIST modelindeki tüm operasyonlar nicelleştirilmiş bir uygulamaya sahiptir.)

Bu nedenle, uçtan uca yalnızca tamsayılı bir model sağlamak için birkaç parametreye daha ihtiyacınız var...

Yalnızca tamsayı niceleme kullanarak dönüştürme

Giriş ve çıkış tensörlerini nicemlemek ve dönüştürücünün niceleyemediği bir işlemle karşılaşırsa hata vermesini sağlamak için modeli bazı ek parametrelerle yeniden dönüştürün:

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/tmp8ygc2_3y/assets
INFO:tensorflow:Assets written to: /tmp/tmp8ygc2_3y/assets
2021-10-30 12:04:59.308505: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:351] Ignored output_format.
2021-10-30 12:04:59.308542: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:354] Ignored drop_control_dependency.
fully_quantize: 0, inference_type: 6, input_inference_type: 3, output_inference_type: 3
WARNING:absl:For model inputs containing unsupported operations which cannot be quantized, the `inference_input_type` attribute will default to the original type.

Dahili niceleme yukarıdakiyle aynı kalır, ancak giriş ve çıkış tensörlerinin artık tamsayı biçiminde olduğunu görebilirsiniz:

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'>

Şimdi bir tamsayı Nicemlenmis modeli var modelin giriş ve çıkış tensörlerle verilerine tamsayı kullanır, bu gibi tamsayı okunur donanım ile uyumlu böylece Kenar TPU .

Modelleri dosya olarak kaydedin

Bir gerekir .tflite diğer cihazlarda modelinizi dağıtmak için dosyayı. O halde dönüştürülen modelleri dosyalara kaydedelim ve aşağıdaki çıkarımları çalıştırdığımızda onları yükleyelim.

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)
24280

TensorFlow Lite modellerini çalıştırın

Şimdi TensorFlow Lite kullanarak çıkarımlar yayınlarız Interpreter modeli doğrulukları karşılaştırmak.

İlk olarak, belirli bir model ve görüntülerle çıkarım yapan ve ardından tahminleri döndüren bir işleve ihtiyacımız var:

# 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

Modelleri tek bir görüntü üzerinde test edin

Şimdi şamandıra modeli ile nicelenmiş modelin performansını karşılaştıracağız:

  • tflite_model_file kayan nokta verileri ile orijinal TensorFlow Lite modelidir.
  • tflite_model_quant_file biz tamsayıdır okunur niceleme kullanılarak dönüştürülmüş son modelidir (giriş ve çıkış için uint8 verileri kullanır).

Tahminlerimizi yazdırmak için başka bir fonksiyon oluşturalım:

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)

Şimdi şamandıra modelini test edin:

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

png

Ve nicelenmiş modeli test edin:

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

png

Modelleri tüm görsellerde değerlendirin

Şimdi bu öğreticinin başında yüklediğimiz tüm test görüntülerini kullanarak her iki modeli de çalıştıralım:

# 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)))

Şamandıra modelini değerlendirin:

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

Kuantize modeli değerlendirin:

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

Yani artık, kayan model ile karşılaştırıldığında, doğrulukta neredeyse hiçbir fark olmayan bir modelin nicemlenmiş bir tamsayısına sahipsiniz.

Hakkında okumak diğer nicemleme stratejileri hakkında daha fazla bilgi edinmek için TensorFlow Lite modeli optimizasyonu .