ดูบน TensorFlow.org | ทำงานใน Google Colab | ดูแหล่งที่มาบน GitHub | ดาวน์โหลดโน๊ตบุ๊ค |
ภาพรวม
การหาจำนวนเต็มเป็นกลยุทธ์การปรับให้เหมาะสมที่แปลงตัวเลขทศนิยม 32 บิต (เช่นน้ำหนักและเอาต์พุตการเปิดใช้งาน) เป็นตัวเลขจุดคงที่ 8 บิตที่ใกล้ที่สุด ผลนี้ในรูปแบบที่มีขนาดเล็กลงและเพิ่มความเร็วในการสรุปอิงซึ่งเป็นประโยชน์สำหรับอุปกรณ์ที่ใช้พลังงานต่ำเช่น ไมโครคอนโทรลเลอร์ รูปแบบข้อมูลนี้ถูกต้องตามจำนวนเต็มเท่านั้นเร่งเช่น ขอบ TPU
ในการกวดวิชานี้คุณจะฝึกรูปแบบ MNIST จากรอยขีดข่วนแปลงเป็นไฟล์ Tensorflow Lite และ quantize โดยใช้ ควอนโพสต์การฝึกอบรม สุดท้าย คุณจะตรวจสอบความถูกต้องของแบบจำลองที่แปลงแล้วและเปรียบเทียบกับแบบจำลองลูกลอยดั้งเดิม
จริงๆ แล้วคุณมีหลายทางเลือกว่าต้องการหาปริมาณของแบบจำลองเท่าใด ในบทช่วยสอนนี้ คุณจะดำเนินการ "การหาปริมาณเต็มจำนวนเต็ม" ซึ่งจะแปลงน้ำหนักและเอาต์พุตการเปิดใช้งานทั้งหมดเป็นข้อมูลจำนวนเต็ม 8 บิต ในขณะที่กลยุทธ์อื่นๆ อาจทำให้ข้อมูลจำนวนหนึ่งอยู่ในทศนิยม
ต้องการเรียนรู้เพิ่มเติมเกี่ยวกับกลยุทธ์ quantization ต่างๆอ่านเกี่ยวกับ การเพิ่มประสิทธิภาพรุ่น TensorFlow Lite
ติดตั้ง
ในการหาปริมาณทั้งเทนเซอร์อินพุตและเอาต์พุต เราจำเป็นต้องใช้ 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 Lite ใช้ TFLiteConverter
API และใช้องศาที่แตกต่างของควอน
ระวังว่าการควอนไทซ์บางรุ่นปล่อยให้ข้อมูลบางส่วนอยู่ในรูปแบบทศนิยม ดังนั้นส่วนต่อไปนี้จะแสดงแต่ละตัวเลือกด้วยจำนวนที่เพิ่มขึ้นของ quantization จนกว่าเราจะได้โมเดลที่เป็นข้อมูล 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 แต่ยังคงใช้ค่าทศนิยม 32 บิตสำหรับข้อมูลพารามิเตอร์ทั้งหมด
แปลงโดยใช้การหาปริมาณช่วงไดนามิก
ตอนนี้ขอเปิดใช้งานเริ่มต้น optimizations
ธง quantize พารามิเตอร์ถาวรทั้งหมด (เช่นน้ำหนัก):
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.
ขณะนี้โมเดลมีขนาดเล็กลงเล็กน้อยโดยมีน้ำหนักเชิงปริมาณ แต่ข้อมูลตัวแปรอื่นๆ ยังอยู่ในรูปแบบโฟลต
แปลงโดยใช้ float fallback quantization
เพื่อ quantize ข้อมูลตัวแปร (เช่นรูปแบบอินพุต / เอาต์พุตและตัวกลางระหว่างชั้น), คุณต้องให้ 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 Converter จะปล่อยให้เทนเซอร์อินพุตและเอาต์พุตของโมเดลเป็นแบบลอย:
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
นอกจากนี้ กระบวนการข้างต้นอาจทำให้การดำเนินการอยู่ในรูปแบบ float หาก TensorFlow Lite ไม่ได้รวมการใช้งานเชิงปริมาณสำหรับการดำเนินการนั้น กลยุทธ์นี้ช่วยให้การแปลงเสร็จสมบูรณ์ เพื่อให้คุณมีโมเดลที่เล็กกว่าและมีประสิทธิภาพมากกว่า แต่จะใช้งานไม่ได้กับฮาร์ดแวร์ที่เป็นจำนวนเต็มเท่านั้น (ops ทั้งหมดในโมเดล 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'>
ตอนนี้คุณมีจำนวนเต็ม quantized รุ่นที่ใช้จำนวนเต็มข้อมูลสำหรับรูปแบบของอินพุตและเอาต์พุตเทนเซอร์เพื่อให้มันเข้ากันได้กับฮาร์ดแวร์จำนวนเต็มเท่านั้นเช่น ขอบ 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 Lite 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 สำหรับ input และ output)
มาสร้างฟังก์ชันอื่นเพื่อพิมพ์คำทำนายของเรากัน:
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")
และทดสอบแบบจำลองเชิงปริมาณ:
test_model(tflite_model_quant_file, test_image_index, model_type="Quantized")
ประเมินรุ่นในภาพทั้งหมด
ตอนนี้ ให้เรียกใช้ทั้งสองรุ่นโดยใช้ภาพทดสอบทั้งหมดที่เราโหลดในตอนต้นของบทช่วยสอนนี้:
# 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)
ดังนั้นตอนนี้คุณจึงมีจำนวนเต็มในเชิงปริมาณของแบบจำลองโดยแทบไม่มีความแตกต่างในความแม่นยำเลย เมื่อเทียบกับแบบจำลองโฟลต
ต้องการเรียนรู้เพิ่มเติมเกี่ยวกับกลยุทธ์ quantization อื่น ๆ อ่านเกี่ยวกับ การเพิ่มประสิทธิภาพรุ่น TensorFlow Lite