(这是有关容器化世界里的数据科学与工程系列博客文章的第二部分,点 此 看第一部分)。
首先要承认,数据科学家正在设计一些非常有意思(而且或许很有价值的)的模型、优化以及虚拟化等。不幸的是,由于很多模型不能被产业化,它们将永远也不会被使用。事实上,很多工业界正在发生的“数据科学”也同步而孤立的发生在数据科学家的笔记本上。而且,在数据科学的应用被实际部署的场景中,它们经常被部署为python/R脚本,上传到AWS并作为一个cron任务来运行。
正如下面所言,这是数据科学用于工业界的一个非常大的问题和障碍:
"只有一个问题——我所有的工作都是在本地机器的R中完成的。人们欣赏我的努力,但是由于它没有被“产品化”且框架不能和本地模型通信,他们不知道如何使用我的模型。非常大的教训!"—— Twitter 的数据科学家 Robert Chang 。
“数据工程师经常抱怨:数据科学家缩写的代码效率低、风格差;他们很少考虑想法产品化后的维护代价;他们经常要求一些努力很多、受益很小的不切现实的特性。类似的抱怨还有很多,但你已经知道要点在哪了。”——数据平台 Stitchfix 的经理 Jeff Magnusson 。
但是,请不要担心!有一个更好的方法: 容器化你的数据科学应用,以方便部署、可移植以及框架内的集成 。
该问题的简单回答就是:数据科学家想让他们的模型、仪表盘、优化等等被实际使用。为了让数据科学的应用被使用并带来价值,它们需要走出笔记本电脑,并被实际部署。它们还需要能够与现有的架构兼容,并易于升级和迭代。
一个Docker化的数据科学应用是如何提供以下好处的呢?
接下来,让我们从一个python脚本开始了解容器化的数据科学应用。接下来,我会给出容器化数据科学应用的一个简单例子:
这里,我们将利用著名的 Iris数据集 来构架一个k-NN分类模型(带 scikit-learn ):
from sklearn import datasets from sklearn.neighbors import KNeighborsClassifier def predict(inputFeatures): iris = datasets.load_iris() knn = KNeighborsClassifier() knn.fit(iris.data, iris.target) predictInt = knn.predict(inputFeatures) if predictInt[0] == 0: predictString = 'setosa' elif predictInt[0] == 1: predictString = 'versicolor' elif predictInt[0] == 2: predictString = 'virginica' else: predictString = 'null' return predictString
该预测函数将基于输入特征 `inputFeatures
(sepal length、sepal width、petal length和petal width)返回一种Iris。在本例中,用于训练模型的数据集是静态的(也就是说,从scikit-learn数据集中加载)。然而,你可以很轻易的想到如何从一个数据集或利用消息、API和数据库交互所聚合的值中动态加载。
接下来,我们需要将这些预测传递到其他组件。为此,我将开发自己作为简单JSON API的应用。对于很多使用微服务架构的工程团队而言,这种应用只是一种普通的练习。而且它可以使得数据应用与其他现存的服务更好的协同工作。
这里,我们将在API中使用 flashk-restful
,你可以使用 twisted 或其他任何架构:
from flask import Flask from flask_restful import Resource, Api from flask_restful import reqparse from utils import makeprediction app = Flask(__name__) api = Api(app) class Prediction(Resource): def get(self): parser = reqparse.RequestParser() parser.add_argument('slength', type=float, help='slength cannot be converted') parser.add_argument('swidth', type=float, help='swidth cannot be converted') parser.add_argument('plength', type=float, help='plength cannot be converted') parser.add_argument('pwidth', type=float, help='pwidth cannot be converted') args = parser.parse_args() prediction = makeprediction.predict([ args['slength'], args['swidth'], args['plength'], args['pwidth'] ]) print "THE PREDICTION IS: " + str(prediction) return { 'slength': args['slength'], 'swidth': args['swidth'], 'plength': args['plength'], 'pwidth': args['pwidth'], 'species': prediction } api.add_resource(Prediction, '/prediction') if __name__ == '__main__': app.run(debug=False)
那么,我就得到了一个 GET
端点,使得我们可以利用其来获得针对一个特征集的预测。例如,路径
http://<host>:5000/prediction?slength=1.5&swidth=0.7&plength=1.3&pwidth=0.3
将返回:
{ "pwidth": 0.3, "plength": 1.3, "slength": 1.5, "species": "setosa", "swidth": 0.7 }
其中,在响应JSON中的 species
表示基于输入特征预测的种类。
为了构建一个我们数据科学应用的“Docker镜像”,我们西药一个 Dockerfile
。该 Dockerfile
将呆在repo的root中,并包含Docker镜像中的所有必须的文件和依赖关系。当我们运行Docker镜像时,运行我们所选择的一个命令:
FROM ubuntu:12.04 # get up pip, vim, etc. RUN apt-get -y update --fix-missing RUN apt-get install -y python-pip python-dev libev4 libev-dev gcc libxslt-dev libxml2-dev libffi-dev vim curl RUN pip install --upgrade pip # get numpy, scipy, scikit-learn and flask RUN apt-get install -y python-numpy python-scipy RUN pip install scikit-learn RUN pip install flask-restful # add our project ADD . / # expose the port for the API EXPOSE 5000 # run the API CMD [ "python", "/api.py" ]
以上就是构建第一个容器化的数据科学应用所需要的所有步骤(对于Docker的安装指令,参看 Docker网站 )。现在,让我们构建应用的“Docker镜像”:
docker build --force-rm=true -t pythoniris
该命令将构建一个名为 pythoniris
的Docker镜像。我们可以根据需要标记该镜像(例如, pythoniris:latest
),或将其和 Docker Hub 上的用户/账号(例如, dwhitena/pythoniris
)关联起来(Docker Hub是一个专门存储Docker镜像的公开仓库,类似于Docker镜像的Github)。
如果你将镜像上传到Docker Hub(或一个私有仓库),部署就像运行引用Docker Hub或仓库中的用户名/镜像名的Docker镜像一样容易。然而,假设你想首先在本地进行这些尝试,你可以通过如下命令来运行Docker镜像:
docker run --net host -d --name myiris pythoniris
该命令将运行Docker镜像运行为一个名为 myiris
的容器、一个守护进程(-d),并使用与本地主机相同的网络接口( --net host
)。现在,你的JOSN API就可以通过 localhost:5000
端口进行访问了。
可以看的出来,从python脚本到容器化的数据应用只需要一点点的付出。现在,请继续向前——研究数据科学、容器化数据科学和部署你的数据科学吧。
以上代码可以在 Github 中下载。
感谢陈兴璐对本文的审校。
给InfoQ中文站投稿或者参与内容翻译工作,请邮件至editors@cn.infoq.com。也欢迎大家通过新浪微博(@InfoQ,@丁晓昀),微信(微信号: InfoQChina )关注我们。