【第1回】ResponderとKerasを使って機械学習Webアプリケーションを作ってみた【大枠作成編】
IT技術
第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"""
2run.py
3サーバ立ち上げ用ファイル
4"""
5
6from urls import api
7
8if __name__ == '__main__':
9 api.run()
ルーティング用 - urls.py
このファイルに、「ルーティング処理」を記述していきます。
が、ここにはURLを受け取ったときの処理は書きません。
この後に説明する、コントローラに処理を投げます。
Responderは通常、@api.route() デコレータでルーティングをします。
しかし、今回は処理を分けるためにapi.add_route('URL', classなど) を使います。
1"""
2urls.py
3ここではURLとコントローラのルーティング、およびJinja2のフィルタ設定を行う。
4"""
5
6from controllers import *
7
8
9# ルーティング
10api.add_route('/', IndexController)
ルーティング処理用 - controller.py
先ほどのapi.add_route() で追加されたURLの処理を書くファイルです。
また、ここで Responder の APIインスタンスを作成します。
1"""
2controllers.py
3ResponderAPIを生成し、コントローラを管理するファイル。
4"""
5
6import responder
7
8api = responder.API(
9 title='Let\'s Learn Machine Learning',
10 openapi='3.0.2',
11 description='Web上で機械学習を学ぼう!',
12 version='Beta',
13)
14
15
16class IndexController:
17 async def on_get(self, req, resp):
18 title = 'ResponderとKerasで学ぶ機械学習アプリケーション'
19 resp.html = api.template('index.html', title=title)
これで、Responder-Webアプリケーションの大枠が完成です。
それでは試しに、全体レイアウトの「 templates/layout.html 」と、トップページデザインの「 templates/index.html 」を作りましょう。
全体のレイアウト - layout.html
今回もデザインには、Bootstrap4 を用います。
【参考】
はじめに - Bootstrap 4.3 - 日本語リファレンス
各コントローラから、ページタイトルを受け取る仕様にしてみます。
1<!DOCTYPE html>
2<html lang="ja">
3<head>
4 <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">
5 <meta charset="UTF-8">
6 <title>ResKeras | {{title}}</title>
7</head>
8<body>
9<div style="display: flex; flex-direction: column; min-height: 80vh">
10 <div class="container">
11 {% block content %}
12 <!-- メインコンテンツ -->
13 {% endblock %}
14 </div>
15</div>
16<br>
17<hr>
18<footer>
19 <div align="center">
20 <p>Copyright © RightCode Inc. All right reserves.</p>
21 <p>Powered by Responder and Keras</p>
22 </div>
23</footer>
24</body>
25</html>
このファイルは、もういじることはありません。
トップページ - index.html
それでは、トップページを適当に作ります。
1{% extends "layout.html" %}
2
3{% block content %}
4<br>
5<h1>ResKeras</h1>
6<p> - ResponderとKerasで学ぶ機械学習アプリケーション - </p>
7<hr>
8<br>
9<br>
10<p>Web上で気軽に機械学習を学ぼう!</p>
11<p>まずは以下から学習させたいタスクを選択しましょう。</p>
12
13{% 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"""
2jinja_env.py
3Jinja2のフィルタを定義する
4"""
5
6
7def static_filter(path):
8 return '/static/' + path
9
10
11def image_filter(path):
12 return '/static/images/' + path
13
14
15def css_filter(path):
16 return '/static/css/' + path
17
18
19def script_filter(path):
20 return '/static/script/' + path
21
22
23def badge_filter(text):
24 return '<span class="badge badge-secondary">' + text + '</span>'
25
26
27def badge_active_filter(text):
28 return '<span class="badge badge-primary">' + text + '</span>'
urls.pyでフィルタを登録
次に、urls.py に以下を追記します。
1import jinja_env # 追記部分
2from controllers import *
3
4# 以下追記部分 ... フィルタを辞書に登録
5api.jinja_env.filters.update(
6 static=jinja_env.static_filter,
7 image=jinja_env.image_filter,
8 css=jinja_env.css_filter,
9 script=jinja_env.script_filter,
10 badge=jinja_env.badge_filter,
11 badge_active=jinja_env.badge_active_filter,
12)
13
14# ルーティング
15api.add_route('/', IndexController)
そうすると、テンプレート側では、'/static/images/image.png' と書いていたところを、{{ 'image.png' | image }} のように、パイプでスッキリ書けます。
これで管理のしやすさも向上しました。
バッジ
また、ついでに「バッジ」もフィルタに登録しました。
これは
1{% autoescape false %}
2{{ 'データセットを選択' | badge_active }}
3{{ 'ネットワークを作成' | badge }}
4{{ '学習' | badge }}
5{{ '結果' | badge }}
6{% endautoescape %}
と書くと、以下のように表示されます。
ちょっとしたオシャレ要素です(笑)
ここで{% autoescape false %} をつけないと、うまく表示されません。(一度消してみるとどうなるか分かります)
トップページを完成させる
では、トップページを完成させましょう。
役割としては、ユーザに「データセット」を選ばせるページなので、使うデータセットの情報を表示し、選択されたデータセットに対応したネットワーク作成ページにリンクさせます。
そのため、こんな感じにしてみました。
1{% extends "layout.html" %}
2
3{% block content %}
4<br>
5<h1>ResKeras</h1>
6<p> - ResponderとKerasで学ぶ機械学習アプリケーション - </p>
7<hr>
8
9{% autoescape false %}
10{{ 'データセットを選択' | badge_active }}
11{{ 'ネットワークを作成' | badge }}
12{{ '学習' | badge }}
13{{ '結果' | badge }}
14{% endautoescape %}
15
16<br>
17<br>
18<p>Web上で気軽に機械学習を学ぼう!</p>
19<p>まずは以下から学習させたいタスクを選択しましょう。</p>
20<div class="row">
21 <div class="col-md-4">
22 <div class="card bg-dark text-white">
23 <div class="card-header">
24 <a href="/create/mnist">MNIST Dataset</a>
25 </div>
26 <div class="card-body">
27 <a href="/create/mnist"><img src="{{ 'mnist.png' | image }}" width="100%"></a>
28 </div>
29 <div class="card-footer">
30 <p>
31 タスク : 画像分類<br>
32 入力 : 28x28のグレースケール画像<br>
33 ラベル : 0~9 (欠損なし)<br>
34 データ : 計70000枚<br>
35 特徴 : 簡易画像分類ベンチマーク
36 </p>
37 <p>配布元 : <a href="http://yann.lecun.com/exdb/mnist/">THE MNIST DATABAE</a></p>
38 </div>
39 </div>
40 </div>
41
42 <div class="col-md-4">
43 <div class="card bg-dark text-white">
44 <div class="card-header">
45 <a href="/create/iris">UCI Iris Dataset</a>
46 </div>
47 <div class="card-body">
48 <a href="/create/iris"><img src="{{ 'iris.png' | image }}" width="100%"></a>
49 </div>
50 <div class="card-footer">
51 <p>
52 タスク : 単純クラス分類<br>
53 入力 : 4次元の実数値 <br>
54 [sepal length, sepal width, petal length, petal width]<br>
55 ラベル : 3クラス <br>
56 [iris-setosa, iris-versicolour, iris-virginica]<br>
57 データ : 計150枚<br>
58 特徴 : 簡易・軽量多クラス分類ベンチマーク
59 </p>
60 <p>配布元 : <a href="https://archive.ics.uci.edu/ml/datasets/iris">UCI Machine Learning Repository: Iris Data Set</a></p>
61 </div>
62 </div>
63 </div>
64
65 <div class="col-md-4">
66 <div class="card bg-dark text-white">
67 <div class="card-header">
68 <a href="/create/wine">UCI Wine Dataset</a>
69 </div>
70 <div class="card-body">
71 <a href="/create/wine"><img src="{{ 'wine.png' | image }}" width="100%"></a>
72 </div>
73 <div class="card-footer">
74 <p>
75 タスク : 単純クラス分類<br>
76 入力 : 13次元の実数値 <br>
77 1) Alcohol <br>
78 2) Malic acid <br>
79 3) Ash <br>
80 4) Alcalinity of ash <br>
81 5) Magnesium <br>
82 6) Total phenols <br>
83 7) Flavanoids <br>
84 8) Nonflavanoid phenols <br>
85 9) Proanthocyanins <br>
86 10)Color intensity <br>
87 11)Hue <br>
88 12)OD280/OD315 of diluted wines <br>
89 13)Proline<br>
90 ラベル : 3クラス (品種)<br>
91 データ : 計178枚<br>
92 特徴 : 簡易・軽量多クラス分類ベンチマーク
93 </p>
94 <p>配布元 : <a href="https://archive.ics.uci.edu/ml/datasets/wine">UCI Machine Learning Repository: Wine Data Set</a></p>
95 </div>
96 </div>
97 </div>
98
99</div>
100
101{% endblock %}
長々としたコードですが、大したことは書いていません。
最初に見せたトップページのデザインになります。
ネットワーク作成URLは、http://127.0.0.1:5042/create/mnist といったhttp://127.0.0.1:5042/create/{dataset} とします。
新たにルーティング
したがって、「 urls.py 」に新たに、以下を記述しましょう。
1api.add_route('/create/{dataset}', CreateController)
そうしたら、controllers.py にclass CreateController を作れば、ルーティング完了です。
その実装は、次の記事にて!
第2回へ続く!
今回から新たに「Responder で機械学習アプリを作る」という短い連載がスタートしました。
最初に書いたように、「Responder の非同期処理を如何にうまく利用するか」が重要なアプリケーションです。
筆者も非同期処理には、少し格闘しながら作成したのですが、これがなかなか思うようにいかず…。
そんな「苦労」と「発見」を読者のみなさまと共有できたらと思っています(笑)
それでは、第2回でまたお会いしましょう!
第2回はこちら!
こちらの記事もオススメ!
2020.07.17ライトコード的「やってみた!」シリーズ「やってみた!」を集めました!(株)ライトコードが今まで作ってきた「やってみた!」記事を集めてみました!※作成日が新し...
2020.07.28機械学習 特集知識編人工知能・機械学習でよく使われるワード徹底まとめ!機械学習の元祖「パーセプトロン」とは?【人工知能】ニューラルネ...
2020.07.30Python 特集実装編※最新記事順Responder + Firestore でモダンかつサーバーレスなブログシステムを作ってみた!P...
Kerasのオススメ本
ライトコードでは、エンジニアを積極採用中!
ライトコードでは、エンジニアを積極採用しています!社長と一杯しながらお話しする機会もご用意しております。そのほかカジュアル面談等もございますので、くわしくは採用情報をご確認ください。
採用情報へ
「好きを仕事にするエンジニア集団」の(株)ライトコードです! ライトコードは、福岡、東京、大阪、名古屋の4拠点で事業展開するIT企業です。 現在は、国内を代表する大手IT企業を取引先にもち、ITシステムの受託事業が中心。 いずれも直取引で、月間PV数1億を超えるWebサービスのシステム開発・運営、インフラの構築・運用に携わっています。 システム開発依頼・お見積もり大歓迎! また、現在「WEBエンジニア」「モバイルエンジニア」「営業」「WEBデザイナー」を積極採用中です! インターンや新卒採用も行っております。 以下よりご応募をお待ちしております! https://rightcode.co.jp/recruit