TensorFlow Lite モデルへのメタデータの追加

TensorFlow Lite メタデータは、モデル記述の標準を提供します。メタデータは、モデルの動作とその入出力情報に関する重要な情報源です。メタデータは両方で構成されます

TensorFlow Hubで公開されているすべての画像モデルにはメタデータが入力されています。

メタデータ形式のモデル

メタデータ付きモデル
図 1. メタデータと関連ファイルを含む TFLite モデル。

モデルのメタデータは、 FlatBufferファイルであるmetadata_schema.fbsで定義されます。図 1 に示すように、これはTFLite モデル スキーマメタデータフィールドに"TFLITE_METADATA"という名前で保存されます。一部のモデルには、分類ラベル ファイルなどの関連ファイルが付属している場合があります。これらのファイルは、ZipFile の「追加」モード( 'a'モード) を使用して、ZIP として元のモデル ファイルの末尾に連結されます。 TFLite インタープリターは、以前と同じ方法で新しいファイル形式を使用できます。詳細については、「関連ファイルをパックする」を参照してください。

メタデータの入力、視覚化、読み取り方法については、以下の手順を参照してください。

メタデータ ツールをセットアップする

モデルにメタデータを追加する前に、TensorFlow を実行するための Python プログラミング環境をセットアップする必要があります。これを設定する方法については、ここに詳細なガイドがあります。

Python プログラミング環境をセットアップした後、追加のツールをインストールする必要があります。

pip install tflite-support

TensorFlow Lite メタデータ ツールは Python 3 をサポートします。

Flatbuffers Python API を使用したメタデータの追加

スキーマ内のモデル メタデータには 3 つの部分があります。

  1. モデル情報- モデルの全体的な説明とライセンス条項などの項目。 ModelMetadataを参照してください。
  2. 入力情報- 入力の説明と、正規化など必要な前処理。 SubGraphMetadata.input_tensor_metadataを参照してください。
  3. 出力情報- ラベルへのマッピングなど、必要な出力および後処理の説明。 SubGraphMetadata.output_tensor_metadataを参照してください。

TensorFlow Lite は現時点では単一のサブグラフのみをサポートしているため、 TensorFlow Lite コード ジェネレーターAndroid Studio ML Binding 機能は、メタデータを表示してコードを生成するときに、 SubGraphMetadata.nameSubGraphMetadata.descriptionの代わりにModelMetadata.nameModelMetadata.descriptionを使用します。

サポートされている入力/出力タイプ

入力および出力の TensorFlow Lite メタデータは、特定のモデル タイプを念頭に置いて設計されているのではなく、入力および出力タイプを念頭に置いて設計されています。モデルが機能的に何を行うかは問題ではありません。入出力タイプが次のもの、または次の組み合わせで構成されている限り、TensorFlow Lite メタデータによってサポートされます。

  • 機能 - 符号なし整数または float32 の数値。
  • 画像 - メタデータは現在、RGB およびグレースケール画像をサポートしています。
  • 境界ボックス - 長方形の境界ボックス。このスキーマは、さまざまな番号付けスキームをサポートしています。

関連ファイルをパックする

TensorFlow Lite モデルには、異なる関連ファイルが付属している場合があります。たとえば、自然言語モデルには通常、単語の断片を単語 ID にマッピングする語彙ファイルが含まれています。分類モデルには、オブジェクト カテゴリを示すラベル ファイルが含まれる場合があります。関連ファイルがないと (存在する場合)、モデルは適切に機能しません。

関連ファイルは、メタデータ Python ライブラリを通じてモデルにバンドルできるようになりました。新しい TensorFlow Lite モデルは、モデルと関連ファイルの両方を含む zip ファイルになります。一般的な zip ツールを使用して解凍できます。この新しいモデル形式では、同じファイル拡張子.tfliteが引き続き使用されます。既存の TFLite フレームワークおよびインタープリターと互換性があります。詳細については、「メタデータと関連ファイルをモデルにパックする」を参照してください。

関連するファイル情報をメタデータに記録できます。ファイルの種類とファイルの添付場所 (つまり、 ModelMetadataSubGraphMetadataTensorMetadata ) に応じて、 TensorFlow Lite Android コード ジェネレーターは、対応する前後処理をオブジェクトに自動的に適用する場合があります。詳細については、スキーマ内の各関連ファイル タイプの <Codegen の使用法> セクションを参照してください。

正規化および量子化パラメータ

正規化は、機械学習における一般的なデータ前処理手法です。正規化の目的は、値の範囲の違いを歪めることなく、値を共通のスケールに変更することです。

モデル量子化は、重みの精度を下げた表現を可能にし、オプションでストレージと計算の両方をアクティブ化できるようにする手法です。

前処理と後処理の観点から見ると、正規化と量子化は 2 つの独立したステップです。詳細は次のとおりです。

正規化量子化

浮動小数点モデルと量子モデルのそれぞれに対する MobileNet の入力画像のパラメーター値の例。
フロートモデル:
- 平均: 127.5
- 標準: 127.5
量子モデル:
- 平均: 127.5
- 標準: 127.5
フロートモデル:
- ゼロポイント: 0
- スケール: 1.0
量子モデル:
- ゼロポイント: 128.0
- スケール:0.0078125f




いつ発動するのか?


入力: トレーニングで入力データが正規化されている場合、それに応じて推論の入力データも正規化する必要があります。
出力: 出力データは通常、正規化されません。
Float モデルには量子化は必要ありません。
量子化されたモデルは、前後処理で量子化が必要な場合と必要ない場合があります。それは入出力テンソルのデータ型に依存します。
- 浮動小数点テンソル: 前処理/後処理での量子化は必要ありません。 Quant op と dequant op はモデル グラフにベイクされます。
- int8/uint8 テンソル: 前処理/後処理で量子化が必要です。




Normalized_input = (入力 - 平均) / std
入力の量子化:
q = f / スケール + ゼロポイント
出力の逆量子化:
f = (q - ゼロポイント) * スケール

パラメータはどこにありますか
モデル作成者によって入力され、 NormalizationOptionsとしてモデルのメタデータに保存されます。 TFLite コンバーターによって自動的に入力され、tflite モデル ファイルに保存されます。
パラメータを取得するにはどうすればよいですか? MetadataExtractor API 経由 [2] TFLite Tensor API [1] またはMetadataExtractor API [2] を介して
float モデルと quant モデルは同じ値を共有しますか?はい、float モデルと quant モデルには同じ正規化パラメータがありますいいえ、float モデルには量子化は必要ありません。
TFLite コード ジェネレーターまたは Android Studio ML バインディングはデータ処理時に自動的に生成しますか?
はい

はい

[1] TensorFlow Lite Java APIおよびTensorFlow Lite C++ API
[2]メタデータ抽出ライブラリ

uint8 モデルの画像データを処理する場合、正規化と量子化がスキップされる場合があります。ピクセル値が[0, 255]の範囲にある場合は問題ありません。ただし、一般に、該当する場合は、常に正規化パラメータと量子化パラメータに従ってデータを処理する必要があります。

メタデータでNormalizationOptionsを設定すると、 TensorFlow Lite タスク ライブラリで正規化を処理できます。量子化および逆量子化の処理は常にカプセル化されます。

さまざまなタイプのモデルにメタデータを設定する方法の例は、次のとおりです。

画像分類

ここからスクリプトをダウンロードします。このスクリプトにより、メタデータがmobilenet_v1_0.75_160_quantized.tfliteに設定されます。次のようにスクリプトを実行します。

python ./metadata_writer_for_image_classifier.py \
    --model_file=./model_without_metadata/mobilenet_v1_0.75_160_quantized.tflite \
    --label_file=./model_without_metadata/labels.txt \
    --export_directory=model_with_metadata

他の画像分類モデルのメタデータを設定するには、次のようなモデル仕様をスクリプトに追加します。このガイドの残りの部分では、画像分類例の重要なセクションのいくつかを強調表示して、主要な要素を説明します。

画像分類の例を詳しく見る

機種情報

メタデータは、新しいモデル情報を作成することから始まります。

from tflite_support import flatbuffers
from tflite_support import metadata as _metadata
from tflite_support import metadata_schema_py_generated as _metadata_fb

""" ... """
"""Creates the metadata for an image classifier."""

# Creates model info.
model_meta = _metadata_fb.ModelMetadataT()
model_meta.name = "MobileNetV1 image classifier"
model_meta.description = ("Identify the most prominent object in the "
                          "image from a set of 1,001 categories such as "
                          "trees, animals, food, vehicles, person etc.")
model_meta.version = "v1"
model_meta.author = "TensorFlow"
model_meta.license = ("Apache License. Version 2.0 "
                      "http://www.apache.org/licenses/LICENSE-2.0.")

入出力情報

このセクションでは、モデルの入力および出力シグネチャを記述する方法を説明します。このメタデータは、自動コード ジェネレーターによって前処理コードと後処理コードを作成するために使用される場合があります。テンソルに関する入力または出力情報を作成するには:

# Creates input info.
input_meta = _metadata_fb.TensorMetadataT()

# Creates output info.
output_meta = _metadata_fb.TensorMetadataT()

画像入力

画像は機械学習の一般的な入力タイプです。 TensorFlow Lite メタデータは、色空間などの情報や正規化などの前処理情報をサポートします。画像の寸法は入力テンソルの形状によってすでに提供されており、自動的に推測できるため、手動で指定する必要はありません。

input_meta.name = "image"
input_meta.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 0 and 255.".format(160, 160))
input_meta.content = _metadata_fb.ContentT()
input_meta.content.contentProperties = _metadata_fb.ImagePropertiesT()
input_meta.content.contentProperties.colorSpace = (
    _metadata_fb.ColorSpaceType.RGB)
input_meta.content.contentPropertiesType = (
    _metadata_fb.ContentProperties.ImageProperties)
input_normalization = _metadata_fb.ProcessUnitT()
input_normalization.optionsType = (
    _metadata_fb.ProcessUnitOptions.NormalizationOptions)
input_normalization.options = _metadata_fb.NormalizationOptionsT()
input_normalization.options.mean = [127.5]
input_normalization.options.std = [127.5]
input_meta.processUnits = [input_normalization]
input_stats = _metadata_fb.StatsT()
input_stats.max = [255]
input_stats.min = [0]
input_meta.stats = input_stats

ラベル出力

ラベルは、 TENSOR_AXIS_LABELSを使用する関連ファイルを介して出力テンソルにマッピングできます。

# Creates output info.
output_meta = _metadata_fb.TensorMetadataT()
output_meta.name = "probability"
output_meta.description = "Probabilities of the 1001 labels respectively."
output_meta.content = _metadata_fb.ContentT()
output_meta.content.content_properties = _metadata_fb.FeaturePropertiesT()
output_meta.content.contentPropertiesType = (
    _metadata_fb.ContentProperties.FeatureProperties)
output_stats = _metadata_fb.StatsT()
output_stats.max = [1.0]
output_stats.min = [0.0]
output_meta.stats = output_stats
label_file = _metadata_fb.AssociatedFileT()
label_file.name = os.path.basename("your_path_to_label_file")
label_file.description = "Labels for objects that the model can recognize."
label_file.type = _metadata_fb.AssociatedFileType.TENSOR_AXIS_LABELS
output_meta.associatedFiles = [label_file]

メタデータのフラットバッファーを作成する

次のコードは、モデル情報と入力および出力情報を結合します。

# Creates subgraph info.
subgraph = _metadata_fb.SubGraphMetadataT()
subgraph.inputTensorMetadata = [input_meta]
subgraph.outputTensorMetadata = [output_meta]
model_meta.subgraphMetadata = [subgraph]

b = flatbuffers.Builder(0)
b.Finish(
    model_meta.Pack(b),
    _metadata.MetadataPopulator.METADATA_FILE_IDENTIFIER)
metadata_buf = b.Output()

メタデータと関連ファイルをモデルにパックする

メタデータ フラットバッファーが作成されると、メタデータとラベル ファイルは、 populateメソッドを介して TFLite ファイルに書き込まれます。

populator = _metadata.MetadataPopulator.with_model_file(model_file)
populator.load_metadata_buffer(metadata_buf)
populator.load_associated_files(["your_path_to_label_file"])
populator.populate()

load_associated_filesを使用して、必要な数の関連ファイルをモデルにパックできます。ただし、少なくともメタデータに文書化されているファイルをパックする必要があります。この例では、ラベル ファイルのパッキングは必須です。

メタデータを視覚化する

Netronを使用してメタデータを視覚化することも、 MetadataDisplayerを使用して TensorFlow Lite モデルからメタデータを json 形式に読み取ることもできます。

displayer = _metadata.MetadataDisplayer.with_model_file(export_model_path)
export_json_file = os.path.join(FLAGS.export_directory,
                                os.path.splitext(model_basename)[0] + ".json")
json_file = displayer.get_metadata_json()
# Optional: write out the metadata as a json file
with open(export_json_file, "w") as f:
  f.write(json_file)

Android Studio は、Android Studio ML バインディング機能を介したメタデータの表示もサポートしています。

メタデータのバージョン管理

メタデータ スキーマは、スキーマ ファイルの変更を追跡するセマンティック バージョン番号と、真のバージョン互換性を示すフラットバッファ ファイル ID の両方によってバージョン管理されます。

セマンティック バージョン番号

メタデータ スキーマは、MAJOR.MINOR.PATCH などのセマンティック バージョン番号によってバージョン管理されます。ここのルールに従ってスキーマの変更を追跡します。バージョン1.0.0以降に追加されたフィールドの履歴を参照してください。

Flatbuffers ファイルの識別

セマンティック バージョニングは、ルールに従っている場合に互換性を保証しますが、実際の非互換性を意味するものではありません。 MAJOR 番号を大きくしても、必ずしも下位互換性が失われるわけではありません。したがって、フラットバッファーのファイル識別子file_identifier を使用して、メタデータ スキーマの真の互換性を示します。ファイル識別子の長さはちょうど 4 文字です。これは特定のメタデータ スキーマに固定されており、ユーザーによる変更の対象にはなりません。何らかの理由でメタデータ スキーマの下位互換性を解除する必要がある場合、file_identifier は、たとえば「M001」から「M002」に増加します。 File_identifier は、metadata_version よりもはるかに少ない頻度で変更されることが予想されます。

最低限必要なメタデータ パーサーのバージョン

必要なメタデータ パーサーの最小バージョンは、メタデータ フラットバッファーを完全に読み取ることができるメタデータ パーサー (フラットバッファーで生成されたコード) の最小バージョンです。バージョンは、実際には、入力されているすべてのフィールドのバージョンの中で最大のバージョン番号であり、ファイル識別子によって示される互換性のある最小のバージョンです。メタデータが TFLite モデルに入力されるときに、 MetadataPopulatorによって最小限必要なメタデータ パーサーのバージョンが自動的に入力されます。必要な最小限のメタデータ パーサー バージョンの使用方法の詳細については、メタデータ エクストラクターを参照してください。

モデルからメタデータを読み取る

Metadata Extractor ライブラリは、さまざまなプラットフォームのモデルからメタデータと関連ファイルを読み取るための便利なツールです ( Java バージョンC++ バージョンを参照)。 Flatbuffers ライブラリを使用して、他の言語で独自のメタデータ抽出ツールを構築できます。

Java でメタデータを読み取る

Android アプリで Metadata Extractor ライブラリを使用するには、 MavenCentral でホストされている TensorFlow Lite Metadata AARを使用することをお勧めします。これには、 MetadataExtractorクラスと、メタデータ スキーマおよびモデル スキーマの FlatBuffers Java バインディングが含まれています。

次のように、 build.gradle依存関係でこれを指定できます。

dependencies {
    implementation 'org.tensorflow:tensorflow-lite-metadata:0.1.0'
}

夜間のスナップショットを使用するには、 Sonatype スナップショット リポジトリを追加していることを確認してください。

モデルを指すByteBufferを使用してMetadataExtractorオブジェクトを初期化できます。

public MetadataExtractor(ByteBuffer buffer);

ByteBufferMetadataExtractorオブジェクトの存続期間中、変更されないままでなければなりません。モデル メタデータの Flatbuffers ファイル識別子がメタデータ パーサーのファイル識別子と一致しない場合、初期化は失敗する可能性があります。詳細については、 「メタデータのバージョン管理」を参照してください。

ファイル識別子が一致すると、メタデータ エクストラクターは、フラットバッファーの上位および下位互換性メカニズムにより、過去および将来のすべてのスキーマから生成されたメタデータを正常に読み取ることができます。ただし、将来のスキーマのフィールドは、古いメタデータ抽出プログラムでは抽出できません。メタデータの最小必要パーサー バージョンは、メタデータ フラットバッファーを完全に読み取ることができるメタデータ パーサーの最小バージョンを示します。次の方法を使用して、必要な最小パーサー バージョンの条件が満たされているかどうかを確認できます。

public final boolean isMinimumParserVersionSatisfied();

メタデータなしでモデルを渡すことは許可されます。ただし、メタデータから読み取るメソッドを呼び出すと、実行時エラーが発生します。 hasMetadataメソッドを呼び出すことで、モデルにメタデータがあるかどうかを確認できます。

public boolean hasMetadata();

MetadataExtractor入力/出力テンソルのメタデータを取得するための便利な関数を提供します。例えば、

public int getInputTensorCount();
public TensorMetadata getInputTensorMetadata(int inputIndex);
public QuantizationParams getInputTensorQuantizationParams(int inputIndex);
public int[] getInputTensorShape(int inputIndex);
public int getoutputTensorCount();
public TensorMetadata getoutputTensorMetadata(int inputIndex);
public QuantizationParams getoutputTensorQuantizationParams(int inputIndex);
public int[] getoutputTensorShape(int inputIndex);

TensorFlow Lite モデル スキーマは複数のサブグラフをサポートしていますが、TFLite インタープリターは現在 1 つのサブグラフのみをサポートしています。したがって、 MetadataExtractorメソッドの入力引数としてサブグラフ インデックスを省略します。

モデルから関連ファイルを読み取る

メタデータと関連ファイルを含む TensorFlow Lite モデルは基本的に zip ファイルであり、一般的な zip ツールで解凍して関連ファイルを取得できます。たとえば、次のようにmobilenet_v1_0.75_160_quantizedを解凍し、モデル内のラベル ファイルを抽出できます。

$ unzip mobilenet_v1_0.75_160_quantized_1_metadata_1.tflite
Archive:  mobilenet_v1_0.75_160_quantized_1_metadata_1.tflite
 extracting: labels.txt

Metadata Extractor ライブラリを通じて関連ファイルを読み取ることもできます。

Java では、ファイル名をMetadataExtractor.getAssociatedFileメソッドに渡します。

public InputStream getAssociatedFile(String fileName);

同様に、C++ では、これはModelMetadataExtractor::GetAssociatedFileメソッドを使用して実行できます。

tflite::support::StatusOr<absl::string_view> GetAssociatedFile(
      const std::string& filename) const;