TensorFlowを使ってIoTデータを人工知能してみるの練習用に、学習と判定を繰り返し行えるよう、それぞれ別のportを開けてPOSTできるようにしました。また練習用にFisherのiris data setを使用します。
1. TensorFlowを準備します
-
BluemixのDockerコンテナ環境にTensorFlowをインストールするを参照し、Bluemix環境にTensorFlowを準備します
-
「デプロイ」ステージを構成するステップで、portとして、8888以外に、6006,9000,9001も開けておくようにします
-
ビルド⇨デプロイが完了すると下記のような画面が表示されます。デプロイの「最終実行の結果」欄に表示される外向け(パブリック)IPアドレスを確認します
-
Bluemixのダッシュボードから、デプロイされたDockerコンテナーを開き、パブリックIPアドレス(前項と同じ)とプライベートIPアドレスを確認します
-
Chromeなどのブラウザで上記のパブリックIPアドレスの8888ポートへアクセスします。画面右上の「New」プルダウンメニューから「Terminal」でターミナル画面を開きます。
-
このページでご紹介しているサンプルを実行するため、表示されたターミナル画面でflaskとpandasをインストールします。flaskは
pip istall flask
などで、pandasはpip install pandas
などでインストール可能です
-
続いて作成したフォルダー内に入り、同様に画面右上の「New」プルダウンメニューからText Fileを作成し、このページの下記のセクションにあるサンプルのpythonプログラムをコピペしていきます
2. サンプルを準備します
- 用意したTensorFlow環境に下記のソースを配置します。
-
model.py
でモデルを定義します- 隠れ層2でそれぞれ32、16個のReLuで構成しています
-
COLUMN_SIZE
に対象にするデータの項目数を指定します。iris data setでは、'Sepal Length', 'Sepal Width', 'Petal Length', 'Petal Width'を対象にしています -
actual_class
に判定に使用する目的変数の項目数を指定します。iris data setでは setosa = 0, versicolor = 1, virginica = 2の3個の値を使用しています - ここではGradientDescentOptimizerを使用していますが、AdamOptimizerなど異なるアルゴリズムを使用する事も可能です
- 学習30回毎に学習とテストの精度を出力します
- その他詳細はTensorFlowのTutorialをご参照ください
# -*- coding: utf-8 -*-
import tensorflow as tf
import numpy as np
import os
class Model:
HIDDEN_UNIT_SIZE = 32
HIDDEN_UNIT_SIZE2 = 16
# 対象データの項目数
COLUMN_SIZE = 4
def __init__(self):
self.__setup_placeholder()
self.__setup_model()
self.__setup_ops()
def __enter__(self):
self.session = tf.Session()
return self
def __exit__(self, exc_type, exc_value, traceback):
self.session.close()
return False
def save(self, path):
saver = tf.train.Saver()
saver.save(self.session, path)
def restore(self, path):
saver = tf.train.Saver()
saver.restore(self.session, path)
def __setup_placeholder(self):
column_size = Model.COLUMN_SIZE
self.iot_data = tf.placeholder("float", [None, column_size])
# 目的変数が3値
self.actual_class = tf.placeholder("float", [None, 3])
self.keep_prob = tf.placeholder("float")
self.label = tf.placeholder("string")
def __setup_model(self):
column_size = Model.COLUMN_SIZE
w1 = tf.Variable(tf.truncated_normal([column_size, Predictor.HIDDEN_UNIT_SIZE], stddev=0.1))
b1 = tf.Variable(tf.constant(0.1, shape=[Predictor.HIDDEN_UNIT_SIZE]))
h1 = tf.nn.relu(tf.matmul(self.iot_data, w1) + b1)
w2 = tf.Variable(tf.truncated_normal([Predictor.HIDDEN_UNIT_SIZE, Predictor.HIDDEN_UNIT_SIZE2], stddev=0.1))
b2 = tf.Variable(tf.constant(0.1, shape=[Predictor.HIDDEN_UNIT_SIZE2]))
h2 = tf.nn.relu(tf.matmul(h1, w2) + b2)
h2_drop = tf.nn.dropout(h2, self.keep_prob)
# 目的変数が3値
w2 = tf.Variable(tf.truncated_normal([Predictor.HIDDEN_UNIT_SIZE2, 3], stddev=0.1))
# 目的変数が3値
b2 = tf.Variable(tf.constant(0.1, shape=[3]))
self.output = tf.nn.softmax(tf.matmul(h2_drop, w2) + b2)
def __setup_ops(self):
cross_entropy = -tf.reduce_sum(self.actual_class * tf.log(self.output))
self.summary = tf.scalar_summary(self.label, cross_entropy)
# 異なるアルゴリズムを使用
# self.train_op = tf.train.AdamOptimizer(0.0001).minimize(cross_entropy)
self.train_op = tf.train.GradientDescentOptimizer(0.0001).minimize(cross_entropy)
self.merge_summaries = tf.merge_summary([self.summary])
correct_prediction = tf.equal(tf.argmax(self.output,1), tf.argmax(self.actual_class,1))
self.accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
class Trainer(Model):
def train(self, steps, data):
self.__prepare_train(self.session)
for i in range(steps):
self.__do_train(self.session, i, data)
if i %20 == 0:
self.__add_summary(self.session, i, data)
self.__print_status(self.session, i, data)
def __prepare_train(self, session):
self.summary_writer = tf.train.SummaryWriter('logs', graph=session.graph)
if not os.path.exists("./model.ckpt"):
session.run(tf.initialize_all_variables())
print 'variables initialized'
def __do_train(self, session, i, data):
session.run(self.train_op, feed_dict=self.train_feed_dict(data))
def __add_summary(self, session, i, data):
summary_str = session.run(self.merge_summaries, feed_dict=self.train_feed_dict(data))
summary_str += session.run(self.merge_summaries, feed_dict=self.test_feed_dict(data))
self.summary_writer.add_summary(summary_str, i)
def __print_status(self, session, i, data):
train_accuracy = session.run(self.accuracy, feed_dict=self.train_feed_dict(data))
test_accuracy = session.run(self.accuracy, feed_dict=self.test_feed_dict(data))
print 'step {} ,train_accuracy={} ,test_accuracy={} '.format(i, train_accuracy, test_accuracy)
def train_feed_dict(self, data):
return {
self.iot_data: data.train_data(),
self.actual_class: data.train_up_down(),
self.keep_prob: 0.8,
self.label: "train"
}
def test_feed_dict(self, data):
return {
self.iot_data: data.test_data(),
self.actual_class: data.test_up_down(),
self.keep_prob: 1,
self.label: "test"
}
class Predictor(Model):
def predict( self, data ):
return self.session.run(tf.argmax(self.output,1), feed_dict=self.predict_feed_dict(data))
def predict_feed_dict(self, data):
return {
self.iot_data: data,
self.keep_prob: 1,
self.label: "predict"
}
-
iot_results_loader.py
で学習用のデータをロードします-
outcome
項で結果を定義しています - 全体の2/3を学習データに、1/3をテストデータに使用しています
-
# -*- coding: utf-8 -*-
import pandas as pd
class IoTResults:
def __float__(data):
return 1.0
def __init__(self, data):
self.raw = data.copy()
self.data = data
def predictor_data(self):
return self.data
def train_data(self):
return self.__drop_outcome(self.__train_data())
def test_data(self):
return self.__drop_outcome(self.__test_data())
def train_up_down(self):
return self.__good_bad(self.__train_data()["outcome"])
def test_up_down(self):
return self.__good_bad(self.__test_data()["outcome"])
def __train_data(self):
# 全データの 2/3 を訓練データとして使用
return self.data.loc[lambda df: df.index % 3 != 0, :]
def __test_data(self):
# 全データの 1/3 をテストデータとして使用
return self.data.loc[lambda df: df.index % 3 == 0, :]
def __drop_outcome(self, data):
return data.drop("outcome", axis=1)
def __good_bad(self, outcome):
return outcome.apply(
lambda p: pd.Series([
1 if p <= 0 else 0,
1 if p ==1 else 0,
1 if p > 1 else 0
], index=['setosa', 'versicolor', 'virginica']))
class IoTResultsLoader:
def retrieve_iot_data(self, data):
df = pd.DataFrame(data)
return df
-
trainer.py
へ学習用データをPOSTします- flaskで9000ポートでアクセスします。TenserFlowのDockerコンテナのデプロイによりBluemixから提供されるIPアドレスのうち、パブリックIPを使用してブラウザからアクセスします。flaskサーバーはプライベートIPへ向け9000ポートを開けます
- 必要に応じ学習回数を変更して試してみます
- 学習結果が./model.ckptに保存されます
# -*- coding: utf-8 -*-
import os
import pandas as pd
from flask import Flask, jsonify, request
from iot_results_loader import *
from model import *
trainer = Trainer()
trainer.__enter__()
if os.path.exists("./model.ckpt"):
trainer.restore("./model.ckpt")
loader = IoTResultsLoader()
# webapp
app = Flask(__name__)
@app.route('/api/trainer', methods=['POST'])
def train():
data2 = pd.DataFrame(eval(request.data))
data3 = IoTResults(loader.retrieve_iot_data(data2))
# 学習回数
trainer.train(60, data3)
trainer.save("./model.ckpt")
return 'train done'
if __name__ == '__main__':
app.run(host='172.xx.xx.xx', port=9000)
-
predictor.py
へ判定用データを送付し結果を確認します- flaskで9001ポートでアクセスします。TenserFlowのDockerコンテナのデプロイによりBluemixから提供されるIPアドレスのうち、パブリックIPを使用してブラウザからアクセスします。flaskサーバーはプライベートIPへ向け9000ポートを開けます
# -*- coding: utf-8 -*-
import os
import pandas as pd
from flask import Flask, jsonify, request
from iot_results_loader import *
from model import *
predictor = Predictor()
# webapp
app = Flask(__name__)
@app.route('/api/predictor', methods=['POST'])
def predict():
predictor.__enter__()
if os.path.exists("./model.ckpt"):
predictor.restore("./model.ckpt")
data = pd.DataFrame(eval(request.data))
results = predictor.predict(IoTResults(data).predictor_data().iloc[[0]])
predictor.__exit__(1,1,0)
return jsonify(result=("2 virginica!" if results[0] == 2 else "1 versicolor!" if results[0] == 1 else "0 setosa!"))
if __name__ == '__main__':
app.run(host='172.xx.xx.xx', port=9001)
- Node-REDのフローを用意します。フロー中の「trainerへ」と「predictorへ」のhttpノードを開き、前出のパブリックIPアドレスを指定します
[{"id":"7283e6b5.d9c0b","type":"http request","z":"97be8461.26496","name":"predictorへ","method":"POST","ret":"txt","url":"http://xx.xx.xx.xx:9001/api/predictor","tls":"","x":570,"y":280,"wires":[["8bdeafef.6ac928"]]},{"id":"c306faf.2136088","type":"inject","z":"97be8461.26496","name":"起動","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":110,"y":240,"wires":[["72f86ec9.57bc"]]},{"id":"72f86ec9.57bc","type":"template","z":"97be8461.26496","name":"iris test: 0 setosa","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{'Sepal Length': [4.9], 'Sepal Width':[3.1], 'Petal Length':[1.5], 'Petal Width':[0.1]}","x":330,"y":240,"wires":[["7283e6b5.d9c0b"]]},{"id":"2d37564e.bc98fa","type":"template","z":"97be8461.26496","name":"iris test: 1 versicolor","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{'Sepal Length': [5], 'Sepal Width':[2.3], 'Petal Length':[3.3], 'Petal Width':[1]}","x":340,"y":280,"wires":[["7283e6b5.d9c0b"]]},{"id":"977c9b69.d200d","type":"template","z":"97be8461.26496","name":"iris test: 2 virginica","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{'Sepal Length': [6.4], 'Sepal Width':[2.8], 'Petal Length':[5.6], 'Petal Width':[2.2]}","x":330,"y":320,"wires":[["7283e6b5.d9c0b"]]},{"id":"8f973a5b.a6df7","type":"inject","z":"97be8461.26496","name":"起動","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":110,"y":280,"wires":[["2d37564e.bc98fa"]]},{"id":"9d96a668.46b6a8","type":"inject","z":"97be8461.26496","name":"起動","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":110,"y":320,"wires":[["977c9b69.d200d"]]},{"id":"1e9bc0f2.e7629f","type":"http request","z":"97be8461.26496","name":"trainerへ","method":"POST","ret":"txt","url":"http://xx.xx.xx.xx:9000/api/trainer","tls":"","x":560,"y":120,"wires":[["74e86540.88dde4"]]},{"id":"8bdeafef.6ac928","type":"function","z":"97be8461.26496","name":"取り出し","func":"var data = JSON.parse(msg.payload);\nmsg.payload = data.result;\nreturn msg;\n","outputs":1,"noerr":0,"x":720,"y":280,"wires":[["5305aeb5.15d38"]]},{"id":"5305aeb5.15d38","type":"template","z":"97be8461.26496","name":"出力","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"これは {{payload}} ですね!","x":570,"y":360,"wires":[["a0a1c21a.92fd08"]]},{"id":"a0a1c21a.92fd08","type":"debug","z":"97be8461.26496","name":"","active":true,"console":"false","complete":"false","x":730,"y":360,"wires":[]},{"id":"f1d8f1f3.86eac","type":"template","z":"97be8461.26496","name":"iris training","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":" {'Sepal Length': [6.4,5,4.9,4.9,5.7,4.4,5.4,6.9,6.7,5.1,5.2,6.9,5.8,5.4,7.7,6.3,6.8,7.6,6.4,5.7,6.7,6.4,5.4,6.1,7.2,5.2,5.8,5.9,5.4,6.7,6.3,5.1,6.4,6.8,6.2,6.9,6.5,5.8,5.1,4.8,7.9,5.8,6.7,5.1,4.7,6,4.8,7.7,4.6,7.2,5,6.6,6.1,5,7,6,7.4,5.8,6.2,5,5.6,6.7,6.3,6.4,6.2,7.3,4.4,7.2,6.5,5,4.7,6.6,5.5,7.7,6.1,4.9,5.5,5.7,6,6.4,5.4,6.1,6.5,5.6,6.3,4.9,6.8,5.7,6,5,6.5,6.1,5.1,4.6,6.5,4.6,4.6,7.7,5.9,5.1,4.9,4.9,4.5,5.8,5,5.2,5.3,5,5.6,4.8,6.3,5.7,5,6.3,5,5.5,5.7,4.4,4.8,5.5,5.9,6.9,5.1,6,5.5,6.2,5.5,6.3,5.6,6.7,7.1,4.3,5.6,5.5,6,5.1,5.7,4.8,5.1,5.7,5.4,5.6,6.3,6.3,5.8,6.1,5.2,6.7,6.7,6.4],\n 'Sepal Width': [2.8,2.3,2.5,3.1,3.8,3.2,3.4,3.1,3.1,3.7,2.7,3.1,4,3.9,3.8,3.3,3.2,3,3.2,4.4,3.3,2.8,3.9,2.6,3,3.5,2.6,3,3,3,2.3,2.5,3.2,3,2.8,3.2,3.2,2.8,3.8,3,3.8,2.7,3,3.8,3.2,2.2,3.4,2.6,3.6,3.2,3.3,3,2.8,3.2,3.2,3,2.8,2.7,3.4,2,2.5,3.1,2.5,3.1,2.2,2.9,3,3.6,3,3.4,3.2,2.9,3.5,3,3,3.1,2.4,2.9,2.9,2.7,3.7,2.9,2.8,2.7,3.4,3.1,2.8,2.8,2.7,3.5,3,2.8,3.5,3.1,3,3.4,3.2,2.8,3.2,3.8,3,2.4,2.3,2.7,3.4,3.4,3.7,3.6,2.9,3.1,2.7,2.8,3,3.3,3.5,2.6,3,2.9,3,2.4,3,3.1,3.3,3.4,2.5,2.9,4.2,2.8,3,2.5,3,3,2.8,2.3,2.2,3.5,2.6,3.4,3.4,2.5,3.4,3,2.9,2.5,2.7,3,4.1,3.1,3.3,2.9],\n 'Petal Length': [5.6,3.3,4.5,1.5,1.7,1.3,1.5,5.1,4.4,1.5,3.9,4.9,1.2,1.7,6.7,4.7,5.9,6.6,5.3,1.5,5.7,5.6,1.3,5.6,5.8,1.5,4,5.1,4.5,5,4.4,3,4.5,5.5,4.8,5.7,5.1,5.1,1.5,1.4,6.4,5.1,5.2,1.9,1.6,5,1.6,6.9,1,6,1.4,4.4,4,1.2,4.7,4.8,6.1,5.1,5.4,3.5,3.9,5.6,5,5.5,4.5,6.3,1.3,6.1,5.5,1.5,1.3,4.6,1.3,6.1,4.9,1.5,3.8,4.2,4.5,5.3,1.5,4.7,4.6,4.2,5.6,1.5,4.8,4.5,5.1,1.3,5.2,4.7,1.4,1.5,5.8,1.4,1.4,6.7,4.8,1.6,1.4,3.3,1.3,4.1,1.6,1.4,1.5,1.4,3.6,1.6,4.9,4.1,1.6,6,1.6,4.4,4.2,1.4,1.4,3.7,4.2,5.4,1.7,4.5,4,4.3,1.4,5.1,4.1,5.8,5.9,1.1,4.9,4,4,1.4,3.5,1.9,1.5,5,1.7,4.5,5.6,4.9,3.9,4.6,1.5,4.7,5.7,4.3],\n 'Petal Width': [2.2,1,1.7,0.1,0.3,0.2,0.4,2.3,1.4,0.4,1.4,1.5,0.2,0.4,2.2,1.6,2.3,2.1,2.3,0.4,2.1,2.1,0.4,1.4,1.6,0.2,1.2,1.8,1.5,1.7,1.3,1.1,1.5,2.1,1.8,2.3,2,2.4,0.3,0.3,2,1.9,2.3,0.4,0.2,1.5,0.2,2.3,0.2,1.8,0.2,1.4,1.3,0.2,1.4,1.8,1.9,1.9,2.3,1,1.1,2.4,1.9,1.8,1.5,1.8,0.2,2.5,1.8,0.2,0.2,1.3,0.2,2.3,1.8,0.1,1.1,1.3,1.5,1.9,0.2,1.4,1.5,1.3,2.4,0.1,1.4,1.3,1.6,0.3,2,1.2,0.3,0.2,2.2,0.3,0.2,2,1.8,0.2,0.2,1,0.3,1,0.4,0.2,0.2,0.2,1.3,0.2,1.8,1.3,0.2,2.5,0.6,1.2,1.2,0.2,0.1,1,1.5,2.1,0.5,1.6,1.3,1.3,0.2,1.5,1.3,1.8,2.1,0.1,2,1.3,1,0.2,1,0.2,0.2,2,0.2,1.5,1.8,1.5,1.2,1.4,0.1,1.5,2.5,1.3],\n 'outcome': [2,1,2,0,0,0,0,2,1,0,1,1,0,0,2,1,2,2,2,0,2,2,0,2,2,0,1,2,1,1,1,1,1,2,2,2,2,2,0,0,2,2,2,0,0,2,0,2,0,2,0,1,1,0,1,2,2,2,2,1,1,2,2,2,1,2,0,2,2,0,0,1,0,2,2,0,1,1,1,2,0,1,1,1,2,0,1,1,1,0,2,1,0,0,2,0,0,2,1,0,0,1,0,1,0,0,0,0,1,0,2,1,0,2,0,1,1,0,0,1,1,2,0,1,1,1,0,2,1,2,2,0,2,1,1,0,1,0,0,2,0,1,2,1,1,1,0,1,2,1]}","x":310,"y":120,"wires":[["1e9bc0f2.e7629f"]]},{"id":"6027aa75.7a7a24","type":"inject","z":"97be8461.26496","name":"起動","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":110,"y":120,"wires":[["f1d8f1f3.86eac"]]},{"id":"74e86540.88dde4","type":"debug","z":"97be8461.26496","name":"","active":true,"console":"false","complete":"false","x":730,"y":120,"wires":[]},{"id":"d1575987.34ea48","type":"comment","z":"97be8461.26496","name":"学習用フロー","info":"","x":90,"y":80,"wires":[]},{"id":"bc6ca509.b1321","type":"comment","z":"97be8461.26496","name":"判定用フロー","info":"","x":90,"y":200,"wires":[]}]
3. 実行します
-
python -m tensorflow.tensorboard --logdir=./logs
などでtensorboardを稼働しブラウザで6006ポートへアクセスして学習の状況などを確認します。IPアドレスはTenserFlowのDockerコンテナのデプロイによりBluemixから提供されるIPアドレスのうち、パブリックIPを使用してブラウザからアクセスします。
参考
TensorFlowを使った為替(FX)のトレードシステムを作るチュートリアルを大変参考にさせていただきました。どうもありがとうございます。