此页面由 Cloud Translation API 翻译。
Switch to English

向TensorFlow Lite模型添加元数据

TensorFlow Lite元数据提供了模型描述的标准。元数据是有关模型功能及其输入/输出信息的重要知识来源。元数据包含两者

TensorFlow Lite托管模型TensorFlow Hub上发布的所有图像模型均已填充了元数据。

设置元数据工具

在将元数据添加到模型之前,您需要安装Python编程环境以运行TensorFlow。有关于如何设置此的详细指南这里

设置Python编程环境后,您将需要安装其他工具:

pip install tflite-support

TensorFlow Lite元数据工具支持Python 2和Python 3。

添加元数据

有三个部分的模型元数据架构

  1. 型号信息 -型号以及许可条款等项目的总体说明。请参阅ModelMetadata
  2. 输入信息 - 输入的描述和所需的预处理,例如标准化。请参见SubGraphMetadata.input_tensor_metadata
  3. 输出信息 -对输出和后处理的描述,例如映射到标签。请参见SubGraphMetadata.output_tensor_metadata

由于TensorFlow Lite此时仅支持单个子图,因此在显示元数据并生成代码时, TensorFlow Lite代码生成器Android Studio ML绑定功能将使用ModelMetadata.nameModelMetadata.description代替SubGraphMetadata.nameSubGraphMetadata.description

支持的输入/输出类型

用于输入和输出的TensorFlow Lite元数据在设计时并未考虑特定的模型类型,而是考虑了输入和输出类型。只要输入和输出类型包含以下内容或以下内容的组合,TensorFlow Lite元数据都支持该模型,那么该模型在功能上的作用并不重要:

  • 功能-数字为无符号整数或float32。
  • 图像-元数据当前支持RGB和灰度图像。
  • 边界框-矩形边界框。该模式支持多种编号方案

打包相关文件

TensorFlow Lite模型可能随附不同的关联文件。例如,自然语言模型通常具有vocab文件,这些文件将单词片段映射到单词ID。分类模型可能具有指示对象类别的标签文件。没有关联的文件(如果有),模型将无法正常运行。

现在,关联的文件可以通过元数据Python库与模型捆绑在一起。新的TensorFlow Lite模型将成为一个包含模型和关联文件的zip文件。可以使用常用的拉链工具打开包装。这种新的模型格式继续使用相同的文件扩展名.tflite 。它与现有的TFLite框架和解释器兼容。有关更多详细信息,请参见将mtadata和关联文件打包到模型中。

关联的文件信息可以在元数据中记录。根据文件类型和文件的附加位置(即ModelMetadataSubGraphMetadataTensorMetadata ), TensorFlow Lite Android代码生成器可能会自动将相应的预处理/后处理应用于对象。有关更多详细信息,请参见架构中每个关联文件类型的<Codegen用法>部分

归一化和量化参数

规范化是机器学习中常见的数据预处理技术。标准化的目的是将值更改为通用标度,而不会扭曲值范围的差异。

模型量化是一种技术,可以降低权重的精确度,并可以选择激活存储和计算。

就预处理和后处理而言,归一化和量化是两个独立的步骤。这是详细信息。

正常化量化

MobileNet中分别针对浮点模型和定量模型的输入图像的参数值示例。
浮子模型
-均值:127.5
-标准:127.5
数量模型
-均值:127.5
-标准:127.5
浮子模型
-零点:0
-比例:1.0
数量模型
-零点:128.0
-规模:0.0078125f




什么时候调用?


输入 :如果在训练中对输入数据进行了归一化,则需要对推断的输入数据进行相应的归一化。
输出 :通常不会对输出数据进行规范化。
浮点模型不需要量化。
量化的模型在前/后处理中可能需要量化,也可能不需要。它取决于输入/输出张量的数据类型。
-浮点张量:不需要在前/后处理中进行量化。 Quant op和dequant op被烘焙到模型图中。
-int8 / uint8张量:在前/后处理中需要量化。




normalized_input =(输入-平均值)/ std
量化输入
q = f /比例+零点
减少产出
f =(q-zeroPoint)*比例

参数在哪里
由模型创建者填充并存储在模型元数据中,作为NormalizationOptions 由TFLite转换器自动填充,并存储在tflite模型文件中。
如何获取参数? 通过MetadataExtractor API [2] 通过TFLite Tensor API [1]或通过MetadataExtractor API [2]
浮点模型和定量模型共享相同的值吗? 是的,浮点模型和定量模型具有相同的归一化参数不,浮动模型不需要量化。
TFLite代码生成器或Android Studio ML绑定是否会在数据处理中自动生成它?

[1] TensorFlow Lite Java APITensorFlow Lite 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.")

输入/输出信息

本节向您展示如何描述模型的输入和输出签名。自动代码生成器可以使用此元数据来创建预处理和后处理代码。创建有关张​​量的输入或输出信息:

f5b29​​53ca9

影像输入

图像是机器学习的常见输入类型。 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()

将元数据和关联文件打包到模型中

一旦创建了元数据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将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绑定功能显示元数据。

元数据版本控制

通过跟踪版本文件更改的语义版本号和通过Flatbuffers文件标识(指示真正的版本兼容性)对元数据模式进行版本控制。

语义版本号

元数据模式通过语义版本号 (例如MAJOR.MINOR.PATCH)进行版本控制 。它根据此处的规则跟踪架构更改。请参阅版本1.0.0之后添加的字段历史记录

Flatbuffers文件标识

如果遵循规则,语义版本控制可确保兼容性,但并不表示真正的不兼容性。当提高主号码时,并不一定意味着向后兼容性被破坏。因此,我们使用Flatbuffers文件标识 file_identifiler来表示元数据架构的真正兼容性。文件标识符的长度为4个字符。它固定于特定的元数据架构,并且不受用户更改。如果由于某种原因必须中断元数据模式的向后兼容性,则file_identifier会从“ M001”变为“ M002”。与元数据版本相比,预期File_identifiler的更改频率要低得多。

最低必需的元数据解析器版本

最低必需的元数据解析器版本是可以完整读取元数据Flatbuffers的最低元数据解析器版本 (Flatbuffers生成的代码)。该版本实际上是所填充的所有字段的版本中最大的版本号,并且是文件标识符所指示的最小的兼容版本。当将元数据填充到TFLite模型中时,最低必需的元数据解析器版本将由MetadataPopulator自动填充。有关如何使用最低必需的元数据解析器版本的更多信息,请参见元数据提取器

从模型中读取元数据

Metadata Extractor库是方便的工具,可以从跨不同平台的模型中读取元数据和关联的文件(请参阅Java版本C ++版本 )。您可以使用Flatbuffers库以其他语言构建自己的元数据提取器工具。

读取Java中的元数据

要在您的Android应用中使用Metadata Extractor库,我们建议使用JCenter托管TensorFlow Lite Metadata AAR 。它包含MetadataExtractor类,以及元数据模式模型模式的FlatBuffers Java绑定。

您可以在build.gradle依赖项中指定以下内容:

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

您可以使用指向模型的ByteBuffer初始化MetadataExtractor对象:

67

MetadataExtractor对象的整个生命周期中, ByteBuffer必须保持不变。如果模型元数据的Flatbuffers文件标识符与元数据解析器的标识符不匹配,则初始化可能会失败。有关更多信息,请参见元数据版本控制

使用匹配的文件标识符,由于Flatbuffer的向前和向后兼容性机制,元数据提取器将成功读取从所有过去和将来的模式生成的元数据。但是,较旧的元数据提取器无法提取未来架构中的字段。元数据的最低必需解析器版本指示可以完全读取元数据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);

您还可以使用getAssociatedFile方法通过名称读取关联文件:

public InputStream getAssociatedFile(String fileName);

尽管TensorFlow Lite模型模式支持多个子图,但TFLite解释器当前仅支持单个子图。因此, MetadataExtractor在其方法中忽略了子图索引作为输入参数。