学习器模型中一般有两类参数:
一类是可以从数据中学习估计得到,我们称为参数(Parameter)。
还有一类参数时无法从数据中估计,只能靠人的经验进行设计指定,我们称为超参数(Hyper parameter)。超参数是在开始学习过程之前设置值的参数。相反,其他参数的值通过训练得出。
我们在选择超参数有两个途径:
1)凭经验;
2)选择不同大小的参数,带入到模型中,挑选表现最好的参数。通过途径2选择超参数时,人力手动调节注意力成本太高,非常不值得。For循环或类似于for循环的方法受限于太过分明的层次,不够简洁与灵活,注意力成本高,易出错。
有一种选择方法叫做网络搜索(GridSearchCV),利用计算机快速计算的特点遍历所有的参数组合,找到最好的参数组合。听起来很高大上,本质上就是暴力搜索。注意的是,该方法在小数据集上很有用,数据集大了就不太适用了。会比较耗费时间和计算资源。数据量比较大的时候可以使用一个快速调优的方法——坐标下降。它其实是一种贪心算法:拿当前对模型影响最大的参数调优,直到最优化;再拿下一个影响最大的参数调优,如此下去,直到所有的参数调整完毕。这个方法的缺点就是可能会调到局部最优而不是全局最优,但是省时间省力。
使用示例:
from sklearn.model_selection import GridSearchCV
from sklearn.svm import SVR
from sklearn import datasets
dataset = datasets.load_iris()
X = dataset.data
y = dataset.target
grid = GridSearchCV(
estimator=SVR(kernel='rbf'),
param_grid={
'C': [0.1, 1, 10, 100],
'epsilon': [0.0001, 0.001, 0.01, 0.1, 1, 10],
'gamma': [0.001, 0.01, 0.1, 1]
},
cv=5, scoring='neg_mean_squared_error', verbose=0, n_jobs=-1)
grid.fit(X, y)
print(grid.best_score_)
print(grid.best_params_)
还有一种方法叫做随机搜索(RandomizedSearchCV),再参数量较大的时候使用这种方法可以快速或者较好的参数组合,在搜索超参数的时候,如果超参数个数较少(三四个或者更少),那么我们可以采用网格搜索,一种穷尽式的搜索方法。
但是当超参数个数比较多的时候,我们仍然采用网格搜索,那么搜索所需时间将会指数级上升。所以有人就提出了随机搜索的方法,随机在超参数空间中搜索几十几百个点,其中就有可能有比较小的值。这种做法比上面稀疏化网格的做法快,而且实验证明,随机搜索法结果比稀疏网格法稍好。RandomizedSearchCV使用方法和类GridSearchCV 很相似,但他不是尝试所有可能的组合,而是通过选择每一个超参数的一个随机值的特定数量的随机组合,这个方法有两个优点:
相比于整体参数空间,可以选择相对较少的参数组合数量。如果让随机搜索运行,它会探索每个超参数的不同的值 可以方便的通过设定搜索次数,控制超参数搜索的计算量,但是这个方法也有缺点,他会再搜索的过程中逐步偏向某些更加重要的超参数,会影响搜索的方向。
使用示例:
from scipy.stats import randint as sp_randint
from sklearn.model_selection import RandomizedSearchCV
from sklearn.datasets import load_digits
from sklearn.ensemble import RandomForestClassifier
# 载入数据
digits = load_digits()
X, y = digits.data, digits.target
# 建立一个分类器或者回归器
clf = RandomForestClassifier(n_estimators=20)
# 给定参数搜索范围:list or distribution
param_dist = {"max_depth": [3, None], # 给定list
"max_features": sp_randint(1, 11), # 给定distribution
"min_samples_split": sp_randint(2, 11), # 给定distribution
"bootstrap": [True, False], # 给定list
"criterion": ["gini", "entropy"]} # 给定list
# 用RandomSearch+CV选取超参数
n_iter_search = 20
random_search=RandomizedSearchCV(clf,param_distributions=param_dist,n_iter=n_iter_search, cv=5, iid=False)
random_search.fit(X, y)
print(random_search.best_score_)
print(random_search.best_params_)
还有一种方法叫贝叶斯优化(Bayesian optimization),给定一组超参数,为了计算相应的模型泛化误差,我们需要进行一次完整的模型训练,对于大型的深度学习模型可能需要花上几个小时的时间。注意到网格搜索和随机搜索中,不同的超参数采样是相互独立的,一个直接的想法是,能否充分利用已采样数据来决定下一次采样,以提高搜索效率(或者说减少采样次数)。
贝叶斯优化属于一类优化算法,称为基于序列模型的优化(SMBO)算法。这些算法使用先前对损失 f 的观察结果,以确定下一个(最优)点来抽样 f。该算法大致可以概括如下。
1、使用先前评估的点 X 1:n,计算损失 f 的后验期望。
2、在新的点 X 的抽样损失 f,从而最大化f的期望的某些方法。该方法指定 f 域的哪些区域最适于抽样。
3、重复这些步骤,直到满足某些收敛准则
使用例子:
from skopt import BayesSearchCV
import warnings
warnings.filterwarnings("ignore")
from skopt.space import Real, Categorical, Integer
knn = KNeighborsClassifier()
定义参数
grid_param = { 'n_neighbors' : list(range(2,11)) ,
'algorithm' : ['auto','ball_tree','kd_tree','brute'] }
#初始化贝叶斯搜索
Bayes = BayesSearchCV(knn , grid_param , n_iter=30 , random_state=14)
Bayes.fit(X_train,y_train)
#最好的参数组合
Bayes.best_params_
#最好分数
Bayes.best_score_
#所有的参数组合
Bayes.cv_results_['params']