【tensorflow】Irisデータセットで線形分離で二値分類
Irisデータセットは特徴量として「萼片の長さ」「萼片の幅」「花びらの長さ」「花びらの幅」が与えられ
ラベルはそれぞれ0:setosa, 1:versicolor, 3:virginicaである.
setosa
versicolor
verginica
このデータセットに対してsetosaとそれ以外の二値分類を行った.
まず使うモジュールをimportし計算グラフを宣言する.
import matplotlib.pyplot as plt import numpy as np from sklearn import datasets import tensorflow as tf sess = tf.Session()
次にIrisデータセットを取得
setosaに1 , それ以外に0を割り当てる.
iris = datasets.load_iris() binary_target = np.array([1. if x==0[f:id:umashika5555:20170907030429p:plain] else 0. for x in iris.target]) iris_2d = np.array([[x[2],x[3]] for x in iris.data])# 花びらの長さと花びらの幅の2つの値の組をデータとする
バッチサイズ, プレースホルダ, 変数を宣言
batch_size = 20 x1_data = tf.placeholder(shape=[None,1], dtype=tf.float32) x2_data = tf.placeholder(shape=[None,1], dtype=tf.float32) y_target = tf.placeholder(shape=[None,1], dtype=tf.float32) A = tf.Variable(tf.random_normal(shape=[1,1])) b = tf.Variable(tf.random_normal(shape=[1,1]))
線形モデルを定義
my_mult = tf.matmul(x2_data,A) my_add = tf.add(my_mult,b) my_output = tf.subtract(x1_data,my_add)
損失関数を定義
xentropy = tf.nn.sigmoid_cross_entropy_with_logits(logits=my_output,labels=y_target)
最適化関数を定義
my_opt = tf.train.GradientDescentOptimizer(0.05)
train_step = my_opt.minimize(xentropy)
変数を初期化する
init = tf.global_variables_initializer() sess.run(init)
線形モデルを1000回のイテレーションでトレーニング
for i in range(1000): rand_index = np.random.choice(len(iris_2d),size=batch_size) rand_x = iris_2d[rand_index] rand_x1 = np.array([[x[0]] for x in rand_x]) rand_x2 = np.array([[x[1]] for x in rand_x]) rand_y = np.array([[y] for y in binary_target[rand_index]]) sess.run(train_step,feed_dict={x1_data:rand_x1, x2_data:rand_x2, y_target:rand_y}) if (i+1)%200==0: print("step #", str(i+1) + "A=" + str(sess.run(A)) + ", b= " + str(sess.run(b)))
実行結果
step # 200A=[[-2.14318705]], b= [[ 8.48896122]] step # 400A=[[-3.59071422]], b= [[ 10.84847546]] step # 600A=[[-4.73809004]], b= [[ 12.31665611]] step # 800A=[[-5.16311646]], b= [[ 13.66902447]] step # 1000A=[[-5.86469412]], b= [[ 14.52292442]]
結果をグラフにプロットする.
[[slope]] = sess.run(A) [[intercept]] = sess.run(b) x = np.linspace(0,3,num=50) ablineValues = [] for i in x: ablineValues.append(slope*i+intercept) setosa_x = [a[1] for i,a in enumerate(iris_2d) if binary_target[i] == 1] setosa_y = [a[0] for i,a in enumerate(iris_2d) if binary_target[i] == 1] non_setosa_x = [a[1] for i,a in enumerate(iris_2d) if binary_target[i] == 0] non_setosa_y = [a[0] for i,a in enumerate(iris_2d) if binary_target[i] == 0] plt.plot(setosa_x,setosa_y,"rx",ms=10, mew=2, label="setosa") plt.plot(non_setosa_x,non_setosa_y,"ro",label="NOn setosa") plt.plot(x,ablineValues) plt.xlim([0.0,2.7]) plt.ylim([0.0,7.1]) plt.suptitle("Linear Separator For I.setosa") plt.xlabel("Petal Length") plt.ylabel("Petal Width") plt.legend(loc="lower right") plt.show()
これは線形分離でx1[None*1] - (x2[None*1]*A[1*1] + b[1*1]) = 0[1*1]という直線の下か上かで種類を判別する方法である.
この場合線形分離可能なモデルなので綺麗に分離できたがsetosa以外を分類しようとすると上手くいかない.
versicolorを分類しようとした場合
versinicaを分類しようとした場合
線形分離可能なデータに対しては上手く働くが, それ以外のものに関しては上手く行かないことが分かる.
むしろ現実世界では線形分離不可能なもののほうが多いのでそれらに対処していく必要がある.
今後SVMやNNの記事を書いていく.