PyTorch教程-19.1. 什么是超参数优化?

电子说

1.3w人已加入

描述

正如我们在前几章中所见,深度神经网络带有大量在训练过程中学习的参数或权重。除此之外,每个神经网络都有额外的 超参数需要用户配置。例如,为了确保随机梯度下降收敛到训练损失的局部最优(参见第 12 节),我们必须调整学习率和批量大小。为了避免在训练数据集上过度拟合,我们可能必须设置正则化参数,例如权重衰减(参见第 3.7 节)或 dropout(参见 第 5.6 节)). 我们可以通过设置层数和每层单元或过滤器的数量(即权重的有效数量)来定义模型的容量和归纳偏差。

不幸的是,我们不能简单地通过最小化训练损失来调整这些超参数,因为这会导致训练数据过度拟合。例如,将正则化参数(如 dropout 或权重衰减)设置为零会导致较小的训练损失,但可能会损害泛化性能。

神经网络

图 19.1.1机器学习中的典型工作流程,包括使用不同的超参数多次训练模型。

如果没有不同形式的自动化,就必须以反复试验的方式手动设置超参数,这相当于机器学习工作流程中耗时且困难的部分。例如,考虑在 CIFAR-10 上训练 ResNet(参见第 8.6 节g4dn.xlarge),这需要在 Amazon Elastic Cloud Compute (EC2)实例上训练 2 个多小时。即使只是依次尝试十个超参数配置,这也已经花费了我们大约一天的时间。更糟糕的是,超参数通常不能直接跨架构和数据集传输 (Bardenet等人,2013 年,Feurer等人,2022 年,Wistuba等人,2018 年),并且需要针对每个新任务重新优化。此外,对于大多数超参数,没有经验法则,需要专业知识才能找到合理的值。

超参数优化 (HPO)算法旨在以一种有原则的和自动化的方式解决这个问题 (Feurer 和 Hutter,2018 年),将其定义为一个全局优化问题。默认目标是保留验证数据集上的错误,但原则上可以是任何其他业务指标。它可以与次要目标结合或受其约束,例如训练时间、推理时间或模型复杂性。

最近,超参数优化已扩展到神经架构搜索 (NAS) (Elsken等人,2018 年,Wistuba等人,2019 年),目标是找到全新的神经网络架构。与经典 HPO 相比,NAS 在计算方面的成本更高,并且需要额外的努力才能在实践中保持可行性。HPO 和 NAS 都可以被视为 AutoML 的子领域 ( Hutter et al. , 2019 ),旨在自动化整个 ML 管道。

在本节中,我们将介绍 HPO 并展示我们如何自动找到第 4.5 节介绍的逻辑回归示例的最佳超参数。

19.1.1. 优化问题

我们将从一个简单的玩具问题开始:搜索第 4.5 节SoftmaxRegression中 的多类逻辑回归模型的学习率,以最小化 Fashion MNIST 数据集上的验证错误。虽然批量大小或轮数等其他超参数也值得调整,但为简单起见,我们只关注学习率。

 

import numpy as np
import torch
from scipy import stats
from torch import nn
from d2l import torch as d2l

 

在运行 HPO 之前,我们首先需要定义两个要素:目标函数和配置空间。

19.1.1.1。目标函数

学习算法的性能可以看作是一个函数 f:X→R从超参数空间映射x∈X到验证损失。对于每一个评价f(x),我们必须训练和验证我们的机器学习模型,对于在大型数据集上训练的深度神经网络,这可能是时间和计算密集型的。鉴于我们的标准f(x)我们的目标是找到 x⋆∈argminx∈Xf(x).

没有简单的方法来计算的梯度f关于 x,因为它需要在整个训练过程中传播梯度。虽然最近有工作 (Franceschi等人,2017 年,Maclaurin等人,2015 年)通过近似“超梯度”驱动 HPO,但现有方法中没有一种与最先进的方法具有竞争力,我们将不在这里讨论它们。此外,评估的计算负担f 要求 HPO 算法以尽可能少的样本接近全局最优。

神经网络的训练是随机的(例如,权重是随机初始化的,mini-batches 是随机采样的),因此我们的观察结果会很嘈杂:y∼f(x)+ϵ,我们通常假设ϵ∼N(0,σ) 观察噪声呈高斯分布。

面对所有这些挑战,我们通常会尝试快速识别一小组性能良好的超参数配置,而不是准确地达到全局最优值。然而,由于大多数神经网络模型的大量计算需求,即使这样也可能需要数天或数周的计算时间。我们将在19.4 节中探讨如何通过分布搜索或使用目标函数的评估成本更低的近似值来加快优化过程。

我们从计算模型验证误差的方法开始。

 

class HPOTrainer(d2l.Trainer): #@save
  def validation_error(self):
    self.model.eval()
    accuracy = 0
    val_batch_idx = 0
    for batch in self.val_dataloader:
      with torch.no_grad():
        x, y = self.prepare_batch(batch)
        y_hat = self.model(x)
        accuracy += self.model.accuracy(y_hat, y)
      val_batch_idx += 1
    return 1 - accuracy / val_batch_idx

 

我们优化了关于超参数配置的验证错误config,由learning_rate. 对于每个评估,我们训练我们的模型max_epochsepochs,然后计算并返回其验证错误:

 

def hpo_objective_softmax_classification(config, max_epochs=8):
  learning_rate = config["learning_rate"]
  trainer = d2l.HPOTrainer(max_epochs=max_epochs)
  data = d2l.FashionMNIST(batch_size=16)
  model = d2l.SoftmaxRegression(num_outputs=10, lr=learning_rate)
  trainer.fit(model=model, data=data)
  return trainer.validation_error().detach().numpy()

 

19.1.1.2。配置空间

随着目标函数f(x),我们还需要定义可行集x∈X优化过来,称为配置空间或搜索空间。对于我们的逻辑回归示例,我们将使用:

 

config_space = {"learning_rate": stats.loguniform(1e-4, 1)}

 

这里我们使用loguniformSciPy 中的对象,它表示对数空间中 -4 和 -1 之间的均匀分布。这个对象允许我们从这个分布中抽样随机变量。

每个超参数都有一个数据类型,例如floatfor learning_rate,以及一个封闭的有界范围(即下限和上限)。我们通常为每个超参数分配一个先验分布(例如,均匀分布或对数均匀分布)以从中进行采样。一些正参数(例如learning_rate)最好用对数标度表示,因为最佳值可能相差几个数量级,而其他参数(例如动量)则采用线性标度。

下面我们展示了一个配置空间的简单示例,该配置空间由多层感知器的典型超参数组成,包括它们的类型和标准范围。

表 19.1.1多层感知机配置空间示例

姓名 类型 超参数范围 对数刻度
学习率 漂浮 [10−6,10−1] 是的
批量大小 整数 [8,256] 是的
势头 漂浮 [0,0.99]
激活函数 明确的 {tanh,relu}  
单位数 整数 [32,1024] 是的
层数 整数 [1,6]

一般来说,配置空间的结构X 可能很复杂,也可能与Rd. 在实践中,一些超参数可能取决于其他超参数的值。例如,假设我们尝试调整多层感知器的层数,以及每一层的单元数。的单位数目l−th只有当网络至少有l+1层。这些高级 HPO 问题超出了本章的范围。我们建议感兴趣的读者参阅 (Baptista 和 Poloczek,2018 年,Hutter等人,2011 年,Jenatton等人,2017 年)。

配置空间对于超参数优化起着重要作用,因为没有算法可以找到不包含在配置空间中的东西。另一方面,如果范围太大,找到性能良好的配置的计算预算可能变得不可行。

19.1.2. 随机搜索

随机搜索是我们将考虑的第一个超参数优化算法。随机搜索的主要思想是从配置空间中独立采样,直到用尽预定义的预算(例如最大迭代次数),并返回最佳观察到的配置。所有评估都可以并行独立执行(请参阅第 19.3 节),但这里我们为简单起见使用顺序循环。

 

errors, values = [], []
num_iterations = 5

for i in range(num_iterations):
  learning_rate = config_space["learning_rate"].rvs()
  print(f"Trial {i}: learning_rate = {learning_rate}")
  y = hpo_objective_softmax_classification({"learning_rate": learning_rate})
  print(f"  validation_error = {y}")
  values.append(learning_rate)
  errors.append(y)

 

 

  validation_error = 0.17659997940063477

 

神经网络

神经网络

神经网络

神经网络

神经网络

最好的学习率就是验证错误率最低的那个。

 

best_idx = np.argmin(errors)
print(f"optimal learning rate = {values[best_idx]}")

 

 

optimal learning rate = 0.24202220709278127

 

由于其简单性和通用性,随机搜索是最常用的 HPO 算法之一。它不需要任何复杂的实现,并且可以应用于任何配置空间,只要我们可以为每个超参数定义一些概率分布。

不幸的是,随机搜索也有一些缺点。首先,它没有根据迄今为止收集的先前观察结果调整抽样分布。因此,与性能较好的配置相比,同样可能对性能较差的配置进行采样。其次,所有配置都花费了相同数量的资源,即使有些配置可能显示出较差的初始性能并且不太可能胜过之前看到的配置。

在接下来的部分中,我们将研究更多样本高效的超参数优化算法,这些算法通过使用模型来指导搜索来克服随机搜索的缺点。我们还将研究自动停止对性能不佳配置的评估过程以加快优化过程的算法。

19.1.3. 概括

在本节中,我们介绍了超参数优化 (HPO) 以及如何通过定义配置空间和目标函数将其表述为全局优化。我们还实现了我们的第一个 HPO 算法,随机搜索,并将其应用于简单的 softmax 分类问题。

虽然随机搜索非常简单,但它是网格搜索的更好替代方案,后者只评估一组固定的超参数。随机搜索在某种程度上减轻了维数灾难 ( Bellman, 1966 ),并且如果标准最强烈地依赖于超参数的一小部分,则它可以比网格搜索更有效。

19.1.4。练习

在本章中,我们优化了在不相交的训练集上训练后模型的验证错误。为简单起见,我们的代码使用 Trainer.val_dataloader,它映射到 周围的加载器 FashionMNIST.val。

说服自己(通过查看代码)这意味着我们使用原始 FashionMNIST 训练集(60000 个示例)进行训练,并使用原始测试集(10000 个示例)进行验证。

为什么这种做法会有问题?提示:重新阅读 第 3.6 节,尤其是关于模型选择的内容。

我们应该怎么做呢?

我们在上面说过,通过梯度下降进行超参数优化是很难做到的。考虑一个小问题,例如在 FashionMNIST 数据集(第 5.2 节)上训练一个批量大小为 256 的双层感知器。我们想调整 SGD 的学习率,以便在一个训练周期后最小化验证指标.

为什么我们不能为此目的使用验证错误?您将使用验证集的什么指标?

在训练一个时期后(粗略地)绘制验证指标的计算图。您可以假设初始权重和超参数(例如学习率)是该图的输入节点。提示:重新阅读 第 5.3 节中有关计算图的内容。

粗略估计在此图的前向传递过程中需要存储的浮点值的数量。提示:FashionMNIST 有 60000 个案例。假设所需的内存由每层之后的激活决定,并在第 5.2 节中查找层宽度。

除了需要大量的计算和存储之外,基于梯度的超参数优化还会遇到哪些其他问题?提示:重新阅读 第 5.4 节中关于梯度消失和爆炸的内容。

进阶:阅读(Maclaurin等人,2015 年),了解基于梯度的 HPO 的优雅(但仍然有些不切实际)方法。

网格搜索是另一个 HPO 基线,我们在其中为每个超参数定义一个等距网格,然后迭代(组合)笛卡尔积以建议配置。

我们在上面说过,如果标准最强烈地依赖于超参数的一小部分,那么在大量超参数上随机搜索比网格搜索 HPO 更有效。为什么是这样?提示:阅读 (Bergstra等人,2011 年)。

Discussions

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分