ソフトマックス関数で3色の分類を実施してみました。
お決まりのモジュールのインポートです。
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
from numpy.random import multivariate_normal, permutation
import pandas as pd
from pandas import DataFrame, Series
np.random.seed(20170426)
#青のデータセット
num_train0=100
x0=np.random.normal(-1.5,1.3,num_train0)
t0=np.zeros((num_train0,3))
df0=DataFrame(np.c_[x0,t0],columns=['x','blue','red','green'])
df0['blue']=1
#赤のデータセット
num_train1=100
x1=np.random.normal(0.5,0.8,num_train1)
t1=np.zeros((num_train1,3))
df1=DataFrame(np.c_[x1,t1],columns=['x','blue','red','green'])
df1['red']=1
#緑のデータセット
num_train2=100
x2=np.random.normal(3.5,1.2,num_train2)
t2=np.zeros((num_train2,3))
df2=DataFrame(np.c_[x2,t2],columns=['x','blue','red','green'])
df2['green']=1
#繋ぎあわせて一つのデータフレームにします
df=pd.concat([df0,df1,df2],ignore_index=True)
df=df.reindex(permutation(df.index)).reset_index(drop=True)
#データフレームから行列変換します。train_tはOne-Hot表現にしています。
train_x=df['x'].as_matrix().reshape([len(df),1])
train_t=df[['blue','red','green']].as_matrix().reshape([len(df),3])
冗長ですが散布図を描いてみました。縦軸に意味はありません。
値の小さい方から青→赤→緑となっていますが、その境目は渾然としています。
この境界をソフトマックス関数で決定しようというのが狙いです。
fig = plt.figure(figsize=(3,3))
subplot = fig.add_subplot(1,1,1)
subplot.set_xlim([-5,5])
subplot.set_ylim([-1,1.5])
red=df[df.red==1]
subplot.scatter(red.x,-0.5*red.red+0.05, color='r', marker='o')
blue=df[df.blue==1]
subplot.scatter(blue.x,-0.5*blue.blue-0.05, color='b', marker='o')
green=df[df.green==1]
subplot.scatter(green.x,-0.5*green.green, color='g', marker='o')
xは300×1の行列です。300はデータセットの標本数です。
青、赤、緑の3つに分類するので、wとw0は3列となります。これは未知数です。
wとw0に適当な数値を仮定してf=x*w+w0という一次関数を計算します。
これにソフトマックス関数を適用することで、仮定したw,w0に対応する確率pを求めます。
プレースホルダーtにはtrain_tが代入されることとなります。
例えば実際に「青」であった場合t=[1 0 0]です。
t*log(p)を計算することにより、仮定したw,w0により「青」と推定された確率p[0]だけが意味を持つこととなります。
これの総和(reduce_sum)が最も良い値となるようにトレーニングを実施します。
x=tf.placeholder(tf.float32,[None,1])
w=tf.Variable(tf.zeros([1,3]))
w0=tf.Variable(tf.zeros([3]))
f=tf.matmul(x,w)+w0
p=tf.nn.softmax(f)
t=tf.placeholder(tf.float32,[None,3])
loss=-tf.reduce_sum(t*tf.log(p))
train_step=tf.train.AdamOptimizer().minimize(loss)
sess=tf.Session()
sess.run(tf.initialize_all_variables())
10000回トレーニングを実施します。
テストデータとして-5から5を50分割したtest_xを作成しました。
このテストデータで、青赤緑それぞれの確率を計算して描画します
#10000回トレーニングを実施します。
for _ in range(10000):
sess.run(train_step,feed_dict={x:train_x, t:train_t})
# テストデータとして-5から5を50分割したtest_xを作成します
# このテストデータで、青赤緑それぞれの確率を計算して描画します
test_x=np.linspace(-5,5,50).reshape([50,1])
p_val=sess.run(p,feed_dict={x:test_x})
line=DataFrame(np.c_[test_x,p_val],columns=['x','blue','red','green'])
fig = plt.figure(figsize=(3,3))
subplot = fig.add_subplot(1,1,1)
subplot.set_xlim([-5,5])
subplot.set_ylim([-1,1.5])
subplot.plot(line.x,line.blue,color='b')
subplot.plot(line.x,line.red,color='r')
subplot.plot(line.x,line.green,color='g')
red=df[df.red==1]
subplot.scatter(red.x,-0.5*red.red+0.05, color='r', marker='o')
blue=df[df.blue==1]
subplot.scatter(blue.x,-0.5*blue.blue-0.05, color='b', marker='o')
green=df[df.green==1]
subplot.scatter(green.x,-0.5*green.green, color='g', marker='o')
値の小さいうち、例えば-5から-3位までは青がほぼ100%で、赤や緑は0%です。
実際そのような値の赤点や緑点は存在しません。
赤点が存在し始める(より、やや小さな)-2位から赤の確率が上昇してきます。
同時に青の確率が下降し、概ね-0.2で両者は交差します
値の大きな青もあれば値の小さな赤もあるのですが、その境界は-0.2であったと断言することができるわけです。
同様に赤と緑の境界は+1.8であったと言い切れます。
このようにソフトマックス関数を適用することで渾然としたデータの境界を決定することが可能となります。