基于Optuna实现多种贝叶斯优化

基于Optuna实现多种贝叶斯优化

Optuna是当前最成熟、最具扩展性的超参数优化框架,相较于传统的bayes_opt,Optuna明显专为机器学习和深度学习而设计。为了满足机器学习开发者的需求,Optuna提供了强大而稳定的API,因此其代码简洁、模块化程度高,是我们介绍的库中最为精简的之一。Optuna的优势在于,它能够与PyTorch、Tensorflow等深度学习框架无缝集成,同时也能与scikit-optimize等sklearn优化库结合使用,因此可适用于各种优化场景。

1 定义目标函数与参数空间

在Optuna中,我们并不需要将参数或参数空间输入目标函数,而是需要直接在目标函数中定义参数空间

def optuna_objective(trial):
    
    #定义参数空间
    n_estimators = trial.suggest_int("n_estimators",80,100,1) #整数型,(参数名称,下界,上界,步长)
    max_depth = trial.suggest_int("max_depth",10,25,1)
    max_features = trial.suggest_int("max_features",10,20,1)
    #max_features = trial.suggest_categorical("max_features",["log2","sqrt","auto"]) #字符型
    min_impurity_decrease = trial.suggest_int("min_impurity_decrease",0,5,1)
    #min_impurity_decrease = trial.suggest_float("min_impurity_decrease",0,5,log=False) #浮点型
    
    #定义评估器
    #需要优化的参数由上述参数空间决定
    #不需要优化的参数则直接填写具体值
    reg = RFR(n_estimators = n_estimators
              ,max_depth = max_depth
              ,max_features = max_features
              ,min_impurity_decrease = min_impurity_decrease
              ,random_state=1412
              ,verbose=False
              ,n_jobs=-1
             )
    
    #交叉验证过程,输出负均方根误差(-RMSE)
    #optuna同时支持最大化和最小化,因此如果输出-RMSE,则选择最大化
    #如果选择输出RMSE,则选择最小化
    cv = KFold(n_splits=5,shuffle=True,random_state=1412)
    validation_loss = cross_validate(reg,X,y
                                     ,scoring="neg_root_mean_squared_error"
                                     ,cv=cv #交叉验证模式
                                     ,verbose=False #是否打印进程
                                     ,n_jobs=-1 #线程数
                                     ,error_score='raise'
                                    )
    #最终输出RMSE
    return np.mean(abs(validation_loss["test_score"]))

2 定义优化目标函数的具体流程

在HyperOpt中,我们可以通过调整参数algo来自定义执行贝叶斯优化的具体算法,而在Optuna中也可以实现相同的操作。大部分备选的算法都集中在Optuna的模块sampler中,包括我们熟悉的TPE优化、随机网格搜索以及其他各类更加高级的贝叶斯过程。对于Optuna.sampler中调用的类,我们可以直接输入参数来设置初始观测值的数量,以及每次计算采集函数时所考虑的观测值量。在Optuna库中并没有集成实现高斯过程的方法,但我们可以从scikit-optimize中导入高斯过程来作为Optuna中的algo设置,而具体的高斯过程相关的参数则可以通过以下方法进行设置:

def optimizer_optuna(n_trials, algo):
    
    #定义使用TPE或者GP
    if algo == "TPE":
        algo = optuna.samplers.TPESampler(n_startup_trials = 10, n_ei_candidates = 24)
    elif algo == "GP":
        from optuna.integration import SkoptSampler
        import skopt
        algo = SkoptSampler(skopt_kwargs={'base_estimator':'GP', #选择高斯过程
                                          'n_initial_points':10, #初始观测点10个
                                          'acq_func':'EI'} #选择的采集函数为EI,期望增量
                           )
    
    #实际优化过程,首先实例化优化器
    study = optuna.create_study(sampler = algo #要使用的具体算法
                                , direction="minimize" #优化的方向,可以填写minimize或maximize
                               )
    #开始优化,n_trials为允许的最大迭代次数
    #由于参数空间已经在目标函数中定义好,因此不需要输入参数空间
    study.optimize(optuna_objective #目标函数
                   , n_trials=n_trials #最大迭代次数(包括最初的观测值的)
                   , show_progress_bar=True #要不要展示进度条呀?
                  )
    
    #可直接从优化好的对象study中调用优化的结果
    #打印最佳参数与最佳损失值
    print("\n","\n","best params: ", study.best_trial.params,
          "\n","\n","best score: ", study.best_trial.values,
          "\n")
    
    return study.best_trial.params, study.best_trial.values

3 执行实际优化流程

Optuna库虽然是当今最为成熟的HPO方法之一,但当参数空间较小时,Optuna库在迭代中容易出现抽样BUG,即Optuna会持续抽到曾经被抽到过的参数组合,并且持续报警告说"算法已在这个参数组合上检验过目标函数了"。在实际迭代过程中,一旦出现这个Bug,那当下的迭代就无用了,因为已经检验过的观测值不会对优化有任何的帮助,因此对损失的优化将会停止。如果出现该BUG,则可以增大参数空间的范围或密度。或者使用如下的代码令警告关闭:

import warnings
warnings.filterwarnings('ignore', message='The objective has been evaluated at this point before.')
best_params, best_score = optimizer_optuna(10,"GP") #默认打印迭代过程
optuna.logging.set_verbosity(optuna.logging.ERROR) #关闭自动打印的info,只显示进度条
#optuna.logging.set_verbosity(optuna.logging.INFO)
best_params, best_score = optimizer_optuna(300,"TPE")

最后总结下HPO库

HPO库优劣评价推荐指数
bayes_opt✅实现基于高斯过程的贝叶斯优化
✅当参数空间由大量连续型参数构成时

⛔包含大量离散型参数时避免使用
⛔算力/时间稀缺时避免使用
⭐⭐
hyperopt✅实现基于TPE的贝叶斯优化
✅支持各类提效工具
✅进度条清晰,展示美观,较少怪异警告或报错
✅可推广/拓展至深度学习领域

⛔不支持基于高斯过程的贝叶斯优化
⛔代码限制多、较为复杂,灵活性较差
⭐⭐⭐⭐
optuna✅(可能需结合其他库)实现基于各类算法的贝叶斯优化
✅代码最简洁,同时具备一定的灵活性
✅可推广/拓展至深度学习领域

⛔非关键性功能维护不佳,有怪异警告与报错
⭐⭐⭐⭐
  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个基于高斯过程的贝叶斯优化的Python代码示例: ``` import numpy as np from scipy.stats import norm from sklearn.gaussian_process import GaussianProcessRegressor from sklearn.gaussian_process.kernels import ConstantKernel, Matern # 定义目标函数 def target_function(x): return np.sin(3*x) + x**2 - 0.7*x # 定义贝叶斯优化函数 def bayesian_optimization(n_iters, sample_loss, bounds): # 定义高斯过程回归模型 kernel = ConstantKernel(1.0) * Matern(length_scale=1.0, nu=2.5) gp = GaussianProcessRegressor(kernel=kernel, alpha=1e-6) # 初始化参数和损失列表 x_list = [] y_list = [] # 迭代优化 for i in range(n_iters): # 根据高斯过程模型和边界值抽样生成一个候选点 x = np.random.uniform(bounds[:, 0], bounds[:, 1], size=(1, bounds.shape[0])) # 计算候选点的目标函数值 y = sample_loss(x) # 更新参数和损失列表 x_list.append(x) y_list.append(y) # 在更新高斯过程回归模型 X = np.concatenate(x_list, axis=0) Y = np.concatenate(y_list, axis=0) gp.fit(X, Y) # 返回参数和损失列表中的最优值 best_idx = np.argmax(y_list) return x_list[best_idx], y_list[best_idx] # 定义损失函数为目标函数的负值 def sample_loss(x): return -target_function(x) # 定义参数边界值 bounds = np.array([[-1.0, 2.0]]) # 进行贝叶斯优化 x_best, y_best = bayesian_optimization(n_iters=20, sample_loss=sample_loss, bounds=bounds) # 输出最优解和目标函数值 print("最优解:", x_best) print("目标函数值:", -y_best) ``` 在上面的代码中,我们首先定义了一个目标函数 `target_function`,这个函数是我们要优化的函数。然后我们定义了 `bayesian_optimization` 函数,这个函数使用高斯过程回归模型进行贝叶斯优化,其中参数 `n_iters` 是迭代次数,`sample_loss` 是损失函数,`bounds` 是参数的边界值。在 `bayesian_optimization` 函数中,我们使用高斯过程回归模型和边界值抽样生成一个候选点,然后计算其目标函数值,最后更新高斯过程回归模型。在迭代结束后,我们返回参数和损失列表中的最优值。 接下来我们定义了损失函数 `sample_loss`,这个函数是目标函数的负值,因为我们要最小化目标函数。最后我们定义了参数的边界值 `bounds`,这个例子中我们只有一个参数,所以是一个二维数组。 最后我们调用 `bayesian_optimization` 函数进行贝叶斯优化,然后输出最优解和目标函数值。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值