寫(xiě)在之前
支持向量機(jī)(SVM),一個(gè)神秘而眾知的名字,在其出來(lái)就受到了莫大的追捧,號(hào)稱最優(yōu)秀的分類算法之一,以其簡(jiǎn)單的理論構(gòu)造了復(fù)雜的算法,又以其簡(jiǎn)單的用法實(shí)現(xiàn)了復(fù)雜的問(wèn)題,不得不說(shuō)確實(shí)完美。
本系列旨在以基礎(chǔ)化的過(guò)程,實(shí)例化的形式一探SVM的究竟。曾經(jīng)也只用過(guò)集成化的SVM軟件包,效果確實(shí)好。因?yàn)楸娙私哉f(shuō)原理復(fù)雜就對(duì)其原理卻沒(méi)怎么研究,最近經(jīng)過(guò)一段時(shí)間的研究感覺(jué)其原理還是可以理解,這里希望以一個(gè)從懵懂到略微熟知的角度記錄一下學(xué)習(xí)的過(guò)程。其實(shí)網(wǎng)絡(luò)上講SVM算法的多不勝數(shù),博客中也有許多大師級(jí)博主的文章,寫(xiě)的也很簡(jiǎn)單明了,可是在看過(guò)之和總是感覺(jué)像差點(diǎn)什么,當(dāng)然對(duì)于那些基礎(chǔ)好的可能一看就懂了,然而對(duì)于像我們這些薄基礎(chǔ)的一遍下來(lái)也能馬馬虎虎懂,過(guò)一兩天后又忘了公式怎么來(lái)的了。比如說(shuō)在研究SVM之前,你是否聽(tīng)說(shuō)過(guò)拉格朗日乘子法?你是否知道什么是對(duì)偶問(wèn)題?你是否了解它們是怎么解決問(wèn)題的?Ok這些不知道的話,更別說(shuō)什么是KKT條件了,哈哈,有沒(méi)有說(shuō)到你的心聲,不用怕,學(xué)學(xué)就會(huì)了。話說(shuō)像拉格朗日乘子法,在大學(xué)里面學(xué)數(shù)學(xué)的話,不應(yīng)該沒(méi)學(xué)過(guò),然你學(xué)會(huì)了嗎?你知道是干什么的嗎?如果那個(gè)時(shí)候就會(huì)了,那你潛質(zhì)相當(dāng)高了。作為一個(gè)過(guò)來(lái)的人,將以簡(jiǎn)單實(shí)例化形式記錄自己的學(xué)習(xí)過(guò)程,力圖幫助新手級(jí)學(xué)習(xí)者少走彎路。
一、關(guān)于拉格朗日乘子法和KKT條件
1)關(guān)于拉格朗日乘子法
首先來(lái)了解拉格朗日乘子法,那么為什么需要拉格朗日乘子法?記住,有拉格朗日乘子法的地方,必然是一個(gè)組合優(yōu)化問(wèn)題。那么帶約束的優(yōu)化問(wèn)題很好說(shuō),就比如說(shuō)下面這個(gè):

這是一個(gè)帶等式約束的優(yōu)化問(wèn)題,有目標(biāo)值,有約束條件。那么想想假設(shè)沒(méi)有約束條件這個(gè)問(wèn)題是怎么求解的呢?是不是直接f對(duì)各個(gè)x求導(dǎo)等于0,,解x就可以了,可以看到?jīng)]有約束的話,求導(dǎo)為0,那么各個(gè)x均為0吧,這樣f=0了,最小。但是x都為0不滿足約束條件呀,那么問(wèn)題就來(lái)了。這里在說(shuō)一點(diǎn)的是,為什么上面說(shuō)求導(dǎo)為0就可以呢?理論上多數(shù)問(wèn)題是可以的,但是有的問(wèn)題不可以。如果求導(dǎo)為0一定可以的話,那么f一定是個(gè)凸優(yōu)化問(wèn)題,什么是凸的呢?像下面這個(gè)左圖:

凸的就是開(kāi)口朝一個(gè)方向(向上或向下)。更準(zhǔn)確的數(shù)學(xué)關(guān)系就是:

注意的是這個(gè)條件是對(duì)函數(shù)的任意x取值。如果滿足第一個(gè)就是開(kāi)口向上的凸,第二個(gè)是開(kāi)口向下的凸??梢钥吹綄?duì)于凸問(wèn)題,你去求導(dǎo)的話,是不是只有一個(gè)極點(diǎn),那么他就是最優(yōu)點(diǎn),很合理。類似的看看上圖右邊這個(gè)圖,很明顯這個(gè)條件對(duì)任意的x取值不滿足,有時(shí)滿足第一個(gè)關(guān)系,有時(shí)滿足第二個(gè)關(guān)系,對(duì)應(yīng)上面的兩處取法就是,所以這種問(wèn)題就不行,再看看你去對(duì)它求導(dǎo),會(huì)得到好幾個(gè)極點(diǎn)。然而從圖上可以看到,只有其中一個(gè)極點(diǎn)是最優(yōu)解,其他的是局部最優(yōu)解,那么當(dāng)真實(shí)問(wèn)題的時(shí)候你選擇那個(gè)?說(shuō)了半天要說(shuō)啥呢,就是拉格朗日法是一定適合于凸問(wèn)題的,不一定適合于其他問(wèn)題,還好我們最終的問(wèn)題是凸問(wèn)題。
回頭再來(lái)看看有約束的問(wèn)題,既然有了約束不能直接求導(dǎo),那么如果把約束去掉不就可以了嗎?怎么去掉呢?這才需要拉格朗日方法。既然是等式約束,那么我們把這個(gè)約束乘一個(gè)系數(shù)加到目標(biāo)函數(shù)中去,這樣就相當(dāng)于既考慮了原目標(biāo)函數(shù),也考慮了約束條件,比如上面那個(gè)函數(shù),加進(jìn)去就變?yōu)椋?img src="http://file.elecfans.com/web1/M00/4F/A8/o4YBAFrgUP2AbSKhAAAXOuUF1sc646.jpg" />
這里可以看到與相乘的部分都為0,所以的取值為全體實(shí)數(shù)。現(xiàn)在這個(gè)優(yōu)化目標(biāo)函數(shù)就沒(méi)有約束條件了吧,既然如此,求法就簡(jiǎn)單了,分別對(duì)x求導(dǎo)等于0,如下:

把它在帶到約束條件中去,可以看到,2個(gè)變量?jī)蓚€(gè)等式,可以求解,最終可以得到,這樣再帶回去求x就可以了。那么一個(gè)帶等式約束的優(yōu)化問(wèn)題就通過(guò)拉格朗日乘子法完美的解決了。那么更高一層的,帶有不等式的約束問(wèn)題怎么辦?那么就需要用更一般化的拉格朗日乘子法即KKT條件來(lái)解決這種問(wèn)題了。
2)關(guān)于KKT條件
繼續(xù)討論關(guān)于帶等式以及不等式的約束條件的凸函數(shù)優(yōu)化。任何原始問(wèn)題約束條件無(wú)非最多3種,等式約束,大于號(hào)約束,小于號(hào)約束,而這三種最終通過(guò)將約束方程化簡(jiǎn)化為兩類:約束方程等于0和約束方程小于0。再舉個(gè)簡(jiǎn)單的方程為例,假設(shè)原始約束條件為下列所示:

那么把約束條件變個(gè)樣子:

為什么都變成等號(hào)與小于號(hào),方便后面的,反正式子的關(guān)系沒(méi)有發(fā)生任何變化就行了。
現(xiàn)在將約束拿到目標(biāo)函數(shù)中去就變成:

那么KKT條件的定理是什么呢?就是如果一個(gè)優(yōu)化問(wèn)題在轉(zhuǎn)變完后變成

其中g(shù)是不等式約束,h是等式約束(像上面那個(gè)只有不等式約束,也可能有等式約束)。那么KKT條件就是函數(shù)的最優(yōu)值必定滿足下面條件:

這三個(gè)式子前兩個(gè)好理解,重點(diǎn)是第三個(gè)式子不好理解,因?yàn)槲覀冎涝诩s束條件變完后,所有的g(x)<=0,且,然后求和還要為0,無(wú)非就是告訴你,要么某個(gè)不等式,要么其對(duì)應(yīng)的。那么為什么KKT的條件是這樣的呢?
假設(shè)有一個(gè)目標(biāo)函數(shù),以及它的約束條件,形象的畫(huà)出來(lái)就如下:

假設(shè)就這么幾個(gè)吧,最終約束是把自變量約束在一定范圍,而函數(shù)是在這個(gè)范圍內(nèi)尋找最優(yōu)解。函數(shù)開(kāi)始也不知道該取哪一個(gè)值是吧,那就隨便取一個(gè),假設(shè)某一次取得自變量集合為x1,發(fā)現(xiàn)一看,不滿足約束,然后再換呀換,換到了x2,發(fā)現(xiàn)可以了,但是這個(gè)時(shí)候函數(shù)值不是最優(yōu)的,并且x2使得g1(x)與g2(x)等于0了,而g3(x)還是小于0。
這個(gè)時(shí)候,我們發(fā)現(xiàn)在x2的基礎(chǔ)上再尋找一組更優(yōu)解要靠誰(shuí)呢?當(dāng)然是要靠約束條件g1(x)與g2(x),因?yàn)樗麄兊扔?了,很極限呀,一不小心,走錯(cuò)了就不滿足它們兩了,這個(gè)時(shí)候我們會(huì)選擇g1(x)與g2(x)的梯度方向往下走,這樣才能最大程度的拜托g(shù)1(x)與g2(x)=0的命運(yùn),使得他們滿足小于0的約束條件對(duì)不對(duì)。至于這個(gè)時(shí)候需不需要管g3(x)呢?正常來(lái)說(shuō)管不管都可以,如果管了,也取g3在x2處的梯度的話,因?yàn)間3已經(jīng)滿足了小于0的條件,這個(gè)時(shí)候在取在x2處的梯度,你能保證它是往好的變了還是往差的變了?答案是都有可能。運(yùn)氣好,往好的變了,可以更快得到結(jié)果,運(yùn)氣不好,往差的變了,反而適得其反。
那么如果不管呢?因?yàn)間1(x)與g2(x)已經(jīng)在邊緣了,所以取它的梯度是一定會(huì)讓目標(biāo)函數(shù)變好的。綜合來(lái)看,這個(gè)時(shí)候我們就不選g3。那么再往下走,假設(shè)到了自變量?jī)?yōu)化到了x3,這個(gè)時(shí)候發(fā)現(xiàn)g2(x)與g3(x)等于0,也就是走到邊了,而g1(x)小于0,可變化的空間綽綽有余,那么這個(gè)時(shí)候舉要取g2(x)與g3(x)的梯度方向作為變化的方向,而不用管g1(x)。那么一直這樣走呀走,最終找到最優(yōu)解??梢钥吹降氖牵鲜鋈绻鹓1(x)、g2(x)=0的話,我們是需要優(yōu)化它的,又因?yàn)樗麄儽旧淼臈l件是小于0的,所以最終的公式推導(dǎo)上表明,是要乘以一個(gè)正系數(shù)作為他們梯度增長(zhǎng)的倍數(shù),而那些不需要管的g(x)為了統(tǒng)一表示,這個(gè)時(shí)候可以將這個(gè)系數(shù)設(shè)置為0,那么這一項(xiàng)在這一次的優(yōu)化中就沒(méi)有了。那么把這兩種綜合起來(lái)就可以表示為

也即是某次的g(x)在為最優(yōu)解起作用,那么它的系數(shù)值(可以)不為0。如果某次g(x)沒(méi)有為下一次的最優(yōu)解x的獲得起到作用,那么它的系數(shù)就必須為0,這就是這個(gè)公式的含義。
比如上面例子的目標(biāo)值與約束:

將約束提到函數(shù)中有:

此時(shí)分別對(duì)x1、x2求導(dǎo)數(shù):

而我們還有一個(gè)條件就是,那么也就是:

這樣我們就去討論下,要么g=0,要么,這里兩個(gè)g兩個(gè),這樣我們就需要討論四種情況,可能你會(huì)說(shuō),這是約束條件少的情況,那么如果有10個(gè)約束條件,這樣就有10個(gè)g和10個(gè),你去給我討論?多少種組合,不知道,但是換個(gè)思路,我們非得去10個(gè)一起去討論?機(jī)智的學(xué)者想到一種方法,考慮到這個(gè)條件,那么我兩個(gè)兩個(gè)討論不就可以了,比如現(xiàn)在我就討論7,8,讓其他的不變,為什么選或者至少選兩個(gè)討論呢,因?yàn)檫@個(gè)式子求和為0,改變一個(gè)顯然是不行的,那就改變兩個(gè),你增我就減,這樣和可以為0。再問(wèn)為什么不討論3個(gè)呢?也可以,這不是麻煩嘛,一個(gè)俗語(yǔ)怎么說(shuō)來(lái)著,三個(gè)和尚沒(méi)水喝,假設(shè)你改變了一個(gè),另外兩個(gè)你說(shuō)誰(shuí)去減或者加使得和為0,還是兩個(gè)都變化一點(diǎn)呢?不好說(shuō)吧,自然界都是成雙成對(duì)的才和諧,沒(méi)有成三成四的(有的話也少)。
這里順便提一下后面會(huì)介紹到的內(nèi)容,就是實(shí)現(xiàn)SVM算法的SMO方法,在哪里,會(huì)有很多,那么人們?cè)趺唇鉀Q的呢,就是隨便選擇兩個(gè)去變化,看看結(jié)果好的話,就接受,不好的話就舍棄在選擇兩個(gè),如此反復(fù),后面介紹。

可以看到像這種簡(jiǎn)單的討論完以后就可以得到解了。
x1=110/101=1.08;x2=90/101=0.89,那么它得到結(jié)果對(duì)不對(duì)呢?這里因?yàn)楹瘮?shù)簡(jiǎn)單,可以在matlab下畫(huà)出來(lái),同時(shí)約束條件也可以畫(huà)出來(lái),那么原問(wèn)題以及它的約束面畫(huà)出來(lái)就如下所示:

這是截取下來(lái)的符合約束要求的目標(biāo)面

可以看到最優(yōu)解確實(shí)就是上面我們求的那個(gè)解。既然簡(jiǎn)單的問(wèn)題可以這樣解,那么復(fù)雜一點(diǎn)的只需要簡(jiǎn)單化,照樣可以解,至此KKT條件解這類約束性問(wèn)題就是這樣,它對(duì)后續(xù)的SVM求解最優(yōu)解至關(guān)重要。
二、SVM的理論基礎(chǔ)
上節(jié)我們探討了關(guān)于拉格朗日乘子和KKT條件,這為后面SVM求解奠定基礎(chǔ),本節(jié)希望通俗的細(xì)說(shuō)一下原理部分。
一個(gè)簡(jiǎn)單的二分類問(wèn)題如下圖:

我們希望找到一個(gè)決策面使得兩類分開(kāi),這個(gè)決策面一般表示就是W'X+b=0,現(xiàn)在的問(wèn)題是找到對(duì)應(yīng)的W和b使得分割最好,知道logistic分類機(jī)器學(xué)習(xí)之logistic回歸與分類的可能知道,這里的問(wèn)題和那里的一樣,也是找權(quán)值。在那里,我們是根據(jù)每一個(gè)樣本的輸出值與目標(biāo)值得誤差不斷的調(diào)整權(quán)值W和b來(lái)求得最終的解的。當(dāng)然這種求解最優(yōu)的方式只是其中的一種方式。那么SVM的求優(yōu)方式是怎樣的呢?
這里我們把問(wèn)題反過(guò)來(lái)看,假設(shè)我們知道了結(jié)果,就是上面這樣的分類線對(duì)應(yīng)的權(quán)值W和b。那么我們會(huì)看到,在這兩個(gè)類里面,是不是總能找到離這個(gè)線最近的點(diǎn),向下面這樣:

然后定義一下離這個(gè)線最近的點(diǎn)到這個(gè)分界面(線)的距離分別為d1,d2。那么SVM找最優(yōu)權(quán)值的策略就是,先找到最邊上的點(diǎn),再找到這兩個(gè)距離之和D,然后求解D的**最大值**,想想如果按照這個(gè)策略是不是可以實(shí)現(xiàn)最優(yōu)分類,是的。好了,還是假設(shè)找到了這樣一個(gè)分界面W'X+b=0,那么做離它最近的兩類點(diǎn)且平行于分類面,如上面的虛線所示。
好了再假設(shè)我們有這兩個(gè)虛線,那么真實(shí)的分界面我們認(rèn)為正好是這兩個(gè)分界面的中間線,這樣d1就等于d2了。因?yàn)檎鎸?shí)的分界面為W'X+b=0,那么就把兩個(gè)虛線分別設(shè)置為W'X+b=1和W'X+b=-1,可以看到虛線相對(duì)于真實(shí)面只是上下移動(dòng)了1個(gè)單位距離,可能會(huì)說(shuō)你怎么知道正好是一個(gè)距離?確實(shí)不知道,就假設(shè)上下是k個(gè)距離吧,那么假設(shè)上虛線現(xiàn)在為W'X+b=k,兩邊同時(shí)除k可以吧,這樣上虛線還是可以變成W'X+b=1,同理下虛線也可以這樣,然后他們的中線就是W1'X+b1=0吧,可以看到從k到1,權(quán)值無(wú)非從w變化到w1,b變到b1,我在讓w=w1,b=b1,不是又回到了起點(diǎn)嗎,也就是說(shuō),這個(gè)中間無(wú)非是一個(gè)倍數(shù)關(guān)系。
所以我們只需要先確定使得上下等于1的距離,再去找這一組權(quán)值,這一組權(quán)值會(huì)自動(dòng)變化到一定倍數(shù)使得距離為1的。
好了再看看D=d1+d2怎么求吧,假設(shè)分界面W'X+b=0,再假設(shè)X是兩維的,那么分界面再細(xì)寫(xiě)出來(lái)就是:W1'X1+W2'X2+b=0。上分界線:W1'X1+W2'X2+b=1,這是什么,兩條一次函數(shù)(y=kx+b)的曲線是不是,那么初中就學(xué)過(guò)兩直線的距離吧,

這里W=(w1,w2),是個(gè)向量,||W||為向量的距離,那么||W||^2=W'W。下界面同理。這樣

,
要使D最大,就要使分母最小,這樣優(yōu)化問(wèn)題就變?yōu)?img src="http://file.elecfans.com/web1/M00/4F/A8/o4YBAFrgUQOAJsupAAAGZd1TwCk021.jpg" />,乘一個(gè)系數(shù)0.5沒(méi)影響,但是在后面卻有用。

注意的是這可不是一個(gè)約束條件,而是對(duì)所有的每個(gè)樣本xi都有一個(gè)這樣的約束條件。轉(zhuǎn)換到這種形式以后是不是很像上節(jié)說(shuō)到的KKT條件下的優(yōu)化問(wèn)題了,就是這個(gè)。但是有一個(gè)問(wèn)題,我們說(shuō)上節(jié)的KKT是在凸函數(shù)下使用的,那么這里的目標(biāo)函數(shù)是不是呢?答案是的,想想W'*W,函數(shù)乘出來(lái)應(yīng)該很單一,不能有很多極點(diǎn),當(dāng)然也也可以數(shù)學(xué)證明是的。
好了那樣的話就可以引入拉格朗日乘子法了,優(yōu)化的目標(biāo)變?yōu)椋?/p>

然后要求這個(gè)目標(biāo)函數(shù)最優(yōu)解,求導(dǎo)吧,

這兩個(gè)公式非常重要,簡(jiǎn)直是核心公式。
求導(dǎo)得到這個(gè)應(yīng)該很簡(jiǎn)單吧,那我問(wèn)你為什么W'W 對(duì)w求導(dǎo)是w呢?如果你知道,那么你很厲害了,反正開(kāi)始我是一直沒(méi)轉(zhuǎn)過(guò)來(lái)。其實(shí)說(shuō)起來(lái)也很簡(jiǎn)單,如果光去看看為什么求導(dǎo)以后,轉(zhuǎn)置就沒(méi)了,不太好想明白,設(shè)想一下假設(shè)現(xiàn)在是二維樣本點(diǎn),也就是最終的W=(w1,w2),那么W'W=w1*w1+w2*w2那么對(duì)w1求導(dǎo)就是2w1,對(duì)w2就是2w2,這樣寫(xiě)在一起就是對(duì)w求導(dǎo)得到(2w1,2w2)=2w了,然后乘前面一個(gè)1/2(這也就是為什么要加一個(gè)1/2),就變成w了。
好了得到上面的兩個(gè)公式,再帶回L中把去w和b消掉,你又可能發(fā)現(xiàn),w確實(shí)可以消,因?yàn)橛械仁疥P(guān)系,那b怎么辦?上述對(duì)b求導(dǎo)的結(jié)果竟然不含有b,上天在開(kāi)玩笑嗎?其實(shí)沒(méi)有,雖然沒(méi)有b,但是有那個(gè)求和為0呀,帶進(jìn)去你會(huì)驚人的發(fā)現(xiàn),b還真的可以消掉,就是因?yàn)榱四莻€(gè)等式。簡(jiǎn)單帶下:

那么求解最最開(kāi)始的函數(shù)的最小值等價(jià)到這一步以后就是求解W的最大值了,因?yàn)槭褂昧死窭嗜粘俗臃ê?,原?wèn)題就變?yōu)槠鋵?duì)偶問(wèn)題了,最小變成了最大,至于為什么,等到詳細(xì)研究過(guò)對(duì)偶問(wèn)題再來(lái)解釋吧。不了解的,只需要知道求W的極值即可。整理一下,經(jīng)過(guò)這么一圈的轉(zhuǎn)化,最終的問(wèn)題為:

為什么有ai>0$,這是上節(jié)說(shuō)到的KKT條件的必須。至此問(wèn)題來(lái)源部分到這。
細(xì)心的你肯可能會(huì)發(fā)現(xiàn),上述所有的構(gòu)造等等都是在數(shù)據(jù)完全線性可分,且分界面完全將兩類分開(kāi),那么如果出現(xiàn)了下面這種情況:

正負(fù)兩類的最遠(yuǎn)點(diǎn)沒(méi)有明顯的分解面,搞不好正類的最遠(yuǎn)點(diǎn)反而會(huì)跑到負(fù)類里面去了,負(fù)類最遠(yuǎn)點(diǎn)跑到正類里面去了,要是這樣的話,你的分界面都找不到,因?yàn)槟悴豢赡苷业綄⑺鼈兺耆珠_(kāi)的分界面,那么這些點(diǎn)在實(shí)際情況是有的,就是一些離群點(diǎn)或者噪聲點(diǎn),因?yàn)檫@一些點(diǎn)導(dǎo)致整個(gè)系統(tǒng)用不了。當(dāng)然如果不做任何處理確實(shí)用不了,但是我們處理一下就可以用了。SVM考慮到這種情況,所以在上下分界面上加入松弛變量e,認(rèn)為如果正類中有點(diǎn)到上界面的距離小于e,那么認(rèn)為他是正常的點(diǎn),哪怕它在上界面稍微偏下一點(diǎn)的位置,同理下界面。還是以上面的情況,我們目測(cè)下的是理想的分解面應(yīng)該是下面這種情況:

如果按照這種分會(huì)發(fā)現(xiàn)4個(gè)離群點(diǎn),他們到自己對(duì)應(yīng)分界面的距離表示如上,理論上講,我們給每一個(gè)點(diǎn)都給一個(gè)自己的松弛變量ei,如果一個(gè)分界面求出來(lái)了,那么比較這個(gè)點(diǎn)到自己對(duì)應(yīng)的界面(上、下界面)的距離是不是小于這個(gè)值,要是小于這個(gè)值,就認(rèn)為這個(gè)界面分的可以,比如上面的e3這個(gè)點(diǎn),雖然看到明顯偏離了正軌,但是計(jì)算發(fā)現(xiàn)它的距離d小于等于我們給的e3,那么我們說(shuō)這個(gè)分界面可以接受。你可能會(huì)說(shuō)那像上面的e10,距離那么遠(yuǎn)了,他肯定是大于預(yù)設(shè)給這個(gè)點(diǎn)的ei了對(duì)吧,確實(shí)是這樣的,但是我們還發(fā)現(xiàn)什么?這個(gè)點(diǎn)是分對(duì)了的點(diǎn)呀,所以你管他大不大于預(yù)設(shè)值,反正不用調(diào)整分界面。需要調(diào)整分界面的情況是只有當(dāng)類似e3這樣的點(diǎn)的距離大于了e3的時(shí)候。

你發(fā)現(xiàn)目標(biāo)函數(shù)里面多了一點(diǎn)東西,而加上這個(gè)是合理的,我們?cè)趦?yōu)化的同時(shí),也使得總的松弛變量之和最小。常數(shù)C決定了松弛變量之和的影響程度,如果越大,影響越嚴(yán)重,那么在優(yōu)化的時(shí)候會(huì)更多的注重所有點(diǎn)到分界面的距離,優(yōu)先保證這個(gè)和小。好了將問(wèn)題寫(xiě)在一起吧:


三、SMO算法原理與實(shí)戰(zhàn)求解
上節(jié)我們討論到解SVM問(wèn)題最終演化為求下列帶約束條件的問(wèn)題:

問(wèn)題的解就是找到一組
使得W最小。
現(xiàn)在我們來(lái)看看最初的約束條件是什么樣子的:

這是最初的一堆約束條件吧,現(xiàn)在有多少個(gè)約束條件就會(huì)有多少個(gè)αi。那么KKT條件的形成就是讓:

我們知道αi≥0,而后面那個(gè)小于等于0,所以他們中間至少有一個(gè)為0(至于為什么要這么做,第一節(jié)討論過(guò))。再簡(jiǎn)單說(shuō)說(shuō)原因,假設(shè)現(xiàn)在的分類問(wèn)題如下:

某一次迭代后,分類面為粗藍(lán)線所示,上下距離為1的分界面如細(xì)藍(lán)線所示,而理想的分界面如紫虛線所示。那么我們想想,要想把粗藍(lán)線變化到紫虛線,在這一次是哪些個(gè)點(diǎn)在起作用?很顯然是界于細(xì)藍(lán)線邊上以及它們之間的所有樣本點(diǎn)在起作用吧,而對(duì)于那些在細(xì)藍(lán)線之外的點(diǎn),比如正類的四個(gè)圈和反類的三個(gè)叉,它們?cè)谶@一次的分類中就已經(jīng)分對(duì)了,那還考慮它們干什么?所以這一次就不用考慮這些分對(duì)了的點(diǎn)。那么我們用數(shù)學(xué)公式可以看到,對(duì)于在這一次就分對(duì)了的點(diǎn),它們滿足什么關(guān)系,顯然yi(Wxi+b)>1,然后還得滿足
,那么顯然它們的αi=0。對(duì)于那些在邊界內(nèi)的點(diǎn),顯然yi(Wxi+b)≤1,而這些點(diǎn)我們說(shuō)是要為下一次達(dá)到更好的解做貢獻(xiàn)的,那么我們就取這些約束條件的極限情況,也就是yi(Wxi+b)=1,在這些極限約束條件下,我們就會(huì)得到一組新的權(quán)值W與b,也就是改善后的解。那么既然這些點(diǎn)的yi(Wxi+b)=1,那它對(duì)應(yīng)的αi就可以不為0了,至于是多少,那就看這些點(diǎn)具體屬于分界面內(nèi)的什么位置了,偏離的越狠的點(diǎn),我想它對(duì)應(yīng)的αi就越大,這樣才能把這個(gè)偏得非常狠的點(diǎn)給拉回來(lái),或者說(shuō)使其在下一次的解中更靠近正確的分類面。

那么滿足KKT條件的,我們說(shuō)如果一個(gè)點(diǎn)滿足KKT條件,那么它就不需要調(diào)整,一旦不滿足,就需要調(diào)整。由上可知,不滿足KKT條件的也有三種情況:





至此我們可以說(shuō),簡(jiǎn)單的,線性的,帶有松弛條件(可以容錯(cuò)的)的整個(gè)SMO算法就完了,剩下的就是循環(huán),選擇兩個(gè)α,看是否需要更新(如果不滿足KKT條件),不需要再選,需要就更新。一直到程序循環(huán)很多次了都沒(méi)有選擇到兩個(gè)不滿足KKT條件的點(diǎn),也就是所有的點(diǎn)都滿足KKT了,那么就大功告成了。
當(dāng)然了,這里面還有些問(wèn)題就是如何去優(yōu)化這些步驟,最明顯的就是怎么去選擇這兩個(gè)α,程序越到后期,你會(huì)發(fā)現(xiàn)只有那么幾個(gè)點(diǎn)不滿足KKT條件,這個(gè)時(shí)候如果你再去隨機(jī)選擇兩個(gè)點(diǎn)的α,那么它是滿足的,就不更新,循環(huán),這樣一直盲目的找呀找,程序的效率明顯就下來(lái)了。當(dāng)然這在后面是有解決辦法的。
先不管那么多,就先讓他盲目盲目的找吧,設(shè)置一個(gè)代數(shù),盲目到一定代數(shù)停止就ok了,下面就來(lái)一個(gè)盲目找α的matlab程序,看看我們的SMO算法如何。

我的樣本是這樣的:

程序如下:
%%% * svm 簡(jiǎn)單算法設(shè)計(jì)%%% 加載數(shù)據(jù)% * 最終data格式:m*n,m樣本數(shù),n維度% * label:m*1 標(biāo)簽必須為-1與1這兩類clcclearclose alldata = load('data_test2.mat');data = data.data;train_data = data(1:end-1,:)';label = data(end,:)';[num_data,d] = size(train_data);data = train_data;%% 定義向量機(jī)參數(shù)alphas = zeros(num_data,1);% 系數(shù)b = 0;% 松弛變量影響因子C = 0.6;iter = 0;max_iter = 40;%%while iter < max_iter ? ?alpha_change = 0; ? ?for i = 1:num_data ? ? ? ?%輸出目標(biāo)值 ? ? ? ?pre_Li = (alphas.*label)'*(data*data(i,:)') + b; ? ? ? ?%樣本i誤差 ? ? ? ?Ei = pre_Li - label(i); ? ? ? ?% 滿足KKT條件 ? ? ? ?if (label(i)*Ei<-0.001 && alphas(i)
程序中設(shè)置了松弛變量前的系數(shù)C是事先規(guī)定的,表明松弛變量項(xiàng)的影響程度大小。下面是幾個(gè)不同C下的結(jié)果:
這是80個(gè)樣本點(diǎn),matlab下還是挺快2秒左右就好了。上圖中,把真實(shí)分界面,上下范圍為1的界面,以及那些α不為0的點(diǎn)(綠色標(biāo)出)都畫(huà)了出來(lái),可以看到,C越大,距離越起作用,那么落在分界線之間的點(diǎn)就越少。同時(shí)可以看到,三種情況下,真實(shí)的分界面(藍(lán)色)都可以將兩種樣本完全分開(kāi)(我的樣本并沒(méi)有重疊,也就是完全是可分的)。
好了,這就是隨機(jī)選取α的實(shí)驗(yàn),第一個(gè)α是按順序遍歷所有的α,第二個(gè)α是在剩下的α中在隨機(jī)選一個(gè)。當(dāng)?shù)诙€(gè)α選了iter次還沒(méi)有發(fā)現(xiàn)不滿足KKT條件的,就退出循環(huán)。同時(shí)程序中的KKT條件略有不同,不過(guò)是一樣的。下面介紹如何進(jìn)行啟發(fā)式的選取α呢?我們分析分析,比如上一次的一些點(diǎn)的α在0-C之間,也就是這些點(diǎn)不滿足條件需要調(diào)整,那么一次循環(huán)后,他調(diào)整了一點(diǎn),在下一次中這些點(diǎn)是不是還是更有可能不滿足條件,因?yàn)槊恳淮蔚恼{(diào)整比較不可能完全。而那些在上一次本身滿足條件的點(diǎn),那么在下一次后其實(shí)還是更有可能滿足條件的。所以在啟發(fā)式的尋找α過(guò)程中,我們并不是遍歷所有的點(diǎn)的α,而是遍歷那些在0-C之間的α,而0-C反應(yīng)到點(diǎn)上就是那些屬于邊界之間的點(diǎn)是不是。當(dāng)某次遍歷在0-C之間找不到α了,那么我們?cè)偃フw遍歷一次,這樣就又會(huì)出現(xiàn)屬于邊界之間α了,然后再去遍歷這些α,如此循環(huán)。那么在遍歷屬于邊界之間α的時(shí)候,因?yàn)槭切枰x兩個(gè)α的,第一個(gè)可以隨便選,那第二個(gè)呢?這里在用一個(gè)啟發(fā)式的思想,第1個(gè)α選擇后,其對(duì)應(yīng)的點(diǎn)與實(shí)際標(biāo)簽是不是有一個(gè)誤差,屬于邊界之間α的所以點(diǎn)每個(gè)點(diǎn)都會(huì)有一個(gè)自己的誤差,這個(gè)時(shí)候選擇剩下的點(diǎn)與第一個(gè)α點(diǎn)產(chǎn)生誤差之差最大的那個(gè)點(diǎn)。
程序如下:
%%% * svm 簡(jiǎn)單算法設(shè)計(jì) --啟發(fā)式選擇%%% 加載數(shù)據(jù)% * 最終data格式:m*n,m樣本數(shù),n維度% * label:m*1 標(biāo)簽必須為-1與1這兩類clcclearclose alldata = load('data_test2.mat');data = data.data;train_data = data(1:end-1,:)';label = data(end,:)';[num_data,d] = size(train_data);data = train_data;%% 定義向量機(jī)參數(shù)alphas = zeros(num_data,1);b = 0;error = zeros(num_data,2);tol = 0.001;C = 0.6;iter = 0;max_iter = 40;%%alpha_change = 0;entireSet = 1;%作為一個(gè)標(biāo)記看是選擇全遍歷還是部分遍歷while (iter < max_iter) && ((alpha_change > 0) || entireSet) alpha_change = 0; %% -----------全遍歷樣本------------------------- if entireSet for i = 1:num_data Ei = calEk(data,alphas,label,b,i);%計(jì)算誤差 if (label(i)*Ei<-0.001 && alphas(i)
其中的子函數(shù),一個(gè)是計(jì)算誤差函數(shù),一個(gè)是選擇函數(shù)如下:
function Ek = calEk(data,alphas,label,b,k)pre_Li = (alphas.*label)'*(data*data(k,:)') + b;Ek = pre_Li - label(k);
function [J,Ej] = select(i,data,num_data,alphas,label,b,C,Ei,choose)maxDeltaE = 0;maxJ = -1;if choose == 1 %全遍歷---隨機(jī)選擇alphas j = randi(num_data ,1); if j == i temp = 1; while temp j = randi(num_data,1); if j ~= i temp = 0; end end end J = j; Ej = calEk(data,alphas,label,b,J);else %部分遍歷--啟發(fā)式的選擇alphas index = find(alphas>0 & alphas < C); ? ?for k = 1:length(index) ? ? ? ?if i == index(k) ? ? ? ? ? ?continue; ? ? ? ?end ? ? ? ?temp_e = calEk(data,alphas,label,b,k); ? ? ? ?deltaE = abs(Ei - temp_e); %選擇與Ei誤差最大的alphas ? ? ? ?if deltaE > maxDeltaE maxJ = k; maxDeltaE = deltaE; Ej = temp_e; end end J = maxJ;end
至此算是完了,試驗(yàn)了一下,兩者的效果其實(shí)差不多(反而隨機(jī)選取的效果更好一點(diǎn),感覺(jué)是因?yàn)殡S機(jī)保證了更多的可能,畢竟隨機(jī)選擇包括了你的特殊選擇,但是特殊選擇到后期是特殊不起來(lái)的,反而隨機(jī)會(huì)把那些差一點(diǎn)的選擇出來(lái)),但是速度上當(dāng)樣本小的時(shí)候,基本上差不多,但是當(dāng)樣本大的時(shí)候,啟發(fā)式的特殊選擇明顯占優(yōu)勢(shì)了。我試驗(yàn)了400個(gè)樣本點(diǎn)的情況,隨機(jī)選擇10多秒把,而啟發(fā)式2,3秒就好了??梢?jiàn)效果差不多的情況下,啟發(fā)式選擇是首要選擇。
至此兩種方式下的方法都實(shí)驗(yàn)完了。那么我們看到,前面(三節(jié))所講的一切以及實(shí)驗(yàn),分類的樣本都是線性樣本,那么如果來(lái)了非線性樣本該如何呢?而SVM的強(qiáng)大之處更在于對(duì)非線性樣本的準(zhǔn)確劃分。那么前面的理論對(duì)于非線性樣本是否適用?我們又該如何處理非線性樣本呢?請(qǐng)看下節(jié)SVM非線性樣本的分類。
四、SVM非線性分類原理實(shí)驗(yàn)
前面幾節(jié)我們討論了SVM原理、求解線性分類下SVM的SMO方法。本節(jié)將分析SVM處理非線性分類的相關(guān)問(wèn)題。
一般的非線性分類如下左所示(后面我們將實(shí)戰(zhàn)下面這種情況):
可以看到在原始空間中你想用一個(gè)直線分類面劃分開(kāi)來(lái)是不可能了,除非圓。而當(dāng)你把數(shù)據(jù)點(diǎn)映射一下成右圖所示的情況后,現(xiàn)在數(shù)據(jù)點(diǎn)明顯看上去是線性可分的,那么在這個(gè)空間上的數(shù)據(jù)點(diǎn)我們?cè)儆们懊娴腟VM算法去處理,就可以得到每個(gè)數(shù)據(jù)點(diǎn)的分類情況了,而這個(gè)分類情況也是我們?cè)诘途S空間的情況。也就是說(shuō),單純的SVM是不能處理非線性問(wèn)題的,說(shuō)白了只能處理線性問(wèn)題,但是來(lái)了非線性樣本怎么辦呢?我們是在樣本上做的文章,我把非線性樣本變成線性樣本,再去把變化后的線性樣本拿去分類,經(jīng)過(guò)這么一圈,就達(dá)到了把非線性樣本分開(kāi)的目的,所以只看開(kāi)頭和結(jié)尾的話發(fā)現(xiàn),SVM竟然可以分非線性問(wèn)題,其實(shí)呢還是分的線性問(wèn)題。
現(xiàn)在的問(wèn)題是如何找到這個(gè)映射關(guān)系對(duì)吧,就比如上面那個(gè)情況,我們可以人為計(jì)算出這種映射,比如一個(gè)樣本點(diǎn)是用坐標(biāo)表示的(x1,x2),它有個(gè)類標(biāo)簽,假設(shè)為1,那么把這個(gè)點(diǎn)映射到三維中變成
然后按照上面那個(gè)公式去把每個(gè)點(diǎn)映射成3維坐標(biāo)點(diǎn)后,畫(huà)出來(lái)是這樣的:
可以看到是線性可分的吧,如果還看不清把視角換個(gè)角度(右視圖):
現(xiàn)在能看清楚了吧。那這是二維的點(diǎn)到三維,映射的關(guān)系就是上面的那個(gè)關(guān)系,那如果是三維到四維,四維到N維呢?這個(gè)關(guān)系你還想去找嗎?理論上是找的到的,但是實(shí)際上人工去找你怎么去找?你怎么知道數(shù)據(jù)的映射關(guān)系是這樣的是那樣的?不可能知道。然而我們真的需要找到這種關(guān)系嗎?答案是不需要的,返回去看看前三節(jié)的關(guān)于SVM的理論部分可以看到,無(wú)論是計(jì)算a呀,還是b呀等等,只要涉及到原始數(shù)據(jù)點(diǎn)的,都是以內(nèi)積的形式出來(lái)的,也就是說(shuō)是一個(gè)點(diǎn)的向量與另一個(gè)點(diǎn)的向量相乘的,向量?jī)?nèi)積出來(lái)是一個(gè)值。
就拿a來(lái)更新來(lái)說(shuō),如下:
最后也是得到一個(gè)值比如C2。既然SVM里面所有涉及到原始數(shù)據(jù)的地方都是以向量的形式出現(xiàn)的,那么我們還需要管它的映射關(guān)系嗎?因?yàn)樗膊恍枰闳ビ?jì)算說(shuō)具體到比如說(shuō)三維以后,三維里面的三個(gè)坐標(biāo)值究竟是多少,他需要的是內(nèi)積以后的一個(gè)結(jié)果值。那么好辦了,我就假設(shè)有一個(gè)黑匣子,輸入原始數(shù)據(jù)維度下的兩個(gè)坐標(biāo)向量,然后經(jīng)過(guò)黑匣子這么一圈,出來(lái)一個(gè)值,這個(gè)值我們就認(rèn)為是高維度下的值。而黑匣子的潛在意義就相當(dāng)于一個(gè)高維映射器一樣。更重要的是我們并不需要知道黑匣子究竟是怎么映射的,只需要知道它的低緯度下的形式就可以了。常用的黑匣子就是徑向基函數(shù),而這個(gè)黑匣子在數(shù)學(xué)上就叫做核函數(shù),例如徑向基函數(shù)的外在形式如下所示:
o是需要預(yù)先設(shè)定的參數(shù)。至于這個(gè)黑匣子把初始數(shù)據(jù)映射到多少維了,誰(shuí)知道呢,既然是黑匣子,那就是看不到的,上帝給了人類這么一個(gè)黑匣子就已經(jīng)很夠意思了??梢钥吹降氖窃紨?shù)據(jù)結(jié)果黑匣子算了以后,出來(lái)就是一個(gè)值了,而這個(gè)值就認(rèn)為是高維度下的數(shù)據(jù)通過(guò)內(nèi)積計(jì)算而來(lái)的值。當(dāng)然上帝還留了一個(gè)窗戶,就是o,相傳o選取的越小,數(shù)據(jù)映射的維度越大,小到一定程度,維度空間大到無(wú)窮維。反之越大,映射的維度空間就越小,但是會(huì)不會(huì)小到低于原始空間維度呢?誰(shuí)知道了,然而通過(guò)實(shí)驗(yàn)我發(fā)現(xiàn),大到一定程度,樣本點(diǎn)分的亂七八糟,并且o正好在一定范圍的時(shí)候效果非常好,這個(gè)范圍既不是極小的范圍,也不是極大的范圍,那這暗示了什么呢?也就是說(shuō)非線性原始樣本是有一個(gè)屬于他自己的最佳高維空間的,大了小了似乎都不好。
好了既然黑匣子是藏著的,那也就只能說(shuō)這么多了。有趣的是上帝給的這個(gè)黑匣子不止一個(gè),有好幾個(gè),只是上面的那個(gè)普遍效果更好而已?;诖耍敲磳?duì)于上節(jié)的SMO算法,如果拿來(lái)求解非線性數(shù)據(jù)的話,我們只需要將其中對(duì)應(yīng)的內(nèi)積部分改成核函數(shù)的形式即可。一個(gè)數(shù)據(jù)核函數(shù)程序如下:
function result = Kernel(data1,data2,sigma)% data里面每一行數(shù)據(jù)是一個(gè)樣本(的行向量)[m1,~] = size(data1);[m2,~] = size(data2);result = zeros(m1,m2);for i = 1:m1 for j = 1:m2 result(i,j) = exp(-norm(data1(i,:)-data2(j,:))/(2*sigma^2)); endend
有了此核函數(shù),我們用上節(jié)的隨機(jī)遍歷αα的方式(這個(gè)函數(shù)代碼少一點(diǎn))來(lái)實(shí)驗(yàn)一下非線性樣本,非線性樣本如下:然后把主程序?qū)?yīng)的部分用上述核函數(shù)代替:
%%% * svm 簡(jiǎn)單算法設(shè)計(jì)%%% 加載數(shù)據(jù)% * 最終data格式:m*n,m樣本數(shù),n維度% * label:m*1 標(biāo)簽必須為-1與1這兩類clcclear% close alldata = load('data_test1.mat');data = data.data;train_data = data(1:end-1,:)';label = data(end,:)';[num_data,d] = size(train_data);data = train_data;%% 定義向量機(jī)參數(shù)alphas = zeros(num_data,1);% 系數(shù)b = 0;% 松弛變量影響因子C = 0.6;iter = 0;max_iter = 80;% 核函數(shù)的參數(shù)sigma = 4;%%while iter < max_iter ? ?alpha_change = 0; ? ?for i = 1:num_data ? ? ? ?%輸出目標(biāo)值 ? ? ? ?pre_Li = (alphas.*label)'*Kernel(data,data(i,:),sigma) + b; ? ? ? ?%樣本i誤差 ? ? ? ?Ei = pre_Li - label(i); ? ? ? ?% 滿足KKT條件 ? ? ? ?if (label(i)*Ei<-0.001 && alphas(i)
下面是幾個(gè)不同參數(shù)下的結(jié)果:
可以看到σ到4以后就分不出來(lái)了。綠色的為支持向量,可以看到在σ在0.6到1之間是最少的,結(jié)果應(yīng)該也是最好的。至此SMO實(shí)驗(yàn)非線性樣本完畢。
當(dāng)今學(xué)者已經(jīng)有非常多的人研究SVM算法,同時(shí)開(kāi)發(fā)了許多開(kāi)源的程序,這些程序都是經(jīng)過(guò)不斷優(yōu)化的,性能比起我們這里自己編的來(lái)說(shuō)要好得多,所以在實(shí)際應(yīng)用中通常都是用他們無(wú)私貢獻(xiàn)的軟件包。一個(gè)典型的軟件包就是***一個(gè)教授團(tuán)隊(duì)的LIBSVM軟件包,那么你是否想一窺其用法,看看它的性能如何呢?請(qǐng)看下節(jié)matlab下LIBSVM的簡(jiǎn)單使用。
五、MATLAB下libsvm的簡(jiǎn)單使用:分類與回歸
本節(jié)簡(jiǎn)單介紹一下libsvm的使用方法。關(guān)于libsvm似乎曾經(jīng)使用過(guò),那個(gè)時(shí)候主要用libsvm進(jìn)行簡(jiǎn)單的人臉識(shí)別實(shí)驗(yàn)。
1)介紹與分類實(shí)驗(yàn)
那么現(xiàn)在最新版本的libsvm為3.2.0,下載地址如下:http://www.csie.ntu.edu.tw/~cjlin/libsvm/
下載下來(lái)的libsvm其實(shí)包含好多個(gè)平臺(tái)的工具箱軟件,c++,matlab,java,python都有。他們的函數(shù)使用方法是一樣的。
那么在下載完以后,點(diǎn)擊里面的matlab下平臺(tái),直接在點(diǎn)擊里面的make.m函數(shù)就可以了。正常情況下如果你的matlab含有編譯平臺(tái)的話直接就可以運(yùn)行了,如果沒(méi)有,還需要選擇一個(gè)平臺(tái) mex -setup 。小提醒一下,這個(gè)編譯過(guò)程不要在c盤下使用,也就是libsvm先不要放在c盤,涉及到權(quán)限,機(jī)器不讓編譯。編譯完后在matlab的設(shè)置路徑中添加進(jìn)去編譯的文件夾及其內(nèi)容,那么就可以使用了。正常編譯的過(guò)程是這樣的: 在上面的人臉識(shí)別實(shí)驗(yàn)中曾經(jīng)介紹過(guò)里面的主要函數(shù),這里為了放在一塊,把那里的拿過(guò)來(lái)吧:
目前版LIBSVM(3.2.0)在matlab下編譯完后只有四個(gè)函數(shù),libsvmread,Libsvmwrite,svmtrain(matlab自帶的工具箱中有一個(gè)同名的函數(shù)),svmpredict。
libsvmread主要用于讀取數(shù)據(jù)
這里的數(shù)據(jù)是非matlab下的.mat數(shù)據(jù),比如說(shuō)是.txt,.data等等,這個(gè)時(shí)候需要使用libsvmread函數(shù)進(jìn)行轉(zhuǎn)化為matlab可識(shí)別數(shù)據(jù),比如自帶的數(shù)據(jù)是heart_scale數(shù)據(jù),那么導(dǎo)入到matlab有兩種方式,一種使用libsvmread函數(shù),在matlab下直接libsvmread(heart_scale);第二種方式為點(diǎn)擊matlab的‘導(dǎo)入數(shù)據(jù)’按鈕,然后導(dǎo)向heart_scale所在位置,直接選擇就可以了。個(gè)人感覺(jué)第二種方式超級(jí)棒,無(wú)論對(duì)于什么數(shù)據(jù),比如你在哪個(gè)數(shù)據(jù)庫(kù)下下載的數(shù)據(jù),如何把它變成matlab下數(shù)據(jù)呢?因?yàn)橛械臄?shù)據(jù)libsvmread讀取不管用,但是‘導(dǎo)入數(shù)據(jù)’后就可以變成matlab下數(shù)據(jù)。
libsvmwrite寫(xiě)函數(shù),就是把已知數(shù)據(jù)存起來(lái)
使用方式為:libsvmwrite(‘filename’,label_vector, instance_matrix);label_vector是標(biāo)簽,instance_matrix為數(shù)據(jù)矩陣(注意這個(gè)數(shù)據(jù)必須是稀疏矩陣,就是里面的數(shù)據(jù)不包含沒(méi)用的數(shù)據(jù)(比如很多0),有這樣的數(shù)據(jù)應(yīng)該去掉再存)。
svmtrain訓(xùn)練函數(shù),訓(xùn)練數(shù)據(jù)產(chǎn)生模型的
一般直接使用為:model=svmtrain(label,data,cmd); label為標(biāo)簽,data為訓(xùn)練數(shù)據(jù)(數(shù)據(jù)有講究,每一行為一個(gè)樣本的所有數(shù)據(jù),列數(shù)代表的是樣本的個(gè)數(shù)),每一個(gè)樣本都要對(duì)應(yīng)一個(gè)標(biāo)簽(分類問(wèn)題的話一般為二分類問(wèn)題,也就是每一個(gè)樣本對(duì)應(yīng)一個(gè)標(biāo)簽)。cmd為相應(yīng)的命令集合,都有哪些命令呢?很多,-v,-t,-g,-c,等等,不同的參數(shù)代表的含義不同,比如對(duì)于分類問(wèn)題,這里-t就表示選擇的核函數(shù)類型,-t=0時(shí)線性核。-t=1多項(xiàng)式核,-t=2,徑向基函數(shù)(高斯),-t=3,sigmod核函數(shù),新版出了個(gè)-t=4,預(yù)計(jì)算核(還不會(huì)用);-g為核函數(shù)的參數(shù)系數(shù),-c為懲罰因子系數(shù),-v為交叉驗(yàn)證的數(shù),默認(rèn)為5,這個(gè)參數(shù)在svmtrain寫(xiě)出來(lái)使用與不寫(xiě)出來(lái)不使用的時(shí)候,model出來(lái)的東西不一樣,不寫(xiě)的時(shí)候,model為一個(gè)結(jié)構(gòu)體,是一個(gè)模型,可以帶到svmpredict中直接使用,寫(xiě)出來(lái)的時(shí)候,出來(lái)的是一個(gè)訓(xùn)練模型的準(zhǔn)確率,為一個(gè)數(shù)值。一般情況下就這幾個(gè)參數(shù)重要些,還有好多其他參數(shù),可以自己參考網(wǎng)上比較全的,因?yàn)橄旅娴倪@種方法的人臉識(shí)別就用到這么幾個(gè)參數(shù),其他的就不寫(xiě)了。
svmpredict訓(xùn)練函數(shù),使用訓(xùn)練的模型去預(yù)測(cè)來(lái)的數(shù)據(jù)類型。
使用方式為:
[predicted_label,accuracy,decision_values/prob_estimates]= svmpredict(testing_label_vector,testing_instance_matrix,model,’libsvm_options’)
或者:
[predicted_label]=svmpredict(testing_label_vector,testing_instance_matrix, model, ‘libsvm_options’)
第一種方式中,輸出為三個(gè)參數(shù),預(yù)測(cè)的類型,準(zhǔn)確率,評(píng)估值(非分類問(wèn)題用著),輸入為測(cè)試類型(這個(gè)可與可無(wú),如果沒(méi)有,那么預(yù)測(cè)的準(zhǔn)確率accuracy就沒(méi)有意義了,如果有,那么就可以通過(guò)這個(gè)值與預(yù)測(cè)出來(lái)的那個(gè)類型值相比較得出準(zhǔn)確率accuracy,但是要說(shuō)明一點(diǎn)的是,無(wú)論這個(gè)值有沒(méi)有,在使用的時(shí)候都得加上,即使沒(méi)有,也要隨便加上一個(gè)類型值,反正你也不管它對(duì)不對(duì),這是函數(shù)使用所規(guī)定的的),再就是輸入數(shù)據(jù)值,最后是參數(shù)值(這里的參數(shù)值只有兩種選擇,-p和-b參數(shù)),曾經(jīng)遇到一個(gè)這樣的問(wèn)題,比如說(shuō)我在訓(xùn)練函數(shù)中規(guī)定了-g參數(shù)為0.1,那么在預(yù)測(cè)的時(shí)候是不是也要規(guī)定這個(gè)參數(shù)呢?當(dāng)你規(guī)定了以后,程序反而錯(cuò)誤,提醒沒(méi)有svmpredict的-g參數(shù),原因是在svmtrain后會(huì)出現(xiàn)一個(gè)model,而在svmpredict中你已經(jīng)用了這個(gè)model,而這個(gè)model中就已經(jīng)包含了你所有的訓(xùn)練參數(shù)了,所以svmpredict中沒(méi)有這個(gè)參數(shù),那么對(duì)于的libsvm_options就是-p和-b參數(shù)了。對(duì)于函數(shù)的輸出,兩種方式調(diào)用的方法不一樣,第一種調(diào)用把所有需要的數(shù)據(jù)都調(diào)用出來(lái)了,二第二種調(diào)用,只調(diào)用了predicted_label預(yù)測(cè)的類型,這里我們可以看到,在單純的分類預(yù)測(cè)模型中,其實(shí)第二種方式更好一些吧,既簡(jiǎn)單有實(shí)用。
致此,四個(gè)函數(shù)在分類問(wèn)題中的介紹大概如此,當(dāng)然還有很多可以優(yōu)化的細(xì)節(jié)就不詳細(xì)說(shuō)了,比如可以再使用那些參數(shù)的時(shí)候,你如果不規(guī)定參數(shù)的話,所有的-參數(shù)都是使用默認(rèn)的,默認(rèn)的就可能不是最好的吧,這樣就涉及到如何去優(yōu)化這個(gè)參數(shù)了。
使用就介紹到這里吧,下面實(shí)戰(zhàn)一下,樣本集選擇前面使用的200個(gè)非線性樣本集,函數(shù)如下:
%%% * libsvm 工具箱簡(jiǎn)單使用%%% 加載數(shù)據(jù)% * 最終data格式:m*n,m樣本數(shù),n維度% * label:m*1 標(biāo)簽為-1與1這兩類clcclearclose alldata = load('data_test1.mat');data = data.data';%選擇訓(xùn)練樣本個(gè)數(shù)num_train = 80;%構(gòu)造隨機(jī)選擇序列choose = randperm(length(data));train_data = data(choose(1:num_train),:);gscatter(train_data(:,1),train_data(:,2),train_data(:,3));label_train = train_data(:,end);test_data = data(choose(num_train+1:end),:);label_test = test_data(:,end);predict = zeros(length(test_data),1);%% ----訓(xùn)練模型并預(yù)測(cè)分類model = svmtrain(label_train,train_data(:,1:end-1),'-t 2');% -t = 2 選擇徑向基函數(shù)核 true_num = 0;for i = 1:length(test_data) % 作為預(yù)測(cè),svmpredict第一個(gè)參數(shù)隨便給個(gè)就可以 predict(i) = svmpredict(1,test_data(i,1:end-1),model);end%% 顯示結(jié)果figure;index1 = find(predict==1);data1 = (test_data(index1,:))';plot(data1(1,:),data1(2,:),'or');hold onindex2 = find(predict==-1);data2 = (test_data(index2,:))';plot(data2(1,:),data2(2,:),'*');hold onindexw = find(predict~=(label_test));dataw = (test_data(indexw,:))';plot(dataw(1,:),dataw(2,:),'+g','LineWidth',3);accuracy = length(find(predict==label_test))/length(test_data);title(['predict the testing data and the accuracy is :',num2str(accuracy)]);
可以看到,關(guān)于svm的部分就那么一點(diǎn),其他的都是輔助吧,那么一個(gè)結(jié)果如下:
數(shù)據(jù)人為設(shè)置了一些重疊,這個(gè)結(jié)果算是非常好了。當(dāng)然對(duì)于libsvm函數(shù),里面還有許多細(xì)節(jié),像參數(shù)選擇等等,不同的參數(shù)結(jié)果是不一樣的,這就待你去探究了。
2)回歸實(shí)驗(yàn)
回歸問(wèn)題不像分類問(wèn)題,回歸問(wèn)題相當(dāng)于根據(jù)訓(xùn)練樣本訓(xùn)練出一個(gè)擬合函數(shù)一樣,可以根據(jù)這個(gè)擬合函數(shù)可以來(lái)預(yù)測(cè)給定一個(gè)樣本的輸出值。可以看到分類問(wèn)題輸出的是樣本所屬于的類,而回歸問(wèn)題輸出的是樣本的預(yù)測(cè)值。
常用的地方典型的比如股票預(yù)測(cè),人口預(yù)測(cè)等等此類預(yù)測(cè)問(wèn)題。
libsvm同樣可以進(jìn)行回歸預(yù)測(cè),所需要改變的只是里面的參數(shù)設(shè)置。查看libsvm的官網(wǎng)介紹參數(shù)詳情如下:
options:-s svm_type : set type of SVM (default 0) 0 -- C-SVC 1 -- nu-SVC 2 -- one-class SVM 3 -- epsilon-SVR 4 -- nu-SVR-t kernel_type : set type of kernel function (default 2) 0 -- linear: u'*v 1 -- polynomial: (gamma*u'*v + coef0)^degree 2 -- radial basis function: exp(-gamma*|u-v|^2) 3 -- sigmoid: tanh(gamma*u'*v + coef0)-d degree : set degree in kernel function (default 3)-g gamma : set gamma in kernel function (default 1/num_features)-r coef0 : set coef0 in kernel function (default 0)-c cost : set the parameter C of C-SVC, epsilon-SVR, and nu-SVR (default 1)-n nu : set the parameter nu of nu-SVC, one-class SVM, and nu-SVR (default 0.5)-p epsilon : set the epsilon in loss function of epsilon-SVR (default 0.1)-m cachesize : set cache memory size in MB (default 100)-e epsilon : set tolerance of termination criterion (default 0.001)-h shrinking: whether to use the shrinking heuristics, 0 or 1 (default 1)-b probability_estimates: whether to train a SVC or SVR model for probability estimates, 0 or 1 (default 0)-wi weight: set the parameter C of class i to weight*C, for C-SVC (default 1)
可以看到-s svm_type 控制的就是訓(xùn)練類型,而當(dāng)-s等于3或4的時(shí)候,就是回歸模型SVR。
-s 3 就是常用的帶懲罰項(xiàng)的 SVR模型,我們用這個(gè)實(shí)驗(yàn)。我使用的是libsvm3.2.0工具箱,版本不同可能會(huì)帶來(lái)調(diào)用方式的不同。測(cè)試實(shí)驗(yàn)的代碼如下,可能會(huì)有一些細(xì)節(jié)需要自己去探索:
close all;clear;clc;%%% 生成待回歸的數(shù)據(jù)x = (-1:0.1:1)';y = -100*x.^3 + x.^2 - x + 1;% 加點(diǎn)噪聲y = y+ 20*rand(length(y),1);%% 采用交叉驗(yàn)證選擇參數(shù)mse = 10^7;for log2c = -10:0.5:3, for log2g = -10:0.5:3, % -v 交叉驗(yàn)證參數(shù):在訓(xùn)練的時(shí)候需要,測(cè)試的時(shí)候不需要,否則出錯(cuò) cmd = ['-v 3 -c ', num2str(2^log2c), ' -g ', num2str(2^log2g) , ' -s 3 -p 0.4 -t 3']; cv = svmtrain(y,x,cmd); if (cv < mse), ? ? ? ? ? ?mse = cv; bestc = 2^log2c; bestg = 2^log2g; ? ? ? ?end ? ?endend%% ?訓(xùn)練--cmd = ['-c ', num2str(2^bestc), ' -g ', num2str(2^bestg) , ' -s 3 -p 0.4 -n 0.1'];model = svmtrain(y,x,cmd);% model% 利用建立的模型看其在訓(xùn)練集合上的回歸效果% 注意libsvm3.2.0的svmpredict函數(shù)必須有三個(gè)參數(shù)輸出[py,~,~] = svmpredict(y,x,model);figure;plot(x,y,'o');hold on;plot(x,py,'g+');%% % 進(jìn)行預(yù)測(cè)新的x值%-- 產(chǎn)生[-1 1]的隨機(jī)數(shù)testx = -2+(2-(-2))*rand(10,1);testy = zeros(10,1);% 理論y值無(wú)所謂[ptesty,~,~] = svmpredict(testy,testx,model);hold on;plot(testx,ptesty,'r*');legend('原始數(shù)據(jù)','回歸數(shù)據(jù)','新數(shù)據(jù)');grid on;% title('t=0:線性核')% title('t=1:多項(xiàng)式核')% title('t=2:徑向基函數(shù)(高斯)')title('t=3:sigmod核函數(shù)')
這里我隨機(jī)生成一個(gè)3次函數(shù)的隨機(jī)數(shù)據(jù),測(cè)試了幾種不同svm里面的核函數(shù):
因?yàn)槲覀兊臄?shù)據(jù)是由三次函數(shù)模擬生成的,所以可以看到,在這種情況下使用線性核t=0時(shí)候效果更好,然而實(shí)際情況下一般我們也不知道數(shù)據(jù)的分布函數(shù),所以在選擇核函數(shù)的時(shí)候還是需要多實(shí)驗(yàn),找到最適合自己數(shù)據(jù)的核函數(shù)。
這里采用了交叉驗(yàn)證的方式自適應(yīng)選擇模型中重要的兩個(gè)參數(shù),需要注意的是參數(shù)的范圍,不要太大,步長(zhǎng)可能也需要控制,否則在數(shù)據(jù)量很大的時(shí)候需要運(yùn)行很久。



,對(duì)每個(gè)點(diǎn)我都這么去映射,假設(shè)一個(gè)原始點(diǎn)樣本集是這樣的:?














-
SVM
+關(guān)注
關(guān)注
0文章
154瀏覽量
33694 -
kkt
+關(guān)注
關(guān)注
0文章
4瀏覽量
4141
原文標(biāo)題:SVM大解密(附代碼和公式)
文章出處:【微信號(hào):AI_Thinker,微信公眾號(hào):人工智能頭條】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
心率、脈搏血氧監(jiān)測(cè)儀(硬件+Arduino代碼,附心率和SpO2算法)
一種基于凸殼算法的SVM集成方法
SVM與Fourier算法在電網(wǎng)短期負(fù)荷預(yù)測(cè)中的應(yīng)用
PID控制超詳細(xì)教程-附凌陽(yáng)芯片源代碼
卡爾曼濾波簡(jiǎn)介及其實(shí)現(xiàn)(附C代碼)
一種混沌人工魚(yú)群算法對(duì)SVM參數(shù)的優(yōu)化及應(yīng)用
基于MapReduce的SVM態(tài)勢(shì)評(píng)估算法
PID程序算法的詳細(xì)資料概述免費(fèi)下載
正激變換器中的高頻變壓器設(shè)計(jì)公式詳細(xì)概述
PA043圖像文字識(shí)別SVM的技術(shù)源代碼和資料講解
SPI總線驅(qū)動(dòng)的C語(yǔ)言源代碼詳細(xì)概述
支持向量機(jī)SVM算法在智能交通系統(tǒng)中的應(yīng)用綜述
SVM算法附代碼和公式詳細(xì)概述
評(píng)論