RM新时代网站-首页

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

怎樣使用Python從零實(shí)現(xiàn)多分類SVM呢?

冬至子 ? 來源:思否AI ? 作者:思否AI ? 2023-11-09 14:24 ? 次閱讀

本文將首先簡(jiǎn)要概述支持向量機(jī)及其訓(xùn)練和推理方程,然后將其轉(zhuǎn)換為代碼以開發(fā)支持向量機(jī)模型。之后然后將其擴(kuò)展成多分類的場(chǎng)景,并通過使用Sci-kit Learn測(cè)試我們的模型來結(jié)束。

SVM概述

支持向量機(jī)的目標(biāo)是擬合獲得最大邊緣的超平面(兩個(gè)類中最近點(diǎn)的距離)??梢灾庇^地表明,這樣的超平面(A)比沒有最大化邊際的超平面(B)具有更好的泛化特性和對(duì)噪聲的魯棒性。

為了實(shí)現(xiàn)這一點(diǎn),SVM通過求解以下優(yōu)化問題找到超平面的W和b:

它試圖找到W,b,使最近點(diǎn)的距離最大化,并正確分類所有內(nèi)容(如y取±1的約束)。這可以被證明相當(dāng)于以下優(yōu)化問題:

可以寫出等價(jià)的對(duì)偶優(yōu)化問題

這個(gè)問題的解決方案產(chǎn)生了一個(gè)拉格朗日乘數(shù),我們假設(shè)數(shù)據(jù)集中的每個(gè)點(diǎn)的大小為m:(α 1, α 2,…,α _n)。目標(biāo)函數(shù)在α中明顯是二次的,約束是線性的,這意味著它可以很容易地用二次規(guī)劃求解。一旦找到解,由對(duì)偶的推導(dǎo)可知:

注意,只有具有α>0的點(diǎn)才定義超平面(對(duì)和有貢獻(xiàn))。這些被稱為支持向量。因此當(dāng)給定一個(gè)新例子x時(shí),返回其預(yù)測(cè)y=±1的預(yù)測(cè)方程為:

這種支持向量機(jī)的基本形式被稱為硬邊界支持向量機(jī)(hard margin SVM),因?yàn)樗鉀Q的優(yōu)化問題(如上所述)強(qiáng)制要求訓(xùn)練中的所有點(diǎn)必須被正確分類。但在實(shí)際場(chǎng)景中,可能存在一些噪聲,阻止或限制了完美分離數(shù)據(jù)的超平面,在這種情況下,優(yōu)化問題將不返回或返回一個(gè)糟糕的解決方案。

軟邊界支持向量機(jī)(soft margin SVM)通過引入C常數(shù)(用戶給定的超參數(shù))來適應(yīng)優(yōu)化問題,該常數(shù)控制它應(yīng)該有多“硬”。特別地,它將原優(yōu)化問題修改為:

它允許每個(gè)點(diǎn)產(chǎn)生一些錯(cuò)誤λ(例如,在超平面的錯(cuò)誤一側(cè)),并且通過將它們?cè)谀繕?biāo)函數(shù)中的總和加權(quán)C來減少它們。當(dāng)C趨于無窮時(shí)(一般情況下肯定不會(huì)),它就等于硬邊界。與此同時(shí),較小的C將允許更多的“違規(guī)行為”(以換取更大的支持;例如,更小的w (w)。

可以證明,等價(jià)對(duì)偶問題只有在約束每個(gè)點(diǎn)的α≤C時(shí)才會(huì)發(fā)生變化。

由于允許違例,支持向量(帶有α>0的點(diǎn))不再都在邊界的邊緣。任何錯(cuò)誤的支持向量都具有α=C,而非支持向量(α=0)不能發(fā)生錯(cuò)誤。我們稱潛在錯(cuò)誤(α=C)的支持向量為“非錯(cuò)誤編劇支持向量”和其他純粹的支持向量(沒有違規(guī);“邊界支持向量”(0<α

這樣推理方程不變:

現(xiàn)在(x?,y?)必須是一個(gè)沒有違規(guī)的支持向量,因?yàn)榉匠碳僭O(shè)它在邊界的邊緣。

軟邊界支持向量機(jī)擴(kuò)展了硬邊界支持向量機(jī)來處理噪聲,但通常由于噪聲以外的因素,例如自然非線性,數(shù)據(jù)不能被超平面分離。軟邊界支持向量機(jī)可以用于這樣的情況,但是最優(yōu)解決方案的超平面,它允許的誤差遠(yuǎn)遠(yuǎn)超過現(xiàn)實(shí)中可以容忍的誤差。

例如,在左邊的例子中,無論C的設(shè)置如何,軟邊界支持向量機(jī)都找不到線性超平面。但是可以通過某種轉(zhuǎn)換函數(shù)z=Φ(x)將數(shù)據(jù)集中的每個(gè)點(diǎn)x映射到更高的維度,從而使數(shù)據(jù)在新的高維空間中更加線性(或完全線性)。這相當(dāng)于用z替換x得到:

在現(xiàn)實(shí)中,特別是當(dāng)Φ轉(zhuǎn)換為非常高維的空間時(shí),計(jì)算z可能需要很長(zhǎng)時(shí)間。所以就出現(xiàn)了核函數(shù)。它用一個(gè)數(shù)學(xué)函數(shù)(稱為核函數(shù))的等效計(jì)算來取代z,并且更快(例如,對(duì)z進(jìn)行代數(shù)簡(jiǎn)化)。例如,這里有一些流行的核函數(shù)(每個(gè)都對(duì)應(yīng)于一些轉(zhuǎn)換Φ到更高維度空間):

這樣,對(duì)偶優(yōu)化問題就變成:

直觀地,推理方程(經(jīng)過代數(shù)處理后)為:

上面所有方程的完整推導(dǎo),有很多相關(guān)的文章了,我們就不詳細(xì)介紹了。

Python實(shí)現(xiàn)

對(duì)于實(shí)現(xiàn),我們將使用下面這些庫:

import numpy as np                  # for basic operations over arrays
 from scipy.spatial import distance  # to compute the Gaussian kernel
 import cvxopt                       # to solve the dual opt. problem
 import copy                         # to copy numpy arrays

定義核和SVM超參數(shù),我們將實(shí)現(xiàn)常見的三個(gè)核函數(shù):

class SVM:
     linear = lambda x, x? , c=0: x @ x?.T
     polynomial = lambda x, x? , Q=5: (1 + x @ x?.T)**Q
     rbf = lambda x, x?, γ=10: np.exp(-γ*distance.cdist(x, x?,'sqeuclidean'))
     kernel_funs = {'linear': linear, 'polynomial': polynomial, 'rbf': rbf}

為了與其他核保持一致,線性核采用了一個(gè)額外的無用的超參數(shù)。kernel_funs接受核函數(shù)名稱的字符串,并返回相應(yīng)的內(nèi)核函數(shù)。

繼續(xù)定義構(gòu)造函數(shù):

class SVM:
     linear = lambda x, x? , c=0: x @ x?.T
     polynomial = lambda x, x? , Q=5: (1 + x @ x?.T)**Q
     rbf = lambda x, x?, γ=10: np.exp(-γ*distance.cdist(x, x?,'sqeuclidean'))
     kernel_funs = {'linear': linear, 'polynomial': polynomial, 'rbf': rbf}
     
     def __init__(self, kernel='rbf', C=1, k=2):
         # set the hyperparameters
         self.kernel_str = kernel
         self.kernel = SVM.kernel_funs[kernel]
         self.C = C                  # regularization parameter
         self.k = k                  # kernel parameter
         
         # training data and support vectors (set later)
         self.X, y = None, None
         self.αs = None
         
         # for multi-class classification (set later)
         self.multiclass = False
         self.clfs = []

SVM有三個(gè)主要的超參數(shù),核(我們存儲(chǔ)給定的字符串和相應(yīng)的核函數(shù)),正則化參數(shù)C和核超參數(shù)(傳遞給核函數(shù));它表示多項(xiàng)式核的Q和RBF核的γ。

為了兼容sklearn的形式,我們需要使用fit和predict函數(shù)來擴(kuò)展這個(gè)類,定義以下函數(shù),并在稍后將其用作裝飾器:

SVMClass = lambda func: setattr(SVM, func.__name__, func) or func

擬合SVM對(duì)應(yīng)于通過求解對(duì)偶優(yōu)化問題找到每個(gè)點(diǎn)的支持向量α:

設(shè)α為可變列向量(α?α?…α _n);y為標(biāo)簽(y?α?…y_N)常數(shù)列向量;K為常數(shù)矩陣,其中K[n,m]計(jì)算核在(x, x)處的值。點(diǎn)積、外積和二次型分別基于索引的等價(jià)表達(dá)式:

可以將對(duì)偶優(yōu)化問題寫成矩陣形式如下:

這是一個(gè)二次規(guī)劃,CVXOPT的文檔中解釋如下:

可以只使用(P,q)或(P,q,G,h)或(P,q,G,h, A, b)等等來調(diào)用它(任何未給出的都將由默認(rèn)值設(shè)置,例如1)。

對(duì)于(P, q, G, h, A, b)的值,我們的例子可以做以下比較:

為了便于比較,將第一個(gè)重寫如下:

現(xiàn)在很明顯(0≤α等價(jià)于-α≤0):

我們就可以寫出如下的fit函數(shù):

@SVMClass
 def fit(self, X, y, eval_train=False):
     # if more than two unique labels, call the multiclass version
     if len(np.unique(y)) > 2:
         self.multiclass = True
         return self.multi_fit(X, y, eval_train)
     
     # if labels given in {0,1} change it to {-1,1}
     if set(np.unique(y)) == {0, 1}: y[y == 0] = -1
 
     # ensure y is a Nx1 column vector (needed by CVXOPT)
     self.y = y.reshape(-1, 1).astype(np.double) # Has to be a column vector
     self.X = X
     N = X.shape[0]  # Number of points
     
     # compute the kernel over all possible pairs of (x, x') in the data
     # by Numpy's vectorization this yields the matrix K
     self.K = self.kernel(X, X, self.k)
     
     ### Set up optimization parameters
     # For 1/2 x^T P x + q^T x
     P = cvxopt.matrix(self.y @ self.y.T * self.K)
     q = cvxopt.matrix(-np.ones((N, 1)))
     
     # For Ax = b
     A = cvxopt.matrix(self.y.T)
     b = cvxopt.matrix(np.zeros(1))
 
     # For Gx <= h
     G = cvxopt.matrix(np.vstack((-np.identity(N),
                                  np.identity(N))))
     h = cvxopt.matrix(np.vstack((np.zeros((N,1)),
                                  np.ones((N,1)) * self.C)))
 
     # Solve    
     cvxopt.solvers.options['show_progress'] = False
     sol = cvxopt.solvers.qp(P, q, G, h, A, b)
     self.αs = np.array(sol["x"])            # our solution
         
     # a Boolean array that flags points which are support vectors
     self.is_sv = ((self.αs-1e-3 > 0)&(self.αs <= self.C)).squeeze()
     # an index of some margin support vector
     self.margin_sv = np.argmax((0 < self.αs-1e-3)&(self.αs < self.C-1e-3))
     
     if eval_train:  
       print(f"Finished training with accuracy{self.evaluate(X, y)}")

我們確保這是一個(gè)二進(jìn)制問題,并且二進(jìn)制標(biāo)簽按照支持向量機(jī)(±1)的假設(shè)設(shè)置,并且y是一個(gè)維數(shù)為(N,1)的列向量。然后求解求解(α?α?…α _n) 的優(yōu)化問題。

使用(α?α?…α _n) _來獲得在與支持向量對(duì)應(yīng)的任何索引處為1的標(biāo)志數(shù)組,然后可以通過僅對(duì)支持向量和(x?,y?)的邊界支持向量的索引求和來應(yīng)用預(yù)測(cè)方程。我們確實(shí)假設(shè)非支持向量可能不完全具有α=0,如果它的α≤1e-3,那么這是近似為零(CVXOPT結(jié)果可能不是最終精確的)。同樣假設(shè)非邊際支持向量可能不完全具有α=C。

下面就是預(yù)測(cè)的方法,預(yù)測(cè)方程為:

@SVMClass
 def predict(self, X_t):
     if self.multiclass: return self.multi_predict(X_t)
     # compute (x?, y?)
     x?, y? = self.X[self.margin_sv, np.newaxis], self.y[self.margin_sv]
     # find support vectors
     αs, y, X= self.αs[self.is_sv], self.y[self.is_sv], self.X[self.is_sv]
     # compute the second term
     b = y? - np.sum(αs * y * self.kernel(X, x?, self.k), axis=0)
     # compute the score
     score = np.sum(αs * y * self.kernel(X, X_t, self.k), axis=0) + b
     return np.sign(score).astype(int), score

我們還可以實(shí)現(xiàn)一個(gè)評(píng)估方法來計(jì)算精度(在上面的fit中使用)。

@SVMClass
 def evaluate(self, X,y):  
     outputs, _ = self.predict(X)
     accuracy = np.sum(outputs == y) / len(y)
     return round(accuracy, 2)

最后測(cè)試我們的完整代碼:

from sklearn.datasets import make_classification
 import numpy as np
 
 # Load the dataset
 np.random.seed(1)
 X, y = make_classification(n_samples=2500, n_features=5, 
                            n_redundant=0, n_informative=5, 
                            n_classes=2,  class_sep=0.3)
 
 # Test Implemented SVM
 svm = SVM(kernel='rbf', k=1)
 svm.fit(X, y, eval_train=True)
 
 y_pred, _ = svm.predict(X)
 print(f"Accuracy: {np.sum(y==y_pred)/y.shape[0]}")  #0.9108
 
 # Test with Scikit
 from sklearn.svm import SVC
 clf = SVC(kernel='rbf', C=1, gamma=1)
 clf.fit(X, y)
 y_pred = clf.predict(X)
 print(f"Accuracy: {sum(y==y_pred)/y.shape[0]}")    #0.9108

多分類SVM

我們都知道SVM的目標(biāo)是二元分類,如果要將模型推廣到多類則需要為每個(gè)類訓(xùn)練一個(gè)二元SVM分類器,然后對(duì)每個(gè)類進(jìn)行循環(huán),并將屬于它的點(diǎn)重新標(biāo)記為+1,并將所有其他類的點(diǎn)重新標(biāo)記為-1。

當(dāng)給定k個(gè)類時(shí),訓(xùn)練的結(jié)果是k個(gè)分類器,其中第i個(gè)分類器在數(shù)據(jù)上進(jìn)行訓(xùn)練,第i個(gè)分類器被標(biāo)記為+1,所有其他分類器被標(biāo)記為-1。

@SVMClass
 def multi_fit(self, X, y, eval_train=False):
     self.k = len(np.unique(y))      # number of classes
     # for each pair of classes
     for i in range(self.k):
         # get the data for the pair
         Xs, Ys = X, copy.copy(y)
         # change the labels to -1 and 1
         Ys[Ys!=i], Ys[Ys==i] = -1, +1
         # fit the classifier
         clf = SVM(kernel=self.kernel_str, C=self.C, k=self.k)
         clf.fit(Xs, Ys)
         # save the classifier
         self.clfs.append(clf)
     if eval_train:  
         print(f"Finished training with accuracy {self.evaluate(X, y)}")

然后,為了對(duì)新示例執(zhí)行預(yù)測(cè),我們選擇相應(yīng)分類器最自信(得分最高)的類。

@SVMClass
 def multi_predict(self, X):
     # get the predictions from all classifiers
     N = X.shape[0]
     preds = np.zeros((N, self.k))
     for i, clf in enumerate(self.clfs):
         _, preds[:, i] = clf.predict(X)
     
     # get the argmax and the corresponding score
     return np.argmax(preds, axis=1), np.max(preds, axis=1)

完整測(cè)試代碼:

from sklearn.datasets import make_classification
 import numpy as np
 
 # Load the dataset
 np.random.seed(1)
 X, y = make_classification(n_samples=500, n_features=2, 
                            n_redundant=0, n_informative=2, 
                            n_classes=4, n_clusters_per_class=1,  
                            class_sep=0.3)
 
 # Test SVM
 svm = SVM(kernel='rbf', k=4)
 svm.fit(X, y, eval_train=True)
 
 y_pred = svm.predict(X)
 print(f"Accuracy: {np.sum(y==y_pred)/y.shape[0]}") # 0.65
 
 # Test with Scikit
 from sklearn.multiclass import OneVsRestClassifier
 from sklearn.svm import SVC
 
 clf = OneVsRestClassifier(SVC(kernel='rbf', C=1, gamma=4)).fit(X, y)
 y_pred = clf.predict(X)
 print(f"Accuracy: {sum(y==y_pred)/y.shape[0]}")    # 0.65

繪制每個(gè)決策區(qū)域的圖示,得到以下圖:

可以看到,我們的實(shí)現(xiàn)與Sci-kit Learn結(jié)果相當(dāng),說明在算法實(shí)現(xiàn)上沒有問題。注意:SVM默認(rèn)支持OVR(沒有如上所示的顯式調(diào)用),它是特定于SVM的進(jìn)一步優(yōu)化。

總結(jié)

我們使用Python實(shí)現(xiàn)了支持向量機(jī)(SVM)學(xué)習(xí)算法,并且包括了軟邊界和常用的三個(gè)核函數(shù)。我們還將SVM擴(kuò)展到多分類的場(chǎng)景,并使用Sci-kit Learn驗(yàn)證了我們的實(shí)現(xiàn)。希望通過本文你可以更好的了解SVM。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 向量機(jī)
    +關(guān)注

    關(guān)注

    0

    文章

    166

    瀏覽量

    20872
  • SVM
    SVM
    +關(guān)注

    關(guān)注

    0

    文章

    154

    瀏覽量

    32436
  • python
    +關(guān)注

    關(guān)注

    56

    文章

    4792

    瀏覽量

    84627
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    求助,SVM分類時(shí)要不要先進(jìn)行PCA降維

    大家知道,既然SVM可以較好地解決小樣本、非線性、高維數(shù)等分類問題,那對(duì)于高維樣本輸入,需不需要提前進(jìn)行PCA降維?PCA降維對(duì)SVM有意義嗎?還有,當(dāng)
    發(fā)表于 10-27 20:13

    KNN分類算法及python代碼實(shí)現(xiàn)

    kNN分類算法的Python實(shí)現(xiàn)
    發(fā)表于 06-05 12:02

    在stm32上實(shí)現(xiàn)svm實(shí)時(shí)訓(xùn)練與分類

    目標(biāo)在stm32上實(shí)現(xiàn)svm實(shí)時(shí)訓(xùn)練與分類,特征向量為10維向量,分類結(jié)果為多目標(biāo)分類; 1.代碼分解與抽取 libsvm源代碼文件有5個(gè):
    發(fā)表于 08-17 06:24

    怎樣通過python實(shí)現(xiàn)上位機(jī)和下位機(jī)的通信

    怎樣通過python實(shí)現(xiàn)上位機(jī)和下位機(jī)的通信?有哪些操作流程?
    發(fā)表于 11-16 06:48

    如何在stm32上實(shí)現(xiàn)svm實(shí)時(shí)訓(xùn)練與分類?

    如何在stm32上實(shí)現(xiàn)svm實(shí)時(shí)訓(xùn)練與分類?
    發(fā)表于 11-19 07:05

    集成學(xué)習(xí)的多分類器動(dòng)態(tài)組合方法

    為了提高數(shù)據(jù)的分類性能,提出一種集成學(xué)習(xí)的多分類器動(dòng)態(tài)組合方法(DEA)。該方法在多個(gè)UCI標(biāo)準(zhǔn)數(shù)據(jù)集上進(jìn)行測(cè)試,并與文中使用的基于Adaboost算法訓(xùn)練出的各個(gè)成員分類器的分類
    發(fā)表于 04-08 08:58 ?19次下載

    基于SVM的兩級(jí)指紋分類研究

    利用SVM(Support Vector Machine)解決二類分類問題的優(yōu)勢(shì),設(shè)計(jì)了一個(gè)粗細(xì)兩級(jí)指紋分類體器,提出并實(shí)現(xiàn)了一種新型的指紋分類
    發(fā)表于 07-16 14:55 ?23次下載

    基于GA-SVM的帶鋼表面缺陷模式識(shí)別

    本文采用遺傳算法(GA)對(duì)支持向量機(jī)(SVM分類器進(jìn)行參數(shù)優(yōu)化,并將其應(yīng)用于帶鋼表面缺陷分類的模式分類。實(shí)驗(yàn)數(shù)據(jù)來源于UCI標(biāo)準(zhǔn)數(shù)據(jù)集,采用10折交叉驗(yàn)證法進(jìn)行
    發(fā)表于 01-04 17:03 ?8次下載

    基于優(yōu)化SVM模型的網(wǎng)絡(luò)負(fù)面信息分類方法研究

    基于優(yōu)化SVM模型的網(wǎng)絡(luò)負(fù)面信息分類方法研究_鄭金芳
    發(fā)表于 01-07 18:56 ?0次下載

    采用SVM的網(wǎng)頁分類方法研究

    中,成功地將非線性可分問題轉(zhuǎn)化為線性可分的問題,并且在特征空間中構(gòu)造線性函數(shù),實(shí)現(xiàn)對(duì)文本的自動(dòng)分類。SVM將非線性問題轉(zhuǎn)化成線性可分問題,巧妙地解決維災(zāi)難和過學(xué)習(xí)現(xiàn)象。特征選擇是整個(gè)分類
    發(fā)表于 11-08 11:42 ?3次下載

    多分類孿生支持向量機(jī)研究進(jìn)展

    孿生支持向量機(jī)因其簡(jiǎn)單的模型、快速的訓(xùn)練速度和優(yōu)秀的性能而受到廣泛關(guān)注.該算法最初是為解決二分類問題而提出的。不能直接用于解決現(xiàn)實(shí)生活中普遍存在的多分類問題.近來,學(xué)者們致力于將二分類孿生支持向量機(jī)
    發(fā)表于 12-19 11:32 ?0次下載

    支持向量機(jī)多分類的眼電輔助肌電的人機(jī)交互

    針對(duì)單一肌電信號(hào)在控制系統(tǒng)中正確識(shí)別率不高問題,設(shè)計(jì)并實(shí)現(xiàn)了一種基于支持向量機(jī)( SVM多分類的眼電(EOG)輔助肌電(EMG)的人機(jī)交互(HCI)系統(tǒng)。該系統(tǒng)采用改進(jìn)小波包算法和閾值法分別
    發(fā)表于 01-26 17:24 ?1次下載

    SVM分類器實(shí)驗(yàn)的資料和工程文件資料免費(fèi)下載

    一、實(shí)驗(yàn)?zāi)康?1、掌握線性主持向量機(jī)(SVM分類器。 2、掌握基于高斯核的SVM分類器。 3、掌握基于拉普拉斯核的SVM
    發(fā)表于 06-17 08:00 ?0次下載

    基于SVM分類檢測(cè)器的公路車輛智能跟蹤技術(shù)

    基于SVM分類檢測(cè)器的公路車輛智能跟蹤技術(shù)
    發(fā)表于 06-22 15:58 ?18次下載

    使用Python實(shí)現(xiàn)多分類SVM

    支持向量機(jī)的目標(biāo)是擬合獲得最大邊緣的超平面(兩個(gè)類中最近點(diǎn)的距離)??梢灾庇^地表明,這樣的超平面(A)比沒有最大化邊際的超平面(B)具有更好的泛化特性和對(duì)噪聲的魯棒性。
    的頭像 發(fā)表于 12-07 09:33 ?575次閱讀
    使用<b class='flag-5'>Python</b><b class='flag-5'>從</b><b class='flag-5'>零</b><b class='flag-5'>實(shí)現(xiàn)</b><b class='flag-5'>多分類</b><b class='flag-5'>SVM</b>
    RM新时代网站-首页