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输出的模型如下:

  1. # Directory written by mlflow.sklearn.save_model(model, "my_model")
  2. my_model/
  3. ├── MLmodel
  4. └── model.pkl

它的MLmodel文件描述了两种风格:

  1. time_created: 2018-05-25T17:28:53.35
  2. flavors:
  3. sklearn:
  4. sklearn_version: 0.19.1
  5. pickled_model: model.pkl
  6. python_function:
  7. loader_module: mlflow.sklearn

这个模型可以与任何支持sklearn或python_function模型风格的工具一起使用。例如,mlflow models serve命令可以使用python_function或crate (R函数)样式的模型:

  1. mlflow models serve -m my_model

此外,mlflow sagemaker命令行工具可以打包和部署模型到AWS sagemaker,只要它们支持python_function风格:

  1. 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个命名的数字列。输出是一个未命名的整数,指定了预期的类:

  1. signature:
  2. inputs: '[{"name": "sepal length (cm)", "type": "double"}, {"name": "sepal width
  3. (cm)", "type": "double"}, {"name": "petal length (cm)", "type": "double"}, {"name":
  4. "petal width (cm)", "type": "double"}]'
  5. 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数据集训练的简单分类器的模型签名:

  1. import pandas as pd
  2. from sklearn import datasets
  3. from sklearn.ensemble import RandomForestClassifier
  4. import mlflow
  5. import mlflow.sklearn
  6. from mlflow.models.signature import infer_signature
  7. iris = datasets.load_iris()
  8. iris_train = pd.DataFrame(iris.data, columns=iris.feature_names)
  9. clf = RandomForestClassifier(max_depth=7, random_state=0)
  10. clf.fit(iris_train, iris.target)
  11. signature = infer_signature(iris_train, clf.predict(iris_train))
  12. mlflow.sklearn.log_model(clf, "iris_rf", signature=signature)

同样的签名可以显式地创建如下:

  1. from mlflow.models.signature import ModelSignature
  2. from mlflow.types.schema import Schema, ColSpec
  3. input_schema = Schema([
  4. ColSpec("double", "sepal length (cm)"),
  5. ColSpec("double", "sepal width (cm)"),
  6. ColSpec("double", "petal length (cm)"),
  7. ColSpec("double", "petal width (cm)"),
  8. ])
  9. output_schema = Schema([ColSpec("long")])
  10. signature = ModelSignature(inputs=input_schema, outputs=output_schema)

模型输入的例子

模型输入示例提供了一个有效模型输入的实例。这可以是单个记录,也可以是一批记录。输入示例作为单独的工件与模型一起存储,并在MLmodel文件中引用。

如何用实例进行对数模型

要在模型中包含输入示例,请将其添加到适当的log_model调用中,例如sklearn.log_model()。示例可以作为Pandas数据帧、Numpy数组、列表或字典传入。给定的示例将被转换为Pandas数据帧,然后使用面向熊猫拆分的格式序列化为json。字节是base64编码。下面的例子演示了如何用你的模型记录一个输入示例:

  1. input_example = {
  2. "sepal length (cm)": 5.1,
  3. "sepal width (cm)": 3.5,
  4. "petal length (cm)": 1.4,
  5. "petal width (cm)": 0.2
  6. }
  7. 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方法对模型进行评分,该方法有以下签名:
    1. 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):

  1. def __init__(self, n):
  2. self.n = n
  3. def predict(self, context, model_input):
  4. 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)]))

  1. <a name="FrDS9"></a>
  2. #### 示例:以MLflow格式保存XGBoost模型
  3. 本示例首先使用XGBoost库训练并保存一个梯度增强树模型。接下来,它围绕XGBoost模型定义了一个包装器类,该类符合MLflow的python_function推断API。然后,它使用包装器类和保存的XGBoost模型构建一个MLflow模型,该模型使用梯度增强树执行推断。最后,它以python_function格式加载MLflow模型,并使用它来计算测试数据。
  4. ```bash
  5. # Load training and test datasets
  6. from sys import version_info
  7. import xgboost as xgb
  8. from sklearn import datasets
  9. from sklearn.model_selection import train_test_split
  10. PYTHON_VERSION = "{major}.{minor}.{micro}".format(major=version_info.major,
  11. minor=version_info.minor,
  12. micro=version_info.micro)
  13. iris = datasets.load_iris()
  14. x = iris.data[:, 2:]
  15. y = iris.target
  16. x_train, x_test, y_train, _ = train_test_split(x, y, test_size=0.2, random_state=42)
  17. dtrain = xgb.DMatrix(x_train, label=y_train)
  18. # Train and save an XGBoost model
  19. xgb_model = xgb.train(params={'max_depth': 10}, dtrain=dtrain, num_boost_round=10)
  20. xgb_model_path = "xgb_model.pth"
  21. xgb_model.save_model(xgb_model_path)
  22. # Create an `artifacts` dictionary that assigns a unique name to the saved XGBoost model file.
  23. # This dictionary will be passed to `mlflow.pyfunc.save_model`, which will copy the model file
  24. # into the new MLflow Model's directory.
  25. artifacts = {
  26. "xgb_model": xgb_model_path
  27. }
  28. # Define the model class
  29. import mlflow.pyfunc
  30. class XGBWrapper(mlflow.pyfunc.PythonModel):
  31. def load_context(self, context):
  32. import xgboost as xgb
  33. self.xgb_model = xgb.Booster()
  34. self.xgb_model.load_model(context.artifacts["xgb_model"])
  35. def predict(self, context, model_input):
  36. input_matrix = xgb.DMatrix(model_input.values)
  37. return self.xgb_model.predict(input_matrix)
  38. # Create a Conda environment for the new MLflow Model that contains all necessary dependencies.
  39. import cloudpickle
  40. conda_env = {
  41. 'channels': ['defaults'],
  42. 'dependencies': [
  43. 'python={}'.format(PYTHON_VERSION),
  44. 'pip',
  45. {
  46. 'pip': [
  47. 'mlflow',
  48. 'xgboost=={}'.format(xgb.__version__),
  49. 'cloudpickle=={}'.format(cloudpickle.__version__),
  50. ],
  51. },
  52. ],
  53. 'name': 'xgb_env'
  54. }
  55. # Save the MLflow Model
  56. mlflow_pyfunc_model_path = "xgb_mlflow_pyfunc"
  57. mlflow.pyfunc.save_model(
  58. path=mlflow_pyfunc_model_path, python_model=XGBWrapper(), artifacts=artifacts,
  59. conda_env=conda_env)
  60. # Load the model in `python_function` format
  61. loaded_model = mlflow.pyfunc.load_model(mlflow_pyfunc_model_path)
  62. # Evaluate the model
  63. import pandas as pd
  64. test_predictions = loaded_model.predict(pd.DataFrame(x_test))
  65. 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。

示例请求:

  1. # split-oriented
  2. curl http://127.0.0.1:5000/invocations -H 'Content-Type: application/json' -d '{
  3. "columns": ["a", "b", "c"],
  4. "data": [[1, 2, 3], [4, 5, 6]]
  5. }'
  6. # record-oriented (fine for vector rows, loses ordering for JSON records)
  7. curl http://127.0.0.1:5000/invocations -H 'Content-Type: application/json; format=pandas-records' -d '[
  8. {"a": 1,"b": 2,"c": 3},
  9. {"a": 4,"b": 5,"c": 6}
  10. ]'

有关序列化pandas数据帧的更多信息,请参见panda . dataframe .to_json。
predict命令接受相同的输入格式。格式指定为命令行参数。

命令

  • serve将模型部署为本地REST API服务器。
  • build_docker封包了一个REST API端点作为docker映像服务于模型。
  • predict使用该模型为本地CSV或JSON文件生成预测。

更多的信息请查看

  1. mlflow models --help
  2. mlflow models serve --help
  3. mlflow models predict --help
  4. 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:显示指定目标器的帮助字符串

更多信息,请查看

  1. mlflow deployments --help
  2. mlflow deployments create --help
  3. mlflow deployments delete --help
  4. mlflow deployments update --help
  5. mlflow deployments list --help
  6. mlflow deployments get --help
  7. mlflow deployments run-local --help
  8. mlflow deployments help --help