思考ノイズ

無い知恵を絞りだす。無理はしない。

<SVM> サポートベクタマシン自主勉強(1):方針

ちょっと間が空いてしまいましたが機械学習のエントリとなります。前回最後にちらっとお話ししたのですが、サポートベクタマシン(SVM)に足を突っ込んでみたいと思っています。

SVMのコーディングが自力でできない問題

ただ、このSVMは何回か挑戦して失敗している経緯があります。前回のようにはじパタ本だけでは私のレベルでクリアができない代物となります。そこではじパタと合わせて、「異常検知と変化検知」の内容と相互補完してみています。

異常検知と変化検知 (機械学習プロフェッショナルシリーズ)

異常検知と変化検知 (機械学習プロフェッショナルシリーズ)

そこでやっと、SVMの概要について理解した。。。。つもりでした。しかしながらいざこれをスクリプトに落とそうとするとどう書いていいのかわからない。つまりロジックがわかったつもりでも、実行に移すとなるとどうしていいのかわからなくなってしまいました。

頼るべきはGoogle先生集合知

しかしながらもうすでに歴史のあるこの分野では検索してしまえばいくらでもコードが出てきます。今回は以下のサイトさまのコードを拝借してやはりアヤメデータを使った分類を行ってみました。

qiita.com

こちらのコードは y = x の線形で分離をして  t を1, -1とわけています。アヤメデータもとりあえず、3種のうちの最初の1種を1, その他を-1としてインプットするコードに改造をしてみました。 その結果が以下となります。

f:id:bython-chogo:20180430230944g:plain

おぉ、なんとなく分類する線が学習を経るごとに赤と緑の間にはいっていきますね。赤が1としたアヤメデータなのでうまくいっているようです。

ここからスタート

SVMについてまとめることはたくさんありそうです。ラグランジュ乗数法、正則化、双対問題、KKT条件、カーネルトリック。数学的要素が多くどこまでカバーできるかわかりませんが、まず次回はこのスクリプトについて解いていくことから初めてみようかと思います。正直きちんと着地できるかまだ不明瞭ではあります。

コード

Jupyter Notebookで実行しています。

import sys
import numpy as np
from sklearn import datasets
import itertools
import matplotlib.pyplot as plt
#inline pyplot

from matplotlib import animation
from IPython.display import HTML

iris = datasets.load_iris()
features = iris.data
feature_names = iris.feature_names
targets = iris.target

class SVM():
    def __init__(self, v1=0, v2=2, t=0):
        self.X = np.array([features.T[v1], features.T[v2]]).T
        self.T = np.array([1 if i==t else -1 for i in targets])
        self.N = self.X.shape[0]
        self.d = self.X.shape[1]
        self.alpha = np.zeros(self.N)
        self.beta = 1.0
        self.eta_al = 0.0001
        self.eta_be = 0.1
        self.v = [v1, v2]

    def test(self):
        print(self.X.shape)
        print(self.T)
        print(self.N)
        print(self.alpha)
        
    def plot_map(self, w, b):
        plt.subplot(1, 1, 1)
        seq = np.arange(4.0, 8.0, 0.02)

        plt.xlabel(feature_names[self.v[0]])
        plt.ylabel(feature_names[self.v[1]])
        plt.xlim(4, 8)
        plt.ylim(0, 8)

        plt.plot(seq, -(w[0] * seq + b) / w[1], 'k-')
        #plt.autoscale()
        plt.grid()
        for t, marker, c in zip(range(3), '>ox', 'rgb'):
            #print(self.X[self.T==1], 0)
            #print(self.T)
            plt.scatter(
                features[targets == t, self.v[0]],
                features[targets == t, self.v[1]],
                marker=marker,
                c=c,
            )
            #print(linear_pro(w, np.array([1.,1.,1.])))
        plt.show()
        
        
    def rtin(self, show=False):
        
        k_w = np.array([-100.0, -100.0])
        k_b = -100.0
        value = []
        for _itr in range(1000):
            for i in range(self.N):

                self.delta = 1 - (self.T[i] * self.X[i]).dot(self.alpha * self.T * self.X.T).sum() - self.beta * self.T[i] * self.alpha.dot(self.T)
                self.alpha[i] += self.eta_al * self.delta
            for i in range(self.N):
                self.beta += self.eta_be * self.alpha.dot(self.T) ** 2 / 2

            index = self.alpha > 0
            w = (self.alpha * self.T).T.dot(self.X)
            b = (self.T[index] - self.X[index].dot(w)).mean()

            value.append([w, b])

            if (np.power(np.array([k_w - w]), 2) < 0.00001).all() and (k_b - b) ** 2 < 0.00001:
                print(_itr)
                break

            if _itr % 10 == 0 and show:
                self.plot_map(w, b)        
            k_w = w
            k_b = b
        return value
svm = SVM(t=0)
_ = svm.rtin(True)