同じ .tflite のファイルでも違いがいろいろ:メタデータまわりについてTeachable Machine、Lobe、TensorFlow Hub等で出力した画像分類用のものを例に


最近書いた以下の記事に登場する「TFJS Task API(TensorFlow Lite のモデルを JavaScript で扱える仕組み)」による画像分類の処理を行っていた際に、Teachable Machine や Lobe の TensorFlow Lite用のモデルエクスポートを組み合わせようとして、その時にすんなり進められなかったのがあり、この記事を書きました。

要点から書くと、問題が出た原因はメタデータの扱いというか、出力ファイルにメタデータがどのような形で含まれるか、という話です。
(ちなみに、TFJS Task API を利用しない方向でやるなら、TensorFlow.js向けの機械学習モデルをエクスポートするやり方をとることで、すんなり進められます)

TensorFlow Lite用の機械学習モデルのファイル構成

Teachable Machine の画像プロジェクトの場合

以下の記事にも書いたのですが、Teachable Machine の画像プロジェクト(画像分類を行うための仕組み)で TensorFlow Lite用のモデルをダウンロードすると、「model.tflite(または、model_unquant.tflite)」と「labels.txt」の 2つのファイルを得ることができます。

●Teachable Machine の機械学習モデル出力に関するメモ 〜画像プロジェクト編〜【2021年5月版】 - Qiita
 https://qiita.com/youtoy/items/685d97e0acc5cfc184c0

画像分類で、分類したいクラスをいくつか設定するステップがありますが、その設定をしたクラスの名称の情報は「labels.txt」に書かれて出てきます。

TFJS Task API で .tflite のファイルを直接使った場合の問題

TFJS Task API のデフォルト設定では、.tflite のファイル内にクラスの情報も書かれている前提となっているようで、Teachable Machine の画像プロジェクトで出力した TensorFlow Lite用のモデルについて、.tflite のファイルを TFJS Task API でそのまま使うと、以下のように推論結果での ClassName が空になるということが起こります。

Lobe の場合

Lobe で TensorFlow Lite用のモデルをエクスポートした場合、「saved_model.tflite」・「labels.txt」と「signature.json」の 3つを、関連するファイルとして得られます。

Teachable Machine の画像プロジェクトの時と比べると、「signature.json」というファイルが 1つ多いです。
中を見てみると、以下のような内容が書かれたファイルです。

機械学習モデルでのパラメータ的なものやその他の情報が書かれていそうな感じです。

TFJS Task API で .tflite のファイルを直接使った場合の問題

Lobe からのエクスポートで得られた 3つのファイルのうち、.tflite のファイルを TFJS Task API で使おうとすると、以下のようにエラーが発生します。

この結果を、Teachable Machine の画像プロジェクトの時の結果と比べて推測すると、おそらく Teachable Machine の .tflite のファイルでは Lobe の signature.json に書かれていた情報が .tflite のファイル内に含まれていたのではないかと思われます。

TensorFlow Lite のモデルとメタデータ

TensorFlow Lite用のモデルのメタデータに関するツール

上記の問題やエラーの解決方法について調べてみたところ、以下のページに関係する情報がありそうでした。

●TensorFlowLiteモデルへのメタデータの追加  |  TensorFlow Lite
 https://www.tensorflow.org/lite/convert/metadata

例えばファイルのフォーマット関連で、以下の内容が正に関連していそうな部分のうちの 1つです。

そして、クラス名が書かれた「labels.txt」が「.tflite のファイル」に含まれる場合の構成は、以下のように書かれています。

「labels.txt」を含むモデルを ZIPファイルとして解凍してみる

上記の labels.txt に関する話をここで確かめてみようと思います。

手軽にできそうなやり方の 1つとして、TensorFlow Hub から labels.txt を含んだモデルをダウンロードしてきて解凍処理を行ってみる、というのが良さそうです。

そこで、実際に以下の画像で示した内容のモデルを使って試していきます。

このモデルの出力形式がいくつかある中で、以下からファイルをダウンロードすると「lite-model_imagenet_mobilenet_v3_large_100_224_classification_5_metadata_1.tflite」というファイルが得られます。

そのファイルについて、Mac だと unzip 【対象ファイル】 というコマンドを実行することで解凍を実行できます。
実際にそのコマンドを実行した結果は以下の通りです。

$ unzip lite-model_imagenet_mobilenet_v3_large_100_224_classification_5_metadata_1.tflite
Archive:  lite-model_imagenet_mobilenet_v3_large_100_224_classification_5_metadata_1.tflite
 extracting: labels.txt

labels.txt が抽出されるのを確認できました。

ちなみに、「TFLite (v5, metadata)」ではなく「TFLite (v5, default)」のほうのタブを選び、そこからファイルをダウンロードして unzip を実行すると、以下のようになります。

$ unzip lite-model_imagenet_mobilenet_v3_large_100_224_classification_5_default_1.tflite
Archive:  lite-model_imagenet_mobilenet_v3_large_100_224_classification_5_default_1.tflite
  End-of-central-directory signature not found.  Either this file is not
  a zipfile, or it constitutes one disk of a multi-part archive.  In the
  latter case the central directory and zipfile comment will be found on
  the last disk(s) of this archive.
unzip:  cannot find zipfile directory in one of lite-model_imagenet_mobilenet_v3_large_100_224_classification_5_default_1.tflite or
        lite-model_imagenet_mobilenet_v3_large_100_224_classification_5_default_1.tflite.zip, and cannot find lite-model_imagenet_mobilenet_v3_large_100_224_classification_5_default_1.tflite.ZIP, period.

こちらは、「labels.txt」を含んでないファイルだと思われるので、ファイルフォーマット的に ZIP の形をとっていなくて上記のエラーがでる、という状況だと思われます。

.tflite のファイル と label.txt を統合する

上で書いていた話のうち、Teachable Machine のほうは、比較的簡単に対応ができます。

以下の「TensorFlowLiteメタデータライターAPI」を使うと、.tflite のファイル と label.txt を統合することができます。

●TensorFlowLiteメタデータライターAPI  |  TensorFlow Lite
 https://www.tensorflow.org/lite/convert/metadata_writer_tutorial#image_classifiers

統合する手順

TensorFlowLiteメタデータライターAPI のページに書かれている「TensorFlow Lite SupportPypiパッケージのインストール」を行います。

$ pip install tflite-support-nightly

そして、TensorFlowLiteメタデータライターAPI のページに書かれているのと同じような Python のプログラムを作成して実行します。

from tflite_support.metadata_writers import image_classifier
from tflite_support.metadata_writers import writer_utils

ImageClassifierWriter = image_classifier.MetadataWriter
_MODEL_PATH = "model_unquant.tflite"
_LABEL_FILE = "labels.txt"
_SAVE_TO_PATH = "model_unquant_metadata.tflite"

_INPUT_NORM_MEAN = 127.5
_INPUT_NORM_STD = 127.5

writer = ImageClassifierWriter.create_for_inference(
    writer_utils.load_file(_MODEL_PATH), [_INPUT_NORM_MEAN], [_INPUT_NORM_STD],
    [_LABEL_FILE])
print(writer.get_metadata_json())
writer_utils.save_file(writer.populate(), _SAVE_TO_PATH)

そうすると、以下のように TFJS Task API での画像分類(推論)を実行した際に、ClassName が表示されるようになりました。
(以下の例は、学習させた画像と推論の対象の画像もマッチしていないし、label.txt に含まれた数字の情報がそのまま統合されていて、イマイチな感じになっているのはありますが...)

Lobe の事例のほうは「signature.json」の中身も統合する必要がありそうで、上でも記載していた「TensorFlowLiteモデルへのメタデータの追加」のページに書いてあることを利用すれば良さそうなのかもしれないですが、詳細は調査できてない状況です。

終わりに

Teachable Machine と Lobe で TensorFlow Lite用のモデルをエクスポートし、TFJS Task API で使おうとしたらすんなりとは進められなかった...、という状況から TensorFlow Lite用の機械学習モデルのファイルの構成について調査したりしてみました。

出力した機械学習モデル関連のファイルが、単体・2つのファイル・3つのファイルのパターンがあり、それらを変換する方法を調べて試そうとしましたが、2つのファイルを 1つに統合するというところは実現できました(TensorFlowLiteメタデータライターAPI を利用)。
3つのファイルに分かれているパターン(Lobe の出力するファイル)を 1つのファイルに統合するのは、まだ調査が必要な状況です。

TensorFlow Lite用モデルを HTML+JavaScript から使って画像分類などを簡単に行える TFJS Task API は、いろいろ活用してみたいところなので、今回未解決の部分も引き続き調査してみようと思います。