CIFAR10 上的 DenseNet
这篇文章可以在 PDF 这里下载。
这是关于 CNN 架构的系列教程的一部分。
主要目的是在应用于 CIFAR-10 数据集时提供理解 DenseNets 的洞察力。
- 对于 DenseNets 应用于 ImageNet,这是一个更深入的教程,有另一个教程在这里。
- 在这里找到构建这些架构的代码:
索引
- 介绍
- 结构
- 卷积 1
- 密集块
- 过渡块
- 致密层
- 摘要
介绍
这项工作是之前教程的延续,在那里我们在原始论文之后揭开了 DenseNet 的神秘面纱。但是,这种结构是为了在 ImageNet 数据集上运行良好而构建的。
ImageNet 数据集由属于 1000 个不同类别的一组大小(224x224)的图像(作者使用了 128 万幅训练图像、5 万幅验证图像和 10 万幅测试图像)组成。但是,CIFAR10 由一组不同的映像(45k 训练映像、5k 验证映像和 10k 测试映像)组成,这些映像分布在 10 个不同的类别中。
因为输入体积(图像)的大小完全不同,所以很容易认为相同的结构不适合在该数据集上训练。我们无法在没有维度不匹配的情况下对数据集执行相同的缩减。
我们将遵循作者给出的解决方案(让 DenseNets 在 CIFAR10 上进行训练,以构建具有 100 个层和 12 的增长因子的 DenseNet-BC),这也像 ImageNet 数据集一样难以遵循。在论文[1]的第 3 节 DenseNet—实现细节 中,提供了为 CIFAR10 构建 dense net 的配置。
让我们按照他们给出的字面解释来构造 DenseNets。最重要的是,对于 CIFAR10 实施,有 3 个 DenseBlock,而不是 4 个,**,每个 dense block 中的 DenseLayers 数量相等。**因为作者给出的参数是网络的总层数 L ,所以我们计算每个密集块中需要包含多少个密集层才能达到该配置。被压缩系数为θ:
移除 4 层的原因是因为我们只需要考虑那些属于密集块的层。此外,压缩在过渡层引入了一种新的操作(第一个 1x1 卷积,如我们在原始作品中看到的)
因此,对于 100 层 DenseNet-BC,每个 DenseBlock 将由 16 个密集层组成。由于我们将在“DenseNet-Layers-GrowthRate”之后调用 DenseNet,因此本文中涉及的 DenseNet 对应于 dense net-100–12。
结构
遵循之前关于 DenseNets 工作的相同方法,让我们先看一下整体情况,然后再一层一层地深入细节。
Figure 1. Scheme DenseNet-100–12 on CIFAR10
揭开 ResNet-121 的神秘面纱后,图 1 看起来已经很熟悉了。我们可以观察到相同的模式,第一个单卷积层,然后是两对密集块—过渡块对,第三个密集块,然后是全局平均池,以将其减少到 1x1x342 矢量,从而提供给密集层。
卷积 1
在进入第一个密集块之前,DenseNet 的第一步是一个 3×3 卷积和一个批处理归一化操作。步幅为 1,填充为 1,以使输出大小与输入大小相匹配。请注意,我们与 DenseNet for ImageNet 的第一个重大区别是,我们没有在第一个块中包括 max pooling 操作,以减少输入卷的维数。
Figure 2. Conv1
我们可以从图 2 中看出,Conv1 的输出音量确实是 32x32x24。下一步是将这个新卷作为输入引入下面的密集数据块 1 (D1)。
密集块
致密块(DB)由 16 个致密层组成,如之前对 dense net-BC-100–12 的计算。
Figure 3. One level deeper look at Dense-100–12. Dense Block and Transition Block. DLx: Dense Layer x
图 3 表示了一个简化的版本,因为 16 个块在一个图像中压缩太多了,但是我们可以看到特征图的数量是如何以增长率增加的,每次 12 个(24、36、48……)。因为有 16 层,DB1 的最终体积将是 216。
过渡块
两个 db 之间的过渡块(TB)充当下采样,通过合并步幅= 2、核大小= 2 和填充= 1,将特征图的数量减少一半(θ= 0.5),并且还将特征图的大小减少一半。
致密层
我们只需要看看数据库中发生了什么,以确认为什么特征地图的大小增加了*(增长率密集图层的数量)/ 2 —查看 D1 是如何从 24 增加到 216 的—而特征地图的大小保持不变。
Figure 4. 2nd level deep. Full schematic representation of DenseNet-BC-100–12
可以检查每个密集层(DL)如何以 4 *过滤器数量的增长率执行 1x1 卷积。数字 4 是作者在论文中给出的,大多数知识库称之为 bn_size(瓶颈层数的乘法因子)。这个 1x1 卷积在 3x3 卷积之前应用线性变换,滤波器的数量是增长率。
查看第二个卷积如何唯一负责连接的过滤器贴图的数量,因此它在连接它们之后完美地匹配增长率配置。每个 DL 都向它们的输入卷添加 k 个新的特征地图。这再次证实了为什么致密块体增加了增长率致密层数*。
摘要
通过改变图 1 中 n 的值,遵循作者建立的解释规则的结果产生以下结构:
Table 1. DenseNets architectures for CIFAR-10
请注意,直观地说,这些架构与在 ImageNet 的工作结束时展示的 ImageNet 架构并不匹配。
在这里找到构建这些架构的代码:
一种基于密度的离群点检测算法
离群点检测(也称为异常检测)是发现行为与预期非常不同的数据对象的过程。这种对象被称为异常值或异常值。最有趣的物体是那些明显偏离正常物体的物体。离群值不是由与其余数据相同的机制生成的。
异常值检测在许多应用中非常重要,例如:
- 通信网络中的入侵
- 财务数据中的欺诈
- 假新闻和错误信息
- 医疗保健分析
- 工业损伤检测
- 安全和监控
- 等等
离群点检测和聚类分析是两个高度相关的任务。聚类发现数据集中的大多数模式,并相应地组织数据,而异常值检测试图捕获那些与大多数模式有很大差异的异常情况。
在本文中,我将介绍离群点检测的基本方法,并重点介绍一类基于邻近度的方法。此外,我将提供一个 LOF 算法的代码实现。
Nassim taleb is an inventor of Black Swan theory — extreme impact of rare and unpredictable outlier event and the human tendency to find simplistic explanations for these events, retrospectively.
离群值和噪声数据
首先,你需要从嘈杂的数据中分辨出离群值。
在应用异常值检测时,应该去除噪声。它可能会扭曲正常对象,模糊正常对象和异常值之间的区别。这可能有助于隐藏异常值并降低异常值检测的有效性。例如,如果用户考虑购买比他以前通常购买的更贵的午餐,这种行为应该被视为“噪声交易”,如“随机误差”或“方差”。
异常值的类型
一般来说,离群值可以分为三类,即全局离群值、上下文(或条件)离群值和集体离群值。
- 全局异常值-对象明显偏离数据集的其余部分
- 上下文异常值—对象根据选定的上下文显著偏离。例如,28⁰C 是莫斯科冬天的异常值,但在另一种情况下不是异常值,28⁰C 不是莫斯科夏天的异常值。
- 集体离群值—数据对象的子集集体显著偏离整个数据集,即使单个数据对象可能不是离群值。例如,一个小团体在短时间内大量交易同一只股票,可以被认为是操纵市场的证据。
Collective outlier.
通常,一个数据集可能包含不同类型的异常值,同时可能属于不止一种异常值。
离群点检测方法
在文献中有许多离群点检测方法,并在实践中使用。首先,离群点检测方法根据用于分析的数据样本是否具有领域专家提供的标签而不同,这些标签可用于建立离群点检测模型。第二,方法可以根据它们对正常对象和异常值的假设分成不同的组。
如果可以获得正常和/或异常对象的专家标记的示例,则它们可以用于建立异常检测模型。使用的方法可分为监督方法、半监督方法和非监督方法。
监督方法
我们将异常检测建模为一个分类问题。领域专家检查的样本用于培训和测试。
挑战:
- 阶级不平衡。也就是说,异常值的总体通常比正常对象的总体小得多。可以使用处理不平衡类的方法,例如过采样。
- 捕捉尽可能多的异常值,即召回比准确性更重要(即不要将正常对象误标为异常值)
无监督方法
在某些应用场景中,标记为“正常”或“异常值”的对象不可用。因此,必须使用无监督的学习方法。无监督的离群点检测方法做出了一个隐含的假设:正常对象在某种程度上是“聚集的”换句话说,无监督离群点检测方法期望正常对象比离群点更频繁地遵循一种模式。
挑战:
- 正常对象可能不共享任何强模式,但是集体离群值可能在小区域中共享高相似性
- 如果正常活动是多样的并且不属于高质量的聚类,则无监督的方法可能具有高的假阳性率,并且可能让许多实际的异常值未被检测到。
最新的非监督方法开发了智能思想,直接处理离群值,而无需显式检测聚类。
半监督方法
在许多应用中,虽然获得一些标记的例子是可行的,但是这种标记的例子的数量通常很少。如果一些带标签的正常对象可用:
- 使用已标记的示例和最接近的未标记对象来训练正常对象的模型
- 不符合正常对象模型的那些被检测为异常值
如果只有一些标记异常值可用,少量的标记异常值可能无法很好地覆盖可能的异常值。
统计方法
统计方法(也称为基于模型的方法)假设正态数据遵循某种统计模型(随机模型)。其思想是学习适合给定数据集的生成模型,然后将模型的低概率区域中的对象识别为异常值。
参数方法
参数方法假设正态数据对象是由具有参数𝜃.的参数分布生成的参数分布 f(x, 𝜃 ) 的概率密度函数给出了对象 x 由该分布生成的概率。该值越小, x 越有可能是异常值。
对于随机模型,正常对象出现在高概率区域,低概率区域的对象是异常值。
统计方法的有效性高度依赖于对分布的假设。
例如,考虑具有正态分布的单变量数据。我们将使用最大似然法检测异常值。
Maximum likelihood methods to estimate the parameter 𝜇 and 𝜎
对𝜇和𝜎求导,并求解一阶条件的结果系统,得到以下最大似然估计
Maximum likelihood estimates of 𝜇 and 𝜎²
偏离值最大的是 24⁰,偏离平均值 4.61。我们知道𝜇 +/- 3𝜎地区包含了正态分布假设下的 97%的数据。因为 4.61/1.54 > 3,我们认为 24⁰是一个异常值。
此外,我们可以使用另一种统计方法,称为格拉布斯检验,并计算 z 分数。
s — standart deviation
但是我们很少处理只有一个属性的数据。涉及两个或多个属性的数据称为多元数据。这些方法的中心思想是将多元数据转化为单变量异常检测问题。
一种流行的方法是𝜒 - 统计法。
Oi — the value of O in i-th dimension. Ei — the mean of the i-th dimension among all objects, n — dimensionality.
如果𝜒 -大,该对象是一个离群值。
参数模型的主要缺点是,在许多情况下,数据分布可能是未知的。
例如,如果我们有两个大的集群,关于正态分布的假设就不适用。
相反,我们假设正态数据对象由多个正态分布𝛩 (𝜇1,𝜎1)和𝛩 (𝜇2,𝜎2)生成,并且对于数据集中的每个对象 o ,我们计算由混合分布生成的概率。
pr(o|𝛩1,𝛩2)= f𝛩1(o)+f𝛩2(o)
其中f𝛩1(o)——分别为 𝛩1 和𝛩2 的概率密度函数。为了学习参数𝜇和𝜎,我们可以使用 EM 算法。EM 算法的一个例子可以在这里找到。
非参数方法
在用于异常值检测的非参数方法中,从输入数据中学习“正常数据”的模型,而不是先验地假设一个模型。非参数方法通常对数据做较少的假设,因此可以适用于更多的情况。例如,我们可以使用直方图。
在最简单的方法中,如果对象在直方图仓之一中失败,则认为它是正常的。缺点是很难选择箱子的大小。
基于邻近的算法
给定特征空间中的一组对象,可以使用距离度量来量化对象之间的相似性。直观上,距离他人较远的对象可以视为离群值。基于邻近度的方法假设离群对象与其最近邻居的邻近度明显偏离该对象与数据集中大多数其他对象的邻近度。
基于邻近度的算法可以分为基于距离的方法(如果一个对象的邻域没有足够的点,则该对象是异常值)和基于密度的方法(如果一个对象的密度比其邻域的密度相对低得多,则该对象是异常值)
基于密度
基于距离的离群点检测方法参考由给定半径定义的对象的邻域。如果一个对象的邻域没有足够多的其他点,则该对象被认为是异常值。
距离阈值可以被定义为对象的合理邻域。对于每个对象,我们可以找到一个对象的合理数量的邻居。
形式上,设 r(r > 0) 为距离阈值,𝜋 (0 < 𝜋 < 1) 为分数阈值。的一个对象 o 是 DB(r, 𝜋 )
距离 —距离测量。
简单的方法需要 O(n)时间。
挖掘基于距离的异常值的算法;
- 基于索引的算法
- 嵌套循环算法
- 基于单元的算法
基于密度的方法
基于密度的离群点检测方法研究对象及其邻居的密度。这里,如果一个对象的密度比其邻居的密度相对低得多,则该对象被识别为异常值。
许多真实世界的数据集展示了更复杂的结构,其中对象可以被认为是关于它们的局部邻域的离群值,而不是关于全局数据分布的离群值。
考虑上面的例子,基于距离的方法能够检测到 o3,但是对于 o1 和 o2 就不那么明显了。
基于密度的思想是,我们需要将对象周围的密度与其局部邻居周围的密度进行比较。基于密度的异常检测方法的基本假设是,非异常对象周围的密度与其邻居周围的密度相似,而异常对象周围的密度与其邻居周围的密度显著不同。
dist _ k(o)-是对象 o 和 k 个最近邻之间的距离。o的 k 距离邻域包含所有到o的距离不大于*dist _ k(o)*oo的第 k 个距离的物体
我们可以用 Nk(o)中的物体到 o的平均距离作为 o 局部密度的度量。如果 o 具有非常接近的邻居o’**使得 dist(o,o’)非常小,则距离测量的统计波动可能会不期望地高。为了克服这个问题,我们可以通过添加平滑效果来切换到下面的可达性距离度量。
k 是用户指定的参数,控制平滑效果。本质上, k 指定了要检查的最小邻域,以确定对象的局部密度。可达性距离是不对称的。
一个对象 o 的局部可达性密度为
我们计算一个对象的局部可达性密度,并将其与其邻居的可达性密度进行比较,以量化该对象被视为离群值的程度。
局部离群因子是 o 的局部可达性密度与 o 的 k 个最近邻的局部可达性密度之比的平均值。 o 的局部可达性密度越低,o 的 k 最近邻的局部可达性密度越高,则 LOF 值越高。这准确地捕获了局部离群值,其局部密度与其 k 个最近邻居的局部密度相比相对较低。
LOF 算法
基于 data.csv 中的点击流事件频率模式,我们将应用 LOF 算法计算每个点的 LOF,初始设置如下:
- k = 2 并使用曼哈顿距离。
- k = 3 并使用欧几里德距离。
结果,我们将找到 5 个异常值和它们的 LOF_k(o)
数据可以从 github 库下载
参考文献
- http://www . kdnugges . com/2017/01/3-methods-deal-outliers . html
- https://www . analyticsvidhya . com/blog/2016/01/guide-data-exploration/
- 韩佳玮,Micheline Kamber,JianPei 数据挖掘概念和技术-第 3 版-摩根-考夫曼-2011 【亚马逊】
- https://towards data science . com/a-brief-overview-of-outlier-detection-techniques-1e 0 b 2c 19 e 561
MSBD 5002 HKUST 讲稿
使用 flask 部署机器学习模型
作为机器学习的初学者,对于任何人来说,获得关于机器学习和深度学习的所有算法的足够资源可能都很容易,但是当我开始寻找将 ML 模型部署到生产的参考资料时,我没有找到任何可以帮助我部署我的模型的好资源,因为我对这个领域非常陌生。因此,当我成功地使用 Flask 作为 API 部署我的模型时,我决定写一篇文章来帮助其他人简单地部署他们的模型。希望有帮助:)
在本文中,我们将使用简单的线性回归算法和 scikit-learn。为了简单起见,我们将使用 Flask,因为它是一个非常轻量级的 web 框架。我们将创建三个文件,
- model.py
- server.py
- request.py
在一个 model.py 文件中,我们将开发并训练我们的模型,在一个 *server.py 中,*我们将编码处理 POST 请求并返回结果,最后在 request.py 中,我们将向服务器发送带有特性的请求并接收结果。
让我们开始编码部分
- model.py
正如我上面提到的,在这个文件中我们将开发我们的 ML 模型并训练它。我们将根据员工在该领域的经验来预测他/她的工资。你可以在这里找到数据集。
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
import pickle
import requests
import json
导入我们将用来开发模型的库。 numpy 和 pandas 分别操作矩阵和数据,sk learn . model _ selection将数据拆分为训练集和测试集, sklearn.linear_model 使用 LinearRegression 训练我们的模型。 pickle 将我们训练好的模型保存到磁盘,请求向服务器发送请求, json 在我们的终端打印结果。
dataset = pd.read_csv('Salary_Data.csv')
X = dataset.iloc[:, :-1].values
y = dataset.iloc[:, 1].values
我们已经使用 pandas 导入了数据集,并将要素和标注从数据集中分离出来。
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.33, random_state = 0)
在本节中,我们使用来自 sklearn 的 train_test_split 将我们的数据分为训练和测试大小分别为 0.67 和 0.33。
regressor = LinearRegression()
regressor.fit(X_train, y_train)y_pred = regressor.predict(X_test)
该对象被实例化为类 LinearRegression() 的回归变量,并使用 X_train 和 *y_train 进行训练。*后者预测结果存储在 y_pred 中。
pickle.dump(regressor, open('model.pkl','wb'))
我们将使用 pickle 库将训练好的模型保存到磁盘上。 Pickle 用于序列化和反序列化 Python 对象结构。其中 python 对象被转换成字节流。 dump() 方法将对象转储到参数中指定的文件中。
在我们的例子中,我们希望保存我们的模型,以便服务器可以使用它。因此,我们将把我们的对象回归器保存到名为 model.pkl. 的文件中
我们可以通过下面的方法再次加载模型,
model = pickle.load(open('model.pkl','rb'))
print(model.predict([[1.8]]))
pickle.load() 方法加载方法并将反序列化后的字节保存到*模型。*可以使用 model.predict()进行预测。
例如,我们可以预测有 1.8 年工作经验的雇员的工资。
在这里,我们的 model.py 准备训练并保存模型。 model.py 的完整代码如下。
# Importing the libraries
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
import pickle
import requests
import json# Importing the dataset
dataset = pd.read_csv('Salary_Data.csv')
X = dataset.iloc[:, :-1].values
y = dataset.iloc[:, 1].values# Splitting the dataset into the Training set and Test set
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 1/3, random_state = 0)# Fitting Simple Linear Regression to the Training set
regressor = LinearRegression()
regressor.fit(X_train, y_train)# Predicting the Test set results
y_pred = regressor.predict(X_test)# Saving model to disk
pickle.dump(regressor, open('model.pkl','wb'))# Loading model to compare the results
model = pickle.load(open('model.pkl','rb'))
print(model.predict([[1.8]]))
2。server.py
在这个文件中,我们将使用 flask web 框架来处理从 request.py 获得的 POST 请求。
导入我们将在代码中使用的方法和库。
import numpy as np
from flask import Flask, request, jsonify
import pickle
这里我们导入了 numpy 来创建请求数据的数组, pickle 来加载我们训练好的模型进行预测。
在下面的代码中,我们创建了 Flask() 的实例,并将模型加载到模型中。
app = Flask(__name__)model = pickle.load(open('model.pkl','rb'))
这里,我们用方法 predict()绑定了 /api 。其中 predict 方法从请求者传递的 json 中获取数据。 model.predict() 方法从 json 获取输入,并将其转换为 2D numpy 数组结果存储在名为的变量中,输出和我们在使用 flaks*json ify()*方法将其转换为 JSON 对象后返回此变量。
[@app](http://twitter.com/app).route('/api',methods=['POST'])
def predict():
data = request.get_json(force=True)
prediction = model.predict([[np.array(data['exp'])]])
output = prediction[0]
return jsonify(output)
最后,我们将通过下面的代码运行我们的服务器。这里我使用了端口 5000,并设置了 debug=True ,因为如果我们遇到任何错误,我们可以调试并解决它。
if __name__ == '__main__':
app.run(port=5000, debug=True)
在这里,我们的服务器已经准备好为请求提供服务。下面是 server.py. 的完整代码
# Import libraries
import numpy as np
from flask import Flask, request, jsonify
import pickleapp = Flask(__name__)# Load the model
model = pickle.load(open('model.pkl','rb'))@app.route('/api',methods=['POST'])
def predict():
# Get the data from the POST request.
data = request.get_json(force=True) # Make prediction using model loaded from disk as per the data.
prediction = model.predict([[np.array(data['exp'])]]) # Take the first value of prediction
output = prediction[0] return jsonify(output)if __name__ == '__main__':
app.run(port=5000, debug=True)
- request.py
正如我前面提到的, request.py 将向服务器请求预测。
下面是向服务器发出请求的完整代码。
import requestsurl = '[http://localhost:5000/api'](http://localhost:5000/api')r = requests.post(url,json={'exp':1.8,})
print(r.json())
我们已经使用请求库来发出 post 请求。 requests.post() 获取 URL 和 post 请求中要传递的数据,从服务器返回的结果存储到变量 r 中,并由 r.json()打印。
结论
我们创建了三个文件 model.py、server.py 和 request.py 来训练和保存模型,处理请求,分别向服务器发出请求。
在对所有这些文件进行编码之后,执行文件的顺序应该是 model.py 、 server.py (在单独的终端中)以及最后 request.py 。
您可以将预测的结果与一个 model.py 进行比较,因为我们将结果打印在文件的末尾。
你可以在我的 Github 库 flask-salary-predictor 中找到所有的代码。
不要犹豫,在下面的评论区说出你的想法。
谢谢:)
将 Nodejs 微服务部署到 Docker Swarm 集群[Docker 从零到英雄]
这是🖐🏽“构建 NodeJS 影院微服务”系列的第五篇文章。这一系列文章演示了如何使用 ES6,ES7 …8,用 expressjs设计、构建和部署微服务 ?,连接到 MongoDB 副本集,并将其部署到 docker 容器中,以模拟云环境的强大功能。
##快速回顾一下我们之前的章节
第一篇文章介绍了微服务架构模式,并讨论了使用微服务的好处和缺点。在第二篇文章中,我们讨论了使用 HTTP/2 协议的微服务安全性,并了解了如何实现它**。本系列的第三篇文章我们描述了微服务架构内通信的不同方面,我们解释了关于设计模式的 NodeJS 像依赖注入、反转控制和**坚实的原理。在第四篇文章中,我们谈到了什么是 API 网关,我们看到了什么是网络代理和 ES6 代理对象。我们已经开发了 5 个服务,我们已经将它们归档,我们也做了很多类型的测试,因为我们是好奇的好开发者。
如果你没有读过前面的章节,你会错过一些很棒的东西👍🏽,所以我会把链接放在下面,这样你就可以看看了👀。
[## 构建 NodeJS 影院微服务并使用 docker 部署它—第 1 部分
这是“构建节点影院微服务”系列的第一章,该系列是关于构建节点影院微服务的
medium.com](https://medium.com/@cramirez92/build-a-nodejs-cinema-microservice-and-deploying-it-with-docker-part-1-7e28e25bfa8b) [## 构建 NodeJS 影院微服务并使用 docker 部署它(第 2 部分)
这是✌️“构建 NodeJS 影院微服务”系列的第二篇文章。
medium.com](https://medium.com/@cramirez92/build-a-nodejs-cinema-microservice-and-deploying-it-with-docker-part-2-e05cc7b126e0) [## 构建 NodeJS 影院预订微服务并使用 docker 部署它(第 3 部分)
你好社区这是🏰“构建 NodeJS 影院微服务”系列的第三篇文章。这一系列的…
medium.com](https://medium.com/@cramirez92/build-a-nodejs-cinema-booking-microservice-and-deploying-it-with-docker-part-3-9c384e21fbe0) [## 构建 NodeJS cinema API 网关并将其部署到 Docker(第 4 部分)
这是🏛“构建 NodeJS 影院微服务”系列的第四篇文章。这一系列文章…
medium.com](https://medium.com/@cramirez92/build-a-nodejs-cinema-api-gateway-and-deploying-it-to-docker-part-4-703c2b0dd269)
我们一直在开发,编码,编程,👩🏻💻👨🏻💻在最后几集中,我们对如何创建 nodejs 微服务非常兴奋,我们还没有时间谈论我们系统的架构,我们还没有谈论从第 1 章开始就一直在使用的东西,那就是 Docker 。
现在是人们见识力量的时候了💪🏽集装箱化的🗄.如果你想得到你的手🙌🏽肮脏和学习所有关于 Docker 的大惊小怪,然后抓住你的座位,系上你的安全带,因为我们的旅程将变得有趣。
##当前影院微服务架构
直到我们知道我们已经创建了 3 个**docker-machines**
**,**我们创建了一个**mongo database replica set cluster**
,在那里我们在每个 docker-machine 中放置了一个副本,然后我们创建了我们的微服务,但是我们一直只在**manager1**
docker-machine 中手动创建和部署它,所以我们一直在浪费其他两个 docker-machine 中的计算资源,但是我们不再这样做了,因为我们将开始配置 Docker ,
我们将在本文中使用:
- NodeJS 版本 7.5.0(针对我们的微服务)
- MongoDB 3.4.2(针对我们的数据库)
- Mac 版 docker 1 . 13 . 0 或同等版本(已安装,版本 1.13.1 与 dockerode 不兼容)
跟进文章的先决条件:
- bash 脚本的基础知识。
- 我已经完成了上一章的例子。
如果你还没有,我已经上传了一个 github 库,所以你可以在分支机构步骤 5 的回购链接处获得最新信息。
# Docker 是什么?
Docker 是一个开源项目,可以将任何应用程序作为一个轻量级容器来打包、运输和运行。
Docker 容器既与硬件无关,也与平台无关。这意味着它们可以在任何地方运行,从您的笔记本电脑到最大的云计算实例以及二者之间的任何东西,并且它们不需要您使用特定的语言、框架或打包系统。这使得它们成为部署和扩展 web 应用程序、数据库和后端服务的绝佳构建块,而无需依赖特定的堆栈或提供商。— @Docker
Docker structure
换句话说 docker 到底是什么?
换句话说,docker 让我们构建模板(如果我们可以称之为模板,这个模板是 docker 映像)来创建容纳虚拟机的容器(如果我们可以称之为虚拟机,因为它们不是),我们可以在其中包含我们的应用程序,安装它的所有依赖项,并作为一个独立的进程运行它,与主机操作系统或任何 IaaS 平台中的其他容器共享内核。
Virtual machine structure
和虚拟机有什么区别?
虚拟机包括应用程序、必要的二进制文件、库和整个客户操作系统,其容量可达数十 GB — @Docker
#什么是 Docker-Machine?
Docker Machine 让我们可以在自己的计算机、云提供商和数据中心内部创建 Docker 主机。它创建服务器,在服务器上安装 Docker,然后配置 Docker 客户机与服务器对话。— @Docker
Docker Machine 是一个让我们在虚拟主机上安装 Docker 引擎,并使用docker-machine
命令管理主机的工具。您可以使用 Machine 在本地 Mac 或 Windows box、公司网络、数据中心或 AWS 或 Digital Ocean 等云提供商上创建 Docker 主机。Docker 引擎在 Linux 系统上本地运行。如果你有一个 Linux 系统作为你的主系统,并且想要运行docker
命令,你需要做的就是下载并安装 Docker 引擎。
但是为什么我们甚至在 Linux 上也需要 Docker-Machine 呢?
如果我们想要高效地管理我们的 Docker 主机 在网络上、在云中甚至在本地,我们需要它,因为如果我们在本地进行测试,Docker-Machine 可以帮助我们模拟云环境。
#什么是 Docker Swarm?
Docker Swarm 是 Docker 的本地集群。它使用 API 代理系统将一个 Docker 主机池变成一个单独的虚拟主机。
让我们先理解集群是什么意思。
集群是一组紧密耦合的计算机,像单台机器一样运行。称为节点的单个机器通过非常快速的网络相互通信,并且它们在物理上非常接近,可能在同一个机柜中。通常他们有相同或几乎相同的硬件和软件。所有节点都可以处理相同类型的请求。有时,一个节点接受请求并将其分派给其他节点。— 菲尔·多尔蒂
好了,现在让我们看看创建 Docker Swarm 集群可以实现什么:
- 多主机网络
- 结垢
- 负载平衡
- 默认安全性
- 集群管理
等等,现在我们已经获得了一些关于 Docker 生态系统的词汇和知识,是时候看看我们如何创建我们的架构并将我们的 cinema 微服务部署到 Docker Swarm 集群 ,该集群可以处理数百、数千或数百万的用户请求,如预订🎟,逛🕹,看🎥、或用户的任何动作👥在我们的电影系统中。
当不使用 swarm 模式运行 Docker 时,执行容器命令。当您在集群模式下运行 Docker 时,您编排了服务。您可以在同一个 Docker 实例上运行 swarm 服务和独立容器。— @Docker
#构建架构
步骤 1:创建并初始化 docker swarm 集群
我们将从零开始构建我们的影院微服务架构,所以让我们先来谈谈如何创建我们的**docker machines**
以及如何初始化一个**docker swarm cluster.**
首先,在开始创建和修改文件之前,我们需要在 cinemas 项目的根目录下创建一个名为**_docker_setup**
的新文件夹,因此我们的项目需要如下所示:
*.
|*--* ***_docker_setup***
| `*-- ... here we are going to put our bash files*
|*--* ***api-gateway***| `*-- ... more files* |*--* ***booking-service***| `*-- ... more files* |*--* ***cinema-catalog-service***| `*-- ... more files* |*--* ***movies-service***| `*-- ... more files* |*--* ***notification-service***| `*-- ... more files* |*--* ***payment-service***| `*-- ... more files**
因此,让我们在我们的**_docker_setup folder**
中创建一个 bash 文件,名为**setup-swarm.sh**
,这将创建并设置我们的**docker swarm cluster.**
为什么是 bash 文件,因为一个好的开发人员可以自动完成很多这样的事情:
好吧,这是一个有点长的脚本,但我想把它全部写下来,因为它让我们更好地了解正在发生的事情,以及我们如何才能完成 docker swarm 集群设置自动化。
所以让我们分开剧本,谈谈那里发生了什么。
***# So first the basics, how do we create a docker-machine.**$ docker-machine create -d $DRIVER $ADDITIONAL_PARAMS $MACHINE_NAME*
这就是我们创建机器的基本方法,不管它们是管理节点还是工作节点,对两者来说都是相同的命令。驱动程序可能是 virtualbox、parallels、digital-ocean、AWS 等。
*一旦我们创建了我们的机器,它的时间 **初始化蜂群,*如下:
*$ docker-machine ssh manager1 docker swarm init --advertise-addr $(getIP manager1)*
它的一个 简单的 docker 命令 ,就这么简单,docker swarm init,初始化 swarm manager 配置。我们可以用两种方式来做这件事,像下面的eval
docker-machine env manager1``一样 设置我们的环境 并执行docker swarm init
命令或者 我们可以 ssh 到机器 像下面的docker-machine ssh manager1 {and here we pass the docker commands}
一样,初始化 swarm 我们需要docker-machine ip
ip 可能会因驱动程序提供者而异,所以为了获取 ip,我做了一个 bash 函数,它将检索给定 docker-machine 的 IP。
一旦群管理器被启动,我们就准备添加工人节点,为此我们调用函数join_node_manager
,它执行以下操作:
*$ docker-machine ssh {name of worker} docker swarm join --token $(get_worker_token) $(getIP manager1):2377*
我们将在脚本中使用给定数量的 workers 变量再次循环该命令,该命令首先调用函数get_worker_token
,这将从管理器节点获取令牌,这是将 worker 节点注册到群集群所需的令牌,接下来它将再次调用检索给定 docker-machine 的 ip 的函数,并将 完成 docker 群集群配置 ,我们准备好部署我们的 cinema 微服务。
为了利用 swarm 模式的容错特性,Docker 建议您根据组织的高可用性要求实现奇数个节点。— @Docker
步骤 2:创建 docker 图像
容器是将 Node.js 应用程序部署到生产环境的最佳方式。容器提供了各种各样的好处,从在生产和开发中拥有相同的环境到为了速度和大小而简化部署。— 蒂尔尼·赛丽
目前我们有 5 个微服务和 1 个 api-gateway 服务,我们可以在 dev box 上运行,只要它安装了 Node.js 的兼容版本。我们想要做的是创建一个 Docker 服务( 我们将在后面的章节 ) 中看到这是什么,但是为此我们需要为我们拥有的每个微服务创建一个 Docker 映像 。
一旦创建了 Docker 映像 ,我们就能够在任何支持 Docker 的地方部署我们的服务。
我们创建一个 Docker 图像 的方法是先创建一个**Docker file(**模板 ) )。Docker 文件是一个告诉 Docker 引擎如何构建我们的图像的配方。
由于我们只开发了 nodejs 应用程序,我们可以在项目中的所有微服务中使用相同的 Dockerfile 规范, 但是我们是否尽了一切努力使这个过程尽可能可靠和有活力呢?
这是我们要查看的下一个文件,我们也将对其应用良好的实践。
现在我们可以用这个规范修改我们之前创建的所有微服务docker files**,。
让我们谈一点这是怎么回事,如果这个过程是可靠的。
默认情况下,Docker 容器中的应用程序进程作为根用户运行。这在生产运行时会造成 潜在的严重安全风险 。这个问题的一个简单的 解决方案 是在 Docker 映像的 中 创建一个新用户,并使用该用户来执行我们的应用程序。Docker 容器内的第一个进程 将是 PID 1 。Linux 内核给予 PID 1 特殊的待遇,许多应用程序并不是为处理 PID 1 带来的额外责任而设计的。当以 PID 1 的身份运行 Node.js 时,进程无法处理那些责任会有几种表现,其中最痛苦的是进程忽略了SIGTERM
命令。dumb-init 被设计成一个超级简单的进程,无论它被告知启动哪个进程,它都负责作为 PID 1 运行。**
步骤 3:构建并运行我们的 docker 映像
要构建我们的 Docker 图像 ,我们需要运行以下命令:
***# This command will create a new docker image**$ docker build -t movies-service .*
让我们看看 build 命令。
docker build
告诉引擎我们想要创建一个新的图像。-t flag
用标签movies-service
给这个图像加标签。从现在开始我们可以通过标签来引用这张图片。.
使用当前目录找到Dockerfile
。
现在我们已经准备好使用新的 docker 映像运行容器,为此我们需要以下命令:
*$ docker run --name movies-service -l=apiRoute='/movies' -p 3000:3000 -d movies-service*
让我们来看看 run 命令。
docker run
告诉引擎我们要启动一个新的容器。--name
flag 为容器设置一个名称。从现在开始我们可以用这个名字来称呼这个容器。-l
标志为容器设置元数据。-p
flag 设置来自{host}:{container}的端口绑定-d
标志在分离模式下运行容器,这保持了容器在后台运行。
所以现在让我们在我们的**_docker_setup**
foleder 中创建一个 bash 文件,名为**create-images.sh**
,来自动创建我们所有的微服务 docker 映像。
在执行这个脚本之前,我们需要修改每个微服务上的**start-service.sh**
,并将其重命名为**create-image.sh**
,如下所示:
*#!/usr/bin/env bashdocker rm -f {name of the service}docker rmi {name of the service}docker image prunedocker volume prune**# the previous commands are for removing existing containers,
# and image, then we clean our environment and finally
# we creat or re-build our image**docker build -t {name of the service} .*
步骤 4:将我们的 docker 映像发布到 docker hub 存储库
发布我们的 docker 图像🤔?,Docker 维护着一个巨大的图像库,称为Docker Hub,您可以使用它作为起点或免费存储我们自己的图像。这是我们将**node:7.5.0-alpine**
映像用于创建微服务映像的地方。 但是为什么我们需要发布我们的图片呢?
因为在本章的后面,我们将创建 Docker 服务 ,这些服务将在我们的 Docker Swarm 集群上部署和复制,为了启动我们的服务,集群节点需要服务的映像来启动容器,如果映像不在本地,它将在 docker hub 中搜索它,然后将它拉至主机,以便在本地拥有映像并能够统计我们的服务。
但是首先我们需要在 Docker Hub 网站 , 创建一个帐户,然后我们需要在我们的 shell 中登录,执行以下命令:
*$ docker login
Username: *****
Password: *****
Login Succeeded*
接下来,我们需要标记我们的图像,以便能够通过名称引用它们,并将它们推送到 docker hub。
docker tagging images structure
既然我们已经登录,我们现在知道了如何标记 docker 图像的结构,现在是修改我们的**create-images.sh**
的时候了,所以它可以创建我们的图像,标记我们的图像,将我们的图像推送到 docker hub ,所有这些都是自动完成的,我们的 bash 文件需要看起来如下。
步骤 5:设置我们的 mongodb 副本集集群
这是 docker 步骤的一个小主题,但我们需要一个数据库来保存我们的微服务使用的数据,在这一步中,我不会花时间来描述如何做到这一点,我已经写了一篇关于如何将 mongodb 副本集集群部署到 docker 的文章,我强烈建议您,如果您还没有,可以看看我的文章。
* [## 如何使用 Docker 部署 MongoDB 副本集
本文将介绍如何使用 docker 设置带身份验证的 MongoDB 副本集。
medium.com](https://medium.com/@cramirez92/how-to-deploy-a-mongodb-replica-set-using-docker-6d0b9ac00e49)
或者跳过这一步,等到阅读完第 7 步。
(又搞点暴徒生活😎)
步骤 6:在我们的 docker 集群中创建 docker 服务
做第 5 步是非常重要的,因为如果我们没有我们的数据库和运行我们的 docker 服务将无法正确启动。
现在让我们在我们的**_docker_setup**
文件夹中创建另一个名为**start-services.sh**
的文件。这个 bash 脚本将启动我们所有类型为 Docker 服务 的微服务,这样这些服务就可以根据需要扩大或缩小规模。
既然我们的服务规模将会扩大和缩小,我们在调用这些服务时会遇到麻烦,但亲爱的读者们,没有什么可害怕的,因为,我之前说过,创建Docker swarm 集群的好处之一是,它在幕后为我们设置了一个负载平衡器,Docker 负责在请求时处理要调用的服务。让我们回顾下一个文件。**
正如你所看到的,这个文件与我们的**create-images.sh**
非常相似,但是这次我们从每个服务中调用**start-service.sh**
,现在让我们看看**start-service.sh**
文件是如何组成的。
**#!/usr/bin/env bashdocker service create --replicas 3 --name {service name} -l=apiRoute='{our api route}' -p {port binding} --env-file env {microservice image}**
让我们看一下服务命令:
docker service create
命令创建服务。--name
标志为服务命名,例如movies-service
。--replicas
标志指定了 3 个运行实例的期望状态。- 我们可以附加元数据的
-l
标志物种,例如apiRoute="/movies"
。 -p
标志指定主机和容器上的端口绑定。-e
标志指定了服务环境变量的 can 设置。
步骤 7:在一个命令中执行所有自动化文件
好啦好啦,是施展魔法的时候了🔮✨的人们。
为了执行我们已经创建的所有自动化文件,让我们创建最终的脚本来为我们做所有的事情,因为开发人员很懒🤓。
所以我们需要在 影院微服务 项目的根目录下创建这个文件,我们将把它命名为**kraken.sh**
🦑只是为了好玩,因为很强大😎。
它内部没有复杂的编程,但是它所做的,是为我们调用所有的自动化脚本并完成我们的工作。
最后让我们像下面这样执行它。
**$ bash < kraken.sh**
就这么简单,我们已经做了这么多模块化来简化创建 Docker 群集群 的过程,并自动启动我们的 Docker 服务。
“简单可能比复杂更难:你必须努力让自己的思维变得清晰,才能变得简单。但最终还是值得的,因为一旦你到了那里,你就可以移山。”—史蒂夫·乔布斯
我上传了一个视频演示,看看当我们执行**kraken.sh**
时会发生什么。我稍微加快了视频的速度,但 kraken 过程可能需要 10 分钟左右才能完成,这取决于主机的功率。
最后,我们可以检查 docker 环境执行以下命令的状态,如下图所示。
docker — bash output
正如所示,您可以看到我们的集群中已经复制了一些服务,其他的甚至还没有启动,这是因为机器正在获取我们的映像来启动我们的服务,一旦我们的映像被下载并且我们的服务被启动,我们应该会看到类似下图的内容。
docker service ls — bash output
**现在我们的架构看起来如下图所示,其中我们所有的微服务都是动态创建的,通过所有集群复制,并且可以根据需要进行扩展,唯一手动创建的服务是我们的 mongo 容器和 api-gateways ,为什么因为它们与我们的主机服务器的规范相关,所以 mongo 需要持久存储,我们的 api 需要发现主机 docker 服务。
现在,让我们验证我们的服务当前已经启动并正在运行,因此我们需要执行如下图所示的命令。
docker service ps {service} — bash output
如果我们运行 github 上的 Docker Swarm visualizer、 ,我们可以看到我们的服务(容器)是如何分布在我们的 Docker swarm 集群 上的,如下图所示。
Docker swarm visualizer
如果我们缩小一些服务,例如docker-machine ssh manager1 docker service scale movies-service=1
,我们可以看到我们的服务是如何在我们的集群上重新分布的,如下图所示。
Docker swarm visualizer
***我们几乎完成了 *cinemas 微服务配置、以及 cinemas 微服务系统。
步骤 8:额外配置
这是一篇非常大的文章,但是我们已经学到了很多关于 docker 如何适应我们的开发,以及 docker 如何补充我们的系统使之更加健壮。
我们还需要做一些事情,正确设置并准备运行我们的影院微服务:****
- 我们需要更新 api-gateway,,以便现在可以发现正在运行的 docker 服务,从而能够进行代理。
- 我们需要填充我们的数据库,为此你可以去查看这里的 github 仓库自述文件中的命令。
在我们的 API 网关中,我们只需要修改我们的**docker.js**
中的几行代码,而不是调用listContainers()
函数,我们会调用listServices()
函数并用提供的服务设置我们的路线。
为了不使这篇文章变得更长,欢迎您在 github 仓库检查对 API 网关的完整代码更改,如果您有任何问题,一如既往地欢迎您给我发推文或在下面发表评论😃📝。
步骤 9:测试我们的设置
因为如果不对我们的系统进行一些测试,我们的文章是不完整的。测试从根本上来说是重要的,因为我们可以从不同的角度,用不同的视角来看待系统,并以不同的期望来测试它。软件测试的最终目的不是找到 bug,而是使产品定性。作为一名优秀的测试人员,我们正在为产品质量的提高做出贡献。
*****# we need to locate at the api-gateway folder and execute the test** $ npm run int-test***
我们将得到如下输出。
这里我们调用我们的 api 网关服务,正如你所看到的,我们调用不同的docker-machine
ip,我们的 api 网关代理我们的请求到我们的 Docker 服务 ,,最后我们的测试正确通过😎。
我还对部署在 docker swarm 集群中的 cinema 微服务系统进行了 jmeter 压力测试,因此您可以看到预期的结果。
#是时候回顾一下了
我们所做的…
我们见过很多码头工人🐋。我们讨论了 whale、 Docker、Docker-Machine、Docker-Swarm、Docker-Images、Docker-Hub、Docker-Services 是什么,以及如何进行适当的配置,如何设置自动化流程,以及如何与我们的 cinemas 系统相适应。
**借助 docker,我们使我们的影院微服务和系统更具动态性、容错性、可扩展性和安全性。 但是 docker 还有太多有趣的东西可以看,比如 ***Docker 网络、Docker 撰写、Docker 插件等等……*Docker 是一个不断扩展的 devops 世界。
我们已经看到了使用 NodeJS 的微服务的大量开发,并且我们已经看到了如何使用 Docker 生态系统来实现这种微服务,但是我们还可以做和学习更多的东西,这只是更高级的 Docker 平台的一个小高峰。我希望这已经展示了一些有趣和有用的东西,您可以在您的工作流中使用这些东西。
#还有一件事…
我知道这篇文章变得很长,但我认为值得再看一步,这将向我们展示如何监控我们的 docker swarm 集群。
步骤 9:监控 docker 集群
因此,要开始监控我们的集群,我们需要在我们的**manager1 docker-machine**
中执行以下命令
**$ docker-machine ssh manager1 docker run --name rancher --restart=unless-stopped -p 9000:8080 -d rancher/server**
然后,当容器准备好了,我们需要在浏览器中访问下面的 url [http://192.168.99.100:9000](http://192.168.99.100:9000i)
。
然后,rancher gui 将向您介绍整个设置过程,最后我们将能够监视我们的群集。
Rancher UI of our cluster
如果我们单击其中一个主机,我们可以看到如下内容。
Rancher — Manager 1 logs
最后,我们录制了 super duper 压力集成测试,这样您就可以在视频中看到所有这些配置的结果,以及我们如何通过图形界面或控制台日志来监控我们的群集😎控制台日志晃动🤘🏽。
所以我们已经看到了超能力💪🏽蓝鲸🐋提供给我们的。
##最终意见
好了,我们的影院微服务系统已经接近完成,但还缺少一些东西,如果我们不开发出缺少的主要部分,我们的影院微服务系统就没有用了,我的朋友们,这是我们的最终用户将与我们的系统交互的前端服务😎,而 web 用户界面是我们系统中缺少的部分。
#感谢阅读
感谢阅读!希望你在文章中找到价值!如果你看过,按下推荐键,推荐给朋友,分享或者再读一遍。
如果你对这个系列的任何方面有疑问,或者需要我的帮助来理解某些东西,请随时给我发推特或者在下面留下评论。
让我记住你,这篇文章是“ 搭建 NodeJS 影院微服务 ”系列的一部分,所以,下周我会再发表一章。
与此同时,请继续关注,保持对✌的好奇🏼👨🏻💻👩🏻💻
再见了!😁
你可以在 Twitter @ crami rez _ 92
https://twitter.com/cramirez_92关注我*
# Github 的完整代码
您可以在下面的链接中查看文章的完整代码。
** [## GitHub-Crizstian/cinema-微服务:影院微服务示例
电影院微服务-电影院微服务示例
github.com](https://github.com/Crizstian/cinema-microservice)
#进一步阅读||阅读互补
参考数量
在 Spark 上部署 Python 模型(更高效)
更新:我写了关于 部署 Scikit 的另一种方式——通过 Spark 学习模型,避免了这种方法的一些问题。
我把这个贴出来,希望其他人可以避免一些我必须经历的痛苦。有时候我想在 scikit-learn 中训练一个模型,但是在 Spark 中为一个大型数据集中的所有记录建模结果。是的,我知道我可以使用 Spark MLlib,但我发现 scikit-learn 有一套更强大的产品,我理解 scikit 中的代码-learn 比我理解 MLlib 中的代码更好,我只是更熟悉 scikit-learn。然而,通过 PySpark UDF 调用 scikit-learn 的“predict”方法会产生一些问题:
- 对于 Spark 数据帧的每一条记录,它都会导致对模型对象进行清理和拆包的开销。
- 它没有利用 scikit-learn 的优化,这主要是由于对 NumPy 数组的矢量化函数调用。
我发现可以通过对 spark 数据帧进行分组来减轻一些开销,以便一次在多个记录上调用我的 Python 对象的方法。你可以这样做:
- 在 Spark 数据框中设置三列:
*一个唯一的 id。这可以是任何东西。只要它是独一无二的,你就可以去。
所有你的预测者。您可以使用 Structype 或 MLLib 的 VectorAssembler 将所有预测器放入一列。
***一组列。**你可以调用 row_number()按你想要的组数取模运算。我发现创建足够多的组,每个组包含 50-100k 条记录,这样做通常很有效。
2.调用 Spark SQL 函数“create_map ”,将您的唯一 id 和预测值列合并成一列,其中每条记录都是一个键值存储。
3.按 groups 列分组,并在 key-value 列上调用 Spark SQL 函数“collect_list”。这将把你的数据集合到字典列表中。
4.传播你的 scikit-learn 模型。
5.创建一个 UDF,将字典列表解包为一个键列表(您的唯一 id)和一个列表列表(您的预测值)。然后,您可以将列表列表直接输入到广播的 scikit-learn 模型的“predict”方法中。然后用您的键列表压缩该函数调用的结果,并转换成一个字典。udf 将返回一个 MapType,根据您的键所采用的格式以及您希望从 scikit-learn 函数调用返回的格式来适当地设置键和值的类型。
6.对 udf 的结果调用 explode,并包含两个别名—一个用于键,一个用于结果。然后,您将拥有一个新的数据框,其大小与原始(预分组)数据框相同,其中一列是您的结果,另一列是可用于将结果与原始数据连接起来的键。
这里有一个例子:
"""
assumes the following already exist within the environment:
`model`: a scikit-learn class that predicts probabilities for a two-class (0.0, 1.0) model
`sdf`: a spark dataframe with at least two columns: "unique_id" and "feature_list"
"""**import** pyspark.sql.functions as f
**import** pyspark.sql.types as t
**import** pyspark.sql.window.Window as w
**from** pyspark.context **import** SparkContextsc **=** SparkContext.getOrCreate()# broadcast model
model_broadcast **=** sc.broadcast(model)# udf to predict on the cluster
**def** predict_new(feature_map): ids, features **=** zip(*****[
(k, v) **for** d **in** feature_map **for** k, v **in** d.items()
]) ind **=** model_broadcast.value.classes_.tolist().index(1.0) probs **=** [
float(v) **for** v **in**
model_broadcast.value.predict_proba(features)[:, ind]
] **return** dict(zip(ids, probs))predict_new_udf **=** f.udf(
predict_new,
t.MapType(t.LongType(), t.FloatType()
)# set the number of prediction groups to create
nparts **=** 5000# put everything together
outcome_sdf **=** (
sdf
.select(
f.create_map(
f.col('unique_id'),
f.col('feature_list')
).alias('feature_map'),
(
f.row_number().over(
w.partitionBy(f.lit(1)).orderBy(f.lit(1))
) **%** nparts
).alias('grouper')
)
.groupby(f.col('grouper'))
.agg(
f.collect_list(f.col('feature_map')).alias('feature_map')
)
.select(
predict_new_udf(f.col('feature_map')).alias('results')
)
.select(
f.explode(f.col('results'))
.alias('unique_id', 'probability_estimate')
)
)
我希望能够展示一些图表,将上述方法的性能与在 PySpark UDF 中简单包装对模型的 predict 方法的调用的性能进行比较,但是我不能:我想出了这个方法,因为我无法让这个简单的方法完成。我有一个超过 1 亿条记录的数据集。我训练了一个朴素贝叶斯(使用 scikit-learn 的 MultinomialNB)分类器,根据散列的术语-文档矩阵(使用 scikit-learn 的 HashingVectorizer)来区分两个类——0 和 1。起初,我只是简单地广播了训练好的模型,然后编写了一个 UDF,它将一个预处理过的字符串作为参数。UDF 通过哈希矢量器运行字符串,然后将这些结果输入模型预测方法。然后,我运行脚本并监控 YARN。两天后,这个过程大约完成了 10%。然后,我按照我在这里概述的方法重新编写了这个过程:UDF 接受一个字符串列表作为参数,这个列表由哈希矢量器处理,结果提供给模型的 predict 方法。整个过程在 30 分钟内完成。
最后一点:不同的 scikit-learn 模型在内存中有很大的不同。朴素贝叶斯模型只需要为每个参数保留几个值。随机森林需要保留森林中的每一棵树。因为您需要将模型传播给每个执行者,所以您会很容易地发现,根据大量数据训练的模型需要大量内存。
部署张量流模型
了解如何将您的模型部署到生产中
更新至 tensorflow 1.7
好,你有一个模型,你想让它可以从网上访问。有几种方法可以做到这一点,但最快和最强大的是 TensorFlow 服务。
它是如何工作的?基本上 TensorFlow 服务创建了一个 gRPC 服务器,您可以在其中发送和接收来自模型的响应。你并不真正了解成为巫师背后的魔力。
这些是我们要做的步骤:
- 做一个笨模型做例子,训练存储
- 从存储的模型中获取您需要的变量
- 从它们中建立张量信息
- 创建模型签名
- 创建并保存模型构建器
- 下载已经编译了 TensorFlow 服务的 Docker 映像
- 使用正确的配置运行 docker 映像
- 创建客户端以发送 gRPC 请求
- 制作一个 API
- 测试一下
代码可以在这里找到。
制作一个愚蠢的模型作为例子,训练和存储它
我们只需要一个模型来玩。下面是一个非常基本的模型,它以两个随机数组作为输入和目标。
*import* tensorflow *as* tf
*import* numpy *as* np
*import* os, sys
DATA_SIZE = 100
SAVE_PATH = './save'
EPOCHS = 1000
LEARNING_RATE = 0.01
MODEL_NAME = 'test'
*if not* os.path.exists(SAVE_PATH):
os.mkdir(SAVE_PATH)
data = (np.random.rand(DATA_SIZE, 2), np.random.rand(DATA_SIZE, 1))
test = (np.random.rand(DATA_SIZE // 8, 2), np.random.rand(DATA_SIZE // 8, 1))
tf.reset_default_graph()
x = tf.placeholder(tf.float32, shape=[*None*, 2], name='inputs')
y = tf.placeholder(tf.float32, shape=[*None*, 1], name='targets')
net = tf.layers.dense(x, 16, activation=tf.nn.relu)
net = tf.layers.dense(net, 16, activation=tf.nn.relu)
pred = tf.layers.dense(net, 1, activation=tf.nn.sigmoid, name='prediction')
loss = tf.reduce_mean(tf.squared_difference(y, pred), name='loss')
train_step = tf.train.AdamOptimizer(LEARNING_RATE).minimize(loss)
checkpoint = tf.train.latest_checkpoint(SAVE_PATH)
should_train = checkpoint == *None
with* tf.Session() *as* sess:
sess.run(tf.global_variables_initializer())
*if* should_train:
print("Training")
saver = tf.train.Saver()
*for* epoch *in* range(EPOCHS):
_, curr_loss = sess.run([train_step, loss], feed_dict={x: data[0], y: data[1]})
print('EPOCH = {}, LOSS = {:0.4f}'.format(epoch, curr_loss))
path = saver.save(sess, SAVE_PATH + '/' + MODEL_NAME + '.ckpt')
print("saved at {}".format(path))
*else*:
print("Restoring")
graph = tf.get_default_graph()
saver = tf.train.import_meta_graph(checkpoint + '.meta')
saver.restore(sess, checkpoint)
loss = graph.get_tensor_by_name('loss:0')
test_loss = sess.run(loss, feed_dict={'inputs:0': test[0], 'targets:0': test[1]})
print(sess.run(pred, feed_dict={'inputs:0': np.random.rand(10,2)}))
print("TEST LOSS = {:0.4f}".format(test_loss))
记住:如果你使用 tf.layers.dense,实际的输出是用你提供的名字+ 函数名(lol)来调用的
x = tf.placeholder(tf.float32, shape=[*None*, 2], name='inputs')...
pred = tf.layers.dense(net, 1, activation=tf.nn.sigmoid, name='prediction')
如果您运行代码,它将创建./save
文件夹(如果它不存在),或者如果已经有一个存储的实例,它将只评估测试集上的模型。
# training the model
...
EPOCH = 997, LOSS = 0.0493
EPOCH = 998, LOSS = 0.0495
EPOCH = 999, LOSS = 0.0497
saved at ./save/test.ckpt
如果我们再次运行脚本,我们会看到
Restoring
TEST LOSS = 0.0710
完美!现在我们有了保存的模型
从存储的模型中获取您需要的变量
让我们创建一个名为serve.py
的文件,它将处理服务于我们的 TF 模型背后的逻辑。首先要做的是从存储的图中获取我们需要的变量。
*import* tensorflow *as* tf
*import* os
SAVE_PATH = './save'
MODEL_NAME = 'test'
VERSION = 1
SERVE_PATH = './serve/{}/{}'.format(MODEL_NAME, VERSION)
checkpoint = tf.train.latest_checkpoint(SAVE_PATH)
tf.reset_default_graph()
*with* tf.Session() *as* sess:
# import the saved graph
saver = tf.train.import_meta_graph(checkpoint + '.meta')
# get the graph for this session
graph = tf.get_default_graph()
sess.run(tf.global_variables_initializer())
# get the tensors that we need
inputs = graph.get_tensor_by_name('inputs:0')
predictions = graph.get_tensor_by_name('prediction/Sigmoid:0')
从它们中建立张量信息
现在我们有了我们的变量inputs
和predictions
。我们需要从它们中构建张量信息,该信息将用于创建将被传递给 SavedModelBuilder 实例的签名定义。非常容易
# create tensors info
model_input = tf.saved_model.utils.build_tensor_info(inputs)
model_output = tf.saved_model.utils.build_tensor_info(predictions)
创建模型签名
现在,我们终于可以创建模型签名了,它标识了服务对客户端的期望。在我们的情况下
# build signature definition
signature_definition = tf.saved_model.signature_def_utils.build_signature_def(
inputs={'inputs': model_input},
outputs={'outputs': model_output},
method_name= tf.saved_model.signature_constants.PREDICT_METHOD_NAME)
这里我们从 TF 中调用一个 utils 函数,它接受inputs
、outputs
和method_name
。最后一个只是一个常量,表示将要做什么,在我们想要预测的情况下,它们被定义为:
创建并保存模型构建器
创建一个 SavedModelBuilder 实例,并传递我们需要的所有信息。
builder = tf.saved_model.builder.SavedModelBuilder(SERVE_PATH)
builder.add_meta_graph_and_variables(
sess, [tf.saved_model.tag_constants.SERVING],
signature_def_map={
tf.saved_model.signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY:
signature_definition
})
# Save the model so we can serve it with a model server :)
builder.save()
在add_meta_graph_and_variables
中,我们通过当前会话,一个我不知道为什么需要它们的tags
数组,SERVING
常量和signature_def_map
。同样,对于最后一个,我不知道我们为什么需要它,但是基本上我们传递一个字典,在那里我们告诉DEFAULT_SERVING_SIGNATURE_DEF_KEY
我们有那个签名定义(在前面的“创建模型签名”一节中定义的那个)。
完整剧本这里。
运行脚本,它会创建serve
目录:
下载已经编译了 TensorFlow 服务的 Docker 映像
首先安装 docker 。
不要遵循 TensorFlow 文档,因为它们解释了如何设置 docker 映像和编译 TF serving,这需要花费很长时间。
现在单据坏了,查看这里:
https://github.com/tensorflow/tensorflow/issues/19006
有人制作了一个 docker 图像,上面已经编译了所有东西,所以我们将使用这个图像。图像链接:
https://hub.docker.com/r/epigramai/model-server/
使用正确的参数运行该命令
docker run -it -p <PORT>:<PORT> — name <CONTAINER_NAME> -v <ABSOLUTE_PATH_TO_SERVE_DIR>:<SERVE_DIR> epigramai/model-server:light-universal-1.7 — port=<PORT> — model_name=<MODEL_NAME> — model_base_path=<MODEL_DIR>
在我们的情况下
docker run -it -p 9000:9000 --name tf-serve -v $(pwd)/serve/:/serve/ epigramai/model-server:light-universal-1.7 --port=9000 --model_name=test --model_base_path=/serve/test
如果一切正常,您应该会看到类似这样的内容:
创建客户端以发送 gRPC 请求
怎么做呢?好吧,再说一次,医生真的不太好。所以我们将使用一个库,这将使事情变得更容易。
使用pip
运行这个命令来安装它,在我的例子中,我使用的是 python3
pip3 install git+ssh://[git@github.com](mailto:git@github.com)/epigramai/tfserving-python-predict-client.git
让我们创建一个名为client.py
的新文件
*import* numpy *as* np
*from* predict_client.prod_client *import* ProdClient
HOST = '0.0.0.0:9000'
# a good idea is to place this global variables in a shared file
MODEL_NAME = 'test'
MODEL_VERSION = 1
client = ProdClient(HOST, MODEL_NAME, MODEL_VERSION)
req_data = [{'in_tensor_name': 'inputs', 'in_tensor_dtype': 'DT_FLOAT', 'data': np.random.rand(1,2)}]
prediction = client.predict(req_data, request_timeout=10)
print(prediction)
在运行它之前,确保您已经启动了 docker 容器。午饭后你应该会看到这样的脚本:
{'outputs': array([[ 0.53334153]])}
以outputs
为关键字、以正确预测为值的字典
创建 API 端点
是时候最终让我们的模型可以从网上访问了。我们将使用 Flask 来创建 HTTP 服务器。让我们重构我们的client.py
客户端必须接受 HTTP 调用,将响应数据转换为 numpy 数组,调用模型并返回包含预测的 JSON。下面是的最终代码。
*import* numpy *as* np
*from* predict_client.prod_client *import* ProdClient
*from* flask *import* Flask
*from* flask *import* request
*from* flask *import* jsonify
HOST = 'localhost:9000'
MODEL_NAME = 'test'
MODEL_VERSION = 1
app = Flask(__name__)
client = ProdClient(HOST, MODEL_NAME, MODEL_VERSION)
*def* convert_data(*raw_data*):
*return* np.array(*raw_data*, dtype=np.float32)
*def* get_prediction_from_model(*data*):
req_data = [{'in_tensor_name': 'inputs', 'in_tensor_dtype': 'DT_FLOAT', 'data': *data*}]
prediction = client.predict(req_data, request_timeout=10)
*return* prediction
@app.route("/prediction", methods=['POST'])
*def* get_prediction():
req_data = request.get_json()
raw_data = req_data['data']
data = convert_data(raw_data)
prediction = get_prediction_from_model(data)
# ndarray cannot be converted to JSON
*return* jsonify({ 'predictions': prediction['outputs'].tolist() })
*if* __name__ == '__main__':
app.run(host='localhost',port=3000)
测试一下
终于!我成功了!是时候尝试一下了,打开您最喜欢的 HTTP 客户端,在我的例子中是 postman ,尝试使用POST
请求向localhost:3000/prediction
发送一个以data
为键、以矢量为值的 JSON
发送后,我们有了回应
完美!它工作了。
最终代码可以在这里找到
结论
我们已经看到了服务 TensorFlow 模型并使用 Flask 通过 HTTP 请求访问它的最佳方式。
也许你还可以找到值得一读的我的其他文章:
https://towards data science . com/reinforcement-learning-cheat-sheet-2f 9453 df 7651
https://towards data science . com/how-to-use-dataset-in-tensor flow-c 758 ef 9 e 4428
感谢您的阅读,
弗朗西斯科·萨维里奥
在 Python 中将 Keras 深度学习模型部署为 Web 应用程序
(Source)
深度学习、web 应用、Flask、HTML 和 CSS 在一个项目中
建立一个很酷的机器学习项目是一回事,但归根结底,你希望其他人能够看到你的努力。当然,你可以把整个项目放在 GitHub 上,但是你的祖父母怎么知道呢?不,我们想要的是将我们的深度学习模型部署为世界上任何人都可以访问的 web 应用程序。
在本文中,我们将看到如何编写一个 web 应用程序,它采用一个经过训练的 Keras 递归神经网络,并允许用户生成新的专利摘要。这个项目建立在示例递归神经网络文章的基础上,但是知道如何创建 RNN 并不是必需的。我们现在只是把它当作一个黑盒:我们放入一个开始序列,它输出一个全新的专利摘要,我们可以在浏览器中显示它!
传统上,数据科学家开发模型,前端工程师向世界展示它们。在这个项目中,我们将不得不扮演这两个角色,并投入到 web 开发中(尽管几乎都是用 Python)。
该项目需要将众多主题结合在一起:
最终的结果是一个 web 应用程序,它允许用户使用经过训练的递归神经网络生成全新的专利摘要:
这个项目的完整代码可以在 GitHub 上找到。
方法
目标是让 web 应用程序尽快启动并运行。为此,我选择了 Flask,它允许我们用 Python 编写应用程序。我不喜欢弄乱样式(这很明显),所以几乎所有的 CSS 都是复制和粘贴的。Keras 团队的这篇文章对基础知识很有帮助这篇文章也是一个有用的指南。
总的来说,这个项目坚持我的设计原则:快速建立并运行一个原型——根据需要尽可能多地复制和粘贴——然后迭代开发出更好的产品。
带有 Flask 的基本 Web 应用程序
用 Python 构建 web 应用程序的最快方法是使用 Flask 。要制作我们自己的应用程序,我们可以使用以下代码:
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "<h1>Not Much Going On Here</h1>"app.run(host='0.0.0.0', port=50000)
如果您复制并粘贴这段代码并运行它,您将能够在 localhost:50000 上查看您自己的 web 应用程序。当然,我们想做的不止这些,所以我们将使用一个稍微复杂一点的函数,它基本上做同样的事情:处理来自浏览器的请求,并以 HTML 的形式提供一些内容。对于我们的主页,我们希望为用户提供一个表单来输入一些细节。
用户输入表单
当我们的用户到达应用程序的主页时,我们将向他们显示一个表单,其中有三个参数可供选择:
- 输入 RNN 的开始序列或随机选择
- 选择 RNN 预测的多样性
- 选择 RNN 输出的字数
为了用 Python 构建一个表单,我们将使用[wtforms](https://wtforms.readthedocs.io/)
。制作表单的代码是:
这将创建一个如下所示的表单(样式来自main.css
):
代码中的validator
确保用户输入正确的信息。例如,我们检查所有的框都被填满,并且diversity
在 0.5 和 5 之间。必须满足这些条件,表单才能被接受。
Validation error
在Flask
中,我们实际上提供表单的方式是使用模板。
模板
模板是一个具有基本框架的文档,我们需要在其中填入细节。对于 Flask web 应用程序,我们可以使用 Jinja 模板库将 Python 代码传递给 HTML 文档。例如,在我们的 main 函数中,我们将把表单的内容发送给一个名为index.html
的模板。
当用户到达主页时,我们的应用程序将提供来自form
的详细信息index.html
。该模板是一个简单的 html 脚手架,其中我们使用{{variable}}
语法引用 python 变量。
对于表单中的每个错误(那些不能被验证的条目),一个错误将flash.
除此之外,这个文件将显示如上的表单。
当用户输入信息并点击submit
(一个POST
请求)时,如果信息是正确的,我们希望将输入转移到适当的函数,用训练过的 RNN 进行预测。这意味着修改home()
。
现在,当用户点击submit
并且信息正确时,根据输入,输入被发送到generate_random_start
或generate_from_seed
。这些函数使用经过训练的 Keras 模型来生成一个由用户指定了diversity
和num_words
的新专利。这些函数的输出依次被发送到模板random.html
或seeded.html
中的任一个,以作为网页。
使用预先训练的 Keras 模型进行预测
model
参数是经过训练的 Keras 模型,加载如下:
(tf.get_default_graph()
是基于此要点的变通方法。
我不会展示这两个util
函数的全部内容(这里的是代码),您需要理解的是,它们使用经过训练的 Keras 模型和参数,并对新的专利摘要进行预测。
这两个函数都返回带有格式化 HTML 的 Python 字符串。该字符串被发送到另一个模板以呈现为网页。例如,generate_random_start
返回进入random.html
的格式化 html:
这里我们再次使用Jinja
模板引擎来显示格式化的 HTML。由于 Python 字符串已经被格式化为 HTML,我们所要做的就是使用{{input|safe}}
(其中input
是 Python 变量)来显示它。然后,我们可以像处理其他 html 模板一样,在main.css
中处理这个页面。
输出
函数generate_random_start
选择一个随机的专利摘要作为开始序列,并根据它进行预测。然后,它显示启动序列、RNN 生成的输出和实际输出:
Random starting sequence output.
函数generate_from_seed
采用用户提供的启动序列,然后使用训练好的 RNN 在此基础上构建。输出如下所示:
Output from starting seed sequence
虽然结果并不总是完全正确,但它们确实表明递归神经网络已经学会了英语的基础知识。它被训练来从前面的 50 个单词中预测下一个单词,并且学会了如何写一份稍微令人信服的专利摘要!根据预测的diversity
,输出可能看起来完全随机或循环。
运行应用程序
要自己运行这个应用程序,你需要做的就是下载存储库,导航到deployment
目录并输入python run_keras_server.py
。这将立即使 web 应用程序在 localhost:10000 上可用。
根据您的家庭 WiFi 配置,您应该能够使用您的 IP 地址从网络上的任何计算机访问该应用程序。
后续步骤
在你的个人电脑上运行的网络应用程序非常适合与朋友和家人分享。不过,我绝对不建议向你家庭网络上的所有人开放这个!为此,我们希望在 AWS EC2 实例上设置应用程序,并向全世界提供服务(稍后推出)。
为了改进应用程序,我们可以改变风格(通过[main.css](https://github.com/WillKoehrsen/recurrent-neural-networks/blob/master/deployment/static/css/main.css)
)并可能增加更多的选项,例如选择预训练网络的能力。个人项目的伟大之处在于,你可以随心所欲地进行。如果你想玩这个应用,下载代码并开始使用。
结论
在本文中,我们看到了如何将经过训练的 Keras 深度学习模型部署为 web 应用程序。这需要将许多不同的技术结合在一起,包括递归神经网络、web 应用程序、模板、HTML、CSS,当然还有 Python。
虽然这只是一个基本的应用程序,但它表明您可以通过相对较少的努力使用深度学习开始构建 web 应用程序。没有多少人可以说他们已经将深度学习模型部署为 web 应用程序,但是如果您阅读了这篇文章,请将自己算作其中一员!
一如既往,我欢迎反馈和建设性的批评。可以通过推特 @koehrsen_will 或者通过我的个人网站willk . online找到我
submit = SubmitField("Enter")
在训练模型中加载
将机器学习模型部署为 REST API
Artwork by Igor Kozak
作为一名 Python 开发人员和数据科学家,我渴望构建 web 应用程序来展示我的工作。尽管我喜欢设计前端,但同时学习机器学习和应用程序开发变得非常困难。因此,我必须找到一种解决方案,能够轻松地将我的机器学习模型与其他开发人员集成,这些开发人员能够比我更好地构建一个健壮的 web 应用程序。
通过为我的模型构建 REST API,我可以将我的代码与其他开发人员分开。这里有明确的分工,这有利于定义责任,并防止我直接阻止不参与项目机器学习方面的队友。另一个优点是,我的模型可以被在不同平台上工作的多个开发人员使用,比如 web 或 mobile。
在本文中,我将构建一个简单的 Scikit-Learn 模型,并使用 Flask RESTful 将其部署为 REST API。本文特别面向没有广泛计算机科学背景的数据科学家。
关于模型
对于这个例子,我组装了一个简单的朴素贝叶斯分类器来预测电影评论中短语的情感。
数据来自 Kaggle 竞赛,影评情感分析。评论被分成单独的句子,句子被进一步分成单独的短语。所有的短语都有一个情感分数,这样就可以训练一个模型,根据这个模型,哪些词可以给一个句子带来积极的、中性的或消极的情感。
Distribution of ratings from the Kaggle dataset
大多数短语的评级都是中性的。首先,我尝试使用多项式朴素贝叶斯分类器来预测 5 个可能类别中的一个。但是,因为大多数数据的等级为 2,所以该模型的表现不是很好。我决定保持简单,因为这个练习的要点主要是关于作为 REST API 进行部署。因此,我将数据限制在极端类别,并训练模型仅预测消极或积极的情绪。
结果证明,多项式朴素贝叶斯模型在预测积极和消极情绪方面非常有效。你可以在这个 Jupyter 笔记本演练中找到模型训练过程的快速概述。在 Jupyter 笔记本中训练完模型后,我将代码转移到 Python 脚本中,并为 NLP 模型创建了一个类对象。你可以在这个链接找到我的 Github repo 中的代码。您还需要 pickle 或保存您的模型,以便您可以快速地将训练好的模型加载到您的 API 脚本中。
现在我们有了模型,让我们将它部署为一个 REST API。
REST API 指南
为 API 的 Flask 应用程序启动一个新的 Python 脚本。
导入库并加载 Pickles
下面的代码块包含许多 Flask 样板文件和加载分类器和矢量器 pickles 的代码。
from flask import Flask
from flask_restful import reqparse, abort, Api, Resource
import pickle
import numpy as np
from model import NLPModelapp = Flask(__name__)
api = Api(app)# create new model object
model = NLPModel()# load trained classifier
clf_path = 'lib/models/SentimentClassifier.pkl'
with open(clf_path, 'rb') as f:
model.clf = pickle.load(f)# load trained vectorizer
vec_path = 'lib/models/TFIDFVectorizer.pkl'
with open(vec_path, 'rb') as f:
model.vectorizer = pickle.load(f)
创建参数解析器
解析器将检查用户发送给 API 的参数。参数将位于 Python 字典或 JSON 对象中。对于这个例子,我们将特别寻找一个名为query
的键。查询将是一个短语,用户将希望我们的模型预测该短语是积极的还是消极的。
# argument parsing
parser = reqparse.RequestParser()
parser.add_argument('query')
资源类对象
资源是 Flask RESTful APIs 的主要构件。每个类都可以有对应于 HTTP 方法的方法,比如:GET
、PUT
、POST
和DELETE
。GET
将是主要方法,因为我们的目标是服务于预测。在下面的get
方法中,我们提供了如何处理用户查询以及如何打包将返回给用户的 JSON 对象的指导。
class PredictSentiment(Resource):
def get(self):
# use parser and find the user's query
args = parser.parse_args()
user_query = args['query'] # vectorize the user's query and make a prediction
uq_vectorized = model.vectorizer_transform(
np.array([user_query]))
prediction = model.predict(uq_vectorized)
pred_proba = model.predict_proba(uq_vectorized) # Output 'Negative' or 'Positive' along with the score
if prediction == 0:
pred_text = 'Negative'
else:
pred_text = 'Positive'
# round the predict proba value and set to new variable
confidence = round(pred_proba[0], 3) # create JSON object
output = {'prediction': pred_text, 'confidence': confidence}
return output
有一个很棒的教程是由 Flask-RESTful 提供的,他们在其中构建了一个待办事项应用程序,并演示了如何使用PUT
、POST
和DELETE
方法。
端点
以下代码将设置情绪预测器资源的基本 url。您可以想象您可能有多个端点,每个端点都指向一个不同的模型,该模型将做出不同的预测。一个例子可以是端点'/ratings'
,它将用户引导到另一个模型,该模型可以预测给定类型、预算和制作成员的电影评级。您需要为第二个模型创建另一个资源对象。这些可以一个接一个地添加,如下所示。
api.add_resource(PredictSentiment, '/')
# example of another endpoint
api.add_resource(PredictRatings, '/ratings')
Name ==主块
这里不多说了。如果要将此 API 部署到生产环境中,请将 debug 设置为 False。
if __name__ == '__main__':
app.run(debug=True)
用户请求
下面是一些用户如何访问你的 API 的例子,这样他们就可以得到预测。
Jupyter 笔记本中的请求模块:
url = '[http://127.0.0.1:5000/'](http://127.0.0.1:5000/')
params ={'query': 'that movie was boring'}
response = requests.get(url, params)
response.json()Output: {'confidence': 0.128, 'prediction': 'Negative'}
在终端中使用 curl:
$ curl -X GET [http://127.0.0.1:5000/](http://127.0.0.1:5000/) -d query='that movie was boring'
{
"prediction": "Negative",
"confidence": 0.128
}
在终端中使用 HTTPie:
$ http [http://127.0.0.1:5000/](http://127.0.0.1:5000/) query=='that movie was boring'HTTP/1.0 200 OK
Content-Length: 58
Content-Type: application/json
Date: Fri, 31 Aug 2018 18:49:25 GMT
Server: Werkzeug/0.14.1 Python/3.6.3{
"confidence": 0.128,
"prediction": "Negative"
}
现在,我的队友只需向这个 API 发出请求,就可以将情绪预测添加到他们的应用程序中,而无需将 Python 和 JavaScript 混合在一起。
完整的app.py
代码
有时在一个地方看到所有代码会很有帮助。
文件结构
我想包括的最后一件事是这个简单 API 的文件结构的概述。
sentiment-clf/
├── README.md
├── app.py **# Flask REST API script**
├── build_model.py **# script to build and pickle the classifier**
├── model.py **# script for the classifier class object**
├── util.py **# helper functions**
├── requirements.txt
└── lib/
├── data/ **# data from Kaggle**
│ ├── sampleSubmission.csv
│ ├── test.tsv
│ └── train.tsv
└── models/ **# pickled models for import into API script**
├── SentimentClassifier.pkl
└── TFIDFVectorizer.pkl
部署
一旦你建立了你的模型和 REST API,并完成了本地测试,你就可以像部署 Flask 应用程序一样部署你的 API 到网络上的许多主机服务上。通过部署在 web 上,任何地方的用户都可以向您的 URL 发出请求以获得预测。部署指南包含在烧瓶文档中。
关闭
这只是为情感分类器构建 Flask REST API 的一个非常简单的例子。同样的过程可以应用于其他机器学习或深度学习模型,只要你训练并保存了它们。
除了将模型部署为 REST API 之外,我还使用 REST API 来管理我从 web 上收集的数据的数据库查询。这让我可以与全栈开发人员合作,而不必管理他们的 React 应用程序的代码。如果一个移动开发者想要开发一个应用,那么他们只需要熟悉 API 端点。
如果你有任何反馈或批评,请随时与我分享。如果本演练对您有所帮助,请喜欢👏文章。干杯!🍻
在 AWS 上部署 Python Web 应用程序
(Source)
如何与世界分享您的 Python 项目
虽然我喜欢做数据科学和编程项目,因为我个人喜欢构建自己的东西,但与世界上的任何人在线分享您的项目也是一种快乐。幸运的是,多亏了亚马逊网络服务(AWS ),在几分钟内,我们就可以向全世界免费部署一个 Python 网络应用程序。
在本文中,我们将了解如何在免费的 EC2 实例上将深度学习 web 应用部署到 AWS。本文将使用内置于的应用程序,部署一个 Keras 深度学习模型作为 Python 中的 Web 应用程序,通过 Python 中的示例使用在递归神经网络中开发的模型。这两个都不是必需的,只需知道我们的应用程序使用 RNN 生成新颖的专利摘要。项目的所有代码都可以在 GitHub 上找到。
亚马逊网络服务 EC2
亚马逊网络服务是亚马逊云计算产品系列的总称。我们将使用亚马逊弹性计算云(EC2) ,这是一项服务,我们在云中租用虚拟计算机来运行应用程序。AWS EC2 提供了一个免费层,因此我们可以不花一分钱进行部署。
首先,创建一个 AWS 账户,然后前往位于https://console.aws.amazon.com/ec2的 EC2 控制台。点击 Launch Instance 按钮,选择一个Amazon Machine Instance(AMI)“包含启动实例所需的软件配置(操作系统)的模板”你可以使用任何你熟悉的操作系统(尽管有些不符合免费层的条件),但我将使用 Ubuntu Server 18.04:
AMI type (Ubuntu 18.04)
点击 Select,然后在下一页选择符合条件的 t2.micro 实例(实例是我们 AMI 的硬件)。这只有 1 个 CPU 和 1 GB 的 RAM,但实际上足以运行我们预先训练的递归神经网络应用程序!如果你期望更多的流量或者运行一个 cpu 密集型的应用程序,你可能不得不付钱。
安全组
选择所需的实例类型,然后转到选项卡 6。在页面顶部配置安全组。安全组过滤进出我们实例的流量——基本上,谁可以访问我们的虚拟计算机。
您(只有您)需要通过ssh
访问实例,所以添加一个规则,允许 SSH 使用Source
“My IP”。我们希望 others 能够在网络浏览器中访问我们的应用程序,所以添加一个规则来允许所有来源的 HTTP 访问。最终的安全配置是:
Security group rules
接下来,点击查看和启动,然后启动。这将显示使用密钥对的选项。你需要这个来通过ssh
访问服务器,所以请确保创建一个新的密钥对,并将私钥保存在你记得的地方。如果丢失,您将无法再次访问您的实例!
最后,点击 Launch Instances,Amazon 将启动您自己的虚拟机,该虚拟机实际位于… 某处。等待几分钟,让实例启动,然后进入下一步:连接到实例。
通过 SSH 连接到服务器
一旦实例启动并运行,在 EC2 实例仪表板上选择它(服务> EC2 >运行实例)并点击 Connect。这将为我们提供连接到实例的确切命令。
Connect dialog from EC2 running instances dashboard.
复制示例代码,并将其粘贴到 Bash 中,或者粘贴到在带有您的私钥的文件夹中运行的命令提示符中(在启动您的实例时生成)。假设一切顺利,您将登录到您的实例并看到一个熟悉的终端命令提示符。
安装要求
这个 AMI 配备了 Python 3.6 ,所以我们只需要克隆存储库并安装应用依赖项。首先,获取存储库:
git clone [https://github.com/WillKoehrsen/recurrent-neural-networks.git](https://github.com/WillKoehrsen/recurrent-neural-networks.git)
然后安装pip
,移入资源库,安装需求。
sudo apt-get update
sudo apt-get install python3-pip
cd recurrent-neural-networks
pip3 install --user -r requirements.txt
运行和访问 Web 应用程序
运行应用程序很简单(第二个命令可能需要sudo
):
cd deployment
python3 run_keras_server.py
(如果你想了解 web 应用程序中发生了什么,看看以前的文章中的开发过程)。
您应该在终端中看到以下输出:
虽然看起来这个应用运行在 localhost:80/上,但那是在虚拟机上。为了访问 web 应用程序,我们必须使用实例的公共 DNS IPv4 ,它可以在正在运行的实例仪表板上找到。
Public DNS for running instance.
将地址复制并粘贴到您的浏览器中,您将看到该应用程序!
Homepage of the web application.
请随意使用递归神经网络应用程序。它所做的是用一个递归神经网络生成新的专利摘要,这个神经网络用关键词“神经网络”训练成千上万的摘要,你可以输入random
作为随机的开始序列,或者你自己的序列。(要看发展,查看这篇文章或者这个笔记本)。
Keras recurrent neural network application.
现在,世界上任何人都可以通过 IPv4 访问您的应用程序。如果您想让应用程序在您注销实例后继续运行,请在屏幕会话中运行它。( Screen 是一个方便的程序,它可以让你使用虚拟控制台从一个终端窗口运行终端会话。)
# From within recurrent-neural-networks/deployment
screen -R deploy
python3 run_keras_server.py
我的(如果我没有关闭它或遇到错误)应用程序应该在http://54.173.255.177/运行。因为我使用的是 t2.micro 实例,所以永久运行这个 web 应用程序的成本正好是$0.00!如果你想要一个域名,你可以从域名注册商比如哈弗那里拿一个。
后续步骤
尽管这是一个快速部署个人项目的不错的解决方案,但这不是一个生产就绪的部署!为此,你要确保使用适当的安全措施(HTTPS 和认证证书)。您还需要确保您的应用程序能够处理预期的流量。仅将此特定解决方案用于没有敏感数据的小型项目。
结论
我们确实生活在一个不可思议的时代:使用 Flask,我们可以在几分钟内开发一个 Python web 应用程序,然后我们可以使用 AWS 将其免费部署到世界各地。我们遵循的一般流程是:开发一个 web 应用程序(最好用 Python),从云提供商那里租用商用硬件,然后向全世界部署一个 web 应用程序。
如果您能够遵循所有教程,从递归神经网络的实现到开发本地 web 应用到在 AWS 上部署,那么您将完成一个令人印象深刻的项目!从一个空白文件到一个正在运行的 web 应用程序的整个过程可能令人望而生畏,但是像大多数技术问题一样,如果你把它分解,每一步都不是压倒性的,有许多开源工具可以使这个过程变得容易。如果你是一个厌倦了在 Jupyter 笔记本上做独立分析的数据科学家,那就主动做一个可以作为应用程序部署的项目。扩展到其他学科是很好的,构建和部署 web 应用程序是学习一些新技能的好机会。
一如既往,我欢迎反馈和建设性的批评。可以通过 Twitter @koehrsen_will 或者通过我的个人网站 willk.online 找到我。
为您的小型企业部署人工智能—预算有限
Photo by Felix Russell-Saw on Unsplash
像大多数成功的小企业主一样,你可能会雄心勃勃地实施新的想法和战略,以保证你的企业保持领先地位。新兴技术也不例外。因此,在花时间探索了一些人工智能(AI)的用例之后,您已经准备好尝试一下了。
当然,总会有人唱反调。“人工智能技术并不适合所有人,”一些人会说。“小公司缺乏部署人工智能工具的预算、资源和能力。”当然,像亚马逊、易贝和 UPS 这样的知名品牌主导了围绕人工智能的对话。随着数据科学家团队夜以继日地构建机器学习模型,以提高效率或找到最佳递送路线,他们不断地创造新闻。
但是人工智能技术并不仅仅适用于预算数十亿美元的公司。事实上,小型企业社区正在削减成本,并通过人工智能应用程序提供出色的客户体验——他们正在与大公司进行大规模竞争。
利用人工智能的力量远没有你想象的那么复杂。这里有一些让你开始的想法。
打造一个 简单的机器人——提高客户满意度,改善员工工作流程。
尝试人工智能的最简单方法之一是建立一个公司聊天机器人,并将其集成到您的客户服务流程中。定制的机器人可以通过提供 24 小时支持、处理简单的查询和实时回答问题来提高客户满意度,这对于没有耐心的客户来说是一大胜利。消费者不仅已经习惯了它们,还喜欢它们。
这也是一件好事,因为专家预测,“到 2020 年,超过 85%的客户互动将无人管理。”网站上一个友好、信息丰富的机器人会让您的客户高兴,同时为您的代理腾出时间来处理更独特、更具挑战性的需求。正确的机器人也是促进员工工作流程的一种聪明方式。公司机器人可以回答人力资源问题,推动入职,并为需要即时答案的忙碌员工提供详细信息。
开始使用聊天机器人很简单。有了各种各样的免费和付费解决方案,构建和运行机器人再简单不过了。
部署人工智能就绪型解决方案——另一个经济实惠的切入点。
即使没有花哨的数据仓库或预算来进行重大的基础设施大修,小公司仍然可以利用智能技术和使用人工智能的应用程序。
软件即服务提供商以低成本或零成本提供人工智能就绪的解决方案,即使在预算有限的情况下也能提供最先进的工具。例如,WorkFusion 帮助企业使用他们的 RPA Express 将人工智能工具插入到现有的工作流程中,这是一种免费下载,提供企业级自动化,不需要编码。实际上,只需几分钟,您就可以开始意识到效率的提高和工作流程的减少。
为了实现数字营销的成功,成千上万的小企业通过脸书和谷歌的广告平台利用人工智能。另一种进入人工智能技术的快速而肮脏的方法是,他们的算法通过锁定和匹配具有相似特征的人来创建相似的广告活动,从而优化广告活动。
有了多渠道营销活动,像acquisito这样的平台可以分析和管理点击付费成功案例,为优化营销支出提供明智的建议。
不要害怕尝试——但首先要制定战略。
小型企业人工智能成功的关键是将有前途的应用程序与业务目标结合起来。思考并定义技术的目的,并根据这些计划确定优先级。
例如,如果您经常使用复杂的数据,并且后端工作流也很复杂,那么考虑自动化如何能够收紧船只、提高效率并增强工作流。提高后端业务的自动化有助于您更加专注于提供客户渴望的获奖体验。
当你的营销团队的目标是优化广告定位时,人工智能驱动的预测分析可能是一个很好的起点。外卖?一旦人工智能功能被部署,就可以对其进行实验,但是没有计划就进行实验是疯狂的。
总之
有了比以往更多的选择,小企业正在建立强大的人工智能战略,而不必雇用数据科学家或昂贵的营销专家。通过轻松访问第三方工具和用户友好的应用程序,人工智能支持的功能正在使工作流程更加高效,客户更加满意,同时为企业主提供应对数据驱动型经济日益增长的挑战的能力。
无论你现在决定部署人工智能还是以后部署,了解你的选择是必不可少的。现在的明智决策将使你以后受益——这是人工智能旅程中良好的第一步。
部署深度学习模型
创建模型是一回事,但是部署模型来解决业务问题是另一回事。看看部署深度学习模型的最佳选择之一。
什么是模型?
https://towardsdatascience.com/creating-intelligence-with-data-science-2fb9f697fc79
我们人类模拟这个世界,用我们的智慧去理解事物的运作方式,并用这种理解和知识去解决困难和复杂的问题。建模是理解“现实”,我们周围的世界,但创建一个更高层次的原型来描述我们看到的,听到的和感觉到的东西的过程,但它是一个代表性的东西,而不是“实际”或“真实”的东西。
在过去的一篇文章中,我谈到了用人工智能和数据科学解决商业问题的过程,
这里的模型是由像深度学习(DL)算法这样的人工智能创建的。如果您想了解更多关于 DL 的信息,您可以阅读以下内容:
有关于深度学习的惊人介绍、课程和博文。但这是一种不同的介绍…
towardsdatascience.com](/a-weird-introduction-to-deep-learning-7828803693b0) [## 关于深度学习的对话
有人无意中听到两个人谈论深度学习,让我知道每一个小细节。其中一个完全…
towardsdatascience.com](/a-conversation-about-deep-learning-9a915983107)
好了,你刚刚创建了一个模型(比如说一个 DL 模型)来解决一个业务问题,现在你想把它投入生产。
什么是生产?
投入生产对你们每个人来说都有不同的意义。
对一些人来说,将模型投入生产意味着任何人都可以使用模型来计算、测量或观察某些东西。例如,这里一个闪亮的仪表板后面有一个简单的模型,业务分析师可以访问它,它可以是一个“生产化”的模型。
对其他人来说意味着让模型做一些事情或者与客户互动。就像在你的移动应用程序中让一个模型预测当人们向你借钱时你是否应该借钱给他们。
我创建了这个简单的图表来指定部署模型的不同方式:
在这里,我将教你如何通过深度认知将深度学习在线模型或 AaaS 模型部署到生产服务中。
部署您的 DL 模型
deepcognition.ai
如果你想了解更多关于深度认知和他们的深度学习工作室(DLS ),看看这个:
在过去的一个月里,我有幸见到了 DeepCognition.ai 的创始人
becominghuman.ai](https://becominghuman.ai/deep-learning-made-easy-with-deep-cognition-403fbe445351) [## 深度认知的视频漫游
大家好!在本文中,我将与您分享几个视频,带您浏览深度认知的平台…
towardsdatascience.com](/a-video-walkthrough-of-deep-cognition-fd0ca59d2f76)
一旦模型构建完成,DLS 允许将模型部署为 REST API。除了部署 REST API 之外,还生成并部署了一个简单的基于表单的 Web 应用程序,用于快速测试和共享。
这些 REST API 或 Web app 可以用作在线模型或 AaaS。要部署您的模型,您有两种选择:
- 上传您的 DL 代码(如 keras 或 TF),系统会识别它,您可以用 DLS 和您的数据训练它,然后您必须单击部署部分。
- 从头开始用 DLS 创建你的模型,然后训练和部署它。
这里有一个视频来自过去的帖子,您可以从中了解如何部署它:
基本上这些是步骤:
- 点击部署选项卡。
- 选择训练跑步。
- 输入服务名称。
- 选择是否要在您的实例(可以是 web 或本地,如您的公司集群)或远程实例(如 AWS、GCP、Azure 等)中部署它。)
- 点击部署按钮。
就是这样!如果你能以一种非常简单的方式免费完成,你就不必花几个小时去想如何去做。我使用这种方法的经验非常成功。
部分推荐:
- 如果您想要高可用性,就有一个专用的实例来部署您的模型。
- 确保您使用了良好的培训结果,并且在投入生产之前已经验证了您的参数。
- 读读这个:
机器学习无处不在。从广告到物联网到医疗保健等等,几乎所有行业都…
www.kdnuggets.com](https://www.kdnuggets.com/2018/04/operational-machine-learning-successful-mlops.html) [## 将机器学习模型转化为实际产品和服务的经验教训
人工智能仍处于初级阶段。今天,只有 15%的企业在使用机器学习,但是两倍…
www.oreilly.com](https://www.oreilly.com/ideas/lessons-learned-turning-machine-learning-models-into-real-products-and-services)
如果您有任何问题,请在 Twitter 上关注我:
Favio Vázquez 的最新推文(@FavioVaz)。数据科学家。物理学家和计算工程师。我有一个…
twitter.com](https://twitter.com/faviovaz)
和 LinkedIn:
[## favio vázquez——science ia y Datos | LinkedIn 创始人
查看 Favio Vázquez 在世界上最大的职业社区 LinkedIn 上的个人资料。Favio 有 16 个工作列在他们的…
www.linkedin.com](https://www.linkedin.com/in/faviovazquez/)
那里见:)
部署深度学习模型:第 1 部分概述
Diagram overviewing the CI/CD deployment process with Kubernetes. Taken from Kubecon slideshow
最近,学术界和行业研究人员在深度学习领域进行了大量令人兴奋和开创性的研究。他们开发了许多功能强大得令人难以置信的新型号。然而,这种研究的大部分(少数科技巨头之外)仍然只是研究,而不是生产应用的一部分。尽管新论文不断涌现,但在生产中实际利用这些模型仍然非常困难(即使论文提供了代码)。部署机器学习模型仍然是一个重大挑战。在这篇文章中,我将概述“生产化”机器学习模型的各种方法,并权衡它们各自的利弊,而不会涉及太多细节。在后续文章中,我将通过实际代码和示例来探索这些方法。
挑战
我们将假设我们已经自己训练了模型,或者已经从互联网上获得了训练的权重。为了在应用程序中使用您的模型,您必须:
- 用模型的权重加载模型
- 预处理您的数据
- 执行实际预测
- 处理预测响应数据
听起来够简单吧?实际上,这个过程可能非常复杂。
像许多事情一样,关于将机器学习模型部署到生产环境的最佳方式,没有一个明确的答案。你应该问自己的问题是:
- 我的要求是什么?(例如,您预计每秒有多少请求,需要多长时间的延迟等等)
- 我将如何评估模型在生产中的表现?(我将如何收集和存储来自交互的额外数据)
- 我计划多长时间重新培训一次我的模型?
- 有哪些数据预处理需求?
- 生产输入数据的格式是否会与模型训练数据大相径庭?它会分批来还是一股一股来?
- 模型需要能够离线运行吗?
这些是您在尝试部署您的模型之前应该问的基本问题。
将模型直接加载到应用程序中
这个选项本质上将模型视为整个应用程序的一部分,因此将它加载到应用程序中。这种方法在某些情况下比其他情况更容易。
例如,如果核心应用程序本身是用 Python 编写的,这个过程可能会很顺利。总之,它通常需要在设置/配置文件中添加依赖项,并修改您的预测函数,以便通过适当的用户交互来调用。模型是作为应用程序的一部分加载的,所有依赖项都必须包含在应用程序中。
如果您的应用程序不是用 Python 编写的,这个过程会变得更加困难。例如,没有好的方法将 PyTorch 或 Caffe 加载到 Java 程序中。即使是有 Java 库的 Tensorflow,也需要编写大量额外的代码才能完全集成到应用程序中。最后,这并没有明确解决可伸缩性的问题。
然而,如前所述,当您想要快速部署用 Python 编写的应用程序时,这种方法仍然是有益的。它也是没有互联网连接的设备的较好选择之一。
调用 API
第二个选项包括创建一个 API 并从您的应用程序中调用该 API。这可以通过多种不同的方式来实现。我在这里详细介绍了最常见的方式。
Kubernetes
在许多方面,Docker 似乎是部署机器学习模型的自然选择。一个模型及其所有的依赖项可以整齐地打包在一个容器中。此外,服务器可以在需要时通过添加更多 Docker 容器来自动扩展。Kubernetes 是管理 Docker 容器的最佳方式之一,因此有利于机器学习。
最近,Kubernetes 发布了 Kubeflow ,旨在将机器学习引入 Kubernetes 框架。Kubeflow 试图使训练、测试和部署您的模型以及收集评估指标变得容易。我计划在以后的博客中介绍 Kubeflow,因为它可能非常复杂。现在只需要理解它是一个完整的软件包,旨在使大规模开发和部署机器学习微服务变得容易。
用 Flask/Django 定制 REST-API
另一个选择是根据您对制作 API 的熟悉程度,从头开始创建自己的 REST-API(这个选项也可以与 Docker 结合使用)。这可以使用烧瓶相对容易地完成。我不会详细讨论如何做到这一点,因为已经有很多教程详细介绍了这个主题。根据请求的数量,您通常可以轻松扩展 Flask。
然而,由于 ML 框架、加载时间和特定的模型预处理需求的差异,即使这样也会变得相当混乱。目前,我正在开发一个用于 Flask/Django 的模型不可知实例化类,以便更容易使用模型,并提供一个使用模型的标准化模板。因此,你可以调用model.preprocess()
和model.predict()
而不用考虑后端,而不必记住并实现不同模型的不同函数(另一篇文章中也有更多相关内容)。
AWS Lambda/无服务器
AWS Lambda 是另一条可能的路线。你可以阅读 AWS 的文档来了解如何设置。在“机器学习”中有一篇关于使用 AWS lambda 和 Caffe2 的好文章
其他方法
Apache Beam —我不太了解这种方法,但该方法似乎涉及到使用 Beam 做模型预处理,然后 Tensorflow(目前只支持框架)做实际预测。查看这些幻灯片了解更多信息。
火花/火花
Spark 和 Flink 等几个主要的数据处理框架正在开发软件包,以帮助部署机器学习模型。Flink 有 Flink Tensorflow 旨在将 TF 模型集成到 Flink 流管道中。对于 Spark,有许多不同的包和集成深度学习的尝试。此外,雅虎最近发布了自己的 库 ,允许分布式训练和模型服务。
结论
在未来的文章中,我将更详细地介绍如何用 Kubeflow 构建一个 API 来服务模型,并讨论如何将深度学习模型加载到 Java 程序和 Flink 管道中。
使用 Flask 部署 Keras 深度学习模型
Source: Wikimedia Commons
这篇文章演示了如何使用用 Keras 构建的深度学习模型来设置端点以服务于预测。它首先介绍了一个使用 Flask 来设置 Python 端点的例子,然后展示了在使用 Flask 为预测构建 Keras 端点时需要解决的一些问题。
将深度学习模型产品化具有挑战性,或者至少在过去对我来说是如此,原因有很多:
- **模型序列化:**序列化模型的标准方法,比如 PMML,只有有限的支持。例如 keras2pmml 缺少 relu 激活,这意味着我在模型生产帖子中提出的数据流+ PMML 方法是不可行的。
- **大型库:**在我过去的帖子中,我展示了如何使用 AWS lambda 函数来托管 scikit-learn 模型。这种方法对于 Keras 是有问题的,因为未压缩的 Keras 和 Tensorflow 库超过了 AWS lambda 的 256MB 文件上传限制。
- **运行时间:**批处理和实时预测都很难伸缩,因为我的大部分模型预测经验都是用 Java 编写的。我之前在的博客中提到使用 Jetty 提供实时评估,使用 Google 的数据流提供批量评估。这篇文章展示了当你需要使用 Python 库进行估算时,如何使用 Flask 来代替 Jetty。
这篇文章的目的是展示如何使用 AWS 在 EC2 实例上设置一个 Keras 模型作为端点。我从探索下面的例子开始:
[## 构建一个简单的 Keras +深度学习 REST API
这篇文章中的例子将作为构建你自己的深度学习 API 的模板/起点…
blog.keras.io](https://blog.keras.io/building-a-simple-keras-deep-learning-rest-api.html)
我将讨论的一些问题包括在 Keras 中使用模型持久性时处理自定义指标,在 Keras 与 Flask 结合使用时处理多线程问题,以及让它在 EC2 实例上运行。这篇文章的完整代码清单可以在 GitHub 上找到。
这篇文章介绍了如何设置一个简单的 Flask 应用程序,然后展示了如何使用 Flask 来设置一个带有 Keras 模型的端点。它假设读者熟悉用 jupyter 设置 EC2 实例,这将在这里讨论。
带烧瓶的 Hello World
Flask 是一个 Python 库,它使得设置可以通过 web 调用的 Python 函数变得很容易。它使用注释来提供关于在哪些端点设置哪些功能的元数据。要使用 Flask,您首先需要安装模块:
pip3 install --user Flask
为了熟悉 Flask,我们将设置一个简单的函数来回显传入的参数。下面的代码片段首先实例化一个 Flask 应用程序,定义函数,然后启动应用程序。使用 Flask, app.route 注释用于指定在 web 上的何处使函数可用,以及允许哪些方法。使用下面的代码,该功能将在*location:5000/predict*
可用。该函数检查request.json
和request.args
对象的输入参数,这些参数的使用基于函数的调用方式(例如浏览器 get vs curl post )。如果一个消息参数已经被传递给该函数,当它被回显到该函数返回的 JSON 响应时。
**# load Flask** import flask
app = flask.Flask(__name__)**# define a predict function as an endpoint** [@app](http://twitter.com/app).route("/predict", methods=["GET","POST"])
def predict():
data = {"success": False} **# get the request parameters** params = flask.request.json
if (params == None):
params = flask.request.args **# if parameters are found, echo the msg parameter**
if (params != None):
data["response"] = params.get("msg")
data["success"] = True **# return a response in json format** return flask.jsonify(data)**# start the flask app*, allow remote connections*** app.run(host='0.0.0.0')
当您运行python3 [Flask_Echo.py](https://github.com/bgweber/StartupDataScience/blob/master/DeepLearning/Flask_Echo.py)
时,您将得到以下结果:
* Running on [http://127.0.0.1:5000/](http://127.0.0.1:5000/) (Press CTRL+C to quit)
我们现在可以连接到函数来测试它。为了支持远程连接,我加入了host='0.0.0.0'
,因为 Flask 应用程序运行在 EC2 实例上。如果您使用 EC2,您需要修改安全组以允许在端口 5000 上访问 Flask,类似于在 8888 上允许 Jupyter 访问。
Inbound rules for the EC2 instance.
可以使用 web 浏览器或 curl 调用该函数。我用的是 Windows 环境下的 curl,不然你可以用-d '{"msg":"Hello World"}'
。两种方法的结果是一样的,来自客户端的 JSON 响应重复了传入的 msg 参数。
**# Browser**
[http://](http://localhost:5000/predict?msg=HelloWorld1)[54.227.110.43](http://54.227.110.43:5000/predict?g1=1&g2=0&g3=0&g4=0&g5=0&g6=0&g7=0&g8=0&g9=0&g10=0)[:5000/predict?msg=HelloWorld](http://localhost:5000/predict?msg=HelloWorld1)**# Curl** >curl -X POST -H "Content-Type: application/json" -d "{ \"msg\":
\"Hello World\" }" [http://](http://localhost:5000/predict)[54.227.110.43](http://54.227.110.43:5000/predict?g1=1&g2=0&g3=0&g4=0&g5=0&g6=0&g7=0&g8=0&g9=0&g10=0)[:5000/predict](http://localhost:5000/predict)**# Response** {
"response": "Hello World",
"success": true
}
我们现在有能力将 Python 函数设置为 web 端点,下一步是让函数调用一个经过训练的深度网络。
弗拉斯克&克拉斯
要使用 Keras 进行深度学习,我们需要首先用 Keras 和 Tensorflow 库设置环境,然后训练一个模型,我们将通过 Flask 在 web 上公开该模型。
**# Deep Learning setup** pip3 install --user tensorflow
pip3 install --user keras
pip3 install --user pandas
因为我使用了一个没有附加 GPU 的 EC2 实例,所以在 CPU 模式下运行 Keras 不需要额外的配置。
模型训练 我用一个简单的网络结构创建了一个二元分类器。模型的输入是描述用户以前玩过哪些游戏的特征数组,输出是玩家将来玩特定游戏的可能性。关于训练模型的更多细节可以在我过去关于深度学习的帖子中找到。
**# import panda, keras and tensorflow** import pandas as pd
import tensorflow as tf
import keras
from keras import models, layers**# Load the sample data set and split into x and y data frames** df = pd.read_csv("https://github.com/bgweber/Twitch/raw/
master/Recommendations/games-expand.csv")
x = df.drop(['label'], axis=1)
y = df['label']**# Define the keras model** model = models.Sequential()
model.add(layers.Dense(64, activation='relu', input_shape=(10,)))
model.add(layers.Dropout(0.1))
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dropout(0.1))
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))
**# Use a custom metricfunction** def auc(y_true, y_pred):
auc = tf.metrics.auc(y_true, y_pred)[1]
keras.backend.get_session().run(tf.local_variables_initializer())
return auc **# Compile and fit the model** model.compile(optimizer='rmsprop',loss='binary_crossentropy',
metrics=[auc])
history = model.fit(x, y, epochs=100, batch_size=100,
validation_split = .2, verbose=0) **# Save the model in h5 format** model.save("games.h5")
代码片段定义了一个自定义指标函数,用于训练模型以优化 ROC AUC 指标。这段代码的主要附加部分是最后一步,它将模型序列化为 h5 格式。我们可以稍后将这个模型加载到 Flask 应用程序中,以服务于模型预测。可以通过运行生成games.h5
的python3 [Flask_Train.py](https://github.com/bgweber/StartupDataScience/blob/master/DeepLearning/Flask_Train.py)
来训练模型。
模型部署
用于模型预测的完整代码清单如下所示。代码的整体结构与我们前面的例子相同,但是主要的区别是在定义预测函数之前加载模型,并在预测函数中使用模型。为了重新加载模型,我们需要使用 custom_objects 参数将自定义度量函数作为输入参数传递给 load_model 。
**# Load libraries** import flask
import pandas as pd
import tensorflow as tf
import keras
from keras.models import load_model
***# instantiate flask*** app = flask.Flask(__name__)
***# we need to redefine our metric function in order
# to use it when loading the model*** def auc(y_true, y_pred):
auc = tf.metrics.auc(y_true, y_pred)[1]
keras.backend.get_session().run(tf.local_variables_initializer())
return auc
***# load the model, and pass in the custom metric function*** global graph
graph = tf.get_default_graph()
model = load_model('games.h5', custom_objects={'auc': auc})
***# define a predict function as an endpoint*** @app.route("/predict", methods=["GET","POST"])
def predict():
data = {"success": False}
params = flask.request.json
if (params == None):
params = flask.request.args
***# if parameters are found, return a prediction*** if (params != None):
x=pd.DataFrame.from_dict(params, orient='index').transpose()
with graph.as_default():
data["prediction"] = str(model.predict(x)[0][0])
data["success"] = True
***# return a response in json format*** return flask.jsonify(data)
*#* ***start the flask app, allow remote connections*** app.run(host='0.0.0.0')
使用tf.get_default_graph()
建立对张量流图的引用也是必要的。如果省略此步骤,预测步骤期间可能会发生异常。条件with graph.as_default()
用于在进行预测时获取对图的线程安全引用。在预测函数中,请求参数被转换为数据帧,然后传递给 Keras 模型进行预测。关于使用传入参数的更多细节在我的模型即服务帖子中有所介绍。
可以通过运行python3 [Flask_Deploy.py](https://github.com/bgweber/StartupDataScience/blob/master/DeepLearning/Flask_Deploy.py)
来部署 Flask app。你可以像以前一样连接到应用程序,但是你需要指定属性 G1 到 G10 的值。我使用浏览器测试端点,结果如下:
**# Browser** [http://54.227.110.43:5000/predict?g1=1&g2=0&g3=0&g4=0&g5=0&g6=0&g7=0&g8=0&g9=0&g10=0](http://54.227.110.43:5000/predict?g1=1&g2=0&g3=0&g4=0&g5=0&g6=0&g7=0&g8=0&g9=0&g10=0)**# Response** {
"prediction":"0.04930059",
"success":true}
}
您现在有了一个 EC2 实例,可以在 web 上提供 Keras 预测服务!
结论
部署深度学习模型并不简单,因为您需要使用支持 tensorflow 运行时的环境。为了以服务的形式提供 Keras 模型,我展示了如何使用 Flask 来为预先训练好的模型提供预测服务。这种方法不如我在上一种方法中讨论的 AWS lambda 方法可伸缩,但可能更适合您的用例。在原型制作时,Flash 对于设置本地服务也很有用。
理想情况下,我希望能够将 Flask 中的注释与 AWS lambda 的可伸缩性结合起来,而不需要将库安装到目录中并上传结果的中间步骤。AWS SageMaker 有助于实现这一目标,我将在未来几周内更详细地探索这一工具。
本·韦伯是 Zynga 的首席数据科学家。我们正在招聘!
用 Java 部署 Keras 深度学习模型
Source: Wikipedia
Keras 库为深度学习提供了一个可接近的接口,使神经网络可以为广大受众所用。然而,我所面临的挑战之一是从在 Keras 中探索模型过渡到产品化模型。Keras 是用 Python 编写的,直到最近,在这些语言之外还只有有限的支持。虽然 Flask、PySpark 和 Cloud ML 等工具使得直接用 Python 将这些模型产品化成为可能,但我通常更喜欢用 Java 来部署模型。
像 ONNX 这样的项目正在走向深度学习的标准化,但支持这些格式的运行时仍然有限。一种常用的方法是将 Keras 模型转换成张量流图,然后在其他支持张量流的运行程序中使用这些图。我最近发现了 Deeplearning4J (DL4J)项目,该项目原生支持 Keras 模型,使得用 Java 进行深度学习变得很容易。
[## Keras 导入概述| Deeplearning4j
Keras 模型导入提供了导入最初使用 Keras 配置和训练的神经网络模型的例程…
deeplearning4j.org](https://deeplearning4j.org/docs/latest/keras-import-overview)
我一直在探索的深度学习的一个用例是使用 Keras 在 Python 中训练模型,然后使用 Java 将模型产品化。这对于需要直接在客户端进行深度学习的情况很有用,比如 Android 设备应用模型,以及想要利用现有的用 Java 编写的生产系统的情况。关于使用 Keras 的 DL4J 介绍可以在这里找到。
这篇文章概述了用 Python 训练 Keras 模型,并用 Java 部署它。我使用 Jetty 提供实时预测,使用 Google 的数据流构建批量预测系统。GitHub 上提供了运行这些示例所需的全部代码和数据。
GitHub 是人们构建软件的地方。超过 2800 万人使用 GitHub 来发现、分享和贡献超过…
github.com](https://github.com/bgweber/DeployKeras/tree/master)
模特培训
第一步是使用 Python 中的 Keras 库训练一个模型。一旦有了准备部署的模型,就可以将其保存为 h5 格式,并在 Python 和 Java 应用程序中使用它。在本教程中,我们将使用我在 Flask 上的博客文章中训练的预测哪些玩家可能会购买新游戏的相同模型。
这篇文章演示了如何使用 Keras 构建的深度学习模型来设置端点以服务于预测。它…
towardsdatascience.com](/deploying-keras-deep-learning-models-with-flask-5da4181436a2)
模型的输入是描述玩家已经购买的游戏的十个二元特征( G1,G2,…,G10 ),标签是描述用户是否购买了不包括在输入中的游戏的单个变量。培训过程中涉及的主要步骤如下所示:
import keras
from keras import models, layers**# Define the model structure** model = models.Sequential()
model.add(layers.Dense(64, activation='relu', input_shape=(10,)))
...
model.add(layers.Dense(1, activation='sigmoid'))**# Compile and fit the model** model.compile(optimizer='rmsprop',loss='binary_crossentropy',
metrics=[auc])
history = model.fit(x, y, epochs=100, batch_size=100,
validation_split = .2, verbose=0)**# Save the model in h5 format** model.save("games.h5")
这个过程的输出是一个 h5 文件,它表示我们可以在 Python 和 Java 应用程序中部署的经过训练的模型。在我过去的帖子中,我展示了如何使用 Flask 在 Python 中提供实时模型预测。在这篇文章中,我将展示如何用 Java 构建批处理和实时预测。
Java 设置
为了用 Java 部署 Keras 模型,我们将使用 Deeplearing4j 库。它为 Java 中的深度学习提供了功能,并可以加载和利用用 Keras 训练的模型。我们还将使用数据流进行批量预测,使用 Jetty 进行实时预测。以下是我在这个项目中使用的库:
- deep learning 4j**😗*为 Java 提供深度神经网络功能。
- ND4J**😗*为 Java 提供张量运算。
- Jetty**😗*用于设置 web 端点。
- 云数据流: 为 GCP 上的批量预测提供自动缩放。
我使用下面显示的 pom.xml 将它们导入到我的项目中。对于 DL4J,使用 Keras 时需要核心库和模型导入库。
<dependencies>
<dependency>
<groupId>org.deeplearning4j</groupId>
<artifactId>deeplearning4j-core</artifactId>
<version>1.0.0-beta2</version>
</dependency>
<dependency>
<groupId>org.deeplearning4j</groupId>
<artifactId>deeplearning4j-modelimport</artifactId>
<version>1.0.0-beta2</version>
</dependency>
<dependency>
<groupId>org.nd4j</groupId>
<artifactId>nd4j-native-platform</artifactId>
<version>1.0.0-beta2</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>9.4.9.v20180320</version>
</dependency> <dependency>
<groupId>com.google.cloud.dataflow</groupId>
<artifactId>google-cloud-dataflow-java-sdk-all</artifactId>
<version>2.2.0</version>
</dependency>
</dependencies>
我在 Eclipse 中设置了我的项目,一旦我正确配置了 pom 文件,就不需要额外的设置就可以开始了。
使用 DL4J 的 Keras 预测
现在我们已经建立了库,我们可以开始使用 Keras 模型进行预测。我编写了下面的脚本来测试加载 Keras 模型并对样本数据集进行预测。第一步是从 h5 文件中加载模型。接下来,我定义一个长度为 10 的 1D 张量,并生成随机的二进制值。最后一步是对模型调用 output 方法来生成预测。因为我的模型只有一个输出节点,所以我使用 getDouble(0) 来返回模型的输出。
**// imports** import org.deeplearning4j.nn.modelimport.keras.KerasModelImport;
import org.deeplearning4j.nn.multilayer.MultiLayerNetwork;
import org.nd4j.linalg.api.ndarray.INDArray;
import org.nd4j.linalg.factory.Nd4j;
import org.nd4j.linalg.io.ClassPathResource;**// load the model** String simpleMlp = new ClassPathResource(
"games.h5").getFile().getPath();
MultiLayerNetwork model = KerasModelImport.
importKerasSequentialModelAndWeights(simpleMlp);**// make a random sample** int inputs = 10;
INDArray features = Nd4j.zeros(inputs);
for (int i=0; i<inputs; i++)
features.putScalar(new int[] {i}, Math.random() < 0.5 ? 0 : 1);**// get the prediction** double prediction = model.output(features).getDouble(0);
使用 DL4J 时需要熟悉的一个关键概念是张量。Java 没有高效张量选项的内置库,这就是为什么 NDJ4 是先决条件。它提供了用 Java 实现深度学习后端的 N 维数组。要在张量对象中设置一个值,需要传递一个整数数组,该数组为张量提供一个 n 维索引,并提供要设置的值。因为我用的是 1D 张量,所以数组的长度是 1。
模型对象提供了预测和输出方法。predict 方法返回一个类预测(0 或 1),而 output 方法返回一个连续的标签,类似于 scikit-learn 中的 predict_proba 。
实时预测
现在我们已经有了一个用 Java 运行的 Keras 模型,我们可以开始为模型预测服务了。我们将采用的第一种方法是使用 Jetty 在 web 上设置一个端点来提供模型预测。我之前在关于跟踪数据和模型生产的帖子中提到过 Jetty 的设置。模型端点的完整代码可在这里获得。
模型端点被实现为加载 Keras 模型并提供预测的单个类。它实现 Jetty 的 AbstractHandler 接口来提供模型结果。下面的代码展示了如何设置 Jetty 服务在端口 8080 上运行,并实例化 JettyDL4J 类,该类在构造函数中加载 Keras 模型。
**// Setting up the web endpoint** Server server = new Server(8080);
server.setHandler(new JettyDL4J());
server.start();
server.join();**// Load the Keras model** public JettyDL4J() throws Exception {
String p=new ClassPathResource("games.h5").getFile().getPath();
model=KerasModelImport.importKerasSequentialModelAndWeights(p);
}
管理 web 请求的处理程序如下面的代码片段所示。传入的参数( G1,G2,…,G10 )被转换成 1D 张量对象,并传递给 Keras 模型的输出方法。然后,请求被标记为已处理,预测作为字符串返回。
**// Entry point for the model prediction request** public void handle(String target,Request baseRequest,
HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException { **// create a dataset from the input parameters** INDArray features = Nd4j.zeros(inputs);
for (int i=0; i<inputs; i++)
features.putScalar(new int[] {i}, Double.parseDouble(
baseRequest.getParameter("G" + (i + 1)))); **// output the estimate** double prediction = model.output(features).getDouble(0);
response.setStatus(HttpServletResponse.SC_OK);
response.getWriter().println("Prediction: " + prediction);
baseRequest.setHandled(true);
}
当您运行该类时,它会在端口 8080 上设置一个端点。您可以通过将浏览器指向以下 URL 来调用模型服务:
**// Request**[http://localhost:8080/?G1=1&G2=0&G3=1&G4=1&G5=0&G6=1&G7=0&G8=1&G9=1&G10=1](http://localhost:8080/?G1=1&G2=0&G3=1&G4=1&G5=0&G6=1&G7=0&G8=1&G9=1&G10=1)**// Result** Prediction: 0.735433042049408
结果是一个 Keras 模型,你现在可以实时调用它来从你的深度学习模型中获得预测。对于生产系统,您可能希望在 Jetty 端点前设置一个服务,而不是直接在 web 上公开端点。
批量预测
Keras 模型的另一个用例是批量预测,在这种情况下,您可能需要对数百万条记录应用估计量。您可以使用 Keras 模型在 Python 中直接实现这一点,但是这种方法的可伸缩性有限。我将展示如何使用 Google 的数据流,通过完全管理的管道将预测应用于海量数据集。我之前在关于模型制作和游戏模拟的帖子中提到过设置数据流。
使用数据流,您可以指定要在数据集上执行的操作的图形,其中源和目标数据集可以是关系数据库、消息服务、应用程序数据库和其他服务。这些图形可以作为批处理操作执行,其中基础架构启动以处理大型数据集,然后关闭;或者以流模式执行,其中维护基础架构并在请求到达时进行处理。在这两种情况下,服务将自动伸缩以满足需求。它经过全面管理,非常适合可以独立执行的大型计算。
DataFlow DAG for Batch Deep Learning
我的数据流流程中的 DAG 操作如上所示。第一步是为要评分的模型创建数据集。在本例中,我从示例 CSV 加载值,而实际上我通常使用 BigQuery 作为模型预测的源和同步。下一步是转换,将表行对象作为输入,将行转换为 1D 张量,将模型应用于每个张量,并使用预测值创建新的输出表行。DAG 的完整代码可在这里获得。
这个管道中的关键步骤是 Keras Predict 转换,如下面的代码片段所示。转换对对象集合进行操作,并返回对象集合。在转换器中,您可以定义诸如 Keras 模型之类的对象,这些对象在转换器中定义的每个流程元素步骤之间共享。结果是,模型为每个转换器加载一次,而不是为需要预测的每个记录加载一次。
**// Apply the transform to the pipeline** .apply("Keras Predict", new PTransform<PCollection<TableRow>,
PCollection<TableRow>>() { **// Load the model in the transformer** public PCollection<TableRow> expand(PCollection<TableRow> input) { final int inputs = 10;
final MultiLayerNetwork model;
try {
String p= newClassPathResource("games.h5").getFile().getPath();
model=KerasModelImport.importKerasSequentialModelAndWeights(p);
}
catch (Exception e) {
throw new RuntimeException(e);
} **// create a DoFn for applying the Keras model to instances** return input.apply("Pred",ParDo.of(new DoFn<TableRow,TableRow>(){
@ProcessElement
public void processElement(ProcessContext c) throws Exception {
**... // Apply the Keras model** }}));
}})
process element 方法的代码如下所示。它读取输入记录,从表行创建张量,应用模型,然后保存记录。输出行包含预测值和实际值。
**// get the record to score** TableRow row = c.element(); **// create the feature vector** INDArray features = Nd4j.zeros(inputs);
for (int i=0; i<inputs; i++)
features.putScalar(new int[] {i},
Double.parseDouble(row.get("G" + (i+1)).toString())); **// get the prediction** double estimate = model.output(features).getDouble(0); **// save the result** TableRow prediction = new TableRow();
prediction.set("actual", row.get("actual"));
prediction.set("predicted", estimate);
c.output(prediction);
我在本文中排除了 CSV 加载和 BigQuery 编写代码块,因为您可能使用不同的端点。如果你想试着运行 DAG,可以在 GitHub 上找到代码和 CSV。要将结果保存到 BigQuery,您需要如下设置 tempLocation 程序参数:
--tempLocation=gs://your-gs-bucket/temp-dataflow-location
运行 DAG 后,将在 BigQuery 中创建一个新表,其中包含数据集的实际值和预测值。下图显示了我应用 Keras 模型的样本数据点。
Prediction results in BigQuery
将数据流与 DL4J 结合使用的结果是,您可以使用批量预测的自动缩放基础设施对数百万条记录进行评分。
结论
随着深度学习越来越受欢迎,越来越多的语言和环境支持这些模型。随着库开始标准化模型格式,使用不同的语言进行模型训练和模型部署变得可能。这篇文章展示了使用 Python 中的 Keras 库训练的神经网络如何使用 Java 中的 DL4J 库进行批量和实时预测。我第一次能够建立一个批处理过程,将深度学习应用于数百万个数据点。
使用 TensorFlow 服务和 Flask 部署 Keras 模型
通常需要抽象出机器学习模型的细节,并将其部署或集成到易于使用的 API 端点中。例如,我们可以提供一个 URL 端点,任何人都可以使用它来发出 POST 请求,他们将获得模型推断的 JSON 响应,而不必担心它的技术细节。
在本教程中,我们将创建一个 TensorFlow 服务服务器来部署我们在 Keras 中构建的InceptionV3
图像分类卷积神经网络(CNN)。然后,我们将创建一个简单的 Flask 服务器,它将接受 POST 请求并进行 Tensorflow 服务服务器所需的一些图像预处理,然后返回一个 JSON 响应。
TensorFlow 提供的是什么?
服务就是你在训练完机器学习模型后如何应用它。
Know more about TensorFlow Serving here
TensorFlow 服务使模型投入生产的过程变得更加简单快捷。它允许您安全地部署新模型和运行实验,同时保持相同的服务器架构和 API。开箱即用,它提供了与 TensorFlow 的集成,但它可以扩展为服务于其他类型的模型。
安装 TensorFlow 服务
先决条件:请创建一个 python 虚拟环境,并在其中安装带有 TensorFlow 后端的 Keras。点击阅读更多。
*注意:*所有命令都已经在 Ubuntu 18.04.1 LTS 上的 python 虚拟环境中执行。
现在,在同一个虚拟环境中运行以下命令(使用sudo
获得 root 权限):
$ apt install curl$ echo "deb [arch=amd64] [http://storage.googleapis.com/tensorflow-serving-apt](http://storage.googleapis.com/tensorflow-serving-apt) stable tensorflow-model-server tensorflow-model-server-universal" | sudo tee /etc/apt/sources.list.d/tensorflow-serving.list && curl [https://storage.googleapis.com/tensorflow-serving-apt/tensorflow-serving.release.pub.gpg](https://storage.googleapis.com/tensorflow-serving-apt/tensorflow-serving.release.pub.gpg) | sudo apt-key add -$ apt-get update$ apt-get install tensorflow-model-server$ tensorflow_model_server --version
TensorFlow ModelServer: 1.10.0-dev
TensorFlow Library: 1.11.0$ python --version
Python 3.6.6
您可以通过以下方式升级到tensorflow-model-server
的新版本:
$ apt-get upgrade tensorflow-model-server
我们将要构建的目录概述
在我们开始之前,理解目录结构将有助于我们清楚地了解每一步的进展情况。
(tensorflow) ubuntu@Himanshu:~/Desktop/Medium/keras-and-tensorflow-serving$ tree -c
└── keras-and-tensorflow-serving
├── README.md
├── my_image_classifier
│ └── 1
│ ├── saved_model.pb
│ └── variables
│ ├── variables.data-00000-of-00001
│ └── variables.index
├── test_images
│ ├── car.jpg
│ └── car.png
├── flask_server
│ ├── app.py
│ ├── flask_sample_request.py
└── scripts
├── download_inceptionv3_model.py
├── inception.h5
├── auto_cmd.py
├── export_saved_model.py
├── imagenet_class_index.json
└── serving_sample_request.py6 directories, 15 files
您可以从我的 GitHub 存储库中获得所有这些文件:
[## himanshurawlani/keras-和-tensor flow-服务
使用 TensorFlow 服务和 Flask 部署 Keras 模型-himanshurawlani/Keras-and-tensor flow-Serving
github.com](https://github.com/himanshurawlani/keras-and-tensorflow-serving)
导出张量流服务的 Keras 模型
对于本教程,我们将下载和保存InceptionV3
CNN,使用download_inceptionv3_model.py
在 Keras 中使用 Imagenet 权重。您可以下载keras.applications
库中的任何其他可用模型(此处为),或者如果您已经在 Keras 中构建了自己的模型,则可以跳过这一步。
执行上述脚本后,您应该得到以下输出:
$ python download_inceptionv3_model.py
Using TensorFlow backend.
Downloading data from [https://github.com/fchollet/deep-learning-models/releases/download/v0.5/inception_v3_weights_tf_dim_ordering_tf_kernels.h5](https://github.com/fchollet/deep-learning-models/releases/download/v0.5/inception_v3_weights_tf_dim_ordering_tf_kernels.h5)
96116736/96112376 [==============================] - 161s 2us/step
现在我们有了以 Keras 格式保存的 CNN ( inception.h5
)。我们希望以 TensorFlow 服务器可以处理的格式导出我们的模型。我们通过执行export_saved_model.py
脚本来做到这一点。
TensorFlow 提供了SavedModel
格式作为导出模型的通用格式。在幕后,我们的 Keras 模型完全是根据 TensorFlow 对象指定的,因此我们可以使用 Tensorflow 方法很好地导出它。TensorFlow 提供了一个便利的函数tf.saved_model.simple_save()
,它抽象出了一些细节,对于大多数用例来说都很好。
输出:
$ python export_saved_model.py
WARNING:tensorflow:No training configuration found in save file: the model was *not* compiled. Compile it manually.
我们得到这个警告是因为我们下载了一个预先训练好的模型。我们可以按原样使用这个模型进行推理,但是如果我们想进一步训练它,我们需要在加载它之后运行compile()
函数。现在可以安全地忽略这个警告。执行该脚本后,以下文件保存在my_image_classifier
目录中:
├── my_image_classifier
└── 1
├── saved_model.pb
└── variables
├── variables.data-00000-of-00001
└── variables.index2 directories, 3 files
假设我们希望在未来更新我们的模型(可能是因为我们收集了更多的训练数据,并在更新的数据集上训练了模型),我们可以通过,
- 在新的 keras 模型上运行相同的脚本
- 将
export_saved_model.py
中的export_path = ‘../my_image_classifier/1’
更新为export_path = ‘../my_image_classifier/2’
TensorFlow Serving 会在my_image_classifier
目录下自动检测模型的新版本,并在服务器中进行更新。
启动 TensorFlow 服务服务器
要在本地计算机上启动 TensorFlow 服务服务器,请运行以下命令:
$ tensorflow_model_server --model_base_path=/home/ubuntu/Desktop/Medium/keras-and-tensorflow-serving/my_image_classifier --rest_api_port=9000 --model_name=ImageClassifier
--model_base_path
:这必须是一个绝对路径,否则你会得到一个错误消息:
Failed to start server. Error: Invalid argument: Expected model ImageClassifier to have an absolute path or URI; got base_path()=./my_image_classifier
--rest_api_port
: Tensorflow 服务将在端口 8500 上启动 gRPC ModelServer,REST API 将在端口 9000 上可用。--model_name
:这将是您用来发送 POST 请求的服务器的名称。您可以在此键入任何名称。
测试我们的 TensorFlow 服务器
From raw data to production models (Source)
serving_sample_request.py
脚本向 TensorFlow 服务服务器发出 POST 请求。输入图像通过命令行参数传递。
输出:
$ python serving_sample_request.py -i ../test_images/car.png
Using TensorFlow backend.
[["n04285008", "sports_car", 0.998414], ["n04037443", "racer", 0.00140099], ["n03459775", "grille", 0.000160794], ["n02974003", "car_wheel", 9.57862e-06], ["n03100240", "convertible", 6.01581e-06]]
与后续调用相比,TensorFlow 服务服务器响应第一个请求的时间稍长。
为什么我们需要 Flask 服务器?
正如我们所看到的,我们已经在serving_sample_request.py
(前端调用程序)中执行了一些图像预处理步骤。以下是在 TensorFlow 服务器上创建 Flask 服务器的原因:
- 当我们向前端团队提供 API 端点时,我们需要确保我们不会用预处理技术淹没他们。
- 我们可能并不总是有 Python 后端服务器(例如 Node.js 服务器),所以使用 numpy 和 keras 库进行预处理可能会很痛苦。
- 如果我们计划服务多个模型,那么我们将不得不创建多个 TensorFlow 服务服务器,并将不得不添加新的 URL 到我们的前端代码。但是我们的 Flask 服务器会保持域名 URL 不变,我们只需要添加一个新的路由(一个函数)。
- 提供基于订阅的访问,异常处理和其他任务可以在 Flask app 中进行。
我们正在努力消除 TensorFlow 服务服务器和我们前端之间的紧密耦合。
Multiple TensorFlow Serving servers hidden behind a Flask server
在本教程中,我们将在与 TensorFlow 服务器相同的计算机和虚拟环境中创建一个 Flask 服务器,并使用已安装的库。理想情况下,两者都应该在不同的机器上运行,因为大量的请求会导致 Flask 服务器由于正在执行图像预处理而变慢。此外,如果请求数量非常多,单个 Flask 服务器可能不够用。如果我们有多个前端调用者,我们可能还需要一个排队系统。尽管如此,我们可以使用这种方法来开发一个令人满意的概念证明。
创建 Flask 服务器
先决条件:从这里在 python 虚拟环境中安装 Flask。
我们只需要一个app.py
文件来创建我们的 Flask 服务器。
转到保存app.py
文件的目录,使用以下命令启动 Flask 服务器:
$ export FLASK_ENV=development && flask run --host=0.0.0.0
FLASK_ENV=development
:这启用了调试模式,基本上给你完整的错误日志。不要在生产环境中使用它。flask run
命令自动执行当前目录下的app.py
文件。--host=0.0.0.0
:这使您能够从任何其他机器向 Flask 服务器发出请求。要从不同的机器发出请求,您必须指定运行 Flask 服务器的机器的 IP 地址来代替localhost
。
输出:
* Running on [http://0.0.0.0:5000/](http://0.0.0.0:5000/) (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger PIN: 1xx-xxx-xx4
Using TensorFlow backend.
使用前面相同的命令启动 TensorFlow 服务器:
$ tensorflow_model_server --model_base_path=/home/ubuntu/Desktop/Medium/keras-and-tensorflow-serving/my_image_classifier --rest_api_port=9000 --model_name=ImageClassifier
这里有一个脚本(auto_cmd.py
)来自动启动和停止两个服务器(TensorFlow Serving 和 Flask)。您也可以为两台以上的服务器修改该脚本。
记得在auto_cmd.py
的行第 10 处更改路径,使其指向您的app.py
目录。你可能还需要修改第 6 行以使它指向你的虚拟环境的 bin。然后,通过在终端中执行以下命令,您可以从任何目录执行上述脚本:
$ python auto_cmd.py
测试我们的 Flask 服务器和 TensorFlow 服务器
我们使用flask_sample_request.py
脚本制作一个示例请求。该脚本基本上模拟了来自前端的请求:
- 我们获取一个输入图像,将其编码为 base64 格式,并使用 POST 请求将其发送到我们的 Flask 服务器。
- Flask server 对这个 base64 图像进行解码,并为我们的 TensorFlow 服务器进行预处理。
- 然后,Flask server 向我们的 TensorFlow 服务服务器发出 POST 请求,并对响应进行解码。
- 解码后的响应被格式化并发送回前端。
输出:
$ python flask_sample_request.py -i ../test_images/car.png
[
[
"n04285008",
"sports_car",
0.998414
],
[
"n04037443",
"racer",
0.00140099
],
[
"n03459775",
"grille",
0.000160794
],
[
"n02974003",
"car_wheel",
9.57862e-06
],
[
"n03100240",
"convertible",
6.01581e-06
]
]
我们的 flask 服务器目前只有一条路由用于我们的单个 Tensorflow 服务服务器。我们可以通过在不同或相同的机器上创建多个 Tensorflow 服务服务器来服务多个模型。为此,我们只需向我们的app.py
文件中添加更多的路线(功能),并在其中执行所需的特定于模型的预处理。我们可以将这些路线交给我们的前端团队,以便根据需要调用模型。
处理跨源 HTTP 请求
考虑这样一个场景,我们使用 Angular 发出一个 POST 请求,我们的 Flask 服务器收到 OPTIONS header 而不是 POST,因为,
- 当 web 应用程序请求来源(域、协议和端口)不同于其自身来源的资源时,它会发出跨来源 HTTP 请求。
- CORS(跨源资源共享)是一种机制,它使用额外的 HTTP 报头来告诉浏览器,让在一个源(域)上运行的 web 应用程序有权访问来自不同源的服务器的选定资源。在这里阅读更多关于 CORS 的信息。
因此,Angular 没有从 Flask 服务器得到任何响应。为了解决这个问题,我们必须在我们的app.py
中启用弗拉斯克-CORS。了解更多这里。
结论
这就是我们服务于机器学习模型所需要的一切。TensorFlow 服务使得将机器学习集成到网站和其他应用程序中变得非常容易。keras 中有大量预构建的模型可用(此处),有可能用最少的机器学习和深度学习算法知识开发出超级有用的应用。
如果你觉得这个教程有帮助,请分享给你的朋友,并留下掌声:-)。如果你有任何疑问、反馈或建议,请在评论中告诉我。另外,你可以在推特和 T2【LinkedIn】和我联系。有太多的东西要与你们分享,而我才刚刚开始。敬请关注更多内容!