Optuna是一个自动超参数优化软件框架,专为机器学习而设计。它具有命令式、 运行时定义的用户 API。Optuna的用户可以动态地构建超参数的搜索空间。
optuna API

Xgboost、CatBoost 和 Lightgbm 与 Optuna……测试
建模是预测中最重要的部分之一。你应该找到最好的机器学习模型以获得更好的结果。在第 1 部分中,我们从事 EDA 和特征工程。你可以在这里看到这篇文章。

在本文的这一部分,我们比较了 Xgboost、Catboost 和 LGBM 三种机器学习模型。竞争指标是接收器操作特征曲线下的面积 (ROC AUC)。

您可以在此处查看数据集,也可以在文末查看完整的 Python 代码。
介绍
首先我们导入库,然后计算这些机器学习模型的基线分数。

from xgboost import XGBClassifier
from lightgbm import LGBMClassifier
from catboost import CatBoostClassifier
from sklearn.metrics import roc_auc_score
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import StratifiedKFold
import optuna
from optuna.visualization import plot_optimization_history
from optuna.visualization import plot_param_importances
# XGBClassifier
xgbc_model = XGBClassifier(min_child_weight=0.1, reg_lambda=100, booster='gbtree', objective='binary:logitraw', random_state=42)
xgbc_score = cross_val_score(xgbc_model, train_X, train_y, scoring='roc_auc', cv=5)
print('xgbc_score: ', xgbc_score.mean())

# LGBMClassifier
ligthgbmc_model = LGBMClassifier(boosting_type='gbdt', objective='binary', random_state=42)
ligthgbmc_score = cross_val_score(ligthgbmc_model, train_X, train_y, scoring='roc_auc', cv=5)
print('ligthgbmc_score: ', ligthgbmc_score.mean())

# CatBoostClassifier
cbc_model = CatBoostClassifier(loss_function='Logloss', random_state=42, verbose=False)
cbc_score = cross_val_score(cbc_model, train_X, train_y, scoring='roc_auc', cv=5)
print('cbc_score: ', cbc_score.mean())
####################################################################
Outputs:
xgbc_score:  0.8898202612356174
ligthgbmc_score:  0.8879385374274603
cbc_score:  0.8909648517647316

Xgboost + Optuna
根据基线得分,最好的模型是catboost,但可以在超参数调整后更改。您可以在下面看到XGB在Optuna中的用法。

def objective(trial, data=X, target=y):
    X_train, X_val, y_train, y_val = train_test_split(data, target, test_size=0.2, random_state=42)

    params = {
        'max_depth': trial.suggest_int('max_depth', 3, 32),
        'learning_rate': trial.suggest_categorical('learning_rate', [0.005, 0.02, 0.05, 0.08, 0.1]),
        'n_estimators': trial.suggest_int('n_estimators', 2000, 8000),
        'min_child_weight': trial.suggest_int('min_child_weight', 1, 300),
        'gamma': trial.suggest_float('gamma', 0.0001, 1.0, log = True),
        'alpha': trial.suggest_float('alpha', 0.0001, 10.0, log = True),
        'lambda': trial.suggest_float('lambda', 0.0001, 10.0, log = True),
        'colsample_bytree': trial.suggest_float('colsample_bytree', 0.1, 0.8),
        'subsample': trial.suggest_float('subsample', 0.1, 0.8),
        'tree_method': 'gpu_hist',
        'booster': 'gbtree',
        'random_state': 42,
        'use_label_encoder': False,
        'eval_metric': 'auc'

    }
    
    model = XGBClassifier(**params)  
    model.fit(X_train, y_train, eval_set = [(X_val,y_val)], early_stopping_rounds = 333, verbose = False)
    y_pred = model.predict_proba(X_val)[:,1]
    roc_auc = roc_auc_score(y_val, y_pred)

    return roc_auc
study = optuna.create_study(direction='maximize')
study.optimize(objective, n_trials=50)
print('Best value: ', study.best_value)
####################################################################
Outputs:
Best value: 0.8951492161710065

CatBoost + Optuna

def objective(trial, data=X, target=y):
    X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=42)

    params = {
        'max_depth': trial.suggest_int('max_depth', 3, 64),
        'learning_rate': trial.suggest_categorical('learning_rate', [0.005, 0.02, 0.05, 0.08, 0.1]),
        'n_estimators': trial.suggest_int('n_estimators', 2000, 8000),
        'max_bin': trial.suggest_int('max_bin', 200, 400),
        'min_data_in_leaf': trial.suggest_int('min_data_in_leaf', 1, 300),
        'l2_leaf_reg': trial.suggest_float('l2_leaf_reg', 0.0001, 1.0, log = True),
        'subsample': trial.suggest_float('subsample', 0.1, 0.8),
        'random_seed': 42,
        'task_type': 'GPU',
        'loss_function': 'Logloss',
        'eval_metric': 'AUC',
        'bootstrap_type': 'Poisson'
    }
    
    model = CatBoostClassifier(**params)  
    model.fit(X_train, y_train, eval_set = [(X_val,y_val)], early_stopping_rounds = 222, verbose = False)
    y_pred = model.predict_proba(X_val)[:,1]
    roc_auc = roc_auc_score(y_val, y_pred)

    return roc_auc
study = optuna.create_study(direction = 'maximize')
study.optimize(objective, n_trials = 50)
print('Best value:', study.best_value)
####################################################################
Outputs:
Best value: 0.8925910141177894

LGBM + Optuna
经过超参数优化,可以看出LGBM是目前最好的模型。

def objective(trial,data=X,target=y):   
    train_x, test_x, train_y, test_y = train_test_split(data, target, test_size=0.15,random_state=42)
    params = {
        'reg_alpha': trial.suggest_float('reg_alpha', 0.001, 10.0),
        'reg_lambda': trial.suggest_float('reg_lambda', 0.001, 10.0),
        'num_leaves': trial.suggest_int('num_leaves', 11, 333),
        'min_child_samples': trial.suggest_int('min_child_samples', 5, 100),
        'max_depth': trial.suggest_int('max_depth', 5, 64),
        'learning_rate': trial.suggest_categorical('learning_rate', [0.01, 0.02, 0.05, 0.005, 0.1]),
        'colsample_bytree': trial.suggest_float('colsample_bytree', 0.1, 0.5),
        'n_estimators': trial.suggest_int('n_estimators', 2000, 8000),
        'cat_smooth' : trial.suggest_int('cat_smooth', 10, 100),
        'cat_l2': trial.suggest_int('cat_l2', 1, 20),
        'min_data_per_group': trial.suggest_int('min_data_per_group', 50, 200),
        'cat_feature' : [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, 66, 67],
        'n_jobs' : -1, 
        'random_state': 42,
        'boosting_type': 'gbdt',
        'metric': 'AUC',
        'device': 'gpu'
    }
    model = LGBMClassifier(**params)  
    model.fit(train_x,train_y,eval_set=[(test_x,test_y)],eval_metric='auc', early_stopping_rounds=300, verbose=False)
    preds = model.predict_proba(test_x)[:,1]
    auc = roc_auc_score(test_y, preds)
    
    return auc
study = optuna.create_study(direction='maximize')
study.optimize(objective, n_trials=50)
####################################################################
Outputs:
Best value:  0.8966645758299353

可视化效果

优化历史记录

# Historic
plot_optimization_history(study)

在这里插入图片描述

Hyperparameter Importances

# Importance
optuna.visualization.plot_param_importances(study)

在这里插入图片描述

使用optuna

Optuna 与几乎所有可用的机器学习框架一起使用:TensorFlow、PyTorch、LightGBM、XGBoost、CatBoost、sklearn、FastAI 等。

安装optuna
 pip install optuna

每个 Optuna 超参数调整会话称为学习。我们通过调用create_study方法来实例化一个学习会话。我们可以将几个重要的参数传递给这个方法,如下所示

import optuna
study = optuna.create_study(direction="maximize", sampler=optuna.samplers.TPESampler())

direction

direction value 可以设置为maximize或minimize,具体取决于我们的超参数调整的最终目标。

  • 如果目标是通过准确度、F1 分数、精确度或召回率等指标来提高性能,则将其设置为maximize.
  • 如果目标是减少损失函数,例如 log-loss、MSE、RMSE 等,则将其设置为minimize.
sampler

sampler value 指示您希望 Optuna 实施的采样器方法。您可以选择多个采样器选项,例如:

  • GridSampler:根据定义的搜索空间中的每个组合选择一组超参数值。
  • RandomSampler:从定义的搜索空间中随机选择一组超参数值。
  • TPESampler:这是sampler我们使用 Optuna
    时的默认设置。它基于贝叶斯超参数优化,这是一种有效的超参数调整方法。它将像随机采样器一样开始,但该采样器记录了一组超参数值的历史以及过去试验的相应目标值。然后,它将根据过去试验的有希望的目标值集为下一次试验建议一组超参数值。

接下来,我们可以调用optimize我们学习中的方法,并将我们的objective函数作为参数之一传递。

import optuna

study = optuna.create_study(direction="maximize", sampler=optuna.samplers.TPESampler())
study.optimize(objective, n_trials=30)

上面的n_trials参数表示您希望 Optuna 在研究中执行的试验次数。

到目前为止,我们还没有创建objective 函数。所以让我们objective首先定义搜索空间来创建我们的函数。

搜索空间定义

在每个超参数调整会话中,我们需要为采样器定义一个搜索空间。搜索空间是采样器应该从超参数中考虑的值的范围。
例如,假设我们要调整三个超参数:学习率、层的单元数和神经网络模型的优化器。然后,我们可以定义搜索空间如下:

def objective(trial):

    params = {
              'learning_rate': trial.suggest_loguniform('learning_rate', 1e-5, 1e-1),
              'optimizer': trial.suggest_categorical("optimizer", ["Adam", "RMSprop", "SGD"]),
              'n_unit': trial.suggest_int("n_unit", 4, 18)
              }
    
    model = build_model(params)
    
    accuracy = train_and_evaluate(params, model)

    return accuracy

在objective函数中,我们传递了一个名为 的参数trial,它来自TrialOptuna 的类。此类使 Optuna 能够记录一组选定的超参数值,并objective在每次试验中记录我们的函数值(在我们的例子中是准确性)

正如您在上面看到的,我们将每个超参数的搜索空间定义为一个名为 的字典params。对于每个超参数,我们用方法定义搜索空间的范围(最小值和最大值)suggest_*

suggest_*方法有几个扩展,具体取决于超参数的数据类型:

  • suggest_int:如果您的超参数接受一系列整数类型的数值。
  • suggest_categorical:如果您的超参数接受分类值的选择。
  • suggest_uniform:如果您的超参数接受一系列数值,并且您希望对每个值进行同样的采样。
  • suggest_loguniform:如果您的超参数接受一系列数值,并且您希望在对数域中对每个值进行同样的采样。
  • suggest_discrete_uniform:如果您的超参数接受特定区间内的一系列数值,并且您希望每个值都以同样的可能性进行采样。
  • suggest_float:如果您的超参数接受一系列浮点类型的数值。这是 , 和
    的suggest_uniform包装suggest_loguniform方法suggest_discrete_uniform
构建 PyTorch 模型、训练循环和评估目标函数

现在我们可以使用保存在params字典中的选定超参数值来构建 PyTorch 模型。接下来,我们将训练模型并评估我们的目标函数,在我们的例子中是准确度。

import optuna
import torch
import torch.nn as nn
import torch.optim as optim
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split


def build_model(params):
    
    in_features = 20
    
    return nn.Sequential(
    
        nn.Linear(in_features, params['n_unit']),
        nn.LeakyReLU(),
        nn.Linear(params['n_unit'], 2),
        nn.LeakyReLU()
        
    )
 
 

def train_and_evaluate(param, model):
    
    df = pd.read_csv('heart.csv')
    df = pd.get_dummies(df)
    
    train_data, val_data = train_test_split(df, test_size = 0.2, random_state = 42)
    train, val = Dataset(train_data), Dataset(val_data)

    train_dataloader = torch.utils.data.DataLoader(train, batch_size=2, shuffle=True)
    val_dataloader = torch.utils.data.DataLoader(val, batch_size=2)

    use_cuda = torch.cuda.is_available()
    device = torch.device("cuda" if use_cuda else "cpu")

    criterion = nn.CrossEntropyLoss()
    optimizer = getattr(optim, param['optimizer'])(model.parameters(), lr= param['learning_rate'])

    if use_cuda:

            model = model.cuda()
            criterion = criterion.cuda()

    for epoch_num in range(EPOCHS):

            total_acc_train = 0
            total_loss_train = 0

            for train_input, train_label in train_dataloader:

                train_label = train_label.to(device)
                train_input = train_input.to(device)

                output = model(train_input.float())
                
                batch_loss = criterion(output, train_label.long())
                total_loss_train += batch_loss.item()
                
                acc = (output.argmax(dim=1) == train_label).sum().item()
                total_acc_train += acc

                model.zero_grad()
                batch_loss.backward()
                optimizer.step()
            
            total_acc_val = 0
            total_loss_val = 0

            with torch.no_grad():

                for val_input, val_label in val_dataloader:

                    val_label = val_label.to(device)
                    val_input = val_input.to(device)

                    output = model(val_input.float())

                    batch_loss = criterion(output, val_label.long())
                    total_loss_val += batch_loss.item()
                    
                    acc = (output.argmax(dim=1) == val_label).sum().item()
                    total_acc_val += acc
            
            accuracy = total_acc_val/len(val_data)

    return accuracy
  
 
def objective(trial):

     params = {
              'learning_rate': trial.suggest_loguniform('learning_rate', 1e-5, 1e-1),
              'optimizer': trial.suggest_categorical("optimizer", ["Adam", "RMSprop", "SGD"]),
              'n_unit': trial.suggest_int("n_unit", 4, 18)
              }
    
     model = build_model(params)
    
     accuracy = train_and_evaluate(params, model)

     return accuracy

运行超参数调优

我们已经创建了目标函数,我们已经定义了搜索空间,我们已经构建了模型和训练循环,现在我们准备好使用 Optuna 运行超参数调整。
要运行超参数调整,我们需要实例化一个study会话,调用optimize方法,并将我们的objective函数作为参数传递。

超参数调整过程完成后,我们可以通过访问best_trial方法来获取超参数的最佳组合,如下所示:

EPOCHS = 100
    
study = optuna.create_study(direction="maximize", sampler=optuna.samplers.TPESampler())
study.optimize(objective, n_trials=100)

best_trial = study.best_trial

for key, value in best_trial.params.items():
print(“{}: {}”.format(key, value))


以下是某项目的调参案例展示  
![在这里插入图片描述](https://img-blog.csdnimg.cn/9226acd2bf454584adc0d73da16b3d74.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBASmFtZXNfQm9ibw==,size_20,color_FFFFFF,t_70,g_se,x_16)

optuna可视化
---------

Optuna 提供了一项功能,使我们能够在完成后可视化调整过程的历史。我们现在将介绍其中的一些。  
第一个可视化是每个训练步骤中每个试验的目标函数图(在我们的例子中是准确性)。

optuna.visualization.plot_intermediate_values(study)


还可以将优化历史可视化:这种可视化有助于查看哪个试验是最佳试验,以及其他试验的客观价值与最佳试验相比如何。由于修剪机制,在特定试验中缺少几个数据点。

optuna.visualization.plot_optimization_history(study)


Optuna 还使我们能够绘制超参数的重要性,如下所示:

optuna.visualization.plot_param_importances(study)


![在这里插入图片描述](https://img-blog.csdnimg.cn/92c689c0a45c48c8a86561aab884ecab.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBASmFtZXNfQm9ibw==,size_20,color_FFFFFF,t_70,g_se,x_16)

optuna dashboard可视化
-------------------

conda install -c conda-forge optuna-dashboard
pip install optuna-dashboard

study = optuna.create_study(study_name='test',direction="maximize",storage='sqlite:///db.sqlite3') 

```

定义完后创建会话时,study\_name指定了你的会话名称,direction为maximize或者minimize,最大或者最小,默认是最小,这里我们要让精确度最大,所以用maximize,storage定义了你的存储方式,这里我们用sqlite3,也可以用mysql等。

以上日志默认的保存位置在你当前的工作目录,会生成一个db.sqlite3的文件  
![在这里插入图片描述](https://img-blog.csdnimg.cn/d9e62be466af4890a7cee6b2a414e703.png)  
再打开命令行或者anaconda-prompt,输入以下命令启动dashboard:

```
optuna-dashboard sqlite:///db.sqlite3 


```

复制127.0.0.1:8080到你的浏览器里打开,就可以看到你的dashboard和study了:

如果指定服务器IP地址可使用

```
optuna-dashboard sqlite:///db.sqlite3 --host 0.0.0.0

```

复制IP:8080到你的浏览器里打开,同样可以看到你的dashboard和study  
![在这里插入图片描述](https://img-blog.csdnimg.cn/b00f2007423047b7a0e7ea792f1edd53.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBASmFtZXNfQm9ibw==,size_20,color_FFFFFF,t_70,g_se,x_16)  
![在这里插入图片描述](https://img-blog.csdnimg.cn/a4ee8fce9c274dff9e041126c4fe8832.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBASmFtZXNfQm9ibw==,size_20,color_FFFFFF,t_70,g_se,x_16)  
![在这里插入图片描述](https://img-blog.csdnimg.cn/d894ff79ab514792b33d111483b78c8b.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBASmFtZXNfQm9ibw==,size_20,color_FFFFFF,t_70,g_se,x_16)  
![在这里插入图片描述](https://img-blog.csdnimg.cn/aef7071341b743bba575ecf66529c566.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBASmFtZXNfQm9ibw==,size_20,color_FFFFFF,t_70,g_se,x_16)  
![在这里插入图片描述](https://img-blog.csdnimg.cn/b36d63f77cc04b8a8e1c3c1a526b1e71.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBASmFtZXNfQm9ibw==,size_20,color_FFFFFF,t_70,g_se,x_16)
References:
[1]: https://www.kaggle.com/hasanbasriakcay/xgb-catboost-lgbm-optuna-lb-14/notebook
[2]: https://www.kaggle.com/c/tabular-playground-series-mar-2021/data
[3]: https://optuna.readthedocs.io/en/stable/reference/study.html
[4]: https://xgboost.readthedocs.io/en/stable/
[5]: https://catboost.ai/en/docs/
[6]: https://lightgbm.readthedocs.io/en/latest/:https://blog.csdn.net/weixin_42788078/article/details/122984184
[7]https://blog.csdn.net/weixin_42788078/article/details/122984184

[video(video-mWcRt5ep-1654994593942)(type-bilibili)(url-https://player.bilibili.com/player.html?aid=683702670)(image-https://img-blog.csdnimg.cn/img_convert/8648215eb181ee950946f2a4e1f7e900.png)(title-论文复现机器学习模型案例大本营(收藏))]

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐