今回研修で作成するシステム(AI家賃予測システム)
今回は前回構築してherokuに配備したモデルを家賃予想モデルに入れ替えます。それにあわせてクライアントも入れ替えます
前回構築したPythonAPIですが、修正点は学習済のモデルを入れ替えるだけです。
app.py
from joblib import dump, load
import flask
import numpy as np
from flask_cors import CORS
# initialize our Flask application and pre-trained model
app = flask.Flask(__name__)
CORS(app)
model = None
# 学習済モデルの読み込み
def load_model():
global model
print(" * Loading pre-trained model ...")
model = load("sample-model.pkl")
print(' * Loading end')
# 接続確認テスト用 getでrootにアクセスしたときに、Hello Worldを表示させる
@app.route('/')
def index():
return 'Hello World!'
# 機械学習結果返却処理
@app.route("/predict", methods=["POST"])
def predict():
model = load("sample-model.pkl") #このファイルを入れ替えます
response = {
"success": False,
"Content-Type": "application/json"
}
# ensure an feature was properly uploaded to our endpoint
if flask.request.method == "POST":
if flask.request.get_json().get("feature"):
# read feature from json
feature = flask.request.get_json().get("feature")
# preprocess for classification
# list -> np.ndarray
feature = np.array(feature).reshape((1, -1))
# classify the input feature
response["prediction"] = model.predict(feature).tolist()
# indicate that the request was a success
response["success"] = True
# return the data dictionary as a JSON response
return flask.jsonify(response)
if __name__ == "__main__":
load_model()
print(" * Flask starting server...")
app.run(host='0.0.0.0', port='8000')
サンプルを以下の機械学習モデルに入れ替えてみましょう(家賃を予測するモデル)
#家賃を予測する
import numpy as np
from sklearn import linear_model
#1次元目は面積 2次元目は階
X = np.array([
[7, 7.12, 7.2, 7.69, 7.79, 8, 8.28, 8.37, 8.7, 9.93, 10.5, 10.53, 11, 12.19, 12.4],
[2, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 3, 3, 1]
]).T
#家賃(千円単位)
Y = np.array([
[45, 51, 52, 53, 52.6, 52, 54, 54.2, 56, 64, 65, 72, 75, 78.3, 80]
]).T
model = linear_model.LinearRegression(fit_intercept=False)
model.fit(X, Y)
#面積8m² で3階にある部屋の家賃は?=>[[51.32707814]]
print(model.predict([[8, 3]]))
学習したモデルを保存するには、学習したモデルをdumpします
from sklearn import svm
from sklearn import datasets
from joblib import dump, load
# classifier
clf = svm.SVC()
iris = datasets.load_iris()
X, y = iris.data, iris.target
clf.fit(X, y)
dump(clf, 'sample-model.pkl')
下記のサンプルは4つの変数をAPIに渡す形なので、家賃について、予測する変数の数を渡すように修正します
注意)Herokuの無料枠はしばらく使っていないとスリープするので、クライアントの初回実行はちょっと時間がかかります
Controller
require 'json'
require 'net/https'
require "uri"
class ApiTestController < ApplicationController
def index
data={feature: [10, 20, 5, 1]} #このパラメタの数は変更になります
uri = URI.parse("http://syslink-ai-api.herokuapp.com/predict")
http = Net::HTTP.new(uri.host, uri.port)
req = Net::HTTP::Post.new(uri.path)
req.set_content_type("application/json")
req.body = data.to_json
res = http.request(req)
p res.code
#if res.code == Net::HTTPSuccess
if res.code == "200"
res_data = JSON.parse(res.body)
@prediction = res_data["prediction"]
end
end
end
View
<div class="container">
<!-- 表題 -->
<div class="content-title">
<h3><span class="title-style"><label>AI分析結果</label></span></h3>
</div>
<div class="well">
<h2>AI分析結果</h2>
<h1>あなたの評価は<%= @prediction %>です</h1>
</div>
</div>
main.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<p><input type="text" id="input1" value="0.74"></p>
<p><input type="text" id="input2" value="1.22"></p>
<p><input type="text" id="input3" value="1.22"></p>
<p><input type="text" id="input4" value="1.22"></p>
<button id="button">ボタン</button>
<p>結果:<span id="answer"></span></p>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script src="main.js"></script>
</body>
</html>
main.js
$(function(){
var url = 'http://syslink-ai-api.herokuapp.com/predict';
$('#button').on('click', function() {
var arays = []
arays.push(parseFloat($('#input1').val()));
arays.push(parseFloat($('#input2').val()));
arays.push(parseFloat($('#input3').val()));
arays.push(parseFloat($('#input4').val()));
console.log(arays);
// API連携
$.ajax({
type: 'POST', // 使用するHTTPメソッド
url : url, // 通信先URL
dataType: 'json', // レスポンスのデータタイプ
contentType: "application/json",
data: JSON.stringify({feature: arays}),
traditional: true
})
.done(function(data, textStatus, jqXHR) {
console.log(data.prediction[0]);
$('#answer').text(data.prediction[0]);
})
.fail(function(jqXHR, textStatus, errorThrown) {
console.log('通信が失敗しました');
});
});
});
main.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div id="app">
<p><input type="text" id="input1" value="10"></p>
<p><input type="text" id="input2" value="20"></p>
<p><input type="text" id="input3" value="5"></p>
<p><input type="text" id="input4" value="1"></p>
<button v-on:click="showData">ボタン</button>
<p>結果:<span id="answer"></span></p>
</div>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script src="https://jp.vuejs.org/js/vue.js"></script>
<script src="main.js"></script>
</body>
</html>
main.js
var app = new Vue({
el: '#app',
data: {
message: ''
},
methods: {
showData: function() {
var url = 'http://syslink-ai-api.herokuapp.com/predict';
var arays = []
arays.push(parseFloat($('#input1').val()));
arays.push(parseFloat($('#input2').val()));
arays.push(parseFloat($('#input3').val()));
arays.push(parseFloat($('#input4').val()));
console.log(arays);
// API連携
$.ajax({
type: 'POST', // 使用するHTTPメソッド
url : url, // 通信先URL
dataType: 'json', // レスポンスのデータタイプ
contentType: "application/json",
data: JSON.stringify({feature: arays}),
traditional: true
})
.done(function(data, textStatus, jqXHR) {
console.log(data.prediction[0]);
$('#answer').text(data.prediction[0]);
})
.fail(function(jqXHR, textStatus, errorThrown) {
console.log('通信が失敗しました');
})
}
}
});
Controller
require 'json'
require 'net/https'
require "uri"
class ApiTestController < ApplicationController
def index
if params[:input_form].present?
params[:input_form] = find_params.to_h
@input_form = InputForm.new(params)
data={feature: [params[:input_form][:area], params[:input_form][:floor]]}
uri = URI.parse("http://(your url)/predict")
http = Net::HTTP.new(uri.host, uri.port)
req = Net::HTTP::Post.new(uri.path)
req.set_content_type("application/json")
req.body = data.to_json
res = http.request(req)
p res.code
#if res.code == Net::HTTPSuccess
if res.code == "200"
res_data = JSON.parse(res.body)
@prediction = res_data["prediction"]
end
else
@input_form = InputForm.new(nil)
@prediction = ""
end
end
private
def find_params
params.require(:input_form).permit(:area, :floor)
end
end
view(index.html.erb)
<div class="container">
<!-- 表題 -->
<div class="content-title">
<h3><span class="title-style"><label>AI家賃予測</label></span></h3>
</div>
<%= form_for @input_form,url:{action: :index},html:{method: :get, class:'form-search'} do |f| %>
<div class="table-responsive">
<table class="table table-bordered">
<colgroup>
<col width="150px">
<col width="180px">
<col width="150px">
<col width="180px">
</colgroup>
<tr>
<td class="label-success" colspan="4">条件</td>
</tr>
<tr>
<td class="success middle">面積</td>
<td><%= f.text_field :area, class:"form-control" %></td>
<td class="success middle">階</td>
<td><%= f.text_field :floor, class:"form-control" %></td>
</tr>
</table>
</div>
<%= button_tag(type: 'submit', class: "btn btn-primary") do %>
<span>検索</span>
<% end %>
<% end %>
<div class="well">
<h2>予測結果</h2>
<% if @prediction.present? %>
<h1>家賃は<%= @prediction[0][0].to_i * 1000 %>円です</h1>
<% end %>
</div>
</div>
model(input_form.rb)
class InputForm
include ActiveModel::Model
attr_accessor :area
attr_accessor :floor
def initialize(params)
if params.present?
if params.is_a?(Hash)
@area = params["area"]
@floor = params["floor"]
else
@area = params[:input_form][:area]
@floor = params[:input_form][:floor]
end
end
end
end
実行した画面
上記の家賃を予測するシステムが作成したら、今度は松江家賃.csvを学習したモデルに書き換えて、松江の家賃を予測するシステムにしましょう 上記のモデルはプログラムの中に配列のデータを持っていますが、そこをpandasでcsvをデータフレームに読み込んで、学習させます
下記のサンプルは広さと何階かを入力としていますが、色々変えてみてください
#家賃を予測する
import pandas as pd
from sklearn import linear_model
df = pd.read_csv("松江家賃.csv", encoding="cp932")
X = df[["広さ", "階"]]
Y = df["家賃"]
model = linear_model.LinearRegression(fit_intercept=False)
model.fit(X, Y)
#面積47.7m² で1階にある部屋の家賃は?=>[1.70486347]
print(model.predict([[47.7, 1]]))