تكميم صحيح بعد التدريب مع عمليات تنشيط int16

عرض على TensorFlow.org تشغيل في Google Colab عرض المصدر على جيثب تحميل دفتر

ملخص

TensorFlow لايت يدعم الآن تحويل التنشيط إلى قيم عددية صحيحة 16 بت والأوزان إلى 8 بت عدد صحيح القيم خلال تحويل نموذج من TensorFlow إلى تنسيق عازلة شقة TensorFlow لايت. نشير إلى هذا الوضع باسم "وضع تكميم 16x8". يمكن لهذا الوضع تحسين دقة النموذج الكمي بشكل كبير ، عندما تكون التنشيطات حساسة للتكميم ، مع الاستمرار في تحقيق ما يقرب من 3-4x في حجم النموذج. علاوة على ذلك ، يمكن استهلاك هذا النموذج الكمي بالكامل بواسطة مسرعات الأجهزة ذات الأعداد الصحيحة فقط.

تتضمن بعض الأمثلة على النماذج التي تستفيد من هذا الوضع في تكميم ما بعد التدريب ما يلي:

  • دقة فائقة ،
  • معالجة الإشارات الصوتية مثل إلغاء الضوضاء وتشكيل الحزمة ،
  • إزالة الضوضاء من الصورة ،
  • إعادة بناء HDR من صورة واحدة

في هذا البرنامج التعليمي ، تقوم بتدريب نموذج MNIST من البداية ، والتحقق من دقته في TensorFlow ، ثم تحويل النموذج إلى Tensorflow Lite مسطح باستخدام هذا الوضع. في النهاية ، تتحقق من دقة النموذج المحول ومقارنته بنموذج float32 الأصلي. لاحظ أن هذا المثال يوضح استخدام هذا الوضع ولا يُظهر فوائد على تقنيات التكميم الأخرى المتاحة في TensorFlow Lite.

بناء نموذج MNIST

يثبت

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

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

تأكد من أن وضع التكميم 16x8 متاح

tf.lite.OpsSet.EXPERIMENTAL_TFLITE_BUILTINS_ACTIVATIONS_INT16_WEIGHTS_INT8
<OpsSet.EXPERIMENTAL_TFLITE_BUILTINS_ACTIVATIONS_INT16_WEIGHTS_INT8: 'EXPERIMENTAL_TFLITE_BUILTINS_ACTIVATIONS_INT16_WEIGHTS_INT8'>

تدريب وتصدير النموذج

# 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.2797 - accuracy: 0.9224 - val_loss: 0.1224 - val_accuracy: 0.9641
<keras.callbacks.History at 0x7f6f19eff210>

على سبيل المثال ، قمت بتدريب النموذج على حقبة واحدة فقط ، لذا فهو يتدرب فقط بدقة تصل إلى ~ 96٪.

قم بالتحويل إلى نموذج TensorFlow Lite

باستخدام بيثون TFLiteConverter ، يمكنك الآن تحويل نموذج تدريب إلى نموذج TensorFlow لايت.

الآن، وتحويل النموذج باستخدام TFliteConverter في شكل float32 الافتراضي:

converter = tf.lite.TFLiteConverter.from_keras_model(model)
tflite_model = converter.convert()
2021-10-30 11:55:42.971843: 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/tmpbriefkal/assets
2021-10-30 11:55:43.402148: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:351] Ignored output_format.
2021-10-30 11:55:43.402187: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:354] Ignored drop_control_dependency.

الكتابة بها إلى .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

بدلا من ذلك ثبت قيمة النموذج ل16x8 وضع تكميم، أولا تعيين optimizations العلم أمثل استخدام الافتراضي. ثم حدد أن وضع التكميم 16x8 هو العملية المدعومة المطلوبة في المواصفات المستهدفة:

converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.target_spec.supported_ops = [tf.lite.OpsSet.EXPERIMENTAL_TFLITE_BUILTINS_ACTIVATIONS_INT16_WEIGHTS_INT8]

كما هو الحال في حالة int8 تكميم بعد التدريب، فمن الممكن لإنتاج نموذج كامل الكم صحيح عن طريق وضع خيارات تحويل inference_input(output)_type إلى tf.int16.

اضبط بيانات المعايرة:

mnist_train, _ = tf.keras.datasets.mnist.load_data()
images = tf.cast(mnist_train[0], tf.float32) / 255.0
mnist_ds = tf.data.Dataset.from_tensor_slices((images)).batch(1)
def representative_data_gen():
  for input_value in mnist_ds.take(100):
    # Model has only one input so each data point has one element.
    yield [input_value]
converter.representative_dataset = representative_data_gen

أخيرًا ، قم بتحويل النموذج كالمعتاد. ملاحظة ، بشكل افتراضي ، سيظل النموذج المحول يستخدم المدخلات والمخرجات العائمة لتسهيل الاستدعاء.

tflite_16x8_model = converter.convert()
tflite_model_16x8_file = tflite_models_dir/"mnist_model_quant_16x8.tflite"
tflite_model_16x8_file.write_bytes(tflite_16x8_model)
INFO:tensorflow:Assets written to: /tmp/tmpfxn_2jql/assets
INFO:tensorflow:Assets written to: /tmp/tmpfxn_2jql/assets
2021-10-30 11:55:44.514461: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:351] Ignored output_format.
2021-10-30 11:55:44.514507: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:354] Ignored drop_control_dependency.
24768

لاحظ كيف الملف الناتج هو ما يقرب من 1/3 حجم.

ls -lh {tflite_models_dir}
total 136K
-rw-rw-r-- 1 kbuilder kbuilder 83K Oct 30 11:55 mnist_model.tflite
-rw-rw-r-- 1 kbuilder kbuilder 24K Oct 30 11:54 mnist_model_quant.tflite
-rw-rw-r-- 1 kbuilder kbuilder 25K Oct 30 11:55 mnist_model_quant_16x8.tflite

قم بتشغيل نماذج TensorFlow Lite

قم بتشغيل نموذج TensorFlow Lite باستخدام مترجم Python TensorFlow Lite.

تحميل النموذج في المترجمين الفوريين

interpreter = tf.lite.Interpreter(model_path=str(tflite_model_file))
interpreter.allocate_tensors()
interpreter_16x8 = tf.lite.Interpreter(model_path=str(tflite_model_16x8_file))
interpreter_16x8.allocate_tensors()

اختبر النماذج على صورة واحدة

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)

بي إن جي

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

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

interpreter_16x8.set_tensor(input_index, test_image)
interpreter_16x8.invoke()
predictions = interpreter_16x8.get_tensor(output_index)
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)

بي إن جي

تقييم النماذج

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

كرر التقييم على النموذج الكمي 16x8:

# NOTE: This quantization mode is an experimental post-training mode,
# it does not have any optimized kernels implementations or
# specialized machine learning hardware accelerators. Therefore,
# it could be slower than the float interpreter.
print(evaluate_model(interpreter_16x8))
0.964

في هذا المثال ، قمت بتقسيم نموذج إلى 16x8 مع عدم وجود اختلاف في الدقة ، ولكن بحجم أصغر 3x.

و

عرض على TensorFlow.org تشغيل في Google Colab عرض المصدر على جيثب تحميل دفتر

ملخص

TensorFlow لايت يدعم الآن تحويل التنشيط إلى قيم عددية صحيحة 16 بت والأوزان إلى 8 بت عدد صحيح القيم خلال تحويل نموذج من TensorFlow إلى تنسيق عازلة شقة TensorFlow لايت. نشير إلى هذا الوضع باسم "وضع تكميم 16x8". يمكن لهذا الوضع تحسين دقة النموذج الكمي بشكل كبير ، عندما تكون التنشيطات حساسة للتكميم ، مع الاستمرار في تحقيق ما يقرب من 3-4x في حجم النموذج. علاوة على ذلك ، يمكن استهلاك هذا النموذج الكمي بالكامل بواسطة مسرعات الأجهزة ذات الأعداد الصحيحة فقط.

تتضمن بعض الأمثلة على النماذج التي تستفيد من هذا الوضع في تكميم ما بعد التدريب ما يلي:

  • دقة فائقة ،
  • معالجة الإشارات الصوتية مثل إلغاء الضوضاء وتشكيل الحزمة ،
  • إزالة الضوضاء من الصورة ،
  • إعادة بناء HDR من صورة واحدة

في هذا البرنامج التعليمي ، تقوم بتدريب نموذج MNIST من البداية ، والتحقق من دقته في TensorFlow ، ثم تحويل النموذج إلى Tensorflow Lite مسطح باستخدام هذا الوضع. في النهاية ، تتحقق من دقة النموذج المحول ومقارنته بنموذج float32 الأصلي. لاحظ أن هذا المثال يوضح استخدام هذا الوضع ولا يُظهر فوائد على تقنيات التكميم الأخرى المتاحة في TensorFlow Lite.

بناء نموذج MNIST

يثبت

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

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

تأكد من أن وضع التكميم 16x8 متاح

tf.lite.OpsSet.EXPERIMENTAL_TFLITE_BUILTINS_ACTIVATIONS_INT16_WEIGHTS_INT8
<OpsSet.EXPERIMENTAL_TFLITE_BUILTINS_ACTIVATIONS_INT16_WEIGHTS_INT8: 'EXPERIMENTAL_TFLITE_BUILTINS_ACTIVATIONS_INT16_WEIGHTS_INT8'>

تدريب وتصدير النموذج

# 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.2797 - accuracy: 0.9224 - val_loss: 0.1224 - val_accuracy: 0.9641
<keras.callbacks.History at 0x7f6f19eff210>

على سبيل المثال ، قمت بتدريب النموذج على حقبة واحدة فقط ، لذا فهو يتدرب فقط بدقة تصل إلى ~ 96٪.

قم بالتحويل إلى نموذج TensorFlow Lite

باستخدام بيثون TFLiteConverter ، يمكنك الآن تحويل نموذج تدريب إلى نموذج TensorFlow لايت.

الآن، وتحويل النموذج باستخدام TFliteConverter في شكل float32 الافتراضي:

converter = tf.lite.TFLiteConverter.from_keras_model(model)
tflite_model = converter.convert()
2021-10-30 11:55:42.971843: 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/tmpbriefkal/assets
2021-10-30 11:55:43.402148: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:351] Ignored output_format.
2021-10-30 11:55:43.402187: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:354] Ignored drop_control_dependency.

الكتابة بها إلى .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

بدلا من ذلك ثبت قيمة النموذج ل16x8 وضع تكميم، أولا تعيين optimizations العلم أمثل استخدام الافتراضي. ثم حدد أن وضع التكميم 16x8 هو العملية المدعومة المطلوبة في المواصفات المستهدفة:

converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.target_spec.supported_ops = [tf.lite.OpsSet.EXPERIMENTAL_TFLITE_BUILTINS_ACTIVATIONS_INT16_WEIGHTS_INT8]

كما هو الحال في حالة int8 تكميم بعد التدريب، فمن الممكن لإنتاج نموذج كامل الكم صحيح عن طريق وضع خيارات تحويل inference_input(output)_type إلى tf.int16.

اضبط بيانات المعايرة:

mnist_train, _ = tf.keras.datasets.mnist.load_data()
images = tf.cast(mnist_train[0], tf.float32) / 255.0
mnist_ds = tf.data.Dataset.from_tensor_slices((images)).batch(1)
def representative_data_gen():
  for input_value in mnist_ds.take(100):
    # Model has only one input so each data point has one element.
    yield [input_value]
converter.representative_dataset = representative_data_gen

أخيرًا ، قم بتحويل النموذج كالمعتاد. ملاحظة ، بشكل افتراضي ، سيظل النموذج المحول يستخدم المدخلات والمخرجات العائمة لتسهيل الاستدعاء.

tflite_16x8_model = converter.convert()
tflite_model_16x8_file = tflite_models_dir/"mnist_model_quant_16x8.tflite"
tflite_model_16x8_file.write_bytes(tflite_16x8_model)
INFO:tensorflow:Assets written to: /tmp/tmpfxn_2jql/assets
INFO:tensorflow:Assets written to: /tmp/tmpfxn_2jql/assets
2021-10-30 11:55:44.514461: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:351] Ignored output_format.
2021-10-30 11:55:44.514507: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:354] Ignored drop_control_dependency.
24768

لاحظ كيف الملف الناتج هو ما يقرب من 1/3 حجم.

ls -lh {tflite_models_dir}
total 136K
-rw-rw-r-- 1 kbuilder kbuilder 83K Oct 30 11:55 mnist_model.tflite
-rw-rw-r-- 1 kbuilder kbuilder 24K Oct 30 11:54 mnist_model_quant.tflite
-rw-rw-r-- 1 kbuilder kbuilder 25K Oct 30 11:55 mnist_model_quant_16x8.tflite

قم بتشغيل نماذج TensorFlow Lite

قم بتشغيل نموذج TensorFlow Lite باستخدام مترجم Python TensorFlow Lite.

تحميل النموذج في المترجمين الفوريين

interpreter = tf.lite.Interpreter(model_path=str(tflite_model_file))
interpreter.allocate_tensors()
interpreter_16x8 = tf.lite.Interpreter(model_path=str(tflite_model_16x8_file))
interpreter_16x8.allocate_tensors()

اختبر النماذج على صورة واحدة

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)

بي إن جي

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

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

interpreter_16x8.set_tensor(input_index, test_image)
interpreter_16x8.invoke()
predictions = interpreter_16x8.get_tensor(output_index)
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)

بي إن جي

تقييم النماذج

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

كرر التقييم على النموذج الكمي 16x8:

# NOTE: This quantization mode is an experimental post-training mode,
# it does not have any optimized kernels implementations or
# specialized machine learning hardware accelerators. Therefore,
# it could be slower than the float interpreter.
print(evaluate_model(interpreter_16x8))
0.964

في هذا المثال ، قمت بتقسيم نموذج إلى 16x8 مع عدم وجود اختلاف في الدقة ، ولكن بحجم أصغر 3x.