跳到主要内容

使用 MLflow 开发 ML 模型并部署到 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 时,您应该会注意到运行“hyperparameter-tuning”包含 5 个子运行。MLflow 利用父子关系,这对于对一组运行进行分组特别有用,例如超参数调整中的运行。此处启用了自动日志记录,MLflow 会根据 scoring 指标自动为前 5 个运行创建子运行,在本例中该指标是负均绝对误差。

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

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

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

注意

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

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

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

注意

在实践中,还建议使用 MLflow Model Registry 来注册和管理您的模型。

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

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

model.pkl 是包含序列化模型权重的文件。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

创建部署配置

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

有两种方法可以在 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 公开,请按照 这些说明 查找 Ingress 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 Model Registry - 了解有关 MLflow Model Registry 的更多信息,以在集中式模型存储中管理模型版本和阶段。
  • MLflow 部署 - 了解有关 MLflow 部署和不同部署目标的更多信息。
  • KServe 官方文档 - 深入了解 KServe 及其高级功能,包括自动缩放、金丝雀发布、A/B 测试、监控、可解释性等。
  • Seldon Core 官方文档 - 了解 Seldon Core,这是我们支持用于 Kubernetes 的另一种无服务器模型服务框架。