تكميم float16 بعد التدريب

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

ملخص

TensorFlow لايت يدعم الآن تحويل الأوزان إلى القيم نقطة عائمة 16 بت خلال تحويل نموذج من TensorFlow إلى تنسيق عازلة شقة TensorFlow لايت. ينتج عن هذا تقليل حجم النموذج بمقدار ضعفين. يمكن لبعض الأجهزة ، مثل وحدات معالجة الرسومات (GPU) ، الحساب محليًا في هذا الحساب الدقيق المنخفض ، مما يحقق تسريع تنفيذ النقطة العائمة التقليدية. يمكن تكوين مفوض Tensorflow Lite GPU للعمل بهذه الطريقة. ومع ذلك ، لا يزال من الممكن تشغيل نموذج تم تحويله إلى أوزان float16 على وحدة المعالجة المركزية دون تعديل إضافي: تتم زيادة أوزان float16 إلى float32 قبل الاستنتاج الأول. يسمح هذا بتخفيض كبير في حجم النموذج مقابل الحد الأدنى من التأثيرات على زمن الوصول والدقة.

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

بناء نموذج MNIST

يثبت

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

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

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

# 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)
)
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/mnist.npz
11493376/11490434 [==============================] - 0s 0us/step
11501568/11490434 [==============================] - 0s 0us/step
1875/1875 [==============================] - 13s 2ms/step - loss: 0.2655 - accuracy: 0.9244 - val_loss: 0.1237 - val_accuracy: 0.9654
<keras.callbacks.History at 0x7f3f8428e6d0>

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

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

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

الآن تحميل نموذج باستخدام TFLiteConverter :

converter = tf.lite.TFLiteConverter.from_keras_model(model)
tflite_model = converter.convert()
2021-12-14 12:18:07.073783: W tensorflow/python/util/util.cc:368] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them.
INFO:tensorflow:Assets written to: /tmp/tmpm1s3vkrd/assets
2021-12-14 12:18:07.876066: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:363] Ignored output_format.
2021-12-14 12:18:07.876112: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:366] Ignored drop_control_dependency.
WARNING:absl:Buffer deduplication procedure will be skipped when flatbuffer library is not properly loaded

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

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

converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.target_spec.supported_types = [tf.float16]

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

tflite_fp16_model = converter.convert()
tflite_model_fp16_file = tflite_models_dir/"mnist_model_quant_f16.tflite"
tflite_model_fp16_file.write_bytes(tflite_fp16_model)
INFO:tensorflow:Assets written to: /tmp/tmpvjt9l68i/assets
INFO:tensorflow:Assets written to: /tmp/tmpvjt9l68i/assets
2021-12-14 12:18:08.810262: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:363] Ignored output_format.
2021-12-14 12:18:08.810303: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:366] Ignored drop_control_dependency.
WARNING:absl:Buffer deduplication procedure will be skipped when flatbuffer library is not properly loaded
44384

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

ls -lh {tflite_models_dir}
total 128K
-rw-rw-r-- 1 kbuilder kbuilder 83K Dec 14 12:18 mnist_model.tflite
-rw-rw-r-- 1 kbuilder kbuilder 44K Dec 14 12:18 mnist_model_quant_f16.tflite

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

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

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

interpreter = tf.lite.Interpreter(model_path=str(tflite_model_file))
interpreter.allocate_tensors()
interpreter_fp16 = tf.lite.Interpreter(model_path=str(tflite_model_fp16_file))
interpreter_fp16.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_fp16.get_input_details()[0]["index"]
output_index = interpreter_fp16.get_output_details()[0]["index"]

interpreter_fp16.set_tensor(input_index, test_image)
interpreter_fp16.invoke()
predictions = interpreter_fp16.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.9654

كرر التقييم على نموذج Float16 الكمي للحصول على:

# NOTE: Colab runs on server CPUs. At the time of writing this, TensorFlow Lite
# doesn't have super optimized server CPU kernels. For this reason this may be
# slower than the above float interpreter. But for mobile CPUs, considerable
# speedup can be observed.
print(evaluate_model(interpreter_fp16))
0.9654

في هذا المثال ، قمت بتحديد نموذج لتعويم 16 دون اختلاف في الدقة.

من الممكن أيضًا تقييم نموذج fp16 الكمي على وحدة معالجة الرسومات. لأداء جميع العمليات الحسابية مع القيم الدقة انخفاض، ومن المؤكد أن خلق TfLiteGPUDelegateOptions البنية في التطبيق الخاص بك، ومجموعة precision_loss_allowed إلى 1 ، مثل هذا:

//Prepare GPU delegate.
const TfLiteGpuDelegateOptions options = {
  .metadata = NULL,
  .compile_options = {
    .precision_loss_allowed = 1,  // FP16
    .preferred_gl_object_type = TFLITE_GL_OBJECT_TYPE_FASTEST,
    .dynamic_batch_enabled = 0,   // Not fully functional yet
  },
};

يمكن العثور على وثائق مفصلة على مندوب TFLite GPU وكيفية استخدامها في التطبيق الخاص بك هنا