在 LiteRT 模型中新增中繼資料

LiteRT 中繼資料提供了模型說明的標準, 中繼資料是瞭解模型用途和模型的重要知識來源 輸入 / 輸出資訊中繼資料包含

所有在 Kaggle 發布的圖片模型 模型已填入 中繼資料。

中繼資料格式的模型

model_with_metadata
敬上
圖 1.具有中繼資料和相關檔案的 TFLite 模型。

模型中繼資料的定義位置: metadata_schema.fbsFlatBuffer 檔案。如圖 1 所示,資料會儲存在 中繼資料 TFLite 模型的] 欄位 結構定義 並在名稱下方指定 "TFLITE_METADATA"部分模型可能含有相關聯的檔案 例如分類標籤 檔案。 這些檔案會以 ZIP 格式串連至原始模型檔案的結尾 使用 ZipFile "append" 模式 ('a' 模式)。TFLite 翻譯模式能夠以和先前相同的方式使用新檔案格式。請參閱 Pack 關聯檔案

請參閱下方操作說明,瞭解如何填入、視覺化及讀取中繼資料。

設定中繼資料工具

在將中繼資料新增至模型之前,需要有 Python 程式設計 執行 TensorFlow 的環境設定作業查閱詳盡的指南 請前往這裡進行設定。

設定 Python 程式設計環境後,您需要安裝 其他工具:

pip install tflite-support

LiteRT 中繼資料工具支援 Python 3。

使用 Flatbuffers Python API 新增中繼資料

模型中繼資料包含三個部分 結構定義

  1. 模型資訊:模型與項目的整體說明 例如授權條款詳情請見 ModelMetadata
    1. 輸入資訊:輸入內容和預先處理的說明 例如正規化等詳情請見 SubGraphMetadata.input_tensor_metadata
      1. 輸出資訊:輸出內容的說明和 需要進行後續處理,例如對應至標籤詳情請見 SubGraphMetadata.output_tensor_metadata

由於 LiteRT 目前僅支援單一子圖表,因此 LiteRT 程式碼產生器 以及 Android Studio 機器學習繫結 功能 將使用 ModelMetadata.nameModelMetadata.description,而不是 SubGraphMetadata.nameSubGraphMetadata.description (用於顯示裝置) 中繼資料和產生程式碼

支援的輸入 / 輸出類型

輸入和輸出的 LiteRT 中繼資料並未針對特定 具體來說是輸入和輸出類型其實並不重要 模型仍會運作,前提是輸入和輸出類型 下列項目或下列項目的組合,可以使用 TensorFlow 支援 Lite 中繼資料:

  • 特徵 - 不是帶正負號整數或 float32 的數字。
  • 圖片 - 中繼資料目前支援 RGB 和灰階圖片。
  • 定界框 - 矩形定界框。結構定義支援 a 各種編號 配置

封裝相關聯的檔案

LiteRT 模型可能會有不同的相關檔案。例如: 自然語言模型通常會有詞彙檔案,將字詞對應至 編號;分類模型可能有標籤檔案 指明物件類別 如果沒有關聯檔案 (如果有的話),模型將無法正常運作。

您現在可以透過中繼資料,將相關聯的檔案與模型一起封裝 Python 程式庫。新的 LiteRT 模型會成為 ZIP 檔案,當中包含 模型和相關檔案的資訊可以與一般郵遞區號解壓縮 工具。這個新模型格式會繼續使用相同的副檔名 .tflite。這項服務 與現有的 TFLite 架構和解譯器相容。請參閱「封裝中繼資料」 複製到 模型

相關的檔案資訊可以記錄在中繼資料中。視乎 檔案類型和附加檔案的位置 (例如 ModelMetadataSubGraphMetadataTensorMetadata),也就是 LiteRT Android 程式碼 產生器可能會套用相關的前後對照 自動處理到物件請參閱<Codegen 用法>的第 節 每個關聯檔案 類型 建立 Deployment 資訊清單

正規化和量化參數

正規化是機器學習的常見資料預先處理技術。 正規化的目標是將值變更為共通的量表 用來表示值範圍的差異

模型量化是一種技巧 可降低權重的精確度表示法 儲存和運算作業的啟動功能。

在預先處理和後續處理、正規化和量化方面 兩個獨立步驟以下是問題的詳細說明:

正規化 量化

「 參數值 輸入圖片 MobileNet 可用於浮動和 量化模型 。
浮點模型
- 平均值:127.5
- std:127.5
數量模型
- 平均值:127.5
- 標準:127.5
浮點模型
- 零點:0
- 比例:1.0
數量模型
- 零點:128.0
- scale:0.0078125f




何時應叫用?


輸入內容:如果輸入內容 資料經過正規化處理的 訓練、輸入內容 推論需求 正規化 。
輸出:輸出 一般情況會經過正規化處理
浮點模型能 也不必量化
量化模型 或者可能不需要 前後測中的量化 和資料處理之間視情況而定 儲存資料類型 輸入/輸出張量
- 浮點張量:否 前後測中的量化 來處理所需資料Quant 運算和量級運算 並放入模型中 圖表。
- int8/uint8 張量: 需要量化 事前/事後處理


公式


正規化輸入 = (輸入 - 平均值) / std
量化輸入值
q = f / 尺 + zeroPoint
去量化 輸出:
f = (q - 零點) * 縮放

哪裡可以查看 參數
由模型建立者填入 並儲存在模型中 中繼資料 NormalizationOptions 自動填入依據: TFLite 轉換工具 儲存在 tflite 模型中 檔案。
如何取得 參數呢? 透過 MetadataExtractor API [2]。 穿越時空 Tensor API [1] 或 透過 MetadataExtractor API [2]。
浮點值和量化 共用相同的 值呢? 是,浮點值和量化值 都具有相同的 正規化 參數 否,浮點模型會 也不必量化
有 TFLite 程式碼 產生器或 Android Studio 機器學習繫結 自動產生 該怎麼辦?

[1] LiteRT Java APILiteRT C++ API
[2] 中繼資料擷取器資料庫

處理 uint8 模型的圖片資料時,正規化和量化 有時會略過。即使像素值介於 [0, 255]。但一般而言,在您處理資料時,應一律根據 常態化和量化參數

範例

我們提供多種範例,說明應如何填入不同格式的中繼資料 這裡有幾種模型

圖片分類

下載指令碼 這裡 ,會將中繼資料填入 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()

圖片輸入

圖片是機器學習的常見輸入類型。LiteRT 中繼資料 支援色域和預先處理資訊,如 以便處理正規化的情況不需要手動規格圖片尺寸 因為已經由輸入張量的形狀提供 由系統自動推測出來

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]

建立中繼資料 Flatbuffers

下列程式碼會合併模型資訊與輸入和輸出內容 每個 ACL 都由一或多個項目組成 而這些項目包含兩項資訊

# 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()

將中繼資料和相關聯的檔案封裝至模型

建立中繼資料 Flatbuffers 後,中繼資料和標籤檔案就會 已透過 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()

透過這個 API,您可以將任意數量的相關檔案封裝至模型 load_associated_files。不過,您至少要封裝這些檔案 中繼資料並列示在中繼資料內在這個範例中,如果將標籤檔案封裝為 強制規定。

以視覺化方式呈現中繼資料

您可以使用 Netron 查看 也能將 LiteRT 模型的中繼資料 使用 MetadataDisplayer 進行相同格式:

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 顯示中繼資料。 繫結 功能

中繼資料版本管理

中繼資料 結構定義 都有版本編號的語意化編號 結構定義檔案以及 Flatbuffers 檔案識別, 與實際版本相容性

語意版本編號

中繼資料結構定義是由 Semantic 版本管理 編號, 例如 MAJOR.MINOR.PATCH可根據規則追蹤結構定義異動 請按這裡。 查看歷史沿革 欄位 已加至版本 1.0.0

Flatbuffers 檔案識別

語意版本管理可以在遵循規則的情況下保證相容性,但前提是 不代表實際不相容。提高 MAJOR 的數值時 但不一定代表回溯相容性故障。因此,我們 使用 Flatbuffers 檔案 身分file_identifier, 代表中繼資料結構定義的真正相容性。檔案 ID 為 長度為 4 個字元此政策固定為特定中繼資料結構定義,而非 隨時可能變動如果中繼資料結構定義的回溯相容性 「file_identifier」會因為某些原因而損壞,舉例來說, 從「M001」變為「M002」File_identifier 預期變更幅度會大幅減少 更新的頻率比 metadata_version 更高

中繼資料剖析器的最低版本需求

必要的中繼資料剖析器最少 版本 是中繼資料剖析器 (Flatbuffers 產生的程式碼) 的最低版本, 可以完整讀取中繼資料 Flatbuffers。版本實際上是 而所有已填入欄位的版本編號,以及 最小相容的版本 (以檔案 ID 表示)。最低 而 Deployment 將自動填入必要的中繼資料剖析器版本 MetadataPopulator (當中繼資料填入 TFLite 模型時)。詳情請參閱 中繼資料擷取器,進一步瞭解如何 且使用的是最低必要中繼資料剖析器版本。

讀取模型的中繼資料

中繼資料擷取器程式庫可讓您輕鬆讀取中繼資料 來自不同平台模型的關聯檔案 (請參閱 Java 版本C++ version)。 您可以使用其他語言的 Flatbuffers 程式庫。

以 Java 讀取中繼資料

如要在 Android 應用程式中使用中繼資料擷取器程式庫,建議您使用 LiteRT 中繼資料 AAR, MavenCentral. 其中包含 MetadataExtractor 類別和 FlatBuffers Java 中繼資料的繫結 結構定義模型 結構定義

您可以在 build.gradle 依附元件中指定此屬性,如下所示:

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

如要使用夜間快照,請確定已加入 Sonatype 快照 存放區

您可以使用指向該 ByteBuffer 點的 ByteBuffer 來初始化 MetadataExtractor 物件 對應至模型:

public MetadataExtractor(ByteBuffer buffer);

ByteBuffer 在整個生命週期內必須保持不變 MetadataExtractor 物件。如果 Flatbuffers 檔案,初始化作業可能會失敗 模型中繼資料的 ID 與中繼資料剖析器的 ID 不相符。詳情請見 中繼資料版本管理

比對檔案 ID 後,中繼資料擷取工具就能順利讀取 由 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);

雖然 LiteRT 模型 結構定義 支援多個子圖表,TFLite 解譯器目前僅支援 單一子圖表。因此,MetadataExtractor 會在輸入內容中省略子圖表索引 引數。

讀取模型中的關聯檔案

包含中繼資料和相關檔案的 LiteRT 模型基本上是 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

您也可以透過中繼資料擷取器程式庫讀取相關聯的檔案。

在 Java 中,將檔案名稱傳遞至 MetadataExtractor.getAssociatedFile 方法:

public InputStream getAssociatedFile(String fileName);

同樣地,在 C++ 中,您也可以使用 方法完成這項操作 ModelMetadataExtractor::GetAssociatedFile:

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