RaspberryPi

ラズパイとscikit-learnとFlaskとnginxでお手軽?なWebアプリ

RaspberryPi

[PR]当サイトはアフィリエイト広告を利用しています。

背景

以前このブログでラズパイにローカルなWordPressを導入する記事を書きました。

さらにそのWordPressでSupport Vector Regressionを実施しようということで、scikit-learnの出力を利用して記事にJavaScriptを利用してSupport Vector Regressionの計算をさせました。

これはNode.jsのハードルが高くて設定が難しいということに端を発していました。

色々試してはみたんですよ。

でもNode.jsでSupport Vector Regressionを実行しようとすると、node-svmとかを使うほかなく、手持ちのUbuntuには入るんですけどラズパイには入らないのです。色々なモジュールのバージョンを変えて試したんですけどなんかうまくいかない。

でもやっぱりWebアプリみたいにしたいじゃないですか。

ブラウザでは入力だけを行って、ラズパイ側で処理をして、その出力をブラウザで受け取るだけ。

これを本当はしたいわけです。

そこでふと気づいたんです。

PythonでWebアプリ作ることってできないのかな?

するとあるじゃないですか。

Node.jsのPython版みたいなモジュールが。

どうやらDjangoがいいらしいということでさっそくやってみました。

しかしやってみるとDjangoは覚えることが多い印象でなかなかやりたいことに近づけない感じがしました。

そこで構築が簡単で覚えることも少ないというFlaskを利用することにしました

結果なんとか形になりました。

ローカルなWebアプリを作成できました。

今回はその備忘録です。

なおこの記事は「RaspberryPiでローカルなWordPress」でnginxをインストールした状態で話を展開していきます。

ラズパイにscikit-learnを入れる

意外に難しかった。

UbuntuとWindowsには簡単に入るんですけど、ラズパイには簡単に入らない。

上手くいった手順を示します。

まずNumpyを入れます。そしてバージョンを上げます。

$ sudo pip3 install numpy
$ sudo pip3 install numpy --upgrade

そうしたらscikit-learnを入れます。

$ sudo pip3 install scikit-learn

そうしたらNumpyの「Troubleshooting ImportError」にあるように次のコマンドを打つ。

$ sudo apt-get install libatlas-base-dev

これでscikit-learnを使う準備が整いました。

Flaskを入れる

次のコマンドを打つ。

$ sudo pip3 install flask

nginxでリバースプロキシ

このままFlaskを使うと「http://IPアドレス:5000」とかでサーバーが起動してしまいます。

やはりurlでアプリを振り分けたいわけです。

今回はWordPressへのアクセスなら

「http://IPアドレス」

Webアプリへのアクセスなら

「http://IPアドレス/app1/」

で処理をすることにします。

それを実現する方法がリバースプロキシです。

まず次のコマンドを打ちます。

$ sudo nano /etc/nginx/sites-enabled/default

そして以下のように記入します。

server {
        listen 80 default_server;
        listen [::]:80 default_server;
  
        # SSL configuration
        #
…
…  
        #location ~ /\.ht {
        #       deny all;
        #}
  
        location /app1/ {
            proxy_pass http://IPアドレス:5000/;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection keep-alive;
            proxy_set_header Host $host;
            proxy_cache_bypass $http_upgrade;
        }
}

13行目から20行目を記入します。

ただし入力したら次のコマンドを忘れずに。

sudo service nginx restart

これをやらないといつまでもnginxへの変更が反映されません。

気をつけましょう。

これで

「http://IPアドレス/app1/」

にアクセスすれば

「http://IPアドレス:5000」

で動いているサーバーにつながります。

メインプログラムの作成

メインプログラムをデスクトップに作ります。

今回は「ful.py」です。

このファイルに次のように記入します。

from flask import Flask, render_template, request, redirect, url_for
app = Flask(__name__)
from sklearn import svm
x = [[0,0,0],[0,0,0],[1,0,0],[1,0,0],[0,1,0],[0,1,0],[0,0,1],[0,0,1],[1,0,1],[1,0,1],[0,1,1],[0,1,1]]
y = [51,52,50,51,51,49,60,61,61,62,60,61]
model = svm.SVR(C=5, kernel='rbf', epsilon=0.1, gamma='auto')
model.fit(x, y)
@app.route('/')
def form0():
	return render_template('index.html', \
		title = 'Form Sample(get)', \
		message = 'hello', \
		message1 = 'Nan', \
		message2 = 'Nan', \
		message3 = 'Nan', \
		)
@app.route('/', methods=["POST"])
def post():
	print('post success!')
	x1 = int(request.form['x1val'])
	x2 = int(request.form['x2val'])
	x3 = int(request.form['x3val'])
	x = [[x1,x2,x3]]
	p1 = model.predict(x)
	return render_template('index.html', \
		title = 'Form Sample(get)', \
		message = p1, \
		message1 = x1, \
		message2 = x2, \
		message3 = x3, \
		)
if __name__=='__main__':
	app.run(debug=False, host='192.168.100.107', port=5000)

●モジュールのインポートとscikit-learnの設定

必要なモジュールをインポートし、いつも使っている作物高さのSVRをscikit-learnで実行します。

from flask import Flask, render_template, request, redirect, url_for
app = Flask(__name__)
from sklearn import svm
x = [[0,0,0],[0,0,0],[1,0,0],[1,0,0],[0,1,0],[0,1,0],[0,0,1],[0,0,1],[1,0,1],[1,0,1],[0,1,1],[0,1,1]]
y = [51,52,50,51,51,49,60,61,61,62,60,61]
model = svm.SVR(C=5, kernel='rbf', epsilon=0.1, gamma='auto')
model.fit(x, y)

●とりあえずアクセスがあったらアプリのトップページにつなぐ

最初に表示するページを表示します。

「index.html」はこのあと編集します。

@app.route('/')
def form0():
	return render_template('index.html', \
		title = 'Form Sample', \
		message = 'hello', \
		message1 = 'Nan', \
		message2 = 'Nan', \
		message3 = 'Nan', \
		)

今回はindex.htmlの「message」「message1」「message2」「message3」という変数に結果を表示します。

●POSTが送られたらscikit-learnでSVRを実行して変数に格納

ウェブページで入力が行われたら結果を受け取って処理してウェブページに戻します。

@app.route('/', methods=["POST"])
def post():
	x1 = int(request.form['x1val'])
	x2 = int(request.form['x2val'])
	x3 = int(request.form['x3val'])
	x = [[x1,x2,x3]]
	p1 = model.predict(x)
	return render_template('index.html', \
		title = 'Form Sample(get)', \
		message = p1, \
		message1 = x1, \
		message2 = x2, \
		message3 = x3, \
		)

●サーバーの立ち上げ

flaskでサーバーを立ち上げます。

if __name__=='__main__':
	app.run(debug=False, host='IPアドレス', port=5000)

hostがアクセスするIPアドレスで、(ここではラズパイ本体のIPアドレス)そのポート5000番でサーバーを立ち上げます。

色々なサイトで

@app.route(‘/’)を

@app.route(‘/app1’)

にするとそのページに遷移するとか書かれているのですが、リバースプロキシを設定している場合、ルートの(‘/’)のままでよいようです。

実際はすべて

「http://IPアドレス:5000」

で処理が行われていて

「http://IPアドレス/app1/」

に対しての処理はnginxがうまいことやってくれるみたいです。

ウェブページの準備

デスクトップに

「templates」

というフォルダを作成して(ful.pyと同じ階層に置きます)その中に

「index.html」

というファイルを作成します。

そして「index.html」に次のように記入します。

<!doctype html>
<title>サンプル</title>
<head>
    <title></title>
    
</head>
 
<body>
    <header>
        <div style="font-size:30px;">SVR</div>
    </header>
    <div  style="font-size:30px;">
        <h2>値の表示</h2>
        <p>{{ message }}</p><p>{{ message1 }}</p><p>{{ message2 }}</p><p>{{ message3 }}</p>
        <form action="" method="POST">
			<div>
				<label for="x1">x1:</label>
				<input type="text" id="x1val" name="x1val" placeholder="x1" style="height:30px;font-size:30px;">	
			</div>
			<div> </div>
			<div>
				<label for="x2">x2:</label>
				<input type="text" id="x2val" name="x2val" placeholder="x2" style="height:30px;font-size:30px;">	
			</div>
			<div> </div>
			<div>
				<label for="x3">x3:</label>
				<input type="text" id="x3val" name="x3val" placeholder="x3" style="height:30px;font-size:30px;">	
			</div>
			<div> </div>
			<div>
				<input type="submit" value="送信" style="font-size:30px;width:100px;">
			</div>
		</form>
    </div>
</body>
</html>

フォームのinputにname属性で「x1val」「x2val」「x3val」と指定しています。

これでful.pyのrequest.form[‘x1val’]が動きます。

私はここで「x1val」を「x1Val」とvを大文字でPythonファイルに書いてしまい、かなり詰まりました。入力には気をつけましょう。

変数は{{ message }}などと書いています。

注意しなければいけないのが

<form action=”” method=”POST”>

「action=””」

です。

ここを

「”/app1″」

とするなどとflask入門サイトなどで書かれることが多いのですが、「/app1」へのアクセスはすべてnginxがうまいことやってくれるようなので、ルート「””」ですべて処理すると記載してよいようです。

プログラムを実行

プログラムを実行するために以下のコマンドを打ちます。

$ sudo python3 /home/pi/Desktop/ful.py

するとサーバーが立ち上がるのでブラウザで

「http://IPアドレス/app1/」

にアクセスします。

上手くいっていれば入力フォームのあるページが表示され、x1などに値を入れると結果が送られ、表示されます。

ラズパイ起動時にサーバーを立ち上げる

以前WordPressでSeleniumを使うときの記事でやったように起動時に今回のサーバーを立ち上げます。

コンソールに

$ cd /home/pi/.config/autostart
$ nano flask_app1.desktop

と打ちます。

エディタ編集画面で

[Desktop Entry]
Exec=lxterminal -e "/home/pi/Desktop/flask_app1.sh;SHELL"
Type=Application
Name=flask_app1
Terminal=true

と記入します。

いったんコンソールから離れてデスクトップで右クリックして

「flask_app1.sh」

というファイルを作成して中身をテキストエディタで開きます。

そこに

#!/bin/sh
python3 /home/pi/Desktop/flu.py

と入力して保存します。

次にコンソールに戻って

$ cd /home/pi/Desktop
$ chmod +x flask_app1.sh

と入力します。

flask_app1.shに実行権限を付与します。

これでラズパイ起動時にflu.pyが自動的に実行されサーバーが立ち上がります。

以前の記事でも取り上げていますが、再起動するときはモニターにつないだ状態で再起動してください。

モニターにつながずに再起動すると後からモニターにつないでも画面が表示されません。

まとめ

今回はラズパイとscikit-learnとFlaskとnginxと色々と使ってローカルなWebアプリを作ってみました。

本番の気温に関するSupport Vector Regressionが作成できたら続きを載せるかもしれません。

それにしてもPythonって今は色々なことができるんですねー。

Pythonが普通に使えるなら便利なライブラリも普通に使えますし、かなりできることが広がります。

勉強になりました。

これまで使い道が見いだせず家に眠っていたラズパイが今輝きを放っています。