使用Optuna进行模型的自动调参

在做机器学习作业的时候苦于手动调参(甚至一度想自己简单写个函数自动调参,不过想来python库中肯定有相关函数,便有了这篇文章)在文章的结尾,我会以李宏毅机器学习hw01为例子介绍怎么插入这段代码
关于课程说句题外话,2023 更多的是讲一些前沿的东西,基础性课程还是用的过去的影像,所以你如果觉得 2023 课程进度慢(因为刚开始)可以看 2022 的
李宏毅2023春机器学习课程
李宏毅2021/2022春机器学习课程
Study — Optuna 1.4.0 文档

假设你已经编写好了你的 model classtrainer() ,其中trainer() 返回的值是模型在验证集上的 performance

如果满足上述条件,你可以直接替换掉代码中 YourModelClass()trainer() 函数,然后修改 hyperparameters 字典中的参数来进行调优。

注意,需要根据目标函数修改 direction ,根据需要修改 n_trials ,然后,将所有需要调参的函数调用塞入 objective()

import optuna

def objective(trial):
    # 定义需要调优的超参数空间
    hyperparameters = {
        'learning_rate': trial.suggest_loguniform('lr', 1e-5, 1e-1),
        'batch_size': trial.suggest_categorical('batch_size', [16, 32, 64]),
    }
    
    # 调用trainer函数进行训练并返回验证集上的 performance
    model = YourModelClass()
    performance = trainer(model, hyperparameters)
    
    # 简单来说,只要你的 trainer() 接收 hyperparameters 并返回 performance,就能成功运行
    return performance

# 使用Optuna库进行超参数搜索
study = optuna.create_study(direction='maximize') # 根据目标函数来决定是'minimize'还是'maximize'
study.optimize(objective, n_trials=100) # n_trials 指的是试验次数

# 输出最优的超参数组合和性能指标
print('Best hyperparameters: {}'.format(study.best_params))
print('Best performance: {:.4f}'.format(study.best_value))

举例说明

写在前面:如果你还没有手动调参过,那么我建议你先去试试,而不是将调参这件事提前当作黑箱进行理解
这里有一份不错的文档:Deep Learning Tuning Playbook,或许能给你提供帮助
下面的例子来源于李宏毅机器学习课程的homework01,完整代码在colab上:Code
如果你并不需要做这份作业,就不用花费时间去查看,因为我并没有将例子缩减到容易理解的地步 😃

这是课程助教写的一个 simple baseline 的代码样例,我删去了一些不重要的东西

class My_Model(nn.Module):
    def __init__(self, input_dim):
        super(My_Model, self).__init__()
        self.layers = nn.Sequential(
            nn.Linear(input_dim, 16),
            nn.ReLU(),
            nn.Linear(16, 8),
            nn.ReLU(),
            nn.Linear(8, 1)
        )

    def forward(self, x):
        x = self.layers(x)
        x = x.squeeze(1) # (B, 1) -> (B)
        return x

# Feature Selection
def select_feat(train_data, valid_data, test_data, select_all=True):
    '''Selects useful features to perform regression'''
    y_train, y_valid = train_data[:,-1], valid_data[:,-1]
    raw_x_train, raw_x_valid, raw_x_test = train_data[:,:-1], valid_data[:,:-1], test_data

    if select_all:
        feat_idx = list(range(raw_x_train.shape[1]))
    else:
        feat_idx = [0,1,2,3,4]
        
    return raw_x_train[:,feat_idx], raw_x_valid[:,feat_idx], raw_x_test[:,feat_idx], y_train, y_valid

def trainer(train_loader, valid_loader, model, config, device):

    criterion = nn.MSELoss(reduction='mean')

    optimizer = torch.optim.SGD(model.parameters(), lr=config['learning_rate']) 

    n_epochs, best_loss, step, early_stop_count = 5000, math.inf, 0, 0

    for epoch in range(n_epochs):
        model.train() # Set your model to train mode.
        loss_record = []

        for x, y in train_loader:
            optimizer.zero_grad()               # Set gradient to zero.
            x, y = x.to(device), y.to(device)   # Move your data to device. 
            pred = model(x)             
            loss = criterion(pred, y)
            loss.backward()                     # Compute gradient(backpropagation).
            optimizer.step()                    # Update parameters.
            step += 1
            loss_record.append(loss.detach().item())

        mean_train_loss = sum(loss_record)/len(loss_record)

        model.eval() # Set your model to evaluation mode.
        loss_record = []
        for x, y in valid_loader:
            x, y = x.to(device), y.to(device)
            with torch.no_grad():
                pred = model(x)
                loss = criterion(pred, y)

            loss_record.append(loss.item())
            
        mean_valid_loss = sum(loss_record)/len(loss_record)

        if mean_valid_loss < best_loss:
            best_loss = mean_valid_loss
            early_stop_count = 0
        else: 
            early_stop_count += 1

        if early_stop_count >= 400:
            print('\nModel is not improving, so we halt the training session.')
            return best_loss # 源代码是不返回loss的,这里加上用来自动调参

# 处理数据
train_data, test_data = pd.read_csv('./covid_train.csv').values, pd.read_csv('./covid_test.csv').values
train_data, valid_data = train_valid_split(train_data, 0.2, 5201314)

# Select features
x_train, x_valid, x_test, y_train, y_valid = select_feat(train_data, valid_data, test_data, True)

train_dataset, valid_dataset, test_dataset = COVID19Dataset(x_train, y_train), \
                                            COVID19Dataset(x_valid, y_valid), \
                                            COVID19Dataset(x_test)

# Pytorch data loader loads pytorch dataset into batches.
train_loader = DataLoader(train_dataset, batch_size=config['batch_size'], shuffle=True, pin_memory=True)
valid_loader = DataLoader(valid_dataset, batch_size=config['batch_size'], shuffle=True, pin_memory=True)
test_loader = DataLoader(test_dataset, batch_size=config['batch_size'], shuffle=False, pin_memory=True)
	
model = My_Model(input_dim=x_train.shape[1]).to(device) # put your model and data on the same computation device.
trainer(train_loader, valid_loader, model, config, device)

现在有了我们自己的 model classtrainer(),就可以直接代入上面的代码了,

import optuna

def objective(trial):
    # 定义需要调优的超参数空间
    config = {
        'learning_rate': trial.suggest_loguniform('lr', 1e-5, 1e-1),
        'batch_size': trial.suggest_categorical('batch_size', [16, 32, 64]),
    }
    
    # 处理数据
    train_data, test_data = pd.read_csv('./covid_train.csv').values, pd.read_csv('./covid_test.csv').values
	train_data, valid_data = train_valid_split(train_data, 0.2, 5201314)
	
	# Feature Selection
	x_train, x_valid, x_test, y_train, y_valid = select_feat(train_data, valid_data, test_data, True)
	
	train_dataset, valid_dataset, test_dataset = COVID19Dataset(x_train, y_train), \
	                                            COVID19Dataset(x_valid, y_valid), \
	                                            COVID19Dataset(x_test)
	
	# Pytorch data loader loads pytorch dataset into batches.
	train_loader = DataLoader(train_dataset, batch_size=config['batch_size'], shuffle=True, pin_memory=True)
	valid_loader = DataLoader(valid_dataset, batch_size=config['batch_size'], shuffle=True, pin_memory=True)
	test_loader = DataLoader(test_dataset, batch_size=config['batch_size'], shuffle=False, pin_memory=True)
	
    # 调用 trainer() 进行训练并返回验证集上的 performance
    model = My_Model(input_dim=x_train.shape[1]).to(device) 
	performance = trainer(train_loader, valid_loader, model, config, device)
    
    # 简单来说,只要你的 trainer() 接收 config 并返回 performance,就能成功运行
    return performance

# 使用Optuna库进行超参数搜索
study = optuna.create_study(direction='minimize')
study.optimize(objective, n_trials=100)

# 输出最优的超参数组合和性能指标
print('Best hyperparameters: {}'.format(study.best_params))
print('Best performance: {:.4f}'.format(study.best_value))
  • 6
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
多粒度粒球计算模型调参是一个重要的步骤,可以帮助优化模型性能。虽然有些模型可能具有内置的自动调参方法,但通常还是需要手动调整一些超参数来实现更好的性能。 多粒度粒球计算模型通常具有多个超参数,如粒子数量、粒子半径、计算步长等。这些超参数的选择会对模型的性能产生重要影响。以下是一些可能需要调整的超参数和调参方法: 1. 粒子数量:模型中的粒子数量决定了模型的复杂度和计算开销。较大的粒子数量可以提供更准确的模拟结果,但也会增加计算开销。可以根据问题的复杂度和计算资源来选择合适的粒子数量。 2. 粒子半径:粒子半径决定了相互作用范围,影响模型对局部和全局结构的建模能力。较小的粒子半径可以捕捉更细致的结构,但也可能导致计算不稳定。较大的粒子半径则可能丢失一些局部细节。可以通过尝试不同的粒子半径来平衡局部和全局结构的建模。 3. 计算步长:计算步长决定了模拟的时间间隔。较小的计算步长可以提供更准确的模拟结果,但也会增加计算开销。可以根据问题的时间尺度和计算资源来选择合适的计算步长。 4. 其他超参数:根据具体的多粒度粒球计算模型,可能还有其他需要调节的超参数,如模型的层数、每层的神经元数量、学习率等。可以通过交叉验证、网格搜索等方法来寻找最佳的超参数组合。 对于调参方法,可以尝试使用传统的网格搜索、随机搜索或贝叶斯优化等方法来搜索超参数空间。此外,还可以使用自动机器学习(AutoML)工具,如AutoGluon、Optuna等,来自动调参过程。这些工具可以帮助自动搜索超参数并优化模型性能。 需要注意的是,调参是一个迭代的过程,需要根据实际情况进行多次实验和评估。同时,为了避免过拟合,建议在训练集和验证集上进行调参,并在测试集上进行最终性能评估。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hoper.J

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值