跳到主要内容

使用 MLflow 开发机器学习模型并部署到 Kubernetes

注意

本教程假设您可以使用 Kubernetes 集群。但是,您也可以通过使用本地集群仿真工具(如 KindMinikube)在本地机器上完成本教程。

本指南演示了如何端到端使用 MLflow:

在本教程中,我们将介绍端到端的模型开发过程,包括模型训练和测试。如果您已经有一个模型并且只想学习如何将其部署到 Kubernetes,则可以跳到步骤 6 - 在本地测试模型服务

简介:使用 KServe 和 MLServer 的可扩展模型服务

MLflow 提供了一个易于使用的接口,用于在基于 FastAPI 的推理服务器中部署模型。您可以使用 mlflow models build-docker 命令通过容器化将相同的推理服务器部署到 Kubernetes 集群。但是,这种方法可能不可扩展,并且可能不适合生产用例。FastAPI 并非为高性能和规模而设计(为什么?),并且手动管理推理服务器的多个实例也是非常繁琐的。

幸运的是,MLflow 为此提供了一个解决方案。MLflow 提供了一个替代的推理引擎,它更适合大规模推理部署,因为它支持 MLServer,这使得一键式部署到 Kubernetes 上流行的无服务器模型服务框架成为可能,例如 KServeSeldon Core

什么是 KServe?

KServe,正式名称为 KFServing,为 Tensorflow、XGBoost、scikit-learn 和 Pytorch 等常见机器学习框架提供了高性能、可扩展和高度抽象的接口。它提供了有助于操作大规模机器学习系统的高级功能,例如自动缩放金丝雀发布A/B 测试监控可解释性等,利用 Kubernetes 生态系统,包括 KNativeIstio

使用 MLflow 和 KServe 的好处

虽然 KServe 支持高度可扩展和生产就绪的模型服务,但将模型部署到那里可能需要一些努力。MLflow 简化了使用 KServe 和 MLServer 将模型部署到 Kubernetes 集群的过程。此外,它还提供无缝的端到端模型管理,作为管理整个 ML 生命周期的单一平台。这包括实验跟踪模型打包版本控制评估部署,我们将在本教程中介绍这些内容。

步骤 1:安装 MLflow 和其他依赖项

首先,请使用以下命令将 mlflow 安装到您的本地计算机

pip install mlflow[mlserver]

[extras] 将安装本教程所需的其他依赖项,包括 mlserverscikit-learn。请注意,部署不需要 scikit-learn,仅用于训练本教程中使用的示例模型。

您可以通过运行以下命令检查 MLflow 是否正确安装

mlflow --version

步骤 2:设置 Kubernetes 集群

如果您已经可以访问 Kubernetes 集群,则可以按照官方说明将 KServe 安装到您的集群中。

现在您已经拥有一个作为部署目标的 Kubernetes 集群,让我们继续创建要部署的 MLflow 模型。

步骤 3:训练模型

在本教程中,我们将训练并部署一个简单的回归模型,该模型预测葡萄酒的质量。

让我们从使用默认超参数训练模型开始。在笔记本或 Python 脚本中执行以下代码。

注意

为方便起见,我们使用 mlflow.sklearn.autolog() 函数。此函数允许 MLflow 在训练期间自动记录适当的模型参数和指标集。要了解有关自动日志记录功能或如何手动日志记录的更多信息,请参阅 MLflow Tracking 文档

import mlflow

import numpy as np
from sklearn import datasets, metrics
from sklearn.linear_model import ElasticNet
from sklearn.model_selection import train_test_split


def eval_metrics(pred, actual):
rmse = np.sqrt(metrics.mean_squared_error(actual, pred))
mae = metrics.mean_absolute_error(actual, pred)
r2 = metrics.r2_score(actual, pred)
return rmse, mae, r2


# Set th experiment name
mlflow.set_experiment("wine-quality")

# Enable auto-logging to MLflow
mlflow.sklearn.autolog()

# Load wine quality dataset
X, y = datasets.load_wine(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25)

# Start a run and train a model
with mlflow.start_run(run_name="default-params"):
lr = ElasticNet()
lr.fit(X_train, y_train)

y_pred = lr.predict(X_test)
metrics = eval_metrics(y_pred, y_test)

现在您已经训练了一个模型,让我们通过 MLflow UI 检查参数和指标是否正确记录。您可以通过在终端中运行以下命令来启动 MLflow UI

mlflow ui --port 5000

然后访问 https://:5000 打开 UI。

请打开左侧名为“wine-quality”的实验,然后点击表中名为“default-params”的运行。在这种情况下,您应该看到包括 alphal1_ratio 在内的参数以及诸如 training_scoremean_absolute_error_X_test 之类的指标。

步骤 4:运行超参数调优

现在我们已经建立了一个基线模型,让我们尝试通过调整超参数来提高其性能。我们将进行随机搜索以确定 alphal1_ratio 的最佳组合。

from scipy.stats import uniform
from sklearn.model_selection import RandomizedSearchCV

lr = ElasticNet()

# Define distribution to pick parameter values from
distributions = dict(
alpha=uniform(loc=0, scale=10), # sample alpha uniformly from [-5.0, 5.0]
l1_ratio=uniform(), # sample l1_ratio uniformlyfrom [0, 1.0]
)

# Initialize random search instance
clf = RandomizedSearchCV(
estimator=lr,
param_distributions=distributions,
# Optimize for mean absolute error
scoring="neg_mean_absolute_error",
# Use 5-fold cross validation
cv=5,
# Try 100 samples. Note that MLflow only logs the top 5 runs.
n_iter=100,
)

# Start a parent run
with mlflow.start_run(run_name="hyperparameter-tuning"):
search = clf.fit(X_train, y_train)

# Evaluate the best model on test dataset
y_pred = clf.best_estimator_.predict(X_test)
rmse, mae, r2 = eval_metrics(clf.best_estimator_, y_pred, y_test)
mlflow.log_metrics(
{
"mean_squared_error_X_test": rmse,
"mean_absolute_error_X_test": mae,
"r2_score_X_test": r2,
}
)

当您重新打开 MLflow UI 时,您应该会注意到“超参数调优”运行包含 5 个子运行。MLflow 利用父子关系,这对于对一组运行进行分组特别有用,例如超参数调优中的那些。此处已启用自动日志记录,MLflow 会根据 scoring 指标(在此示例中为负平均绝对误差)自动为前 5 个运行创建子运行。

要比较结果并确定最佳模型,您可以使用 MLflow UI 中的可视化功能。

  1. 选择第一个作业(“default-params”)和超参数调优的父作业(“hyperparameter-tuning”)。
  2. 单击“图表”选项卡以在图表中可视化指标。
  3. 默认情况下,会显示预定义的一组指标的几个条形图。
  4. 您可以添加不同的图表,例如散点图,以比较多个指标。例如,我们可以看到超参数调优的最佳模型在测试数据集上的均方误差方面优于默认参数模型

您可以通过查看父级运行“hyperparameter-tuning”来检查超参数的最佳组合。在此示例中,最佳模型是 alpha=0.11714084185001972l1_ratio=0.3599780644783639(您可能会看到不同的结果)。

注意

要了解有关 MLflow 超参数调优的更多信息,请参阅 使用 MLflow 和 Optuna 进行超参数调优

步骤 5:打包模型和依赖项

由于我们正在使用自动日志记录,MLflow 会自动为每次运行记录 模型。此过程方便地将模型权重和依赖项打包成可部署的格式。

注意

实际上,还建议使用 MLflow 模型注册表 来注册和管理您的模型。

让我们简要了解一下这种格式的外观。您可以通过运行详细信息页面上的 Artifacts 选项卡查看已记录的模型。

model
├── MLmodel
├── model.pkl
├── conda.yaml
├── python_env.yaml
└── requirements.txt

model.pkl 是包含序列化模型权重的D文件。MLmodel 包含指导 MLflow 如何加载模型的通用元数据。其他文件指定运行模型所需的依赖项。

注意

如果您选择手动日志记录,则需要使用 mlflow.sklearn.log_model 函数显式日志记录模型,如下所示

mlflow.sklearn.log_model(lr, name="model")

步骤 6:在本地测试模型服务

在部署模型之前,我们首先在本地测试模型是否可以提供服务。如 在本地部署 MLflow 模型 中所述,您只需一个命令即可运行本地推理服务器。请记住使用 enable-mlserver 标志,该标志指示 MLflow 使用 MLServer 作为推理服务器。这可确保模型以与在 Kubernetes 中相同的方式运行。

mlflow models serve -m models:/<model_id_for_your_best_iteration> -p 1234 --enable-mlserver

此命令启动一个在端口 1234 上侦听的本地服务器。您可以使用 curl 命令向服务器发送请求

$ curl -X POST -H "Content-Type:application/json" --data '{"inputs": [[14.23, 1.71, 2.43, 15.6, 127.0, 2.8, 3.06, 0.28, 2.29, 5.64, 1.04, 3.92, 1065.0]]}' http://127.0.0.1:1234/invocations

{"predictions": [-0.03416275504140387]}

有关请求格式和响应格式的更多信息,请参阅推理服务器规范

步骤 7:将模型部署到 KServe

最后,我们已准备好将模型部署到 Kubernetes 集群。

创建命名空间

首先,为部署 KServe 资源和您的模型创建一个测试命名空间

kubectl create namespace mlflow-kserve-test

创建部署配置

创建描述模型部署到 KServe 的 YAML 文件。

在 KServe 配置文件中有两种指定要部署模型的方式

  1. 使用模型构建 Docker 镜像并指定镜像 URI。
  2. 直接指定模型 URI(这仅在您的模型存储在远程存储中时有效)。

请打开下面的选项卡以获取每种方法的详细信息。

注册 Docker 帐户

由于 KServe 无法解析本地构建的 Docker 镜像,因此您需要将镜像推送到 Docker 注册表。对于本教程,我们将把镜像推送到 Docker Hub,但您可以使用任何其他 Docker 注册表,例如 Amazon ECR 或私有注册表。

如果您还没有 Docker Hub 帐户,请在 https://hub.docker.com/signup 创建一个。

构建 Docker 镜像

使用 mlflow models build-docker 命令构建一个可部署的 Docker 镜像

mlflow models build-docker -m runs:/<run_id_for_your_best_run>/model -n <your_dockerhub_user_name>/mlflow-wine-classifier --enable-mlserver

此命令构建一个包含模型和依赖项的 Docker 镜像,并将其标记为 mlflow-wine-classifier:latest

推送 Docker 镜像

构建镜像后,将其推送到 Docker Hub(或使用适当的命令推送到另一个注册表)

docker push <your_dockerhub_user_name>/mlflow-wine-classifier

编写部署配置

然后创建一个这样的 YAML 文件

apiVersion: "serving.kserve.io/v1beta1"
kind: "InferenceService"
metadata:
name: "mlflow-wine-classifier"
namespace: "mlflow-kserve-test"
spec:
predictor:
containers:
- name: "mlflow-wine-classifier"
image: "<your_docker_user_name>/mlflow-wine-classifier"
ports:
- containerPort: 8080
protocol: TCP
env:
- name: PROTOCOL
value: "v2"

部署推理服务

运行以下 kubectl 命令,将新的 InferenceService 部署到 Kubernetes 集群

$ kubectl apply -f YOUR_CONFIG_FILE.yaml

inferenceservice.serving.kserve.io/mlflow-wine-classifier created

您可以通过运行以下命令检查部署状态

$ kubectl get inferenceservice mlflow-wine-classifier

NAME URL READY PREV LATEST PREVROLLEDOUTREVISION LATESTREADYREVISION
mlflow-wine-classifier http://mlflow-wine-classifier.mlflow-kserve-test.local True 100 mlflow-wine-classifier-100
注意

部署状态可能需要几分钟才能就绪。有关详细的部署状态和日志,请运行 kubectl get inferenceservice mlflow-wine-classifier -oyaml

测试部署

部署就绪后,您可以向服务器发送测试请求。

首先,创建一个包含测试数据的 JSON 文件并将其保存为 test-input.json。确保请求数据已格式化为 V2 推理协议,因为我们使用 protocolVersion: v2 创建了模型。请求应如下所示

{
"inputs": [
{
"name": "input",
"shape": [13],
"datatype": "FP32",
"data": [14.23, 1.71, 2.43, 15.6, 127.0, 2.8, 3.06, 0.28, 2.29, 5.64, 1.04, 3.92, 1065.0]
}
]
}

然后将请求发送到您的推理服务

假设您的集群通过 LoadBalancer 公开,请按照这些说明查找入口 IP 和端口。然后使用 curl 命令发送测试请求

$ SERVICE_HOSTNAME=$(kubectl get inferenceservice mlflow-wine-classifier -n mlflow-kserve-test -o jsonpath='{.status.url}' | cut -d "/" -f 3)
$ curl -v \
-H "Host: ${SERVICE_HOSTNAME}" \
-H "Content-Type: application/json" \
-d @./test-input.json \
http://${INGRESS_HOST}:${INGRESS_PORT}/v2/models/mlflow-wine-classifier/infer

故障排除

如果在部署过程中遇到任何问题,请查阅 KServe 官方文档及其 MLflow 部署指南

结论

恭喜您完成本指南!在本教程中,您学习了如何使用 MLflow 训练模型、运行超参数调优以及将模型部署到 Kubernetes 集群。

进一步阅读:

  • MLflow Tracking - 探索更多关于 MLflow Tracking 以及管理实验和模型的各种方式,例如团队协作。
  • MLflow 模型注册表 - 了解更多关于 MLflow 模型注册表,用于在集中式模型存储中管理模型版本和阶段。
  • MLflow 部署 - 了解更多关于 MLflow 部署和不同的部署目标。
  • KServe 官方文档 - 深入了解 KServe 及其高级功能,包括自动缩放、金丝雀发布、A/B 测试、监控、可解释性等。
  • Seldon Core 官方文档 - 了解 Seldon Core,我们支持的 Kubernetes 的另一种无服务器模型服务框架。