TensorFlow Lite Converter เป็นตัวแปลงโมเดล TensorFlow ตัวเต็ม ให้ย่อลงมาเป็นโมเดลขนาดเล็ก ที่ทำงานได้รวดเร็ว สำหรับรันกับ Interpreter บนอุปกรณ์ Edge Device ที่มี Resource จำกัด ด้วยเทคนิค Quantization โดยพิจารณาจาก Hardware ปลายทาง ที่จะนำโมเดลไป Deploy เช่น อุปกรณ์ IoT Device, มือถือ Mobile, Microcontroller ต่าง ๆ
TensorFlow Lite Converter คืออะไร

TensorFlow Lite Converter จะแปลงโมเดล TensorFlow ไปเป็นไฟล์ TensorFlow Lite FlatBuffer (ไฟล์นามสกุล .tflite) โดยรองรับโมเดลต้นทางในรูปแบบ SavedModel, tf.keras, และ Concrete Function
เราจะนำไฟล์ FlatBuffer ของ TensorFlow Lite ไป Deploy บนอุปกรณ์ที่ต้องการ แล้วรันด้วย TensorFlow Lite Inteprter สำหรับ Platform นั้น ๆ ดังกระบวนการด้านล่าง

Converting models
เราควรเรียกใช้ TensorFlow Lite Converter ด้วย Python API จากภายในโปรแกรม ซึ่งจะทำการแปลงโมเดลทำได้ง่าย และเป็นส่วนหนึ่งของ Model Deveopment Pipeline
การใช้ Python API มีข้อดีคือช่วยให้เรารู้ปัญหาเรื่อง Compatibility แต่เนิ่น ๆ ลดปัญหาในระยะยาว
และนอกจากนี้ เรายังสามารถใช้ Command Line Tools ในการ Convert โมเดลที่ไม่ซับซ้อนมากได้
เรามาเริ่มกันเลยดีกว่า
Copyright 2018 The TensorFlow Authors.¶
#@title Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
0. Setup¶
Uninstall TensorFlow เวอร์ชันที่อยู่ใน Colab, Install Version nightly แล้ว Restart Runtime
# !pip3 uninstall tensorflow
# !pip3 install tf-nightly
ใน ep นี้ เราจะใช้ TensorFlow 2 ด้วยคำสั่ง Magic %tensorflow_version 2.x (สำหรับ Google Colab)
try:
%tensorflow_version 2.x
except:
pass
1. Import¶
1.1 Import Library¶
Import Library ที่เกี่ยวข้อง และ Print เลข Version
import numpy as np
import matplotlib.pylab as plt
import tensorflow as tf
import tensorflow_hub as hub
import tensorflow_datasets as tfds
tfds.disable_progress_bar()
from tqdm import tqdm
print("\u2022 Using TensorFlow Version:", tf.__version__)
print("\u2022 Using TensorFlow Hub Version: ", hub.__version__)
print('\u2022 GPU Device Found.' if tf.test.is_gpu_available() else '\u2022 GPU Device Not Found. Running on CPU')
1.2 เลือกโมดูล¶
เลือกโมดูล TensorFlow 2 ที่ต้องการจาก TensorFlow Hub
module_selection = ("mobilenet_v2", 224, 1280) #@param ["(\"mobilenet_v2\", 224, 1280)", "(\"inception_v3\", 299, 2048)"] {type:"raw", allow-input: true}
handle_base, pixels, FV_SIZE = module_selection
MODULE_HANDLE ="https://tfhub.dev/google/tf2-preview/{}/feature_vector/4".format(handle_base)
IMAGE_SIZE = (pixels, pixels)
print("Using {} with input size {} and output dimension {}".format(MODULE_HANDLE, IMAGE_SIZE, FV_SIZE))
2. Dataset¶
2.1 Split Data to Training / Validation / Test Set¶
เราจะใช้ TensorFlow Dataset tfds
โหลดข้อมูล Cats and Dogs Dataset (ที่คล้าย ๆ กับ Pets Dataset แต่ง่ายกว่า) ขึ้นมา แล้ว Split Training / Validation / Test Set ด้วยสัดส่วน 80/10/10
splits = tfds.Split.ALL.subsplit(weighted=(80, 10, 10))
splits, info = tfds.load('cats_vs_dogs', with_info=True, as_supervised=True, split = splits)
(train_examples, validation_examples, test_examples) = splits
num_examples = info.splits['train'].num_examples
num_classes = info.features['label'].num_classes
num_examples, num_classes
จะได้ Dataset ที่มีข้อมูล 23262 ตัวอย่าง มี 2 Class
2.2 Transform¶
ประกาศฟังก์ชัน ใช้ tf.image
เพื่อแปลงรูปใน Dataset ให้อยู่ในรูปแบบที่โมเดลต้องการ ในที่นี้คือ Resize เป็นขนาดที่กำหนด และ Rescale ค่าสี จาก 0-255 หาร 255 ให้เป็น Float 0-1
def format_image(image, label):
image = tf.image.resize(image, IMAGE_SIZE) / 255.0
return image, label
กำหนดขนาด Batch Size ให้ DataLoader
BATCH_SIZE = 32 #@param {type:"integer"}
Shuffle สับไพ่ข้อมูล และแบ่งข้อมูลเป็น Batch ตาม Batch Size ที่กำหนดด้านบน
train_batches = train_examples.shuffle(num_examples // 4).map(format_image).batch(BATCH_SIZE).prefetch(1)
validation_batches = validation_examples.map(format_image).batch(BATCH_SIZE).prefetch(1)
test_batches = test_examples.map(format_image).batch(1)
ดู shape ของข้อมูล 1 Batch จะได้ Batch Size = 32, Wigth = 224, Height = 224, Channels = 3
for image_batch, label_batch in train_batches.take(1):
pass
image_batch.shape
3. Model¶
เราทำ Transfer Learning ด้วยการสร้าง 1 Dense Layer จาก Linear Classifier เป็น Head ต่อจาก feature_extractor_layer ของโมเดลที่โหลดมาจาก TensorFlow Hub
3.1 Fine-Tuning¶
เราสามารถกำหนดได้ว่า จะเทรน Fune-Tuning ทั้งโมเดลเลยหรือไม่ เพื่อเพิ่มความแม่นยำ หรือเทรนแค่ Head Layer สุดท้ายที่สร้างใหม่ก็พอ เพื่อประหยัดเวลา
do_fine_tuning = False #@param {type:"boolean"}
3.2 Pre-trained Model¶
ใช้ TensorFlow Hub โหลดโมเดล Pre-trained ที่เลือกด้านบนขึ้นมา กำหนด Hyperparameter ของโมเดล เช่น Input / Output Shape, Freeze โมเดลหรือไม่
feature_extractor = hub.KerasLayer(MODULE_HANDLE,
input_shape=IMAGE_SIZE + (3,),
output_shape=[FV_SIZE],
trainable=do_fine_tuning)
3.3 Pre-trained Feature Extractor + Custom Head¶
สร้าง Head ด้วย 1 Dense Layer ที่มี Activation Function เป็น Softmax
print("Building model with", MODULE_HANDLE)
model = tf.keras.Sequential([
feature_extractor,
tf.keras.layers.Dense(num_classes, activation='softmax')
])
model.summary()
3.4 Unfreeze Layers¶
ในกรณีต้องการ Fine-Tuning เราสามารถเลือกได้ว่าจะ Unfreeze ถึง Layer ไหน เพื่อเทรนจาก Layer ท้ายสุดมาหน้า
#@title (Optional) Unfreeze some layers
NUM_LAYERS = 10 #@param {type:"slider", min:1, max:50, step:1}
if do_fine_tuning:
feature_extractor.trainable = True
for layer in model.layers[-NUM_LAYERS:]:
layer.trainable = True
else:
feature_extractor.trainable = False
3.5 Compile Model¶
if do_fine_tuning:
model.compile(optimizer=tf.keras.optimizers.SGD(lr=0.002, momentum=0.9),
loss=tf.keras.losses.SparseCategoricalCrossentropy(),
metrics=['accuracy'])
else:
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
4. Training the Model¶
เทรนไป 5 Epoch
EPOCHS = 5
hist = model.fit(train_batches,
epochs=EPOCHS,
validation_data=validation_batches)
5. Export the Model¶
Export โมเดลที่เทรนเสร็จเรียบร้อยแล้ว ในรูปแบบ ไฟล์ SavedModel Format
CATS_VS_DOGS_SAVED_MODEL = "exp_saved_model"
tf.saved_model.save(model, CATS_VS_DOGS_SAVED_MODEL)
ดูรายละเอียดของโมเดล ในไฟล์ SavedModel
%%bash -s $CATS_VS_DOGS_SAVED_MODEL
saved_model_cli show --dir $1 --tag_set serve --signature_def serving_default
ลองโหลดโมเดลขึ้นมาดู
loaded = tf.saved_model.load(CATS_VS_DOGS_SAVED_MODEL)
ดู Signature Input / Output Shape
print(list(loaded.signatures.keys()))
infer = loaded.signatures["serving_default"]
print(infer.structured_input_signature)
print(infer.structured_outputs)
6. Convert ไฟล์โมเดลด้วย TFLite Converter¶
ใช้ TFLiteConverter โหลดไฟล์โมเดล SavedModel ที่เรา Export ไว้ด้านบน
converter = tf.lite.TFLiteConverter.from_saved_model(CATS_VS_DOGS_SAVED_MODEL)
converter.experimental_new_converter = True
6.1 Post-Training Quantization¶
เราจะ Optimize โมเดล ด้วยการทำ Quantize ลดจำนวน Bit ของ Parameter ในโมเดลลง เพื่อให้โมเดลมีขนาดเล็กลง และทำงานได้เร็วขึ้น จะอธิบายต่อไป ในเรื่อง Quantization
เราสามารถเลือกได้ว่า จะให้ Optimize เพื่อ Latency, Size หรือ ทั้งสองอย่าง (Default)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
6.2 Post-Training Integer Quantization¶
นอกเหนือจาก Parameter เราสามารถ Quantize ข้อมูล และ Activation ได้อีก โดยการให้ชุดข้อมูลตัวอย่าง รันผ่านโมเดล เพื่อเก็บสถิติ Representative Dataset วัด Dynamic Range ของข้อมูล และ Activation สร้าง Input Data Generator เพื่อส่งให้กับ Converter ใช้ในการทำ Integer Quantization ต่อไป
def representative_data_gen():
for input_value, _ in test_batches.take(100):
yield [input_value]
converter.representative_dataset = representative_data_gen
โมเดลที่แปลงแล้ว จะยังรับ Input / Output เป็น Float เหมือนเดิมเพื่อความสะดวก จะได้ไม่ต้องแก้โปรแกรม
และ ในโมเดล ถ้า Ops ไหน ที่ไม่มี Quantized Implementation ก็จะใช้เป็น Floating Point Implementation เหมือนเดิม แบบนี้จะทำให้การ Convert โมเดลทำได้อย่างราบรื่น แต่ก็จะจำกัดให้รันได้เฉพาะ Hardware ที่รองรับ Floating Point
6.3 Full Integer Quantization¶
ถ้าเราต้องการให้ Converter แปลงโมเดล ให้เป็น Integer อย่างเดียวเท่านั้น สามารถระบุได้ดังนี้ โดยถ้าเจอ Ops ที่ไม่สามารถ Convert ได้ก็จะ Error
converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]
6.4 Convert โมเดล¶
Convert โมเดลเป็นไฟล์ tflite แล้ว Save ลง Disk
tflite_model = converter.convert()
tflite_model_file = 'converted_model.tflite'
with open(tflite_model_file, "wb") as f:
f.write(tflite_model)
7. Test ไฟล์ tflite ด้วย TFLite Intepreter¶
ใช้ TFLite Intepreter โหลดไฟล์ tflite ขึ้นมา
# Load TFLite model and allocate tensors.
interpreter = tf.lite.Interpreter(model_path=tflite_model_file)
interpreter.allocate_tensors()
input_index = interpreter.get_input_details()[0]["index"]
output_index = interpreter.get_output_details()[0]["index"]
สุ่มเลือกรูปจาก Test Set มาให้โมเดล ทำ Inference
# Gather results for the randomly sampled test images
predictions = []
test_labels, test_imgs = [], []
for img, label in tqdm(test_batches.take(10)):
interpreter.set_tensor(input_index, img)
interpreter.invoke()
predictions.append(interpreter.get_tensor(output_index))
test_labels.append(label.numpy()[0])
test_imgs.append(img)
นำผลลัพธ์ที่ได้ มาพล็อตแสดงรูป เปรียบเทียบ label และ prediction
#@title Utility functions for plotting
# Utilities for plotting
class_names = ['cat', 'dog']
def plot_image(i, predictions_array, true_label, img):
predictions_array, true_label, img = predictions_array[i], true_label[i], img[i]
plt.grid(False)
plt.xticks([])
plt.yticks([])
img = np.squeeze(img)
plt.imshow(img, cmap=plt.cm.binary)
predicted_label = np.argmax(predictions_array)
if predicted_label == true_label:
color = 'green'
else:
color = 'red'
plt.xlabel("{} {:2.0f}% ({})".format(class_names[predicted_label],
100*np.max(predictions_array),
class_names[true_label]), color=color)
#@title Visualize the outputs { run: "auto" }
index = 5 #@param {type:"slider", min:0, max:9, step:1}
plt.figure(figsize=(6,3))
plt.subplot(1,2,1)
plot_image(index, predictions, test_labels, test_imgs)
plt.show()
สร้างไฟล์เก็บ Label
labels = ['cat', 'dog']
with open('labels.txt', 'w') as f:
f.write('\n'.join(labels))
8. Save และ Download ไฟล์ tflite¶
Save ไฟล์ และ Download โมเดล และ Label มาที่ Local Disk เพื่อนำไปใส่ Device ที่ต้องการต่อไป
หมายเหตุ: เราอาจจะต้อง กดอนุญาตให้ Web Browser สามารถ Download หลาย ๆ ไฟล์ได้พร้อมกัน
try:
from google.colab import files
files.download('converted_model.tflite')
files.download('labels.txt')
except:
pass
9. Credit¶