贝叶斯优化python包_贝叶斯优化
万壑松风知客来,摇扇抚琴待留声
1. 文起
本文旨在阐述借助 Python 调用第三方库的方法,并采用贝叶斯优化原理的 Hyperopt 方法来进行超参数优化的选择。具体而言,贝叶斯优化原理及其相关内容将在下次文章中进行较为详细的阐述,并建议参考此处。
Hyperopt 属于 Python 贝叶斯优化库中的一员。该库采用 Tree Parzen Estimator(TPE),而其他 Python 库则包括 Spearmint(基于高斯过程代理)和 SMAC(基于随机森林回归)。贝叶斯优化问题包含四个关键组成部分:目标函数:机器学习模型被用来评估一组超参数在验证集上的损失。
域空间:类似于网格搜索,传入超参数的搜索范围。
参数搜索:构造替代函数并选择下一个超参数值进行评估的方法。
存储结果:最小化函数在评估每组测试后的最优超参数存储结果。
基于 Hyperopt 的简单示例说明:最简化的操作流程是实现以 XGBoost 作为调参模型,并通过 hyperopt 实现贝叶斯优化的四个主要环节。
一:定义目标函数1
2
3
4
5
6
7
8
9
该代码使用10倍划分比例将数据集分为训练集与测试集,并通过随机种子999确保数据分割的可重复性
data_train =xgb.DMatrix(train_X, train_y, silent=False)
定义目标函数
def (params, n_folds=10):
result = XGBoost.迭代过程(
params=参数配置,
data_train=训练数据集,
num_boost_round=循环次数设定,
nfold=折数设置,
stratified=False→分层划分选项不执行,
shuffle=True→打乱顺序选项执行,
metrics='mean absolute error'→评估指标包括MAE度量标准,
early_stopping_rounds=10→早停轮次设定为10
)
mae = max(cv_results['test-mae-mean'])
loss = mae
return loss
其中objective()被定义为一个黑箱目标函数,在其内部计算并返回损失值。通过评估该损失值,Hyperopt能够系统地优化并选择出最佳超参数组合。随后,fmin()将通过迭代优化算法对该损失进行最小化处理。在此情境下,我们的目标函数较为简单,未对其实现进行复杂的优化或修改。
二:设置域空间1
2
3
4
5
6
7
8
9from hyperopt import hp
space = {
'learning_rate': hp.loguniform('learning_rate',np.log(0.01),np.log(0.4)),
'max_depth': hp.choice('max_depth',range(1,8,1)),
'min_child_weight': hp.choice('min_child_weight',range(1,5,1)),
'reg_alpha': hp.uniform('reg_alpha',0.0,1.0),
'subsample': hp.uniform('subsample',0.5,1.0),
'colsample_bytree': hp.uniform('colsample_bytree',0.6,1.0)
}
搜索空间即为给定超参数优化范围,在该库中通过hp接口设计即可实现该功能。该库中的hp接口设计支持多种参数采样策略:采用对数尺度均匀分布采样(如hp.loguniform)、基于对数正态分布的采样策略(hp.lognormal)、基于正态分布的概率密度采样(hp.normal)、通过自定义候选列表进行随机抽样的选项策略(hp.choice)、采用线性尺度均匀分布采样策略(hp.uniform)以及离散整数型变量上的均匀分布采样方法(hp.quniform)。
在这里仅涉及基本的域空间配置。除了这种方法外,还可以通过选择特定模型构建列表来实现多模型筛选的功能。这部分内容将在后面详细讲解。需要注意的是,在实际应用中如果遇到参数名称相同的情况可能会导致错误(例如当两个不同的机器学习算法如XGBoost和LightGBM拥有部分相同的参数名称时)。这种情况下系统会抛出'DuplicateLabel'错误提示信息。为了解决这个问题建议在内层组件命名时采用唯一的标识符以避免冲突问题,并且这部分的具体修改方案将会在后续章节中进行详细说明
三:参数搜索1
2
3
4
5
6
7
8# 参数搜索算法
from hyperopt import tpe
tpe_algorithm = tpe.suggest
寻找目标函数的最小值
from hyperopt import fmin
MAX_EVALS = 500
best = fmin(fn=objective, space=space, algo=tpe.suggest, max_evals=MAX_EVALS)
Hyperopt 提供了不同种类的搜索算法选择方案:包括泰特优化器(TPE)(tpe. suggest)、随机采样方法(rand)(rand. suggest),以及模拟退火算法(annal)(annal. suggest)。此外,在优化过程中需要预先定义用于优化目标函数并获取其最小损失值的 fmin() 函数。其中参数max_evals的作用是决定迭代次数。
四:存储结果1
2# 优化结果参数
print(best)
best 就是 Hyperopt 返回最佳结果的参数。
3. Hyperopt 可以变复杂
在上述代码中使用了几处少量的简单代码实现了Python语言调用Hyperopt算法来完成超参数优化的功能。任何单一的方法都可以变得复杂起来甚至更加难以处理,并且Hyperopt作为一种优化工具也不例外。因此,在原有代码基础上稍作修改就可以实现一个稍微复杂的Hyperopt配置方案从而获得更为强大的性能支持。注释详细解释了以下代码的作用:首先从支持向量机(SVM)、梯度提升树(XGBoost)、lightgbm模型(LightGBM)、k近邻算法(KNN)等五个不同的机器学习模型中选择合适的超参数组合最终确定HyperOpt算法认为最合适的模型参数。其中损失值定义为偏离度并且可以在黑箱函数内部追踪整个优化过程
一:定义目标函数1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66import pandas as pd
import numpy as np
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.model_selection import cross_val_score
from sklearn.metrics import mean_absolute_error
from sklearn.svm import SVR
import xgboost as xgb
import lightgbm as lgb
from sklearn.neighbors import KNeighborsRegressor
from sklearn.linear_model import LinearRegression
from hyperopt import STATUS_OK
import warnings
warnings.filterwarnings('ignore')
df = pd.read_csv('data.csv')
features = df.iloc[:,:-1]
target = df.iloc[:,-1]
scaler = StandardScaler()
features = scaler.fit_transform(features)
将数据集分为训练集和测试集,并使用特征集合与目标变量作为输入进行处理
计算偏离度
def dod(real_values, pred_values):
dod_resulting = numpy.around(((abs(real_values - pred_values) / real_values).mean()), 4)
return dod_result
计算传入模型的损失
def (params):
model_name = params['model_name']
del params['model_name']
if model_name == 'svm':
clf = SVR(**params)
elif model_name == 'xgboost':
clf = xgb.XGBRegressor(**params)
elif model_name == 'lightgbm':
clf = lgb.LGBMRegressor(**params)
elif model_name == 'knn':
clf = KNeighborsRegressor(**params)
elif model_name == 'linear':
clf = LinearRegression(**params)
else:
return 0
clf.fit(train_X, train_y)
pred = clf.predict(test_X)
loss = dod(test_y, pred)
偏离程度是一种自行设计的指标,在实际应用中可以通过交叉验证获得结果需要注意的是,在计算过程中损失函数的值通常是负数
损失值 = 使用10折交叉验证计算分类器在训练集上表现的平均值(评估指标为负平均绝对误差)。
return {'loss':loss, 'params':params, 'status':STATUS_OK}
定义总的目标函数
count = 0
best_score = np.inf
model_name = None
def fn(params):
global model_name, best_score, count
count +=1
score = objective(params.copy())
loss = score['loss']
if loss < best_score:
best_score = loss
model_name = params['model_name']
if count % 50 == 0:
print('iters:{0}, score:{1}'.format(count, score))
return loss
第二部分:阐述域空间设定。由于这两个树模型共享了相同的参数名称,在配置相关参数时必须区分这些参数名称。
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42from hyperopt import hp
设置域空间
space = hp.choice('regressor_type',[
{
'model_name': 'svm',
'C': hp.uniform('C',0, 10.0),
'kernel': hp.choice('kernel', ['linear', 'rbf']),
'gamma': hp.uniform('gamma', 0, 20.0)
},
{
'model_name': 'xgboost',
'n_estimators': hp.choice('xgb_n_estimators', range(50,501,2)),
'learning_rate': hp.uniform('xgb_learning_rate', 0.01, 0.3),
'max_depth': hp.choice('xgb_max_depth', range(2,8,1)),
'min_child_weight': hp.choice('xgb_min_child_weight', range(1,5,1)),
'reg_alpha': hp.uniform('xgb_reg_alpha', 0, 1.0),
'subsample': hp.uniform('xgb_subsample', 0.5, 1.0),
'colsample_bytree': hp.uniform('xgb_colsample_bytree', 0.6, 1.0)
},
{
'model_name': 'lightgbm',
'n_estimators': hp.choice('lgb_n_estimators', range(50,501,2)),
'learning_rate': hp.uniform('lgb_learning_rate', 0.01, 0.3),
'max_depth': hp.choice('lgb_max_depth', range(2,8,1)),
'num_leaves': hp.choice('lgb_num_leaves', range(20, 50, 1)),
'min_child_weight': hp.choice('lgb_min_child_weight', [0.001,0.005,0.01,0.05,0.1]),
'min_child_samples': hp.choice('lgb_min_child_samples', range(5,51,5)),
'subsample': hp.uniform('lgb_subsample', 0.5, 1.0),
'colsample_bytree': hp.uniform('lgb_colsample_bytree', 0.6, 1.0),
'reg_alpha': hp.uniform('lgb_reg_alpha', 0, 1.0)
},
{
'model_name': 'knn',
'n_neighbors': hp.choice('n_neighbors', range(2,11)),
'algorithm': hp.choice('algorithm', ['auto','ball_tree','kd_tree','brute'])
},
{
'model_name': 'linear',
'normalize': hp.choice('normalize', [False, True])
}
])
三:参数搜索1
2
3
4
5
6
7
8
9
10
11
12# 设定搜索算法
from hyperopt import tpe
如果有有必要,可以设置查看黑盒函数fn中的搜索情况(每次选择参数等)
from hyperopt import Trials
trials = Trials()
定义搜索目标函数最小值函数
from hyperopt import fmin
MAX_EVALS = 1500
将最佳参数赋值为fmin函数的结果;该函数接受目标函数(fn)、搜索空间(space)、使用Tree Parzen Estimator(TPE)的建议方法(algo=tpe.suggest)、最大评估次数(MAX_EVALS)以及试验次数(Trials)。
print('model_name: {0}, best_score: {1}'.format(model_name, best_score))
四:存储结果1
2
3
4
5# 最佳参数
print(best_params)
查看黑盒函数中的变化
print(trials)# 可以通过循环依次打印结果
4. 文末
Hyperopt 借助不同的配置方案能够实现更为精确和完善的结果,在优化搜索参数方面也取得了显著成效。
你需要注意的一点是,Hyperopt并不是一个完全没有缺陷的方法;它还可能在初期就陷入局部最优状态;因此,在这种情况下它仅仅是一种基于数学理论支撑的高级暴力搜索手段;相较于暴力网格搜索方法而言
