部署机器学习模型原理及实践(bentoml)
前言
在进入正题之前,首先我们来讲点概念性的东西,在传统的软件开发流程中,我们一般采用devops的流程,其中的核心阶段包含产品立项–需求分析–原型设计–前后端开发–测试–持续发布–生产运维等等,可以看出整个周期是非常长,这其实不满足当下机器学习不断产出新模型不断落地的要求,特别是在没有做过机器学习业务的传统软件开发公司里。于是引出了mlops的概念,即更快的开发模型,更快的部署模型,和确保模型的质量,而为了达成这点就需要一个统一管理部署模型的工具。这个工具应该让数据科学家能够直接使用,尽量减少语言障碍,以及尽量减少部署要求。
什么意思呢?下面我将给大家一个实例理解:笔者身为公司唯一一个数据科学家,每次训练完模型之后需要把它投入生产,此时我需要先找产品说明情况,再找平台端(java)商量怎么部署,按之前的做法需要笔者本人自己把模型用m2cgen库直接转换为java代码(只有简单的十几种模型可以且不支持预处理),或者用pmml标准格式把模型导出为pmml文件,再通过jpmml库调用(比m2cgen全多了支持pipeline直接转换但是bug奇多且一个bug找一天)。以上两种方式,需要你有一定的java知识,同时也浪费了你大量时间在找不属于自身的bug上,导致新模型开发进度严重缓慢,虽然好处是你不用管后面的事情,但这种方式也对java开发的程序员不友好,增加了任务,延长了周期,甚至部署的时候还容易出毛病(需要大量的沟通毕竟他们不懂)。
那么正确的做法我想也有些老手猜到了,没错,就是把模型放在云上,用API服务去调用。但问题也随之而来:
一.放在交钱的大型云上,如paddlepaddle,华为云。这方面外国更成熟,但是我想因为隐私和机密还有网络问题大家很少会去选择。且国内的大厂都给你开发好了一套白痴型的部署工具,管理起来不是很方便吗?没问题,有钱任性,但我没钱,我也不可能向公司申请一个流程来照顾我这还没盈利的业务,我觉得这种方法更适合那些有钱的中大型公司。
二.那就本地在服务器上起个服务部署,使用100%你会搜索到的python的flask库自己写。 这种方式的问题在于,你得自己写很多额外的代码,麻烦,同时部署不方便,你需要一个单独部署python环境的服务器,如果你到别人企业里私有化部署难不成你还一步步给它安装一个python环境吗?所以照我来看,这也只是一种临时方案,无法满足我一键部署一键生产的要求。
于是在翻遍了github的机器学习的生产部署库后,我终于看到了一款完美符合我需求,即使渣渣服务器也能跑的免费开源库----bentoml。
bentoml非常通用,基本支持常见的框架,这里就不说了,总之就是非常通用,深度学习的模型也可以通过它布,下面我还是用最简单的sklearn讲解。
在讲解bentoml库的同时我也将分享我自己的部署方案。
所以流程是?
其实在搜索机器学习模型部署的过程中最头疼的事情就是你没有一个清晰的概念,该怎么做,服务器是什么,怎么和我的模型联系在一起,怎么通过API调用,而网上的很多文章也不讲具体的流程,把代码往那一贴就完事了,也不知道是从哪抄来的代码,又或者是官方示例,不知所云。
下面给出我自己画的大概流程图配合食用:
那么代码是?
首先是安装,这个想必大家懂得都懂了
pip install bentoml
这里说一下bentoml目前最高兼容python3.8,虽然3.9也能用,但是假如你用不习惯win10的docker想用虚拟机装环境跑docker时请务必保持各包(python,sklearn,numpy等等)版本一致,不然可能导致某些复杂模型结果不准(比如stackingclassifier)。
然后就是第一步,本地先把模型训练到完美的程度,当然如果你只想随便试一下能不能用,建议抄示例:
from sklearn import svm
from sklearn import datasets# Load training data
iris = datasets.load_iris()
X, y = iris.data, iris.target# Model Training
clf = svm.SVC(gamma='scale')
clf.fit(X, y)
这一步我在流程图上写.ipynb是因为个人喜欢用Jupyterlab跑模型,在部署的过程中把你的关键代码复制到notebook里跑一跑是一个好习惯。总之,你要在这一步保证你的代码就算作为一个脚本文件也能顺利运行。
第二步,利用bentoml库打包模型,个人不喜欢官网的打包架构方式,不利于操作和理解,在这里我们把主体分为export.py和bento_service.py两部分。export.py为主体,涵盖了模型的训练和打包两部分,bento_service.py作为一个类导入进export.py里使用。你需要把它们放到conda的python解释器的具体目录下方便后面的命令行操作。
具体如下:
#export.py
import pandas as pd
from sklearn import preprocessing
from sklearn.model_selection import train_test_split
from sklearn.ensemble import StackingClassifier
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.naive_bayes import GaussianNB
from bento_service_json import IrisClassifier
from sklearn.decomposition import PCA
df_temp1 = pd.read_excel('temp1.xlsx')
df_temp2 = pd.read_excel('temp-e.xlsx')
le = preprocessing.LabelEncoder()
x = df_temp1.iloc[:,1:17]
y = le.fit_transform(df_temp1.iloc[:,17])
x1 = df_temp2.iloc[:,1:17]
y1 = le.fit_transform(df_temp2.iloc[:,17])
X_train, X_test, y_train, y_test = train_test_split(x, y,train_size=0.8, test_size=0.2, random_state=42)
estimators = [('GB', GradientBoostingClassifier(learning_rate=1.0, max_depth=8, max_features=0.35000000000000003, min_samples_leaf=9, min_samples_split=6, n_estimators=100, subsample=0.6500000000000001,random_state=42)),('tree', DecisionTreeClassifier(criterion="gini", max_depth=9, min_samples_leaf=1, min_samples_split=2,random_state=42))
]
model = StackingClassifier(estimators=estimators,stack_method='predict',final_estimator=KNeighborsClassifier(n_neighbors=3, p=2, weights="uniform")
)
model.fit(X_train,y_train) #模型1
X_train, X_test, y_train, y_test = train_test_split(x1, y1,train_size=0.75, test_size=0.25, random_state=42)
clf=GaussianNB()
clf.fit(X_train,y_train) #模型2
# 从bento_service.py里面抽取的服务类
iris_classifier_service = IrisClassifier()# 打包两个模型
iris_classifier_service.pack('StackingClassifier', model)
iris_classifier_service.pack('GaussianNB', clf)
# 保存到本地,路径可自己写
saved_path = iris_classifier_service.save()
别看代码那么长,其实只是把第一步的训练代码放了进去,同时加上了四行打包代码,另外为了拓展知识,我们在这里使用了两个模型,同时打包进一个服务里面。
#bento_service.py
import pandas as pd
import json
from bentoml import env, artifacts, api, BentoService
from bentoml.adapters import JsonInput
from bentoml.frameworks.sklearn import SklearnModelArtifact@env(infer_pip_packages=True) #打包时自动寻找所有的依赖
@artifacts([SklearnModelArtifact('StackingClassifier'),SklearnModelArtifact("GaussianNB")])#定义的两个模型
class IrisClassifier(BentoService):@api(input=JsonInput(), batch=False)#使用jsoninput,batch注意为falsedef predict(self, parsed_json):df = pd.read_json(parsed_json,orient='table')#将json转换为dataframedata1 = df[["Aggression", "pressure", "anxiety", "suspect", "balance","confidence", "energy", "self-regulation", "inhibition", "neuroticism","deperession", "happiness", "fh_m", "fh_s","I","E"]]#选取特征列result = pd.DataFrame([['StackingClassifier', self.artifacts.StackingClassifier.predict(data1),'HealthType=2'], ['GaussianNB', self.artifacts.GaussianNB.predict_proba(data1)[:, 0],'Probability']]) return json.loads(result.to_json(orient="records")) #按行导出json
bento_service.py是核心,如果代码报错90%可能性是出自这块,这块我们比较关心的是输入和输出,输入有多种方式,你也可以直接用dataframeinput,但这里我们为了扩展知识采取了与示例不同的json方式,json的输入格式如下:
datain = '{"schema":{"fields":[{"name":"index","type":"integer"},{"name":"Aggression","type":"number"},{"name":"pressure","type":"number"},{"name":"anxiety","type":"number"},{"name":"suspect","type":"number"},{"name":"balance","type":"number"},{"name":"confidence","type":"number"},{"name":"energy","type":"number"},{"name":"self-regulation","type":"number"},{"name":"inhibition","type":"number"},{"name":"neuroticism","type":"number"},{"name":"deperession","type":"number"},{"name":"happiness","type":"number"},{"name":"I","type":"number"},{"name":"E","type":"number"},{"name":"fh_m","type":"number"},{"name":"fh_s","type":"number"},{"name":"Extroversion","type":"number"},{"name":"Stability","type":"number"}],"primaryKey":["index"],"pandas_version":"0.20.0"},"data":[{"index":100,"Aggression":46.58,"pressure":23.35,"anxiety":41.71,"suspect":37.76,"balance":64.67,"confidence":79.75,"energy":31.07,"self-regulation":72.71,"inhibition":23.41,"neuroticism":23.65,"deperession":25.13,"happiness":28.26,"I":28.99,"E":4.23,"fh_m":2.26,"fh_s":0.71,"Extroversion":0.36,"Stability":0.43}]}'
用pd.read_json时传入的json一定要包含schema,不然pandas不知道用什么数据类型去读你传过来的数据,这边非常建议百度json,复制校验一下你的json格式对不对,如果你传的json包含很多斜杠,说明你用了json.dumps,你应该用json.loads方法先把斜杠去掉再传。
核心的predict方法,想返回什么参数,是预测值还是概率,都可以自己定义自己写。
在准备好两个py文件之后,进入第三步,启动命令行:
输入python export.py,就会开始运行你的脚本程序,如果出现以下字样:
表示模型已经打包成功了!现在你可以启动你的服务了。使用bentoml serve IrisClassifier:latest命令启动你最新生成的服务,或者把latest改为你要启动的服务的版本号,比如上图里就是20220110113101_2C47F4,实际上是年月日时分秒加六位十六进制。
你就拿到了你本地服务器的ip地址,http://127.0.0.1:25577,模型已经跑在服务器上了,接下来进行本地传参测试:
import requests
response = requests.post("http://127.0.0.1:25577/predict", json=datain) #datain是你要传的json
print(response.text)
#[{"0": "StackingClassifier", "1": [1], "2": "HealthType=2"}, {"0": "GaussianNB", "1": [1.0], "2": "Probability"}]
返回结果了(命令行也能看到返回什么),我自己定义了三个字段,一个是模型名称,一个是返回的概率值,另一个是返回的数据类型。
这上面都大功告成之后,接下来就是第四步导出了:
这里我只讲win10的docker安装的一些问题:
一.请预留至少10个G的C盘空间,docker本身不大,它的vmdx文件很大(我这里占了7个G)。
二.想要docker_engine跑起来,要么安装linux内核的虚拟环境(wsl2),要么安装hyper-V,hyper-V相对于wsl2运行更慢,但是安装更傻瓜,windows程序和功能里面勾上就会安装重启。
成功起来之后长这样。
确保docker能运行之后,在命令行里输入:
bentoml containerize IrisClassifier:latest -t iris-classifier
bentoml就会自动把你的最新版本的服务容器化为docker的镜像。使用镜像的话可以pull但是这里选择更简单的不需要网络的方式,即把镜像save为tar包:
docker save -o iris.tar
这也就是第五步,在你的电脑上完成的最后一步,时间可能有点久,生成的tar包大概有1个G多大。
完成之后先把iris.tar远程传到linux服务器的root目录下,
在linux服务器的shell上使用以下命令:
#centos没安装docker的先一键安装docker
#curl -sSL https://get.daocloud.io/docker | sh
#装载镜像
docker load -i iris.tar
#启动服务
docker run -p 5000:5000 iris-classifier:20220110113101_2C47F4
这样就在linux服务器的5000端口上跑起来了服务,可以使用postman和curl命令传参测试。
到此,我们完成了一个模型周期的生产部署,还有很多细节,限于篇幅限制就不写了,希望各位参阅官方文档:
https://docs.bentoml.org/en/0.13-lts/quickstart.html
官方项目地址:
https://github.com/bentoml/BentoML
这是一个非常良心的开源库,希望能有更多的人使用和发展它!
部署机器学习模型原理及实践(bentoml)相关推荐
- 手把手教你使用Flask轻松部署机器学习模型(附代码链接) | CSDN博文精选
作者 | Abhinav Sagar 翻译 | 申利彬 校对 | 吴金笛 来源 | 数据派THU(ID:DatapiTHU) 本文旨在让您把训练好的机器学习模型通过Flask API 投入到生产环境 ...
- 独家 | 手把手教你如何使用Flask轻松部署机器学习模型(附代码链接)
作者:Abhinav Sagar 翻译:申利彬 校对:吴金笛 本文约2700字,建议阅读7分钟. 本文可以让你把训练好的机器学习模型使用Flask API 投入生产环境. 本文旨在让您把训练好的机器学 ...
- 陈天奇任CTO,TVM团队成立OctoML:让任何硬件都能部署机器学习模型
陈天奇任CTO,TVM团队成立OctoML:让任何硬件都能部署机器学习模型 据机器之心消息,知名人工智能青年学者.华盛顿大学博士陈天奇于近期参与创建了创业公司 OctoML,担任 CTO 一职. 随着 ...
- 机器学习模型部署_9月版部署机器学习模型
机器学习模型部署 每月版 (MONTHLY EDITION) Often, the last step of a Data Science task is deployment. Let's say ...
- 只需10分钟!就能用Flask,Docker和Jenkins部署机器学习模型
在生产环境中部署机器学习模型是数据工程中经常被忽视的领域.网上的大多数教程/博客都侧重于构建.训练和调整机器学习模型.如果它不能用于实际的预测,那么它又有什么用呢? 接下来了解一下有哪些部署选项吧: ...
- flask 部署_只需10分钟!就能用Flask,Docker和Jenkins部署机器学习模型
摘要: 一杯茶的功夫部署完成机器学习模型! 在生产环境中部署机器学习模型是数据工程中经常被忽视的领域.网上的大多数教程/博客都侧重于构建.训练和调整机器学习模型.如果它不能用于实际的预测,那么它又有什 ...
- 机器学习 部署 嵌入式_如何在移动和嵌入式设备上部署机器学习模型
机器学习 部署 嵌入式 介绍 (Introduction) Thanks to libraries such as Pandas, scikit-learn, and Matplotlib, it i ...
- 部署机器学习模型的后期监视
概述 部署机器学习模型后下一步是什么? 部署后的监视是任何机器学习项目中的关键步骤 学习部署模型后的监视的各个方面 介绍 你已经建立了你的机器学习模型.你甚至已经准备将你的模型投入生产(或模型部署). ...
- Django零基础部署机器学习模型(将模型预测打包成API接口/网页URL)
Django零基础部署机器学习模型 Django REST framework项目创建 框架结构了解 部署代码 Django REST framework项目创建 建立一个项目文件夹,使用VScode ...
最新文章
- 获取执行SQL语句的返回结果
- python买什么书好-python看什么书好
- centos7.4 ngixn1.13.10 mysql5.7.21 php7.2.3 源码编译安装之后php无法连接mysql
- 熊猫烧香演神话——在Windows mobile手机中运行
- mysql热备 binlog日志切割_查看MySQL还原出来的binlog日志中内容方法
- ActiveMQ官方文档翻译-内嵌消息中间件
- PHP中date()日期函数有关参数整理
- linux源码编译安装apache,Ubuntu 16.04源码编译安装Apache 2.4.25教程
- socks5认证过程
- .net core 跨平台UI框架 Avalonia
- opencv python 的基本操作案例(一) 记录,可查看
- 计算机组装与维护日记,计算机毕业生实习日志
- 无线 WIFI 的13个信道频率范围
- Android 出海 Admob 踩坑
- 北京航空航天大学计算机考研难度,北京航空航天大学考研难吗?一般要什么水平才可以进入?...
- 一页纸项目管理pdf_项目管理,一页纸就够了
- 控制面板打印机显示不出来的解决办法
- 某医药公司HP-EVA4400数据恢复报告
- RabbitMQ ACK消息确认机制 快速入门
- dns 解析,一个域名解析到多个ip地址
热门文章
- 考研学习视频资料下载
- 2022年上半年软考考试报名入口汇总(3月18日更新)
- Classifying Relations via Long Short Term Memory Networks along Shortest Dependency Paths
- 全球经济遭重创 中国科技公司应该如何突围?
- 与python相关的爬虫工具_python小课堂|爬虫工程师必备的10个python爬虫工具!
- UPC 2020年夏混合个人训练第六十场
- [ZT] 肯定是作弊:CNN这次投票要创“世界纪录”了
- 心理学在产品中的应用
- 规格组件-SKUSPU
- what is ITL( Interested Transaction list)