MLflow模型是打包机器学习模型的标准格式,可以用于各种下游工具-例如,通过REST API或Apache Spark上的批处理推理提供实时服务。该格式定义了一种约定,允许您以不同的“风格”保存模型,以供不同的下游工具理解。
存储格式
每个MLflow模型都是一个目录,其中包含任意文件,以及目录根中的一个MLmodel文件,该文件可以定义可以在其中查看模型的多种样式。
样式是使MLflow模型强大的关键概念:它们是部署工具可以用来理解模型的一种约定,这使得可以编写与任何ML库中的模型一起工作的工具,而不必将每个工具与每个库集成。MLflow定义了其所有内置部署工具都支持的几种“标准”样式,例如描述如何将模型作为Python函数运行的“Python函数”样式。不过,库还可以定义和使用其他风格。例如,MLflow的MLflow.sklearn库允许将模型作为一个scikit-learn管道对象加载回代码中,用于了解scikit-learn的代码,或者作为一个通用的Python函数用于仅需要应用模型的工具(例如,用于将模型部署到Amazon sagemaker的mlflow sagemaker工具)。
特定模型支持的所有样式都在其MLmodel文件中以YAML格式定义。例如,mlflow.sklearn输出的模型如下:
# Directory written by mlflow.sklearn.save_model(model, "my_model")
my_model/
├── MLmodel
└── model.pkl
它的MLmodel文件描述了两种风格:
time_created: 2018-05-25T17:28:53.35
flavors:
sklearn:
sklearn_version: 0.19.1
pickled_model: model.pkl
python_function:
loader_module: mlflow.sklearn
这个模型可以与任何支持sklearn或python_function模型风格的工具一起使用。例如,mlflow models serve命令可以使用python_function或crate (R函数)样式的模型:
mlflow models serve -m my_model
此外,mlflow sagemaker命令行工具可以打包和部署模型到AWS sagemaker,只要它们支持python_function风格:
mlflow sagemaker deploy -m my_model [other options]
字段的MLmodel格式
除了列出模型的flavor字段外,MLmodel YAML格式还可以包含以下字段:
time_created
创建模型的日期和时间,UTC ISO 8601格式。
run_id
创建模型的运行的ID,如果模型是使用MLflow跟踪保存的。
signature
JSON格式的model signature。
input_example
引用带有input example的工件。
模型签名和输入示例
在使用ML模型时,通常需要了解模型的一些基本功能属性,例如“它期望什么输入?”和“它产生了什么结果?”MLflow模型可以包含以下关于模型输入和输出的额外元数据,可被下游工具使用:
模型签名-对模型的输入和输出的描述。
模型输入示例—有效的模型输入示例。
模型签名
模型签名定义了模型输入和输出的模式。模型输入和输出被描述为一个(可选的)命名列序列,其类型指定为MLflow数据类型之一。该签名以JSON格式存储在MLmodel文件中,与其他模型元数据一起存储。标准的MLflow模型部署工具可以识别和实施模型签名。例如,mlflow模型服务工具(它将模型部署为REST API,基于模型的签名验证输入)。
下面的示例显示一个MLmodel文件摘录,其中包含在Iris数据集上训练的分类模型的模型签名。输入有4个命名的数字列。输出是一个未命名的整数,指定了预期的类:
signature:
inputs: '[{"name": "sepal length (cm)", "type": "double"}, {"name": "sepal width
(cm)", "type": "double"}, {"name": "petal length (cm)", "type": "double"}, {"name":
"petal width (cm)", "type": "double"}]'
outputs: '[{"type": "integer"}]'
签名的执行
当为包含签名的模型评分时,将根据签名的输入模式对输入进行验证。此输入模式强制检查输入列的顺序和列类型,如果输入不兼容将引发异常。在调用底层模型实现之前,将在MLflow中应用此实施。注意,这种强制仅适用于使用MLflow模型部署工具或将模型加载为python_function时。特别是,它不适用于以其本机格式加载的模型(例如,通过调用mlflow.sklearn.load_model())。
列顺序执行
根据模型签名检查输入列。如果有任何缺失的列,MLflow将引发异常。没有在签名中声明的额外列将被忽略。如果签名中的输入模式定义了列名,则按名称进行列匹配,并对列重新排序以匹配签名。如果输入模式没有列名,则根据位置进行匹配(即MLflow只检查列的数量)。
列类型执行
根据签名检查输入列类型。如果有必要,MLflow将执行安全的类型转换。通常,只允许保证无损的转换。例如,int -> long或int -> double转换是可以的,long -> double就不行。如果不能使类型兼容,MLflow将引发错误。
处理缺少值的整数
在Python中,缺少值的整型数据通常表示为浮点数。因此,Python中整数列的数据类型可以根据数据样本而变化。由于integer和float是不兼容的类型,这种类型差异可能会在运行时导致模式实施错误。例如,如果您的训练数据对于整数列c没有任何遗漏的值,那么它的类型将是integer。然而,当您试图在c列中包含缺失值的数据样本中评分时,它的类型将是float。如果你的模型签名指定c为整数类型,MLflow将会引发一个错误,因为它不能将float转换为int。注意,MLflow使用python来服务模型,并将模型部署到Spark中,所以这可能会影响大多数模型的部署。避免这个问题的最佳方法是,当存在缺值时,将整型列声明为双精度浮点数(float64)。
如何记录带有签名的模型
要在模型中包含签名,请将签名对象作为参数传递给适当的log_model调用,例如sklearn.log_model()。模型签名对象可以手动创建,也可以从具有有效模型输入的数据集(例如,省略目标列的训练数据集)和有效模型输出(例如,在训练数据集上生成的模型预测)推断出来。下面的例子演示了如何存储一个基于Iris数据集训练的简单分类器的模型签名:
import pandas as pd
from sklearn import datasets
from sklearn.ensemble import RandomForestClassifier
import mlflow
import mlflow.sklearn
from mlflow.models.signature import infer_signature
iris = datasets.load_iris()
iris_train = pd.DataFrame(iris.data, columns=iris.feature_names)
clf = RandomForestClassifier(max_depth=7, random_state=0)
clf.fit(iris_train, iris.target)
signature = infer_signature(iris_train, clf.predict(iris_train))
mlflow.sklearn.log_model(clf, "iris_rf", signature=signature)
同样的签名可以显式地创建如下:
from mlflow.models.signature import ModelSignature
from mlflow.types.schema import Schema, ColSpec
input_schema = Schema([
ColSpec("double", "sepal length (cm)"),
ColSpec("double", "sepal width (cm)"),
ColSpec("double", "petal length (cm)"),
ColSpec("double", "petal width (cm)"),
])
output_schema = Schema([ColSpec("long")])
signature = ModelSignature(inputs=input_schema, outputs=output_schema)
模型输入的例子
模型输入示例提供了一个有效模型输入的实例。这可以是单个记录,也可以是一批记录。输入示例作为单独的工件与模型一起存储,并在MLmodel文件中引用。
如何用实例进行对数模型
要在模型中包含输入示例,请将其添加到适当的log_model调用中,例如sklearn.log_model()。示例可以作为Pandas数据帧、Numpy数组、列表或字典传入。给定的示例将被转换为Pandas数据帧,然后使用面向熊猫拆分的格式序列化为json。字节是base64编码。下面的例子演示了如何用你的模型记录一个输入示例:
input_example = {
"sepal length (cm)": 5.1,
"sepal width (cm)": 3.5,
"petal length (cm)": 1.4,
"petal width (cm)": 0.2
}
mlflow.sklearn.log_model(..., input_example=input_example)
模型API
您可以通过多种方式保存和加载MLflow模型。首先,MLflow包含与几个常见库的集成。例如,mlflow.sklearn包含用于scikit-learn模型的save_model、log_model和load_model函数。其次,您可以使用mlflow.models.Model创建和编写模型的模型类。这个类有四个关键函数:
- add_flavor向模型添加一个flavor。每个flavor都有一个字符串名称和一个键-值属性字典,其中的值可以是可以序列化到YAML的任何对象。
- save将模型保存到本地目录。
log
使用MLflow跟踪将模型记录为当前运行中的工件。load
从本地目录或前一次运行中的工件加载模型。内置模型
MLflow提供了几种可能在应用程序中有用的标准样式。具体来说,它的许多部署工具都支持这些风格,因此您可以在其中一种风格中导出自己的模型,从而受益于所有这些工具:Python函数
python_function模型样式作为MLflow Python模型的默认模型接口。任何MLflow Python模型都可以作为python_function模型加载。这使得其他MLflow工具可以与任何python模型一起工作,而不必考虑使用哪个持久模块或框架来生成模型。这种互操作性非常强大,因为它允许在各种环境中生产任何Python模型。
此外,python_function模型样式为Python模型定义了一种通用的文件系统模型格式,并提供了用于保存和加载模型的实用工具。该格式是自包含的,因为它包含了加载和使用模型所需的所有信息。依赖关系可以直接存储在模型中,也可以通过conda环境引用。这种模型格式允许其他工具将它们的模型与MLflow集成。如何将模型保存为Python函数
大多数python_function模型都保存为其他模型样式的一部分——例如,所有mlflow内置样式都在导出的模型中包含python_function样式。此外,mlflow.pyfunc模块定义了显式创建python_function模型的函数。这个模块还包括用于创建自定义Python模型的实用工具,这是将自定义Python代码添加到ML模型的方便方法。更多信息,请参阅自定义Python模型文档。如何加载和评分Python函数模型
你可以通过调用mlflow. pyfunct .load_model()函数来加载Python中的python_function模型。请注意,load_model函数假设所有依赖项都已经可用,并且不会检查或安装任何依赖项(请参阅模型部署部分,了解使用自动依赖项管理部署模型的工具)。
一旦加载,您可以通过调用predict方法对模型进行评分,该方法有以下签名:predict(model_input: pandas.DataFrame) -> [numpy.ndarray | pandas.(Series | DataFrame)]
Keras (Keras)
keras模型样式支持对keras模型进行日志记录和加载。它在Python和R客户端中都可用。mlflow.keras模块定义了save_model()和log_model()函数,您可以使用它们在Python中以MLflow模型格式保存keras模型。类似地,在R中,您可以使用mlflow_save_model和mlflow_log_model保存或记录模型。这些函数使用Keras库的内置模型持久性函数将Keras模型序列化为HDF5文件。由这些函数生成的MLflow模型也包含python_function风格,允许将它们解释为通用的Python函数,以便通过MLflow . pyfunct .load_model()进行推断。最后,您可以使用Python中的MLflow .keras.load_model()函数或R中的mlflow_load_model函数来使用keras风格的keras模型对象加载MLflow模型。
有关更多信息,请参见mlflow.keras。PyTorch (PyTorch)
pytorch模型风格支持对pytorch模型进行日志记录和加载。
mlflow.pytorch模块定义了用于保存和加载具有pytorch风格的MLflow模型的实用工具。你可以使用MLflow . PyTorch .save_model()和MLflow . PyTorch .log_model()方法以MLflow格式保存PyTorch模型;这两个函数都使用了torch.save()方法来序列化PyTorch模型。此外,还可以使用MLflow .pytorch.load_model()方法将带有pytorch风格的MLflow模型作为pytorch模型对象加载。最后,由mlflow.pytorch.save_model()和mlflow.pytorch.log_model()生成的模型包含python_function风格,允许您将它们作为通用Python函数加载,以便通过mlflow. pyfunct .load_model()进行推断。
有关更多信息,请参见mlflow.pytorch。Scikit-learn (sklearn)
sklearn模型样式为保存和加载scikit-learn模型提供了一个易于使用的界面。mlflow.sklearn模块定义了save_model()和log_model()函数,以MLflow格式保存scikit-learn模型,使用Python的pickle模块(pickle)或CloudPickle对模型进行序列化。这些函数生成具有python_function风格的MLflow模型,允许将它们作为通用Python函数加载,以便通过MLflow . pyfunct .load_model()进行推断。最后,可以使用MLflow .sklearn.load_model()方法以sklearn样式作为scikit-learn模型对象加载MLflow模型。
有关更多信息,请参见mlflow.sklearn。Spark MLlib(spark)
spark模型样式允许将spark MLlib模型导出为MLflow模型。
mlflow.spark模块定义了save_model()和log_model()方法,用于以MLflow模型格式保存spark MLlib管道。由这些函数生成的MLflow模型包含python_function风格,允许您通过MLflow .pyfunc.load_model()将它们作为通用Python函数加载。当带有spark风格的模型通过mlflow.pyfunc.load_model()作为Python函数加载时,将创建一个新的SparkContext用于模型推断;此外,该函数在得分前将所有熊猫数据帧输入转换为Spark数据帧。虽然这种初始化开销和格式转换延迟对于高性能用例来说并不理想,但它使您能够轻松地将任何MLlib PipelineModel部署到MLflow支持的任何生产环境(SageMaker、AzureML等)。
最后,使用MLflow .spark.load_model()方法以spark MLlib管道的形式加载具有spark风格的MLflow模型。
有关更多信息,请参见mlflow.spark。TensorFlow (TensorFlow)
tensorflow模型规范允许SavedModel格式的序列化tensorflow模型通过MLflow .tensorflow.save_model()和MLflow .tensorflow.log_model()方法记录在MLflow格式中。这些方法还将python_function风格添加到它们生成的MLflow模型中,允许将模型解释为通用的Python函数,以便通过MLflow .pyfunc.load_model()进行推断。最后,你可以使用MLflow .tensorflow.load_model()方法来加载带有tensorflow风格的MLflow模型作为tensorflow图。
有关更多信息,请参见mlflow.tensorflow。模型定制
虽然MLflow内置的模型持久性实用程序可以方便地将各种流行的ML库中的模型打包成MLflow模型格式,但它们并没有覆盖所有用例。例如,您可能希望使用ML库中的模型,而MLflow的内置样式并不显式支持该模型。或者,您可能希望打包自定义推理代码和数据来创建MLflow模型。幸运的是,MLflow提供了两种可用于完成这些任务的解决方案:自定义Python模型和自定义风格。自定义Python模型
mlflow.pyfunc模块提供了save_model()和log_model()实用程序,用于创建具有python_function风格的MLflow模型,其中包含用户指定的代码和工件(文件)依赖项。这些工件依赖关系可能包括由任何Python ML库生成的序列化模型。
因为这些定制模型包含python_function风格,所以可以将它们部署到MLflow支持的任何生产环境中,比如SageMaker、AzureML或本地REST端点。
下面的示例演示如何使用mlflow.pyfunc模块创建自定义的Python模型。有关使用MLflow的python_function实用程序定制模型的其他信息,请参阅python_function自定义模型文档。示例:创建一个自定义的“add n”模型
这个例子为一个自定义模型定义了一个类,该模型将指定的数值n添加到Pandas数据帧输入的所有列中。然后,它使用mlflow.pyfunc api以MLflow模型格式保存该模型的实例,且n = 5。最后,它以python_function格式加载模型,并使用它来计算一个示例输入。 ```bash import mlflow.pyfunc
Define the model class
class AddN(mlflow.pyfunc.PythonModel):
def __init__(self, n):
self.n = n
def predict(self, context, model_input):
return model_input.apply(lambda column: column + self.n)
Construct and save the model
model_path = “add_n_model” add5_model = AddN(n=5) mlflow.pyfunc.save_model(path=model_path, python_model=add5_model)
Load the model in python_function
format
loaded_model = mlflow.pyfunc.load_model(model_path)
Evaluate the model
import pandas as pd model_input = pd.DataFrame([range(10)]) model_output = loaded_model.predict(model_input) assert model_output.equals(pd.DataFrame([range(5, 15)]))
<a name="FrDS9"></a>
#### 示例:以MLflow格式保存XGBoost模型
本示例首先使用XGBoost库训练并保存一个梯度增强树模型。接下来,它围绕XGBoost模型定义了一个包装器类,该类符合MLflow的python_function推断API。然后,它使用包装器类和保存的XGBoost模型构建一个MLflow模型,该模型使用梯度增强树执行推断。最后,它以python_function格式加载MLflow模型,并使用它来计算测试数据。
```bash
# Load training and test datasets
from sys import version_info
import xgboost as xgb
from sklearn import datasets
from sklearn.model_selection import train_test_split
PYTHON_VERSION = "{major}.{minor}.{micro}".format(major=version_info.major,
minor=version_info.minor,
micro=version_info.micro)
iris = datasets.load_iris()
x = iris.data[:, 2:]
y = iris.target
x_train, x_test, y_train, _ = train_test_split(x, y, test_size=0.2, random_state=42)
dtrain = xgb.DMatrix(x_train, label=y_train)
# Train and save an XGBoost model
xgb_model = xgb.train(params={'max_depth': 10}, dtrain=dtrain, num_boost_round=10)
xgb_model_path = "xgb_model.pth"
xgb_model.save_model(xgb_model_path)
# Create an `artifacts` dictionary that assigns a unique name to the saved XGBoost model file.
# This dictionary will be passed to `mlflow.pyfunc.save_model`, which will copy the model file
# into the new MLflow Model's directory.
artifacts = {
"xgb_model": xgb_model_path
}
# Define the model class
import mlflow.pyfunc
class XGBWrapper(mlflow.pyfunc.PythonModel):
def load_context(self, context):
import xgboost as xgb
self.xgb_model = xgb.Booster()
self.xgb_model.load_model(context.artifacts["xgb_model"])
def predict(self, context, model_input):
input_matrix = xgb.DMatrix(model_input.values)
return self.xgb_model.predict(input_matrix)
# Create a Conda environment for the new MLflow Model that contains all necessary dependencies.
import cloudpickle
conda_env = {
'channels': ['defaults'],
'dependencies': [
'python={}'.format(PYTHON_VERSION),
'pip',
{
'pip': [
'mlflow',
'xgboost=={}'.format(xgb.__version__),
'cloudpickle=={}'.format(cloudpickle.__version__),
],
},
],
'name': 'xgb_env'
}
# Save the MLflow Model
mlflow_pyfunc_model_path = "xgb_mlflow_pyfunc"
mlflow.pyfunc.save_model(
path=mlflow_pyfunc_model_path, python_model=XGBWrapper(), artifacts=artifacts,
conda_env=conda_env)
# Load the model in `python_function` format
loaded_model = mlflow.pyfunc.load_model(mlflow_pyfunc_model_path)
# Evaluate the model
import pandas as pd
test_predictions = loaded_model.predict(pd.DataFrame(x_test))
print(test_predictions)
自定义样式
您还可以通过编写自定义样式来创建自定义MLflow模型。
正如在模型API和存储格式部分中讨论的,MLflow模型由包含MLmodel配置文件的文件目录定义。这个MLmodel文件描述了各种模型属性,包括解释模型的风格。MLmodel文件包含每个样式名称的条目;每个条目都是特定于样式的属性的yaml格式集合。
要创建新的样式来支持自定义模型,您需要定义一组要包含在MLmodel配置文件中的特定样式属性,以及可以解释模型目录内容和样式属性的代码。
作为一个例子,让我们研究一下mlflow。pytorch模块对应于MLflow的pytorch风格。在mlflow.pytorch.save_model()方法中,PyTorch模型被保存到指定的输出目录中。此外,mlflow.pytorch.save_model()利用了mlflow.models.Model.add_flavor()和mlflow.models.Model.save()函数来生成包含pytorch flavor的MLmodel配置。生成的配置有几个特定于风格的属性,比如pytorch_version,它表示用于训练模型的PyTorch库的版本。要解释save_model()生成的模型目录,mlflow。pytorch模块还定义了一个load_model()方法。mlflow.pytorch.load_model()从指定的模型目录读取MLmodel配置,并使用pytorch样式的配置属性从其序列化表示中加载并返回pytorch模型。
内置的部署工具
MLflow提供了将MLflow模型部署到本地机器和多个生产环境的工具。并不是所有的部署方法都适用于所有的模型。
部署MLflow模型
MLflow可以将模型本地部署为本地REST API端点,也可以直接对文件进行评分。此外,MLflow可以用REST API端点将模型打包为自包含的Docker图像。可以使用映像将模型安全地部署到各种环境中,比如Kubernetes。
您可以在本地部署MLflow模型,或者使用CLI接口生成Docker映像到MLflow.models模块。
REST API服务器接受以下数据格式作为POST输入到/invocations路径:
- json序列化的pandas数据帧在split的方向。例如data = pandas_df.to_json(orient=’split’)。此格式的内容类型请求头值指定使用application/json或application/json;format= pandas-split。
- json序列化的pandas数据帧在records方向。我们不建议使用这种格式,因为它不能保证保留列顺序。该Content-Type格式请求头值指定使用application/json;format= pandas-records。
- CSV-serialized pandas DataFrames。例如data = pandas_df.to_csv()。此格式使用的内容类型请求头值指定text/csv。
示例请求:
# split-oriented
curl http://127.0.0.1:5000/invocations -H 'Content-Type: application/json' -d '{
"columns": ["a", "b", "c"],
"data": [[1, 2, 3], [4, 5, 6]]
}'
# record-oriented (fine for vector rows, loses ordering for JSON records)
curl http://127.0.0.1:5000/invocations -H 'Content-Type: application/json; format=pandas-records' -d '[
{"a": 1,"b": 2,"c": 3},
{"a": 4,"b": 5,"c": 6}
]'
有关序列化pandas数据帧的更多信息,请参见panda . dataframe .to_json。
predict命令接受相同的输入格式。格式指定为命令行参数。
命令
- serve将模型部署为本地REST API服务器。
- build_docker封包了一个REST API端点作为docker映像服务于模型。
- predict使用该模型为本地CSV或JSON文件生成预测。
更多的信息请查看
mlflow models --help
mlflow models serve --help
mlflow models predict --help
mlflow models build-docker --help
部署到自定义目标
除了内置的部署工具外,MLflow还提供了一个可插入的MLflow .deployment Python API和MLflow部署CLI,用于将模型部署到自定义目标和环境中。要部署到自定义目标,必须首先安装适当的第三方Python插件。点击这里查看已知的社区维护插件列表。
用于部署到自定义目标的api是实验性的,可能会在未来的版本中更改。
命令
mlflow部署命令行包含以下命令,也可以使用mlflow.deployment Python API以编程方式调用这些命令:
- Create:将MLflow模型部署到指定的自定义目标
- Delete:删除部署
- update:更新一个现有的部署,例如部署一个新的模型版本或更改部署的配置(例如增加副本计数)
- List:列出所有部署的id
- Get:打印特定部署的详细描述
- run local:在本地部署模型以进行测试
- Help:显示指定目标器的帮助字符串
更多信息,请查看
mlflow deployments --help
mlflow deployments create --help
mlflow deployments delete --help
mlflow deployments update --help
mlflow deployments list --help
mlflow deployments get --help
mlflow deployments run-local --help
mlflow deployments help --help