自定义预测例程

通过自定义预测例程,您可以决定 AI Platform Prediction 收到您的在线预测请求时应该运行的代码。

如果您在将版本资源部署到 AI Platform Prediction 时未使用自定义预测例程,则该服务会执行用于训练的机器学习框架的预测操作来处理预测请求。

但是,将自定义预测例程部署为版本资源时,您可以让 AI Platform Prediction 运行自定义 Python 代码来响应其收到的每个预测请求。您可以在经过训练的模型执行预测之前对预测输入进行预处理,也可以在发送预测结果之前对模型的预测进行后处理。

如需创建自定义预测例程,您必须在创建模型版本时向 AI Platform Prediction 提供以下两部分内容:

  • Cloud Storage 中的模型目录,其中包含预测所需的任何工件。

  • Cloud Storage 中的 .tar.gz Python 源分发软件包,其中包含您的 Predictor 接口实现以及您希望 AI Platform Prediction 在预测时使用的任何其他自定义代码。

将模型工件上传到您的模型目录

请按照模型部署指南,将经过训练的模型以及任何其他文件(这些文件用于提供数据或有状态性,以供 AI Platform 在预测时使用)上传到 Cloud Storage。

部署到 AI Platform Prediction 的模型工件的文件总大小不能超过 500 MB。您可以申请增加配额以部署更大的模型。

您可以将经过训练的机器学习模型作为 TensorFlow SavedModelmodel.joblib 文件、model.pkl 文件或 model.bst 文件上传到模型目录中,不过您也可以用包含经过训练的 tf.keras 模型的 HDF5 文件或者其他序列化格式提供模型。

您还可以包括一个带有自定义预处理器类实例的 pickle 文件,用于存储训练中的序列化状态。

preprocess.py 文件中定义的以下处理器为例:

import numpy as np

class ZeroCenterer(object):
    """Stores means of each column of a matrix and uses them for preprocessing.
    """

    def __init__(self):
        """On initialization, is not tied to any distribution."""
        self._means = None

    def preprocess(self, data):
        """Transforms a matrix.

        The first time this is called, it stores the means of each column of
        the input. Then it transforms the input so each column has mean 0. For
        subsequent calls, it subtracts the stored means from each column. This
        lets you 'center' data at prediction time based on the distribution of
        the original training data.

        Args:
            data: A NumPy matrix of numerical data.

        Returns:
            A transformed matrix with the same dimensions as the input.
        """
        if self._means is None:  # during training only
            self._means = np.mean(data, axis=0)
        return data - self._means

在对数值数据集进行训练的过程中,预处理器将各列中的每个值减去该列的平均值,使数据集中于 0 上下。然后,您可以将预处理器实例导出为 pickle 文件 preprocessor.pkl,该文件存储根据训练数据计算的每列的平均值。

在预测过程中,自定义预测例程可以从该文件加载预处理器,以便对预测输入执行相同的转换。

如需了解如何在您的自定义预测例程中使用与此类似的有状态预处理器,请查看下一部分,该部分介绍如何实现 Predictor 接口。

如需查看在训练和预测期间使用有状态预处理器的完整示例,请参阅使用 Keras 创建自定义预测例程使用 scikit-learn 创建自定义预测例程

创建 Predictor

若想让 AI Platform Prediction 了解如何处理预测请求,向其提供 Predictor 类即可。该类实现了以下接口:

class Predictor(object):
    """Interface for constructing custom predictors."""

    def predict(self, instances, **kwargs):
        """Performs custom prediction.

        Instances are the decoded values from the request. They have already
        been deserialized from JSON.

        Args:
            instances: A list of prediction input instances.
            **kwargs: A dictionary of keyword args provided as additional
                fields on the predict request body.

        Returns:
            A list of outputs containing the prediction results. This list must
            be JSON serializable.
        """
        raise NotImplementedError()

    @classmethod
    def from_path(cls, model_dir):
        """Creates an instance of Predictor using the given path.

        Loading of the predictor should be done in this method.

        Args:
            model_dir: The local directory that contains the exported model
                file along with any additional files uploaded when creating the
                version resource.

        Returns:
            An instance implementing this Predictor class.
        """
        raise NotImplementedError()

AI Platform Prediction 预测节点使用 from_path 类方法加载 Predictor 实例。该方法应加载您在模型目录中保存的工件;模型目录的内容是从 Cloud Storage 复制到 model_dir 参数指向的位置。

每当您的部署收到在线预测请求时,from_path 返回的 Predictor 类实例都会使用其 predict 方法生成预测。AI Platform Prediction 会将此方法的返回值序列化为 JSON 格式,并将其作为对预测请求的响应发送。

请注意,predict 方法不需要将输入从 JSON 转换为 Python 对象,也不需要将输出转换为 JSON;AI Platform Prediction 会在 predict 方法之外进行这项处理操作。

AI Platform Prediction 会将 predict 请求正文中的 instances 字段解析到 AI Platform Training and Prediction API,以此提供 instances 参数。它会解析请求正文的其他所有字段,并将这些字段作为 **kwargs 字典中的条目提供给 predict 方法。如需了解详情,请参阅如何设计对 AI Platform Training and Prediction API 的 predict 请求的结构

继续上一部分中的示例,假设您的模型目录包含 preprocessor.pklZeroCenterer 类的 pickle 实例)和一个导出为 model.h5、经过训练的 tf.keras 模型或一个导出为 model.joblib、经过训练的 scikit-learn 模型。

根据您使用的机器学习框架,您可以在名为 predictor.py 的文件中实现下列其中一个 Predictor 类:

TensorFlow

import os
import pickle

import numpy as np
from tensorflow import keras

class MyPredictor(object):
    """An example Predictor for an AI Platform custom prediction routine."""

    def __init__(self, model, preprocessor):
        """Stores artifacts for prediction. Only initialized via `from_path`.
        """
        self._model = model
        self._preprocessor = preprocessor

    def predict(self, instances, **kwargs):
        """Performs custom prediction.

        Preprocesses inputs, then performs prediction using the trained Keras
        model.

        Args:
            instances: A list of prediction input instances.
            **kwargs: A dictionary of keyword args provided as additional
                fields on the predict request body.

        Returns:
            A list of outputs containing the prediction results.
        """
        inputs = np.asarray(instances)
        preprocessed_inputs = self._preprocessor.preprocess(inputs)
        outputs = self._model.predict(preprocessed_inputs)
        return outputs.tolist()

    @classmethod
    def from_path(cls, model_dir):
        """Creates an instance of MyPredictor using the given path.

        This loads artifacts that have been copied from your model directory in
        Cloud Storage. MyPredictor uses them during prediction.

        Args:
            model_dir: The local directory that contains the trained Keras
                model and the pickled preprocessor instance. These are copied
                from the Cloud Storage model directory you provide when you
                deploy a version resource.

        Returns:
            An instance of `MyPredictor`.
        """
        model_path = os.path.join(model_dir, 'model.h5')
        model = keras.models.load_model(model_path)

        preprocessor_path = os.path.join(model_dir, 'preprocessor.pkl')
        with open(preprocessor_path, 'rb') as f:
            preprocessor = pickle.load(f)

        return cls(model, preprocessor)

scikit-learn

import os
import pickle

import numpy as np
from sklearn.externals import joblib

class MyPredictor(object):
    """An example Predictor for an AI Platform custom prediction routine."""

    def __init__(self, model, preprocessor):
        """Stores artifacts for prediction. Only initialized via `from_path`.
        """
        self._model = model
        self._preprocessor = preprocessor

    def predict(self, instances, **kwargs):
        """Performs custom prediction.

        Preprocesses inputs, then performs prediction using the trained
        scikit-learn model.

        Args:
            instances: A list of prediction input instances.
            **kwargs: A dictionary of keyword args provided as additional
                fields on the predict request body.

        Returns:
            A list of outputs containing the prediction results.
        """
        inputs = np.asarray(instances)
        preprocessed_inputs = self._preprocessor.preprocess(inputs)
        outputs = self._model.predict(preprocessed_inputs)
        return outputs.tolist()

    @classmethod
    def from_path(cls, model_dir):
        """Creates an instance of MyPredictor using the given path.

        This loads artifacts that have been copied from your model directory in
        Cloud Storage. MyPredictor uses them during prediction.

        Args:
            model_dir: The local directory that contains the trained
                scikit-learn model and the pickled preprocessor instance. These
                are copied from the Cloud Storage model directory you provide
                when you deploy a version resource.

        Returns:
            An instance of `MyPredictor`.
        """
        model_path = os.path.join(model_dir, 'model.joblib')
        model = joblib.load(model_path)

        preprocessor_path = os.path.join(model_dir, 'preprocessor.pkl')
        with open(preprocessor_path, 'rb') as f:
            preprocessor = pickle.load(f)

        return cls(model, preprocessor)

请注意,predict 方法会使用 tolist 方法将预测结果转换为列表后再将其返回。NumPy 数组不能进行 JSON 序列化,因此您必须将它们转换为可进行 JSON 序列化的数字列表。否则,AI Platform Prediction 将无法发送预测响应。

打包您的 Predictor 及其依赖项

您必须将您的 Predictor 打包为 .tar.gz 源分发软件包。由于 AI Platform Prediction 运行时映像中包含 NumPy、TensorFlow 和 scikit-learn,因此您不需要将这些依赖项加入 tar 压缩文件中。但是,请务必添加 AI Platform Prediction 上未预装的任何 Predictor 依赖项。

对于上述示例,您必须在源分发软件包中包含 preprocess.py,即使您的 Predictor 未明确导入该文件也一样。否则 preprocessor = pickle.load(f) 将失败,因为 Python 无法识别 pickle 文件中 ZeroCenterer 实例的类。

以下 setup.py 介绍了打包这些脚本的一种方法:

from setuptools import setup

setup(
    name='my_custom_code',
    version='0.1',
    scripts=['predictor.py', 'preprocess.py'])

如需打包和上传本页介绍的自定义代码示例,请执行以下操作:

  1. 创建前面部分介绍的 preprocess.pypredictor.pysetup.py 文件,并全部保存在同一目录中。在 shell 中导航到该目录。

  2. 运行 python setup.py sdist --formats=gztar 以创建 dist/my_custom_code-0.1.tar.gz

  3. 将此 tar 压缩文件上传到 Cloud Storage 中的暂存位置。

    该位置不必与您的模型目录相同。如果您计划迭代和部署自定义预测例程的多个版本,则可能需要在指定的暂存目录上传您的自定义代码软件包。更新代码以跟踪不同版本时,您可以递增 setup.py 中的 version 参数。

    以下命令展示了将源分发软件包上传到 Cloud Storage 的一种方法:

    gsutil cp dist/my_custom_code-0.1.tar.gz gs://your-bucket/path-to-staging-dir/
    

您可以在一个或多个软件包中提供自定义预测例程的代码。

部署自定义预测例程

首先,选择一个提供在线预测服务的区域,并使用 gcloud 创建模型资源:

gcloud ai-platform models create model-name \
  --regions chosen-region

确保您的 gcloud beta 组件已更新,然后创建版本资源,请特别注意以下 gcloud 标志:

  • --origin:Cloud Storage 中模型目录的路径。
  • --package-uris:Cloud Storage 中用户代码 tar 存档文件的列表(以英文逗号分隔各项),其中包括含有您的 Predictor 类的 tar 存档文件。
  • --prediction-class:Predictor 类的完全限定名称 (module_name.class_name)。
  • --framework:部署自定义预测例程时,请勿指定框架。
  • --runtime-version运行时版本 1.4 至 2.2 支持自定义预测例程。

以下命令展示了如何基于前面部分中介绍的示例文件创建版本资源:

gcloud components install beta

gcloud beta ai-platform versions create version-name \
  --model model-name \
  --runtime-version 2.2 \
  --python-version 3.7 \
  --origin gs://your-bucket/path-to-model-dir \
  --package-uris gs://your-bucket/path-to-staging-dir/my_custom_code-0.1.tar.gz \
  --prediction-class predictor.MyPredictor

如需详细了解如何创建模型和版本,或了解如何使用 Google Cloud Console 而不是 gcloud 工具来创建模型和版本,请参阅模型部署指南

指定服务帐号

创建版本资源时,您可以选择为自定义预测例程指定一个在预测期间使用的服务帐号。这样,您就可以自定义该例程对其他 Google Cloud 资源的访问权限。详细了解如何为自定义预测例程指定服务帐号

后续步骤

  • 学习有关通过 Keras通过 scikit-learn 使用自定义预测例程的教程,查看更完整的示例,了解如何使用自定义预测例程训练和部署模型。
  • 阅读模型导出指南,了解如何在不使用自定义预测例程的情况下导出用于预测的工件。
  • 参阅模型部署指南,详细了解如何将 modelversion 资源部署到 AI Platform Prediction 以执行预测。