Press "Enter" to skip to content

如何用Flask部署Keras深度学习模型

此前我们在一篇回答中分享了机器/深度学习模型的部署指南,全面概述了从头部署机器/深度学习模型的整个过程。今天就具体说说如何用 Flask 部署由 Keras 创建的深度学习模型。
本文我(作者Ben Weber——译者注)会展示如何使用 Keras 构建的深度学习模型设置端点来提供预测。首先介绍一个使用 Flask 和 Python 设置端点的示例,然后展示在使用 Flask 构建 Keras 端点以进行预测时要解决的一些问题。
将深度学习模型产品化是很有挑战性,主要有以下原因:

  • 模型序列化:用于序列化模型的标准方法(例如 PMML)仅提供有限的支持。例如, keras2pmml 缺少 relu 激活函数,这意味着一些方法比如 DataFlow + PMML 是不可行的。
  • 大型程序库:使用 AWS lambda 函数来托管 scikit-learn 模型的方法,对 Keras 来就成了问题,因为未压缩的 Keras 和 Tensorflow 库超过了 AWS lambda 的 256MB 文件上传限制。
  • 运行时间:如果大部分模型预测都是用 Java 写的,那么批量和实时预测都很难扩展。此前有篇文章提到使用 Jetty 提供实时估算,以及使用 Google 的 DataFlow 进行批量估算。本文会展示当你需要使用 Python 库进行估算时,如何使用 Flask 代替 Jetty。

本文的目的是为大家展示如何用 AWS 将 Keras 模型设置为 EC2 实例上的端点。
文中也会讨论一些问题,包括在用 Keras 使用模型持久性时如何处理自定义指标,在将 Keras 与 Flask 结合使用时怎样处理多线程问题,以及在 EC2 实例上运行全部线程。本文全部代码可在 GitHub 上获取,地址见文末。
文章会介绍如何设置一个简单的 Flask 应用程序,然后展示用 Flask 为 Keras 模型设置一个端点。这里假设大家对 EC2 实例和 Jupyter 有所了解,如果不熟悉,可以参考这篇文章
Flask 简介
Flask 是一个 Python 库,可以轻松设置能通过 Web 调用的 Python 函数。它使用注释来提供关于在哪些端点设置哪些功能的元数据。要使用 Flask,首先需要安装模块:

pip3 install --user Flask

为了帮大家熟悉 Flask,我们会设置一个简单的函数来回显传入的参数。下面的代码片段首先实例化 Flask 应用程序,定义函数,然后启动应用程序。在 Flask 中,app.route 注释用于指定在 Web 上使用函数的位置以及允许的方法。使用下面的代码,就可以在 5000 / predict 这个位置使用函数。该函数会检查 request.json 和 request.args 对象的输入参数,根据函数的调用方式(例如浏览器获取 vs cURL POST)使用这些参数。如果已将 msg 参数传递给函数,则将其回显到函数返回的 JSON 响应中。

# 加载Flask
import flask
app = flask.Flask(__name__)
# 将一个预测函数定义为一个端点
@app.route("/predict", methods=["GET","POST"])
def predict():
    data = {"success": False}
    # 获取请求参数
    params = flask.request.json
    if (params == None):
        params = flask.request.args
    # 若获得参数,则回显msg 参数
    if (params != None):
        data["response"] = params.get("msg")
        data["success"] = True
    # 返回一个 json 格式的响应
    return flask.jsonify(data)
# 开启Flask应用程序,运行远程连接
app.run(host='0.0.0.0')

运行 python3 Flask_Echo.py,会得到如下结果:

* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

现在可以连接函数来测试结果。我们将 host=’0.0.0.0′ 包含在内,目的是实现远程连接,因为 Flask 应用程序是在 EC2 实例上运行的。如果你在用 EC2,需要调整安全组从而能在端口 5000 上访问 Flask,这和让 Jupyter 在端口 8888 上访问是一样的。

图:EC2的入站规则
可以用 Web 浏览器或 cURL 调用该函数。这里在 Windows 环境中使用 cURL,也可以使用 -d ‘{“msg”:”Hello World”}’ 。两种方法的结果相同,来自客户端的 JSON 响应会重复传入的 msg 参数。

# 浏览器
http://54.227.110.43:5000/predict?msg=HelloWorld
# cURL
>curl -X POST -H "Content-Type: application/json" -d "{ \"msg\":
\"Hello World\" }" http://54.227.110.43:5000/predict
# 响应
{
  "response": "Hello World",
  "success": true
}

我们现在能够将 Python 函数设置为 Web 端点,下一步是让函数调用训练好的深层网络。
Flask&Keras
要使用 Keras 进行深度学习,我们首先需要使用 Keras 和 Tensorflow 库设置环境,然后训练一个模型,我们会通过 Flask 在 web 上显示该模型。

# 深度学习设置
pip3 install --user tensorflow
pip3 install --user keras
pip3 install --user  pandas

如果使用的是没有配置 GPU 的 EC2 实例,那么在 CPU 模式下运行 Keras 无需额外配置。
模型训练
我们使用简单的网络结构创建一个二元分类器。模型的输入是特征数组,描述了用户先前玩过哪些游戏,模型的输出是玩家将来玩特定游戏的概率。关于模型训练的信息这里暂且不表我们的重点是部署模型。

# 导入panda,keras 和tensorflow
import pandas as pd
import tensorflow as tf
import keras
from keras import models, layers
# 加载样本数据集,划分为x和y DataFrame
df = pd.read_csv("https://github.com/bgweber/Twitch/raw/
                      master/Recommendations/games-expand.csv")
x = df.drop(['label'], axis=1)
y = df['label']
# 定义Keras模型
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'))
# 使用自定义度量函数
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
# 编译并拟合模型
model.compile(optimizer='rmsprop',loss='binary_crossentropy',
              metrics=[auc])
history = model.fit(x, y, epochs=100, batch_size=100,
                    validation_split = .2, verbose=0)
# 以H5格式保存模型
model.save("games.h5")

上述代码片段定义了自定义度量函数,该函数用于训练模型对 ROC AUC 指标进行优化。此代码的主要附加功能是最后一步,它将模型序列化为 H5 格式。我们稍后可以在 Flask 应用程序中加载此模型以提供模型预测。可以通过运行生成 games.h5 的 python3 Flask_Train.py 来训练模型。
模型部署
现在我们已经设置好了环境,也训练了深度学习模型,接下来可以使用 Flask 来生产 Keras 模型。用于模型预测的完整代码如下所示。代码的整体结构与前面的代码示例相同,但主要区别在于定义预测函数之前先加载模型,并在预测函数中使用模型。要想重新加载模型,我们需要使用 custom_objects 参数将自定义度量函数作为输入参数传递给 load_model。

# 加载库
import flask
import pandas as pd
import tensorflow as tf
import keras
from keras.models import load_model
# 实例化 flask
app = flask.Flask(__name__)
# 我们需要重新定义我们的度量函数,
# 从而在加载模型时使用它
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
# 加载模型,传入自定义度量函数
global graph
graph = tf.get_default_graph()
model = load_model('games.h5', custom_objects={'auc': auc})
# 将预测函数定义为一个端点
@app.route("/predict", methods=["GET","POST"])
def predict():
    data = {"success": False}
    params = flask.request.json
    if (params == None):
        params = flask.request.args
    # 若发现参数,则返回预测值
    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
    # 返回Jason格式的响应
    return flask.jsonify(data)
# 启动Flask应用程序,允许远程连接
app.run(host='0.0.0.0')

使用 tf.get_default_graph()为 TensorFlow 计算图设置一个引用同样必要。如果忽略了这一步,在预测步骤期间可能会发生异常。条件 with graph.as_default()用于在进行预测时获取计算图的线程安全引用。在预测函数中,请求参数被转换为 DataFrame,然后传递给 Keras 模型以进行预测。
可以通过运行 python3 Flask_Deploy.py 来部署 Flask 应用程序。也可以像前面一样连接到应用程序,但是需要指定属性 G1 到 G10 的值。这里使用浏览器测试端点,会得到以下结果:

# 浏览器
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
# 响应
{
 "prediction":"0.04930059",
 "success":true}
}

这样我们获得了一个可以在 web 上提供 Keras 预测的 EC2 实例!
结语
部署深度学习模型并非易事,因为你需要使用支持 TensorFlow 运行时的环境。本文展示了如何使用 Flask 通过预先训练的模型来提供预测。这种方法虽不像 AWS lambda 方法那样可以扩展,但可能更适合你的实际用途。Flask 在原型设计时也可用于设置本地服务。
理想情况下,我们希望能够将 Flask 中的注释与 AWS lambda 的可伸缩性相结合,省去将库安装到目录并上传结果这个中间步骤。AWS SageMaker 能帮我们实现这个目标,未来我们会接着探索这个工具,大家自己也可以试试。

参考资料:
towardsdatascience.com/

Be First to Comment

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注