跳到主要内容

MLflow 项目

MLflow 项目是一种基于约定的、用于以可重用和可复现方式打包数据科学代码的格式。此外,Projects 组件还包含用于运行项目的 API 和命令行工具,可以将项目串联成工作流。

概述

核心而言,MLflow 项目只是一种组织和描述代码的约定,以便其他数据科学家(或自动化工具)能够运行它。每个项目都只是一个包含代码的文件目录或 Git 仓库。MLflow 可以根据在此目录中放置文件的约定来运行某些项目(例如,conda.yaml 文件被视为 Conda 环境),但您可以通过添加一个 MLproject 文件(一个 YAML 格式的文本文件)来更详细地描述您的项目。每个项目可以指定几个属性

名称

项目的可读名称。

入口点

可在项目中运行的命令,以及关于其参数的信息。大多数项目至少包含一个您希望其他用户调用的入口点。某些项目也可以包含多个入口点:例如,您可能有一个包含多个特征化算法的单一 Git 仓库。您还可以将项目中的任何 .py.sh 文件作为入口点调用。但是,如果您在 MLproject 文件中列出入口点,您还可以指定它们的参数,包括数据类型和默认值。

环境

应应用于执行项目入口点的软件环境。这包括项目代码所需的所有库依赖。有关 MLflow 项目支持的软件环境(包括 Conda 环境Virtualenv 环境Docker 容器)的更多信息,请参阅 项目环境

您可以使用 mlflow run 命令行工具或 mlflow.projects.run() Python API,从 Git URI 或本地目录运行任何项目。这些 API 还允许将项目提交到 DatabricksKubernetes 进行远程执行。

重要

默认情况下,MLflow 对 Git 项目使用新的临时工作目录。这意味着您通常应该使用绝对路径而非相对路径将任何文件参数传递给 MLflow 项目。如果您的项目声明了其参数,MLflow 会自动将类型为 path 的参数路径转换为绝对路径。

指定项目

默认情况下,任何 Git 仓库或本地目录都可以被视为 MLflow 项目;您可以将目录中包含的任何 bash 或 Python 脚本作为项目入口点调用。项目目录部分描述了 MLflow 如何将目录解释为项目。

为了提供对项目属性的额外控制,您还可以在项目的仓库或目录中包含一个 MLproject 文件

最后,MLflow 项目允许您指定用于执行项目入口点的软件环境

项目环境

MLflow 目前支持以下项目环境:Virtualenv 环境、conda 环境、Docker 容器环境和系统环境。

Virtualenv 环境(推荐)

Virtualenv 环境支持 PyPI 上可用的 Python 包。当 MLflow 项目指定 Virtualenv 环境时,MLflow 将使用 pyenv 下载指定版本的 Python,并使用 virtualenv 创建一个包含项目依赖的隔离环境,在运行项目代码之前激活该环境作为执行环境。

您可以通过在 MLproject 文件中包含 python_env 条目来为 MLflow 项目指定 Virtualenv 环境。有关详细信息,请参阅项目目录指定环境部分。

Docker 容器环境

Docker 容器允许您捕获非 Python 依赖项,例如 Java 库。

当您运行指定 Docker 镜像的 MLflow 项目时,MLflow 会按照 MLproject 文件中指定的参数原样运行您的镜像。在这种情况下,您需要预先构建包含环境和代码的镜像才能运行它。要使用基于您的镜像并在 /mlflow/projects/code 目录中包含项目内容的新镜像运行项目,请在运行 mlflow run 时使用 --build-image 标志。

环境变量,例如 MLFLOW_TRACKING_URI,在项目执行期间会传播到 Docker 容器内部。此外,项目创建的运行和实验会保存到您的跟踪 URI 指定的跟踪服务器。当针对本地跟踪 URI 运行时,MLflow 会将主机系统的跟踪目录(例如,本地的 mlruns 目录)挂载到容器内部,以便项目执行期间记录的指标、参数和工件可在之后访问。

有关具有 Docker 环境的 MLflow 项目示例,请参阅使用 MLflow 进行 Docker 化模型训练

要指定 Docker 容器环境,您必须在项目中添加一个 MLproject 文件。有关在 MLproject 文件中指定 Docker 容器环境的信息,请参阅指定环境

Conda 环境

Conda 环境支持 Python 包和本地库(例如,CuDNN 或 Intel MKL)。当 MLflow 项目指定 Conda 环境时,会在运行项目代码之前激活该环境。

警告

使用 conda,您有责任遵守 Anaconda 的服务条款

默认情况下,MLflow 使用系统路径查找并运行 conda 二进制文件。您可以通过设置 MLFLOW_CONDA_HOME 环境变量来使用不同的 Conda 安装;在这种情况下,MLflow 会尝试运行 $MLFLOW_CONDA_HOME/bin/conda 路径下的二进制文件。

您可以通过在项目目录的根目录中包含 conda.yaml 文件或在 MLproject 文件中包含 conda_env 条目来为 MLflow 项目指定 Conda 环境。有关详细信息,请参阅项目目录指定环境部分。

mlflow run 命令支持将 conda 环境项目作为 virtualenv 环境项目运行。为此,请使用 --env-manager virtualenv 标志运行 mlflow run

mlflow run /path/to/conda/project --env-manager virtualenv
警告

当 conda 环境项目作为 virtualenv 环境项目执行时,conda 依赖将被忽略,只安装 pip 依赖。

系统环境

您也可以直接在当前系统环境中运行 MLflow 项目。所有项目的依赖必须在项目执行之前安装在您的系统上。系统环境是在运行时提供的。它不是 MLflow 项目目录内容或 MLproject 文件的一部分。有关在运行项目时使用系统环境的信息,请参阅运行项目部分中的 Environment 参数描述。

项目目录

当运行一个*不*包含 MLproject 文件的 MLflow 项目目录或仓库时,MLflow 使用以下约定来确定项目的属性

  • 项目的名称就是目录的名称。

  • 如果存在 conda.yaml 文件,Conda 环境就在其中指定。如果不存在 conda.yaml 文件,MLflow 在运行项目时会使用一个只包含 Python(具体来说,是 Conda 可用的最新 Python)的 Conda 环境。

  • 项目中的任何 .py.sh 文件都可以是入口点。MLflow 使用 Python 执行扩展名为 .py 的入口点,并使用 bash 执行扩展名为 .sh 的入口点。有关在运行时指定项目入口点的更多信息,请参阅运行项目

  • 默认情况下,当未包含 MLproject 文件时,入口点没有任何参数。可以通过 mlflow run 命令行工具mlflow.projects.run() Python API 在运行时提供参数。运行时参数使用 --key value 语法通过命令行传递给入口点。有关运行项目和运行时参数的更多信息,请参阅运行项目

MLproject 文件

通过在项目的根目录中添加一个 MLproject 文件(一个 YAML 语法的文本文件),您可以更好地控制 MLflow 项目。以下是 MLproject 文件示例

name: My Project

python_env: python_env.yaml
# or
# conda_env: my_env.yaml
# or
# docker_env:
# image: mlflow-docker-example

entry_points:
main:
parameters:
data_file: path
regularization: { type: float, default: 0.1 }
command: "python train.py -r {regularization} {data_file}"
validate:
parameters:
data_file: path
command: "python validate.py {data_file}"

该文件可以指定名称和 Conda 或 Docker 环境,以及每个入口点的更详细信息。具体来说,每个入口点定义了要运行的命令要传递给命令的参数(包括数据类型)。

指定环境

本节描述如何在 MLproject 文件中指定 Conda 和 Docker 容器环境。MLproject 文件不能*同时*指定 Conda 环境和 Docker 环境。

Virtualenv 环境

MLproject 文件中包含一个顶级 python_env 条目。此条目的值必须是 MLflow 项目目录中 python_env YAML 文件的*相对*路径。以下是包含 python_env 定义的 MLProject 文件示例

python_env: files/config/python_env.yaml

python_env 指的是位于 <MLFLOW_PROJECT_DIRECTORY>/files/config/python_env.yaml 的环境文件,其中 <MLFLOW_PROJECT_DIRECTORY> 是 MLflow 项目的根目录路径。

以下是 python_env.yaml 文件示例

# Python version required to run the project.
python: "3.8.15"
# Dependencies required to build packages. This field is optional.
build_dependencies:
- pip
- setuptools
- wheel==0.37.1
# Dependencies required to run the project.
dependencies:
- mlflow==2.3
- scikit-learn==1.0.2

Conda 环境

MLproject 文件中包含一个顶级 conda_env 条目。此条目的值必须是 MLflow 项目目录中Conda 环境 YAML 文件的*相对*路径。在以下示例中

conda_env: files/config/conda_environment.yaml

conda_env 指的是位于 <MLFLOW_PROJECT_DIRECTORY>/files/config/conda_environment.yaml 的环境文件,其中 <MLFLOW_PROJECT_DIRECTORY> 是 MLflow 项目的根目录路径。

Docker 容器环境

MLproject 文件中包含一个顶级 docker_env 条目。此条目的值必须是执行项目系统上可访问的 Docker 镜像名称;此镜像名称可以包含注册表路径和标签。以下是几个示例。

示例 1:不带注册表路径的镜像

docker_env:
image: mlflow-docker-example-environment

在此示例中,docker_env 指的是名称为 mlflow-docker-example-environment 且默认标签为 latest 的 Docker 镜像。由于未指定注册表路径,Docker 会在运行 MLflow 项目的系统上搜索此镜像。如果未找到镜像,Docker 会尝试从DockerHub 拉取。

示例 2:挂载卷并指定环境变量

您还可以在 Docker 镜像中指定要挂载的本地卷(通常使用 Docker 的 -v 选项),以及额外的环境变量(根据 Docker 的 -e 选项)。环境变量可以从主机系统的环境变量中复制,也可以指定为 Docker 环境的新变量。environment 字段应该是一个列表。此列表中的元素可以是包含两个字符串的列表(用于定义新变量),也可以是单个字符串(用于从主机系统复制变量)。例如

docker_env:
image: mlflow-docker-example-environment
volumes: ["/local/path:/container/mount/path"]
environment: [["NEW_ENV_VAR", "new_var_value"], "VAR_TO_COPY_FROM_HOST_ENVIRONMENT"]

在此示例中,我们的 Docker 容器将挂载一个额外的本地卷,并包含两个额外的环境变量:一个新定义的变量和一个从主机系统复制的变量。

示例 3:远程注册表中的镜像

docker_env:
image: 012345678910.dkr.ecr.us-west-2.amazonaws.com/mlflow-docker-example-environment:7.0

在此示例中,docker_env 指的是 Docker 注册表路径为 012345678910.dkr.ecr.us-west-2.amazonaws.com 的 Docker 镜像,其名称为 mlflow-docker-example-environment,标签为 7.0。此注册表路径对应于 Amazon ECR 注册表。当 MLflow 项目运行时,Docker 会尝试从指定的注册表拉取镜像。执行 MLflow 项目的系统必须具有从指定注册表拉取此镜像的凭据。

示例 4:构建新镜像

docker_env:
image: python:3.8
mlflow run ... --build-image

要构建一个基于指定镜像和项目目录中文件的新镜像,请使用 --build-image 参数。在上面的示例中,如果本地不存在 python:3.8 镜像,它将从 Docker Hub 拉取,并在此基础上构建一个新镜像。项目将在从此镜像创建的容器中执行。

命令语法

MLproject 文件中指定入口点时,命令可以是 Python 格式字符串语法中的任何字符串。入口点的 parameters 字段中声明的所有参数都会传递到此字符串中进行替换。如果您使用*未*在 parameters 字段中列出的额外参数调用项目,MLflow 会使用 --key value 语法传递它们,因此您可以使用 MLproject 文件仅声明参数子集的类型和默认值。

在替换命令中的参数之前,MLflow 会使用 Python 的 shlex.quote 函数对它们进行转义,因此您无需担心在命令字段中添加引号。

指定参数

MLflow 允许为每个参数指定数据类型和默认值。您可以通过编写以下内容仅指定数据类型

parameter_name: data_type

在您的 YAML 文件中,或者使用以下一种语法添加默认值(在 YAML 中等效)

parameter_name: {type: data_type, default: value}  # Short syntax

parameter_name: # Long syntax
type: data_type
default: value

MLflow 支持四种参数类型,其中一些会得到特殊处理(例如,下载数据到本地文件)。任何未声明的参数都被视为 string 类型。参数类型如下

string

文本字符串。

float

实数。MLflow 会验证参数是否为数字。

path

本地文件系统上的路径。MLflow 会将所有相对 path 参数转换为绝对路径。MLflow 还会将作为分布式存储 URI(如 s3://, dbfs://, gs:// 等)传递的任何路径下载到本地文件。对于只能读取本地文件的程序,请使用此类型。

uri

数据在本地或分布式存储系统中的 URI。MLflow 会将相对路径转换为绝对路径,与 path 类型一样。对于知道如何从分布式存储读取的程序(例如,使用 Spark 的程序),请使用此类型。

运行项目

MLflow 提供了两种运行项目的方式:mlflow run 命令行工具mlflow.projects.run() Python API。这两种工具都接受以下参数

项目 URI

本地文件系统上的目录或 Git 仓库路径,指定为 URI 形式,如 https://<repo>(使用 HTTPS)或 user@host:path(通过 SSH 使用 Git)。要针对项目子目录中的 MLproject 文件运行,请在 URI 参数末尾添加 '#',后跟从项目根目录到包含所需项目的子目录的相对路径。

项目版本

对于基于 Git 的项目,指 Git 仓库中的提交哈希或分支名称。

入口点

入口点的名称,默认为 main。您可以使用 MLproject 文件中命名的任何入口点,或项目中的任何 .py.sh 文件,路径从项目根目录给出(例如,src/test.py)。

参数

键值参数。任何具有声明类型的参数都会进行验证和转换(如果需要)。

部署模式

  • 命令行和 API 都允许您在 Databricks 环境中远程启动项目。这包括设置集群参数,例如 VM 类型。当然,您也可以使用 mlflow run 命令的本地版本在您选择的任何其他计算基础设施上运行项目(例如,将执行 mlflow run 的脚本提交到标准的作业排队系统)。

  • 您也可以使用 mlflow run 命令行工具在 Kubernetes 集群上远程启动项目(请参阅在 Kubernetes 上运行 MLflow 项目)。

环境

默认情况下,MLflow 项目在项目目录或 MLproject 文件指定的环境中运行(参见指定项目环境)。您可以通过提供 --env-manager=local 标志来忽略项目指定的环境并在当前系统环境中运行项目,但这可能导致意外结果,如果项目环境和当前系统环境之间存在依赖不匹配。

例如,教程创建并发布了一个训练线性模型的 MLflow 项目。该项目也发布在 GitHub 上:https://github.com/mlflow/mlflow-example。要运行此项目

mlflow run git@github.com:mlflow/mlflow-example.git -P alpha=0.5

还有其他选项可以禁用 Conda 环境的创建,如果您想在现有 shell 环境中快速测试项目,这会很有用。

在 Databricks 上运行 MLflow 项目

您可以在 Databricks 上远程运行 MLflow 项目。要使用此功能,您必须拥有企业版 Databricks 帐户并已设置 Databricks CLI。请在 Databricks 文档中查找详细说明(Azure DatabricksDatabricks on AWS)。

在 Kubernetes 上运行 MLflow 项目

您可以在 Kubernetes 上运行具有Docker 环境的 MLflow 项目。以下各节提供了此功能的概述,包括带示例的简单项目执行指南。

要了解此功能的实际应用,您还可以参阅Docker 示例,其中包含所需的 Kubernetes 后端配置(kubernetes_backend.json)和Kubernetes Job Speckubernetes_job_template.yaml)文件。

工作原理

当您在 Kubernetes 上运行 MLflow 项目时,MLflow 会构建一个新的 Docker 镜像,其中包含项目的内容;该镜像继承自项目的Docker 环境。然后,MLflow 会将新的项目镜像推送到您指定的 Docker 注册表,并在您指定的 Kubernetes 集群上启动一个Kubernetes Job。此 Kubernetes Job 会下载项目镜像并启动相应的 Docker 容器。最后,容器会调用项目的入口点,将参数、标签、指标和工件记录到您的MLflow 跟踪服务器

执行指南

您可以按照以下步骤在 Kubernetes 上运行 MLflow 项目

  1. 如果您的 MLflow 项目尚无 Docker 环境,请添加一个。有关参考信息,请参阅指定环境

  2. 创建一个包含以下条目的后端配置 JSON 文件

    • kube-context MLflow 将运行作业的Kubernetes 上下文。如果未提供,MLflow 将使用当前上下文。如果没有可用上下文,MLflow 将假定它在 Kubernetes 集群中运行,并将使用运行当前 pod 的 Kubernetes 服务帐户(“集群内”配置)。

    • repository-uri 将上传(推送)项目执行 Docker 镜像的 Docker 仓库 URI。您的 Kubernetes 集群必须能够访问此仓库才能运行 MLflow 项目。

    • kube-job-template-path 您的 Kubernetes Job 的 YAML 配置文件路径 - 一个Kubernetes Job Spec。MLflow 读取 Job Spec 并替换某些字段以方便作业执行和监控;MLflow 不会修改原始模板文件。有关与 MLflow 一起使用的 Kubernetes Job Spec 模板编写的更多信息,请参阅作业模板部分。

      Kubernetes 后端配置示例

      {
      "kube-context": "docker-for-desktop",
      "repository-uri": "username/mlflow-kubernetes-example",
      "kube-job-template-path": "/Users/username/path/to/kubernetes_job_template.yaml"
      }
  3. 如有必要,获取访问项目 Docker 和 Kubernetes 资源的凭据,包括

    MLflow 期望在运行项目之前可以通过 dockerkubectl 命令行工具访问这些资源。

  4. 使用 MLflow Projects 命令行工具Python API 运行项目,指定您的项目 URI 和后端配置文件的路径。例如

     mlflow run <project_uri> --backend kubernetes --backend-config examples/docker/kubernetes_config.json

    其中 <project_uri> 是 Git 仓库 URI 或文件夹。

作业模板

MLflow 通过创建Kubernetes Job 资源在 Kubernetes 上执行项目。MLflow 通过读取用户指定的Job Spec 为 MLflow 项目创建 Kubernetes Job。当 MLflow 读取 Job Spec 时,它会格式化以下字段

  • metadata.name 替换为包含 MLflow 项目名称和项目执行时间的字符串
  • spec.template.spec.container[0].name 替换为 MLflow 项目的名称
  • spec.template.spec.container[0].image 替换为项目执行期间创建的 Docker 镜像的 URI。此 URI 包括 Docker 镜像的摘要哈希。
  • spec.template.spec.container[0].command 替换为执行 MLflow 项目时指定的项目入口点命令。

以下示例展示了一个与 MLflow 项目执行兼容的简单 Kubernetes Job Spec。替换的字段使用括号括起来的文本表示。

Kubernetes Job Spec 示例

apiVersion: batch/v1
kind: Job
metadata:
name: "{replaced with MLflow Project name}"
namespace: mlflow
spec:
ttlSecondsAfterFinished: 100
backoffLimit: 0
template:
spec:
containers:
- name: "{replaced with MLflow Project name}"
image: "{replaced with URI of Docker image created during Project execution}"
command: ["{replaced with MLflow Project entry point command}"]
env: ["{appended with MLFLOW_TRACKING_URI, MLFLOW_RUN_ID and MLFLOW_EXPERIMENT_ID}"]
resources:
limits:
memory: 512Mi
requests:
memory: 256Mi
restartPolicy: Never

只有 Job Spec 中定义的*第一个*容器的 container.namecontainer.imagecontainer.command 字段会被替换。此外,MLFLOW_TRACKING_URIMLFLOW_RUN_IDMLFLOW_EXPERIMENT_ID 会被附加到 container.env。使用 KUBE_MLFLOW_TRACKING_URI 可以将与标准 MLFLOW_TRACKING_URI 不同的跟踪 URI 传递给作业容器。所有后续容器定义都不会修改。

快速迭代

如果您想快速开发项目,我们建议创建一个 MLproject 文件,将您的主程序指定为 main 入口点,并使用 mlflow run . 运行它。为避免重复编写参数,您可以在 MLproject 文件中添加默认参数。

构建多步骤工作流

mlflow.projects.run() API 结合 mlflow.client,使得构建多步骤工作流成为可能,其中每个步骤可以是单独的项目(或同一项目中的入口点)。每次调用 mlflow.projects.run() 都会返回一个运行对象,您可以使用 mlflow.client 来确定运行何时结束并获取其输出工件。然后可以将这些工件传递给接受 pathuri 参数的下一个步骤。您可以在一个 Python 程序中协调整个工作流,该程序查看每个步骤的结果并使用自定义代码决定下一步要提交什么。多步骤工作流的一些示例用例包括

模块化您的数据科学代码

不同的用户可以发布可重用的数据特征化、训练、验证等步骤,供其他用户或团队在其工作流中运行。由于 MLflow 支持 Git 版本控制,另一个团队可以将他们的工作流锁定到项目的特定版本,或者按照自己的计划升级到新版本。

超参数调优

使用 mlflow.projects.run(),您可以在本地机器或 Databricks 等云平台上并行启动多个运行。您的驱动程序可以实时检查每次运行的指标,以取消运行、启动新运行或选择在目标指标上表现最佳的运行。

交叉验证

有时,您可能希望在不同的随机训练和验证数据分割上运行相同的训练代码。使用 MLflow 项目,您可以以允许的方式打包项目,例如,将训练/验证分割的随机种子作为参数,或者首先调用另一个可以分割输入数据的项目。

有关如何构建此类多步骤工作流的示例,请参阅 MLflow 多步骤工作流示例项目