BentoML 是一个用于机器学习模型服务的开源框架,旨在弥合数据科学和 DevOps 之间的差距(gap)。
数据科学家可以使用 BentoMl 轻松打包使用任何 ML 框架训练的模型,并重现该模型以用于生产。
BentoML 协助管理 BentoML 格式打包的模型,并允许 DevOps 将它们部署为任何云平台上的在线 API 服务端点或离线批量推理作业。
下面将演示了如何使用 BentoML 通过 REST API 服务为 sklearn 模型提供服务,然后将模型服务容器化以进行生产部署。
BentoML 需要 Python 3.6 或更高版本,然后,通过 pip 安装依赖项:
# 安装本教程需要的依赖包,包括BentoML
pip install -q bentoml==v1.0.0-a6
pip install -q 'scikit-learn>=0.23.2' 'pandas>=1.1.1'
我们预先准备一个训练的模型来使用 BentoML 提供服务。 模型训练完成后,使用我们的工具将特定框架训练的模型保存为 BentoML 标准格式。
首先,在鸢尾花(Iris)数据集上训练一个分类模型:
# train.py
from sklearn import svm
from sklearn import datasets
import bentoml
# Load training data
iris = datasets.load_iris()
X, y = iris.data, iris.target
# Model Training
clf = svm.SVC(gamma='scale')
clf.fit(X, y)
# 调用`bentoml.<FRAMEWORK>.save(<MODEL_NAME>, model)` 为了在本地模型存储中保存为 BentoML 的标准格式
bentoml.sklearn.save("iris_clf", clf)
运行结果:
$ python train.py
03/31/22 16:15:13 INFO [cli] Successfully saved Model(tag="iris_clf:wdqpqfvqzk32yhqa", path="/Users/liguodong/bentoml/models/iris_clf/wdqpqfvqzk32yhqa/")
bentoml.sklearn.save()
会将 Iris 分类模型保存到由 BentoML 管理的本地模型存储中。 目前所有受支持的建模库,请参阅ML framework specific API。
模型也可以通过 bentoml models
CLI 命令进行管理。 更多信息请使用 bentoml models --help
。
$ bentoml models list
Tag Module Path Size Creation Time
iris_clf:wdqpqfvqzk32yhqa bentoml.sklearn /Users/liguodong/bentoml/models/iris_clf/wdqpqfvqzk32yhqa 5.64 KiB 2022-03-31 08:15:13
然后,您可以使用bentoml.<FRAMEWORK>.load(<TAG>)
加载要在线运行的模型。同时,您也可以使用 bentoml.<FRAMEWORK>.load_runner(<TAG>)
API 使用性能优化的运行器。
# verify.py
import bentoml
runner = bentoml.sklearn.load_runner("iris_clf:latest")
print(runner.run([5.9, 3., 5.1, 1.8])) # => array(2)
服务是 BentoML 的核心组件,其中定义了服务逻辑。
通过保存在模型仓库中的模型,我们可以创建 Python 文件 service.py
来定义服务,其内容如下:
# service.py
import numpy as np
import bentoml
from bentoml.io import NumpyNdarray
# 加载我们刚刚保存的最新 ScikitLearn 模型的运行器
iris_clf_runner = bentoml.sklearn.load_runner("iris_clf:latest")
# 使用 ScikitLearn 运行器创建 iris_classifier 服务
# 如果需要,可以在runners数组中指定多个运行器
# 当包装为bento时,运行器(runners)也会被包括在里面
svc = bentoml.Service("iris_classifier", runners=[iris_clf_runner])
# 使用“svc”注解创建具有预处理和后处理逻辑的 API 函数
@svc.api(input=NumpyNdarray(), output=NumpyNdarray())
def classify(input_series: np.ndarray) -> np.ndarray:
# 定义预处理逻辑
result = iris_clf_runner.run(input_series)
# 定义后处理逻辑
return result
在此示例中,我们将输入和输出类型定义为 numpy.ndarray
。 还支持更多选项,例如 pandas.DataFrame
和 PIL.image
。 要查看所有支持的选项,请参阅API 和 IO 描述。
到此为止,我们现在拥有了满足第一个请求所需要的一切。
我们通过在当前工作目录中运行 bentoml serve
命令以调试模式启动服务。使用 --reload
选项允许服务显示对 service.py
模块所做的任何更改,而无需重新启动(热更新):
$ bentoml serve ./service.py:svc --reload
03/31/22 17:00:54 INFO [cli] Starting development BentoServer from "./service.py:svc" running on http://127.0.0.1:3000 (Press CTRL+C to quit)
03/31/22 17:00:55 INFO [dev_api_server] Service imported from source: bentoml.Service(name="iris_classifier", import_str="service:svc",
working_dir="/Users/liguodong/work/gitee/sample-all-py3/mlops/bentoml/bento_deploy")
03/31/22 17:00:55 INFO [dev_api_server] Will watch for changes in these directories: ['/Users/liguodong/work/gitee/sample-all-py3/mlops/bentoml/bento_deploy']
03/31/22 17:00:55 INFO [dev_api_server] Started reloader process [54356] using statreload
03/31/22 17:00:56 INFO [cli] Started server process [54359]
03/31/22 17:00:56 INFO [cli] Waiting for application startup.
03/31/22 17:00:56 INFO [cli] Application startup complete.
03/31/22 17:05:36 WARNING [dev_api_server] StatReload detected file change in 'service.py'. Reloading...
03/31/22 17:05:36 INFO [cli] Shutting down
03/31/22 17:05:36 INFO [cli] Waiting for application shutdown.
03/31/22 17:05:36 INFO [cli] Application shutdown complete.
03/31/22 17:05:36 INFO [cli] Finished server process [54359]
03/31/22 17:05:37 INFO [cli] Started server process [54372]
03/31/22 17:05:37 INFO [cli] Waiting for application startup.
03/31/22 17:05:37 INFO [cli] Application startup complete.
03/31/22 17:08:13 INFO [cli] 127.0.0.1:56051 (scheme=http,method=POST,path=/classify,type=application/json,length=9) (status=200,type=application/json,length=1) 3.123ms
(trace=108811182904080858968430329246303376687,span=3358824710013532286,sampled=0)
然后,我们可以使用任何 HTTP 客户端向新启动的服务发送请求。比如,通过python http request 请求:
# http_request.py
import requests
print(requests.post(
"http://127.0.0.1:3000/classify",
headers={"content-type": "application/json"},
data="[5,4,3,2]").text)
或者通过curl请求:
> curl \
-X POST \
-H "content-type: application/json" \
--data "[5,4,3,2]" \
http://127.0.0.1:3000/classify
BentoML 可以以多种方式优化您的服务,例如,BentoML 使用了两个最快的 Python Web 框架 Starlette 和 Uvicorn,以便大规模高效地为您的模型提供服务。
有关性能优化的更多信息,请参阅 BentoServer。
一旦我们对服务定义感到满意,我们就可以将模型和服务构建成bento。 Bentos 是服务的分发格式,包含运行或部署这些服务所需的所有信息,例如模型和依赖项。 有关构建bento的更多信息,请参阅Building Bentos。
要构建 Bento,首先在项目目录中创建一个名为 bentofile.yaml 的文件:
# bentofile.yaml
service: "service.py:svc" # 定位服务的约定:<YOUR_SERVICE_PY>:<YOUR_SERVICE_ANNOTATION>
description: "file: ./README.md"
labels:
owner: bentoml-team
stage: demo
include:
- "*.py" # 用于匹配要包含在bento中的文件的格式
python:
packages:
- scikit-learn==0.23.2 # bento中将包含的其他的依赖库
- pandas>=1.1.1
接下来,在同样的目录中的bentoml build
CLI 命令来构建一个bento。
$ bentoml build
03/31/22 17:41:06 INFO [cli] Building BentoML service "iris_classifier:v7eedwvq22c5ahqa" from build context
"/Users/liguodong/work/gitee/sample-all-py3/mlops/bentoml/bento_deploy"
03/31/22 17:41:06 INFO [cli] Packing model "iris_clf:wdqpqfvqzk32yhqa" from "/Users/liguodong/bentoml/models/iris_clf/wdqpqfvqzk32yhqa"
03/31/22 17:41:06 INFO [cli] Successfully saved Model(tag="iris_clf:wdqpqfvqzk32yhqa",
path="/var/folders/_7/b59dvhj56lq3lr4jpsx2h7t80000gn/T/tmpfekkt4b3bentoml_bento_iris_classifier/models/iris_clf/wdqpqfvqzk32yhqa/")
03/31/22 17:41:06 INFO [cli] Locking PyPI package versions..
03/31/22 17:47:00 INFO [cli]
██████╗░███████╗███╗░░██╗████████╗░█████╗░███╗░░░███╗██╗░░░░░
██╔══██╗██╔════╝████╗░██║╚══██╔══╝██╔══██╗████╗░████║██║░░░░░
██████╦╝█████╗░░██╔██╗██║░░░██║░░░██║░░██║██╔████╔██║██║░░░░░
██╔══██╗██╔══╝░░██║╚████║░░░██║░░░██║░░██║██║╚██╔╝██║██║░░░░░
██████╦╝███████╗██║░╚███║░░░██║░░░╚█████╔╝██║░╚═╝░██║███████╗
╚═════╝░╚══════╝╚═╝░░╚══╝░░░╚═╝░░░░╚════╝░╚═╝░░░░░╚═╝╚══════╝
03/31/22 17:47:00 INFO [cli] Successfully built Bento(tag="iris_classifier:v7eedwvq22c5ahqa") at "/Users/liguodong/bentoml/bentos/iris_classifier/v7eedwvq22c5ahqa/"
构建的Bentos将保存在本地bento商店中,您可以使用bentoml list
CLI 命令查看。
$ bentoml list
Tag Service Path Size Creation Time
iris_classifier:v7eedwvq22c5ahqa service:svc /Users/liguodong/bentoml/bentos/iris_classifier/v7eedwvq22c5ahqa 15.21 KiB 2022-03-31 09:47:00
我们可以使用bentoml serve --production
CLI 命令从bento商店提供bentos服务。其中,--production
选项将在生产模式下提供bento服务。
$ bentoml serve iris_classifier:veshoxfq3wzyqhqa --production
03/31/22 18:02:41 INFO [cli] Service loaded from Bento store: bentoml.Service(tag="iris_classifier:v7eedwvq22c5ahqa",
path="/Users/liguodong/bentoml/bentos/iris_classifier/v7eedwvq22c5ahqa")
03/31/22 18:02:41 INFO [cli] Starting production BentoServer from "bento_identifier" running on http://0.0.0.0:3000 (Press CTRL+C to quit)
03/31/22 18:02:42 INFO [api_server] Service loaded from Bento store: bentoml.Service(tag="iris_classifier:v7eedwvq22c5ahqa",
path="/Users/liguodong/bentoml/bentos/iris_classifier/v7eedwvq22c5ahqa")
03/31/22 18:02:42 INFO [iris_clf] Service loaded from Bento store: bentoml.Service(tag="iris_classifier:v7eedwvq22c5ahqa",
path="/Users/liguodong/bentoml/bentos/iris_classifier/v7eedwvq22c5ahqa")
03/31/22 18:02:42 INFO [iris_clf] Started server process [54672]
03/31/22 18:02:42 INFO [iris_clf] Waiting for application startup.
03/31/22 18:02:42 INFO [api_server] Started server process [54673]
03/31/22 18:02:42 INFO [api_server] Waiting for application startup.
03/31/22 18:02:42 INFO [api_server] Application startup complete.
03/31/22 18:02:45 INFO [iris_clf] Application startup complete.
Bento 目录包含运行此服务所需的所有代码、文件、模型和配置。 BentoML 标准化了这个文件结构,使服务运行时和部署工具能够建立在它之上。 默认情况下,Bentos 在~/bentoml/bentos
目录下进行管理:
$ cd ~/bentoml/bentos/iris_classifier && cd $(cat latest)
$ tree
.
├── README.md
├── apis
│ └── openapi.yaml
├── bento.yaml
├── env
│ ├── docker
│ │ ├── Dockerfile
│ │ ├── entrypoint.sh
│ │ └── init.sh
│ └── python
│ ├── requirements.lock.txt
│ ├── requirements.txt
│ └── version.txt
├── models
│ └── iris_clf
│ ├── latest
│ └── y3f4ijcxj3i6zo6x2ie5eubhd
│ ├── model.yaml
│ └── saved_model.pkl
└── src
├── iris_classifier.py
└── train.py
8 directories, 14 files
最后,我们可以使用bentoml containerize
CLI 命令将 bentos 容器化为Docker 镜像,并使用模型和 bento 管理服务 来大规模管理bentos。
首先,需确保您已安装 docker 并运行了 docker deamon,以下命令将使用您的本地 docker 环境构建一个新的 docker 镜像,并包含来自此 Bento 的模型服务配置。
$ bentoml containerize iris_classifier:veshoxfq3wzyqhqa
# 运行容器测试镜像的构建
$ docker run -p 5000:5000 iris_classifier:invwzzsw7li6zckb2ie5eubhd
BentoML 是一个开放平台,可简化 ML 模型部署并使您能够在几分钟内以生产规模为模型提供服务。