Kuantisasi bilangan bulat pasca-pelatihan

Lihat di TensorFlow.org Jalankan di Google Colab Lihat sumber di GitHub Unduh buku catatan

Ringkasan

Kuantisasi bilangan bulat adalah strategi optimasi yang mengubah angka titik-mengambang 32-bit (seperti bobot dan keluaran aktivasi) ke angka titik-tetap 8-bit terdekat. Ini menghasilkan model yang lebih kecil dan peningkatan kecepatan inferensia, yang berharga untuk perangkat daya rendah seperti mikrokontroler . Format data ini juga diperlukan oleh integer-satunya akselerator seperti Ujung TPU .

Dalam tutorial ini, Anda akan melatih model MNIST dari awal, mengubahnya menjadi file Tensorflow Lite, dan quantize menggunakan pasca-pelatihan kuantisasi . Terakhir, Anda akan memeriksa keakuratan model yang dikonversi dan membandingkannya dengan model float asli.

Anda sebenarnya memiliki beberapa opsi tentang seberapa banyak Anda ingin mengkuantisasi model. Dalam tutorial ini, Anda akan melakukan "kuantisasi bilangan bulat penuh", yang mengubah semua bobot dan keluaran aktivasi menjadi data bilangan bulat 8-bit—sementara strategi lain mungkin meninggalkan sejumlah data dalam titik-mengambang.

Untuk mempelajari lebih lanjut tentang berbagai strategi kuantisasi, membaca tentang TensorFlow Lite model optimasi .

Mempersiapkan

Untuk mengkuantisasi tensor input dan output, kita perlu menggunakan API yang ditambahkan di TensorFlow r2.3:

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

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

Buat Model TensorFlow

Kami akan membangun model sederhana untuk angka mengklasifikasikan dari dataset MNIST .

Pelatihan ini tidak akan memakan waktu lama karena Anda melatih model hanya untuk 5 epoch, yang melatih akurasi sekitar ~98%.

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

Konversikan ke model TensorFlow Lite

Sekarang Anda dapat mengkonversi model dilatih ke format TensorFlow Lite menggunakan TFLiteConverter API, dan menerapkan berbagai tingkat kuantisasi.

Hati-hati bahwa beberapa versi kuantisasi meninggalkan beberapa data dalam format float. Jadi, bagian berikut menunjukkan setiap opsi dengan jumlah kuantisasi yang meningkat, hingga kita mendapatkan model yang seluruhnya merupakan data int8 atau uint8. (Perhatikan kami menduplikasi beberapa kode di setiap bagian sehingga Anda dapat melihat semua langkah kuantisasi untuk setiap opsi.)

Pertama, inilah model yang dikonversi tanpa kuantisasi:

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.

Sekarang menjadi model TensorFlow Lite, tetapi masih menggunakan nilai float 32-bit untuk semua data parameter.

Konversi menggunakan kuantisasi rentang dinamis

Sekarang mari kita mengaktifkan default optimizations bendera untuk quantize semua parameter tetap (seperti bobot):

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 sekarang sedikit lebih kecil dengan bobot terkuantisasi, tetapi data variabel lainnya masih dalam format float.

Konversi menggunakan kuantisasi fallback float

Untuk quantize data variabel (seperti model input / output dan intermediet antara lapisan), Anda perlu memberikan RepresentativeDataset . Ini adalah fungsi generator yang menyediakan satu set data input yang cukup besar untuk mewakili nilai-nilai tipikal. Ini memungkinkan konverter untuk memperkirakan rentang dinamis untuk semua data variabel. (Dataset tidak perlu unik dibandingkan dengan dataset pelatihan atau evaluasi.) Untuk mendukung banyak input, setiap titik data representatif adalah daftar dan elemen dalam daftar diumpankan ke model sesuai dengan indeksnya.

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

Sekarang semua bobot dan data variabel dikuantisasi, dan modelnya secara signifikan lebih kecil dibandingkan dengan model TensorFlow Lite asli.

Namun, untuk menjaga kompatibilitas dengan aplikasi yang biasanya menggunakan tensor input dan output model float, TensorFlow Lite Converter membiarkan tensor input dan output model dalam 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'>

Itu biasanya bagus untuk kompatibilitas, tetapi tidak akan kompatibel dengan perangkat yang hanya melakukan operasi berbasis bilangan bulat, seperti Edge TPU.

Selain itu, proses di atas dapat meninggalkan operasi dalam format float jika TensorFlow Lite tidak menyertakan implementasi terkuantisasi untuk operasi tersebut. Strategi ini memungkinkan konversi selesai sehingga Anda memiliki model yang lebih kecil dan lebih efisien, tetapi sekali lagi, itu tidak akan kompatibel dengan perangkat keras khusus bilangan bulat. (Semua operasi dalam model MNIST ini memiliki implementasi terkuantisasi.)

Jadi untuk memastikan model integer-only ujung-ke-ujung, Anda memerlukan beberapa parameter lagi...

Konversi menggunakan kuantisasi bilangan bulat saja

Untuk mengkuantisasi tensor input dan output, dan membuat konverter membuat kesalahan jika menemui operasi yang tidak dapat dikuantisasi, konversi model lagi dengan beberapa parameter tambahan:

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.

Kuantisasi internal tetap sama seperti di atas, tetapi Anda dapat melihat tensor input dan output sekarang dalam format integer:

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

Sekarang Anda memiliki model bilangan bulat dikuantisasi yang menggunakan bilangan bulat data untuk input dan output tensor model, sehingga kompatibel dengan hardware integer-satunya seperti Ujung TPU .

Simpan model sebagai file

Anda akan memerlukan .tflite berkas untuk menyebarkan model Anda pada perangkat lain. Jadi mari kita simpan model yang dikonversi ke file dan kemudian memuatnya saat kita menjalankan inferensi di bawah ini.

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

Jalankan model TensorFlow Lite

Sekarang kami akan menjalankan kesimpulan menggunakan TensorFlow Lite Interpreter untuk membandingkan akurasi model yang.

Pertama, kita membutuhkan fungsi yang menjalankan inferensi dengan model dan gambar tertentu, lalu mengembalikan prediksi:

# 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

Uji model pada satu gambar

Sekarang kita akan membandingkan kinerja model float dan model terkuantisasi:

  • tflite_model_file adalah model TensorFlow Lite asli dengan data floating-point.
  • tflite_model_quant_file adalah model terakhir kita dikonversi menggunakan integer-satunya kuantisasi (menggunakan data uint8 untuk input dan output).

Mari kita buat fungsi lain untuk mencetak prediksi kita:

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)

Sekarang uji model float:

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

png

Dan uji model terkuantisasi:

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

png

Evaluasi model pada semua gambar

Sekarang mari kita jalankan kedua model menggunakan semua gambar uji yang kita muat di awal tutorial ini:

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

Evaluasi model float:

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

Evaluasi model terkuantisasi:

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

Jadi Anda sekarang memiliki model terkuantisasi bilangan bulat dengan hampir tidak ada perbedaan dalam akurasi, dibandingkan dengan model float.

Untuk mempelajari lebih lanjut tentang strategi kuantisasi lainnya, membaca tentang TensorFlow Lite model optimasi .