机器学习调参——通过正交实验进行机器学习超参数调整的尝试

简介

下面的内容是本人想法的一次尝试性的工作,本文的目的仅在于学习交流,有的知识也是一知半解,不对的地方尽请指正。
通过设计正交实验,对结果进行极差分析,选择超参数的值,迭代这个过程,逐渐找到更精细的值。以下简称正交搜索。

目前较常用的超参数调整方法是网格搜索和随机搜索。
网格搜索:
优点:能得到更准确的结果。
缺点:当待调整的超参数较多时,需要进行大量组合。

随机搜索:
优点:计算量小。
缺点:最终的结果和搜索的次数以及随机种子的选取有关,搜索次数不够时可能得不到较好的结果。

正交搜索:
优点:计算量小,可以得到相对准确的结果。同时优化多个超参数。
缺点:需要进行超参数取值进行设计。
解决:相关的设计,代码中可以进行查询,根据正交表,设置超参数范围。

调参流程

以xgboost的超参数调整为例(数据见后面的项目链接)

from xgboost.sklearn import XGBRegressor
xgb_model = XGBRegressor(n_jobs=-1)  
X = pd.read_csv('X.csv')
y = pd.read_csv('y.csv')

1. 设计超参数

查看正交表(比如有四个超参数)

# my_ort代码后面的链接中会有
from my_ort import ORT
# 构建正交实验表
ort = ORT()
# 输入参数数量,返回可选的正交表
ort.seeSets(4,see_num=10)
Out[3]: 
                0  num
1     2^4 4^1 n=8    5
2         3^4 n=9    4
3       2^11 n=12   11
4    2^4 3^1 n=12    5
6    2^8 8^1 n=16    9
7        4^5 n=16    5
8    3^6 6^1 n=18    7
9       2^19 n=20   19
10   2^8 5^1 n=20    9
12  2^20 4^1 n=24   21
解释:
例:
2^4 4^1 n=8    5
2^4 4^1 表示有四个超参数的取值有两个,1个超参数的取值有4个
n=8 表示需要进行8组实验(8次搜索)
num=5 表示最多可以有5个超参数

有4个超参数,可以根据正交表中的3^4设置参数,
即这4个超参数有3个取值

params = {
'gamma':[0.3, 0.4, 0.5],
'subsample':[0.5, 0.7, 0.9],
'reg_lambda':[1,5,10],
'learning_rate':[0.01,0.1,0.3],
'max_depth':[3],
'colsample_bytree':[0.2],
'n_estimators':[750]
}
# 获取参数正交表
param_df=ort.genSets(params,mode=2)
Out[12]: 
   gamma  subsample  reg_lambda  learning_rate  max_depth  colsample_bytree  n_estimators
0    0.3        0.5           1           0.01          3               0.2           750
1    0.3        0.7          10           0.10          3               0.2           750
2    0.3        0.9           5           0.30          3               0.2           750
3    0.4        0.5          10           0.30          3               0.2           750
4    0.4        0.7           5           0.01          3               0.2           750
5    0.4        0.9           1           0.10          3               0.2           750
6    0.5        0.5           5           0.10          3               0.2           750
7    0.5        0.7           1           0.30          3               0.2           750
8    0.5        0.9          10           0.01          3               0.2           750

3. 进行训练

# 训练模型 传入训练集,对应的标签,以及损失函数 AdjustParam类见链接代码
a = AdjustParam(X, y, 'neg_mean_squared_error')
# 开始训练 传入模型,设计好的超参数正交表
a.run_ort(model=xgb_model, df_params=param_df)
# 查看正交搜索自动选出的模型
a.model
Out[15]: 
XGBRegressor(base_score=0.5, booster='gbtree', colsample_bylevel=1,
       colsample_bytree=0.2, gamma=0.3, learning_rate=0.1,
       max_delta_step=0, max_depth=3, min_child_weight=1, missing=None,
       n_estimators=750, n_jobs=-1, nthread=None, objective='reg:linear',
       random_state=0, reg_alpha=0, reg_lambda=1, scale_pos_weight=1,
       seed=None, silent=True, subsample=0.7)
# 查看所有的结果
a.ort_res
   gamma  subsample  reg_lambda  learning_rate  max_depth  colsample_bytree  n_estimators   ort_res  ort_res_std  ort_train_time
0    0.3        0.5           1           0.01          3               0.2           750  0.144111     0.004829               9
1    0.3        0.7          10           0.10          3               0.2           750  0.141269     0.004349              10
2    0.3        0.9           5           0.30          3               0.2           750  0.149688     0.004706              10
3    0.4        0.5          10           0.30          3               0.2           750  0.159380     0.005539               9
4    0.4        0.7           5           0.01          3               0.2           750  0.148800     0.005136               9
5    0.4        0.9           1           0.10          3               0.2           750  0.142483     0.004669               8
6    0.5        0.5           5           0.10          3               0.2           750  0.147529     0.004737               9
7    0.5        0.7           1           0.30          3               0.2           750  0.151033     0.004418               9
8    0.5        0.9          10           0.01          3               0.2           750  0.152610     0.005360               8
ort_res  :均方根误差
ort_res_std :交叉验证的方差
ort_train_time :交叉验证消耗的训练时间
# 查看极差分析结果(可以根据正交实验的结果和训练时间,手动调整超参数)
a.param_res
Out[27]: 
                       ort_res  ort_res_std  ort_train_time
gamma=0.3             0.145023     0.004628        9.666667
gamma=0.4             0.150221     0.005115        8.666667
gamma=0.5             0.150390     0.004838        8.666667
subsample=0.7         0.147034     0.004634        9.333333
subsample=0.9         0.148260     0.004912        8.666667
subsample=0.5         0.150340     0.005035        9.000000
reg_lambda=1          0.145876     0.004639        8.666667
reg_lambda=5          0.148672     0.004860        9.333333
reg_lambda=10         0.151086     0.005083        9.000000
learning_rate=0.1     0.143760     0.004585        9.000000
learning_rate=0.01    0.148507     0.005109        8.666667
learning_rate=0.3     0.153367     0.004888        9.333333
max_depth=3           0.148545     0.004860        9.000000
colsample_bytree=0.2  0.148545     0.004860        9.000000
n_estimators=750      0.148545     0.004860        9.000000
每个超参数对应的最小的ort_res,就是最后确定的超参数值

注:当使用得分优化模型时(分值越大越好)需要对AdjustParam中的代码进行修改

4. 结果验证

def rmsle_cv(model, n_folds=5):
    rmse= np.sqrt(-cross_val_score(model, X.values, y, scoring="neg_mean_squared_error", cv = n_folds))
    return rmse
# 正交分析选出的模型
score = rmsle_cv(a.model)
print("error: {:.4f} ({:.4f})".format(score.mean(), score.std()))
error: 0.1384 (0.0148)
得到的结果优于前面训练的9组数据

5. 随机搜索&网格搜索

# 随机搜索 & 网格搜索
from sklearn.model_selection import GridSearchCV,RandomizedSearchCV
param_test = {
'gamma':[0.3, 0.4, 0.5],
'subsample':[0.5, 0.7, 0.9],
'reg_lambda':[1,5,10],
'learning_rate':[0.01,0.1,0.3]}
xgb_model = XGBRegressor(
    max_depth = 3,
    colsample_bytree = 0.2,
    learning_rate =0.1, 
    n_estimators = 750,
    n_jobs=-1
)

# 随机搜索
t0 = time.time()
rand = RandomizedSearchCV(xgb_model, param_test, cv=5, scoring='neg_mean_squared_error', n_iter=9, random_state=1)  #
rand.fit(X, y)
print('随机搜索-度量记录:',rand.cv_results_)  # 包含每次训练的相关信息
print('随机搜索-最佳度量值:',np.sqrt(-rand.best_score_))  # 获取最佳度量值
print('随机搜索-最佳参数:',rand.best_params_)  # 获取最佳度量值时的代定参数的值。是一个字典
print('随机搜索-最佳模型:',rand.best_estimator_)  # 获取最佳度量时的分类器模型
t_rand = time.time() - t0
# rmse: 0.14600703568644044
# 随机搜索-最佳参数: {'subsample': 0.5, 'reg_lambda': 5, 'learning_rate': 0.1, 'gamma': 0.4}
# 耗时 70

# 网格搜索
gsearch = GridSearchCV( xgb_model , param_grid = param_test, scoring='neg_mean_squared_error', cv=5 )
t1 = time.time()
gsearch.fit(X, y)
gsearch.grid_scores_, gsearch.best_params_, gsearch.best_score_
t_gsearch = time.time()-t1
print(t_gsearch)
print('随机搜索-度量记录:',gsearch.cv_results_)  # 包含每次训练的相关信息
print('随机搜索-最佳度量值:',np.sqrt(-gsearch.best_score_))  # 获取最佳度量值
print('随机搜索-最佳参数:',gsearch.best_params_)  # 获取最佳度量值时的代定参数的值。是一个字典
print('随机搜索-最佳模型:',gsearch.best_estimator_)  # 获取最佳度量时的分类器模型
# rmse :0.13812885469181446
# 网格搜索 最佳参数:{'gamma': 0.3, 'learning_rate': 0.1, 'reg_lambda': 1, 'subsample': 0.5}
# 耗时 :636s

6. 正交搜索VS随机搜索VS网格搜索

           rmse   用时(秒)
正交分析  0.1384   95
网格搜索  0.1381   636
随机搜索  0.1460   70

7. 结论

网格搜索:搜索了所有情况的参数组合, 损失最小,但却需要进行3^4 共81组训练
随机搜索:结果和随机数的选取有关
正交搜索:能在较短时间内得到趋于最优值的结果,效果显著,训练组数和随机搜索一样,结果趋近于网格搜索。

8. 更多分析

还可对正交表做更多的挖掘,比如在损失相当的情况下,可选择训练速度更快的模型。

传送门

本文测试样例链接(含代码及数据)

https://github.com/liujia11/machine_learning_hyperparameter_adjustment_ort

其它

正交表构造参考:https://github.com/lovesoo/OrthogonalArrayTest
添加功能(函数seeSets):输入变量数,返回可选的正交表结构

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值