Lượng tử hóa số nguyên sau đào tạo

Xem trên TensorFlow.org Chạy trong Google Colab Xem nguồn trên GitHub Tải xuống sổ ghi chép

Tổng quat

Lượng tử hóa số nguyên là một chiến lược tối ưu hóa chuyển đổi số dấu phẩy động 32 bit (chẳng hạn như trọng số và đầu ra kích hoạt) thành số điểm cố định 8 bit gần nhất. Đây kết quả trong một mô hình nhỏ hơn và tăng tốc độ suy luận, mà rất có giá trị cho các thiết bị tiết kiệm năng lượng như vi điều khiển . Định dạng dữ liệu này cũng được yêu cầu của số nguyên chỉ tăng tốc nói như Cạnh TPU .

Trong hướng dẫn này, bạn sẽ đào tạo một mô hình MNIST từ đầu, chuyển đổi nó thành một file Tensorflow Lite, và quantize nó sử dụng lượng tử hóa sau đào tạo . Cuối cùng, bạn sẽ kiểm tra độ chính xác của mô hình đã chuyển đổi và so sánh nó với mô hình float ban đầu.

Bạn thực sự có một số tùy chọn về mức độ bạn muốn lượng tử hóa một mô hình. Trong hướng dẫn này, bạn sẽ thực hiện "lượng tử hóa số nguyên đầy đủ", chuyển đổi tất cả các trọng số và đầu ra kích hoạt thành dữ liệu số nguyên 8 bit — trong khi các chiến lược khác có thể để lại một số lượng dữ liệu ở dạng dấu phẩy động.

Để tìm hiểu thêm về chiến lược lượng tử khác nhau, đọc về mô hình tối ưu hóa TensorFlow Lite .

Thành lập

Để lượng tử hóa cả tenxơ đầu vào và đầu ra, chúng ta cần sử dụng các API được thêm vào 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

Tạo mô hình TensorFlow

Chúng tôi sẽ xây dựng một mô hình đơn giản đến các số classify từ dataset MNIST .

Quá trình đào tạo này sẽ không mất nhiều thời gian vì bạn đang đào tạo mô hình chỉ trong 5 kỷ nguyên, đào tạo với độ chính xác khoảng ~ 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>

Chuyển đổi sang mô hình TensorFlow Lite

Bây giờ bạn có thể chuyển đổi các mô hình đào tạo để định dạng TensorFlow Lite sử dụng TFLiteConverter API, và áp dụng các mức độ khác nhau của lượng tử.

Hãy lưu ý rằng một số phiên bản lượng tử hóa để lại một số dữ liệu ở định dạng float. Vì vậy, các phần sau hiển thị từng tùy chọn với số lượng lượng tử hóa ngày càng tăng, cho đến khi chúng ta nhận được một mô hình hoàn toàn là dữ liệu int8 hoặc uint8. (Lưu ý rằng chúng tôi sao chép một số mã trong mỗi phần để bạn có thể xem tất cả các bước lượng tử hóa cho mỗi tùy chọn.)

Đầu tiên, đây là một mô hình được chuyển đổi không có lượng tử hóa:

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.

Bây giờ nó là một mô hình TensorFlow Lite, nhưng nó vẫn sử dụng các giá trị float 32-bit cho tất cả dữ liệu tham số.

Chuyển đổi bằng cách sử dụng lượng tử hóa dải động

Bây giờ chúng ta hãy cho phép mặc định optimizations cờ để quantize tất cả các thông số cố định (chẳng hạn như trọng lượng):

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.

Mô hình hiện nhỏ hơn một chút với các trọng số lượng tử hóa, nhưng dữ liệu biến khác vẫn ở định dạng float.

Chuyển đổi bằng cách sử dụng lượng tử hóa dự phòng float

Để quantize dữ liệu biến (chẳng hạn như mô hình đầu vào / đầu ra và trung gian giữa các lớp), bạn cần phải cung cấp một RepresentativeDataset . Đây là một hàm trình tạo cung cấp một tập hợp dữ liệu đầu vào đủ lớn để đại diện cho các giá trị điển hình. Nó cho phép bộ chuyển đổi ước tính phạm vi động cho tất cả dữ liệu biến đổi. (Tập dữ liệu không cần phải là duy nhất so với tập dữ liệu đào tạo hoặc đánh giá.) Để hỗ trợ nhiều đầu vào, mỗi điểm dữ liệu đại diện là một danh sách và các phần tử trong danh sách được cung cấp cho mô hình theo các chỉ số của chúng.

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

Giờ đây, tất cả các trọng số và dữ liệu biến đổi đều được lượng tử hóa và mô hình nhỏ hơn đáng kể so với mô hình TensorFlow Lite ban đầu.

Tuy nhiên, để duy trì khả năng tương thích với các ứng dụng truyền thống sử dụng bộ căng đầu vào và đầu ra của mô hình float, Bộ chuyển đổi TensorFlow Lite để các bộ căng đầu vào và đầu ra của mô hình trong 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'>

Điều đó thường tốt cho khả năng tương thích, nhưng nó sẽ không tương thích với các thiết bị chỉ thực hiện các hoạt động dựa trên số nguyên, chẳng hạn như Edge TPU.

Ngoài ra, quy trình trên có thể để lại một hoạt động ở định dạng float nếu TensorFlow Lite không bao gồm triển khai lượng tử hóa cho hoạt động đó. Chiến lược này cho phép hoàn tất quá trình chuyển đổi để bạn có một mô hình nhỏ hơn và hiệu quả hơn, nhưng một lần nữa, nó sẽ không tương thích với phần cứng chỉ có số nguyên. (Tất cả các hoạt động trong mô hình MNIST này đều có triển khai lượng tử hóa.)

Vì vậy, để đảm bảo mô hình chỉ số nguyên end-to-end, bạn cần thêm một vài tham số ...

Chuyển đổi bằng cách sử dụng lượng tử hóa chỉ số nguyên

Để lượng tử hóa các tensors đầu vào và đầu ra và làm cho bộ chuyển đổi gặp lỗi nếu nó gặp phải một hoạt động mà nó không thể lượng tử hóa, hãy chuyển đổi lại mô hình với một số tham số bổ sung:

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.

Lượng tử hóa bên trong vẫn giống như trên, nhưng bạn có thể thấy các tenxơ đầu vào và đầu ra bây giờ là định dạng số nguyên:

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

Bây giờ bạn có một mô hình nguyên lượng tử hóa mà sử dụng nguyên liệu cho đầu vào và đầu ra tensors của mô hình, do đó, nó tương thích với phần cứng số nguyên chỉ như Cạnh TPU .

Lưu các mô hình dưới dạng tệp

Bạn sẽ cần một .tflite tập tin để triển khai mô hình của bạn trên các thiết bị khác. Vì vậy, hãy lưu các mô hình đã chuyển đổi thành tệp và sau đó tải chúng khi chúng tôi chạy các suy luận bên dưới.

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

Chạy các mô hình TensorFlow Lite

Bây giờ chúng ta sẽ chạy kết luận bằng cách sử dụng TensorFlow Lite Interpreter để so sánh độ chính xác mô hình.

Đầu tiên, chúng ta cần một hàm chạy suy luận với một mô hình và hình ảnh nhất định, sau đó trả về các dự đoán:

# 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

Kiểm tra các mô hình trên một hình ảnh

Bây giờ chúng ta sẽ so sánh hiệu suất của mô hình float và mô hình lượng tử hóa:

  • tflite_model_file là bản gốc mô hình TensorFlow Lite với dữ liệu dấu chấm động.
  • tflite_model_quant_file là mô hình cuối cùng chúng tôi chuyển đổi sử dụng lượng tử hóa số nguyên chỉ (nó sử dụng dữ liệu uint8 cho đầu vào và đầu ra).

Hãy tạo một hàm khác để in các dự đoán của chúng tôi:

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)

Bây giờ hãy kiểm tra mô hình float:

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

png

Và kiểm tra mô hình lượng tử hóa:

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

png

Đánh giá các mô hình trên tất cả các hình ảnh

Bây giờ, hãy chạy cả hai mô hình bằng cách sử dụng tất cả các hình ảnh thử nghiệm mà chúng tôi đã tải ở đầu hướng dẫn này:

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

Đánh giá mô hình float:

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

Đánh giá mô hình lượng tử hóa:

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

Vì vậy, bây giờ bạn có một số nguyên được lượng tử hóa một mô hình mà hầu như không có sự khác biệt về độ chính xác, so với mô hình float.

Để tìm hiểu thêm về chiến lược lượng tử khác, hãy đọc về mô hình tối ưu hóa TensorFlow Lite .