学习器模型中一般有两类参数,一类是可以从数据中学习估计得到,我们称为参数(Parameter)。还有一类参数时无法从数据中估计,只能靠人的经验进行设计指定,我们称为超参数(Hyper parameter)。超参数是在开始学习过程之前设置值的参数。相反,其他参数的值通过训练得出。
参数空间的搜索一般由以下几个部分构成:
我们在选择超参数有两个途径:1)凭经验;2)选择不同大小的参数,带入到模型中,挑选表现最好的参数。通过途径2选择超参数时,人力手动调节注意力成本太高,非常不值得。For循环或类似于for循环的方法受限于太过分明的层次,不够简洁与灵活,注意力成本高,易出错。GridSearchCV 称为网格搜索交叉验证调参,它通过遍历传入的参数的所有排列组合,通过交叉验证的方式,返回所有参数组合下的评价指标得分。
GridSearchCV听起来很高大上,其实就是暴力搜索。注意的是,该方法在小数据集上很有用,数据集大了就不太适用了。数据量比较大的时候可以使用一个快速调优的方法——坐标下降。它其实是一种贪心算法:拿当前对模型影响最大的参数调优,直到最优化;再拿下一个影响最大的参数调优,如此下去,直到所有的参数调整完毕。这个方法的缺点就是可能会调到局部最优而不是全局最优,但是省时间省力。
class sklearn.model_selection.GridSearchCV(estimator, param_grid, scoring=None, n_jobs=None, refit=True, cv='warn', verbose=0, pre_dispatch='2*n_jobs', error_score='raise-deprecating', return_train_score='warn')
# estimator:所使用的模型,传入除需要确定最佳的参数之外的其他参数。模型都需要一个score方法,或传入scoring参数。
# param_grid:需要搜索调参的参数字典,参数值类型为字典(dict)或由字典组成的列表(list)。用于设置待评测参数和对应的参数值。
# scoring:模型评价标准
使用示例
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使用方法和类GridSearchCV 很相似,但他不是尝试所有可能的组合,而是通过选择每一个超参数的一个随机值的特定数量的随机组合,这个方法有两个优点:
相比于整体参数空间,可以选择相对较少的参数组合数量。如果让随机搜索运行,它会探索每个超参数的不同的值 可以方便的通过设定搜索次数,控制超参数搜索的计算量。添加参数节点不会影响性能,不会降低效率。RandomizedSearchCV的使用方法其实是和GridSearchCV一致的,但它以随机在参数空间中采样的方式代替了GridSearchCV对于参数的网格搜索,在对于有连续变量的参数时,RandomizedSearchCV会将其当做一个分布进行采样进行这是网格搜索做不到的,它的搜索能力取决于设定的n_iter参数。
class sklearn.model_selection.RandomizedSearchCV(estimator, param_distributions, *, n_iter=10, scoring=None, n_jobs=None , refit=True, cv=None, verbose=0, pre_dispatch='2*n_jobs', random_state=None, error_score=nan, return_train_score=False)
# param_distributions:参数分布,字典格式。将我们所传入模型当中的参数组合为一个字典。其搜索策略如下:
# 对于搜索范围是distribution的超参数,根据给定的distribution随机采样
# 对于搜索范围是list的超参数,在给定的list中等概率采样
# n_iter:训练300次,数值越大,获得的参数精度越大,但是搜索时间越长
使用示例:
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_)
遗传算法试图将自然选择机制应用于机器学习环境。它受到达尔文自然选择过程的启发,因此通常也称为进化算法。假设我们创建了具有一些预定义超参数的N个机器学习模型。然后,我们可以计算每个模型的准确性,并决定只保留一半模型(性能最好的模型)。现在,我们可以生成具有与最佳模型相似的超参数的后代,以便再次获得N个模型的种群。在这一点上,我们可以再次计算每个模型的准确性,并在定义的世代中重复该循环。这样,只有最佳模型才能在流程结束时生存下来。
TPOT是一种基于遗传算法优化机器学习管道(pipeline)的Python自动机器学习工具。简单来说,就是TPOT可以智能地探索数千个可能的pipeline,为数据集找到最好的pipeline,从而实现机器学习中最乏味的部分。
TPOT是在sklearn的基础之上做的封装库。其主要封装了sklearn的模型相关模块、processesing模块和feature_selection模块,所以TPOT的主要功能是集中在使用pipeline的方式完成模型的数据预处理、特征选择和模型选择方面。此外,我们还发现了TPOT已经对xgboost进行了支持。
虽然TPOT使用遗传算法代替了传统的网格搜索进行超参数选择,但由于默认初始值的随机性,在少量的进化(迭代)次数下,TPOT最终选择的模型往往并不相同。
计算效率问题。作者在代码中写道:进化(迭代)次数和每一代保留的个体数量值越多,最终得模型得分会越高。但这同样也会导致耗时很长。如果使用相当复杂的数据集或运行TPOT短时间,不同的TPOT运行可能会导致不同的流水线推荐。TPOT的优化算法本质上是随机的,这意味着它使用随机性(部分地)来搜索可能的流水线空间。当两个TPOT运行推荐不同的管道时,这意味着TPOT运行由于时间不够而不收敛,或者多个管道在数据集上执行的次数大致相同。这实际上是一个优于固定网格搜索技术的优点:TPOT是一个助手,它通过探索您可能从未考虑过的流水线配置来提供解决如何解决特定机器学习问题的想法,然后将微调留给更受约束的参数调整技术,例如网格搜索。
使用示例:
from tpot import TPOTClassifier
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
iris = load_iris()
X = iris.data
y = iris.target
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
tpot = TPOTClassifier(generations=5, population_size=50, verbosity=2, n_jobs=-1)
tpot.fit(X_train, y_train)
print(tpot.score(X_test, y_test))
TPOT的主要参数: