LESSON 10.3 Halving网格搜索
三 對半網格搜索HalvingSearchCV
- 基本原理
在講解隨機網格搜索之前,我們梳理了決定枚舉網格搜索運算速度的因子:
1 參數空間的大小:參數空間越大,需要建模的次數越多
2 數據量的大小:數據量越大,每次建模時需要的算力和時間越多
面對枚舉網格搜索過慢的問題,sklearn中呈現了兩種優化方式:其一是調整搜索空間,其二是調整每次訓練的數據。調整搜索空間的方法就是隨機網格搜索,而調整每次訓練數據的方法就是對半網格搜索。
假設現在存在數據集𝐷,我們從數據集𝐷中隨機抽樣出一個子集𝑑。如果一組參數在整個數據集𝐷上表現較差,那大概率這組參數在數據集的子集𝑑上表現也不會太好。反之,如果一組參數在子集𝑑d上表現不好,我們也不會信任這組參數在全數據集𝐷上的表現。參數在子集與全數據集上反饋出的表現一致,如果這一假設成立,那在網格搜索中,比起每次都使用全部數據來驗證一組參數,或許我們可以考慮只帶入訓練數據的子集來對超參數進行篩選,這樣可以極大程度地加速我們的運算。
但在現實數據中,這一假設要成立是有條件的,即任意子集的分布都與全數據集D的分布類似。當子集的分布越接近全數據集的分布,同一組參數在子集與全數據集上的表現越有可能一致。根據之前在隨機網格搜索中得出的結論,我們知道子集越大、其分布越接近全數據集的分布,但是大子集又會導致更長的訓練時間,因此為了整體訓練效率,我們不可能無限地增大子集。這就出現了一個矛盾:大子集上的結果更可靠,但大子集計算更緩慢。對半網格搜索算法設計了一個精妙的流程,可以很好的權衡子集的大小與計算效率問題,我們來看具體的流程:
1、首先從全數據集中無放回隨機抽樣出一個很小的子集𝑑0,并在𝑑0上驗證全部參數組合的性能。根據𝑑0上的驗證結果,淘汰評分排在后1/2的那一半參數組合
2、然后,從全數據集中再無放回抽樣出一個比𝑑0大一倍的子集𝑑1,并在𝑑1上驗證剩下的那一半參數組合的性能。根據𝑑1上的驗證結果,淘汰評分排在后1/2的參數組合
3、再從全數據集中無放回抽樣出一個比𝑑1大一倍的子集𝑑2,并在𝑑2上驗證剩下1/4的參數組合的性能。根據𝑑2上的驗證結果,淘汰評分排在后1/2的參數組合……
持續循環。如果使用S代表首次迭代時子集的樣本量,C代表全部參數組合數,則在迭代過程中,用于驗證參數的數據子集是越來越大的,而需要被驗證的參數組合數量是越來越少的:
當備選參數組合只剩下一組,或剩余可用的數據不足,循環就會停下,具體地來說,當(1/n)*C <= 1或者nS > 總體樣本量,搜索就會停止。在實際應用時,哪一種停止條件會先被觸發,需要看實際樣本量及參數空間地大小。同時,每次迭代時增加的樣本量、以及每次迭代時不斷減少的參數組合都是可以自由設定的。
在這種模式下,只有在不同的子集上不斷獲得優秀結果的參數組合能夠被留存到迭代的后期,最終選擇出的參數組合一定是在所有子集上都表現優秀的參數組合。這樣一個參數組合在全數據上表現優異的可能性是非常大的,同時也可能展現出比網格/隨機搜索得出的參數更大的泛化能力。
- 對半網格搜索的局限性
然而這個過程當中會存在一個問題:子集越大時,子集與全數據集D的分布會越相似,但整個對半搜索算法在開頭的時候,就用最小的子集篩掉了最多的參數組合。如果最初的子集與全數據集的分布差異巨大的化,在對半搜索開頭的前幾次迭代中,就可能篩掉許多對全數據集D有效的參數,因此對半網格搜索最初的子集一定不能太小。
在對半網格搜索過程中,子集的樣本量時呈指數級增長:
n = 10 for i in range(15):print(i,n*3**i) #0 10 #1 30 #2 90 #3 270 #4 810 #5 2430 #6 7290 #7 21870 #8 65610 #9 196830 #10 590490 #11 1771470 #12 5314410 #13 15943230 #14 47829690在初始子集樣本量為10的前提下,7、8次迭代就會消耗掉2500+數據資源。在初始子集一定不能太小、且對半搜索的抽樣是不放回抽樣的大前提下,整體數據的樣本量必須要很大。從經驗來看,對半網格搜索在小型數據集上的表現往往不如隨機網格搜索與普通網格搜索,事實上,如果我們在Kaggle房價數據集上使用對半網格搜索,會發現其搜索結果還不如枚舉網格搜索、且搜索時間長于之前我們嘗試過的任何一種搜索方式。但在大型數據集上(比如,樣本量過w的數據集上),對半網格搜索則展現出運算速度和精度上的巨大優勢。
因此在對半網格搜索實現時,我們使用一組拓展的房價數據集,有2w9條樣本。
data2 = pd.read_csv(r"D:\Pythonwork\2021ML\PART 2 Ensembles\datasets\House Price\big_train.csv",index_col=0) X = data2.iloc[:,:-1] y = data2.iloc[:,-1] X.shape #(29062, 80) y.describe() #count 29062.000000 #mean 182798.864703 #std 72379.404452 #min 34900.000000 #25% 139000.000000 #50% 169092.000000 #75% 203009.750000 #max 755000.000000 #Name: SalePrice, dtype: float64 X.head()- 對半網格搜索的實現
在sklearn當中,我們可以使用HalvingGridSearchCV類來實現對半網格搜索。Halving搜索是sklearn 1.0.1版本才新增的功能,因此現在該功能還處于實驗階段,在導入該類的時候需要同時導入用以開啟對半網格搜索的輔助功能enable_halving_search_cv。當且僅當該功能被導入時,HalvingGridSearchCV才能夠被導入和使用。
import re import sklearn import numpy as np import pandas as pd import matplotlib as mlp import matplotlib.pyplot as plt import time from sklearn.ensemble import RandomForestRegressor as RFR from sklearn.experimental import enable_halving_search_cv from sklearn.model_selection import KFold, HalvingGridSearchCV, cross_validate, RandomizedSearchCV對半網格搜索的類如下所示:
class?sklearn.model_selection.HalvingGridSearchCV(estimator, param_grid, *, factor=3, resource='n_samples', max_resources='auto', min_resources='exhaust', aggressive_elimination=False, cv=5, scoring=None, refit=True, error_score=nan, return_train_score=True, random_state=None, n_jobs=None, verbose=0)
全部參數如下所示:
- factor
每輪迭代中新增的樣本量的比例,同時也是每輪迭代后留下的參數組合的比例。例如,當factor=2時,下一輪迭代的樣本量會是上一輪的2倍,每次迭代后有1/2的參數組合被留下。如果factor=3時,下一輪迭代的樣本量會是上一輪的3倍,每次迭代后有1/3的參數組合被留下。該參數通常取3時效果比較好。
- resource
設置每輪迭代中增加的驗證資源的類型,輸入為字符串。默認是樣本量,輸入為"n_samples",也可以是任意集成算法當中輸入正整數的弱分類器,例如"n_estimators"或者"n_iteration"。
- min_resource
首次迭代時,用于驗證參數組合的樣本量r0。可以輸入正整數,或兩種字符串"smallest" ,"exhaust"。
輸入正整數n,表示首次迭代時使用n個樣本。
輸入"smallest",則根據規則計算r0:
當資源類型是樣本量時,對回歸類算法,r0 = 交叉驗證折數n_splits * 2
當資源類型是樣本量時,對分類算法,r0 = 類別數量n_classes_ * 交叉驗證折數n_splits * 2
當資源類型不是樣本量時,等于1
輸入"exhaust",則根據迭代最后一輪的最大可用資源倒退r0。例如,factor=2, 樣本量為1000時,一共迭代3次時,則最后一輪迭代的最大可用資源為1000,倒數第二輪為500,倒數第三輪(第一輪)為250。此時r0 = 250。"exhaust"模式下最有可能得到好的結果,不過計算量會略大,計算時間會略長。
現在,我們依然使用網格搜索最初的,空間大小為1536的參數空間:
param_grid_simple = {"criterion": ["squared_error","poisson"], 'n_estimators': [*range(20,100,5)], 'max_depth': [*range(10,25,2)], "max_features": ["log2","sqrt",16,32,64,"auto"], "min_impurity_decrease": [*np.arange(0,5,10)]}count_space(param_grid_simple) #1536X.shape #(29062, 80)哪一種停止條件會被觸發?
#2.9w個樣本在factor=2, min_resource = 100的情況下可以迭代多久? for i in range(100):if 100*2**i > 29062:breakprint(i+1,100*2**i) #1 100 #2 200 #3 400 #4 800 #5 1600 #6 3200 #7 6400 #8 12800 #9 25600#1536種參數組合在factor=2的情況下可以迭代多久? for i in range(100):if 1536//2**i < 1:breakprint(i+1,int(1536//2**i+1)) #向上取整 #1 1537 #2 769 #3 385 #4 193 #5 97 #6 49 #7 25 #8 13 #9 7 #10 4 #11 2不難發現,當factor=2的時候,數據集不足的條件會先被觸發,最多只能迭代9次。也就是說,最終我們將在7組參數中選擇表現最好的一組參數,而不會一直讓搜索持續直到找出唯一最優的參數。如果我們無論如何都希望能夠找到唯一最后的參數,那我們可以使用下面的參數:
- aggressive_elimination
輸入布爾值,默認False。當數據總樣本量較小,不足以支撐循環直到只剩下最后一組備選參數時,可以打開該參數。
參數設置為True時,會重復使用首次迭代時的樣本量,直到剩下的數據足以支撐樣本量的增加直到只剩下最后一組備選參數
參數設置為False時,以全部樣本被用完作為搜索結束的指標
對于對半網格搜索應用來說,最困難的部分就是決定搜索本身復雜的參數組合。在調參時,如果我們希望參數空間中的備選組合都能夠被充分驗證,則迭代次數不能太少(例如,只迭代3次),因此factor不能太大。但如果factor太小,又會加大迭代次數,同時拉長整個搜索的運行時間。同時,迭代次數還會影響我們最終能夠使用的數據量,以及迭代完畢之后我們還需進一步驗證的參數組合數量,兩者都不能太少。因此,我們一般在使用對半網格搜索時,需考慮以下三個點:
1、min_resources的值不能太小,且在全部迭代過程結束之前,我們希望使用盡量多的數據
2、迭代完畢之后,剩余的驗證參數組合不能太多,10以下最佳,如果無法實現,則30以下也可以接受
3、迭代次數不能太多,否則時間可能會太長
以隨機網格搜索作為對比,我們來看看隨機網格搜索的結果:
param_grid_simple = {"criterion": ["squared_error","poisson"], 'n_estimators': [*range(20,100,5)], 'max_depth': [*range(10,25,2)], "max_features": ["log2","sqrt",16,32,64,"auto"], "min_impurity_decrease": [*np.arange(0,5,10)]}reg = RFR(random_state=1412,verbose=True,n_jobs=-1) cv = KFold(n_splits=5,shuffle=True,random_state=1412)#定義隨機搜索 search = RandomizedSearchCV(estimator=reg,param_distributions=param_grid_simple,n_iter = 800 #使用全域空間的一半作為子空間,scoring = "neg_mean_squared_error",verbose = True,random_state=1412,cv = cv,n_jobs=-1)#訓練隨機搜索評估器 #=====【TIME WARNING: 1個半小時~2小時】=====# start = time.time() search.fit(X,y) end = time.time()-start print(end/60) #103.20144965251286#查看最佳評估器 search.best_estimator_ #RandomForestRegressor(max_depth=24, max_features=16, min_impurity_decrease=0, # n_estimators=85, n_jobs=-1, random_state=1412, # verbose=True) #查看最終評估指標 abs(search.best_score_)**0.5 #1055.5552571413887 #驗證最佳參數組合的效力 rebuild_on_best_param(search.best_estimator_) #訓練RMSE:465.198 #測試RMSE:1054.359可以看到,隨機網格搜索的結果略微占優,但能夠嘗試的參數組合只有800個,且耗費的時間是對半搜索的4倍(1小時45分鐘)。對于對半搜索,我們可以繼續精細化調整整體的參數空間,進一步尋找更優的參數,但面對上萬樣本量的數據集,隨機搜索的運算速度不足以支撐精細化調參,就更別提網格搜索了。之后,我們會給大家更詳細地講解更快速、更高效的優化方法。?
總結
以上是生活随笔為你收集整理的LESSON 10.3 Halving网格搜索的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mark制图软件_绘图软件有哪些?
- 下一篇: 64位plsql和64位Oracle客户