随着机器学习的广泛应用,如何高效的把训练好的机器学习的模型部署到生产环境,正在被越来越多的工具所支持。我们今天就来看一看不同的工具是如何解决这个问题的。 上图的过程是一个数据科学项目所要经历的典型的过程。从数据采集开始,经历数据分析,数据变形,数据验证,数据拆分,训练,模型创建,模型验证,大规模训练,模型发布,到提供服务,监控和日志。诸多的机器学习工具如Scikt-Learn,Spark, Tensorflow, MXnet, PyTorch提供给数据科学家们不同的选择,同时也给模型的部署带来了不同的挑战。 我们先来简单的看一看机器学习的模型是如何部署,它又会遇到那些挑战。 模型持久化 模型部署一般就是把训练的模型持久化,然后运行服务器加载模型,并提供REST或其它形式的服务接口。我们以RandomForestClassification为例,看一下Sklearn,Spark和Tensorflow是如何持久化模型。 Sklearn 我们使用Iris数据集,利用RandomForestClassifier分类。 训练的代码如上。这里模型导出的代码在最后一句。joblib.dump(),参考这里。Sklearn的模型到处本质上是利用Python的Pickle机制。Python的函数进行序列化,也就是说把训练好的Transformer函数序列化并存为文件。 要加载模型也很简单,只要调用joblib.load()就好了。 Sklearn对Pickle做了一下封装和优化,但这并不能解决Pickle本身的一些限制,例如: 版本兼容问题,不同的Python,Pickle,Sklearn的版本,生成的序列化文件并不兼容 安全性问题,例如序列化的文件中被人注入恶意代码 扩展问题,你自己写了一个扩展类,无法序列化,或者你在Python中调用了C函数 模型的管理,如果我生成了不同版本的模型,该如何管理 Spark Spark的Pipeline和Model都支持Save到文件,然后可以很方便的在另一个Context中加载。 训练的代码如下: 模型加载的代码如下: 调用model的toDebugString方法可以看到分类器的内部细节。 下图是Spark存储的Piple模型的目录结构: 我们可以看到,它包含了元数据Pipeline的五个阶段的数据,这里的文件都是二进制的数据,只有Spark自己可以加载。 Tensorflow 最后我们来看一下Tensorflow。Tensorflow提供了tf.train.Saver来导出他的模型到元图(MetaGraph)。 导出的模型会包含以下文件: 其中checkpoint是元数据,包含其它文件的路径信息。还包含了一个Pickle文件和其它几个checkpiont文件。可以看出,Tensorflow也利用了Python的Pickle机制来存储模型,并在这之外加入了额外的元数据。 模型加载的代码如下: 这里要注意的是,RandomForest不是tensforflow的核心包,所以在模型加载的时候必须tensorflow.contrib.tensor_forest.python.tensor_forest, 否则模型是无法成功加载的。因为不加载的话tensor_forest中定义的一些属性会缺失。 另外就是Tensorflow也可以存储计算图,调用tf.train.write_graph()方法可以把图定义存储下来。当然也可以在TesnsorBoard中展示该图。 好了,我们看到,Sklearn,Spark和Tensorflow都提供了自己的模型持久化的方法,那么简单来说,只要使用一个web服务器例如Flask,加一些模型加载和管理的方法,然后暴露REST API就可以提供预测服务了,是不是很简单呢? 其实要在生产环境下提供服务,还需要面对很多其它的挑战,例如: 在云上如何扩展和伸缩 如何进行性能调优 如何管理模型的版本 安全性 如何持续集成和持续部署 如何支持AB测试 为了解决模型部署的挑战,不同的组织开发了一些开源的工具,例如:Clipper,Seldon,MFlow,MLeap,Oracle Graphpipe,MXnet model server 等等,我们就选其中几个看个究竟。 Clipper Clipper是由UC BerkeleyRISE Lab开发的, 在用户应用和机器学习模型之间的一个提供预测服务的系统,通过解耦合用户应用和机器学习系统的方式,简化部署流程。 它有以下功能: 利用简单标准化的REST接口来简化机器学习系统的集成,支持主要的机器学习框架。 使用开发模型相同的库和环境简化模型部署 利用可适配的Batching,缓存等技术改善吞吐量 通过智能选择和合并模型来改善预测的准确率 Clipper的架构如下图: Clipper使用了容器和微服务技术来构架架构。使用Redis来管理配置,Prometheus来进行监控。Clipper支持使用Kubernetes或者本地的Docker来管理容器。 Clipper支持以下几种模型: 纯Python函数 PyShark PyTorch Tensorflow MXnet 自定义 Clipper模型部署的基本过程如下,大家可以参考我的这个notebook 创建Clipper集群(使用K8s或者本地Docker) 创建一个应用 训练模型 调用Clipper提供的模型部署方法部署模型,这里不同的工具需要调用不同的部署方法。部署时,会把训练好的Estimator利用CloudPickle之久化,本地构建一个容器镜像,部署到Docker或者K8s。 把模型和应用关联到一起,相当于发布模型。然后就可以调用对应的REST API来做预测了。 我试着把之前的三种工具的RomdomForest的例子用Clipper发布到我的Kubernetes集群,踩到了以下的坑坑: 我本地的Cloudpickle的版本太新,导致模型不能反序列化,参考这个Issue Tensorflow在Pickle的时候失败,应该是调用了C的code 我的K8s运行在AWS上,我在K8S上使用内部IP失败,clipper连接一直在使用外部的域名,导致无法部署PySpark的模型。 总之,除了Sklearn成功部署之外,Tensorflow和Spark都失败了。 Seldon Seldon是一家创办于伦敦的公司,致力于提供对于基于开源软件的机器学习系统的控制。Seldon Core是该公司开源的提供在Kubernetes上部署机器学习模型的工具。它拥有以下功能: Python/Spark/H2O/R 的模型支持 REST API和gRPC接口 部署基于Model/Routers/Combiner/Transformers的图的微服务 利用K8S来提供扩展,安全性,监控等等DevOps的功能 Seldon的使用过程如上图, 首先在K8s上安装Seldon Core,Seldon利用ksonnet,以CRD的形式安装seldon core 利用S2i(s2i是openshift开源的一款工具,用于把代码构建成容器镜像),构建运行时模型容器,并注册到容器注册表 编写你的运行图,并提交到K8s来部署你的模型 Seldon支持基于四种基本单元,Model,Transformer, Router, Combiner来构建你的运行图,并按照该图在K8s创建对应的资源和实例,来获得AB测试,模型ensemble的功能。 例如下图的几个例子: AB 测试 模型ensemble 复杂图 图模式是Seldon最大的亮点,可以训练不同的模型,然后利用图来组合出不同的运行时,非常方便。 笔者尝试在K8S上利用Seldon部署之前提到的三种工具生成的模型,都获得了成功(代码在这里)。这里分享一下遇到的几个问题: Seldon支持Java的Python,然而用运行PySpark,这两个都需要,所以我不得不自己构建了一个镜像,手工在Python镜像上安装Java。 因为使用CDR的原因,我没有找到有效改变容器的liveness和readiness的设置,因为Spark初始化模型在Hadoop上,加载模型需要时间,总是readiness超时导致容器无法正常启动,K8s不断的重启容器。所以我只好修改代码,让模型加载变成Lazy Load,但是这样第一次REST Call会比较耗时,但是容器和服务总算是能够正常启动。 MLflow MLflow是Databricks开发的开源系统,用于管理机器学习的端到端的生命周期。 MLflow提供跟踪,项目管理和模型管理的功能。使用MLFlow来提供一个基于Sklearn的模型服务非常简单, 调用mlflow.sklearn.log_model(), MLflow创建以下的目录来管理模型: 我们看到在artifacts目录下有Python的pickle文件和另一个元数据文件,MLModel。 使用 mlflow sklearn serve -m model 就可以很方便的提供基于sklearn的模型服务了。 虽然MLFlow也号称支持Spark和Tensorflow,但是他们都是基于Python来做,我尝试使用,但是文档和例子比较少,所以没能成功。但原理上都是使用Pickle➕元数据的方式。大家有兴趣的可以尝试一下。 关于部署功能,MLFlow的一个亮点是和Sagemaker,AzureML的支持。 MLeap MLeap的目标是提供一个在Spark和Sklearn之间可移植的模型格式,和运行引擎。它包含: 基于JSON的序列化 运行引擎 Benchmark MLeap的架构如下图: 这是一个使用MLeap导出Sklearn模型的例子: 导出的模型结构如下图所示: 这个是randonforest的模型json 我们可以看出MLeap把模型完全序列化成与代码无关的JSON文件,这样就可以在不同的运行时工具Spark/Sklearn之间做到可移植。 MLeap对模型提供服务,不需要依赖任何Sklearn或者Spark的代码。只要启动MLeap的Server,然后提交模型就好了。 下面的代码用Scala在Spark 上训练一个同样的Randonforest分类模型,并利用MLeap持久化模型。 导出的模型和之前的Sklearn具有相同的格式。 MLeap的问题在于要支持所有的算法,对于每一个算法都要实现对应的序列化,这也使得它的需要很多的开发来支持客户自定义的算法 总结 Seldon Core和K8S结合的很好,它提供的运行图的方式非常强大,它也是我实验中唯一一个能够成功部署Sklearn,Spark和Tensorflow三种模型的工具,非常推荐! Clipper提供基于K8s和Docker的模型部署,它的模型版本管理做得不错,但是代码不太稳定,小问题不少,基于CloudPickle也有不少的限制,只能支持Python也是个问题。推荐给数据科学家有比较多的本地交互的情况。 MLFlow能够提供很方便的基于Python的模型服务,但是缺乏和容器的结合。但是它能够支持和Sagemaker,AzureML等云的支持。推荐给已经在使用这些云的玩家。 MLeap的特色是支持模型的可交互性,也就是说我可以把sklearn训练的模型导出在Spark上运行,这的功能很有吸引力,但是要支持全部的算法,它还有很长的路要走。关于机器学习模型标准化的问题,大家也可以关注PMML。现阶段各个工具对PMML的支持比较有限,随着深度学习的广泛应用,PMML何去何从还未可知。 下表是对以上几个工具的简单总结,供大家参考 Model PersistentML ToolsKubernetest IntegrationVersionLicenseImplementation Seldon CoreS2i + PickleTensorflow, SKlearn, Keras, R, H2O, Nodejs, PMMLYes0.3.2ApacheDocker + K8s CRD ClipperPicklePython, PySpark, PyTorch, Tensorflow, MXnet, Customer ContainerYes0.3.0ApacheCPP / Python MLFlowDirectory + MetadataPython, H2O, Kera, MLeap, PyTorch, Sklearn, Spark, Tensorflow, RNoAlphaApachePython MLeap JSONSpark,Sklearn, TensorflowNo0.12.0ApacheScala/Java |
|