ML 元数据

ML 元数据 (MLMD) 是一个用于记录和检索与 ML 开发人员和数据科学家工作流程相关的元数据的库。MLMD 是 TensorFlow Extended (TFX) 的组成部分,但设计为可以独立使用。

生产 ML 管道的每次运行都会生成包含有关各种管道组件、其执行(例如训练运行)和生成的工件(例如训练后的模型)的信息的元数据。如果管道出现意外行为或错误,可以使用此元数据来分析管道组件的谱系并调试问题。将此元数据视为软件开发中的日志记录等效项。

MLMD 帮助您了解和分析 ML 管道的相互关联的部分,而不是孤立地分析它们,并且可以帮助您回答有关 ML 管道的问题,例如

  • 模型是在哪个数据集上训练的?
  • 用于训练模型的超参数是什么?
  • 哪个管道运行创建了模型?
  • 哪个训练运行导致了此模型?
  • 哪个版本的 TensorFlow 创建了此模型?
  • 何时推送了失败的模型?

元数据存储

MLMD 在名为 **元数据存储** 的数据库中注册以下类型的元数据。

  1. 有关通过 ML 管道的组件/步骤生成的工件的元数据
  2. 有关这些组件/步骤执行的元数据
  3. 有关管道和相关谱系信息的元数据

元数据存储提供 API 用于将元数据记录到存储后端以及从存储后端检索元数据。存储后端是可插拔的,可以扩展。MLMD 提供了 SQLite(支持内存和磁盘)和 MySQL 的参考实现。

此图形显示了 MLMD 中各个组件的高级概述。

ML Metadata Overview

元数据存储后端和存储连接配置

MetadataStore 对象接收与使用的存储后端相对应的连接配置。

  • **假数据库** 提供内存中 DB(使用 SQLite)以进行快速实验和本地运行。数据库在存储对象被销毁时被删除。
import ml_metadata as mlmd
from ml_metadata.metadata_store import metadata_store
from ml_metadata.proto import metadata_store_pb2

connection_config = metadata_store_pb2.ConnectionConfig()
connection_config.fake_database.SetInParent() # Sets an empty fake database proto.
store = metadata_store.MetadataStore(connection_config)
  • **SQLite** 从磁盘读取和写入文件。
connection_config = metadata_store_pb2.ConnectionConfig()
connection_config.sqlite.filename_uri = '...'
connection_config.sqlite.connection_mode = 3 # READWRITE_OPENCREATE
store = metadata_store.MetadataStore(connection_config)
  • **MySQL** 连接到 MySQL 服务器。
connection_config = metadata_store_pb2.ConnectionConfig()
connection_config.mysql.host = '...'
connection_config.mysql.port = '...'
connection_config.mysql.database = '...'
connection_config.mysql.user = '...'
connection_config.mysql.password = '...'
store = metadata_store.MetadataStore(connection_config)

类似地,当使用 Google CloudSQL 的 MySQL 实例时(快速入门连接概述),如果适用,也可以使用 SSL 选项。

connection_config.mysql.ssl_options.key = '...'
connection_config.mysql.ssl_options.cert = '...'
connection_config.mysql.ssl_options.ca = '...'
connection_config.mysql.ssl_options.capath = '...'
connection_config.mysql.ssl_options.cipher = '...'
connection_config.mysql.ssl_options.verify_server_cert = '...'
store = metadata_store.MetadataStore(connection_config)
  • **PostgreSQL** 连接到 PostgreSQL 服务器。
connection_config = metadata_store_pb2.ConnectionConfig()
connection_config.postgresql.host = '...'
connection_config.postgresql.port = '...'
connection_config.postgresql.user = '...'
connection_config.postgresql.password = '...'
connection_config.postgresql.dbname = '...'
store = metadata_store.MetadataStore(connection_config)

类似地,当使用 Google CloudSQL 的 PostgreSQL 实例时(快速入门连接概述),如果适用,也可以使用 SSL 选项。

connection_config.postgresql.ssloption.sslmode = '...' # disable, allow, verify-ca, verify-full, etc.
connection_config.postgresql.ssloption.sslcert = '...'
connection_config.postgresql.ssloption.sslkey = '...'
connection_config.postgresql.ssloption.sslpassword = '...'
connection_config.postgresql.ssloption.sslrootcert = '...'
store = metadata_store.MetadataStore(connection_config)

数据模型

元数据存储使用以下数据模型来记录和检索存储后端的元数据。

  • ArtifactType 描述了工件的类型及其存储在元数据存储中的属性。您可以在代码中使用元数据存储动态注册这些类型,也可以从序列化格式中将它们加载到存储中。注册类型后,其定义在存储的整个生命周期内都可用。
  • Artifact 描述了 ArtifactType 的特定实例,以及写入元数据存储的属性。
  • 一个 ExecutionType 描述了工作流中组件或步骤的类型及其运行时参数。
  • 一个 Execution 是组件运行或 ML 工作流中步骤的记录,以及运行时参数。可以将执行视为 ExecutionType 的实例。当您运行 ML 管道或步骤时,会记录执行。
  • 一个 Event 是工件和执行之间关系的记录。当执行发生时,事件会记录执行使用的每个工件以及产生的每个工件。这些记录允许在整个工作流中进行血缘跟踪。通过查看所有事件,MLMD 知道发生了哪些执行以及由此创建了哪些工件。然后,MLMD 可以从任何工件递归回其所有上游输入。
  • 一个 ContextType 描述了工作流中工件和执行的概念性分组类型及其结构属性。例如:项目、管道运行、实验、所有者等。
  • 一个 ContextContextType 的实例。它捕获组内的共享信息。例如:项目名称、变更列表提交 ID、实验注释等。它在其 ContextType 中具有用户定义的唯一名称。
  • 一个 Attribution 是工件和上下文之间关系的记录。
  • 一个 Association 是执行和上下文之间关系的记录。

MLMD 功能

跟踪 ML 工作流中所有组件/步骤的输入和输出及其血缘关系,使 ML 平台能够实现一些重要功能。以下列表提供了对一些主要优势的非详尽概述。

  • 列出特定类型的全部工件。 例如:所有已训练的模型。
  • 加载两种相同类型的工件以进行比较。 例如:比较两个实验的结果。
  • 显示上下文的所有相关执行及其输入和输出工件的 DAG。 例如:可视化实验的工作流以进行调试和发现。
  • 通过所有事件递归回溯以查看工件的创建方式。 例如:查看哪些数据进入了模型;执行数据保留计划。
  • 识别使用给定工件创建的所有工件。 例如:查看使用特定数据集训练的所有模型;根据不良数据标记模型。
  • 确定执行是否之前在相同输入上运行过。 例如:确定组件/步骤是否已完成相同的工作,并且可以重用之前的输出。
  • 记录和查询工作流运行的上下文。 例如:跟踪工作流运行使用的所有者和变更列表;按实验对血缘关系进行分组;按项目管理工件。
  • 对属性和 1 跳邻域节点的声明性节点过滤功能。 例如:查找特定类型且在某些管道上下文下的工件;返回类型为给定属性的值在一定范围内的工件;查找上下文中具有相同输入的先前执行。

请参阅 MLMD 教程,了解如何使用 MLMD API 和元数据存储来检索血缘信息。

将 ML 元数据集成到您的 ML 工作流中

如果您是希望将 MLMD 集成到您的系统中的平台开发人员,请使用以下示例工作流来使用低级 MLMD API 跟踪训练任务的执行。您也可以在笔记本环境中使用更高级别的 Python API 来记录实验元数据。

ML Metadata Example Flow

1) 注册工件类型

# Create ArtifactTypes, e.g., Data and Model
data_type = metadata_store_pb2.ArtifactType()
data_type.name = "DataSet"
data_type.properties["day"] = metadata_store_pb2.INT
data_type.properties["split"] = metadata_store_pb2.STRING
data_type_id = store.put_artifact_type(data_type)

model_type = metadata_store_pb2.ArtifactType()
model_type.name = "SavedModel"
model_type.properties["version"] = metadata_store_pb2.INT
model_type.properties["name"] = metadata_store_pb2.STRING
model_type_id = store.put_artifact_type(model_type)

# Query all registered Artifact types.
artifact_types = store.get_artifact_types()

2) 为 ML 工作流中的所有步骤注册执行类型

# Create an ExecutionType, e.g., Trainer
trainer_type = metadata_store_pb2.ExecutionType()
trainer_type.name = "Trainer"
trainer_type.properties["state"] = metadata_store_pb2.STRING
trainer_type_id = store.put_execution_type(trainer_type)

# Query a registered Execution type with the returned id
[registered_type] = store.get_execution_types_by_id([trainer_type_id])

3) 创建 DataSet ArtifactType 的工件

# Create an input artifact of type DataSet
data_artifact = metadata_store_pb2.Artifact()
data_artifact.uri = 'path/to/data'
data_artifact.properties["day"].int_value = 1
data_artifact.properties["split"].string_value = 'train'
data_artifact.type_id = data_type_id
[data_artifact_id] = store.put_artifacts([data_artifact])

# Query all registered Artifacts
artifacts = store.get_artifacts()

# Plus, there are many ways to query the same Artifact
[stored_data_artifact] = store.get_artifacts_by_id([data_artifact_id])
artifacts_with_uri = store.get_artifacts_by_uri(data_artifact.uri)
artifacts_with_conditions = store.get_artifacts(
      list_options=mlmd.ListOptions(
          filter_query='uri LIKE "%/data" AND properties.day.int_value > 0'))

4) 创建 Trainer 运行的执行

# Register the Execution of a Trainer run
trainer_run = metadata_store_pb2.Execution()
trainer_run.type_id = trainer_type_id
trainer_run.properties["state"].string_value = "RUNNING"
[run_id] = store.put_executions([trainer_run])

# Query all registered Execution
executions = store.get_executions_by_id([run_id])
# Similarly, the same execution can be queried with conditions.
executions_with_conditions = store.get_executions(
    list_options = mlmd.ListOptions(
        filter_query='type = "Trainer" AND properties.state.string_value IS NOT NULL'))

5) 定义输入事件并读取数据

# Define the input event
input_event = metadata_store_pb2.Event()
input_event.artifact_id = data_artifact_id
input_event.execution_id = run_id
input_event.type = metadata_store_pb2.Event.DECLARED_INPUT

# Record the input event in the metadata store
store.put_events([input_event])

6) 声明输出工件

# Declare the output artifact of type SavedModel
model_artifact = metadata_store_pb2.Artifact()
model_artifact.uri = 'path/to/model/file'
model_artifact.properties["version"].int_value = 1
model_artifact.properties["name"].string_value = 'MNIST-v1'
model_artifact.type_id = model_type_id
[model_artifact_id] = store.put_artifacts([model_artifact])

7) 记录输出事件

# Declare the output event
output_event = metadata_store_pb2.Event()
output_event.artifact_id = model_artifact_id
output_event.execution_id = run_id
output_event.type = metadata_store_pb2.Event.DECLARED_OUTPUT

# Submit output event to the Metadata Store
store.put_events([output_event])

8) 将执行标记为已完成

trainer_run.id = run_id
trainer_run.properties["state"].string_value = "COMPLETED"
store.put_executions([trainer_run])

9) 使用属性和断言工件将工件和执行分组到上下文下

# Create a ContextType, e.g., Experiment with a note property
experiment_type = metadata_store_pb2.ContextType()
experiment_type.name = "Experiment"
experiment_type.properties["note"] = metadata_store_pb2.STRING
experiment_type_id = store.put_context_type(experiment_type)

# Group the model and the trainer run to an experiment.
my_experiment = metadata_store_pb2.Context()
my_experiment.type_id = experiment_type_id
# Give the experiment a name
my_experiment.name = "exp1"
my_experiment.properties["note"].string_value = "My first experiment."
[experiment_id] = store.put_contexts([my_experiment])

attribution = metadata_store_pb2.Attribution()
attribution.artifact_id = model_artifact_id
attribution.context_id = experiment_id

association = metadata_store_pb2.Association()
association.execution_id = run_id
association.context_id = experiment_id

store.put_attributions_and_associations([attribution], [association])

# Query the Artifacts and Executions that are linked to the Context.
experiment_artifacts = store.get_artifacts_by_context(experiment_id)
experiment_executions = store.get_executions_by_context(experiment_id)

# You can also use neighborhood queries to fetch these artifacts and executions
# with conditions.
experiment_artifacts_with_conditions = store.get_artifacts(
    list_options = mlmd.ListOptions(
        filter_query=('contexts_a.type = "Experiment" AND contexts_a.name = "exp1"')))
experiment_executions_with_conditions = store.get_executions(
    list_options = mlmd.ListOptions(
        filter_query=('contexts_a.id = {}'.format(experiment_id))))

将 MLMD 与远程 gRPC 服务器一起使用

您可以将 MLMD 与远程 gRPC 服务器一起使用,如下所示

  • 启动服务器
bazel run -c opt --define grpc_no_ares=true  //ml_metadata/metadata_store:metadata_store_server

默认情况下,服务器使用每个请求的假内存数据库,并且不会跨调用持久化元数据。它也可以使用 MLMD MetadataStoreServerConfig 配置为使用 SQLite 文件或 MySQL 实例。该配置可以存储在文本 protobuf 文件中,并使用 --metadata_store_server_config_file=path_to_the_config_file 传递给二进制文件。

文本 protobuf 格式的示例 MetadataStoreServerConfig 文件

connection_config {
  sqlite {
    filename_uri: '/tmp/test_db'
    connection_mode: READWRITE_OPENCREATE
  }
}
  • 创建客户端存根并在 Python 中使用它
from grpc import insecure_channel
from ml_metadata.proto import metadata_store_pb2
from ml_metadata.proto import metadata_store_service_pb2
from ml_metadata.proto import metadata_store_service_pb2_grpc

channel = insecure_channel('localhost:8080')
stub = metadata_store_service_pb2_grpc.MetadataStoreServiceStub(channel)
  • 使用 MLMD 进行 RPC 调用
# Create ArtifactTypes, e.g., Data and Model
data_type = metadata_store_pb2.ArtifactType()
data_type.name = "DataSet"
data_type.properties["day"] = metadata_store_pb2.INT
data_type.properties["split"] = metadata_store_pb2.STRING

request = metadata_store_service_pb2.PutArtifactTypeRequest()
request.all_fields_match = True
request.artifact_type.CopyFrom(data_type)
stub.PutArtifactType(request)

model_type = metadata_store_pb2.ArtifactType()
model_type.name = "SavedModel"
model_type.properties["version"] = metadata_store_pb2.INT
model_type.properties["name"] = metadata_store_pb2.STRING

request.artifact_type.CopyFrom(model_type)
stub.PutArtifactType(request)

资源

MLMD 库具有一个高级 API,您可以轻松地将其与您的 ML 管道一起使用。请参阅 MLMD API 文档 以了解更多详细信息。

查看 MLMD 声明性节点过滤,了解如何使用 MLMD 声明性节点过滤功能对属性和 1 跳邻域节点进行过滤。

还可以查看 MLMD 教程,了解如何使用 MLMD 追踪管道组件的血缘关系。

MLMD 提供实用程序来处理跨版本的架构和数据迁移。请参阅 MLMD 指南 以了解更多详细信息。