FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

TensorFlowを使って分類アルゴリズムを実装する

ITエンジニアのための機械学習理論入門

ITエンジニアのための機械学習理論入門

機械学習の次の分野として、分類アルゴリズムの勉強をしてみよう。分類アルゴリズムの中で、「パーセプトロン」は分類アルゴリズムの手法で、誤差関数を利用したアルゴリズムだ。

http://tensorflow.org/tutorials/pdes/index.md

今回は、上記の書籍の例を参考にして、2つのデータの分類から、それを分割する一次方程式を算出してみよう。 下記のように、

  • データ1 : 20個 (中心 X=10, Y=25, データ範囲15)
  • データ1 : 30個 (中心 X= 0, Y=15, データ範囲15)

f:id:msyksphinz:20151123023103p:plain

分類アルゴリズムの定式化

まずは、パラメータを定義しよう。ここでは、上記の書籍に従って、一次方程式を定義する。W[0], W[1], W[2]を算出することになる。

{
f(x,y) = W_2+W_1x+W_2y = 0
}

分割する方程式に対して、

  • 上側に分類されるデータ

    • データが直線の上側に存在する(正解) : 0
    • データが直線の下側に存在する(不正解) : 直線までの距離(正の数)
  • 下側に分類されるデータ

    • データが直線の下側に存在する(正解) : 0
    • データが直線の上側に存在する(不正解) : 直線までの距離(正の数)

とする。この関数を誤差関数として、これを最小化(→0)とするように学習させれば良い訳だ。

誤差関数

{
tmp = W_2+W_1x+W_2y\
}

{
loss = (tmp\times t > 0.0) ? 0.0 : -tmp\times t
}

ここで、上側に分類されるべきデータはt=1.0、下側に分類されるべきデータはt=-1.0とする。 すると、逆側にグループ化された場合(つまり負の数になる)と、正の数に変換して誤差とする。これを最小化する。

W = tf.Variable(tf.zeros([3]))
X = tf.placeholder("float", [3])
t = tf.placeholder("float")

y = tf.reduce_sum(tf.mul(W, X))
loss = tf.reduce_mean(tf.select(tf.greater(t*y, 0.0), 0.0, -t*y))

学習させる

まずは上側のデータを学習させ、下側のデータを学習させる。train_stepの引数として、

  • W : 現在の学習中パラメータ(W[0],W[1],W[2])
  • t : どちら側に分類されるべきか(t=1.0:上側、t=-1.0:下側)

とする。これを1000回繰替えして収束させていく。

for j in range(1000):
    for i in range(N1-1):
        next_grp = sess.run(grp0)[i]
        sess.run(train_step, feed_dict={X:next_grp, t: 1.0})
    for i in range(N2-1):
        next_grp = sess.run(grp1)[i]
        sess.run(train_step, feed_dict={X:next_grp, t: -1.0})

学習結果から得られた直線のパラメータ

実行結果から、以下の結果が得られた。

$ python perceptron.py
I tensorflow/core/common_runtime/local_device.cc:25] Local device intra op parallelism threads: 1
I tensorflow/core/common_runtime/local_session.cc:45] Local session inter op parallelism threads: 1
11.8301645736 33.7975375936
6.3721922867 20.0283013408
9.54279120396 20.5036238957
8.93012794294 25.4320740275
12.4558098147 24.1691295696
11.712123013 30.9916721474
7.96224594242 28.1186272312
-1.14441878366 20.1146535213
15.3815303446 16.3311509242
16.2858485809 28.276399798
11.318138601 32.5024510104
15.3145841787 33.169439917
9.86939868644 26.3050355861
5.65680444998 15.1521841596
8.99577395706 22.4053180223
1.27422690763 20.0788538154
16.2900669629 33.7956193422
6.34090862522 23.4361873553
8.274108156 24.7673157933

-1.03228478785 12.6707847273
-7.35302555303 10.0511432871
-13.0486602449 7.92992577728
-2.98514937222 1.52491558936
-2.96723904458 8.56845709249
0.947990357606 14.9240248797
1.42585958649 10.1330678777
2.23229826647 11.1247983005
3.02170577393 22.4440187862
3.22232243421 18.9654572865
-9.43096963229 5.17501555756
-7.87980106919 10.5603534195
-0.837600937693 -1.67276942188
-12.5366588778 3.34004169407
5.21500569061 20.765034053
0.675640920862 7.39868575156
-1.25457104952 9.37773237113
-1.66071067421 7.91445975321
-2.0735161238 7.17806619728
-4.44019379412 3.57946865387
-5.86664078923 16.1019402766
-0.454096769706 2.15289934949
-2.34753011619 1.2671985078
-1.55799390941 2.16329891383
7.21918787827 11.3084523064
-2.23623650298 18.1374053032
-12.6823310581 14.4050839961
7.3731135749 7.98695716502
4.1782871166 11.4991252024
answer =
[ 0.51865494  0.15567437 -6.20004702]

得られたパラメータは、 - W[0] = 0.51865494 - W[1] = 0.15567437 - W[2] = -6.20004702

早速Excelに書いて表示させてみた。

f:id:msyksphinz:20151123023027p:plain

お、色がちょっと薄くなっているが、ちゃんと分類できている!

ソースコード

import tensorflow as tf
import numpy as np
import random
import math

N1 = 20
Mu1 = [10,25]

N2 = 30
Mu2 = [0, 10]

Variances = 15

group0 = []
group1 = []

for idx in range(0, N1-1):
    radius = Variances * np.random.random()
    radian = np.random.uniform(0, 2*math.pi)
    x = radius * math.cos(radian) + Mu1[0]
    y = radius * math.sin(radian) + Mu1[1]

    group0.append([x, y, 1.0])

for idx in range(0, N2-1):
    radius = Variances * np.random.random()
    radian = np.random.uniform(0, 2*math.pi)
    x = radius * math.cos(radian) + Mu2[0]
    y = radius * math.sin(radian) + Mu2[1]

    group1.append([x, y, 1.0])

grp0 = tf.Variable(group0)
grp1 = tf.Variable(group1)


W = tf.Variable(tf.zeros([3]))
X = tf.placeholder("float", [3])
t = tf.placeholder("float")

y = tf.reduce_sum(tf.mul(W, X))
loss = tf.reduce_mean(tf.select(tf.greater(t*y, 0.0), 0.0, -t*y))

init = tf.initialize_all_variables()
sess = tf.Session()
sess.run(init)

train_step = tf.train.GradientDescentOptimizer(0.01).minimize(loss)

# print sess.run(loss, feed_dict={W:[3., 2., -10.], X:[5., 5., 1], t:-1.0})
# print sess.run(grp0)[0]

for j in range(1000):
    for i in range(N1-1):
        next_grp = sess.run(grp0)[i]
        sess.run(train_step, feed_dict={X:next_grp, t: 1.0})
    for i in range(N2-1):
        next_grp = sess.run(grp1)[i]
        sess.run(train_step, feed_dict={X:next_grp, t: -1.0})


for idx in range(0, N1-1):
    print group0[idx][0], group0[idx][1]
print ""
for idx in range(0, N2-1):
    print group1[idx][0], group1[idx][1]


print "answer = "
print sess.run(W)