Python機器學習及實踐——進階篇6(超參數搜索)

前面所提到的模型配置,我們一般統稱爲模型的超參數,如K近鄰算法中的K值 支持向量機中不同的和函數等。多數情況下,超參數的選擇是無限的。因此在有限的時間內,除了可以驗證人工預設幾種超參數組合以外,也可以通過啓發式的搜索方法對超參數組合進行調優。我們稱這種啓發式的超參數搜索方法爲網格搜索。同時由於超參數的的驗證過程之間彼此獨立,因此爲並行計算提供了可能。

網格搜索:
由於超參數的空間是無盡的,因此超參數的組合配置只能是“更優”解,沒有最優解。通常情況下,我們依靠網格搜索對多種超參數組合的空間進行暴力搜索。每一套超參數組合被代入到學習函數中作新的模型,並且爲了比較新模型之間的性能,每個模型都會採用交叉驗證的方法在多組相同的訓練和開發數據集下進行評估。請看下述代碼:

# 從sklearn.datasets中導入20類新聞文本抓取器。
from sklearn.datasets import fetch_20newsgroups
# 導入numpy,並且重命名爲np。
import numpy as np

# 使用新聞抓取器從互聯網上下載所有數據,並且存儲在變量news中。
news = fetch_20newsgroups(subset='all')

# 從sklearn.cross_validation導入train_test_split用來分割數據。
from sklearn.model_selection import train_test_split

# 對前3000條新聞文本進行數據分割,25%文本用於未來測試。
X_train, X_test, y_train, y_test = train_test_split(news.data[:3000], news.target[:3000], test_size=0.25, random_state=33)

# 導入支持向量機(分類)模型。
from sklearn.svm import SVC
# 導入TfidfVectorizer文本抽取器。
from sklearn.feature_extraction.text import TfidfVectorizer
# 導入Pipeline。
from sklearn.pipeline import Pipeline

#使用Pipeline 簡化系統搭建流程,將文本抽取與分類器模型串聯起來。
clf = Pipeline([('vect', TfidfVectorizer(stop_words='english', analyzer='word')), ('svc', SVC())])

# 這裏需要試驗的2個超參數的的個數分別是4、3, svc__gamma的參數共有10^-2, 10^-1... 。這樣我們一共有12種的超參數組合,12個不同參數下的模型。
parameters = {'svc__gamma': np.logspace(-2, 1, 4), 'svc__C': np.logspace(-1, 1, 3)}

# 從sklearn.grid_search中導入網格搜索模塊GridSearchCV。
from sklearn.model_selection import GridSearchCV

# 將12組參數組合以及初始化的Pipline包括3折交叉驗證的要求全部告知GridSearchCV。請大家務必注意refit=True這樣一個設定 。
gs = GridSearchCV(clf, parameters, verbose=2, refit=True, cv=3)


# 執行單線程網格搜索。
%time _= gs.fit(X_train, y_train)
gs.best_params_, gs.best_score_

# 輸出最佳模型在測試集上的準確性。
print (gs.score(X_test, y_test))
Fitting 3 folds for each of 12 candidates, totalling 36 fits
[CV] svc__C=0.1, svc__gamma=0.01 .....................................
[CV] ...................... svc__C=0.1, svc__gamma=0.01, total=   4.3s
[CV] svc__C=0.1, svc__gamma=0.01 .....................................
[CV] ...................... svc__C=0.1, svc__gamma=0.01, total=   4.2s
[CV] svc__C=0.1, svc__gamma=0.01 .....................................
[CV] ...................... svc__C=0.1, svc__gamma=0.01, total=   4.3s
[CV] svc__C=0.1, svc__gamma=0.1 ......................................
[CV] ....................... svc__C=0.1, svc__gamma=0.1, total=   4.1s
[CV] svc__C=0.1, svc__gamma=0.1 ......................................
[CV] ....................... svc__C=0.1, svc__gamma=0.1, total=   4.4s
[CV] svc__C=0.1, svc__gamma=0.1 ......................................
[CV] ....................... svc__C=0.1, svc__gamma=0.1, total=   4.4s
[CV] svc__C=0.1, svc__gamma=1.0 ......................................
[CV] ....................... svc__C=0.1, svc__gamma=1.0, total=   4.2s
[CV] svc__C=0.1, svc__gamma=1.0 ......................................
[CV] ....................... svc__C=0.1, svc__gamma=1.0, total=   4.3s
[CV] svc__C=0.1, svc__gamma=1.0 ......................................
[CV] ....................... svc__C=0.1, svc__gamma=1.0, total=   4.3s
[CV] svc__C=0.1, svc__gamma=10.0 .....................................
[CV] ...................... svc__C=0.1, svc__gamma=10.0, total=   4.2s
[CV] svc__C=0.1, svc__gamma=10.0 .....................................
[CV] ...................... svc__C=0.1, svc__gamma=10.0, total=   4.3s
[CV] svc__C=0.1, svc__gamma=10.0 .....................................
[CV] ...................... svc__C=0.1, svc__gamma=10.0, total=   4.3s
[CV] svc__C=1.0, svc__gamma=0.01 .....................................
[CV] ...................... svc__C=1.0, svc__gamma=0.01, total=   4.2s
[CV] svc__C=1.0, svc__gamma=0.01 .....................................
[CV] ...................... svc__C=1.0, svc__gamma=0.01, total=   4.2s
[CV] svc__C=1.0, svc__gamma=0.01 .....................................
[CV] ...................... svc__C=1.0, svc__gamma=0.01, total=   4.3s
[CV] svc__C=1.0, svc__gamma=0.1 ......................................
[CV] ....................... svc__C=1.0, svc__gamma=0.1, total=   4.2s
[CV] svc__C=1.0, svc__gamma=0.1 ......................................
[CV] ....................... svc__C=1.0, svc__gamma=0.1, total=   4.3s
[CV] svc__C=1.0, svc__gamma=0.1 ......................................
[CV] ....................... svc__C=1.0, svc__gamma=0.1, total=   4.3s
[CV] svc__C=1.0, svc__gamma=1.0 ......................................
[CV] ....................... svc__C=1.0, svc__gamma=1.0, total=   4.3s
[CV] svc__C=1.0, svc__gamma=1.0 ......................................
[CV] ....................... svc__C=1.0, svc__gamma=1.0, total=   4.4s
[CV] svc__C=1.0, svc__gamma=1.0 ......................................
[CV] ....................... svc__C=1.0, svc__gamma=1.0, total=   4.6s
[CV] svc__C=1.0, svc__gamma=10.0 .....................................
[CV] ...................... svc__C=1.0, svc__gamma=10.0, total=   4.5s
[CV] svc__C=1.0, svc__gamma=10.0 .....................................
[CV] ...................... svc__C=1.0, svc__gamma=10.0, total=   4.5s
[CV] svc__C=1.0, svc__gamma=10.0 .....................................
[CV] ...................... svc__C=1.0, svc__gamma=10.0, total=   4.5s
[CV] svc__C=10.0, svc__gamma=0.01 ....................................
[CV] ..................... svc__C=10.0, svc__gamma=0.01, total=   4.3s
[CV] svc__C=10.0, svc__gamma=0.01 ....................................
[CV] ..................... svc__C=10.0, svc__gamma=0.01, total=   4.2s
[CV] svc__C=10.0, svc__gamma=0.01 ....................................
[CV] ..................... svc__C=10.0, svc__gamma=0.01, total=   4.3s
[CV] svc__C=10.0, svc__gamma=0.1 .....................................
[CV] ...................... svc__C=10.0, svc__gamma=0.1, total=   4.2s
[CV] svc__C=10.0, svc__gamma=0.1 .....................................
[CV] ...................... svc__C=10.0, svc__gamma=0.1, total=   4.4s
[CV] svc__C=10.0, svc__gamma=0.1 .....................................
[CV] ...................... svc__C=10.0, svc__gamma=0.1, total=   4.4s
[CV] svc__C=10.0, svc__gamma=1.0 .....................................
[CV] ...................... svc__C=10.0, svc__gamma=1.0, total=   4.4s
[CV] svc__C=10.0, svc__gamma=1.0 .....................................
[CV] ...................... svc__C=10.0, svc__gamma=1.0, total=   4.4s
[CV] svc__C=10.0, svc__gamma=1.0 .....................................
[CV] ...................... svc__C=10.0, svc__gamma=1.0, total=   4.4s
[CV] svc__C=10.0, svc__gamma=10.0 ....................................
[CV] ..................... svc__C=10.0, svc__gamma=10.0, total=   4.3s
[CV] svc__C=10.0, svc__gamma=10.0 ....................................
[CV] ..................... svc__C=10.0, svc__gamma=10.0, total=   4.3s
[CV] svc__C=10.0, svc__gamma=10.0 ....................................
[CV] ..................... svc__C=10.0, svc__gamma=10.0, total=   4.4s
[Parallel(n_jobs=1)]: Done  36 out of  36 | elapsed:  2.6min finished
Wall time: 2min 43s
0.8226666666666667

上述代碼的輸出說明:使用單線程的網格搜索技術對樸素貝葉斯模型在文本分類任務中的超參數組合進行調優,共有12組超參數X3折交叉驗證=36項獨立運行的計算任務。該任務一共進行了3分23秒,尋找到的最佳超參數組合在測試集上所能達成的最高分類準確性爲82.27%。

並行搜索:
儘管採用網格搜索結合交叉驗證的方法,來尋找更好超參數組合的過程非常耗時;然而一旦獲取比較好的超參數組合,則可以保持一段時間使用。因此這是值得推薦並且相對一勞永逸的性能提升方法。更可喜的是,由於各個新模型在執行交叉驗證的過程中間是互相獨立的,所以我們可以使用多核處理器甚至是分佈式的計算資源來從事並行搜索,這樣能夠成倍地節省運算時間。我們對之前代碼中的超參數搜索略作修改,看看會有怎樣的效率提升。

# 從sklearn.datasets中導入20類新聞文本抓取器。
from sklearn.datasets import fetch_20newsgroups
# 導入numpy,並且重命名爲np。
import numpy as np

# 使用新聞抓取器從互聯網上下載所有數據,並且存儲在變量news中。
news = fetch_20newsgroups(subset='all')

# 從sklearn.cross_validation導入train_test_split用來分割數據。
#from sklearn.cross_validation import train_test_split
from sklearn.model_selection import train_test_split

# 對前3000條新聞文本進行數據分割,25%文本用於未來測試。
X_train, X_test, y_train, y_test = train_test_split(news.data[:3000], news.target[:3000], test_size=0.25, random_state=33)

# 導入支持向量機(分類)模型。
from sklearn.svm import SVC

# 導入TfidfVectorizer文本抽取器。
from sklearn.feature_extraction.text import TfidfVectorizer
# 導入Pipeline。
from sklearn.pipeline import Pipeline

#使用Pipeline 簡化系統搭建流程,將文本抽取與分類器模型串聯起來。
clf = Pipeline([('vect', TfidfVectorizer(stop_words='english', analyzer='word')), ('svc', SVC())])

# 這裏需要試驗的2個超參數的的個數分別是4、3, svc__gamma的參數共有10^-2, 10^-1... 。這樣我們一共有12種的超參數組合,12個不同參數下的模型。
parameters = {'svc__gamma': np.logspace(-2, 1, 4), 'svc__C': np.logspace(-1, 1, 3)}

# 從sklearn.grid_search中導入網格搜索模塊GridSearchCV。
#from sklearn.grid_search import GridSearchCV
from sklearn.model_selection import GridSearchCV

# 初始化配置並行網格搜索,n_jobs=-1代表使用該計算機全部的CPU。
gs = GridSearchCV(clf, parameters, verbose=2, refit=True, cv=3, n_jobs=-1)

# 執行多線程並行網格搜索。
%time _= gs.fit(X_train, y_train)
gs.best_params_, gs.best_score_

# 輸出最佳模型在測試集上的準確性。
print (gs.score(X_test, y_test))
Fitting 3 folds for each of 12 candidates, totalling 36 fits
Wall time: 30.4 s
0.8226666666666667

同樣是網格搜索,使用多線程並行搜索技術對樸素貝葉斯模型在文本分類任務中的超參數組合進行調優,執行同樣的36項計算任務一共只花了30.4秒,尋找到的最佳超參數組合在測試集上所能達成的最高分類準確性依然爲82.27%。我們發現在沒有影響驗證準確性的前提下,通過並行搜索基礎有效地利用了6核心(cpu)的計算資源,幾乎6倍地提升了運算速度,節省了最佳超參數組合的搜索時間。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章