前面在寫NumPy文章的結尾處也有提到,本來是打算按照《機器學習實戰 / Machine Learning in Action》這本書來手撕其中代碼的,但由于實際原因,可能需要先手撕SVM了,這個算法感覺還是挺讓人頭疼,其中内部太複雜了,涉及到的數學公式太多了,也涉及到了許多陌聲的名詞,如:非線性限制條件下的最優化、KKT條件、拉格朗日對偶、最大間隔、最優下界、核函數等等,天書或許、可能、大概就是這樣的吧。
記得與SVM初次邂逅是在17年,那個時候的自己年少輕狂,視圖想着站在巨人的肩膀上,把所有自己感興趣的内容都搞懂,深入骨髓的那種。但後來殘酷的現實讓我明白一個道理:你知道的越多,你不知道的也越多。而且那個時候自己也沒有能力、資源和機會去深入SVM内部,完全無法了解SVM的内部原理。是以,當時自己對SVM的收獲隻有一個:SVM主要是用來做分類任務的,僅此而已。
第二次接觸SVM是在準備考研複試吧,當時複試并沒有給出具體内容和範圍,而且自己也還是個初出茅廬的小子,對這種所謂的複試有種莫名的恐懼感。也隻有從上屆學長學姐的口中,得知複試的時候老師會考究學生是否有科研的潛力,是以最好把機器學習熟知一下。那個時候也是處于新冠疫情的緊張時期嘛,就瘋狂補習機器學習的内容,其中就包括支援向量機——SVM,主要的學習管道是吳恩達老師的機器學習課程,感覺講的的确不錯,非常适合我這種菜鳥級選手學習。當時也算是對SVM有了一定的認識吧,也大緻了解了SVM的工作原理,當然了,也隻是對SVM有了個的淺顯的認識,沒有手撕SVM的過程,也沒有完全把它整明白。盡管如此,複試的過程依然被面試導師錘的體無完膚,除了問了機器學習相關内容之外,編譯原理等一些專業知識對于我這個貿易專業的學生來講可太痛苦了,之前也沒有接觸過,全程阿巴阿巴。想到這,眼角又又。。。
第三次面對SVM也就是現在了,想着無論如何也要打通我的任督二脈,一定要搞清楚SVM的來龍去脈,也要像面試老師捶我那樣,把SVM往死裡錘。于是有了下文學習SVM之後的總結,一方面算是重新梳理一遍SVM,另一方面也希望來訪的讀者能夠有所收獲。
對于剛剛接觸SVM的讀者,Taoye主要有以下幾條建議,也是我學習SVM過程中的一個小總結吧:
SVM内部的數學公式很多,但請不要未戰先怯,犯下兵家大忌。無論是閱讀該篇文章也好,學習其他相關SVM資源也罷,還請諸君耐心、認真且完整的看完。
SVM的原理過程會涉及到很多的符号或記号,一定要梳理清楚他們所代表的含義。另外,推導過程中會存在很多的向量或矩陣,一定要明白其中shape,這一點可能在不同的資料中會有不一樣的處理方式。
在閱讀的同時,一定要拿出稿紙手動推演SVM的過程,盡可能明白整個過程的來龍去脈,有不明白的地方可以留言或查找其他相關資料來輔助自己的了解。
閱讀一遍或許有不少知識不了解,但多閱讀幾遍相信一定會有不少收獲
本文參考了不少書籍資料以及許多大佬的技術文章,行文風格盡可能做到通俗易懂,但其中涉及到的數學公式在所難免,還請諸讀者靜下心來慢慢品嘗。由于個人水準有限,才疏學淺,對于SVM也隻是略知皮毛,可能文中有不少表述稍有欠妥、有不少錯誤或不當之處,還請諸君批評指正。
我是Taoye,愛專研,愛分享,熱衷于各種技術,學習之餘喜歡下象棋、聽音樂、聊動漫,希望借此一畝三分地記錄自己的成長過程以及生活點滴,也希望能結實更多志同道合的圈内朋友,更多内容歡迎來訪微信公主号:玩世不恭的Coder
符号
說明
表示單個樣本,其中包含多個屬性,顯示為一個行向量
表示單個樣本中的某個屬性特征
表示單個樣本所對應的标簽(具體分類),為整數,非1即-1
表示的是權值行向量,其中,也是所需要訓練的參數
表示的是決策面中的,也是所需要訓練的參數
表示函數間隔,具體解釋見下文
表示幾何間隔,具體解釋見下文
表示拉格朗日乘子
在這篇文章中表示線性核函數
關于上述的符号說明,僅僅隻是本篇文章的一部分,其他符号可通過正文了解。上述符号可能部分暫時不懂,但沒關系,讀者可在閱讀的過程中,随時傳回來檢視,即可了解每個符号所代表的意義。
關于SVM是什麼,之前在Byte Size Biology上看到有篇文章很好的解釋了SVM,在知乎上也有一位名叫“簡之”的使用者通過故事的形式來将其進行轉述,通俗易懂,很好的向首次接觸SVM的讀者介紹了SVM能幹嘛。
Support Vector Machines explained well(可能需要FQ):http://bytesizebio.net/2014/02/05/support-vector-machines-explained-well/
支援向量機(SVM)是什麼意思?:https://www.zhihu.com/question/21094489/answer/86273196

油管上也有更為直覺認識SVM的短視訊(FQ):https://www.youtube.com/watch?v=3liCbRZPrZA
總結一哈:
對于一個二分類問題,樣本資料是線性可分的,我們則需要通過一根直線(也就是上述例子當中枝條)将兩個不同種類的樣本進行分離。按道理來講,我們已經實作了需求,但是,這根枝條的具體擺放位置可能有無數多個,而我們的最終目的是将枝條擺放到一個最好的位置,進而當我們引入了一些新樣本的時候,依然能最好很好将兩類的資料分離開來,也就是說我們需要将模型的“泛化性能”最大化。之前也看到過一個例子(來源忘了),這裡分享下,大概就是講:我們在通過懸崖吊橋的時候,會不自覺的盡可能往中間走,因為這樣的話,當左右起風的時候,雖然我們的位置會左右稍微移動,但還不至于跌落懸崖。而越靠近邊緣,風險就越大,就是這麼個道理。而尋找最大“泛化性能”的過程,就是将枝條擺放在距離小球最遠的位置,而小球相對于枝條的位置就是“間隔”,而我們要做的就是将這間隔最大化。
上述僅僅是對于線性可分資料分類的一種處理方式,但有的時候,理想是美好的,現實卻是殘酷的。在實際樣本資料中,大多都是線性不可分的,也就是說我們無法找到合适位置的枝條将不同分類的資料分離開來,更别提“間隔最大化”了。這個時候,我們就需要将桌上的小球排起,然後用一個平面(紙)将不同分類小球分離開來。也就是說,我們将低次元映射到了高緯度,這樣對于小球的分類就更加容易了。
再之後,無聊的大人們,把這些球叫做 「data」,把棍子 叫做 「classifier」, 最大間隙trick 叫做「optimization」, 拍桌子叫做「kernelling」, 那張紙叫做「hyperplane」。
我們先來看具體看看線性可分的二分類問題。
假如說,我們這裡有一堆樣本,也就是我們常說的訓練集,且表示的是樣本的屬性特征向量,其内部有多個不同屬性,這裡我們不妨指定每個樣本含有兩個屬性特征,也就是說(之是以用列向量表示,主要是友善後面超平面的建構)。而表示的是每個樣本中所有屬性特征所對應的标簽,由于這裡的問題屬性二分類,是以的值隻存在兩種。為此,我們可以通過Matplotlib在平面直角坐标系中繪制其圖像,初步觀察其分布規律,具體代碼如下:
執行代碼,可以繪制如下所示圖檔,注意:以上代碼每次運作都會随機産生不同的二分類資料集,如想每次随機産生相同的資料集,可自行配置<code>np.random.seed</code>随機種子;另外,還有一點需要需要說明的是,上述代碼使用到了NumPy,關于NumPy的使用,可自行參考之前寫的一篇文章:print( "Hello,NumPy!" )
如上圖所示,我們可以發現,棕色代表一類資料集,此時标簽,藍色代表另一類資料集,标簽,而要想将上圖兩類資料集分離開來,顯然不止一條直線,與上圖兩條虛線平行且居其之間的任意一條直線都能達到此目的。在這無數條直線中,要數上圖中的三條最為特殊,中間實線居于兩條虛線中間,我們一般稱其為“決策面”或“超平面”,而其所表示的方程,我們一般稱作“決策方程”或“超平面方程”,在這裡可以表示為。(下面會推導)
從上圖我們還可以觀察得到,在所有樣本資料集中,虛線上的樣本距離決策面最近,我們把這種比較特殊的樣本資料一般稱之為“支援向量”,而支援向量到決策面之間的距離稱為“間隔”。我們不難發現,決策面的位置主要取決于支援向量,而與支援向量除外的資料樣本沒有關系。(因為支援向量的确定就已經确定了最大間隔)
關于上述提到的一些關于SVM的名詞概念,在正式推演之前,還是有必要了解清楚的。
前面我們也有提到,關于能将兩類不同資料集互相分隔開來的直線有無數種,而我們要想在這無數種直線找到一條最合适的,也就是達到一個間隔最大化的目的,這就是一個“最優化”問題。而最優化問題,我們需要了解兩個因素,分别是目标函數和優化對象。既然我們是想要達到間隔最大化的目标,那麼目标函數自然就是間隔,而優化對象就是我們的決策面方程。是以,我們首先需要用數學來明确間隔和決策面方程:
我們知道,在平面直角坐标系中,一條直線可以用其一般式方程來來表示:
而根據上述圖像,我們可以知道,橫縱坐标代表的意義是一個樣本的不同屬性特征,而标簽則是通過顔色(棕色和藍色)來進行表示。是以上述的直線的一般式方程中的表示的就是一個樣本的兩種屬性特征,為了友善了解,我們不妨将其修改為,并将替換為,對此,我們可以将上述方程向量化,得到:
<code></code>
令,則上述指向方程最終可以表示為:
式(1-2)表示的就是我們優化問題的優化對象,也就是決策面方程。我們知道在平面直角坐标系中,一條直線可以通過其斜率和截距來确定,而在決策面方程裡,我們不難得到:确定了決策面的方向(斜率) ,而确定了決策面的截距。既然我們已經得到了優化問題的優化對象——決策面方程,那麼接下來就需要得到目标函數——間隔的表達式了。
在此,我們需要引入函數間隔和幾何間隔的概念了。
一般來講,我們可以通過樣本點到決策面的距離來表示分類預測的正确程度,距離決策面越遠,一般分類就越正确(可根據圖像自行了解),而在超平面确定的情況下,我們可以通過的值來描述樣本距超平面的遠近(注意:這裡是描述遠近。而不是确切的距離)。我們知道,樣本有不同的分類,是以有的時候的符号具有不确定性,是以我們可以通過和的符号來判斷分類結果的正确性。也就是說可以通過值的大小和符号來判斷一個樣本分類的正确性和正确程度,這個就是我們的函數間隔(這個概念務必要了解清楚),我們不妨用來表示:
而我們知道,上述的,表示的是有個樣本,而在個樣本中,固然存在一個樣本使得該值達到最小,該樣本也就是我們前面所說的支援向量,我們把支援向量到超平面的函數間隔定義為,則:
我們隻有函數間隔還不夠,函數間隔描述的僅僅是樣本分類的正确性和正确程度,而不是确切的間隔。當我們成比例的更改和的時候,決策面并沒有發生任何改變,而函數間隔卻發生了改變,是以我們需要對進行限制,進而當無論和怎麼成比例變動的時候,我們的“間隔”都不會發生改變,也就是進行将規範化,由函數間隔規範後的間隔我們稱之為幾何間隔,我們不妨用來表示,則某個樣本到超平面的幾何間隔為:
我們可以将式子(1-5)了解成點到直線的距離公式(這個在中學時期就學過的)。對于這個二分類問題,我們不妨将二分類的标簽定為 ,則可以表示為(之是以乘以,主要是把絕對值符号去掉,這樣就能描述所有樣本了,而省去了分類讨論的麻煩):
而我們知道,上述的,表示的是有個樣本,而在個樣本中,固然存在一個樣本使得該值達到最小,該樣本也就是我們前面所說的支援向量,我們把支援向量到超平面的幾何間隔定義為,則:
通過上述對函數間隔和幾何間隔的分析,我們可以得到他們之間的關系:
自此,我們已經分析得到了該優化問題的優化對象——決策面方程和目标函數——間隔(幾何間隔)。在之前,我們提到了支援向量的概念,那麼支援向量具有什麼特性呢?細想一下不難發現,支援向量到決策平面的間隔是最近的,即滿足如下式子:
對此,我們就可以通過數學來表達該優化問題:
前面,我們提到了,函數間隔描述的僅僅是樣本分類的正确性和正确程度,而不是确切的間隔。當我們成比例的更改和的時候,函數間隔雖然發生了改變,但并不會影響我們的幾何間隔——目标函數,也就是說,此時産生了一個等價的最優化問題。為了友善描述問題,我們不妨取。另外,我們注意到目标函數可以等價于,(注意,僅僅是等價。而之是以等價為二分之一、平方的形式,主要是友善後期的求導操作),對此,我們可以将數學表達的優化問題轉化為如下形式:
關于如上提到的決策平面和間隔等概念,我們可以通過下圖來直覺感受下(了解清楚):
圖檔來源:西瓜書
至此,我們已經得到了該優化問題的數學表達,我們不妨通過一個小例子來檢測下:
例子來源:李航-《統計學習方法》第七章内容
例子1:已知一個如圖所示的訓練資料集,其正例點是,負例點為,試求最大間隔分離的決策面?
根據前面的優化問題表達,我們可以得到如下表示:
求解可以得到目标函數的最小時,,于是最大間隔分離的決策面為:
其中,與為支援向量。
首先,我們有必要先了解下什麼是拉格朗日乘數法。
關于對偶問題,《統計學習方法》一書中是如此描述的:
為了求解線性可分的支援向量機的最優化問題,将它作為原始最優化問題,應用拉格朗日對偶性,通過求解對偶問題(dual problem)得到原始問題(primary problem)的最優解,這就是線性可分支援向量機的對偶算法(dual algorithm)。這樣做的優點,一是對偶問題往往更容易求解;二是自然引入核函數,進而推廣到非線性分類問題。
按照前面對優化問題的求解思路,構造拉格朗日方程的目的是将限制條件放到目标函數中,進而将有限制優化問題轉換為無限制優化問題。我們仍然秉承這一思路去解決不等式限制條件下的優化問題,那麼如何針對不等式限制條件下的優化問題建構拉格朗日函數呢?
因為我們要求解的是最小化問題,是以一個直覺的想法是如果我能夠構造一個函數,使得該函數在可行解區域内與原目标函數完全一緻,而在可行解區域外的數值非常大,甚至是無窮大,那麼這個沒有限制條件的新目标函數的優化問題就與原來有限制條件的原始目标函數的優化是等價的問題。
對此,我們重新回顧下原優化問題的數學表達:
關于拉個朗日乘數法的解題思路,其實早在大學《高等數學》這門課程中就已經提到過,我們不妨通過一個小例子來了解下其解題的一般形式:
例子來源:李億民-《微積分方法》第二章内容
例子2:求函數在上的最值。
做拉格朗日函數:
上面的拉格朗日函數,我們分别對求偏導,得到:
求解得到或,是以
上例就是利用拉格朗日求解最優問題的一般思路,先構造拉格朗日函數,然後分别對參數求偏導,最終求解得到最優解。而我們要想得到最大間隔,同樣可以根據該思路進行,隻不過式子更加複雜,而我們還需要利用拉格朗日的對偶性來簡化優化問題。
在此之前,我們先來回顧下該優化問題下的數學表達:
按照我們例2的思路,我們首先構造出該優化問題的拉格朗日函數,注意:(2-1)式的限制條件是對于樣本 的,而這裡的,是以想這樣的限制條件有N個,而每個限制條件都對應一個拉格朗日乘子(例2的),我們不妨将該拉格朗日乘子定義為。據此,我們建構出的該優化問題的拉格朗日函數如下:
其中,為拉格朗日乘子向量。
令,原始目标函數即可轉化為:
根據上述目标函數,我們可以發現是先求最大值,再求最小值,而内層最小值是關于,而外層最大值是關于,而我們的又是不等式限制,這樣對于求解來講過于麻煩。由拉格朗日的對偶性,原始問題的對偶問題就是極大極小值,其對偶問題如下:
且原問題和對偶問題滿足如關系:,而我們要找的是。讀到這裡,我們應該會存在兩個疑問:
疑問1:為什麼前面我們令$\theta(w,b)=\mathop{max}\limits_{\alpha>0} \ L(w,b,\alpha)$,而不是其他的表達形式呢?
主要是因為,這樣替換之後,我們能使得該函數在可行解區域内與原目标函數完全一緻,而在可行解區域外的數值非常大,甚至是無窮大,那麼這個沒有限制條件的新目标函數的優化問題就與原來有限制條件的原始目标函數的優化是等價的問題。(這句話要重點了解)
令:
之後,在可行解區域之内和可行解區域之外,我們通過分析得到:在可行解區域之内,
此時,我們要求的是 ,而減去一個大于等于0的最大值是多少?不就是等于麼,而同樣也是我們可行解區域之内的目标函數。也就是說在可行解區域之内,就等價于。同理,我們可以分析得到,在的可行解區域之外,此時可區域無窮大。是以沒有限制的新目标函數的優化問題就與原來有限制條件的原始目标函數的優化是等價的問題,即:
疑問2:為什麼将原問題轉化為對偶問題之後,在什麼樣的條件下,才會滿足$d^= p^$?
轉化為對偶問題之後,要使得等式成立,則需要滿足如下條件,也就是該問題成立時候的KKT條件:
前兩個條件我們不難得到,前面我們也有過對其進行分析,那麼第三個條件為什麼需要滿足呢?
在介紹支援向量和決策平面的時候,我們有提到,最終的決策平面隻會與支援向量相關,而與其他大多數樣本資料(非支援向量)無關。我們不妨來對它們分别介紹,當樣本點為支援向量的時候,此時,即當所取的樣本點為非支援向量的時候,要使得,則此時的。是以從整體樣本域來講,隻有滿足的時候,才能到達目标決策平面與支援向量有關,而與其他大多數非支援向量無關。
綜上,隻有滿足KKT條件的時候,才能到達,即在滿足KKT條件的時候,才能将原始目标問題,轉化為對偶問題,此時兩者是等價的,且此時的目标函數為内層關于的最小值,而外層是關于的最大值,這樣一來,大大友善了我們對目标函數的求解。是以優化問題,我們轉化如下:
而要解決這個優化問題,我們可以分為兩步來進行求解:
先求内層關于的最小值,此時我們應該将視為常數
再求外層關于的最大值,由于經過了第一步關于的最小值,這兩個參數已經被消掉了,是以第二步隻會存在關于的求解
經過上述對目标函數的問題分析,我們下面根據上述的兩個步驟來手握手式的進行求解。
首先,我們需要對内層的最小值問題進行求解,即求:
注意,此時僅僅隻是關于,而是由外層最大值問題進行求解的,在這裡當做常數處理即可。根據例2,我們需要求出關于的偏導,我們在這假設每個樣本含有個屬性,則,應各位“老婆們”的要求,具體求偏導的詳細過程如下:
為了讓讀者徹底明白上述過程,是以步驟有點多,這裡就不采用Latex文法來編輯上述公式的推導過程了,當然了,Taoye會盡可能地将過程寫的足夠詳細。上述關于拉格朗日函數求偏導的過程,自認為已經寫的很詳細了,最主要的是要區分的shape問題,以及各自代表的意義是什麼。對于上述過程有不清楚的,随時歡迎聯系Taoye或在下方留言,也歡迎更多讀者來訪微信公衆号:玩世不恭的Coder。
對此,我們已經通過上面過程得到關于偏導所要滿足的式子:
之後,我們将式子(4-2)重新帶回到(4-1)中的最小值問題中,即可消掉參數,也就是說得到的式子僅僅隻是關于,具體代回過程如下圖所示:
上圖就是将對求導之後所得到的式子待會的完整過程,務必要好好了解清楚。
關于這個代回的過程,有兩點還是有必要說一下的,這也是前幾天實驗室的同學存在疑問的地方。(參照上述圖檔來解疑)
疑問1:這裡前一項難道不是和後一項同樣為0麼?因為不是說了$\sum_{i=1}^N\alpha_iy_i=0$啊???
其實這個地方的後一項是為0,而前一項并不一定為0。因為後一項中的其實就相當于一個固定的常數,也就是中的每一項所乘的數都是,這樣的話,固定的常數乘以0,結果當然依然等于0咯。
而我們再看看前一項,可以發現前一項中除了之外,還有的存在,而我們的是會随着樣本的變化而改變的,是以每次乘的數可能并不一定相同。舉個例子了解一下吧:,這個我們都應該知道。當我們在的前面同時乘以一個相同的數,這個等式是依然成立的,然而當我在前面分别乘以一個并不相同的數,那麼這個等式就不成立了,比如 依然成立,而 2+33-45=02∗2+3∗3−4∗5=0就不成立了。
就是這個道理,務必要好好了解清楚。
疑問2:為什麼這一步可以推導至下面那一步呢???
其實這個問題很好了解,因為這兩個成績形式的式子是互相獨立的,也就是說雖然都有,但是這兩個并不一定是同時取同一個值的。這就像一種笛卡爾積的形式,是以将前一個式子中的換成
依然成立,是以能推導至下面那一步。。。
通過上述過程,我們已經得到了代回之後的式子,如下:
并且我們觀察可以發現,式子此時僅僅隻存在,而已經成功被消掉了。注意:上式中的表示的樣本,也就說這些樣本的各個屬性特征以及标簽都是已知的,是以上式隻有是未知的。
至此,我們已經解決了對偶問題的内層最小值問題,接下來我們就要求解外層的最大值問題了,将最小值的式子代回原對偶問題,我們更新下對偶問題,得到如下:
如上,已經将原對偶轉換為了上式的樣子,下面我們據此再來看之前的例1
例子3:已知一個如圖所示的訓練資料集,其正例點是,負例點為,試求最大間隔分離的決策面?
根據所給資料,其對偶問題是:
我們将代入到目标函數并記為:
對求偏導數并令其為0,易知在點取極值,但該點不滿足限制條件,是以最小值應在邊界上達到。
當時,最小值為;當時,最小值。是以,當時,此時達到最小。
這樣的話,就說明所對應的點就是支援向量了,根據,我們可以求得此時,再由,可以得到
綜上,我們可以得到決策面最終為:
曆經九九八十一難,終于來到了這最後一步了,隻要我們能求得上式的最小值,那麼模型的求解也就該到一段落了。
那麼,問題來了,關于上式,我們應當如何求解呢???
下面就應該是我們的重頭戲閃亮登場了——SMO算法,各位看官掌聲歡迎一下,有請SMO大佬登台表演。。。
關于SMO算法,李航老師的《統計學習方法》一書中是這麼描述的,
關于外層問題的求解,我們有許多方法可供使用。當我們的資料樣本比較少的時候,可以将支援向量機的學習問題轉換為凸二次規劃問題,這樣的凸二次規劃問題具有全局最優解,并且有許多最優化算法可以用于這一問題的求解。但是當訓練樣本容量很大時,這些算法往往變得非常低效,以緻無法使用。是以,如何高效地實作支援向量機學習就成為一個重要的問題。目前人們已提出許多快速實作算法。而在這些算法中,要數Platt的序列最小最優化(sequential minimal optimization SMO)算法最為人所知。
SMO算法是一種啟發式算法,其基本思想是:如果所有變量的解都滿足此最優化問題的KKT條件,那麼這個最優化問題的解就得到了。因為KKT條件是該最優化問題的充分必要條件。否則,選擇兩個變量,固定其他變量,針對這兩個變量建構一個二次規劃問題。這個二次規劃問題關于這兩個變量的解就應該更接近原始二次規劃問題的解,因為這會使得原始二次規劃問題的目标函數值變得更小。更重要的是,這時子問題可以通過解析方法求解,這樣就可以大大提高整個算法的計算速度。子問題有兩個變量,一個是違反KKT條件最嚴重的那一個,另一個由限制條件自動确定。如此,SMO算法将原問題不斷分解為子問題并對子問題求解,進而達到求解原問題的目的。
上述内容來自李航——《統計學習方法》第二版。
不知道大夥讀完上述關于内容是什麼感受,這裡簡單總結一下李航老師所表達的意思吧。
在Taoye的印象裡,國小時期上國文課的時候學習過一篇文章叫做《走一步,再走一步》。(具體幾年級就記不清楚了)
嘿!您還别說,剛剛去搜尋了下這篇課文,還真就叫這個名兒。第一次讀李航老師《統計學習方法》中關于SMO的内容之後,就讓我想起這篇文章。我還專門重新讀了一下這篇文章,主要講的内容是這樣的:
文章中主人公名叫小亨特,他不是天生體弱怯懦嘛,在一次和小夥伴攀登懸崖的時候,由于内心的恐懼、害怕,在攀登途中上不去,也下不來。然後呢,他的小夥伴傑裡就把小亨特的父親找來了,父親對小亨特說:“不要想有多遠,有多困難,你需要想的是邁一小步。這個你能做到。看着手電光指的地方。看到那塊石頭沒有?”,最終通過父親的鼓勵,小亨特成功脫險。文末作者還總結道:在我生命中有很多時刻,每當我遇到一個遙不可及、令人害怕的情境,并感到驚慌失措時,我都能夠應付——因為我回想起了很久以前自己上過的那一課。我提醒自己不要看下面遙遠的岩石,而是注意相對輕松、容易的第一小步,邁出一小步、再一小步,就這樣體會每一步帶來的成就感,直到完成了自己想要完成的,達到了自己的目标,然後再回頭看時,不禁對自己走過的這段漫漫長路感到驚訝和自豪。
把《走一步,再走一步》這篇文章搬出來,真的不是在湊字數進而給大家閱讀帶來壓力,隻是覺得SMO算法描述的就是這麼個理兒。算了,不多說了,說多了還真的會有湊字數的嫌疑。(ノへ ̄、)
下面我們開始進入到SMO吧。。。
在這之前,我們把外層的最小值問題再搬出來:
在這裡,我們是假設對于所有的樣本資料都是100%線性可分的。
對于該優化問題的SMO算法,我們可以這樣了解:因為在我們的資料集中,屬于每個樣本的屬性特征,為樣本所對應的标簽,而這些都是已知的,上述優化問題的目标函數隻存在為未知變量,且未知變量有個。而根據SMO算法的思想,我們每次隻将其中兩個看做變量,而其他僅僅隻是常數。在卻确定其中一個變量的時候,另一個變量就可以通過限制得到。我們不妨将該兩個變量定為,則SMO不斷執行如下兩個步驟直至收斂:
選取一對需要更新的變量
固定以外的參數,根據求解式(4-5)獲得更新後
更新好之後,重新選取兩個進行不斷更新疊代(重複1、2步驟)
講到這裡,SMO算法是不是和《走一步,再走一步》中主人公類似呢?将一個大的、複雜的問題轉換成多個小問題,然後不斷的疊代更新。
為什麼我們每次都同時優化兩個參數,而不是一個呢?因為每次更新兩個參數,才能確定限制條件成立。而當我們僅僅隻是修改一個時,那麼就将違背這個限制條件了。
據SMO的思想,我們不妨把目标函數中的單獨拎出來,如下:
注意:因為我們的僅僅隻是對作為參數,而隻是作為一個參數而存在。還有一點需要注意的是,因為我們是二分類問題,且樣本資料的标簽為非1即-1,是以,這個在化簡過程中需要用到。此時我們得到關于的目标函數為:
我們知道對于這個式子是有一個限制條件的,我們可以根據這個用來表示(注意:),如下:
通過上式,用來表示,我們不妨将帶到中,得到一個隻關于的式子:
此時的僅僅隻是關于的函數,我們将對進行求導,并令導數為0:
上述就是SMO中限制其中兩個變量的推到過程的推到過程(公式太多,過程有點複雜,确實不友善使用Latex文法,不過過程都已經寫的很詳細了,還是需要靜下心來慢慢手動推導的)下面總結一下上述SMO算法的過程吧:
前面我們不是得到了僅僅關于為變量的麼,也就是說此時的未知數隻有一個,我們要求的最值應該怎麼求呢?當然是對其進行求導咯,然後對導數為0,即可解出取最值時候的,整理之後得到如下式子:
此時,我們可以發現除了資料樣本相關資訊和之外,還有的存在,而我們前面也又說到,SMO算法本身是一個不斷疊代更新的過程,我們需要的是可以通過的更新之前的來修改,進而得到一個新的,我們不妨令新的為、舊的為。而我們知道舊的之間需要滿足一個限制條件:
是以,我們重新将代回到式,用來代替,(要時刻注意:)得到:
之後我們通過前面拉格朗日得到的關系式,用來代替(4-10)後面的兩個級數,整理最終得到:
PS:關于是什麼,請見上圖中的内容。
通過如上式子,我們就能求得更新之後的,而SMO算法的核心在于兩兩不斷的更新疊代,是以最終我們會得到,每個樣本都會對應一個,而前面我們也有說過,決策面最終隻會與支援向量有關,而與非支援向量的樣本無關,是以大多數的都等于0,隻有少數為非0。如此一來,我們就能求解得到向量:,随後,我們就能通過就能求得參數:
還有一點需要注意的是,上述過程都是預設所有樣本資料都是線性可分的,也就是說沒有一個樣本會被誤分類。但這隻是理想狀态下,而實際不免會有個别資料不得不被誤分類,這時我們需要定義懲罰參數和容錯率,而容錯率是用來不斷優化的,主要通過實際值與真實值得到。而懲罰參數我們定為,而要想成功更新得到,則需要确定的範圍。對此,我們不妨定義如下:
而我們知道:
綜合上式,可以确定的範圍:
而這個在不同情況下的的範圍,我們會在下面實際程式設計的時候需要用到,主要是用來更新值。
接下來,就是更新值了。前面我們已經定義了懲罰參數,且,此時通過更新得到的固然是相等的;但假如我們更新之後的不在這個區間之内,則此時得到的是不相等的,是以我們需要确定在不同情況下更新之後的值:
前面,我們已經得到:
因為我們是打算通過的值來得到更新之後的,是以把單獨拎出來,得到:
同時,因為上述中的級數形式可以使用來表示,是以整理之後得:
同理,可以得到:
當更新之後的都有效的時候,即在區間之内時,此時,而在不滿足上述條件的時候,我們更新之後的取的均值,即:
如此一來,我們就已經完成了SMO算法的流程,該有的參數都已經求解出來了。
說實話,寫到這,Taoye的确有點累了,腦細胞也嚴重不足了,但為了各位“老婆們”的正常閱讀,還是得繼續寫下去才行。
下面,我們就通過程式設計來實作線性SVM算法吧!(本次手撕SVM的資料集依然采用我們前面所随機建立的)
在前面,我們其實已經實作了線性SVM的分類,隻不過那個時候使用的是<code>sklearn</code>内置的接口。但既然是手撕SVM,當然是需要自己來實作這一功能的。
在這裡需要提前說明的是,上述代碼大量使用到了NumPy操作,關于NumPy的使用,可自行參考之前寫的一篇文章:print( "Hello,NumPy!" )
訓練SVM模型,沒資料集可不行,本次手撕SVM的資料集依然采用我們前面所随機建立,對此,我們定義一個<code>etablish_data</code>方法來随機建立一個SVM二分類資料集:
前面,我們在講解SMO算法的時候提到,每次都會選取随機兩個來進行更新,這裡我們不妨将第一個通過周遊的形式逐個選取,而另一個則通過<code>np.random</code>子產品來随機選取,這裡需要主要的是,第二個選取的不能與第一個相同。為此,我們定義一個方法<code>random_select_alpha_j</code>來随機選取第二個(第一個已經通過周遊得到):
我們知道,每一個更新之後的都需要滿足。為此,我們定義一個方法<code>modify_alpha</code>來确定在區間之内:
我們模型訓練是一個疊代更新的過程,而更新的前提是誤差比較大,是以我們需要定義一個方法<code>calc_E_i</code>來計算誤差,但誤差又怎麼計算呢?這一點其實我們在最開始就已經提到過了,誤差是通過模型計算出來的值與其真實值最差得到,也就是前面提到的(下面的推導務必要了解清楚,矩陣變換要十分熟悉):
根據上述誤差的推導,我們現在就可以通過代碼來計算誤差了(上面的推導務必要了解清楚,矩陣變換要十分熟悉,才能了解下面代碼所表達的含義):
同樣的,我們把其他一些用于整體代換的單獨拎出來,并通過方法進行傳回,除了上述的誤差之外,還有,相關推導過程讀者可自行根據上述來進行(一定要會),相關公式和代碼如下:
OK,準備工作已經完成了,接下來是時候放出我們的核心SMO算法的代碼了,大家可根據前面的SMO思想來了解,下面代碼也會放出詳細的注釋來幫助大家了解:
上述SMO核心方法,我們可以通過定義輸入樣本的屬性特征、标簽以及疊代次數等來得到和。随後,我們可以通過與之間的關系來的計算出,關系和相關代碼如下所示:
好的,有了,也有了,該有的都有了,接下來就是驗證模型效果了,這裡我們使用Matplotlib來繪制,定義一個<code>plot_result</code>方法來展示模型分類結果:
繪制分類結果
完整代碼:
呼呼呼!可算是結束了,做個小總結吧。
SVM是學習機器學習必然接觸到的一個重要算法,是以一定要對其内在原理了解清楚,并不是說一定要手撕SVM的完整代碼,但最起碼使用架構的時候要了解内部都做了什麼“小動作”,不要為了用而用。
本文介紹了線性SVM的算法原理,主要分為了五個部分的内容。一、首先通過參考比較權威的書籍以及優秀資料對SVM做了一個比較“良心”的介紹,讓讀者對SVM有一個比較宏觀的概念,這小子(SVM)究竟是誰?竟如此騷氣,讓不少研究者拜倒其石榴裙下。二、其次向讀者介紹了線性SVM以及最大間隔,這部分也是手撕SVM必須要掌握的一些基本概念,并且最終得到了SVM最初的優化問題。三、利用拉格朗日乘數法建構最值問題,将優化問題中的限制問題內建到了目标函數本身,之後利用拉格朗日的對偶性,将最初的優化問題轉化成了内層關于的最小值,外層關于的對偶問題。四、對偶問題的求解,這也是SVM算法的最核心内容,先是對内層關于的函數求導,然後代回原式,進而消掉參數,隻留下未知的,随後利用SMO算法求得疊代更新之後的。五、手撕線性SVM的代碼實作,結果證明,分類的效果還不錯,這是個好家夥!!!
說實話,這篇文章有點肝,也是挪用了不少其他任務的時間。
這篇文章僅僅隻是手撕線性SVM,也就是說大多資料樣本都可以被正确分類,但在實際中,許多的資料集都是線性不可分的,這個時候可能就要引入核函數的概念了。關于非線性SVM,我們留在之後再來肝。。。
本文參考了不少書籍資料以及許多大佬的技術文章,行文風格盡可能做到了通俗易懂,但其中涉及到的數學公式在所難免,還請諸讀者靜下心來慢慢品嘗。由于個人水準有限,才疏學淺,對于SVM也隻是略知皮毛,可能文中有不少表述稍有欠妥、有不少錯誤或不當之處,還請諸君批評指正,有任何問題歡迎在下方留言。
參考資料:
[1] 《機器學習實戰》:Peter Harrington 人民郵電出版社
[2] 《統計學習方法》:李航 第二版 清華大學出版社
[3] 《機器學習》:周志華 清華大學出版社
[4] 《微積分方法》:李億民 中國海洋出版社
[5] Support Vector Machines explained well(FQ):http://bytesizebio.net/2014/02/05/support-vector-machines-explained-well/
[6] 關于更為直覺認識SVM的video(FQ):https://www.youtube.com/watch?v=3liCbRZPrZA
[7] 支援向量機(SVM)是什麼意思?:https://www.zhihu.com/question/21094489/answer/86273196
[8] 看了這篇文章你還不懂SVM你就來打我:https://zhuanlan.zhihu.com/p/49331510
[9] 拉格朗日乘數法:https://www.cnblogs.com/maybe2030/p/4946256.html
推薦閱讀
print( "Hello,NumPy!" )
幹啥啥不行,吃飯第一名
Taoye滲透到一家黑平台總部,背後的真相細思極恐
《大話資料庫》-SQL語句執行時,底層究竟做了什麼小動作?
那些年,我們玩過的Git,真香
基于Ubuntu+Python+Tensorflow+Jupyter notebook搭建深度學習環境
網絡爬蟲之頁面花式解析
手握手帶你了解Docker容器技術
一文詳解Hexo+Github小白建站
打開ElasticSearch、kibana、logstash的正确方式