כימות שלם לאחר אימון עם הפעלות int16

הצג באתר TensorFlow.org הפעל בגוגל קולאב צפה במקור ב-GitHub הורד מחברת

סקירה כללית

TensorFlow לייט תומך כעת המרת הפעלות לערכים שלמים 16 סיביים ו משקולות כדי 8 סיביות שלמות ערכים במהלך המרת מודל מ TensorFlow לפורמט החיץ שטוח של TensorFlow לייט. אנו מתייחסים למצב זה כ"מצב קוונטיזציה של 16x8". מצב זה יכול לשפר את הדיוק של המודל המקוונטי באופן משמעותי, כאשר הפעלות רגישות לכימות, תוך השגת הפחתה של כמעט פי 3-4 בגודל המודל. יתר על כן, ניתן לצרוך את המודל המכומתי במלואו על ידי מאיצי חומרה של מספרים שלמים בלבד.

כמה דוגמאות למודלים הנהנים ממצב זה של הקוונטיזציה שלאחר האימון כוללות:

  • רזולוציית על,
  • עיבוד אותות שמע כגון ביטול רעשים ויצירת אלומה,
  • ביטול רעשים בתמונה,
  • שחזור HDR מתמונה בודדת

במדריך זה, אתה מאמן מודל MNIST מאפס, בודק את הדיוק שלו ב-TensorFlow, ולאחר מכן ממירה את המודל ל-Tensorflow Lite flatbuffer באמצעות מצב זה. בסוף בודקים את הדיוק של הדגם שהומר ומשווים אותו לדגם 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)

png

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)

png

העריכו את המודלים

# 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 ללא הבדל ברמת הדיוק, אלא עם הגודל המופחת פי 3.

,

הצג באתר TensorFlow.org הפעל בגוגל קולאב צפה במקור ב-GitHub הורד מחברת

סקירה כללית

TensorFlow לייט תומך כעת המרת הפעלות לערכים שלמים 16 סיביים ו משקולות כדי 8 סיביות שלמות ערכים במהלך המרת מודל מ TensorFlow לפורמט החיץ שטוח של TensorFlow לייט. אנו מתייחסים למצב זה כ"מצב קוונטיזציה של 16x8". מצב זה יכול לשפר את הדיוק של המודל המקוונטי באופן משמעותי, כאשר הפעלות רגישות לכימות, תוך השגת הפחתה של כמעט פי 3-4 בגודל המודל. יתר על כן, ניתן לצרוך את המודל המכומתי במלואו על ידי מאיצי חומרה של מספרים שלמים בלבד.

כמה דוגמאות למודלים הנהנים ממצב זה של הקוונטיזציה שלאחר האימון כוללות:

  • רזולוציית על,
  • עיבוד אותות שמע כגון ביטול רעשים ויצירת אלומה,
  • ביטול רעשים בתמונה,
  • שחזור HDR מתמונה בודדת

במדריך זה, אתה מאמן מודל MNIST מאפס, בודק את הדיוק שלו ב-TensorFlow, ולאחר מכן ממירה את המודל ל-Tensorflow Lite flatbuffer באמצעות מצב זה. בסוף בודקים את הדיוק של הדגם שהומר ומשווים אותו לדגם 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)

png

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)

png

העריכו את המודלים

# 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 ללא הבדל ברמת הדיוק, אלא עם הגודל המופחת פי 3.