LiteRT 中繼資料提供模型說明的標準。中繼資料是模型功能和輸入 / 輸出資訊的重要知識來源。中繼資料包含
- 人類可讀的部分,說明使用模型時的最佳做法,以及
- 可供程式碼產生器使用的機器可讀部分,例如 LiteRT Android 程式碼產生器和 Android Studio 機器學習繫結功能。
Kaggle 模型上發布的所有圖像模型都已填入中繼資料。
含有中繼資料格式的模型

模型中繼資料定義於 metadata_schema.fbs,這是 FlatBuffer 檔案。如圖 1 所示,這項資料會儲存在 TFLite 模型結構定義的中繼資料欄位中,名稱為 "TFLITE_METADATA"。部分模型可能附有相關聯的檔案,例如分類標籤檔案。這些檔案會以 ZIP 格式串連至原始模型檔案的結尾,並使用 ZipFile「append」模式 ('a' 模式) 。TFLite
解譯器可以像以往一樣使用新檔案格式。詳情請參閱「封裝相關聯的檔案」。
請參閱下方的說明,瞭解如何填入、顯示及讀取中繼資料。
設定中繼資料工具
為模型新增中繼資料前,您需要設定 Python 程式設計環境,才能執行 TensorFlow。如需詳細設定指南,請參閱這篇文章。
設定 Python 程式設計環境後,您需要安裝其他工具:
pip install tflite-support
LiteRT 中繼資料工具支援 Python 3。
使用 Flatbuffers Python API 新增中繼資料
結構定義中的模型中繼資料包含三個部分:
- 模型資訊:模型的整體說明,以及授權條款等項目。請參閱 ModelMetadata。 2. 輸入資訊 - 輸入內容的說明和必要的前置處理,例如正規化。請參閱 SubGraphMetadata.input_tensor_metadata。 3. 輸出資訊 - 輸出內容的說明和所需的後續處理作業,例如對應至標籤。請參閱 SubGraphMetadata.output_tensor_metadata。
由於 LiteRT 目前僅支援單一子圖,因此 LiteRT 程式碼產生器和 Android Studio ML 繫結功能會使用 ModelMetadata.name 和 ModelMetadata.description,而非 SubGraphMetadata.name 和 SubGraphMetadata.description,顯示中繼資料並產生程式碼。
支援的輸入 / 輸出類型
輸入和輸出的 LiteRT 中繼資料並非專為特定模型類型設計,而是針對輸入和輸出類型。只要輸入和輸出類型包含下列類型或下列類型的組合,TensorFlow Lite 中繼資料就支援該模型,模型的功能為何並不重要:
- 特徵 - 無正負號整數或 float32。
- 圖片 - 中繼資料目前支援 RGB 和灰階圖片。
- 定界框 - 矩形定界框。這個結構定義支援各種編號方式。
封裝相關聯的檔案
LiteRT 模型可能附有不同的相關聯檔案。舉例來說,自然語言模型通常會有將字詞片段對應至字詞 ID 的字彙檔案;分類模型則可能有指出物件類別的標籤檔案。如果沒有相關聯的檔案 (如有),模型就無法正常運作。
現在可透過中繼資料 Python 程式庫,將相關聯的檔案與模型一併封裝。新的 LiteRT 模型會變成 ZIP 檔案,內含模型和相關聯的檔案。您可以使用常見的 ZIP 工具解壓縮。這個新模型格式仍使用相同的檔案副檔名 .tflite。與現有的 TFLite 架構和解譯器相容。詳情請參閱將中繼資料和相關聯的檔案封裝到模型中。
相關檔案資訊可以記錄在中繼資料中。視檔案類型和附加檔案的位置 (即 ModelMetadata、SubGraphMetadata 和 TensorMetadata) 而定,LiteRT Android 程式碼產生器可能會自動對物件套用對應的前/後處理程序。詳情請參閱結構定義中每個關聯檔案類型的「<Codegen usage>」部分。
正規化和量化參數
正規化是機器學習中常見的資料預先處理技術。正規化的目標是將值變更為通用比例,但不會扭曲值範圍的差異。
模型量化技術可降低權重的精確度,並視需要降低儲存和運算時的啟用次數。
就預先處理和後續處理而言,正規化和量化是兩個獨立的步驟。以下是問題的詳細說明:
| 正規化 | 量化 | |
|---|---|---|
MobileNet 中輸入圖片的參數值範例,分別適用於浮點和量化模型。 |
浮點模型: - 平均值:127.5 - 標準差:127.5 量化模型: - 平均值:127.5 - 標準差:127.5 |
浮點模型: - zeroPoint:0 - scale:1.0 量化模型: - zeroPoint:128.0 - scale:0.0078125f |
何時叫用? |
輸入:如果訓練資料已正規化,推論資料也必須相應正規化。 輸出內容:輸出資料一般不會經過正規化。 |
浮點模型不需要量化。 量化模型可能需要或不需要在預先/後續處理中量化。這取決於輸入/輸出張量的資料類型。 - 浮點張量:前/後處理不需要量化。量化作業和去量化作業會併入模型圖表。 - int8/uint8 張量: 需要在前/後處理中量化。 |
公式 |
normalized_input = (input - mean) / std |
輸入量化:
q = f / scale + zeroPoint 輸出反量化: f = (q - zeroPoint) * scale |
參數位置 |
由模型建立者填寫,並以 NormalizationOptions 格式儲存在模型中繼資料中 |
由 TFLite 轉換工具自動填入,並儲存在 tflite 模型檔案中。 |
| 如何取得參數? | 透過 MetadataExtractor API
[2]
|
透過 TFLite Tensor API [1] 或 MetadataExtractor API [2] |
| 浮點數和量化模型是否共用相同的值? | 是,浮點數和量化模型具有相同的標準化參數 | 不需要,浮點模型不需要量化。 |
| TFLite 程式碼產生器或 Android Studio 機器學習繫結是否會在資料處理時自動產生這項資訊? | 是 |
是 |
[1] LiteRT Java API 和 LiteRT 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
下列程式碼會將模型資訊與輸入和輸出資訊合併:
# 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()
您可以透過 load_associated_files 將任意數量的相關檔案封裝到模型中。不過,您必須封裝中繼資料中記錄的檔案。在本範例中,必須封裝標籤檔案。
視覺化呈現中繼資料
您可以使用 Netron 將中繼資料視覺化,也可以使用 MetadataDisplayer 將 LiteRT 模型中的中繼資料讀取為 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 繫結功能顯示中繼資料。
中繼資料版本控管
中繼資料結構定義會依據語意版本編號 (追蹤結構定義檔案的變更) 和 Flatbuffers 檔案識別 (指出實際的版本相容性) 進行版本控管。
語意化版本編號
中繼資料結構定義會以語意化版本號碼 (例如 MAJOR.MINOR.PATCH) 進行版本管理。系統會根據這裡的規則追蹤結構定義變更。請參閱版本 1.0.0 後新增的欄位記錄。
Flatbuffers 檔案識別
如果遵循規則,語意版本控管可確保相容性,但這並不代表真正的不相容。調升 MAJOR 編號時,不一定表示回溯相容性會中斷。因此,我們會使用 Flatbuffers 檔案識別資訊 (file_identifier),表示中繼資料結構定義的實際相容性。檔案 ID 長度必須為 4 個字元。這項設定會固定為特定中繼資料結構定義,使用者無法變更。如果因故必須打破中繼資料架構的回溯相容性,file_identifier 就會增加,例如從「M001」變成「M002」。預期 file_identifier 的變更頻率會遠低於 metadata_version。
中繼資料剖析器最低必要版本
必要的中繼資料剖析器最低版本是指可完整讀取中繼資料 Flatbuffers 的中繼資料剖析器 (Flatbuffers 生成的程式碼) 最低版本。這個版本實際上是所有填入欄位版本中最大的版本號碼,以及檔案 ID 指出的最小相容版本。將中繼資料填入 TFLite 模型時,MetadataPopulator會自動填入必要的中繼資料剖析器最低版本。如要進一步瞭解如何使用最低必要的中繼資料剖析器版本,請參閱中繼資料擷取器。
讀取模型中的中繼資料
中繼資料擷取器程式庫是便利的工具,可從不同平台上的模型讀取中繼資料和相關聯的檔案 (請參閱 Java 版本和 C++ 版本)。您可以使用 Flatbuffers 程式庫,以其他語言建構自己的中繼資料擷取工具。
在 Java 中讀取中繼資料
如要在 Android 應用程式中使用 Metadata Extractor 程式庫,建議使用 MavenCentral 託管的 LiteRT Metadata AAR。其中包含 MetadataExtractor 類別,以及 中繼資料結構定義和模型結構定義的 FlatBuffers Java 繫結。
您可以在 build.gradle 依附元件中指定此項目,如下所示:
dependencies {
implementation 'org.tensorflow:tensorflow-lite-metadata:0.1.0'
}
如要使用每晚快照,請務必新增 Sonatype 快照存放區。
您可以使用指向模型的 ByteBuffer 初始化 MetadataExtractor 物件:
public MetadataExtractor(ByteBuffer buffer);
ByteBuffer 在整個 MetadataExtractor 物件的生命週期內都不得變更。如果模型中繼資料的 Flatbuffers 檔案 ID 與中繼資料剖析器不符,初始化作業可能會失敗。詳情請參閱中繼資料版本管理。
有了相符的檔案 ID,中繼資料擷取器就能透過 Flatbuffers 的向前和向後相容機制,順利讀取所有過去和未來結構定義產生的中繼資料。不過,舊版中繼資料擷取工具無法擷取未來架構的欄位。中繼資料的最低必要剖析器版本,是指可完整讀取中繼資料 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 檔案,可使用常見的 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;