久しぶりの投稿になります。今回はサポートベクトルマシーン(SVM)を使って簡単な分類の予想の立て方について記述できればと思います。
SVMとはWikipedaによると「教師あり学習を用いるパターン認識モデルの一つである」のことをいいます。教師ありデータを用いて分類、解析や回帰を行う際はなくてはならないものです。
今回はTensorflowを使ってSVMを用いて花の品種がヒオウギアヤメ(Iris Setosa)かそうでないかを分類する方法について記述していきます。
〇学習データを準備
ヒオウギアヤメのデータはscikit-learnのdatasetsライブラリ内にあります。今回はそれを用いてやっていきます
1 2 3 4 |
import matplotlib.pyplot as plt import numpy as np import tensorflow as tf from sklearn import datasets |
ヒオウギアヤメのデータから1番目(がく片の長さ)と4番目(花びらの幅)の変数をロードする。
またdatasets.targetが0の値が目的のヒオウギアヤメになるのでヒオウギアヤメかそうでないかで分類する。
ちなみにdatasets.targetが1の値の場合Iris versicolor、2の場合Iris virginicaになる。
1 2 3 4 5 |
sess = tf.Session() iris = datasets.load_iris() x_vals = np.array([[x[0], x[3]] for x in iris.data]) y_vals = np.array([1 if y==0 else -1 for y in iris.target]) |
データセットを学習データとテストデータに分割する。今回は学習データを全体の8割、テストデータを2割で分割した
1 2 3 4 5 6 |
train_indices = np.random.choice(len(x_vals), round(len(x_vals)*0.8), replace=False) test_indices = np.array(list(set(range(len(x_vals))) - set(train_indices))) x_vals_train = x_vals[train_indices] x_vals_test = x_vals[test_indices] y_vals_train = y_vals[train_indices] y_vals_test = y_vals[test_indices] |
バッチサイズ、プレースホルダー、変数の設定を行う。
1 2 3 4 5 6 7 |
batch_size = 100 x_data = tf.placeholder(shape=[None, 2], dtype=tf.float32) y_target = tf.placeholder(shape=[None, 1], dtype=tf.float32) A = tf.Variable(tf.random_normal(shape=[2, 1])) b = tf.Variable(tf.random_normal(shape=[1, 1])) |
モデルの出力を行う。今回は直線で分類するためy = Ax + bの形になるようにモデルを設計している。
1 |
model_output = tf.subtract(tf.matmul(x_data, A), b) |
損失関数について設定している。
1 2 3 4 |
l2_norm = tf.constant([0.01]) alpha = tf.constant([0.01]) classification_term = tf.reduce_mean(tf.maximum(0., tf.subtract(1., tf.multiply(model_output, y_target)))) loss = tf.add(classification_term, tf.multiply(alpha, l2_norm)) |
予想関数(正の値なら1に、負の値なら-1に、0なら0にする)と正解率を求める正解関数を設定する
1 2 |
prediction = tf.sign(model_output) accuracy = tf.reduce_mean(tf.cast(tf.equal(prediction, y_target), tf.float32)) |
最適化関数を作成、モデルの変数を初期化する
1 2 3 4 5 |
my_opt = tf.train.GradientDescentOptimizer(0.01) train_step = my_opt.minimize(loss) init = tf.global_variables_initializer() sess.run(init) |
いよいよ学習開始である。勾配、切片、損失率を求める。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
loss_vec = [] train_accuracy = [] test_accuracy = [] for i in range(500): rand_index = np.random.choice(len(x_vals_train), size=batch_size) rand_x = x_vals_train[rand_index] rand_y = np.transpose([y_vals_train[rand_index]]) sess.run(train_step, feed_dict={x_data: rand_x, y_target: rand_y}) temp_loss = sess.run(loss, feed_dict={x_data: rand_x, y_target: rand_y}) loss_vec.append(temp_loss) train_acc_temp = sess.run(accuracy, feed_dict={ x_data: x_vals_train, y_target: np.transpose([y_vals_train])}) train_accuracy.append(train_acc_temp) test_acc_temp = sess.run(accuracy, feed_dict={ x_data: x_vals_test, y_target: np.transpose([y_vals_test])}) test_accuracy.append(test_acc_temp) if (i+1)%100==0: print('Step # {} A = {}, b = {}'.format(str(i+1), str(sess.run(A)), str(sess.run(b)))) print('Loss = ' + str(temp_loss)) |
この時点で実施した結果として
Step # 100 A = [[-0.52861047]
[ 0.63325727]], b = [[-1.13860738]]
Loss = [ 0.77599818]
Step # 200 A = [[-0.41611043]
[ 0.24167725]], b = [[-1.20580769]]
Loss = [ 0.92222953]
Step # 300 A = [[-0.3528904 ]
[-0.09856269]], b = [[-1.25540757]]
Loss = [ 0.43601176]
Step # 400 A = [[-0.26738036]
[-0.41078258]], b = [[-1.31100762]]
Loss = [ 0.56367826]
Step # 500 A = [[-0.21322033]
[-0.70880252]], b = [[-1.3627075]]
Loss = [ 0.36476588]
が表示される(実施するたびごとに値は変わります)そのうえで学習した結果をグラフで表示するようにしていく。
学習結果より直線を求めていく
1 2 3 4 5 6 7 8 9 |
[[a1], [a2]] = sess.run(A) [[b]] = sess.run(b) slope = -a2/a1 y_intercept = b/a1 x1_vals = [d[1] for d in x_vals] best_fit = [] for i in x1_vals: best_fit.append(slope*i+y_intercept) |
ヒオウギアヤメかそうでないかで分割する
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
setosa_x = [d[1] for i,d in enumerate(x_vals) if y_vals[i] == 1] setosa_y = [d[0] for i,d in enumerate(x_vals) if y_vals[i] == 1] not_setosa_x = [d[1] for i,d in enumerate(x_vals) if y_vals[i] == -1] not_setosa_y = [d[0] for i,d in enumerate(x_vals) if y_vals[i] == -1] #以上の内容をプロットする plt.plot(setosa_x, setosa_y, 'o', label='I. setosa') plt.plot(not_setosa_x, not_setosa_y, 'x', label='Non-setosa') plt.plot(x1_vals, best_fit, 'r-', label='Liner Separator', linewidth=3) plt.ylim([0, 10]) plt.legend(loc='lower right') plt.title('Sepal Length vs Pedal Width') plt.xlabel('Pedal Width') plt.ylabel('Sepal Length') plt.show() |
すると以下のようなグラフが表示される。
今回はSVMを使って分類する方法を記述してみた。これを応用することで分類分けができ、画像認識などへ応用することができる。
さらに勉強が必要だ!!