机器学习算法线上部署⽅法
本⽂由携程技术中⼼投递,ID:ctriptech。作者:潘鹏举,携程酒店研发BI经理,负责酒店服务相关的业务建模⼯作,主要研究⽅向是⽤机器学习实现业务流程⾃动化、系统智能化、效率最优化,专注于算法实践和应⽤。
我们经常会碰到⼀个问题:⽤了复杂的GBDT或者xgboost⼤⼤提升了模型效果,可是在上线的时候⼜犯难了,⼯程师说这个模型太复杂了,我没法上线,满⾜不了⼯程的要求,你帮我转换成LR吧,直接套⽤⼀个公式就好了,速度飞速,肯定满⾜⼯程要求。这个时候你⼜屁颠屁颠⽤回了LR,重新训练了⼀下模型,⼼⾥默骂千百遍:⼯程能⼒真弱。
这些疑问,我们以前碰到过,通过不断的摸索,试验出了不同的复杂机器学习的上线⽅法,来满⾜不同场景的需求。在这⾥把实践经验整理分享,希望对⼤家有所帮助。(我们的实践经验更多是倾向于业务模型的上线流程,⼴告和推荐级别的部署请⾃⾏绕道)。
⾸先在训练模型的⼯具上,⼀般三个模型训练⼯具,Spark、R、Python。这三种⼯具各有千秋,以后有时间,我写⼀下三种⼯具的使⽤⼼得。针对不同的模型使⽤场景,为了满⾜不同的线上应⽤的要求,会⽤不同的上线⽅法。
⼀、总结来说,⼤体会区分这三种场景,请⼤家对号⼊座,酌情使⽤
如果是实时的、⼩数据量的预测应⽤,则采⽤的SOA调⽤Rserve或者python-httpserve来进⾏应⽤;这种应⽤⽅式有个缺点是需要启⽤服务来进⾏预测,也就是需要跨环境,从Java跨到R或者Python环境。对于性能,基本上我们⽤Rserver⽅式,针对⼀次1000条或者更少请求的预测,可以控制95%的结果在100ms内返回结果,100ms可以满⾜⼯程上的实践要求。更⼤的数据量,⽐如10000/
次,100000/次的预测,我们⽬前评估下来满⾜不了100ms的要求,建议分批进⾏调⽤或者采⽤多线程请求的⽅式来实现。
如果是实时、⼤数据量的预测应⽤,则会采⽤SOA,训练好的模型转换成PMML(关于如何转换,我在下⾯会详细描述),然后把模型封装成⼀个类,⽤Java调⽤这个类来预测。⽤这种⽅式的好处是SOA不依赖于任何环境,任何计算和开销都是在Java内部⾥⾯消耗掉了,所以这种⼯程级别应⽤速度很快、很稳定。⽤此种⽅法也是要提供两个东西,模型⽂件和预测主类;
如果是Offline(离线)预测的,D+1天的预测,则可以不⽤考虑第1、2中⽅式,可以简单的使⽤Rscript x.R或者python x.py的⽅式来进⾏预测。使⽤这种⽅式需要⼀个调度⼯具,如果公司没有统⼀的调度⼯具,你⽤shell的crontab做定时调⽤就可以了。
以上三种做法,都会⽤SOA⾥⾯进⾏数据处理和变换,只有部分变换会在提供的Function或者类进⾏处理,⼀般性都建议在SOA⾥⾯处理好,否则性能会变慢。
⼤概场景罗列完毕,简要介绍⼀下各不同⼯具的线上应⽤的实现⽅式。
⼆、如何转换PMML,并封装PMML
⼤部分模型都可以⽤PMML的⽅式实现,PMML的使⽤⽅法调⽤范例见:
jpmml的说明⽂档:;
Java调⽤PMML的范例(),此案例是我们的⼯程师写的范例,⼤家可以根据此案例进⾏修改即可;
Jpmml⽀持的转换语⾔,主流的机器学习语⾔都⽀持了,深度学习类除外;
从下图可以看到,它⽀持R、python和spark、xgboost等模型的转换,⽤起来⾮常⽅便。
java调用python模型
三、接下来说⼀下各个算法⼯具的⼯程实践
1.python模型上线:我们⽬前使⽤了模型转换成PMML上线⽅法。
python-sklearn⾥⾯的模型都⽀持,也⽀持xgboost,并且PCA,归⼀化可以封装成preprocess转换成PMML,所以调⽤起来很⽅便;
特别需要注意的是:缺失值的处理会影响到预测结果,⼤家可以可以看⼀下;
⽤PMML⽅式预测,模型预测⼀条记录速度是1ms,可以⽤这个预测来预估⼀下根据你的数据量,整体的速度有多少。
2.R模型上线-这块我们⽤的多,可以⽤R model转换PMML的⽅式来实现。
这⾥我介绍另⼀种的上线⽅式:Rserve。具体实现⽅式是:⽤SOA调⽤Rserve的⽅式去实现,我们会在服务器上部署好R环境和安装好Rserve,然后⽤JAVA写好SOA接⼝,调⽤Rserve来进⾏预测;
java调⽤Rserve⽅式见⽹页链接:;
centos的Rserve搭建⽅法见:,这⾥详细描述了Rserve的搭建⽅式。
Rserve⽅式可以批量预测,跟PMML的单个预测⽅式相⽐,在少数据量的时候,PMML速度更快,但是如果是1000⼀次⼀批的效率上
看,Rserve的⽅式会更快;⽤Rserve上线的⽂件只需要提供两个:
模型结果⽂件(XX.Rdata);
预测函数(Pred.R)。
Rserve_1启动把模型结果(XX.Rdata)常驻内存。预测需要的输⼊Feature都在Java⾥定义好不同的变量,然后你⽤Java访问Rserve_1,调⽤Pred.R进⾏预测,获取返回的List应⽤在线上。最后把相关的输⼊输出存成log进⾏数据核对。
Pred.R <- function(x1,x2,x3){
data <- cbind(x1,x2,x3)
# feature engineering
score <- predict(modelname, data, type = 'prob')
return(list(score))
}
3.Spark模型上线-好处是脱离了环境,速度快。
Spark模型的上线就相对简单⼀些,我们⽤scala训练好模型(⼀般性我们都⽤xgboost训练模型)然后写⼀个Java Class,直接在JAVA中先获取数据,数据处理,把处理好的数据存成⼀个数组,然后调⽤模型Class进⾏预测。模型⽂件也会提前load在内存⾥⾯,存在⼀个进程⾥⾯,然后我们去调⽤这个进程来进⾏预测。所以速度蛮快的。
Spark模型上线,放在spark集,不脱离spark环境,⽅便,需要⾃⼰打jar包;
我们这⾥⽬前还没有尝试过,有⼀篇博客写到了如果把spark模型导出PMML,然后提交到spark集上来调⽤,⼤家可以参考⼀下:Spark加载PMML进⾏预测。
四、只⽤Linux的Shell来调度模型的实现⽅法-简单粗暴
因为有些算法⼯程师想快速迭代,把模型模拟线上线看⼀下效果,所以针对离线预测的模型形式,还有⼀种最简单粗暴的⽅法,这种⽅法开发快速⽅便,具体做法如下:
写⼀下R的预测脚本,⽐如predict.R,是你的主预测的模型;
然后⽤shell封装成xx.sh,⽐如predict.sh,shell⾥⾯调⽤模型,存储数据;
predict.sh的写法如下:
# 数据导出
data_filename = xxx
file_date = xxx
result = xxx
updatedt = xxx
cd path
hive -e "USE tmp_xxxdb;SELECT * FROM db.table1;" > ${data_filname};
# R脚本预测
Rscript path/predict.R  $file_date
if [ $? -ne 0 ]
then
echo"Running RScript Failure"
fi
# R预测的结果导⼊Hive表
list1="use tmp_htlbidb;
load data local inpath 'path/$result'
overwrite into table table2 partition(dt='${updatedt}');"
hive -e "$list1"
最后⽤Crontab来进⾏调度,很简单,如何设置crontab,度娘⼀下就好了。
>crontab -e
-------------------------
### 每天5点进⾏预测模型;
0 5 * * * sh predict.sh
五、说完了部署上线,说⼀下模型数据流转的注意事项
1. 区分offline和realtime数据,不管哪种数据,我们根据key和不同的更新频次,把数据放在redis⾥⾯去,设置不同的key和不同的过期时
间;
2. ⼤部分redis数据都会存放两个批次的数据,⽤来预防⽆法取到最新的数据,则⽤上⼀批次的数据来进⾏填充;
3. 针对offline数据,⽤调度⼯具做好依赖,每天跑数据,并⽣成信号⽂件让redis来进⾏读取;
4. 针对realtime数据,我们区分两种类型,⼀种是历史+实时,⽐如最近30天的累计订单量,则我们会
做两步,第⼀部分是D+1之前的数
据,存成A表,今天产⽣的实时数据,存储B表,A和B表表结构相同,时效性不同;我们分别把A表和B表的数据放在Redis上去,然后在SOA⾥⾯对这两部分数据实时进⾏计算;
5. 模型的输⼊输出数据进⾏埋点,进⾏数据跟踪,⼀是⽤来校验数据,⼆来是⽤来监控API接⼝的稳定性,⼀般性我们会⽤ES来进⾏log
的查看和性能⽅⾯的监控;
6. 任何接⼝都需要有容灾机制,如果接⼝超时,前端需要进⾏容灾,⽴即放弃接⼝调⽤数据,返回⼀个默认安全的数值,这点对于⼯程
上⾮常重要。
以上就是我们在模型部署的经验分享,欢迎⼤家来我⼀起探讨相关⼯程上的最佳实践。
携程技术中⼼现开放⼤数据相关岗位,包括资深NLP科学家/算法⼯程师/⼤数据底层架构⼯程师/⼤数据平台开发⼯程师/机器学习⼯程师/⾃然语⾔处理⼯程师/图像识别⼯程师等,有意者可砸简历⾄tech@ctrip。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。