目的
前回まで
このときに使ったTensorFlow Lite モデル(TF-Lite
モデル)はmetadataが追加されたモデルを使用した(
TensorFlow Hubから入手したモデル)。
今回はTF-Lite モデルにmetadataを自分で追加して、TensorFlow Lite Support Task
Library(TF Lite Support Task Library)で推論することをやってみる。
Metadataとは?
既にあるTF-Lite モデルに補足の情報を追加することができる。
追加できる情報
以下の情報が追加できる。
- モデル全体の説明(概要、著作権、作成者などの情報)
- 入力の説明(画像フォーマット、正規化、入力幅の情報)
- 出力の説明とラベル(説明やラベルとのマッピング)
Metaデータを追加する利点
-
配布するモデルファイルの作成者、著作権を明示できる。
TF-Lite
モデルは端末にダウンロードが前提。
公開・非公開に関わらず情報があるとありがたい。
-
TF Lite Support Task
Libraryを使うと入力、出力情報から必要な前・後処理を行ってくれる。
- 前処理: リサイズ、正規化、モデルのInput(Float, Int)
- 後処理: ラベルとのマッピング
-
推論コードのラッパーを自動生成してくれる。
TensorFlowのドキュメント「メタデータを使用してモデルインターフェイスを生成する」
(まだよく理解していないので後で試す)
Medadataを追加するには?
TF Lite SupportのAPI(Python)を利用する。
Object detectionモデルにmetadataを組み込む
このモデルはFloatモデルで、InputもFloat32である。
なお、Metadataを追加しない状態でTF Lite Support Task
Libraryで推論するとエラーとなってしまう。
これは、TF Lite Support Task
LibraryがInputの正規化するための情報が無いため。
$ ./bazel-bin/tensorflow_lite_support/examples/task/vision/pi/object_detector_capture \
--model_path=/home/pi/ssdlite_mobiledet_cpu.tflite \
--num_thread=4 --score_threshold=0.5
Detection failed: Input tensor has type kTfLiteFloat32: it requires specifying NormalizationOptions metadata to preprocess input images.
モデルにmetadataを追加して推論ができることまで確認する。
参考のコード・サンプル
Metadetaを追加するライブラリはここで実装。
MetadataはFlatBuffersのスキーマで定義。
よく使われるモデルのラッパーの定義。
(Image classification、Object detection、Image segmentation)
使い方はドキュメントはテストコードを参照。
作成したサンプル
Object detectionモデルにmetadataを書き込むサンプルを作成した。
前回のtflite-supportのforkリポジトリに追加。
実装
Pythonでの実装の概要を説明。
必要なimport
from tensorflow_lite_support.metadata import metadata_schema_py_generated as _metadata_fb
from tensorflow_lite_support.metadata.python.metadata_writers import metadata_info
from tensorflow_lite_support.metadata.python.metadata_writers import object_detector
from tensorflow_lite_support.metadata.python.metadata_writers import writer_utils
サンプルではMetadataPopulatorForObjectDetectorクラスの_create_metadataメソッドでmetadataを生成。
# Creates model info.
self.general_md = metadata_info.GeneralMd(
name=self.model_info.name,
version=self.model_info.version,
description=("Identify which of a known set of objects might be present "
"and provide information about their positions within the "
"given image or a video stream."),
author="Test",
licenses=("Apache License. Version 2.0 "
"http://www.apache.org/licenses/LICENSE-2.0.")
)
# Load model to buffer.
self.model_buffer = self._load_file(self.model_file_path)
# Creates input info.
self.input_md = metadata_info.InputImageTensorMd(
name="normalized_input_image_tensor",
description=("Input image to be classified. The expected image is {0} x {1}, with "
"three channels (red, blue, and green) per pixel. Each value in the "
"tensor is a single byte between {2} and {3}.".format(
self.model_info.image_width, self.model_info.image_height,
self.model_info.image_min, self.model_info.image_max)),
norm_mean=self.model_info.mean,
norm_std=self.model_info.std,
color_space_type=_metadata_fb.ColorSpaceType.RGB,
tensor_type=writer_utils.get_input_tensor_types(self.model_buffer)[0])
-
ラベルファイルのパスを渡してあげると、ラベルも一緒に追加してくれる。
# Creates output info.
self.output_category_md = metadata_info.CategoryTensorMd(
name="category",
description="The categories of the detected boxes.",
label_files=[
metadata_info.LabelFileMd(file_path=file_path)
for file_path in self.label_file_path
])
戻り値のMetadataWriterの
populateメソッドを呼び出すことでMetadataを追加したモデルを得ることができる。あとはバイナリファイルに書き込むだけ。
self.writer = object_detector.MetadataWriter.create_from_metadata_info(
model_buffer=self.model_buffer, general_md=self.general_md,
input_md=self.input_md, output_category_md=self.output_category_md)
model_with_metadata = self.writer.populate()
with open(self.export_model_path, "wb") as f:
f.write(model_with_metadata)
ラッパーを使っているので簡単にmetadataを追加できる。
def get_metadata_json(self):
return self.writer.get_metadata_json()
環境の準備
ホストPCでMetadataを書き込む(Windows、LinuxどちらもOK)。
今回はWindowsで実施。
TF Lite Support Task
LibraryのPythonパッケージは0.1.0が公開されている(2021.01.30時点)。
TensorFlowはCPUのみで問題ない。
$ pip install tflite-support-nightly
$ pip install tensorflow
Metadataを組み込むモデル、ラベルファイル
モデル
model.tfliteをssdlite_mobiledet_cpu.tfliteにリネームして使用。
$ wget http://download.tensorflow.org/models/object_detection/ssdlite_mobiledet_cpu_320x320_coco_2020_05_19.tar.gz
$ tar xf ssdlite_mobiledet_cpu_320x320_coco_2020_05_19.tar.gz
$ mv ssdlite_mobiledet_cpu_320x320_coco_2020_05_19/model.tflite ssdlite_mobiledet_cpu.tflite
ラベル
coco datasetsのラベルを記載したファイル(labelmap.txt)を用意する。
Metadataを組み込む
リポジトリをclone後、サンプルのスクリプトを実行する。
引数は追加するモデル、ラベルファイル、出力ディレクトリ。
$ git clone https://github.com/NobuoTsukamoto/tflite-support.git
$ cd tensorflow_lite_support\examples\metadata
$ mkdir model_with_metadata
$ python metadata_writer_for_object_detection.py \
--model_file=PATH_TO\ssdlite_mobiledet_cpu.tflite \
--label_file=PATH_TO\labelmap.txt \
--export_directory=.\model_with_metadata
model_with_metadataディレクトリに以下が生成される。
- ssdlite_mobiledet_cpu.tflite 👈 metadataを追加したモデル
- ssdlite_mobiledet_cpu.json 👈 追加したmetadataのJSONファイル
Metadataを確認
Netronと生成したJSONファイルを確認。
Netron
Input(normalized_input_image_tensor)を選択すると追加したmetadataの情報が表示される。
|
Metadataを追加したモデル
|
追加前と比べるとよくわかる。
|
Metadataを追加する前のオリジナルのモデル
|
JSON
出力したmetadataのJSON。
Netronでは表示できない内容も確認できる。
{
"name": "SSDLite with MobileDet-CPU",
"description": "Identify which of a known set of objects might be present and provide information about their positions within the given image or a video stream.",
"version": "v1",
"subgraph_metadata": [
{
"input_tensor_metadata": [
{
"name": "normalized_input_image_tensor",
"description": "Input image to be classified. The expected image is 320 x 320, with three channels (red, blue, and green) per pixel. Each value in the tensor is a single byte between 0 and 255.",
"content": {
"content_properties_type": "ImageProperties",
"content_properties": {
"color_space": "RGB"
}
},
"process_units": [
{
"options_type": "NormalizationOptions",
"options": {
"mean": [
127.5
],
"std": [
127.5
]
}
}
],
"stats": {
"max": [
1.0
],
"min": [
-1.0
]
}
}
],
"output_tensor_metadata": [
{
"name": "location",
"description": "The locations of the detected boxes.",
"content": {
"content_properties_type": "BoundingBoxProperties",
"content_properties": {
"index": [
1,
0,
3,
2
],
"type": "BOUNDARIES"
},
"range": {
"min": 2,
"max": 2
}
},
"stats": {
}
},
{
"name": "category",
"description": "The categories of the detected boxes.",
"content": {
"content_properties_type": "FeatureProperties",
"content_properties": {
},
"range": {
"min": 2,
"max": 2
}
},
"stats": {
},
"associated_files": [
{
"name": "labelmap.txt",
"description": "Labels for categories that the model can recognize.",
"type": "TENSOR_VALUE_LABELS"
}
]
},
{
"name": "score",
"description": "The scores of the detected boxes.",
"content": {
"content_properties_type": "FeatureProperties",
"content_properties": {
},
"range": {
"min": 2,
"max": 2
}
},
"stats": {
}
},
{
"name": "number of detections",
"description": "The number of the detected boxes.",
"content": {
"content_properties_type": "FeatureProperties",
"content_properties": {
}
},
"stats": {
}
}
],
"output_tensor_groups": [
{
"name": "detection_result",
"tensor_names": [
"location",
"category",
"score"
]
}
]
}
],
"author": "Test",
"license": "Apache License. Version 2.0 http://www.apache.org/licenses/LICENSE-2.0."
}
Metadataを組み込んだモデルを使ってみる
前回のブログで使ったサンプルプログラム(Object
Detector)を使って推論してみる。
モデルをRaspberry Pi 4に転送して推論する。
$ ./bazel-bin/tensorflow_lite_support/examples/task/vision/pi/object_detector_capture \
--model_path=/home/pi/ssdlite_mobiledet_cpu.tflite \
--num_thread=4 --score_threshold=0.5
Detection failed: Input tensor has type kTfLiteFloat32: it requires specifying NormalizationOptions metadata to preprocess input images.
今度はエラーがなく、推論できる👍
感想
推論のコードが変更せずに利用できることはとても良いことだと思う。
(ただ、個人で使う場合、metadataを追加するコストを考えるとあまりメリットがない気も、、、Input,
Outputを統一してしまえばいいし、、、)