超參數優化方法

學習器模型中一般有兩類參數,一類是可以從數據中學習估計得到,還有一類參數時無法從數據中估計,只能靠人的經驗進行設計指定,后者成為超參數。比如,支持向量機里面的C, Kernal, game;樸素貝葉斯里面的alpha等。

使用以下的方法獲得學習器模型的參數列表和當前取值, estimator.get_params()

參數空間的搜索有以下幾個部分構成:

  1. 一個estimator(回歸器 or 分類器)
  2. 一個參數空間
  3. 一個搜索或采樣方法來獲得候選參數集合
  4. 一個交叉驗證機制
  5. 一個評分函數

有些學習器模型有自己獨特的參數選擇優化方法。

Sklearn提供了兩種通用的超參數優化方法: 網格搜索 與 隨機采樣。

網格搜索交叉驗證(GridSearchCV): 以窮舉方法遍歷所有的可能的參數組合。

隨機采樣交叉驗證(RandomizedSearchCV): 依據某種分布對參數空間采樣,隨即得到參數組合方案。

模型 |
---|---
sklearn.model_selection.GridSearchCV |
sklearn.model_selection.RandomizedSearchCV |
sklearn.model_selection.ParameterGrid |
sklearn.model_selection.ParameterSampler |
sklearn.model_selection.fit_grid_point |

GridSearchCV

GridSearchCV提供了在參數網格上窮舉候選參數組合的方法。參數網格由參數param_grid來指定。比如,下面展示了舍子參數網格param_grid的一個例子。

param_grid = [
    {'C': [1,10,100,1000], 'kernel': ['linear']},
    {'C': [1,10,100,1000], 'gamma': [0.001,0.0001], 'kernel':['rbf']},
]

上面的參數指定了要搜索的兩個網格(每個網格是一個字典):第一個網格是線性核然后c
在[1, 10, 100, 1000]中取值;第二個參數時RFB核然后再是gamma的取值列表[0.001, 0.0001]以及C的取回列表[1, 10, 100, 1000]。第一個里面有4
個參數組合節點,第二個里面有4*2=8個參數組合節點。

from sklearn import svm,datasets
from sklearn.model_selection import GridSearchCV

iris = datasets.load_iris()
# 定義參數網格,2*3=6個參數組合
parameters = {'kernel': ('rbf', 'linear'), 'C': [1, 5, 10]}
svr = svm.SVC()
# 對所有的參數組合進行測試,選擇最好的一個組合
clf = GridSearchCV(svr, parameters)
clf.fit(iris.data, iris.target)
print(clf.best_estimator_)
image

RandomizedSearchCV

RandomizedSearchCV實現了一個在參數空間上進行隨機搜索到機制,起哄參數的選值是從某種概率分布中抽取的。這個概率分布描述了對應的參數的所有取值情況的可能性。這種隨機采樣機制與網格搜索窮舉搜索相比,有兩大優點:

  1. 相比于整體參數空間,可以選擇相對較少的參數組合數量。
  2. 添加參數節點不會影響性能,不會降低效率。

指定參數的采樣范圍和分布可以用一個字典來完成,跟網格搜索很像。另外,計算預算(總共要隨機采樣多少個參數組合或者迭代多少次)可以使用參數n_iter來指定,針對每一個參數范圍內的概率,既可以使用可能取值范圍內的概率分布,也可以指定一個離散的取值列表(會被均勻采樣)。

{'C':scipy.stats.expon(scale=100), 'gamma':scipy.stats.expon(scale=0.1),
 'kernel':['rbf'], 'class_weight':['balanced', None]
}

這個例子使用了scipy.stats模塊,其中包含了很多有用的分布來產生參數采樣點,像expon, gamma, uniform or randint。原則上,任何一個函數都要可以傳遞進去,只要他提供了一個rvs(random variate sample)方法來返回采樣值,rvs函數的連續調用應該能保證產生獨立同分布的樣本值。

對于連續取值的參數,比如上面的C, 給他指定一個連續的分布非常重要,這樣可以保證充分利用隨機化帶來的好處,增加迭代次數,n_iter將會帶來非常精準的搜索。

import numpy as np
import time
from scipy.stats import randint
from sklearn.datasets import load_digits
from sklearn.model_selection import RandomizedSearchCV, GridSearchCV
from sklearn.ensemble import RandomForestClassifier

# 用于報告超參數搜索的最好結果的函數
def report(results, n_top=3):
    for i in range(1, n_top + 1):
        candidates = np.flatnonzero(results['rank_test_score'] == i)
        for candidate in candidates:
            print('Model with rank: {0}'.format(i))
            print('Mean validation score: {0:.3f}(std: {1:.3f})'.format(
                results['mean_test_score'][candidate],
                results['std_test_score'][candidate]))
            print('Parameters: {0}'.format(results['params'][candidate]))
            print('')

# 取得數據,手寫字符分類
digits = load_digits()
X, y = digits.data, digits.target
# 構建一個隨機方森林分類器,有20棵數
clf = RandomForestClassifier(n_estimators=20)
# 設置想要優化的超參數以及他們的取值分布
param_dist = {
    'max_depth': [3, None],
    'max_features': randint(1,11),
    'min_samples_split': randint(2,11),
    'bootstrap': [True, False],
    'criterion': ['gini', 'entropy']
}
# 開啟超參數空間的隨機搜索
n_iter_search = 20
random_search = RandomizedSearchCV(clf, param_distributions=param_dist, n_iter=n_iter_search)
start = time.time()
random_search.fit(X, y)
print('time use: {}'.format(time.time() - start))
report(random_search.cv_results_)
image

下面將這兩種方法進行比較

import numpy as np
import time
from scipy.stats import randint
from sklearn.datasets import load_digits
from sklearn.model_selection import RandomizedSearchCV, GridSearchCV
from sklearn.ensemble import RandomForestClassifier

# 用于報告超參數搜索的最好結果的函數
def report(results, n_top=3):
    for i in range(1, n_top + 1):
        candidates = np.flatnonzero(results['rank_test_score'] == i)
        for candidate in candidates:
            print('Model with rank: {0}'.format(i))
            print('Mean validation score: {0:.3f}(std: {1:.3f})'.format(
                results['mean_test_score'][candidate],
                results['std_test_score'][candidate]))
            print('Parameters: {0}'.format(results['params'][candidate]))
            print('')

# 取得數據,手寫字符分類
digits = load_digits()
X, y = digits.data, digits.target
# 構建一個隨機方森林分類器,有20棵數
clf = RandomForestClassifier(n_estimators=20)

print('==========下面是RandomizedSearchCV結果==============')

# 設置想要優化的超參數以及他們的取值分布
param_dist = {
    'max_depth': [3, None],
    'max_features': randint(1,11),
    'min_samples_split': randint(2,11),
    'bootstrap': [True, False],
    'criterion': ['gini', 'entropy']
}
# 開啟超參數空間的隨機搜索
n_iter_search = 20
random_search = RandomizedSearchCV(clf, param_distributions=param_dist, n_iter=n_iter_search)
start = time.time()
random_search.fit(X, y)
print('time use: {}'.format(time.time() - start))
report(random_search.cv_results_)
        
print('==========下面是GridSearchCV結果==============')

# 設置想要優化的超參數以及他們的取值分布
param_grid = {
    'max_depth': [3, None],
    'max_features': [1, 3, 10],
    'min_samples_split': [2, 3, 10],
    'bootstrap': [True, False],
    'criterion': ['gini', 'entropy']
}
# 開啟超參數空間的隨機搜索
grid_search = GridSearchCV(clf, param_grid=param_grid)
start = time.time()
grid_search.fit(X, y)
print('time use: {}'.format(time.time() - start))
report(grid_search.cv_results_) 
image

實驗結果:
以隨機森林分類器為優化對象,所有影響分類器學習的參數都被搜索了,除了樹的數量之外,隨機搜索和網格優化都在同一個超參數空間上對隨機森林分類器進行優化。雖然得到的超參數設置組合比較相似,但是隨機搜索運行的時間卻網格搜索的時間顯著減少,隨季節搜索得到的超參數組合的性能稍微差一點,但是這很大程度上是有噪聲引起的,在實踐中, 我們只是挑選幾個比較重要的參數進行隨機組合來進行優化。

超參空間搜索技巧

  1. 指定一個合適的目標測度對木星進行評估,默認情況下,參數搜索使用的是estimator的score函數來評價模型在某種參數配置下的性能。分類器使用的是sklearn.metrics.accuracy_score, 回歸器使用的是sklearn.metrics.r2_score。但是在某些情況下,其他的評分函數更加實用。
  2. 實用sklearn的Pineline將estimator和它們的參數空間組合起來
  3. 合理劃分數據集:開發集(用于GridSearchCV)+ 測試集(Test)使用model_selection.train_test_split()函數。
  4. 并行化:以上兩者在參數節點的計算上可以做到并行運算,這個通過'n_jobs'來指定。
  5. 提高在某些參數節點上發生錯誤時的魯莽性:在出錯節點上只是提示警告。設置參數error_score = 0(or np.NaN)來解決。
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,923評論 6 535
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,740評論 3 420
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,856評論 0 380
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,175評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,931評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,321評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,383評論 3 443
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,533評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,082評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,891評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,067評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,618評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,319評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,732評論 0 27
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,987評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,794評論 3 394
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,076評論 2 375

推薦閱讀更多精彩內容