简述
BentoML 是一个用于机器学习模型服务的开源框架,旨在弥合数据科学和 DevOps 之间的差距(gap)。
数据科学家可以使用 BentoMl 轻松打包使用任何 ML 框架训练的模型,并重现该模型以用于生产。
BentoML 协助管理 BentoML 格式打包的模型,并允许 DevOps 将它们部署为任何云平台上的在线 API 服务端点或离线批量推理作业。
为什么选择 BentoML
- 将您的 ML 模型转换为生产就绪 API 非常简单。
- 高性能模型服务,并且全部使用 Python。
- 标准化模型打包和 ML 服务定义以简化部署。
- 支持所有主流的机器学习训练框架。
- 通过Yatai在 Kubernetes 上大规模部署和运行 ML 服务。
下面将演示了如何使用 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 本地模型仓库的模型
模型也可以通过 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 定义和调试 ML 预测服务
服务是 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 描述。
到此为止,我们现在拥有了满足第一个请求所需要的一切。
在本地启动一个 API server 进行测试
我们通过在当前工作目录中运行 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。
构建和部署 Bentos
一旦我们对服务定义感到满意,我们就可以将模型和服务构建成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 目录说明
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 复制代码
将 Bento 容器化以进行部署
最后,我们可以使用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 模型部署并使您能够在几分钟内以生产规模为模型提供服务。