1. 程式人生 > >機器學習筆記10——應用機器學習演算法的建議

機器學習筆記10——應用機器學習演算法的建議

目前,我們對機器學習的演算法也有了一定的瞭解,這一節將會給大家一些建議,關於如何有效的使用機器學習演算法。對於相同的演算法,不同的人會使其發揮不同的效果,所以,這一節的主題就是教大家如何用機器學習演算法解決具體問題。

主要內容

  • 學習演算法的除錯診斷方法

  • 誤差分析和消蝕分析

  • 如何求解機器學習問題

    例:過早優化問題(軟體編寫過程中讓程式碼高速執行)

一、學習演算法的除錯問題

舉個例子:

垃圾郵件識別系統,仔細篩選過後得到100個詞作為特徵(而不是詞典中的50000+個詞彙)。

使用的演算法是貝葉斯邏輯迴歸,用梯度下降演算法實現,測試誤差為20%,這是一個不能接受的較高的誤差。


這是貝葉斯邏輯迴歸,有點像最大似然估計,但是這裡多了一項懲罰項,以防止過擬合。

我們的問題是:當你實現了貝葉斯邏輯迴歸並且經過測試得到了較高的誤差,那麼接下來該怎麼辦?

通常來說,我們會想方設法的改造演算法,比如有如下幾種解決方式:

1.使用更多的訓練樣本

2.使用更少的特徵(特徵太多縮小範圍)

3.使用更多的特徵(擴大範圍繼續找)

4.更改特徵 郵件標題特徵 vs 郵件內容特徵

5.梯度下降可能沒有收斂,再多次執行梯度下降

6.使用牛頓演算法收斂(效果好)

7.調節引數λ的值

8.使用SVM演算法(效果好)

上述列舉了幾種改進演算法的可能,這樣的方法可能對演算法有效,但非常耗費時間,且很大程度依賴於運氣。

這八種改進方法處理的都是不同的問題,可能其中的一些方法根本不需要,如果可以排除其中的六項——通過某種方式深度的分析問題,就可以節省很多時間。

一般來說,不應該隨意的改變學習演算法,但改進方法如此之多,也不能一個一個的去嘗試,更好的方式就需要通過不同的診斷方法來確定問題,之後再修正這些問題

之前舉的例子中貝葉斯邏輯迴歸的誤差太大了,假設我們認為可能是過擬合導致的問題(高方差),或者使用的特徵太少了(高偏差)。那麼應該怎樣確定是高方差還是高偏差呢?

高方差存在一個特點:因為資料擬合的好,所以訓練誤差將會遠遠小於測試誤差。高偏差的話,那麼訓練誤差也會很高。


在高方差的前提下,隨著訓練集的增加,測試誤差會逐漸減小(綠線),而訓練誤差會逐漸增加,(紅線表示預期的誤差)。同樣也可以通過這個圖,判斷訓練誤差與測試誤差的差距,如果差距很大,那麼可以通過增加訓練集的大小來縮短二者之間的差距。

在高偏差的前提下,隨著訓練集的增加,測試誤差會逐漸減小並最終趨於平緩不再變化,訓練誤差會逐漸增加。如果發現訓練誤差超過預期誤差了,那麼即使增加再多的資料集,訓練誤差也不會發生改變,不能將其拉回到預期的誤差。

那麼,判斷測試誤差(綠色的曲線)是繼續向下還是水平不變是比較困難的,所以判斷高方差還是高偏差的問題的方法是通過觀測測試誤差與訓練誤差的差距

通過對上述問題的解答,我們回過頭來看最初列舉出的八種解決問題的方法。

1.使用更多的訓練樣本 【解決高方差問題】

2.使用更少的特徵(特徵太多縮小範圍) 【解決高方差問題】

3.使用更多的特徵(擴大範圍繼續找) 【解決高偏差問題】

4.更改特徵 郵件標題特徵 vs 郵件內容特徵 【解決高偏差問題】

之後,我們針對後面的四種方法設計診斷方法。下面我們來看另外一個例子:

垃圾郵件分類系統中,使用貝葉斯邏輯迴歸演算法,最終判斷垃圾郵件時有2%的誤差,判斷非垃圾郵件時有2%的誤差。系統會漏掉2%的垃圾郵件還可以接受,但同時有2%的非垃圾郵件被拒絕是不能忍受的。

同樣是垃圾郵件分類系統,通過SVM中的線性核算法,判斷垃圾郵件時有10%的誤差,判斷非垃圾郵件時有0.01%的誤差,這種解決方法更讓人接受。

那麼問題來了:如果你想用邏輯迴歸來實現垃圾郵件分類(可能因為邏輯迴歸執行效率高,更方便blablabla)可是現在邏輯迴歸的效果並不好,那麼我們該怎麼辦?

非常常見的問題:你可能會懷疑邏輯迴歸演算法並沒有收斂。


圖中曲線意味著邏輯迴歸演算法要優化的目標J(θ),隨著迭代次數的增加,很難區分曲線是上升狀態還是水平保持不變。所以相對於檢視曲線的狀態,我們還需要其他的方法來判斷演算法是否收斂。

另一個懷疑的問題是:我們是否找到了正確的優化函式。


上述等式是對所有預測正確的樣本進行加權求和,意味著預測準確率。非垃圾郵件的權值要比垃圾郵件的權值大,因為我們更看重非垃圾郵件的準確率。


針對貝葉斯邏輯迴歸來說,它的優化目標是上述等式,基本上就是最大似然,只不過多了一個懲罰項。那麼針對誤差問題,我們是應該改變λ的值,還是改變使用的引數?亦或是更改成SVM的優化目標?


那麼接下來要講的第二種診斷方法,用來幫助判斷問題到底是因為演算法的收斂上,還是出在一開始對於目標函式的選擇上。

讓我們再次回顧之前舉的例子,SVM的效果比邏輯迴歸效果要好,但我們要用邏輯迴歸這一演算法。那麼用θSVM代表由SVM生成的引數,用θBLR代表由貝葉斯邏輯迴歸生成的引數。

因為SVM比貝葉斯邏輯迴歸效果要好,所以有α(θSVM) > α(θBLR)(加權準確率)。貝葉斯邏輯迴歸的目標是J(θ),為了判斷問題到底出在哪裡,那麼我們的診斷方法就是要比較J(θSVM)J(θBLR)之間的大小

一種情況是:


我們知道,邏輯迴歸的目的是將J(θ)最大化,而現在的等式中SVM獲得使J(θ)更大的值,那麼問題出在演算法沒有收斂上。

另一種情況是:


這一不等式意味著,邏輯迴歸演算法成功的將J(θ)最大化,但是SVM在加權準確率方面做得更好。這表明最大化J(θ)並不意味著可以最大化加權準確率。這也就說明J(θ)可能是一個錯誤的目標函式。

通過對上述問題的解答,我們回過頭來看最初列舉出的八種解決問題的方法。

5.梯度下降可能沒有收斂,再多次執行梯度下降 【解決優化演算法問題】

6.使用牛頓演算法收斂(效果好)【解決優化演算法問題】

7.調節引數λ的值 【解決優化目標函式問題】

8.使用SVM演算法(效果好) 【解決優化目標函式問題】

總結:針對存在問題的演算法應用,很多人花費大量的時間在優化演算法上,或並不針對具體問題進行修改,從而浪費大量時間。解決問題之前我們要明確問題再後解決。

即使演算法效果不錯,用診斷方法來理解演算法也是個不錯的注意,具體原因如下:

1.幫助你更好的理解問題。深度挖掘具體問題,便於具體分析。針對不同的問題形成個人的見解。

2.寫論文比較方便,診斷方法更容易闡述問題。

二、誤差分析與銷蝕分析

舉個例子:

人臉識別問題。可以用圖片作為輸入,然後進行預處理,識別人臉的部位(眼睛、鼻子、嘴等),最後形成特徵。


如果我們得知這些步驟中誤差是源於哪個元件,那麼會很有幫助。通常的誤差分析過程是逐漸的用基準值代替每個元件的輸出,並觀察準確率的變化。

系統整體的準確率為85%,我們想知道這15%的誤差來自哪裡。所以首先用手動編碼的方式替代扣除背景的演算法,準確率增長至85.1%,之後我們用基準值代替人臉識別的輸出,我們會告訴演算法人臉的具體位置,那麼此時準確率增長至91%。以此類推,我們將每個元件的輸出替換成基準值,告訴演算法具體的眼睛、鼻子、嘴的位置,得到如圖所示的準確率值。

從這張表中可以看到,當我們將人臉識別的輸出替換成基準值時,準確率由85.1%增長至91%。這意味著如果提高人臉識別演算法的效能,可以將準確率提高6%。這類診斷方法非常有用,如果你的目標是改善整個系統的效能的話,選擇正確的改善方面是非常重要的,那麼這種診斷方法就可以告訴你哪方面的努力是最值得的。

接下來要講的是另一種分析方法,與誤差分析相反,誤差分析打算將現有的系統性能與完美的效能進行對比,而銷蝕分析則嘗試將現有的系統性能與一些較差的處於底線的系統性能做對比。

舉個例子:

假設已構建一個垃圾郵件分類系統(好吧,還是它),並且對邏輯迴歸演算法加了一些很好的特徵,比如說:

  • 拼寫檢查的特徵

  • 傳送者主機的特徵

  • 郵件頭的特徵

  • 郵件文字分析的特徵

  • javascript解析特徵

  • 嵌入圖片的特徵等

假如說你想統計一下哪個特徵對系統性能的改進影響最大。利用銷蝕分析可以這樣做,假設利用簡單的邏輯迴歸演算法,沒做任何的改進得到了94%的提升,那麼如何判斷每種特徵對系統性能提高的影響力度呢?利用銷蝕分析,我們不會每次新增一個元件,而是去除一個元件,然後觀察準確率的變化。


從系統現有的準確率99.9%開始,去除拼寫校正這個特徵,準確率下降了,之後再去除傳送主機這個特徵…..,之後我們得到了這個表格。從圖中可以看出,當去除郵件文字分析這一特徵時,準確率下降的最快,也就是說它的影響最大。

三、應用機器學習的建議

方法一:仔細設計系統

  • 提取正確的特徵,收集正確的資料集合,設計正確的演算法結構

  • 實現它

優點:得到表現更好、伸縮性更強的演算法。

方法二:“構建—修改”法

  • 先快速、簡陋的實現

  • 然後利用誤差分析來看看哪裡出現問題,再進行改進

優點:非常快的建立系統,快速出現在市場,讓系統更快的工作起來。這種方式比較好,原因是:通常情況下,一個系統中哪部分更簡單,需要更仔細的設計,需要花更多的時間,這些都不明確。在不明確的前提下,我們可能會花費大量的時間在不能大幅度提高系統性能的部分,造成時間成本浪費。

另外,有很多這樣的情況:在設計演算法過程中,發現數據集出了問題,裡面大部分的值不符合你的要求,是錯誤的,在演算法設計一大半時發現了這樣的問題。其實,一開始處理問題時,不要急著設計演算法,或者越複雜越好,先看看資料集,把點畫出來,對資料的結構有大體的瞭解(當然也包括資料清洗等,資料的質量影響最終的結果,所以不要小看每一個步驟,並不是演算法越高深越好,有可能最後的結果不盡人意)。

以上的一些建議並不適合所有情況,比如說如果你想要發明一個新的學習演算法時,快速實現一個東西並且繼續修正,出現問題後再修正並不是合適的方法,應該更深入的思考而不是參考這些建議。

總結:花在設計診斷方法的時間通常都是有價值的,且通常情況下都需要你自己去設計診斷方法。設計演算法時,不要堆疊貌似相關的、但是高大上理論,我們要明確應用與我們的演算法/系統相關的理論,而不是道聽途說的那些理論,如果真的想應用,就先研究透徹這個理論是否與我們研究的目標相關。總而言之,挖掘問題,對症下藥。