在机器学习和深度学习的实践中,模型参数的调优是一个关键步骤。合适的参数配置可以显著提高模型的性能。为了找到这些最佳参数,研究者们开发了多种优化方法,如网格搜索、随机搜索和贝叶斯优化等。本文将重点介绍贝叶斯优化的原理,并对比其与网格搜索等其他优化方式的优缺点。
一、贝叶斯优化原理
贝叶斯优化是一种基于贝叶斯定理的全局优化算法,适用于目标函数难以计算或计算成本较高的情况。其核心思想是通过建立一个目标函数的概率模型来指导搜索过程,从而找到使目标函数取得最优值的参数配置。
在贝叶斯优化中,我们首先假设目标函数服从一个先验分布(通常是高斯过程模型)。然后,在每次迭代中,我们根据当前的目标函数概率模型选择一个最有可能改善性能的点进行评估。评估完成后,我们将新的观测结果添加到模型中,并更新概率模型。这个过程会一直重复,直到达到预设的迭代次数或满足其他停止条件。
贝叶斯优化的优势在于它能够根据历史观测结果智能地选择下一个评估点,从而在较少的迭代次数内找到接近最优解的参数配置。此外,贝叶斯优化还能够处理多峰、非凸等复杂的目标函数,这使得它在许多实际应用中表现出色。
二、网格搜索与其他优化方式的优缺点
网格搜索是一种简单的参数调优方法,它通过对每个参数预设一个取值范围,并在这个范围内进行穷举搜索来找到最优参数配置。虽然网格搜索可以覆盖所有可能的参数组合,但当参数空间较大时,其计算成本会急剧增加。此外,网格搜索也无法处理非凸或连续的目标函数。
随机搜索则是一种更高效的参数调优方法。它通过在参数空间中随机采样来寻找最优参数配置。与网格搜索相比,随机搜索能够在相同的计算成本下探索更多的参数组合,但也可能错过某些潜在的最优解。
与网格搜索和随机搜索相比,贝叶斯优化具有以下优点:
智能选择评估点:贝叶斯优化能够根据历史观测结果智能地选择下一个评估点,从而在较少的迭代次数内找到接近最优解的参数配置。
处理复杂目标函数:贝叶斯优化能够处理多峰、非凸等复杂的目标函数,这使得它在许多实际应用中表现出色。
自适应调整搜索策略:贝叶斯优化能够根据目标函数的性质自适应地调整搜索策略,以更好地平衡探索和利用的关系。
然而,贝叶斯优化也存在一些缺点:
对先验知识的依赖:贝叶斯优化需要预设目标函数的先验分布,这需要对目标函数有一定的了解。如果先验分布设置不当,可能会影响优化效果。
计算成本较高:虽然贝叶斯优化能够在较少的迭代次数内找到接近最优解的参数配置,但每次迭代都需要更新目标函数的概率模型,这可能会增加计算成本。
三、贝叶斯优化在LightGBM调参中的应用
LightGBM是一个高效、准确的梯度提升框架,广泛应用于各种机器学习任务中。在LightGBM的调参过程中,我们可以使用贝叶斯优化来自动寻找最优参数配置。通过结合k折交叉验证,我们可以更准确地评估模型的性能,并找到使模型在验证集上取得最佳性能的参数配置。
在实际应用中,我们可以使用现成的贝叶斯优化库(如Scikit-Optimize、Hyperopt等)来实现LightGBM的自动调参。这些库提供了丰富的接口和功能,使得我们可以方便地定义目标函数、初始化优化器并运行优化过程。
四、贝叶斯优化的python实现
网格搜索交叉验证的python代码实现参考,以下是具体的贝叶斯优化的python代码实现
import os
import gc
import math
import pandas as pd
import numpy as np
import lightgbm as lgb
import xgboost as xgb
from catboost import CatBoostRegressor
from sklearn.linear_model import SGDRegressor, LinearRegression, Ridge
from sklearn.preprocessing import MinMaxScaler
from sklearn.model_selection import StratifiedKFold, KFold
from sklearn.metrics import log_loss
from sklearn.model_selection import train_test_split
from tqdm import tqdm
import matplotlib.pyplot as plt
import time
import warnings
warnings.filterwarnings('ignore')
df = pd.read_csv("random_data.csv")
# 提取特征和目标变量
X = df.drop(columns="Default")
Y = df["Default"]
# 划分训练集和测试集数据
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.2, random_state=42)
def cv_model(clf, train_x, train_y, test_x, seed=2024):
# 使用K折交叉验证训练和验证模型
folds = 5
kf = KFold(n_splits=folds, shuffle=True, random_state=seed)
# 初始化oof预测和测试集预测
oof = np.zeros(train_x.shape[0])
test_predict = np.zeros(test_x.shape[0])
cv_scores = []
# KFold交叉验证
for i, (train_index, valid_index) in enumerate(kf.split(train_x, train_y)):
print('************************************ {} ************************************'.format(str(i+1)))
trn_x, trn_y, val_x, val_y = train_x.iloc[train_index], train_y[train_index], train_x.iloc[valid_index], train_y[valid_index]
# 转换数据为lightgbm数据格式
train_matrix = clf.Dataset(trn_x, label=trn_y)
valid_matrix = clf.Dataset(val_x, label=val_y)
# 定义lightgbm参数
params = {
'boosting_type': 'gbdt', # GBDT算法为基础
'objective': 'multiclass', # 多分类任务
'num_class': 4, # 设置多分类问题的类别个数
'num_leaves': 2 ** 5, # 指定叶子的个数,默认值为31,大会更准,但可能过拟合。最大不能超过2^max_depth
# 构建弱学习器,对特征随机采样的比例,默认值为1,可以防止过拟合,每次迭代中随机选择80%的参数来建树
'feature_fraction': 0.8,
'bagging_fraction': 0.8, # 每次迭代时用的数据比例,用于加快训练速度和减小过拟合
'bagging_freq': 4, # 表示bagging(采样)的频率,0意味着没有使用bagging ,k意味着每k轮迭代进行一次bagging
'learning_rate': 0.025,
'seed': seed,
# 使用线程数,一般设置成-1,使用所有线程。这个参数用来控制最大并行的线程数,如果你希望取得所有CPU的核,那么你就不用管它。
'nthread': 28,
'n_jobs':24, # 使用多少个线性并构造模型
'verbose': -1,
'lambda_l1': 0.4, # L1正则化权重项,增加此值将使模型更加保守。
'lambda_l2': 0.5, # L2正则化权重项,增加此值将使模型更加保守
# 'device' : 'gpu'
}
# 使用训练集数据进行模型训练
model = clf.train(params,
train_set=train_matrix,
valid_sets=valid_matrix,
num_boost_round=2000,
verbose_eval=100,
early_stopping_rounds=200)
# 对验证集进行预测
val_pred = model.predict(val_x, num_iteration=model.best_iteration)
test_pred = model.predict(test_x, num_iteration=model.best_iteration)
oof[valid_index] = val_pred
test_predict += test_pred / kf.n_splits
# 计算打印当前折的分数
score = np.sqrt(mean_squared_erroe(vale_pred, val_y))
cv_scores.apped(score)
print(cv_scores)
return oof, test_predict
"""
其他训练是的优化方式,可以参考九天老师的信用卡预测的案列
1、贪心调参
2、网格搜索
3、贝叶斯调参 使用前要安装 pip install bayesian-optimization
"""
from sklearn.model_selection import cross_val_score
from sklearn.metrics import make_scorer
"""定义优化函数"""
def rf_cv_lgb(num_leaves, max_depth, bagging_fraction, feature_fraction, bagging_freq, min_data_in_leaf,
min_child_weight, min_split_gain, reg_lambda, reg_alpha):
# 建立模型
model_lgb = lgb.LGBMClassifier(boosting_type='gbdt', objective='multiclass', num_class=4,
learning_rate=0.1, n_estimators=5000,
num_leaves=int(num_leaves), max_depth=int(max_depth),
bagging_fraction=round(bagging_fraction, 2), feature_fraction=round(feature_fraction, 2),
bagging_freq=int(bagging_freq), min_data_in_leaf=int(min_data_in_leaf),
min_child_weight=min_child_weight, min_split_gain=min_split_gain,
reg_lambda=reg_lambda, reg_alpha=reg_alpha,
n_jobs= 8
)
f1 = make_scorer(f1_score, average='micro')
#使用的是5折交叉认证+f1的评定方法
val = cross_val_score(model_lgb, X_train_split, y_train_split, cv=5, scoring=f1).mean()
return val
from bayes_opt import BayesianOptimization
"""定义优化参数"""
bayes_lgb = BayesianOptimization(
rf_cv_lgb,
{
'num_leaves':(10, 200),
'max_depth':(3, 20),
'bagging_fraction':(0.5, 1.0),
'feature_fraction':(0.5, 1.0),
'bagging_freq':(0, 100),
'min_data_in_leaf':(10,100),
'min_child_weight':(0, 10),
'min_split_gain':(0.0, 1.0),
'reg_alpha':(0.0, 10),
'reg_lambda':(0.0, 10),
}
)
"""开始优化"""
bayes_lgb.maximize(n_iter=10)
"""显示优化结果------根据这个进行更改参数"""
bayes_lgb.max