对 AI Platform 模型进行负载测试和监控

本文档介绍如何测试和监控部署到 AI Platform Prediction 的机器学习 (ML) 模型的在线服务性能。本文档使用 Locust,这是一种用于负载测试的开源工具。

本文档适用于想要监控其生产环境中机器学习模型的服务工作负载、延迟时间和资源利用率的数据科学家和 MLOps 工程师。

本文档假定您具有一定的 Google Cloud、TensorFlow、AI Platform Prediction、Cloud Monitoring 和 Jupyter 笔记本的经验。

该文件带有 GitHub 代码库 其中包含代码和部署指南 如本文档中所述。这些任务已整合到 Jupyter 笔记本中。

费用

您在本文档中使用的笔记本采用 Google Cloud 的以下收费组件:

如需根据您的预计使用量来估算费用,请使用价格计算器

准备工作

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  3. Make sure that billing is enabled for your Google Cloud project.

  4. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  5. Make sure that billing is enabled for your Google Cloud project.

架构概览

下图展示了用于部署机器学习模型以进行在线预测、运行负载测试以及收集和分析机器学习模型服务性能指标的系统架构。

用于部署模型以及收集和分析模型性能的架构。

下图展示了以下流程:

  1. 经过训练的模型可能位于 Cloud Storage 中,例如 TensorFlow SavedModelscikit-learn joblib。或者,也可能包含在自定义服务容器中 Container Registry,适用于 示例, TorchServe 提供 PyTorch 模型。
  2. 该模型部署到 AI Platform Prediction 作为 REST API 使用AI Platform Prediction 是一项全代管式服务, 模型服务, 不同的机器类型, 支持 自动扩缩 基于资源利用率,支持各种 GPU 加速器
  3. Locust 用于实现测试任务(即用户行为)。为此,它会调用已部署到 AI Platform Prediction 的机器学习模型,并在 Google Kubernetes Engine (GKE) 上大规模运行该模型。这会模拟用户同时进行多个调用来负载测试模型预测服务的情况。您可以使用 Locust 网页界面监控测试的进度。
  4. Locust 将测试统计信息记录到 Cloud Logging。Locust 测试创建的日志条目用于定义 Cloud Monitoring 中的一组基于日志的指标。这些指标是标准 AI Platform Prediction 指标的补充。
  5. AI Platform 指标和自定义 Locust 指标 可用于直观呈现数据 Cloud Monitoring 信息中心 实时更新测试完成后,系统还会以编程方式收集指标,以便您分析和直观呈现 Vertex AI Workbench 用户管理的笔记本中的指标。

此场景中的 Jupyter 笔记本

准备和部署模型、运行 Locust 测试以及收集和分析测试结果等所有任务都在以下 Jupyter 笔记本中进行编码。如需执行任务,您需要运行每个笔记本中的单元序列。

  1. 01-prepare-and-deploy.ipynb。运行此笔记本以准备用于提供服务的 TensorFlow SavedModel,并将模型部署到 AI Platform Prediction。
  2. 02-perf-testing.ipynb。运行此笔记本以在 Cloud Monitoring 中为 Locust 测试创建基于日志的指标,以及将 Locust 测试部署到 GKE 并运行它。
  3. 03-analyze-results.ipynb。运行此笔记本以从 Cloud Monitoring 创建的标准 AI Platform 指标以及自定义 Locust 指标收集和分析 Locust 负载测试结果。

初始化环境

如关联的 GitHub 代码库的 README.md 文件中所述,您需要执行以下步骤准备环境来运行笔记本:

  1. 在您的 Google Cloud 项目中,创建一个 Cloud Storage 存储桶,用于存储经过训练的模型和 Locust 测试配置。请记下用于存储桶的名称,因为稍后需要用到。
  2. 创建 Cloud Monitoring 工作区
  3. 创建具有所需 CPU 的 Google Kubernetes Engine 集群。节点池必须有权访问 Cloud API。
  4. 创建使用 TensorFlow 2 的 Vertex AI Workbench 用户管理笔记本实例。在本教程中,您不需要 GPU,因为您不需要训练模型。(GPU 在其他场景中可能很有用,特别是用于加快模型训练。)

打开 JupyterLab

如需完成此场景的任务,您需要打开 JupyterLab 环境并获取笔记本。

  1. 在 Google Cloud Console 中,前往 Notebooks 页面。

    前往 Notebooks

  2. 用户管理的笔记本标签页上,点击您创建的笔记本环境旁边的打开 Jupyterlab

    这将在浏览器中打开 JupyterLab 环境。

  3. 如需启动终端标签,请点击启动器标签页中的终端图标。

  4. 在终端中,克隆 mlops-on-gcp GitHub 代码库:

    git clone https://github.com/GoogleCloudPlatform/mlops-on-gcp.git
    

    命令完成后,您会在文件浏览器中看到 mlops-on-gcp 文件夹。 在该文件夹中,您会看到在本文档中使用的笔记本。

配置笔记本设置

在本部分中,您将使用特定于您的上下文的值设置笔记本中的变量,并准备环境以运行适用于该场景的代码。

  1. 导航到 model_serving/caip-load-testing 目录。
  2. 对于这三个笔记本中的每个笔记本,请执行以下操作:
    1. 打开笔记本。
    2. 运行配置 Google Cloud 环境设置下的单元。

以下各部分重点介绍了过程的主要部分,并解释了设计和代码的各个方面。

提供模型以进行在线预测

本文档中使用的机器学习模型使用 ResNet V2 101 图片分类模型 来自 TensorFlow Hub。 但是,您可调整本文档中的系统设计模式和技术,使其适应其他领域和其他类型的模型。

准备和提供 ResNet 101 模型的代码位于 01-prepare-and-deploy.ipynb 笔记本。在笔记本中运行这些单元以执行以下任务:

  1. 从 TensorFlow Hub 下载并运行 ResNet 模型。
  2. 为模型创建服务签名。
  3. 将该模型导出为 SavedModel。
  4. 将 SavedModel 部署到 AI Platform Prediction。
  5. 验证已部署的模型。

本文档中的后续部分详细介绍了如何准备 ResNet 模型以及如何进行部署。

准备 ResNet 模型以进行部署

TensorFlow Hub 中的 ResNet 模型没有服务签名,因为它针对重组和微调进行了优化。因此,您需要为模型创建服务签名,以便可以提供模型用于在线预测。

此外,为了提供模型,我们建议您将特征工程逻辑嵌入服务接口中。这样做可以保证预处理与模型服务之间的关联,而不是依赖于客户端应用以所需的格式预处理数据。您还必须在服务接口中添加后处理,例如将类 ID 转换为类标签。

为使 ResNet 模型可用,您需要实现描述模型推理方法的服务签名。因此,笔记本代码会添加两个签名:

  • 默认签名。此签名公开了 ResNet V2 101 模型的默认 predict 方法。默认方法没有预处理逻辑或后处理逻辑。
  • 预处理和后处理签名。此接口的预期输入需要相对复杂的预处理,包括编码、扩缩和归一化图片。因此,该模型还公开了一个替代签名,它用于嵌入预处理和后处理逻辑。此签名接受未处理的原始图片,并返回一个包含已排序的类标签和关联的标签概率的列表。

签名是在自定义模块类中创建的。该类派生自 该 tf.Module 封装 ResNet 模型的基类。自定义类通过实现图片预处理和输出后处理逻辑的方法扩展基类。自定义模块的默认方法会映射到基础 ResNet 模型的默认方法,来维持类似的接口。自定义模块导出为 SavedModel,其中包含原始模型、预处理逻辑和两个服务签名。

以下代码段展示了自定义模块类的实现:

LABELS_KEY = 'labels'
PROBABILITIES_KEY = 'probabilities'
NUM_LABELS = 5

class ServingModule(tf.Module):
    """
    A custom tf.Module that adds image preprocessing and output post processing to
    a base TF 2 image classification model from TensorFlow Hub.
    """

    def __init__(self, base_model, input_size, output_labels):
        super(ServingModule, self).__init__()
        self._model = base_model
        self._input_size = input_size
        self._output_labels = tf.constant(output_labels, dtype=tf.string)

    def _decode_and_scale(self, raw_image):
        """
        Decodes, crops, and resizes a single raw image.
        """

        image = tf.image.decode_image(raw_image, dtype=tf.dtypes.uint8, expand_animations=False)
        image_shape = tf.shape(image)
        image_height = image_shape[0]
        image_width = image_shape[1]
        crop_size = tf.minimum(image_height, image_width)
        offset_height = ((image_height - crop_size) + 1) // 2
        offset_width = ((image_width - crop_size) + 1) // 2

        image = tf.image.crop_to_bounding_box(image, offset_height, offset_width, crop_size, crop_size)
        image = tf.image.resize(image, [self._input_size, self._input_size])
        image = tf.cast(image, tf.uint8)

        return image

    def _preprocess(self, raw_inputs):
        """
        Preprocesses raw inputs as sent by the client.
        """

        # A mitigation for https://github.com/tensorflow/tensorflow/issues/28007
        with tf.device('/cpu:0'):
            images = tf.map_fn(self._decode_and_scale, raw_inputs, dtype=tf.uint8)
        images = tf.image.convert_image_dtype(images, tf.float32)

        return images

    def _postprocess(self, model_outputs):
        """
        Postprocess outputs returned by the base model.
        """

        probabilities = tf.nn.softmax(model_outputs)
        indices = tf.argsort(probabilities, axis=1, direction='DESCENDING')

        return {
            LABELS_KEY: tf.gather(self._output_labels, indices, axis=-1)[:,:NUM_LABELS],
            PROBABILITIES_KEY: tf.sort(probabilities, direction='DESCENDING')[:,:NUM_LABELS]
        }

    @tf.function(input_signature=[tf.TensorSpec([None, 224, 224, 3], tf.float32)])
    def __call__(self, x):
        """
        A pass-through to the base model.
        """

        return self._model(x)

    @tf.function(input_signature=[tf.TensorSpec([None], tf.string)])
    def predict_labels(self, raw_images):
        """
        Preprocesses inputs, calls the base model
        and postprocess outputs from the base model.
        """

        # Call the preprocessing handler
        images = self._preprocess(raw_images)

        # Call the base model
        logits = self._model(images)

        # Call the postprocessing handler
        outputs = self._postprocess(logits)

        return outputs

serving_module = ServingModule(model, 224, imagenet_labels)

以下代码段展示了模型如何导出为 SavedModel,其中包含之前定义的服务签名:

...

default_signature = serving_module.__call__.get_concrete_function()
preprocess_signature = serving_module.predict_labels.get_concrete_function()
signatures = {
    'serving_default': default_signature,
    'serving_preprocess': preprocess_signature
}

tf.saved_model.save(serving_module, model_path, signatures=signatures)

将模型部署到 AI Platform Prediction

将模型导出为 SavedModel 时,系统将执行以下任务:

  • 系统将该模型上传到 Cloud Storage。
  • 系统在 AI Platform Prediction 中创建模型对象。
  • 系统为 SavedModel 创建模型版本。

笔记本中的以下代码段展示了执行这些任务的命令。

gcloud storage cp {model_path} {GCS_MODEL_LOCATION} --recursive

gcloud ai-platform models create {MODEL_NAME} \
    --project {PROJECT_ID} \
    --regions {REGION}

MACHINE_TYPE='n1-standard-8'
ACCELERATOR='count=1,type=nvidia-tesla-p4'

gcloud beta ai-platform versions create {MODEL_VERSION} \
    --model={MODEL_NAME} \
    --origin={GCS_MODEL_LOCATION} \
    --runtime-version=2.1 \
    --framework=TENSORFLOW \
    --python-version=3.7 \
    --machine-type={MACHINE_TYPE} \
    --accelerator={ACCELERATOR} \
    --project={PROJECT_ID}

该命令会为模型预测服务以及 nvidia-tesla-p4 GPU 加速器创建 n1-standard-8 机器类型。

运行包含这些命令的笔记本单元后,您可以在 Google Cloud 控制台AI Platform 模型页面中查看模型版本,从而验证模型版本是否已部署。输出内容类似如下:

通过 Google Cloud 控制台验证模型是否已部署。

创建 Cloud Monitoring 指标

设置模型以提供服务后,您可以配置指标来监控服务性能。用于配置指标的代码位于 02-perf-testing.ipynb 笔记本。

02-perf-testing.ipynb 笔记本会使用 Python Cloud Logging SDK。 这些指标基于由 Locust 任务生成的日志条目。log_stats 方法会将日志条目写入名为 locust 的 Cloud Logging 日志。

每个日志条目都包含一组 JSON 格式的键值对,如下表所列。这些指标基于日志条目中的部分键。

值的说明 用量
test_id 测试 ID 过滤
特性
model AI Platform Prediction 模型名称
model_version AI Platform Prediction 模型版本
latency 第 95 百分位的响应时间,该时间在 10 秒的滑动窗口中计算得出 指标
num_requests 自测试开始以来的请求总数
num_failures 自测试开始以来的失败总数
user_count 模拟用户的数量
rps 每秒请求数

以下代码段显示了笔记本中创建基于日志的自定义指标的 create_locust_metric 函数。

def create_locust_metric(
    metric_name:str,
    log_path:str,
    value_field:str,
    bucket_bounds:List[int]):

    metric_path = logging_client.metric_path(PROJECT_ID, metric_name)
    log_entry_filter = 'resource.type=global AND logName={}'.format(log_path)

    metric_descriptor = {
        'metric_kind': 'DELTA',
        'value_type': 'DISTRIBUTION',
        'labels': [{'key': 'test_id', 'value_type': 'STRING'},
                   {'key': 'signature', 'value_type': 'STRING'}]}

    bucket_options = {
        'explicit_buckets': {'bounds': bucket_bounds}}

    value_extractor = 'EXTRACT(jsonPayload.{})'.format(value_field)
    label_extractors = {
        'test_id': 'EXTRACT(jsonPayload.test_id)',
        'signature': 'EXTRACT(jsonPayload.signature)'}

    metric = logging_v2.types.LogMetric(
        name=metric_name,
        filter=log_entry_filter,
        value_extractor=value_extractor,
        bucket_options=bucket_options,
        label_extractors=label_extractors,
        metric_descriptor=metric_descriptor,
    )

    try:
        logging_client.get_log_metric(metric_path)
        print('Metric: {} already exists'.format(metric_path))
    except:
        logging_client.create_log_metric(parent, metric)
        print('Created metric {}'.format(metric_path))

以下代码段展示了如何在笔记本中调用 create_locust_metric 方法来创建上表中显示的四个自定义 Locust 指标。

# user count metric
metric_name = 'locust_users'
value_field = 'user_count'
bucket_bounds = [1, 16, 32, 64, 128]

create_locust_metric(metric_name, log_path, value_field, bucket_bounds)

# latency metric
metric_name = 'locust_latency'
value_field = 'latency'
bucket_bounds = [1, 50, 100, 200, 500]

create_locust_metric(metric_name, log_path, value_field, bucket_bounds)

# failure count metric
metric_name = 'num_failures'
value_field = 'num_failures'
bucket_bounds = [1, 1000]

create_locust_metric(metric_name, log_path, value_field, bucket_bounds)

# request count metric
metric_name = 'num_requests'
value_field = 'num_requests'
bucket_bounds = [1, 1000]

create_locust_metric(metric_name, log_path, value_field, bucket_bounds)

笔记本会创建一个名为 AI Platform Prediction 和 Locust 的自定义 Cloud Monitoring 信息中心。信息中心会组合标准 AI Platform Prediction 指标和根据 Locust 日志创建的自定义指标。

有关详情,请参阅 Cloud Logging API 文档。

您可以手动创建此信息中心及其图表。不过,笔记本提供了一种以编程方式创建它的方法,只需使用 monitoring-template.json JSON 模板。代码使用 DashboardsServiceClient 类加载 JSON 模板,并在 Cloud Monitoring 中创建信息中心, 如以下代码段所示:

parent = 'projects/{}'.format(PROJECT_ID)

dashboard_template_file = 'monitoring-template.json'
with open(dashboard_template_file) as f:
    dashboard_template = json.load(f)

dashboard_proto = Dashboard()
dashboard_proto = ParseDict(dashboard_template, dashboard_proto)
dashboard = dashboard_service_client.create_dashboard(parent, dashboard_proto)

创建信息中心后,您可以在 Google Cloud 控制台的 Cloud Monitoring 信息中心列表中看到它:

显示 Monitoring 信息中心列表的 Google Cloud 控制台页面。

您可以点击信息中心将其打开,然后查看图表。每个图表都会显示来自 AI Platform Prediction 或 Locust 日志的指标,如以下屏幕截图所示。

根据日志数据显示指标的各种图表。

将 Locust 测试部署到 GKE 集群

在将 Locust 系统部署到 GKE 之前,您需要构建 Docker 容器映像,其中包含 task.py 文件中内置的测试逻辑。该映像派生自 baseline locust.io 映像,并用于 Locust 主节点和工作器 pod。

用于构建和部署的逻辑位于笔记本的 3. 将 Locust 部署到 GKE 集群下。该映像使用以下代码构建:

image_uri = 'gcr.io/{}/locust'.format(PROJECT_ID)

!gcloud builds submit --tag {image_uri} locust/locust-image

笔记本中描述的部署过程是使用 Kustomize 定义的。通过 Locust Kustomize 部署清单 定义以下定义组件的文件:

  • locust-master。此文件定义了一个部署,用于托管一个网页界面,您可在其中开始测试并查看实时统计信息。
  • locust-worker。此文件定义了一个部署,用于运行任务以对机器学习模型预测服务进行负载测试。通常,系统会创建多个工作器来模拟多个用户同时调用预测服务 API 的效果。
  • locust-worker-service。此文件定义了一项服务,用于通过 HTTP 负载均衡器访问 locust-master 中的网页界面。

在部署集群之前,您需要更新默认清单。通过 默认清单包含 kustomization.yamlpatch.yaml files;则必须在这两个文件中进行更改

kustomization.yaml 文件中,执行以下操作:

  • 设置自定义 Locust 映像的名称。将 images 部分中的 newName 字段设置为您之前构建的自定义映像的名称。
  • (可选)设置工作器 Pod 的数量。默认配置会部署 32 个工作器 Pod。要更改数量,请修改 replicas 部分中的 count 字段。确保您的 GKE 集群具有足够数量的 Locust 工作器 CPU。
  • 为测试配置和载荷文件设置 Cloud Storage 存储桶。在 configMapGenerator 部分中,确保设置以下内容:
    • LOCUST_TEST_BUCKET。将此项设置为您之前创建的 Cloud Storage 存储桶的名称。
    • LOCUST_TEST_CONFIG。将此项设置为测试配置文件名。在 YAML 文件中,此项设置为 test-config.json,但如果您要使用其他名称,可以更改此项。
    • LOCUST_TEST_PAYLOAD。将此项设置为测试载荷文件名。在 YAML 文件中,此项设置为 test-payload.json,但如果您要使用其他名称,可以更改此项。

patch.yaml 文件中,执行以下操作:

  • (可选)修改托管 Locust 主实例和工作器的节点池。如果将 Locust 工作负载部署到 default-pool 以外的节点池,请找到 matchExpressions 部分,然后在 values 下更新 Locust 工作负载将部署到的节点池的名称。

进行这些更改后,您可以将自定义设置构建到 Kustomize 清单中,并将 Locust 部署(locust-masterlocust-workerlocust-master-service)应用到 GKE 集群。笔记本中的以下命令用于执行这些任务:

!kustomize build locust/manifests | kubectl apply -f -

您可以在 Google Cloud 控制台中检查已部署的工作负载。输出内容类似如下:

显示工作负载的 GKE 控制台。

实现 Locust 负载测试

Locust 的测试任务是调用已部署到 AI Platform Prediction 的模型。

此任务在 AIPPClient 类中实现,该类位于 /locust/locust-image/ 文件夹中的 task.py 模块。以下代码段展示了类实现。

class AIPPClient(object):
   """
   A convenience wrapper around AI Platform Prediction REST API.
   """

   def __init__(self, service_endpoint):
       logging.info(
         "Setting the AI Platform Prediction service endpoint: {}".format(service_endpoint))
       credentials, _ = google.auth.default()
       self._authed_session = AuthorizedSession(credentials)
       self._service_endpoint = service_endpoint

   def predict(self, project_id, model, version, signature, instances):
       """
       Invokes the predict method on the specified signature.
       """

       url = '{}/v1/projects/{}/models/{}/versions/{}:predict'.format(
           self._service_endpoint, project_id, model, version)

       request_body = {
           'signature_name': signature,
           'instances': instances
       }

       response = self._authed_session.post(url, data=json.dumps(request_body))
       return response

task.py 文件中的 AIPPUser 类继承自 locust.User 类来模拟调用 AI Platform Prediction 模型的用户行为。此行为是在 predict_task 方法中实现的。AIPPUser 类的 on_start 方法会从 Cloud Storage 存储桶下载以下文件,该存储桶是在 task.py 文件中的 LOCUST_TEST_BUCKET 变量中指定的。

  • test-config.json。此 JSON 文件包括测试的以下配置:test_idproject_idmodelversion
  • test-payload.json。此 JSON 文件包含 AI Platform Prediction 预期格式的数据实例以及目标签名。

用于准备测试数据和测试配置的代码包含在 02-perf-testing.ipynb 笔记本4.配置 Locust 测试

测试配置和数据实例用作 AIPPClient 类中 predict 方法的参数,以使用所需的测试数据测试目标模型。AIPPUser 模拟等待时间 间隔 1 到 2 秒。

运行 Locust 测试

运行笔记本单元以将 Locust 工作负载部署到 GKE 集群后,并且在创建 test-config.jsontest-payload.json 文件然后将这些文件上传到 Cloud Storage 后,您可以使用新 Locust 负载测试的网页界面来启动、停止和配置该测试。笔记本中的代码会使用以下命令检索公开该网页界面的外部负载均衡器的网址:

%%bash
IP_ADDRESS=$(kubectl get service locust-master | awk -v  col=4 'FNR==2{print $col}')
echo http://$IP_ADDRESS:8089

如需执行测试,请执行以下操作:

  1. 在浏览器中,输入您检索的网址。
  2. 如需使用不同的配置模拟测试工作负载,请在 Locust 界面中输入值,如下所示:

    用于启动 Locust 测试运行的 Locust 界面。

    上面的屏幕截图展示了以下配置值:

    • 要模拟的用户总数:150
    • 填充率:1
    • 主机:http://ml.googleapis.com
    • 逐步增加的用户数:10
    • 单步时长:2m

测试运行时,您可以通过检查 Locust 图表来监控测试。以下屏幕截图显示了值的显示方式。

其中一个图表展示了每秒请求总数:

展示每秒请求数的 Locust 图表。

另一个图表展示了以毫秒为单位的响应时间:

显示以毫秒为单位的响应时间的 Locust 图表。

如前所述,这些统计信息也会记录到 Cloud Logging 中,以便您创建基于日志的自定义 Cloud Monitoring 指标。

收集和分析测试结果

下一项任务是收集和分析 Cloud Monitoring 指标, 根据结果日志计算得出, Pandas DataFrame 对象 以便在笔记本中直观呈现和分析结果。用于 执行此任务的 03-analyze-results.ipynb 笔记本。

代码使用 Cloud Monitoring Query Python SDK 来过滤和检索指标值,即传入 project_idtest_idstart_timeend_timemodelmodel_versionlog_name 参数。

以下代码段显示了检索 AI Platform Prediction 指标和基于日志的自定义 Locust 指标的方法。

import pandas as pd
from google.cloud.monitoring_v3.query import Query

def _get_aipp_metric(metric_type: str, labels: List[str]=[], metric_name=None)-> pd.DataFrame:
    """
    Retrieves a specified AIPP metric.
    """
    query = Query(client, project_id, metric_type=metric_type)
    query = query.select_interval(end_time, start_time)
    query = query.select_resources(model_id=model)
    query = query.select_resources(version_id=model_version)

    if metric_name:
        labels = ['metric'] + labels
    df = query.as_dataframe(labels=labels)

    if not df.empty:
        if metric_name:
            df.columns.set_levels([metric_name], level=0, inplace=True)
        df = df.set_index(df.index.round('T'))
        return df

def _get_locust_metric(metric_type: str, labels: List[str]=[],
                       metric_name=None)-> pd.DataFrame:
    """
     Retrieves a specified custom logs-based metric.
     """
     query = Query(client, project_id, metric_type=metric_type)
     query = query.select_interval(end_time, start_time)
     query = query.select_metrics(log=log_name)
     query = query.select_metrics(test_id=test_id)

     if metric_name:
         labels = ['metric'] + labels
     df = query.as_dataframe(labels=labels)

     if not df.empty:
        if metric_name:
            df.columns.set_levels([metric_name], level=0, inplace=True)
        df = df.apply(lambda row: [metric.mean for metric in row])
        df = df.set_index(df.index.round('T'))

     return df

对于每个指标,会以 Pandas DataFrame 对象的形式检索指标数据,然后将各个数据帧合并为一个 DataFrame 对象。具有合并结果的最终 DataFrame 对象在笔记本中如下所示:

笔记本中具有合并 DataFrame 对象的 Pandas 框架的显示情况。

检索到的 DataFrame 对象使用 分层索引 。这是因为某些指标包含多个时间序列。例如,GPU duty_cycle 指标包括部署中使用的每个 GPU 的测量时间序列,表示为 replica_id。列索引的顶层显示单个指标的名称。第二个级别是副本 ID。第三级别显示模型的签名。所有指标都在同一时间轴上对齐。

下图展示了您在笔记本中看到的 GPU 利用率、CPU 利用率和延迟时间。

GPU 利用率:

显示 GPU 利用率随时间变化的折线图。

CPU 利用率:

显示 CPU 利用率随时间变化的折线图。

延迟时间:

显示延迟时间随时间变化的折线图。

这些图表显示以下行为和序列:

  1. 随着工作负载(用户数量)的增加,CPU 和 GPU 利用率也会增加。因此,延迟时间会增加,模型延迟时间与总延迟时间之间的差异也会增加,直到在 20:40 左右达到峰值。
  2. 在 20:40,GPU 利用率达到 100%,而 CPU 图表显示利用率达到 4 个 CPU。示例在此测试使用具有 8 个 CPU 的 n1-standard-8 机器。因此,CPU 利用率达到 50%。
  3. 此时,自动扩缩功能会添加容量:添加新的服务节点并附加一个 GPU 副本。第一个 GPU 副本利用率下降,第二个 GPU 副本利用率增加。
  4. 延迟时间会随着新副本开始处理预测而减少,在大约 200 毫秒时收敛。
  5. 每个副本的 CPU 利用率收敛在大约 250%,即利用 8 个 CPU 中的 2.5 个。此值表示您可以使用 n1-standard-4 机器,而不是 n1-standard-8 机器。

清理

为避免因本文档中使用的资源导致您的 Google Cloud 产生费用,请删除包含这些资源的项目,或者保留项目但删除各个资源。

  1. In the Google Cloud console, go to the Manage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

如果您想保留 Google Cloud 项目但删除您创建的资源,请删除 Google Kubernetes Engine 集群和已部署的 AI Platform 模型。

后续步骤