目的
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アプリを試してみよう。