服务咨询热线0898-88889999
网站首页 关于杏耀 杏耀中心 杏耀动态 杏耀登录 杏耀注册 杏耀平台 杏耀开户 联系我们
咨询热线
0898-88889999
地址:海南省海口市
邮箱:admin@youweb.com

杏耀动态

当前位置: 首页 > 杏耀动态

用Optuna进行Pytorch超参数调优教程

发布时间:2024-06-10 05:14:48 点击量:

使用Pytorch构建深度学习模型的一系列指南中的第四篇来啦!Optuna作为主要面向深度学习超参数调优开发的框架,在实现之初就考虑到了大型模型参数调优的各种实际情况,并逐一针对它们设计了解决方案。今天学姐就带大家学习如何使用Optuna进行Pytorch超参数调优。

前三篇传送门:

1.Pytorch初学者教程

2.了解深度学习模型中的张量维度

3.CNN和特征可视化

Optuna是一个自动超参数搜索的超参数优化框架,可应用于机器学习和深度学习模型;Optuna使用了采样和剪枝算法来优化超参数,所以非常快速和高效;它还可以通过直观的方式动态构建超参数搜索空间。

本篇文章的重点是结合Pytorch和Optuna,在MNIST数据集上找到性能最佳的CNN模型。我将逐步展示应用Optuna所需的函数和要调整的超参数。


先安装Optuna库


!pip install optuna


之后导入库和数据集


import matplotlib.pyplot as plt
import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import random_split
from torch.nn import functional as F
import torchvision
from torchvision import datasets,transforms
import torchvision.transforms as transforms
import optunaimport os
DEVICE=torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
CLASSES=10
DIR=os.getcwd()
EPOCHS=10
train_dataset=torchvision.datasets.MNIST('classifier_data', train=True, download=True)
m=len(train_dataset)transform=torchvision.transforms.Compose([    torchvision.transforms.ToTensor()])
train_dataset.transform=transform


接着将卷积神经网络一起定义到要调整的超参数

class ConvNet(nn.Module):
  def __init__(self, trial):
    # We optimize dropout rate in a convolutional neural network.
    super(ConvNet, self).__init__()
    self.conv1=nn.Conv2d(in_channels=1, out_channels=16, kernel_size=5, stride=1, padding=2)
    self.conv2=nn.Conv2d(in_channels=16, out_channels=32, kernel_size=5, stride=1, padding=2)
    dropout_rate=trial.suggest_float("dropout_rate", 0, 0.5,step=0.1)
    self.drop1=nn.Dropout2d(p=dropout_rate)
    fc2_input_dim=trial.suggest_int("fc2_input_dim", 32, 128,32)
    self.fc1=nn.Linear(32 * 7 * 7, fc2_input_dim)
    dropout_rate2=trial.suggest_float("dropout_rate2", 0, 0.3,step=0.1)
    self.drop2=nn.Dropout2d(p=dropout_rate2)
    self.fc2=nn.Linear(fc2_input_dim, 10)
    def forward(self, x):
      x=F.relu(F.max_pool2d(self.conv1(x),kernel_size=2))
      x=F.relu(F.max_pool2d(self.conv2(x),kernel_size=2))
      x=self.drop1(x)
      x=x.view(x.size(0),-1)
      x=F.relu(self.fc1(x))
      x=self.drop2(x)
      x=self.fc2(x)
      return x


在Optuna中,目标是最小化/最大化目标函数,它将一组超参数作为输入并返回验证分数。对于每个超参数,需要考虑不同范围的值。

优化的过程称为研究,而对目标函数的每次评估称为试验。“Suggest API”在模型架构内被调用,为每个试验动态生成超参数。

可以定义超参数范围的函数:

  • suggest_int 建议为第二完全连接层的输入单元设置整数值
  • suggest_float 建议dropout率的浮点值,在第二个卷积层(0-0.5,步长为0.1)和第一个线性层(0-0.3,步长为0.1)之后作为超参数引入。
  • suggest_categorical 建议优化器的分类值,稍后将显示

更多资料:

optuna.readthedocs.io/e


定义了一个函数来尝试训练集中batch_size的不同值。它将训练数据集和批大小作为输入(稍后将在目标函数中定义),并返回训练和验证加载器对象。


def get_mnist(train_dataset,batch_size):
  train_data, val_data=random_split(train_dataset,[int(m-m*0.2), int(m*0.2)])
  # The dataloaders handle shuffling, batching, etc...
  train_loader=torch.utils.data.DataLoader(train_data, batch_size=batch_size)
  valid_loader=torch.utils.data.DataLoader(val_data, batch_size=batch_size)
  return train_loader, valid_loader


最重要的一步是定义目标函数,它使用采样程序来选择每次试验中的超参数值,并返回在该试验中获得的验证准确度。


def objective(trial):
  # Generate the model.
  model=ConvNet(trial).to(DEVICE)
  # Generate the optimizers.
  # try RMSprop and SGD   
  '''
  optimizer_name=trial.suggest_categorical("optimizer",["RMSprop", "SGD"])
  momentum=trial.suggest_float("momentum", 0.0, 1.0)
  lr=trial.suggest_float("lr", 1e-5, 1e-1, log=True)
  optimizer=getattr(optim, optimizer_name)
  (model.parameters(), lr=lr,momentum=momentum)
  '''
  #try Adam, AdaDelta adn Adagrad
  optimizer_name=trial.suggest_categorical("optimizer",["Adam", "Adadelta","Adagrad"])
  lr=trial.suggest_float("lr", 1e-5, 1e-1,log=True)
  optimizer=getattr(optim, optimizer_name)
  (model.parameters(), lr=lr)
  batch_size=trial.suggest_int("batch_size", 64, 256,step=64)
  criterion=nn.CrossEntropyLoss()
  # Get the MNIST imagesset.
  train_loader, valid_loader=get_mnist(train_dataset,batch_size)
  # Training of the model.
  for epoch in range(EPOCHS):
    model.train()
    for batch_idx, (images, labels) in enumerate(train_loader):
      # Limiting training images for faster epochs.
      #if batch_idx * BATCHSIZE >=N_TRAIN_EXAMPLES:
      #    break
      images, labels=images.to(DEVICE), labels.to(DEVICE)
      optimizer.zero_grad()
      output=model(images)
      loss=criterion(output, labels)
      loss.backward()
      optimizer.step()
      # Validation of the model.
      model.eval()
      correct=0
      with torch.no_grad():
        for batch_idx, (images, labels) in enumerate(valid_loader):
          # Limiting validation images.
          # if batch_idx * BATCHSIZE >=N_VALID_EXAMPLES:
          #    break
          images, labels=images.to(DEVICE), labels.to(DEVICE)
          output=model(images)
          # Get the index of the max log-probability.
          pred=output.argmax(dim=1, keepdim=True)
          correct +=pred.eq(labels.view_as(pred)).sum().item()
          accuracy=correct / len(valid_loader.dataset)
          trial.report(accuracy, epoch)
          # Handle pruning based on the intermediate value.
          if trial.should_prune():
            raise optuna.exceptions.TrialPruned()
            return accuracy


下面创建一个study对象来最大化目标函数,然后使用study.optimize(objective,n_trials=20)进行研究,将试验次数定为20次。可以根据问题的复杂程度对其进行更改

study=optuna.create_study(direction='maximize')
study.optimize(objective, n_trials=20)
trial=study.best_trialprint('Accuracy:{}'.format(trial.value))
print("Best hyperparameters:{}".format(trial.params))


为了更容易地可视化最近5次试验中选择的超参数,我们可以构建一个DataFrame对象:


df=study.trials_dataframe().drop(['state','datetime_start','datetime_complete','duration','number'], axis=1)
df.tail(5)



性能最好的模型在第 20 次试验中获得了 98.9% 的验证准确率。上面是该试验中选择的超参数值。


有许多有趣的可视化方法可以帮助查看优化的不同方面。我们可以看到目标值如何随着试验次数的增加而增加。


optuna.visualization.plot_optimization_history(study)




x轴是试验数据,y轴是客观值,对应于验证精度。仅通过20次试验,我们就可以看到我们获得了90%以上的高分。


我们还可以证明不同超参数之间的关系。在这种情况下,我们只关注批量大小和学习率:


optuna.visualization.plot_contour(study, params=['batch_size', 'lr'])



Contour Plot是一个3D图,其中第三维由目标值构成。从中心的集群(浅蓝色表示验证准确率非常高),我们可以观察到这些结果是在中等学习率(介于0.001和0.01之间)和低/中等批量大小下获得的。

使用平行坐标图,我们可以观察到所有已考虑到的优化历史:

optuna.visualization.plot_parallel_coordinate(study)



另一个有用的表示由超参数重要性构成。因此,可以了解到哪些超参数对模型的性能影响最大。

optuna.visualization.plot_param_importances(study)


从图中可以看出,学习率对目标值的影响最大,而其他超参数对学习率的影响很小。丢失率对性能的影响很小,但仍然需要降低过拟合的风险。


希望学姐的这篇文章能够帮助你理解Optuna!


原文链接:

pub.towardsai.net/tunin


学姐终于建群了~公众号后台回复“进群”拉你进群



分享收藏点赞在看

平台注册入口