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

1,234 阅读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 描述符,包括 PandasDataFrame、String、Image 和 File。

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 实例自定义服务的构建时间和运行时行为。