BentoML核心概念(一):服务定义

962 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第12天,点击查看活动详情

服务定义是面向服务架构(SOA)的体现,是 BentoML 中的核心构建块,用户在其中定义服务运行时架构和模型服务的逻辑。

本文将剖析和解释服务定义中的关键组件。让您将全面了解服务定义的组成以及每个关键组件的职责。

组成组件

在我们之前的快速入门指南中创建的模型服务定义如下所示。

# bento.py
import bentoml
import numpy as np

from bentoml.io import NumpyNdarray

# Load the runner for the latest ScikitLearn model we just saved
runner = bentoml.sklearn.load_runner("iris_classifier_model:latest")

# Create the iris_classifier_service with the ScikitLearn runner
svc = bentoml.Service("iris_classifier_service", runners=[runner])

# Create API function with pre- and post- processing logic
@svc.api(input=NumpyNdarray(), output=NumpyNdarray())
def predict(input_array: np.ndarray) -> np.ndarray:
    # Define pre-processing logic
    result = runner.run(input_array)
    # Define post-processing logic
    return result

从上面可以看出 BentoML 服务由三个组件组成:

  • 推理 APIs
  • 运行器(Runners)
  • 服务(Service)

推理 APIs

推理 API 定义了如何远程访问服务功能以及自定义预处理和后处理逻辑。

# Create API function with pre- and post- processing logic
@svc.api(input=NumpyNdarray(), output=NumpyNdarray())
def predict(input_array: np.ndarray) -> np.ndarray:
    # Define pre-processing logic
    result = runner.run(input_array)
    # Define post-processing logic
    return result

通过使用@svc.api装饰一个函数,我们声明该函数是可以远程访问的 API 的一部分。一个服务可以有一个或多个 API。 @svc.api 装饰器的输入和输出参数进一步定义了 API 的期望 IO(输入输出) 格式。

在上面的示例中,API 通过 NumpyNdarray IO 描述符将 IO (输入输出)类型定义为 numpy.ndarray。 IO 描述符有助于验证输入和输出是否符合预期的格式和模式,并将它们与原始的类型相互转换。 BentoML 支持多种 IO 描述符,包括 PandasDataFrameStringImageFile

API 也是定义模型服务的前处理和后处理逻辑的好地方。在上面的示例中,predict 函数中定义的逻辑将被打包并部署为服务逻辑的一部分。

BentoML 旨在通过基于可用系统资源启动 API 服务器的多个实例来并行化 API 逻辑。为了获得最佳性能,我们建议定义异步 API。要了解更多信息,请参考API 和 IO 描述符

运行器(Runners)

Runners 代表一个服务逻辑单元,可以水平扩展以最大化吞吐量。

# Load the runner for the latest ScikitLearn model we just saved
runner = bentoml.sklearn.load_runner("iris_classifier_model:latest")

可以通过调用特定框架的load_runner()函数或使用 @svc.runner 装饰器的装饰实现类来创建运行器。

框架特定的函数会智能地为运行器加载 ML 框架的最佳配置,以达到最固定的支持。

例如,如果 ML 框架发布了 Python GIL 并原生支持并发访问,BentoML 将创建 runner 的单个全局实例并将所有 API 请求路由到全局实例;否则,BentoML 将根据可用的系统资源创建多个运行器实例。

别担心,我们还允许用户自定义运行时配置以微调运行器性能。

load_runner() 函数的参数是我们之前保存的模型的名称和版本。使用 latest 关键字将确保加载模型的最新版本。加载运行器还向构建器声明,在构建服务时应将特定的模型和版本打包到bento中。我们还可以在服务中定义多个运行器。

要了解更多信息,请参阅 Runner 高级指南

服务(Service)

服务由 API 和 Runner 组成,可以通过 betoml.Service() 进行初始化。

# Create the iris_classifier_service with the ScikitLearn runner
svc = bentoml.Service("iris_classifier_service", runners=[runner])

服务的第一个参数是名称,该名称将在服务构建后成为 Bento 的名称。

运行器(Runners)应该是服务(Service)一部分,通过 runners 关键字参数传入。可以通过 svc 实例自定义服务的构建时间和运行时行为。