1. 背景&预备知识
近期小编写程序的时候,遇到了实验次数非常多的情况(事实上,一篇好的paper通常都是要经过非常多次的实验),比如说有10种不同的输入变量组合,要在10个城市上用4种模型进行建模,这样就有4 * 10 * 8 = 320种组合。如果每一种情况我们都进行手工调优的话,那将花费极大的时间和精力,而且手动调优并不一定能得到满意的效果。今天小编就同大家一起学习一下参数调优中的网格搜索方法,以便更好地解决上述问题。
什么是超参数?
超参数是在训练模型之前就要设置的参数,而不是通过训练得到的参数。举个例子来说,神经网络的隐层数和每层的节点数就是超参数,因为其需要在模型训练前就设定好。而两层神经元之间的权重就不是超参数,因为其随着每一轮迭代而不断更新。
什么是网格搜索?
网格搜索是一种常见的参数调优方法,其根本目的是通过遍历不同的超参数组合,达到模型最优化的效果。比如支持向量机中使用rbf核的情况下,C的调优范围设置为[1, 10, 100],gamma的范围设置为[0.001, 0.0001],那么超参数就有3 * 2 = 6种组合,网格搜索就是遍历这六种组合,找到其中模型表现最好的超参数的值。当然,因为网格搜索是基于遍历的思想,所以当参数空间比较大的时候,模型表现好的同时会牺牲很多的训练时间,所以也会有随机搜索的方法,后续我们会慢慢讲到~
什么是k折交叉验证?
把数据集分成K份,每个子集互不相交且大小相同,依次从K份中选出1份作为验证集,其余K-1份作为训练集,这样进行K次单独的模型训练和验证,最后将K次验证结果取平均值,作为此模型的验证误差。
为什么要划分验证集,直接用测试集调优不行吗?
如果根据测试集上的模型表现来选取超参数的话,可能会得到过度拟合于测试集的超参数,模型泛化能力会降低。如果借助验证集进行超参数选取,并在测试集上测试模型表现的话就能防止上述问题。
2. sklearn中的网格搜索方法
使用常见的机器学习模型时,我们通常会选用sklearn这个库(深度学习时一般不用sklearn,会用keras、pytorch、tensorflow)。
使用网格搜索时,我们需要先从sklearn中调用GridSearchCV这个类。
from sklearn.model_selection import GridSearchCV, KFold
class sklearn.model_selection.GridSearchCV(estimator, param_grid, scoring=None, n_jobs=None, refit=True, cv=None, verbose=0, pre_dispatch='2n_jobs', error_score=nan, return_train_score=False)
GridSearchCV中的参数如下:
-
estimator:可以理解为一个模型框架吧,比如说用支持向量回归就是svr(),多层感知机就是MLPRegressor(),随机森林就是RandomForestRegressor(),当然这里也可以是一些其他的分类器。
-
param_grid:这里一般以字典或者列表形式传入,内容是参数名+参数空间,比如 'C': [1,3,5,7,9,15,20,25,30,40,50,100,200]
-
cv:交叉验证方法,这里通常选用k折交叉验证
-
scoring:测试集中评估交叉验证模型性能的策略
3. 网格搜索程序实现
随机森林
# 调用随机森林回复器、网格搜索和k折交叉验证类
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import GridSearchCV, KFold
# 设置需要调优的超参数 (可以通过RandomForestRegressor().get_params()查看有哪些超参数)
parameters = {'max_depth': range(1, 20),
'n_estimators': range(1, 20)}
# 调用10折交叉验证
kfold = KFold(n_splits=10)
# 设置estimator
forest = RandomForestRegressor()
# 训练集上进行网格搜索
grid = GridSearchCV(forest, parameters, scoring='r2', cv=kfold)
grid = grid.fit(x_train, y_train)
# 查看最优参数
reg = grid.best_estimator_
print('best score: %f'%grid.best_score_)
print('best parameters:')
for key in parameters.keys():
print('%s: %d'%(key, reg.get_params()[key]))
print('test score: %f'%reg.score(x_test, y_test))
# 将最优参数传入estimator,获取最优模型
forest = RandomForestRegressor(max_depth=reg.get_params()['max_depth'], n_estimators=reg.get_params()['n_estimators'])
支持向量回归(除了模型其余程序都是类似的)
from sklearn.svm import SVR
param_grid = [
{'kernel': ['linear'], 'C': [1,3,5,7,9,15,20,25,30,40,50,100,200]},
{'kernel': ['rbf'], 'C': [1,3,5,7,9,15,20,25,30,40,50,100,200], 'gamma': [0.001,0.002,0.003,0.004,0.005,0.006,0.007,0.008,0.009]},
]
kfold = KFold(n_splits=10)
svr = SVR()
grid = GridSearchCV(svr, parameters, scoring='r2', cv=kfold)
grid = grid.fit(x_train, y_train)
神经网络(除了模型其余程序都是类似的)
from sklearn.neural_network import MLPRegressor
parameters = {'hidden_layer_sizes': [(4,4),(5,5),(6,6),(7,7),(8,8),(4,4,4),(5,5,5),(6,6,6),(7,7,7),(8,8,8)]}
kfold = KFold(n_splits=10)
ann = MLPRegressor(solver='lbfgs', alpha=0.5, activation='relu', max_iter=2000)
grid = GridSearchCV(ann, parameters, scoring='r2', cv=kfold)