Mendukung Mesin Vektor, 30 baris

Pada artikel ini saya akan menunjukkan kepada Anda cara menulis mesin vektor dukungan yang sangat sederhana tanpa scikit-learn atau pustaka lain dengan implementasi siap pakai hanya dalam 30 baris dengan Python. Jika Anda ingin memahami algoritma SMO, tetapi sepertinya terlalu rumit, maka artikel ini mungkin bermanfaat bagi Anda.



Tidak mungkin untuk menjelaskan apa itu mesin vektor dukungan Matriks ... Anda harus melihatnya sendiri.





Setelah mengetahui bahwa Habré memiliki kemampuan untuk memasukkan elemen media, saya membuat demo kecil (jika tiba-tiba tidak berhasil, Anda masih dapat mencoba keberuntungan Anda dengan versi di github [1] ). Tempatkan di pesawat (ruang dua fitur X dan Y ) beberapa titik merah dan biru (ini adalah kumpulan data kami) dan mesin akan melakukan klasifikasi (setiap titik latar belakang dicat tergantung di mana permintaan terkait akan diklasifikasikan). Pindahkan poin, ubah kernel (saya sarankan Anda untuk mencoba Fungsi Dasar Radial) dan kekerasan batas (konstan C ). Saya minta maaf atas kode yang mengerikan di JS - saya menulis di dalamnya hanya beberapa kali dalam hidup saya, untuk memahami algoritme, gunakan kode Python nanti di artikel.



Kandungan









Support Vector Machine adalah metode pembelajaran mesin (supervised learning) untuk menyelesaikan masalah klasifikasi, regresi, deteksi anomali, dll. Kami akan mempertimbangkannya menggunakan contoh masalah klasifikasi biner. Sampel pelatihan kami adalah sekumpulan vektor fitur xsaya diklasifikasikan menjadi salah satu dari dua kelas yi=±1 ... Permintaan Klasifikasi - Vektor x ke mana kita harus menetapkan kelas +1 atau 1 ...



Dalam kasus yang paling sederhana, kelas sampel pelatihan dapat dibagi dengan hanya menggambar satu garis lurus seperti pada gambar (untuk sejumlah besar fitur, ini akan menjadi bidang-hiper). Sekarang, ketika sebuah permintaan datang untuk mengklasifikasikan beberapa poin x , masuk akal untuk menempatkannya di kelas di sisi yang mana.



Bagaimana cara memilih garis lurus terbaik? Secara intuitif, saya ingin garis lurus lewat di tengah-tengah antar kelas. Untuk melakukan ini, tulis persamaan garis lurus sebagai xw+b=0 dan menskalakan parameter sehingga titik set data yang paling dekat dengan garis lurus memenuhi xw+b=±1 (plus atau minus, tergantung kelasnya) - titik-titik ini disebut vektor pendukung .



Dalam hal ini, jarak antara titik batas kelas adalah 2/|w| ... Jelas, kami ingin memaksimalkan nilai ini untuk memisahkan kelas sebaik mungkin. Yang terakhir ini setara dengan meminimalkan 12|w|2 , seluruh masalah pengoptimalan telah ditulis





min12|w|2subject to: yi(xiw+b)10.





Jika Anda menyelesaikannya, maka klasifikasi berdasarkan permintaan x diproduksi seperti ini





class(x)=sign(xw+b).





Ini adalah mesin vektor dukungan paling sederhana.



Dan apa yang harus dilakukan jika titik-titik dari kelas yang berbeda saling menembus seperti pada gambar?



Kami tidak dapat lagi menyelesaikan masalah pengoptimalan sebelumnya - tidak ada parameter yang memenuhi kondisi tersebut. Maka dimungkinkan untuk membiarkan poin melanggar batas dengan jumlah ξi0 , tetapi juga diharapkan agar pelanggar seperti itu sesedikit mungkin. Ini dapat dicapai dengan memodifikasi fungsi tujuan dengan istilah tambahan (regularisasi L1 ):





min(12|w|2+Ciξi)subject to: ξi+yi(xiw+b)10,ξi0,





dan prosedur klasifikasi akan berlanjut seperti sebelumnya. Di sini hyperparameter C bertanggung jawab atas kekuatan regularisasi, yaitu menentukan seberapa ketat kami memerlukan poin untuk menghormati batas: semakin C - lebih ξi akan lenyap dan poin yang lebih sedikit akan melanggar batas. Vektor pendukung dalam hal ini adalah titik-titiknya ξi>0 ...



Tetapi bagaimana jika set pelatihan menyerupai logo The Who dan titik-titiknya tidak pernah dapat dipisahkan oleh garis lurus?



Di sini kita akan dibantu oleh teknik yang cerdik - trik kernel [4] . Namun, untuk menerapkannya, seseorang harus meneruskan ke apa yang disebut masalah Lagrange ganda (atau ganda ). Penjelasan rinci tentang hal itu dapat ditemukan di Wikipedia [5] atau di kuliah keenam kursus [3] . Variabel di mana masalah baru diselesaikan disebut pengali ganda atau Lagrange... Masalah ganda sering kali lebih sederhana daripada masalah asli dan memiliki sifat tambahan yang baik, misalnya, masalah cekung meskipun masalah aslinya bukan cembung. Meskipun solusinya tidak selalu sesuai dengan solusi dari masalah aslinya (dualitas putus), ada sejumlah teorema yang, dalam kondisi tertentu, menjamin kebetulan seperti itu (dualitas kuat). Dan ini hanya kasus kami, jadi Anda dapat dengan aman menuju ke masalah ganda





maxλni=1λi12ni=1nj=1yiyj(xixj)λiλj,subject to: 0λiC, for i=1,2,,n,ni=1yiλi=0,





Dimana λi - variabel ganda. Setelah menyelesaikan masalah maksimalisasi, perlu juga dihitung parameternya b , yang tidak termasuk dalam masalah ganda, tetapi dibutuhkan untuk pengklasifikasi





b=Ek,ξk0[ykiλiyi(xixk)].





Pengklasifikasi dapat (dan harus) ditulis ulang dalam istilah variabel ganda





class(x)=sign(f(x)),f(x)=iλiyi(xix)+b.





Apa keuntungan dari rekaman ini? Harap dicatat bahwa semua vektor dari set pelatihan disertakan di sini secara eksklusif dalam bentuk produk titik (xixj) ... Pertama-tama Anda dapat memetakan titik-titik ke permukaan di ruang berdimensi lebih tinggi, dan baru kemudian menghitung produk titik dari gambar di ruang baru. Mengapa ini bisa dilihat dari gambar.



Jika pemetaan berhasil, gambar dari titik-titik tersebut dipisahkan oleh hyperplane! Faktanya, semuanya bahkan lebih baik: tidak perlu menampilkan, karena kami hanya tertarik pada perkalian titik, dan bukan pada koordinat spesifik dari titik-titik tersebut. Jadi keseluruhan prosedur dapat ditiru dengan mengganti perkalian titik dengan fungsinya K(xi;xj) , yang disebut inti . Tentu saja, tidak setiap fungsi bisa menjadi kernel - setidaknya secara hipotetis, harus ada pemetaan φ seperti yang K(xi;xj)=(φ(xi)φ(xj)) ... Kondisi yang diperlukan ditentukan oleh teorema Mercer [6] . Implementasi Python akan mewakili linier ( K(xi;xj)=xTixj ), polinomial ( K(xi;xj)=(xTixj)d ) kernel dan kernel fungsi basis radial ( K(xi;xj)=eγ|xixj|2 ). Seperti yang Anda lihat dari contoh, kernel dapat memasukkan hyperparameter spesifiknya ke dalam algoritme, yang juga akan memengaruhi operasinya.



Anda mungkin pernah melihat video di mana aksi gravitasi dijelaskan menggunakan contoh film karet yang diregangkan dalam bentuk corong [7] . Ini berfungsi, karena pergerakan titik pada permukaan lengkung di ruang berdimensi tinggi setara dengan pergerakan bayangannya di ruang berdimensi lebih rendah, jika Anda memberikannya metrik nontrivial. Faktanya, inti membengkokkan ruang.





Algoritma SMO



Jadi, kami berada di tujuan, tetap menyelesaikan masalah ganda yang diajukan di bagian sebelumnya





maxλni=1λi12ni=1nj=1yiyjK(xi;xj)λiλj,subject to: 0λiC, for i=1,2,,n,ni=1yiλi=0,





kemudian temukan parameternya





b=Ek,ξk0[ykiλiyiK(xi;xk)],





dan pengklasifikasi akan berbentuk seperti berikut





class(x)=sign(f(x)),f(x)=iλiyiK(xi;x)+b.





Algoritma SMO (Sequential minimal optimization, [8] ) untuk memecahkan masalah ganda adalah sebagai berikut. Dalam loop, menggunakan heuristik kompleks ( [9] ), sepasang variabel ganda dipilih λM dan λL , dan kemudian fungsi tujuan diminimalkan di atasnya, dengan kondisi keteguhan jumlah $ sebaris $ y_ \ M \ lambda_ \ M + y_ \ L \ lambda_ \ L $ sebaris $ yMλM+yLλL dan pembatasan 0λMC , 0λLC (mengatur kekerasan perbatasan). Kondisi penjumlahan menyimpan jumlah semua yiλi tidak berubah (setelah semua, kami tidak menyentuh lambda lainnya). Algoritma berhenti ketika mendeteksi ketaatan yang cukup baik dari apa yang disebut kondisi KKT (Karush-Kuna-Tucker [10] ).



Saya akan membuat beberapa penyederhanaan.



  • Saya akan membuang heuristik kompleks pemilihan indeks (ini dilakukan dalam kursus Universitas Stanford [11] ) dan akan mengulang satu indeks, dan memilih indeks lainnya secara acak.
  • Saya akan menolak untuk memeriksa PKC dan akan melakukan sejumlah pengulangan yang telah ditentukan sebelumnya.
  • Dalam prosedur optimasi itu sendiri, berbeda dengan karya klasik [9] atau pendekatan Stanford [11] , saya akan menggunakan persamaan vektor dari sebuah garis lurus. Ini akan sangat menyederhanakan penghitungan (bandingkan volume [12] dan [13] ).


Sekarang untuk detailnya. Informasi dari sampel pelatihan dapat ditulis dalam bentuk matriks





K=(y1y1K(x1;x1)y1y2K(x1;x2)y1yNK(x1;xN)y2y1K(x2;x1)y2y2K(x2;x2)y2yNK(x2;xN)yNy1K(xN;x1)yNy2K(xN;x2)yNyNK(xN;xN)).





Berikut ini, saya akan menggunakan notasi dengan dua indeks ( Ki,j ) untuk merujuk ke elemen matriks dan dengan satu indeks ( Kk ) untuk menunjukkan vektor kolom dari matriks. Kumpulkan variabel ganda menjadi vektor kolom λ ... Kami tertarik





maxλni=1λi12λTKλL.





Misalkan, pada iterasi saat ini, kami ingin memaksimalkan fungsi tujuan dengan indeks L dan M ... Kami akan mengambil derivatif, jadi akan lebih mudah untuk memilih istilah yang mengandung indeks L dan M ... Ini mudah dilakukan di bagian dengan jumlah λi , tetapi bentuk kuadrat akan membutuhkan beberapa transformasi.



Saat menghitung λTKλ penjumlahan dilakukan pada dua indeks, mari i dan j ... Sorot pasangan indeks yang mengandung L atau M ...





Mari tulis ulang masalahnya dengan menggabungkan semua yang tidak mengandung λL atau λM ... Untuk mempermudah melacak indeks, perhatikan K di gambar.

$$ display $$ \ begin {aligned} \ mathscr {L} & = \ lambda_ \ M + \ lambda_ \ L - \ sum_ {j} \ lambda_ \ M \ lambda_j K _ {\ M, j} - \ sum_ { i} \ lambda_ \ L \ lambda_i K _ {\ L, i} + \ text {const} + \\ {\ text {kompensasi} \ atop \ text {hitungan ganda}} \ rightarrow \ qquad & + \ frac {1 } {2} \ lambda_ \ M ^ 2 K _ {\ M, \ M} + \ lambda_ \ M \ lambda_ \ LK _ {\ M, \ L} + \ frac {1} {2} \ lambda_ \ L ^ 2 K_ {\ L, \ L} = \\ & = \ lambda_ \ M \ kiri (1- \ sum_ {j} \ lambda_j K _ {\ M, j} \ kanan) + \ lambda_ \ L \ kiri (1 - \ sum_ {i} \ lambda_i K _ {\ L, i} \ kanan) + \\ & + \ frac {1} {2} \ kiri (\ lambda_ \ M ^ 2 K _ {\ M, \ M} + 2 \ lambda_ \ M \ lambda_ \ LK _ {\ M, \ L} + \ lambda_ \ L ^ 2 K _ {\ L, \ L} \ kanan) + \ text {const} = \\ & = \ boldsymbol {k} ^ T_0 \ simbol tebal {v} _0 + \ frac {1} {2} \ simbol tebal {v} ^ {\, T} _0 \, \ simbol tebal {Q} \, \ simbol tebal {v} _0 + \ teks {const}, \ end {aligned} $$ display $$ L=λM+λLjλMλjKM,jiλLλiKL,i+const+ +12λ2MKM,M+λMλLKM,L+12λ2LKL,L==λM(1jλjKM,j)+λL(1iλiKL,i)++12(λ2MKM,M+2λMλLKM,L+λ2LKL,L)+const==kT0v0+12vT0Qv0+const,





Dimana const menunjukkan istilah independen dari λL atau λM ... Di baris terakhir, saya menggunakan notasi

$$ display $$ \ begin {align} \ boldsymbol {v} _0 & = (\ lambda_ \ M, \ lambda_ \ L) ^ T, \ tag {4a} \\ \ boldsymbol {k} _0 & = \ kiri ( 1 - \ boldsymbol {\ lambda} ^ T \ boldsymbol {K} _ {\ M}, 1 - \ boldsymbol {\ lambda} ^ T \ boldsymbol {K} _ {\ L} \ kanan) ^ T, \ tag { 4b} \\ \ boldsymbol {Q} & = \ begin {pmatrix} K _ {\ M, \ M} & K _ {\ M, \ L} \\ K _ {\ L, \ M} & K _ { \ L, \ L} \\ \ end {pmatrix}, \ tag {4c} \\ \ boldsymbol {u} & = (-y_ \ L, y_ \ M) ^ T. \ tag {4d} \ end {align} $$ display $$ v0=(λM,λL)T,k0=(1λTKM,1λTKL)T,Q=(KM,MKM,LKL,MKL,L),u=(yL,yM)T.





catat itu k0+Qv0 tidak bergantung pada λL atau dari λM

$$ display $$ \ boldsymbol {k} _0 = \ begin {pmatrix} 1 - \ lambda_ \ M K _ {\ M, \ M} - \ lambda_ \ L K _ {\ M, \ L} - \ sum_ {i \ neq \ M, \ L} \ lambda_i K _ {\ M, i} \\ 1 - \ lambda_ \ MK _ {\ L, \ M} - \ lambda_ \ LK _ {\ L, \ L} - \ sum_ { i \ neq \ M, \ L} \ lambda_i K _ {\ L, i} \\ \ end {pmatrix} = \ begin {pmatrix} 1 - \ sum_ {i \ neq \ M, \ L} \ lambda_i K _ {\ M, i} \\ 1 - \ sum_ {i \ neq \ M, \ L} \ lambda_i K _ {\ L, i} \\ \ end {pmatrix} - \ boldsymbol {Q} \ boldsymbol {v} _0. $$ display $$ k0=(1λMKM,MλLKM,LiM,LλiKM,i1λMKL,MλLKL,LiM,LλiKL,i)=(1iM,LλiKM,i1iM,LλiKL,i)Qv0.





Oleh karena itu, kernelnya simetris QT=Q dan Anda bisa menulis





L=(k0+Qv0Qv0)Tv0+12vT0Qv0+const=(k0+Qv0)Tv012vT0Qv0+const





Kami ingin melakukan maksimalisasi sehingga $ sebaris $ y_ \ L \ lambda_ \ L + y_ \ M \ lambda_ \ M $ sebaris $ yLλL+yMλM tetap konstan. Untuk ini, nilai baru harus berada pada garis lurus

$$ display $$ (\ lambda_ \ M ^ \ text {baru}, \ lambda_ \ L ^ \ text {baru}) ^ T = \ boldsymbol {v} (t) = \ boldsymbol {v} _0 + t \ boldsymbol {u}. $$ display $$ (λnewM,λnewL)T=v(t)=v0+tu.





Mudah untuk memastikannya untuk semua orang t

$$ display $$ y_ \ M \ lambda_ \ M ^ \ text {baru} + y_ \ L \ lambda_ \ L ^ \ text {baru} = y_ \ M \ lambda_ \ M + y_ \ L \ lambda_ \ L + t (-y_ \ M y_ \ L + y_ \ L y_ \ M) = y_ \ M \ lambda_ \ M + y_ \ L \ lambda_ \ L. $$ display $$ yMλnewM+yLλnewL=yMλM+yLλL+t(yMyL+yLyM)=yMλM+yLλL.





Dalam hal ini, kita harus memaksimalkan





L(t)=(k0+Qv0)Tv(t)12vT(t)Qv(t)+const,





yang mudah dilakukan dengan mengambil turunannya





dL(t)dt=(k0+Qv0)Tdvdt12(d(vTQv)dv)Tdvdt==kT0u+vT0QTuvTQTu(vT0vT)Qu=kT0utuTQu.





Menyamakan turunannya dengan nol, kita dapatkan





t=kT0uuTQu.





Dan satu hal lagi: mungkin kita akan mendaki lebih jauh dari yang diperlukan dan menemukan diri kita di luar alun-alun seperti pada gambar. Maka Anda perlu mundur selangkah dan kembali ke perbatasannya

$$ display $$ (\ lambda_ \ M ^ \ text {baru}, \ lambda_ \ L ^ \ text {baru}) = \ boldsymbol {v} _0 + t _ * ^ {\ text {restr}} \ boldsymbol { u}. $$ display $$ (λnewM,λnewL)=v0+trestru.





Ini menyelesaikan iterasi dan memilih indeks baru.





Penerapan





Diagram skema pelatihan mesin vektor dukungan yang disederhanakan dapat ditulis sebagai







Mari kita lihat kode dalam bahasa pemrograman yang sebenarnya. Jika Anda tidak menyukai kode di artikel, Anda dapat mempelajarinya di github [14] .



Kode sumber mesin vektor dukungan yang disederhanakan
import numpy as np

class SVM:
  def __init__(self, kernel='linear', C=10000.0, max_iter=100000, degree=3, gamma=1):
    self.kernel = {'poly'  : lambda x,y: np.dot(x, y.T)**degree,
         'rbf': lambda x,y: np.exp(-gamma*np.sum((y-x[:,np.newaxis])**2,axis=-1)),
         'linear': lambda x,y: np.dot(x, y.T)}[kernel]
    self.C = C
    self.max_iter = max_iter

  #   t,       
  def restrict_to_square(self, t, v0, u): 
    t = (np.clip(v0 + t*u, 0, self.C) - v0)[1]/u[1]
    return (np.clip(v0 + t*u, 0, self.C) - v0)[0]/u[0]

  def fit(self, X, y):
    self.X = X.copy()
    #   0,1  -1,+1;     sklearn
    self.y = y * 2 - 1 
    self.lambdas = np.zeros_like(self.y, dtype=float)
    #  (3)
    self.K = self.kernel(self.X, self.X) * self.y[:,np.newaxis] * self.y
    
    #  self.max_iter 
    for _ in range(self.max_iter):
      #     
      for idxM in range(len(self.lambdas)):                                    
        # idxL  
        idxL = np.random.randint(0, len(self.lambdas))                         
        #  (4)
        Q = self.K[[[idxM, idxM], [idxL, idxL]], [[idxM, idxL], [idxM, idxL]]] 
        #  (4a)
        v0 = self.lambdas[[idxM, idxL]]                                        
        #  (4b)
        k0 = 1 - np.sum(self.lambdas * self.K[[idxM, idxL]], axis=1)           
        #  (4d)
        u = np.array([-self.y[idxL], self.y[idxM]])                            
        #   (5),    idxM = idxL
        t_max = np.dot(k0, u) / (np.dot(np.dot(Q, u), u) + 1E-15) 
        self.lambdas[[idxM, idxL]] = v0 + u * self.restrict_to_square(t_max, v0, u)
    
    #    
    idx, = np.nonzero(self.lambdas > 1E-15) 
    #  (1)
    self.b = np.mean((1.0-np.sum(self.K[idx]*self.lambdas, axis=1))*self.y[idx]) 
  
  def decision_function(self, X):
    return np.sum(self.kernel(X, self.X) * self.y * self.lambdas, axis=1) + self.b

  def predict(self, X): 
    #   -1,+1  0,1;     sklearn
    return (np.sign(self.decision_function(X)) + 1) // 2

      
      









Saat membuat objek kelas SVM, Anda dapat menentukan hyperparameter. Pelatihan dilakukan dengan memanggil fungsi fit, kelas harus ditentukan sebagai 0 dan 1 (diubah secara internal menjadi 1 dan +1 , dibuat untuk kompatibilitas yang lebih besar dengan sklearn), dimensi vektor fitur diizinkan secara sewenang-wenang. Fungsi prediksi digunakan untuk klasifikasi.





Perbandingan dengan sklearn.svm.SVC



Bukan berarti perbandingan ini masuk akal, karena kita berbicara tentang algoritma yang sangat disederhanakan, dikembangkan hanya untuk tujuan mengajar siswa, tetapi tetap saja. Untuk pengujian (dan untuk melihat bagaimana menggunakan semuanya), Anda dapat melakukan hal berikut (kode ini juga tersedia di github [14] ).



Perbandingan dengan sklearn.svm.SVC pada dataset 2D sederhana
from sklearn.svm import SVC
import matplotlib.pyplot as plt
import seaborn as sns; sns.set()
from sklearn.datasets import make_blobs, make_circles
from matplotlib.colors import ListedColormap

def test_plot(X, y, svm_model, axes, title):
  plt.axes(axes)
  xlim = [np.min(X[:, 0]), np.max(X[:, 0])]
  ylim = [np.min(X[:, 1]), np.max(X[:, 1])]
  xx, yy = np.meshgrid(np.linspace(*xlim, num=700), np.linspace(*ylim, num=700))
  rgb=np.array([[210, 0, 0], [0, 0, 150]])/255.0
  
  svm_model.fit(X, y)
  z_model = svm_model.decision_function(np.c_[xx.ravel(), yy.ravel()]).reshape(xx.shape)
  
  plt.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap='autumn')
  plt.contour(xx, yy, z_model, colors='k', levels=[-1, 0, 1], alpha=0.5, linestyles=['--', '-', '--'])
  plt.contourf(xx, yy, np.sign(z_model.reshape(xx.shape)), alpha=0.3, levels=2, cmap=ListedColormap(rgb), zorder=1)
  plt.title(title)

X, y = make_circles(100, factor=.1, noise=.1)
fig, axs = plt.subplots(nrows=1,ncols=2,figsize=(12,4))
test_plot(X, y, SVM(kernel='rbf', C=10, max_iter=60, gamma=1), axs[0], 'OUR ALGORITHM')
test_plot(X, y, SVC(kernel='rbf', C=10, gamma=1), axs[1], 'sklearn.svm.SVC')

X, y = make_blobs(n_samples=50, centers=2, random_state=0, cluster_std=1.4)
fig, axs = plt.subplots(nrows=1,ncols=2,figsize=(12,4))
test_plot(X, y, SVM(kernel='linear', C=10, max_iter=60), axs[0], 'OUR ALGORITHM')
test_plot(X, y, SVC(kernel='linear', C=10), axs[1], 'sklearn.svm.SVC')

fig, axs = plt.subplots(nrows=1,ncols=2,figsize=(12,4))
test_plot(X, y, SVM(kernel='poly', C=5, max_iter=60, degree=3), axs[0], 'OUR ALGORITHM')
test_plot(X, y, SVC(kernel='poly', C=5, degree=3), axs[1], 'sklearn.svm.SVC')

      
      







Setelah peluncuran, gambar akan dibuat, tetapi karena algoritme diacak, gambar akan sedikit berbeda untuk setiap peluncuran. Berikut adalah contoh cara kerja algoritme yang disederhanakan (dari kiri ke kanan: kernel linier, polinomial, dan rbf)



Dan ini adalah hasil dari versi industri dari mesin vektor pendukung.



Jika dimensi 2 tampaknya terlalu kecil, Anda masih dapat menguji di MNIST



Perbandingan dengan sklearn.svm.SVC pada 2 kelas dari MNIST
from sklearn import datasets, svm
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix
import matplotlib.pyplot as plt
import seaborn as sns

class_A = 3
class_B = 8

digits = datasets.load_digits()
mask = (digits.target == class_A) | (digits.target == class_B)
data = digits.images.reshape((len(digits.images), -1))[mask]
target = digits.target[mask] // max([class_A, class_B]) # rescale to 0,1
X_train, X_test, y_train, y_test = train_test_split(data, target, test_size=0.5, shuffle=True)

def plot_confusion(clf):
  clf.fit(X_train, y_train)
  y_fit = clf.predict(X_test)

  mat = confusion_matrix(y_test, y_fit)
  sns.heatmap(mat.T, square=True, annot=True, fmt='d', cbar=False, xticklabels=[class_A,class_B], yticklabels=[class_A,class_B])
  plt.xlabel('true label')
  plt.ylabel('predicted label');
  plt.show()

print('sklearn:')
plot_confusion(svm.SVC(C=1.0, kernel='rbf', gamma=0.001))
print('custom svm:')
plot_confusion(SVM(kernel='rbf', C=1.0, max_iter=60, gamma=0.001))

      
      







Untuk MNIST, saya mencoba beberapa pasang kelas secara acak (algoritme yang disederhanakan hanya mendukung klasifikasi biner), tetapi saya tidak menemukan perbedaan dalam pekerjaan algoritme dan sklearn yang disederhanakan. Matriks konfusi berikut memberikan gambaran tentang kualitas.







Kesimpulan



Terima kasih untuk semua orang yang membaca sampai akhir. Dalam artikel ini, kami melihat implementasi tutorial yang disederhanakan dari mesin vektor dukungan. Tentu saja, ini tidak dapat bersaing dengan desain industri, tetapi karena kesederhanaan ekstrim dan kode yang ringkas dalam Python, serta fakta bahwa semua ide dasar SMO telah dipertahankan, versi SVM ini mungkin akan menggantikan tempatnya di kelas. Perlu dicatat bahwa algoritma ini lebih sederhana tidak hanya dari algoritma yang sangat rumit [9] , tetapi bahkan versi yang disederhanakan dari Universitas Stanford [11] . Bagaimanapun, mesin vektor dukungan dalam 30 baris itu indah.



Daftar referensi



  1. https://fbeilstein.github.io/simplest_smo_ever/
  2. halaman di http://www.machinelearning.ru
  3. "Permulaan Machine Learning", KAU
  4. https://en.wikipedia.org/wiki/Kernel_method
  5. https://en.wikipedia.org/wiki/Duality_(optimization)
  6. http://www.machinelearning.ru
  7. https://www.youtube.com/watch?v=MTY1Kje0yLg
  8. https://en.wikipedia.org/wiki/Sequential_minimal_optimization
  9. Platt, John. Fast Training of Support Vector Machines using Sequential Minimal Optimization, in Advances in Kernel Methods – Support Vector Learning, B. Scholkopf, C. Burges, A. Smola, eds., MIT Press (1998).
  10. https://en.wikipedia.org/wiki/Karush%E2%80%93Kuhn%E2%80%93Tucker_conditions
  11. http://cs229.stanford.edu/materials/smo.pdf
  12. https://www.researchgate.net/publication/344460740_Yet_more_simple_SMO_algorithm
  13. http://fourier.eng.hmc.edu/e176/lectures/ch9/node9.html
  14. https://github.com/fbeilstein/simplest_smo_ever



All Articles