
【第1回】ResponderとKerasを使って機械学習Webアプリケーションを作ってみた【大枠作成編】
2021.12.20
目次
第1回~ResponderとKerasで機械学習アプリケーションを作りたい!~
今、人気に火が着きつつある Python の WebAPIフレームワーク「Responder(レスポンダー)」。
以前、ライトコードでも流行りに全力で乗っかり「Responderを使ってDjangoチュートリアルをやってみた」という連載記事を行いました。
ResponderとKerasを使って機械学習Webアプリケーションを作ってみる!
今回から始まる連載は「ResponderとKerasを使って機械学習Webアプリケーションを作ってみた」です!
なぜこのような連載を始めたかというと、3つ理由があります。
- Responderが面白く、他にもWebアプリを作ってみたい!
- Responderの非同期処理を使ってみたい!
- せっかくのPythonのフレームワークなので機械学習と組み合わせたい!
特に、2番目の「非同期処理」については「Responderを使ってDjangoチュートリアルをやってみた」の連載では紹介しきれませんでした。
連載終了後、「機械学習と相性が良いのでは!?」と思い立ち、「Responder」と「機械学習」を絡めた記事を書くことを決めました。
簡単なアプリケーションではありますが、Responderのさらに詳しい使い方が分かっていただける記事になるはずです!
実装環境
- Webアプリケーション部分は、「Responder」
- 機械学習フレームワークは、「Keras」
Responder は Webアプリケーション部分、機械学習フレームワークは Keras を使います。
なお、本記事では、以下の環境で実装をしています。
Python | 3.7.4 |
Responder | 1.3.2 |
Keras | 2.2.4 |
この記事の完成品
今回の連載で「どんなWebアプリケーションが完成するのか?」を、簡単にお見せしておきたいと思います。
トップページ
トップページでは、学習させるタスク(データセット)を選択します。

ネットワーク作成ページ
データセットを選択したら、ユーザがネットワークを自由に作成します。
また、ちょっとしたパラメータも指定できるようにします。

以下のように、層を ある程度自由に追加できます。

ネットワークを学習させる
作成したネットワークをバックグラウンド(重要!)で学習させます。

結果を表示する
学習が終了したら、学習結果ページに移行させます。
そのページでは、学習遷移などが確認できます。

アプリを作成手順
それでは早速、作業に取り掛かってまいりましょう!
手順
アプリ作成は、以下の手順で進めていきます。
- Responderの大枠作成
- トップページのデザインの作成
- ネットワーク作成ページの作成
- バックグラウンドタスク(学習部)の作成
- 学習結果ページの作成
それでは、順番にいきます。
Responderの大枠作成
まずはじめに、Responderのファイル構成などを決めてしまいます。
Responderでは、サーバー立ち上げもルーティングも1つのファイルでやろうと思えばできるのですが、それだと後々管理が困難になります。
ですので、Djangoのように用途によってファイルを分けたいと思います。
サーバー立ち上げ用 - run.py
これは、今後いじることはありません。
サーバーの立ち上げのみ担います。
1 2 3 4 5 6 7 8 9 | """ run.py サーバ立ち上げ用ファイル """ from urls import api if __name__ == '__main__': api.run() |
ルーティング用 - urls.py
このファイルに、「ルーティング処理」を記述していきます。
が、ここにはURLを受け取ったときの処理は書きません。
この後に説明する、コントローラに処理を投げます。
Responderは通常、 @api.route() デコレータでルーティングをします。
しかし、今回は処理を分けるために api.add_route('URL', classなど) を使います。
1 2 3 4 5 6 7 8 9 10 | """ urls.py ここではURLとコントローラのルーティング、およびJinja2のフィルタ設定を行う。 """ from controllers import * # ルーティング api.add_route('/', IndexController) |
ルーティング処理用 - controller.py
先ほどの api.add_route() で追加されたURLの処理を書くファイルです。
また、ここで Responder の APIインスタンスを作成します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | """ controllers.py ResponderAPIを生成し、コントローラを管理するファイル。 """ import responder api = responder.API( title='Let\'s Learn Machine Learning', openapi='3.0.2', description='Web上で機械学習を学ぼう!', version='Beta', ) class IndexController: async def on_get(self, req, resp): title = 'ResponderとKerasで学ぶ機械学習アプリケーション' resp.html = api.template('index.html', title=title) |
これで、Responder-Webアプリケーションの大枠が完成です。
それでは試しに、全体レイアウトの「 templates/layout.html 」と、トップページデザインの「 templates/index.html 」を作りましょう。
全体のレイアウト - layout.html
今回もデザインには、Bootstrap4 を用います。
【参考】
はじめに - Bootstrap 4.3 - 日本語リファレンス
各コントローラから、ページタイトルを受け取る仕様にしてみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | <!DOCTYPE html> <html lang="ja"> <head> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"> <meta charset="UTF-8"> <title>ResKeras | {{title}}</title> </head> <body> <div style="display: flex; flex-direction: column; min-height: 80vh"> <div class="container"> {% block content %} <!-- メインコンテンツ --> {% endblock %} </div> </div> <br> <hr> <footer> <div align="center"> <p>Copyright © RightCode Inc. All right reserves.</p> <p>Powered by Responder and Keras</p> </div> </footer> </body> </html> |
このファイルは、もういじることはありません。
トップページ - index.html
それでは、トップページを適当に作ります。
1 2 3 4 5 6 7 8 9 10 11 12 13 | {% extends "layout.html" %} {% block content %} <br> <h1>ResKeras</h1> <p> - ResponderとKerasで学ぶ機械学習アプリケーション - </p> <hr> <br> <br> <p>Web上で気軽に機械学習を学ぼう!</p> <p>まずは以下から学習させたいタスクを選択しましょう。</p> {% endblock %} |
まだ質素なページですが、ここで動作確認をしてみましょう。
動作確認
1 | $ python run.py |
http://127.0.0.1:5042 にアクセスしてみます。

うまく動作していそうです。
Jinja2にフィルタを追加してみる
トップページに情報を書き加えていきます。
が、その前に、htmlファイルがスッキリするように、Jinja2 のフィルタ機能を活用してみます。
ちなみに、Jinja2とは先程の、htmlファイルでいう {{ }} や {% %} に囲まれた部分がJinja2が処理する部分で、htmlを生成してくれるテンプレートエンジンです。
Jinja2環境設定用ファイル - jinja_env.py
Jinja2のフィルタは、「 jinja_env.py 」というファイルで定義します。
とりあえずは、以下のように書いておきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | """ jinja_env.py Jinja2のフィルタを定義する """ def static_filter(path): return '/static/' + path def image_filter(path): return '/static/images/' + path def css_filter(path): return '/static/css/' + path def script_filter(path): return '/static/script/' + path def badge_filter(text): return '<span class="badge badge-secondary">' + text + '</span>' def badge_active_filter(text): return '<span class="badge badge-primary">' + text + '</span>' |
urls.pyでフィルタを登録
次に、urls.py に以下を追記します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | import jinja_env # 追記部分 from controllers import * # 以下追記部分 ... フィルタを辞書に登録 api.jinja_env.filters.update( static=jinja_env.static_filter, image=jinja_env.image_filter, css=jinja_env.css_filter, script=jinja_env.script_filter, badge=jinja_env.badge_filter, badge_active=jinja_env.badge_active_filter, ) # ルーティング api.add_route('/', IndexController) |
そうすると、テンプレート側では、 '/static/images/image.png' と書いていたところを、 {{ 'image.png' | image }} のように、パイプでスッキリ書けます。
これで管理のしやすさも向上しました。
バッジ
また、ついでに「バッジ」もフィルタに登録しました。
これは
1 2 3 4 5 6 | {% autoescape false %} {{ 'データセットを選択' | badge_active }} {{ 'ネットワークを作成' | badge }} {{ '学習' | badge }} {{ '結果' | badge }} {% endautoescape %} |
と書くと、以下のように表示されます。
ちょっとしたオシャレ要素です(笑)

ここで {% autoescape false %} をつけないと、うまく表示されません。(一度消してみるとどうなるか分かります)
トップページを完成させる
では、トップページを完成させましょう。
役割としては、ユーザに「データセット」を選ばせるページなので、使うデータセットの情報を表示し、選択されたデータセットに対応したネットワーク作成ページにリンクさせます。
そのため、こんな感じにしてみました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | {% extends "layout.html" %} {% block content %} <br> <h1>ResKeras</h1> <p> - ResponderとKerasで学ぶ機械学習アプリケーション - </p> <hr> {% autoescape false %} {{ 'データセットを選択' | badge_active }} {{ 'ネットワークを作成' | badge }} {{ '学習' | badge }} {{ '結果' | badge }} {% endautoescape %} <br> <br> <p>Web上で気軽に機械学習を学ぼう!</p> <p>まずは以下から学習させたいタスクを選択しましょう。</p> <div class="row"> <div class="col-md-4"> <div class="card bg-dark text-white"> <div class="card-header"> <a href="/create/mnist">MNIST Dataset</a> </div> <div class="card-body"> <a href="/create/mnist"><img src="{{ 'mnist.png' | image }}" width="100%"></a> </div> <div class="card-footer"> <p> タスク : 画像分類<br> 入力 : 28x28のグレースケール画像<br> ラベル : 0~9 (欠損なし)<br> データ : 計70000枚<br> 特徴 : 簡易画像分類ベンチマーク </p> <p>配布元 : <a href="http://yann.lecun.com/exdb/mnist/">THE MNIST DATABAE</a></p> </div> </div> </div> <div class="col-md-4"> <div class="card bg-dark text-white"> <div class="card-header"> <a href="/create/iris">UCI Iris Dataset</a> </div> <div class="card-body"> <a href="/create/iris"><img src="{{ 'iris.png' | image }}" width="100%"></a> </div> <div class="card-footer"> <p> タスク : 単純クラス分類<br> 入力 : 4次元の実数値 <br> [sepal length, sepal width, petal length, petal width]<br> ラベル : 3クラス <br> [iris-setosa, iris-versicolour, iris-virginica]<br> データ : 計150枚<br> 特徴 : 簡易・軽量多クラス分類ベンチマーク </p> <p>配布元 : <a href="https://archive.ics.uci.edu/ml/datasets/iris">UCI Machine Learning Repository: Iris Data Set</a></p> </div> </div> </div> <div class="col-md-4"> <div class="card bg-dark text-white"> <div class="card-header"> <a href="/create/wine">UCI Wine Dataset</a> </div> <div class="card-body"> <a href="/create/wine"><img src="{{ 'wine.png' | image }}" width="100%"></a> </div> <div class="card-footer"> <p> タスク : 単純クラス分類<br> 入力 : 13次元の実数値 <br> 1) Alcohol <br> 2) Malic acid <br> 3) Ash <br> 4) Alcalinity of ash <br> 5) Magnesium <br> 6) Total phenols <br> 7) Flavanoids <br> 8) Nonflavanoid phenols <br> 9) Proanthocyanins <br> 10)Color intensity <br> 11)Hue <br> 12)OD280/OD315 of diluted wines <br> 13)Proline<br> ラベル : 3クラス (品種)<br> データ : 計178枚<br> 特徴 : 簡易・軽量多クラス分類ベンチマーク </p> <p>配布元 : <a href="https://archive.ics.uci.edu/ml/datasets/wine">UCI Machine Learning Repository: Wine Data Set</a></p> </div> </div> </div> </div> {% endblock %} |
長々としたコードですが、大したことは書いていません。
最初に見せたトップページのデザインになります。
ネットワーク作成URLは、http://127.0.0.1:5042/create/mnist といった http://127.0.0.1:5042/create/{dataset} とします。
新たにルーティング
したがって、「 urls.py 」に新たに、以下を記述しましょう。
1 | api.add_route('/create/{dataset}', CreateController) |
そうしたら、controllers.py に class CreateController を作れば、ルーティング完了です。
その実装は、次の記事にて!
第2回へ続く!
今回から新たに「Responder で機械学習アプリを作る」という短い連載がスタートしました。
最初に書いたように、「Responder の非同期処理を如何にうまく利用するか」が重要なアプリケーションです。
筆者も非同期処理には、少し格闘しながら作成したのですが、これがなかなか思うようにいかず…。
そんな「苦労」と「発見」を読者のみなさまと共有できたらと思っています(笑)
それでは、第2回でまたお会いしましょう!
第2回はこちら!
こちらの記事もオススメ!
Kerasのオススメ本
書いた人はこんな人

- 「好きなことを仕事にするエンジニア集団」の(株)ライトコードです!
ライトコードは、福岡、東京、大阪の3拠点で事業展開するIT企業です。
現在は、国内を代表する大手IT企業を取引先にもち、ITシステムの受託事業が中心。
いずれも直取引で、月間PV数1億を超えるWebサービスのシステム開発・運営、インフラの構築・運用に携わっています。
システム開発依頼・お見積もりは大歓迎!
また、WEBエンジニアとモバイルエンジニアも積極採用中です!
ご応募をお待ちしております!
ITエンタメ2022.06.22IntelliJ IDEAとkotlinを送り出したJetBrains創業物語
ITエンタメ2022.06.15【アタリ創業者】スティーブ・ジョブズを雇った男「ノーラン・ブッシュネル」
ITエンタメ2022.06.13プログラミングに飽きてPHPを開発したラスマス・ラードフ
ITエンタメ2022.06.03【Unity開発秘話】ゲーマーを開発者にしてしまうゲームエンジン