1. 程式人生 > >模型選擇之交叉驗證

模型選擇之交叉驗證

在機器學習的模型訓練中,我們通常需要比較多個模型,從中選出一個最優的模型作為我們的最終模型。我們知道,超引數(hyper parameter)經常會作為模型的一個組成部分出現,比如說,在正則化後的logistic regression中,正則項和損失函式之間的引數t就是一個超引數,不同的t取值對應了不同的模型,我們對於t的選取實際上也就是對模型的選擇,我們試圖找到一個t,使得t對應的模型最優。再比如說,帶有高斯核函式的模型中,高斯核函式的那個引數實際上也是模型的超引數。

從理論角度講,如果我們的訓練資料量足夠大,我們就可以事先選出一部分訓練資料作為驗證集(佔訓練資料集的1/4到1/3),並且用這部分資料來評估我們的模型。但是在實際當中,訓練資料往往有限,上述方式基本上不可行,因為會造成訓練資料的浪費。這時可以採取交叉驗證的方式,具體地,k折交叉驗證(k-fold cross-validation)用一部分資料來訓練模型,然後用另一部分資料來測試模型的泛化誤差。該演算法的具體步驟如下:

1.      隨機將訓練資料等分成k份,S1, S2, …, Sk。

2.      對於每一個模型Mi,演算法執行k次,每次選擇一個Sj作為驗證集,而其它作為訓練集來訓練模型Mi,把訓練得到的模型在Sj上進行測試,這樣一來,每次都會得到一個誤差E,最後對k次得到的誤差求平均,就可以得到模型Mi的泛化誤差。

3.      演算法選擇具有最小泛化誤差的模型作為最終模型,並且在整個訓練集上再次訓練該模型,從而得到最終的模型。

對於k的選擇,實踐中一般取k =10。這裡有一種情況,k = N,(N為訓練樣本數量)。在這種情況下,k折交叉驗證也稱為留一交叉驗證(leave-one-out cross validation)。由於在留一交叉驗證中,每一次訓練模型的樣本幾乎是一樣的,這樣就會造成估計的偏差很小但方差很大的情況出現,另外,需要呼叫N次學習演算法,這在N很大的時候,對於計算量也是不小的開銷。

另一方面,如果取k = 10,那麼交叉驗證的方差會降低,但是偏差又會成為問題,這取決於訓練樣本的數量。當訓練樣本較小時,交叉驗證很容易有較高的偏差,但是隨著訓練樣本的增加,這種情況會得到改善。

由上分析可知,實踐中主要還是選擇10-折交叉驗證較為理想。

上面介紹了交叉驗證的步驟以及對於k值選擇的分析。

接下來我想結合自己在工程中所犯的一個錯誤來說明交叉驗證的正確使用方式。

對於一個文字分類問題,我們知道這樣的問題往往具有很大量的特徵,其特徵數量基本上遠遠超過訓練樣本數量,但是這些特徵中與類別相關的特徵並不多,大都是無關特徵。因此我的做法是這樣的:

1.      特徵選擇。用資訊增益的方式選擇了與類別有很強關聯性的特徵。

2.      用上面選擇出的特徵來構造文字分類器。

3.      用交叉驗證法來選擇最優的模型並估計最終模型的泛化誤差。

大家覺得上面的做法怎麼樣?正確嗎?這就是我在最初嘗試的做法。

我們首先來看看這樣做的結果。由最終正確的方法得出的結果可知,分類器在驗證集上的泛化誤差在12%左右,而通過上述方法得到的分類器在驗證集上的泛化誤差為3%左右,這和真實資料差了很多,顯然,上述方法出了問題。那麼問題出在哪裡呢?

注意到上述做法的第一步,在進行特徵選擇時,我用到了所有的訓練樣本,這就導致選擇出來的特徵“看見了所有的訓練樣本”,而後我再用交叉驗證時,每次驗證所用到的驗證集實際上對於特徵來講已經是可見的了,這些驗證集已經被“汙染”。

正確的做法應該是這樣:

1.      隨機將訓練樣本等分成k份。

2.      對於每一份驗證資料Sj,演算法在S1, …, SJ-1, SJ+1, …, Sk上進行特徵選擇,並且構造文字分類器。把得到的文字分類器在驗證集Sj上求泛化誤差。

3.      把k個泛化誤差求平均,得到最後的泛化誤差。

從上面的例子可以看出,交叉驗證應該貫穿整個模型建立的過程。上面的錯誤應該引起高度的重視,很多人在實踐中都會不知不覺地犯這個錯誤。

最後需要注意的是,之前我們都是在講交叉驗證作為模型選擇時的方法。交叉驗證也可以用來評估單個模型的誤差。比如說你實現了一個模型,並且想看看這個模型的效果,這時可以考慮交叉驗證。