6
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Flaskで人工知能アプリ:メジャーリーガー年俸予測(1992)

Last updated at Posted at 2019-06-14

#Flaskを使って年俸を予測してみた。
コードはこちらからダウンロード可能です。(GitHub)
緑色の「Clone or Download」をクリックして、「Download ZIP」をクリックするとダウンロードできます。
(このように、「そんなの言われなくてもわかってる」という内容まで書いてあるところもありますので、僕同様に初心者の方も少しはわかりやすくなっていると思います。)

スクリーンショット 2019-06-14 午後21.11.54 午後.png
スクリーンショット 2019-06-14 午後21.53.26 午後.png

[注意]

  • データ数が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()

[実行結果]
スクリーンショット 2019-06-14 午後21.37.13 午後.png

##(2)Flask側
以下のコードはCotEditorで書いています。(ファイル名:baseball_sarary.py)
コードがかければCotEditorである必要は全くないですが、jupyterで実行するわけではありません。

baseball_sarary.py
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 」を検索するとアプリが実行されます。
下のような画面になれば成功です。
最初にも言いましたが、年俸がマイナスになることは多々ありますが、決してエラーではなく、学習モデルが悪いだけです。
スクリーンショット 2019-06-15 8.46.39.png

(終了)

6
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?