こんにちはみなさん
ちょっと前にPHPでニューラルネットワークを作ってみて、だいたい何やっているのかを検証してみました。
とはいえ、現在色んな所で検証・実践され、洗練された計算手法みたいのは一切ないので、遅い上に制度もあまり良くはありませんでした。
そこで今回は、Kerasというフレームワークを使って、イマドキの機械学習機構を試してみます。
Keras
KerasはTensorFlow上で動くニューラルネットワークライブラリで、Pythonで書かれています。
使ってみた感覚では、直感に任せてネットワークが書けそうだなぁ、って思いました。
TensorFlowを生で書くと、色々パラメータの設定が面倒くさかったのですが、
その辺もやりやすくなってました。
Keras on Docker
ああ、やっぱりあるんですよね、Keras入りのイメージ
https://hub.docker.com/r/gw000/keras/
これで、自分の環境を汚すことなく、Kerasを試すことができます。
問題設定
問題設定は以前やったドーナッツ型の分類問題です。
{f(x, y) = \left\{
\begin{array}{1}
1, (1 < x^2 + y^2 < 4)\\
0, ( \rm{otherwise} )
\end{array}
\right.
}
実装
やりたいことを決めたので、実装を初めましょう
学習機構
まずは学習機構から作ります。
from keras.models import Sequential
from keras.layers import Dense, Activation
import numpy as np
import random
import math
def double_circle():
x = random.uniform(-2, 2)
y = random.uniform(-2, 2)
sample = (x,y)
norm = math.sqrt(x * x + y * y)
if norm > 1 and norm < 2:
label = 1
else:
label = 0
return (sample, label)
# Model Definition
model = Sequential()
model.add(Dense(32, input_dim=2))
model.add(Dense(64, activation='relu'))
model.add(Dense(32, activation='relu'))
model.add(Dense(1, activation='sigmoid'))
model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['accuracy'])
data = []
labels = []
for num in range(1024):
(sample, label) = double_circle()
data.append(sample)
labels.append(label)
model.fit(np.array(data), np.array(labels), nb_epoch=100, batch_size=32)
model.save('/srv/model/double_circle')
関数double_circle
を使って、ランダムな座標を選び、その点がドーナッツ図形の内部にあるかどうかを判断したラベルを返します。
そして、座標とラベルの組をリストに投入していきます。
次にモデルを作るわけですが、Kerasはニューラルネットワークの各層を積んでいくイメージでモデルを形成していきます。
model.add(Dense(32, input_dim=2))
model.add(Dense(64, activation='relu'))
例えば、ここは第1層と第2層を定義しています。
第1層は入力次元がわからないので、ちゃんと明示しています。今回は座標点が入力なので、input_dim=2
を入れます。
第1層の第1引数が出力次元になっているので、第2層は入力次元がいりません。
また、第2層の活性化関数にactivation='relu'
設定しています( 設定がない場合はそのまま出力 )。
こんな感じで好きなように層を積んでいけます。
$ docker run --rm -v `pwd`:/srv/ gw000/keras python learn.py
KerasのDockerコンテナを動かしてみて、学習させてみましょう。
私のMacで大体5秒くらいで終わりました。
modelディレクトリにモデルファイルが生成されています。
生成モデルの利用
生成したモデルが、どの程度うまく行っているのか確かめてみましょう。
from keras.models import load_model
import numpy as np
model = load_model('/srv/ai/model/double_circle')
def check(x):
data = np.array([x])
pred = model.predict(np.array([x]))
#print pred
if pred > 0.5:
return 1
else:
return 0
for y in range(20):
labels = []
for x in range(20):
data = [(x-10.0)/5, (10.0-y)/5]
labels.append(check(data))
print labels
Kerasはモデルをロードするだけで、learnで学習したときのネットワークを再現してくれます。
このスクリプトはロードしたモデルを使って、$-2< x < 2$, $-2 < y <2$の範囲を0.1刻みで指定の領域に入っているかどうかを判別します。
こいつを実行すると、こんな感じになります。
$ docker run --rm -v `pwd`:/srv/ gw000/keras python use.py
[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0]
[0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0]
[0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0]
[0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0]
[0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1]
[0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1]
[1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1]
[1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1]
[1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1]
[1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1]
[1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1]
[1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1]
[0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0]
[0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0]
[0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0]
[0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0]
[0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0]
丸い形が浮かび上がっているので、うまく行っている気がしないでもないですね。
もうちょい細かく点を取ってみましょう。
今度は0.02刻みでデータ点を取ってみます。
今回は領域に含まれると判断される座標点をCSV形式で吐き出すようにしてみます
from keras.models import load_model
import numpy as np
model = load_model('/srv/model/double_circle')
def check(x):
data = np.array([x])
pred = model.predict(np.array([x]))
#print pred
if pred > 0.5:
return 1
else:
return 0
for y in range(100):
for x in range(100):
data = [(x-50.0)/20, (50.0-y)/20]
if check(data) == 1:
print "%f,%f" % (data[0],data[1])
で、例によってdockerで処理します。
docker run --rm -v `pwd`:/srv/ gw000/keras python to_csv.py > result.csv
出てきたresult.csvをplotしてみましょう。
まあ、こんなものかもしれませんね
まとめ
とりあえずKerasを始めるために、以前に自分がPHPで作ったやつをこちらで実現してみました。
ネットワークや層を組み立てるのなら、TensorFlowよりもわかりやすいですね。
今回はこんなところです。