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

TensorFlow Lite Converter คืออะไร

android gpu deligate demo.  Credit https://www.tensorflow.org/lite/performance/gpu
android gpu deligate demo. Credit https://www.tensorflow.org/lite/performance/gpu

TensorFlow Lite Converter จะแปลงโมเดล TensorFlow ไปเป็นไฟล์ TensorFlow Lite FlatBuffer (ไฟล์นามสกุล .tflite) โดยรองรับโมเดลต้นทางในรูปแบบ SavedModel, tf.keras, และ Concrete Function

เราจะนำไฟล์ FlatBuffer ของ TensorFlow Lite ไป Deploy บนอุปกรณ์ที่ต้องการ แล้วรันด้วย TensorFlow Lite Inteprter สำหรับ Platform นั้น ๆ ดังกระบวนการด้านล่าง

The TensorFlow Lite converter takes a TensorFlow model and generates a TensorFlow Lite FlatBuffer file (.tflite). The converter supports SavedModel directories, tf.keras models, and concrete functions. Credit https://www.tensorflow.org/lite/convert
The TensorFlow Lite converter takes a TensorFlow model and generates a TensorFlow Lite FlatBuffer file (.tflite). The converter supports SavedModel directories, tf.keras models, and concrete functions. Credit https://www.tensorflow.org/lite/convert

Converting models

เราควรเรียกใช้ TensorFlow Lite Converter ด้วย Python API จากภายในโปรแกรม ซึ่งจะทำการแปลงโมเดลทำได้ง่าย และเป็นส่วนหนึ่งของ Model Deveopment Pipeline

การใช้ Python API มีข้อดีคือช่วยให้เรารู้ปัญหาเรื่อง Compatibility แต่เนิ่น ๆ ลดปัญหาในระยะยาว

และนอกจากนี้ เรายังสามารถใช้ Command Line Tools ในการ Convert โมเดลที่ไม่ซับซ้อนมากได้

เรามาเริ่มกันเลยดีกว่า

Open In Colab
In [0]:
#@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

In [0]:
# !pip3 uninstall tensorflow
# !pip3 install tf-nightly

ใน ep นี้ เราจะใช้ TensorFlow 2 ด้วยคำสั่ง Magic %tensorflow_version 2.x (สำหรับ Google Colab)

In [0]:
try:
    %tensorflow_version 2.x
except:
    pass

1. Import

1.1 Import Library

Import Library ที่เกี่ยวข้อง และ Print เลข Version

In [0]:
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

In [0]:
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

In [0]:
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

In [0]:
def format_image(image, label):
    image = tf.image.resize(image, IMAGE_SIZE) / 255.0
    return  image, label

กำหนดขนาด Batch Size ให้ DataLoader

In [0]:
BATCH_SIZE = 32 #@param {type:"integer"}

Shuffle สับไพ่ข้อมูล และแบ่งข้อมูลเป็น Batch ตาม Batch Size ที่กำหนดด้านบน

In [0]:
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

In [0]:
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 สุดท้ายที่สร้างใหม่ก็พอ เพื่อประหยัดเวลา

In [0]:
do_fine_tuning = False #@param {type:"boolean"}

3.2 Pre-trained Model

ใช้ TensorFlow Hub โหลดโมเดล Pre-trained ที่เลือกด้านบนขึ้นมา กำหนด Hyperparameter ของโมเดล เช่น Input / Output Shape, Freeze โมเดลหรือไม่

In [0]:
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

In [0]:
print("Building model with", MODULE_HANDLE)

model = tf.keras.Sequential([
        feature_extractor,
        tf.keras.layers.Dense(num_classes, activation='softmax')
])
In [0]:
model.summary()
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
keras_layer (KerasLayer)     (None, 1280)              2257984   
_________________________________________________________________
dense (Dense)                (None, 2)                 2562      
=================================================================
Total params: 2,260,546
Trainable params: 2,562
Non-trainable params: 2,257,984
_________________________________________________________________

3.4 Unfreeze Layers

ในกรณีต้องการ Fine-Tuning เราสามารถเลือกได้ว่าจะ Unfreeze ถึง Layer ไหน เพื่อเทรนจาก Layer ท้ายสุดมาหน้า

In [0]:
#@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

ในเคสนี้ ถ้า Fine-Tuning เราจะใช้ SGD ส่วนถ้าไม่ เราจะใช้ Adam Optimizer

In [0]:
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

In [0]:
EPOCHS = 5

hist = model.fit(train_batches,
                 epochs=EPOCHS,
                 validation_data=validation_batches)

5. Export the Model

Export โมเดลที่เทรนเสร็จเรียบร้อยแล้ว ในรูปแบบ ไฟล์ SavedModel Format

In [0]:
CATS_VS_DOGS_SAVED_MODEL = "exp_saved_model"
In [0]:
tf.saved_model.save(model, CATS_VS_DOGS_SAVED_MODEL)

ดูรายละเอียดของโมเดล ในไฟล์ SavedModel

In [0]:
%%bash -s $CATS_VS_DOGS_SAVED_MODEL
saved_model_cli show --dir $1 --tag_set serve --signature_def serving_default

ลองโหลดโมเดลขึ้นมาดู

In [0]:
loaded = tf.saved_model.load(CATS_VS_DOGS_SAVED_MODEL)

ดู Signature Input / Output Shape

In [0]:
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 ไว้ด้านบน

In [0]:
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)

In [0]:
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 ต่อไป

In [0]:
def representative_data_gen():
    for input_value, _ in test_batches.take(100):
        yield [input_value]
In [0]:
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

In [0]:
converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]

6.4 Convert โมเดล

Convert โมเดลเป็นไฟล์ tflite แล้ว Save ลง Disk

In [0]:
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 ขึ้นมา

In [0]:
# 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

In [0]:
# 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

In [0]:
#@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)
In [0]:
#@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

In [0]:
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 หลาย ๆ ไฟล์ได้พร้อมกัน

In [0]:
try:
    from google.colab import files
    files.download('converted_model.tflite')
    files.download('labels.txt')
except:
    pass

9. Credit

In [0]:
 

แชร์ให้เพื่อน:

Keng Surapong on FacebookKeng Surapong on GithubKeng Surapong on Linkedin
Keng Surapong
Project Manager at Bua Labs
The ultimate test of your knowledge is your capacity to convey it to another.

Published by Keng Surapong

The ultimate test of your knowledge is your capacity to convey it to another.

Enable Notifications    Ok No thanks