LoginSignup
6
3

More than 5 years have passed since last update.

[Keras]ドーナッツ型領域分類問題を機械学習で解いてみた[習作]

Posted at

こんにちはみなさん

ちょっと前に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.
}

double_circle.png

実装

やりたいことを決めたので、実装を初めましょう

学習機構

まずは学習機構から作ります。

learn.py
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ディレクトリにモデルファイルが生成されています。

生成モデルの利用

生成したモデルが、どの程度うまく行っているのか確かめてみましょう。

use.py
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形式で吐き出すようにしてみます

to_csv.py
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してみましょう。
result.png
まあ、こんなものかもしれませんね

まとめ

とりあえずKerasを始めるために、以前に自分がPHPで作ったやつをこちらで実現してみました。
ネットワークや層を組み立てるのなら、TensorFlowよりもわかりやすいですね。

今回はこんなところです。

参考

公式サイト

6
3
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
3