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

2018 年 12 月 7 日 全球人工智能

作者:William Koehrsen

来源:towardsdatascience,机器之心

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


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


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


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


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


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

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

  • 使用 Jinja 模板库创建模板

  • 使用 HTML 和 CCS 编写 web 网页


最终我们将得到一个 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」的样式):



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


验证错误


我们实际上是通过 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」函数将会选择一个随机的专利摘要作为起始的输入序列,并且根据它做出预测。接着,它会显示出这个起始的输入序列。循环神经网络会产生输出,真实的输出结果如下:


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


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


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


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


运行应用程序


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

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


下一步的工作


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


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


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



结语


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


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


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

广告 & 商务合作请加微信:kellyhyw    

投稿请发送至:mary.hu@aisdk.com

登录查看更多
3

相关内容

Flask is a microframework for Python based on Werkzeug, Jinja 2 and good intentions. And before you ask: It's BSD licensed! flask.pocoo.org/
专知会员服务
54+阅读 · 2020年7月4日
【实用书】Python机器学习Scikit-Learn应用指南,247页pdf
专知会员服务
266+阅读 · 2020年6月10日
干净的数据:数据清洗入门与实践,204页pdf
专知会员服务
161+阅读 · 2020年5月14日
【深度学习】深度学习的问题究竟在哪?
产业智能官
4+阅读 · 2019年8月30日
用Now轻松部署无服务器Node应用程序
前端之巅
16+阅读 · 2019年6月19日
VS Code Remote发布!真·远程开发
开源中国
6+阅读 · 2019年5月3日
深度学习开发必备开源框架
九章算法
12+阅读 · 2018年5月30日
如何运用Python建一个聊天机器人?
七月在线实验室
17+阅读 · 2018年1月23日
教程帖:深度学习模型的部署
论智
8+阅读 · 2018年1月20日
【迁移学习】简述迁移学习在深度学习中的应用
产业智能官
15+阅读 · 2018年1月9日
迁移学习在深度学习中的应用
专知
23+阅读 · 2017年12月24日
Arxiv
14+阅读 · 2020年1月27日
Arxiv
13+阅读 · 2019年1月26日
Music Transformer
Arxiv
5+阅读 · 2018年12月12日
VIP会员
相关资讯
【深度学习】深度学习的问题究竟在哪?
产业智能官
4+阅读 · 2019年8月30日
用Now轻松部署无服务器Node应用程序
前端之巅
16+阅读 · 2019年6月19日
VS Code Remote发布!真·远程开发
开源中国
6+阅读 · 2019年5月3日
深度学习开发必备开源框架
九章算法
12+阅读 · 2018年5月30日
如何运用Python建一个聊天机器人?
七月在线实验室
17+阅读 · 2018年1月23日
教程帖:深度学习模型的部署
论智
8+阅读 · 2018年1月20日
【迁移学习】简述迁移学习在深度学习中的应用
产业智能官
15+阅读 · 2018年1月9日
迁移学习在深度学习中的应用
专知
23+阅读 · 2017年12月24日
Top
微信扫码咨询专知VIP会员