#Flaskを使って年俸を予測してみた。
コードはこちらからダウンロード可能です。(GitHub)
緑色の「Clone or Download」をクリックして、「Download ZIP」をクリックするとダウンロードできます。
(このように、「そんなの言われなくてもわかってる」という内容まで書いてあるところもありますので、僕同様に初心者の方も少しはわかりやすくなっていると思います。)
[注意]
- データ数が337しかなかったため、精度はあまり良くないどころの騒ぎではありません。
- 今回はデータ分析に重きは置いておらず、WEBアプリケーション制作に集中しています。
- プログラミング歴約1ヶ月の初心者が書いています。
##この記事の対象者
- Flaskと機械学習モデルを組み合わせたWEBアプリを作りたい方
- Flaskの公式チュートリアル程度の内容を理解している方(僕はpaizaでのみ学習)
- 機械学習・深層学習を学習済みの方(機械学習のコードは載せてありますが、WEBアプリ作成が目的のため、解説はしません)
- python, frask(少しでいい), 機械学習(自分でモデルを作れればいい)の知識があれば大丈夫かと思います。(HTMLなどを使いますが、勉強したことないので僕もよく知りません)
##この記事でできること
- Flaskで簡単なAIアプリを作成できる(最悪、コピペ or ダウンロード で行けると思います。)
- 機械学習モデルをFlaskに組み込む方法がわかる
##開発環境
OS:mac
- python3.7
- Flask 1.0.3
- Jupyter 1.0.0
- Keras 2.2.4
- Matplotlib 3.1.0
- numpy 1.16.4
- pandas 0.24.2
- requests 2.22.0
- scikit-learn 0.21.2
- tensorflow 1.13.1
##(1)機械学習モデルを作成する
以下のコードは全てJupyter notebookで実行しています。
###(1−1)使用モジュール
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
from sklearn.preprocessing import StandardScaler
from keras.models import Sequential
from keras.layers.core import Dense, Activation
###(1−2)データ読み込み
データはここからダウンロードできます。
テキストエディタにコピペするなりしてください。(僕は"baseball_data.csv"と名前をつけて保存しました。)
data = pd.read_csv("baseball_data.csv")
data.columns = ("sarary", "batting avg", "OBR", "run", "hit", "double", "triple", "homerun", "RBI",
"fourball", "strikeout", "stolen", "error", "x13", "x14", "x15", "x16")
#OBP:出塁率
#RBI:打点
#run:得点
###(1−3)訓練データとテストデータに分割して正規化
train_data = data.iloc[:300, 1:13].values.astype("float32")#訓練データ
test_data = data.iloc[300:, 1:13].values.astype("float32")#テストデータ
train_label = data["sarary"][:300].values.astype("float32")#訓練データのラベル
test_label = data["sarary"][300:].values.astype("float32")#テストデータのラベル
#正規化
stdc = StandardScaler()
#訓練データの平均と標準偏差
mean_train = np.mean(train_data, axis = 0)
std_train = np.std(train_data, axis = 0)
#ラベルの平均と標準偏差
mean_label = np.mean(train_label, axis = 0)
std_label = np.std(train_label, axis = 0)
#テストデータは訓練データの値で正規化
for column in range(test_data.shape[1]):
test_data[:, column] = (test_data[:, column] - mean_train[column]) / std_train[column]
test_label = (test_label - mean_label) / std_label
#訓練データを正規化
train_data = stdc.fit_transform(train_data)
train_label = (train_label - mean_label) / std_label
###(1−4)k分割交差検証を使って学習モデルを作る
model.save("baseball_model.h5")
を実行することでモデルを保存できます。
("baseball_model.h5"の部分は自由にしてください。)
k = 4#分割数
num_val_data = len(train_data) // k#検証データ数
num_epochs = 150
batch_size = 4
mae_all_scores = []
loss_all_scores = []
val_loss_all_scores = []
for num in range(k):
print(num+1, "回目")
#検証用データ
val_data = train_data[num * num_val_data: (num + 1) * num_val_data]
val_label = train_label[num * num_val_data: (num + 1) * num_val_data]
#訓練用データ
par_train_data = np.concatenate([train_data[: num * num_val_data], train_data[(num + 1) * num_val_data: ]], axis = 0)
par_train_label = np.concatenate([train_label[: num * num_val_data], train_label[(num + 1) * num_val_data: ]], axis = 0)
model = Sequential()
model.add(Dense(4, activation="relu", input_shape=(train_data.shape[1], )))
model.add(Dense(4, activation="relu"))
model.add(Dense(1))
model.compile(optimizer="rmsprop", loss="mse", metrics=["mae"])
history = model.fit(par_train_data, par_train_label,
epochs=num_epochs,
batch_size=batch_size,
validation_data=(val_data, val_label),
verbose = 0
)
mae_history = history.history["val_mean_absolute_error"]
loss_history = history.history["loss"]
val_loss_history = history.history["val_loss"]
mae_all_scores.append(mae_history)
loss_all_scores.append(loss_history)
val_loss_all_scores.append(val_loss_history)
print("終了")
print("モデルを保存しています・・・")
model.save("baseball_model.h5")
print("モデルを保存しました。")
###(1−5)モデルの精度を確認(今回は特に関係ない)
今回はWEBアプリを作ることが目的であるので、モデルの良し悪しは関係ないが、下記のコードを実行することで良し悪しを確認できる。
特に興味のない方は読み飛ばしていただいて大丈夫です。
average_mae_history = [np.mean([x[i] for x in mae_all_scores]) for i in range(num_epochs)]
average_loss_history = [np.mean([x[i] for x in loss_all_scores]) for i in range(num_epochs)]
average_val_loss_history = [np.mean([x[i] for x in val_loss_all_scores]) for i in range(num_epochs)]
plt.plot(range(1, len(average_mae_history) + 1), average_mae_history)
plt.grid(True)
plt.show()
plt.plot(range(1, len(average_loss_history) + 1), average_loss_history, color = "red", label="loss")
plt.plot(range(1, len(average_val_loss_history) + 1), average_val_loss_history, color = "blue", label="val_loss")
plt.legend()
plt.grid(True)
plt.show()
##(2)Flask側
以下のコードはCotEditorで書いています。(ファイル名:baseball_sarary.py)
コードがかければCotEditorである必要は全くないですが、jupyterで実行するわけではありません。
from flask import Flask, request, render_template
import keras
import tensorflow as tf
app = Flask(__name__)
#---------------モデルを読み込む---------------
model = keras.models.load_model("baseball_model.h5")
model._make_predict_function()
graph = tf.get_default_graph()
#---------------------------------------------------------------------------
#---------------モデルを実行するための関数---------------
import numpy as np
def model_run(data):
mean_train = np.array([0.25924, 0.32521668, 46.94, 93.69334, 16.78, 2.4466667, 9, 44.1, 35.193333, 57.013332, 8.576667, 6.76])
std_train = np.array([3.7369091e-02, 4.3865968e-02, 2.8560400e+01, 5.1223877e+01, 1.0147821e+01, 2.6179805e+00, 9.0631123e+00, 2.9168533e+01, 2.4886461e+01, 3.3527500e+01, 1.1886300e+01, 5.9678917e+00])
std_label = 1248.6285
mean_label = 1274.0566
for i in range(12):
data[i] = (data[i] - mean_train[i]) / std_train[i]
data = data.reshape(1, 12)
global graph
with graph.as_default():
ans = model.predict(data)
ans = model.predict(data)
ans = (ans * std_label) + mean_label
ans = int(ans[0][0]*1000)
return ans
#---------------------------------------------------------------------------
@app.route("/")
def home():
message = "起動したいアプリを選んでください。"
return render_template("home.html", message = message)
@app.route("/baseball")
def baseball():
message = "下の項目を入力すると、年俸が算出されます。(1992年)"
return render_template("baseball.html", message = message)
@app.route("/baseball/result", methods = ["POST"])
def baseball_result():
message = "あなたの年俸が予測されました!"
batting_avg = float(request.form["batting_avg"])
obp = float(request.form["obp"])
run = float(request.form["run"])
hit = float(request.form["hit"])
double = float(request.form["double"])
triple = float(request.form["triple"])
homerun = float(request.form["homerun"])
rbi = float(request.form["rbi"])
fourball = float(request.form["fourball"])
strikeout = float(request.form["strikeout"])
stolen = float(request.form["stolen"])
error = float(request.form["error"])
data_list = [batting_avg, obp, run, hit, double, triple, homerun, rbi, fourball, strikeout, stolen, error]
data_np = np.array(data_list)
sarary = model_run(data_np)
sarary_yen = sarary * 128
return render_template("baseball_result.html", message = message, sarary = sarary, sarary_yen = sarary_yen)
重要な部分は、下記の部分かと思います。このコードで、先ほど作ったモデルを読み込んでいます(もう一つ下のコードに特に重要な部分だけを抜き出しました)。
モデルの読み込みはよくわからず、ネットで調べながらやりました。
最初は「pickle」でやろうとしましたが、エラーが出てしましい(jupyterではただしく読み込めた)、この記事を参考にしました。pickleでやった時は、参考記事の方と同じようなエラーが出てしましいました。
import keras
import tensorflow as tf
model = keras.models.load_model("baseball_model.h5")
model._make_predict_function()
graph = tf.get_default_graph()
import numpy as np
def model_run(data):
mean_train = np.array([0.25924, 0.32521668, 46.94, 93.69334, 16.78, 2.4466667, 9, 44.1, 35.193333, 57.013332, 8.576667, 6.76])
std_train = np.array([3.7369091e-02, 4.3865968e-02, 2.8560400e+01, 5.1223877e+01, 1.0147821e+01, 2.6179805e+00, 9.0631123e+00, 2.9168533e+01, 2.4886461e+01, 3.3527500e+01, 1.1886300e+01, 5.9678917e+00])
std_label = 1248.6285
mean_label = 1274.0566
for i in range(12):
data[i] = (data[i] - mean_train[i]) / std_train[i]
data = data.reshape(1, 12)
global graph
with graph.as_default():
ans = model.predict(data)
ans = model.predict(data)
ans = (ans * std_label) + mean_label
ans = int(ans[0][0]*1000)
return ans
####モデルの読み込み方法(Keras:TensorFlowの場合)
(TensorFlowを使った)KerasのモデルをWEBアプリに組み込みたい場合は、下記のようにしていただければ、正常に動作すると思います。
このモデルはjupyterでmodel.save("モデル名")
として保存しており、pickleは使っておりません(エラーが出てしまい、今のところ使い方がわかりません)。下記のコードのように覚えておけば、このアプリに限らず色々な場所で応用できると思います。
#Keras,TensorFlowを読み込む
import keras
import tensorflow as tf
#下記の3行でモデルを読み込む
model = keras.models.load_model("モデル名")
model._make_predict_function()
graph = tf.get_default_graph()
#関数の中で"model.predict()"を使う。(関数化しなくても動作するかとは思います。)
def model_run(data):
global graph
with graph.as_default():
ans = model.predict(data)
return ans
##(3)HTML側
こちらは特に解説はありません。(paizaでFlaskの動画をみているときにおまけで得た知識でやっているため、解説できる知識がありません。)
HTMLのコードはGitHubからダウンロードしてください。「baseball_sarary.py」などのデータもあります。
##(4)アプリ実行
以下、ターミナルで実行してください。GitHubからダウンロードしたままのファイル構成を保っていれば、正常に起動するかと思います。
###(4−1)仮想環境を作成
ターミナルを開いて仮想環境を作ります。(既にある方はスキップ)
$ python3.7 -m venv <仮想環境の名前>#"<>"は要りません
$ source <仮想環境名>/bin/activate#仮想環境起動
$ pip install Flask#Flaskなど、必要なものをインストールしてください
#開発環境に記載したものをインストールしておけば動作すると思います。
###(4−2)実行コード
#先ほどの仮想環境を起動した状態で以下を実行
#GitHubからダウンロードした"MyApp"は仮想環境の場所に置いておいてください
#仮想環境作成時にディレクトリを特に指定しなかった場合は、デスクトップに置いておけばいいかと思います。
$ cd MyApp#MyAppの場所を指定
$ FLASK_APP=baseball_sarary.py FLASK_ENV=development flask run
#「FLASK_APP=<実行したいファイル名>」で起動したいファイルを指定
#「FLASK_ENV=development」としておくことで、HTMLなどを編集した際にブラウザの更新ボタンを押せば、即座に編集内容が反映されます。
#「flask run」で起動
###(4−3)localhost:5000で開く
ブラウザで、「 http://localhost:5000 」を検索するとアプリが実行されます。
下のような画面になれば成功です。
最初にも言いましたが、年俸がマイナスになることは多々ありますが、決してエラーではなく、学習モデルが悪いだけです。
(終了)