37

将深度学习模型部署为web应用有多难?答案自己找

 5 years ago
source link: https://www.jiqizhixin.com/articles/2018-12-07-9?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

本文将教你如何把训练好的 Keras深度学习模型部署为 web 应用程序。虽然这涉及很多技术,但你真的不要试试吗?

虽然创建一个机器学习项目很酷,但你最终往往还是希望其他人能够看到自己的成果。当然,你可以将整个项目放在 GitHub 上,但是,你的祖父母估计很难看明白。因此,我们想要做的是,将 深度学习 模型部署成一个任何人都可以访问的 web 应用程序。

在本文中,你将了解如何编写 web 应用程序,该程序采用训练好的 Keras 循环神经网络并允许用户生成新的专利摘要。本文的项目是基于以下示例文章中的 循环神经网络 研究,但我们没有必要弄清楚如何创建此类循环神经网络。现在我们只需将其当成黑箱模型:输入开始序列,它会输出全新的专利摘要,而我们可以在浏览器中显示出来!

示例地址:https://medium.com/p/ffd204f99470?source=user_profile---------6------------------

传统来说,一般由数据科学家负责开发模型,而前端工程师负责把模型向外界展示。在本项目中,我们将同时扮演这两个角色,并深入解读 web 应用的开发过程(尽管几乎都是用 Python 编写的)。

本项目将涉及以下多个主题:

  • Flask:在 Python 环境下创建一个基础的 web 应用

  • Keras:部署一个训练好的循环神经网络模型

  • 使用 Jinja 模板库创建模板

  • 使用 HTML 和 CCS 编写 web 网页

最终我们将得到一个 web 应用程序,它允许用户使用训练好的循环神经网络生成全新的专利摘要:

2eEBRzA.png!web

完整项目代码可以通过以下地址获得:

https://github.com/WillKoehrsen/recurrent-neural-networks

方法

本项目旨在快速创建并运行一个 web 应用程序。为此,我选择了 Flask 框架,它允许我们用 Python 编写应用程序。我不喜欢杂乱的应用样式,所以几乎所有的 CSS 都是复制粘贴过来的。以下两篇文章对了解这方面的基础知识比较有用,还能提供不错的指南:

  • https://towardsdatascience.com/deploying-keras-deep- learningmodel -with-flask-5da4181436a2

  • https://towardsdatascience.com/deploying-keras-deep-learning-models-with-flask-5da4181436a2

总的来说,这个项目遵循了我的设计原则:快速地建立并运行一个原型——尽量选择复制和粘贴——然后通过不断迭代做出更好的产品。

使用 Flask 实现一个基础的 web 应用

在 Python 环境下构建一个 web 应用,最快捷的方式就是使用 Flask。我们可以通过以下方式来制作自己的 web 应用程序:

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 应用程序。当然,我们当然还想在 web 应用中做更多的事,所以我们将使用一个稍微复杂一点的函数,它的基本功能是一样的:处理来自浏览器的请求并以 HTML 的形式提供一些内容。在主页中,我们会向用户提供一个表单让他们可以输入一些详细信息。

用户输入的表单

当用户打开应用程序主页后,我们将向他们展示一个带有 3 个可选参数的表单:

  1. 输入 RNN 的起始序列或由服务器随机选择一个序列

  2. 选择 RNN 预测的多样性

  3. 选择 RNN 输出的单词数

我们将使用「wtforms」在 Python 环境下建立一个表单。构建表单的代码如下:

from wtforms import (Form, TextField, validators, SubmitField, 
DecimalField, IntegerField)

class ReusableForm(Form):
    """User entry form for entering specifics for generation"""
    # Starting seed
    seed = TextField("Enter a seed string or 'random':", validators=[
                     validators.InputRequired()])
    # Diversity of predictions
    diversity = DecimalField('Enter diversity:', default=0.8,
                             validators=[validators.InputRequired(),
                                         validators.NumberRange(min=0.5, max=5.0,
                                         message='Diversity must be between 0.5 and 5.')])
    # Number of words
    words = IntegerField('Enter number of words to generate:',
                         default=50, validators=[validators.InputRequired(),
                                                 validators.NumberRange(min=10, max=100, 
                                                 message='Number of words must be between 10 and 100')])
    # Submit button
    submit = SubmitField("Enter")

这将创建下图所示的表单(采用了「main.css」的样式):

UVNba2b.png!web

代码中的「validator」确保用户输入了正确的信息。例如,我们会检查所有的复选框是否都已填充,并且检查「diversity」的值是否介于 0.5 到 5 之间。只有满足这些要求的表单才能被接受。

VRjMn2B.png!web

验证错误

我们实际上是通过 Flask 模板提供这些表单的。

模板

模板是一个带有基本框架的文档,我们需要填充其中的一些细节。对于 Flask web 应用程序,我们可以使用 Jinja 模板库将 Python 代码嵌入到 HTML 文档中。例如,在主函数中,我们将把表单的内容发送到一个名为「index.html」的模板中。

from flask import render_template

# Home page
@app.route("/", methods=['GET', 'POST'])
def home():
    """Home page of app with form"""
    # Create form
    form = ReusableForm(request.form)

    # Send template information to index.html
    return render_template('index.html', form=form)

当用户打开主页时,我们的应用程序将使用「form」表单中的详细信息开启一个基于「index.html」模板的页面。这个模板是一个简单的 html 脚手架,在这里我们使用 {{variable}} 语法引用 python 变量。

<!DOCTYPE html> <html> <head>   <title>RNN Patent Writing</title>   <link rel="stylesheet" href="/static/css/main.css">   <link rel="shortcut icon" href="/static/images/lstm.ico"> </head> <body>   <div class="container">     <h1>       <center>Writing Novel Patent Abstracts with Recurrent Neural Networks</center>     </h1>     {% block content %}     {% for message in form.seed.errors %}     <div class="flash">{{ message }}</div>     {% endfor %}     {% for message in form.diversity.errors %}     <div class="flash">{{ message }}</div>     {% endfor %}     {% for message in form.words.errors %}     <div class="flash">{{ message }}</div>     {% endfor %}     <form method=post>       {{ form.seed.label }}       {{ form.seed }}       {{ form.diversity.label }}       {{ form.diversity }}       {{ form.words.label }}       {{ form.words }}       {{ form.submit }}     </form>     {% endblock %}   </div> </body> </html>

表单中的每个错误(那些无法通过验证的条目)将会触发一个错误信息「flash」。如果没有错误,此文件将显示如上所示的表单。

当用户输入信息并点击提交表单(POST 请求)时,如果信息是正确的,我们会将输入传递给适当的函数并用训练好的 RNN 进行预测。这意味着我们需要修改「home()」方法。

from flask import request
# User defined utility functions
from utils import generate_random_start, generate_from_seed

# Home page
@app.route("/", methods=['GET', 'POST'])
def home():
    """Home page of app with form"""

    # Create form
    form = ReusableForm(request.form)

    # On form entry and all conditions met
    if request.method == 'POST' and form.validate():
        # Extract information
        seed = request.form['seed']
        diversity = float(request.form['diversity'])
        words = int(request.form['words'])
        # Generate a random sequence
        if seed == 'random':
            return render_template('random.html', 
                                   input=generate_random_start(model=model, 
                                                               graph=graph, 
                                                               new_words=words, 
                                                               diversity=diversity))
        # Generate starting from a seed sequence
        else:
            return render_template('seeded.html', 
                                   input=generate_from_seed(model=model, 
                                                            graph=graph, 
                                                            seed=seed, 
                                                            new_words=words, 
                                                            diversity=diversity))
    # Send template information to index.html
    return render_template('index.html', form=form)

现在,当用户单击提交按钮「submit」且信息正确时,web 将根据第一个文本框中的输入信息选择将输入的表单发送到「generate_random_start」或「generate_from_seed」。这些函数使用训练好的 Keras 模型生成符合用户指定的多样性和单词数的新专利摘要。这些函数的输出会被依次传给模板「random.html」或「seeded.html」来启动新的 web 页面。

使用预训练的 Keras 模型做预测

参数「model」将指定使用哪个训练好的 Keras 模型,代码如下:

from keras.models import load_model
import tensorflow as tf

def load_keras_model():
    """Load in the pre-trained model"""
    global model
    model = load_model('../models/train-embeddings-rnn.h5')
    # Required for model to work
    global graph
    graph = tf.get_default_graph()

load_keras_model()

(「tf.get_default_graph()」是基于下面的 github gist 采取的一种解决方案:https://gist.github.com/eyesonlyhack/2f0b20f1e73aaf5e9b83f49415f3601a

在这里,我们不会完整地展示这两个「util」函数,你要知道的是,它们使用训练好的 Keras 模型以及相应的参数,并对一个新的专利摘要进行预测。

完整代码见:https://github.com/willkoehrsen/recurent -neural-networks/blob/master/deployment/utils.py

这些函数都返回带有格式化的 HTML 的 Python 字符串。该字符串将被传递给另一个模板,作为 web 页面呈现出来。例如,「generate_random_start」返回的格式化的 html 会带用户跳转到 random.html:

<!DOCTYPE html> <html> <header>     <title>Random Starting Abstract     </title>     <link rel="stylesheet" href="/static/css/main.css">     <link rel="shortcut icon" href="/static/images/lstm.ico">     <ul>         <li><a href="/">Home</a></li>     </ul> </header> <body>     <div class="container">         {% block content %}         {{input|safe}}         {% endblock %}     </div> </body> </html>

在这里,我们再次使用 Jinja 模板引擎来显示格式化的 HTML。由于 Python 字符串已经被格式化为 HTML,我们所要做的就是使用 {{input|safe}}(其中 input 是 Python 变量)来显示它。接着,我们就可以使用「main.css」对这个页面进行样式化了,使用方法就像使用其它 html 模板一样。

输出

「generate_random_start」函数将会选择一个随机的专利摘要作为起始的输入序列,并且根据它做出预测。接着,它会显示出这个起始的输入序列。循环神经网络会产生输出,真实的输出结果如下:

eeiaUzj.png!web

使用随机初始序列得到的输出。

「generate_from_seed」函数使用用户提供的初始序列,然后会使用训练好的循环神经网络作出预测、构建输出。输出的结果如下:

FBrEZfu.png!web

使用指定的初始序列得到的输出。

虽然结果并不总是完全正确,但它们确实表明循环神经网络已经掌握了英语基础。模型经过训练学会了根据前 50 个单词来预测下一个单词,并学会了如何写出一个还不错的专利摘要!根据预测的多样性「diversity」,输出可能完全是随机的或循环的。

运行应用程序

你只需下载代码仓库,转向「deployment」目录并输入「python run_keras_server.py」就可以运行该应用程序了。你可以立刻在地址 localhost:10000 上使用这个 web 应用程序。

你可以根据家庭 WiFi 的配置情况,使用你的 IP 地址从网络上的任何计算机访问该应用程序。

下一步的工作

在个人电脑上运行的 web 应用程序非常适合与朋友和家人共享。不过,我不建议在你的家庭网络中向所有人开放这个网站!为此,我们将在AWSEC2 实例上装载该应用程序,并将其开放(稍后将提供)。

如果你想要改进这个应用程序,可以改变样式(通过 main.css),也许还可以添加更多选项,比如可以选择预训练好的网络。制作个人项目的好处是,你可以随心所欲地去做你想做的事。如果你想试着玩一玩这个应用程序,你可以通过下面的链接下载代码,然后开始你的实验。

链接:https://github.com/willkoehrsen/recursive - neur- networks

ErmeIjz.png!web

结语

在本文中,我们看到了如何将训练好的 Keras深度学习模型部署为 web 应用程序。这需要将许多不同的技术组合在一起,包括循环神经网络、web 应用程序、模板、HTML、CSS,当然还有 Python。

虽然这只是一个基础的应用程序,但它表明你可以在付出相对较少努力的情况下使用深度学习来构建 web 应用程序。目前,还没有多少人敢说他们能将一个深度学习部署为一个 web 应用,如果你遵照这本文的方法进行实验,那你就能成为少数掌握这项技能的开发者之一啦!

原文链接:https://towardsdatascience.com/deploying-a-keras-deep-learning-model-as-a-web-application-in-p-fc0f2354a7ff


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK