创建、使用、传递和跟踪机器学习工件
大多数机器学习流水线旨在创建一个或多个机器学习工件,例如模型、数据集、评估指标等。
KFP 通过 dsl.Artifact
类和其他工件子类提供对创建机器学习工件的一流支持。KFP 将这些工件映射到其底层 ML Metadata 模式标题,这是工件类型的规范名称。
总的来说,工件及其相关注解有以下几个目的
- 提供组件/流水线输入/输出类型的逻辑分组
- 提供一种方便的机制,通过任务的本地文件系统写入对象存储
- 启用创建 ML 工件的流水线的类型检查
- 通过特殊的 UI 渲染,使某些工件类型的内容易于观察
以下 training_component
演示了使用传统工件语法输入和输出工件的用法
from kfp.dsl import Input, Output, Dataset, Model
@dsl.component
def training_component(dataset: Input[Dataset], model: Output[Model]):
"""Trains an output Model on an input Dataset."""
with open(dataset.path) as f:
contents = f.read()
# ... train tf_model model on contents of dataset ...
tf_model.save(model.path)
model.metadata['framework'] = 'tensorflow'
此 training_component
执行以下操作
- 接受输入数据集并声明输出模型
- 从本地文件系统读取输入数据集的内容
- 训练模型(已省略)
- 将模型保存为组件输出
- 设置关于已保存模型的某些元数据
正如 training_component
所示,工件只是围绕某些工件属性的薄层包装,包括可读/写的 .path
和工件的 .metadata
。以下部分将详细描述这些属性和工件的其他方面。
工件属性
要创建和使用组件中的工件,您将使用工件实例上的可用属性。工件具有四个属性
name
,工件的名称(在 Vertex Pipelines 上不可覆盖)。.uri
,您的工件对象的位置。对于输入工件,这是对象当前所在的位置。对于输出工件,这是您将从组件内部写入工件的位置。.metadata
,关于工件的附加键值对。.path
,对应于工件.uri
的本地路径。
工件 .path
属性特别有用。当您将工件的内容写入由工件 .path
属性提供的位置时,流水线后端将自动处理将 .path
处的文件复制到 .uri
处的 URI,从而允许您仅通过与任务的本地文件系统交互来在组件内创建工件文件。
如本节其他示例中将更详细地看到的那样,这些属性在组件内的工件上都是可访问的
from kfp import dsl
from kfp.dsl import Dataset
from kfp.dsl import Input
@dsl.component
def print_artifact_properties(dataset: Input[Dataset]):
with open(dataset.path) as f:
lines = f.readlines()
print('Information about the artifact')
print('Name:', dataset.name)
print('URI:', dataset.uri)
print('Path:', dataset.path)
print('Metadata:', dataset.metadata)
return len(lines)
请注意,输入工件应被视为不可变。您不应尝试修改 .path
处文件的内容,对工件属性的任何更改都不会影响 ML Metadata 中工件的元数据。
组件中的工件
KFP SDK 支持两种形式的组件工件编写语法:传统语法和 Pythonic 语法。
传统工件编写语法是 KFP SDK 提供的原始工件编写样式。传统工件编写语法支持Python 组件和容器组件。它在运行时由开源 KFP 后端和 Google Cloud Vertex Pipelines 后端支持。
Pythonic 工件编写语法提供了一种替代的工件 I/O 语法,Python 开发人员对此很熟悉。Pythonic 工件编写语法仅支持Python 组件。此语法不支持容器组件。它目前仅在运行时由 Google Cloud Vertex Pipelines 后端支持。
传统工件语法
使用传统工件编写语法时,所有工件都作为输入提供给组件函数,并包装在 Input
或 Output
类型标记中。
def my_component(in_artifact: Input[Artifact], out_artifact: Output[Artifact]):
...
对于输入工件,您可以使用其 .uri
或 .path
属性读取工件。
对于输出工件,预先构建的输出工件将传递到组件中。您可以就地更新输出工件的属性,并将工件的内容写入工件的 .path
或 .uri
属性。您不应从组件中返回工件实例。例如
from kfp import dsl
from kfp.dsl import Dataset, Input, Model, Output
@dsl.component
def train_model(dataset: Input[Dataset], model: Output[Model]):
with open(dataset.path) as f:
dataset_lines = f.readlines()
# train a model
trained_model = ...
trained_model.save(model.path)
model.metadata['samples'] = len(dataset_lines)
新 Pythonic 工件语法
要使用 Pythonic 工件编写语法,只需像编写普通 Python 一样,使用工件类注解您的组件即可。
def my_component(in_artifact: Artifact) -> Artifact:
...
在组件主体内部,您可以读取作为输入传递的工件(与传统工件编写语法没有区别)。对于工件输出,您将在组件代码中构造工件,然后将工件作为输出返回。例如
from kfp import dsl
from kfp.dsl import Dataset, Model
@dsl.component
def train_model(dataset: Dataset) -> Model:
with open(dataset.path) as f:
dataset_lines = f.readlines()
# train a model
trained_model = ...
model_artifact = Model(uri=dsl.get_uri(), metadata={'samples': len(dataset_lines)})
trained_model.save(model_artifact.path)
return model_artifact
对于通常写入一个或多个文件的输出工件,可以在运行时使用 dsl.get_uri
函数获取与当前任务对应的唯一对象存储 URI。可选的 suffix
参数在组件具有多个工件输出时有助于避免路径冲突。
应类似于多个输出参数指定多个输出工件
from kfp import dsl
from kfp.dsl import Dataset, Model
from typing import NamedTuple
@dsl.component
def train_multiple_models(
dataset: Dataset,
) -> NamedTuple('outputs', model1=Model, model2=Model):
with open(dataset.path) as f:
dataset_lines = f.readlines()
# train a model
trained_model1 = ...
trained_model2 = ...
model_artifact1 = Model(uri=dsl.get_uri(suffix='model1'), metadata={'samples': len(dataset_lines)})
trained_model1.save(model_artifact1.path)
model_artifact2 = Model(uri=dsl.get_uri(suffix='model2'), metadata={'samples': len(dataset_lines)})
trained_model2.save(model_artifact2.path)
outputs = NamedTuple('outputs', model1=Model, model2=Model)
return outputs(model1=model_artifact1, model2=model_artifact2)
尚未支持
KFP 编排后端尚未支持 Pythonic 工件编写语法,但其他编排后端可能支持。
流水线中的工件
无论您的组件使用 Pythonic 还是传统工件编写语法,使用工件的流水线都应使用Pythonic 工件语法进行注解
def my_pipeline(in_artifact: Artifact) -> Artifact:
...
请参见以下流水线,该流水线接受 Dataset
作为输入并输出 Model
,从内部组件 train_model
中提取
from kfp import dsl
from kfp.dsl import Dataset, Model
@dsl.pipeline
def augment_and_train(dataset: Dataset) -> Model:
augment_task = augment_dataset(dataset=dataset)
return train_model(dataset=augment_task.output).output
KFP SDK 编译器将根据类型检查中描述的规则对工件用法进行类型检查。
请参见流水线基础知识以获取关于如何编写流水线的全面文档。
工件列表
KFP 支持输入工件列表,注解为 List[Artifact]
或 Input[List[Artifact]]
。这在使用 dsl.ParallelFor
和 dsl.Collected
控制流对象从任务循环中收集输出工件时很有用。
流水线还可以通过使用 -> List[Artifact]
返回注解并返回 dsl.Collected
实例来返回输出工件列表。
在流水线控制流:并行循环中描述了消费输入工件列表和从流水线返回输出工件列表。目前不支持从单步组件创建输出工件列表。
工件类型
工件注解指示工件的类型。KFP 在 DSL 中提供了几种工件类型
DSL 对象 | 工件模式标题 |
---|---|
Artifact | system.Artifact |
Dataset | system.Dataset |
Model | system.Model |
Metrics | system.Metrics |
ClassificationMetrics | system.ClassificationMetrics |
SlicedClassificationMetrics | system.SlicedClassificationMetrics |
HTML | system.HTML |
Markdown | system.Markdown |
Artifact
、Dataset
、Model
和 Metrics
是最通用和常用的工件类型。Artifact
是默认的工件基础类型,应用于工件类型不完全适合其他工件类别的情况。Artifact
也与所有其他工件类型兼容。从这个意义上说,Artifact
类型也是一个工件“任何”类型。
在KFP 开源 UI 上,ClassificationMetrics
、SlicedClassificationMetrics
、HTML
和 Markdown
提供特殊的 UI 渲染,使工件内容易于观察。