Перевод статьи подготовлен специально для студентов курса «Web-разработчик на Python».




Создать классный проект с машинным обучением – это одно дело, другое дело, когда вам нужно, чтобы другие люди тоже смогли его увидеть. Конечно, вы можете положить весь проект на GitHub, но как ваши бабушка с дедушкой поймут, что вы сделали? Нет, нам нужно развернуть нашу модель глубокого обучения в виде веб-приложения, которое будет доступно любому человеку в мире.

В этой статье мы узнаем, как написать веб-приложение, которое использует обученную рекуррентную нейронную сеть Keras и позволяет пользователям создавать новые патентные аннотации. Этот проект основан на работе из статьи «Recurrent Neural Networks by Example», однако знать, как строится RNN сейчас совсем не обязательно. На данный момент мы просто будем рассматривать ее как черный ящик: мы задаем начальную последовательность, и она выводит совершенно новую аннотацию к патенту, которую можно просмотреть в браузере!

Обычно специалисты по анализу данных разрабатывают модели, а фронтендеры показывают их миру. В этом проекте нам придется сыграть обе роли и погрузиться в веб-разработку (хотя и почти полностью на Python).

Этот проект потребует объединения нескольких инструментов:

  • Flask: для создания базового веб-приложения на Python;
  • Keras: развертывание предобученной рекуррентной нейронной сети;
  • Шаблоны из шаблонизатора Jinja;
  • HTML и CSS для создания веб-страниц.

В конечном итоге мы получим веб-приложение, которое позволит пользователям создавать совершенно новые патентные аннотации с помощью обученной рекуррентной нейронной сети.



Весь код проекта доступен на GitHub.

Подход


Целью было развернуть веб-приложение как можно быстрее. Для этого я выбрал Flask, который позволяет писать приложения на Python. Я не люблю возиться со стилями (думаю, вы уже увидели), поэтому почти весь CSS я копирую и вставляю из сторонних источников. Эта статья от команды Keras была полезна для изучения основ, также эта статья является полезным руководством.
В целом этот проект отвечает моим принципам проектирования: создать прототип, который работает быстро (копируя и вставляя столько кода, сколько нужно), а затем просто повторять то же самое, чтобы улучшать продукт.

Базовое веб-приложение на Flask


Самый быстрый способ создать веб-приложение на Python — это использовать Flask (http://flask.pocoo.org/). Чтобы создать наше собственное приложение, мы можем использовать следующее:

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. Конечно, нам нужно нечто большее, поэтому мы будем использовать более сложную функцию, которая в целом делает то же самое: обрабатывает запросы из вашего браузера и обслуживает некоторый контент в виде HTML.

Форма ввода для пользователя


Когда пользователи будут переходить на главную страницу приложения, мы будем показывать им форму с тремя опциями:

  1. Ввод исходной последовательности для RNN или ее генерация случайным образом.
  2. Выбор «разнообразия» прогнозов RNN.
  3. Выбор количества слов на выходе из RNN.

Чтобы создать форму на Python мы используем wtforms. Код для ее создания вы увидите ниже:

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):



Проверка в коде нужна, чтобы убедиться, что пользователь вводит корректную информацию. Например, мы проверяем, что все поля заполнены, и что значение параметра diversity находится между 0.5 и 5. Эти условия должны быть выполнены, чтобы начать работу.


Ошибка при проверке корректности введенных данных

Мы обрабатываем эту форму с помощью шаблонов на Flask.

Шаблоны


Шаблон – это файл с уже готовым «каркасом», который просто нужно заполнить определенным образом. Для веб-приложения на Flask мы можем использовать библиотеку шаблонов 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)

Когда пользователь перейдет на главную страницу, наше приложение обеспечит index.html входными данными из формы. Шаблон представляет собой полноценную структуру HTML, в которой мы ссылаемся на переменные Python с помощью синтаксиса {{variable}}.

<!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>

При появлении ошибки в форме (входные данные, которые не могут быть проверены) будет мигать сообщение об ошибке. Помимо этого, форма будет отображаться как в файле выше.

Когда пользователь вводит информацию и нажимает submit (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 и введенная информация оказывается корректной, в зависимости от входных данных ввод отправляется либо в generate_random_start, либо в generate_from_seed. Эти функции используют обученную модель Keras, чтобы создать новый патент с параметрами diversity и num_words, заданными пользователем. Выходные данные этой функции, в свою очередь, отправляются случайным образом в шаблоны random.html или seeded.html, чтобы отобразиться в виде веб-страницы.

Создание прогнозов с помощью предобученной модели 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())
Я не буду показывать полностью две функции util (код вы найдете здесь), ведь все, что вам нужно понять это то, что они хранят уже обученную модель Keras вместе с параметрами и делают прогнозы – патентные аннотации.

Обе эти функции возвращают строку на Python с отформатированным HTML. Эта строка отправляется в другой шаблон, который отобразится в виде веб-страницы. Например, 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>

Здесь мы снова используем шаблонизатор Jinja для отображения отформатированного HTML-файла. Поскольку строка на Python уже транслирована в HTML, все, что нам нужно сделать для ее отображения, это использовать {{input|safe}} (где input — это переменная Python). Затем в main.css мы можем добавить стили этой странице, впрочем, как и другим HTML-страницам.

Результат работы


Функция generate_random_start выбирает случайную аннотацию патента в качестве входной последовательности и строит прогнозы, основываясь на ней. Затем она отображает входную последовательность, сгенерированные RNN выходные данные и фактические выходные данные:


Выходные данные на основе случайной входной последовательности.

Функция generate_from_seed принимает введенную пользователем начальную последовательность и строит прогнозы, основываясь на ней. Выходные данные выглядят следующим образом:


Выходные данные на основе пользовательской входной последовательности.

Несмотря на то, что результаты не всегда образуют логические последовательности, тем не менее они показывают, что нейронная сеть знакома с основами английского языка. Она была обучена прогнозировать каждое следующее слово на основе предыдущих 50 и подбирать тем самым убедительную аннотацию. В зависимости от параметра diversity выходные данные могут оказаться полностью случайными или циклическими.

Запуск приложения


Чтобы запустить приложение для себя, все, что вам нужно сделать, это загрузить репозиторий, перейти в каталог, где происходит развертывание и ввести run_keras_server.py. Приложение будет доступно по адресу localhost:10000.

В зависимости от того, как настроен ваш домашний Wi-Fi, вы должны иметь возможность получить доступ к приложению с любого компьютера в сети, используя свой IP-адрес.

Следующие шаги


Веб-приложение, запущенное на вашем персональном компьютере, отлично подойдет для совместного использования с друзьями и семьей. Однако я определенно не рекомендую открывать его для всех в вашей домашней сети. Позже мы с вами научимся разворачивать приложение на AWS EC2 и покажем наконец-то его миру.

Чтобы улучшить приложение, можно поменять стили (в main.css) и, возможно, добавить дополнительные параметры, такие как возможность выбора предварительно обученной сети. Самое замечательное в личных проектах – это то, что вы можете развивать их так долго, как захотите. Если вы хотите поиграть с приложением, скачайте репозиторий и начните работу.



Заключение


В этой статье мы научились разворачивать предобученную модель глубокого обучения Keras в виде веб-приложения. Это потребовало объединения ряда различных технологий, включая рекуррентные нейронные сети, веб-приложения, шаблоны, HTML, CSS и, конечно же, Python.

Несмотря на то, что это базовое приложение, оно показывает, что вы можете создавать веб-приложения с использованием глубокого обучения с относительно небольшими усилиями. Немного людей могут сказать, что смогли развернуть модель глубокого обучения в виде веб-приложения, но, если вы последуете инструкциям из этой статьи, вы сможете стать одним из них!

Комментарии (0)