目的
TensorFlow Lite SupportのTFLite Model Metadataを使ってTensorFlow Lite
モデルにMetadataを追加する。Metadataを追加したモデルでTensorFlow Lite Support Task Libraryで推論してみる。
前回まで
前回のブログ「Raspberry PiでTensorFlow Lite Support Task Libraryをやってみる。」ではTensorFlow Lite Support Task Library (C++)をつかってRaspberry Pi
4で動くカメラキャプチャのサンプルを作った。
このときに使ったTensorFlow Lite モデル(TF-Lite
モデル)はmetadataが追加されたモデルを使用した(TensorFlow Hubから入手したモデル)。
今回はTF-Lite モデルにmetadataを自分で追加して、TensorFlow Lite Support Task
Library(TF Lite Support Task Library)で推論することをやってみる。
Metadataとは?
既にあるTF-Lite モデルに補足の情報を追加することができる。
追加できる情報
以下の情報が追加できる。
- モデル全体の説明(概要、著作権、作成者などの情報)
- 入力の説明(画像フォーマット、正規化、入力幅の情報)
- 出力の説明とラベル(説明やラベルとのマッピング)
追加した情報は「Netron」や「AndroidStudio」で参照できる。
Metaデータを追加する利点
-
配布するモデルファイルの作成者、著作権を明示できる。
TF-Lite モデルは端末にダウンロードが前提。
公開・非公開に関わらず情報があるとありがたい。 - TF Lite Support Task Libraryを使うと入力、出力情報から必要な前・後処理を行ってくれる。
- 前処理: リサイズ、正規化、モデルのInput(Float, Int)
- 後処理: ラベルとのマッピング
-
推論コードのラッパーを自動生成してくれる。
TensorFlowのドキュメント「メタデータを使用してモデルインターフェイスを生成する」
(まだよく理解していないので後で試す)
Medadataを追加するには?
TF Lite SupportのAPI(Python)を利用する。
Pythonのpipパッケージはtflite-supportが利用できる。
Object detectionモデルにmetadataを組み込む
TensorFlow 1 Detection Model Zooのpre-trainedモデル「ssd_mobiledet_cpu_coco」に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を追加するライブラリはここで実装。
よく使われるモデルのラッパーの定義。
(Image classification、Object detection、Image segmentation)
使い方はドキュメントはテストコードを参照。
作成したサンプル
Object detectionモデルにmetadataを書き込むサンプルを作成した。
- 大枠はmetadata_writer_for_image_classifier.pyを参考。
- tensorflow_lite_support.metadata.python.metadata_writers.object_detectorを使ってmetadetaを設定。
前回の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を生成。
metadata_info.GeneralMdでモデル全体の情報を生成。
# 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.") )
metadata_info.InputImageTensorMdでモデルの入力を生成。
- norm_mean、norm_stdで正規化のパラメータを指定。
- tensor_typeは入力モデルから取得(writer_utils.get_input_tensor_types)。
- モデルはtensorflow.python.platform.resource_loaderを使って読み込み。
# 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])
metadata_info.CategoryTensorMdでモデルの出力を生成。
- ラベルファイルのパスを渡してあげると、ラベルも一緒に追加してくれる。
# 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 ])
object_detector.MetadataWriter.create_from_metadata_infoで生成したMetadataをモデルに追加する。
戻り値の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を追加できる。
また、MetadataWriterのget_metadata_jsonメソッドで追加したMetadataをJSONフォーマットで得ることができる。
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時点)。
しかし、metadata_writersのラッパーは0.1.0には含まれていないため、tflite-support-nightlyを使う。
TensorFlowはCPUのみで問題ない。
$ pip install tflite-support-nightly $ pip install tensorflow
Metadataを組み込むモデル、ラベルファイル
モデル
「ssd_mobiledet_cpu_coco」をダウンロードして目的のTF-Liteモデルを得る。
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)を用意する。
今回はTF Lite Supportのテストデータを使用する。
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を書き込んだモデルがTensorFlow Task Libraryで動いたよ!
— nb.o (@Nextremer_nb_o) January 27, 2021
Float Inputでもコードの変更しなくてよい!! pic.twitter.com/djAUDe4Bmv
今度はエラーがなく、推論できる👍
感想
推論のコードが変更せずに利用できることはとても良いことだと思う。
(ただ、個人で使う場合、metadataを追加するコストを考えるとあまりメリットがない気も、、、Input,
Outputを統一してしまえばいいし、、、)
次は「メタデータを使用してモデルインターフェイスを生成する」を使ってAndroidアプリを試してみよう。