کمی سازی عدد صحیح پس از آموزش

مشاهده در TensorFlow.org در Google Colab اجرا شود مشاهده منبع در GitHub دانلود دفترچه یادداشت

بررسی اجمالی

کوانتیزاسیون عدد صحیح یک استراتژی بهینه سازی است که اعداد ممیز شناور 32 بیتی (مانند وزن ها و خروجی های فعال سازی) را به نزدیک ترین اعداد نقطه ثابت 8 بیتی تبدیل می کند. این نتایج در یک مدل کوچک تر و افزایش سرعت استنتاج، برای دستگاه های کم قدرت با ارزش است که مانند میکروکنترلرها . این فرمت داده نیز توسط مورد نیاز عدد صحیح فقط مانند شتاب دهنده لبه TPU .

در این آموزش، شما یک مدل MNIST از ابتدا آموزش، آن را تبدیل به یک فایل Tensorflow مطلب، و فرمول اندازهگیری آن با استفاده از کوانتیزاسیون پس از آموزش . در نهایت، دقت مدل تبدیل شده را بررسی کرده و آن را با مدل شناور اصلی مقایسه خواهید کرد.

شما در واقع چندین گزینه در مورد اینکه چقدر می خواهید یک مدل را کمی کنید دارید. در این آموزش، شما «کوانتیزه کردن اعداد صحیح کامل» را انجام می‌دهید، که تمام وزن‌ها و خروجی‌های فعال‌سازی را به داده‌های عدد صحیح 8 بیتی تبدیل می‌کند – در حالی که استراتژی‌های دیگر ممکن است مقداری از داده‌ها را در ممیز شناور باقی بگذارند.

برای کسب اطلاعات بیشتر در مورد استراتژی های تدریج مختلف، خواندن در مورد بهینه سازی مدل TensorFlow بازگشت به محتوا | .

برپایی

برای اینکه تانسورهای ورودی و خروجی را کمی کنیم، باید از APIهای اضافه شده در 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

یک مدل TensorFlow ایجاد کنید

ما از یک مدل ساده به شماره طبقه بندی از ساخت مجموعه داده MNIST .

این آموزش زیاد طول نمی کشد زیرا شما در حال آموزش مدل فقط برای 5 دوره هستید که با دقت حدود 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>

تبدیل به یک مدل TensorFlow Lite

در حال حاضر شما می توانید مدل آموزش دیده را به فرمت TensorFlow آرشیو با استفاده از تبدیل TFLiteConverter API، و اعمال درجات مختلفی از تدریج.

مراقب باشید که برخی از نسخه‌های کوانتیزاسیون، برخی از داده‌ها را در قالب شناور می‌گذارند. بنابراین بخش‌های زیر هر گزینه را با افزایش مقدار کوانتیزاسیون نشان می‌دهند، تا زمانی که مدلی به دست آوریم که کاملاً داده‌های int8 یا uint8 است. (توجه داشته باشید که ما در هر بخش تعدادی کد را کپی می کنیم تا بتوانید تمام مراحل کمی سازی هر گزینه را ببینید.)

اول، در اینجا یک مدل تبدیل شده بدون کوانتیزه آورده شده است:

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.

اکنون یک مدل TensorFlow Lite است، اما همچنان از مقادیر شناور ۳۲ بیتی برای تمام داده‌های پارامتر استفاده می‌کند.

با استفاده از کوانتیزه کردن محدوده دینامیکی تبدیل کنید

حالا اجازه دهید به طور پیش فرض فعال optimizations پرچم را به فرمول اندازهگیری تمام پارامترهای ثابت (مانند وزنه ها):

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.

اکنون مدل با وزن‌های کوانتیزه‌شده کمی کوچک‌تر است، اما سایر داده‌های متغیر هنوز در قالب شناور هستند.

تبدیل با استفاده از کوانتیزاسیون بازگشتی شناور

برای فرمول اندازهگیری داده های متغیر (مانند ورودی مدل / خروجی و واسطه بین لایه)، شما نیاز به ارائه یک RepresentativeDataset . این یک تابع مولد است که مجموعه ای از داده های ورودی را ارائه می دهد که به اندازه کافی بزرگ هستند تا مقادیر معمولی را نشان دهند. این به مبدل اجازه می دهد تا محدوده دینامیکی را برای همه داده های متغیر تخمین بزند. (نیازی نیست مجموعه داده در مقایسه با مجموعه داده آموزشی یا ارزیابی منحصر به فرد باشد.) برای پشتیبانی از ورودی های متعدد، هر نقطه داده نماینده یک لیست است و عناصر موجود در لیست بر اساس شاخص های خود به مدل داده می شوند.

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

اکنون همه وزن‌ها و داده‌های متغیر کوانتیزه شده‌اند و مدل در مقایسه با مدل اصلی TensorFlow Lite به‌طور قابل‌توجهی کوچک‌تر است.

با این حال، برای حفظ سازگاری با برنامه‌هایی که به طور سنتی از تانسورهای ورودی و خروجی مدل شناور استفاده می‌کنند، مبدل TensorFlow Lite تانسورهای ورودی و خروجی مدل را در حالت شناور قرار می‌دهد:

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

این معمولاً برای سازگاری خوب است، اما با دستگاه هایی که فقط عملیات مبتنی بر اعداد صحیح را انجام می دهند، مانند Edge TPU سازگار نخواهد بود.

علاوه بر این، اگر TensorFlow Lite شامل اجرای کوانتیزه‌شده برای آن عملیات نباشد، فرآیند فوق ممکن است عملیاتی را در قالب شناور بگذارد. این استراتژی اجازه می دهد تا تبدیل کامل شود، بنابراین شما یک مدل کوچکتر و کارآمدتر داشته باشید، اما باز هم، با سخت افزار فقط عدد صحیح سازگار نخواهد بود. (همه عملیات در این مدل MNIST یک پیاده سازی کوانتیزه شده دارند.)

بنابراین برای اطمینان از یک مدل فقط عدد صحیح سرتاسر، به چند پارامتر دیگر نیاز دارید...

با استفاده از کوانتیزاسیون فقط عدد صحیح تبدیل کنید

برای کمی کردن تانسورهای ورودی و خروجی و ایجاد خطا در مبدل در صورت مواجهه با عملیاتی که نمی تواند کوانتیزه کند، مدل را دوباره با چند پارامتر اضافی تبدیل کنید:

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.

کوانتیزاسیون داخلی مانند بالا باقی می ماند، اما می توانید ببینید تانسورهای ورودی و خروجی اکنون فرمت صحیح هستند:

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

حالا شما یک مدل صحیح کوانتیزه که با استفاده از عدد صحیح داده ها برای ورودی و خروجی تانسورها مدل، پس از آن سازگار با سخت افزار تنها عدد صحیح-مانند لبه TPU .

مدل ها را به صورت فایل ذخیره کنید

شما یک نیاز .tflite فایل به استقرار مدل خود را بر روی دستگاه های دیگر. بنابراین بیایید مدل‌های تبدیل شده را در فایل‌ها ذخیره کنیم و زمانی که استنتاج‌های زیر را اجرا می‌کنیم، آن‌ها را بارگذاری کنیم.

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 را اجرا کنید

در حال حاضر ما با استفاده از استنتاج TensorFlow سبک اجرا Interpreter برای مقایسه دقت مدل.

ابتدا به تابعی نیاز داریم که استنتاج را با یک مدل و تصاویر داده شده اجرا کند و سپس پیش‌بینی‌ها را برمی‌گرداند:

# 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

مدل ها را روی یک تصویر تست کنید

اکنون عملکرد مدل شناور و مدل کوانتیزه را با هم مقایسه می کنیم:

  • tflite_model_file مدل اصلی TensorFlow Lite با داده ممیز شناور است.
  • tflite_model_quant_file آخرین مدل ما با استفاده از کوانتیزاسیون تنها عدد صحیح-تبدیل شده است (آن را با استفاده از داده uint8 برای ورودی و خروجی).

بیایید یک تابع دیگر برای چاپ پیش بینی های خود ایجاد کنیم:

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)

حالا مدل شناور را تست کنید:

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

png

و مدل کوانتیزه را تست کنید:

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

png

مدل ها را روی همه تصاویر ارزیابی کنید

حالا بیایید هر دو مدل را با استفاده از تمام تصاویر آزمایشی که در ابتدای این آموزش بارگذاری کردیم اجرا کنیم:

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

مدل شناور را ارزیابی کنید:

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

مدل کوانتیزه را ارزیابی کنید:

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

بنابراین شما اکنون یک مدل را با یک عدد صحیح کوانتیزه کرده اید که تقریباً هیچ تفاوتی در دقت در مقایسه با مدل شناور ندارد.

برای کسب اطلاعات بیشتر در مورد دیگر استراتژی های تدریج، به عنوان خوانده شده در مورد بهینه سازی مدل TensorFlow بازگشت به محتوا | .