如何对 PyTorch 模型进行超参数网格搜索

神经网络的“权重”在 PyTorch 代码中被称为“参数”,在训练过程中由优化器进行微调。相反,超参数是神经网络中通过设计固定且不通过训练进行调整的参数。例如隐藏层数量和激活函数的选择。超参数优化是深度学习的重要组成部分。原因是神经网络的配置极其困难,需要设置很多参数。此外,单个模型的训练速度可能非常慢。

在本帖中,您将学习如何使用 scikit-learn Python 机器学习库中的网格搜索功能来调整 PyTorch 深度学习模型的超参数。阅读本帖后,您将了解:

  • 如何封装 PyTorch 模型以在 scikit-learn 中使用以及如何使用网格搜索
  • 如何对常见的神经网络参数进行网格搜索,例如学习率、dropout 率、训练轮数和神经元数量
  • 如何定义您自己的超参数调优实验

通过我的《用PyTorch进行深度学习》一书来启动你的项目。它提供了包含可用代码自学教程


让我们开始吧。

如何对 PyTorch 模型进行超参数网格搜索
照片作者:brandon siu。部分权利保留。

概述

在本帖中,您将看到如何使用 scikit-learn 的网格搜索功能,其中包含一系列示例,您可以将这些示例复制粘贴到您自己的项目中作为起点。下面是我们即将涵盖的主题列表:

  • 如何在 scikit-learn 中使用 PyTorch 模型
  • 如何在 scikit-learn 中使用网格搜索
  • 如何调整批次大小和训练轮数
  • 如何调整优化算法
  • 如何调整学习率和动量
  • 如何调整网络权重初始化
  • 如何调整激活函数
  • 如何调整 dropout 正则化
  • 如何调整隐藏层中的神经元数量

如何在 scikit-learn 中使用 PyTorch 模型

如果 PyTorch 模型被 skorch 封装,就可以在 scikit-learn 中使用。这是为了利用 Python 的鸭子类型特性,使 PyTorch 模型提供与 scikit-learn 模型相似的 API,这样 scikit-learn 中的一切都可以协同工作。在 skorch 中,有用于分类神经网络的 NeuralNetClassifier 和用于回归神经网络的 NeuralNetRegressor。您可能需要运行以下命令来安装该模块。

要使用这些封装器,您必须使用 nn.Module 将您的 PyTorch 模型定义为一个类,然后在使用 NeuralNetClassifier 类实例化时,将类的名称传递给 module 参数。例如:

NeuralNetClassifier 类的构造函数可以接受传递给 model.fit() (在 scikit-learn 模型中调用训练循环的方式) 的默认参数,例如训练轮数和批次大小。例如:

NeuralNetClassifier 类的构造函数还可以接受传递给您的模型类的构造函数的新参数,但您必须在前面加上 module__ (两个下划线)。这些新参数可能在构造函数中带有默认值,但在封装器实例化模型时会被覆盖。例如:

您可以通过初始化模型并打印它来验证结果

在此示例中,您应该会看到:

想开始使用PyTorch进行深度学习吗?

立即参加我的免费电子邮件速成课程(附示例代码)。

点击注册,同时获得该课程的免费PDF电子书版本。

如何在 scikit-learn 中使用网格搜索

网格搜索是一种模型超参数优化技术。它简单地穷举超参数的所有组合,并找到给出最佳分数的组合。在 scikit-learn 中,此技术由 GridSearchCV 类提供。在实例化此类时,您必须在 param_grid 参数中提供要评估的超参数字典。这是一个模型参数名称和要尝试的值数组的映射。

默认情况下,准确率是优化的分数,但其他分数可以在 GridSearchCV 构造函数的 score 参数中指定。然后,GridSearchCV 进程将为每个参数组合构建和评估一个模型。交叉验证用于评估每个模型,默认使用 3 折交叉验证,尽管您可以通过在 GridSearchCV 构造函数中指定 cv 参数来覆盖此设置。

下面是一个定义简单网格搜索的示例:

通过将 GridSearchCV 构造函数中的 n_jobs 参数设置为 $-1$,该过程将使用您机器上的所有核心。否则,网格搜索过程将仅在单线程中运行,在多核 CPU 上速度会变慢。

完成后,您可以从 grid.fit() 返回的结果对象中访问网格搜索的结果。best_score_ 成员提供了在优化过程中观察到的最佳分数,而 best_params_ 描述了获得最佳结果的参数组合。您可以在 scikit-learn API 文档中找到有关 GridSearchCV 类的更多信息。

通过我的《用PyTorch进行深度学习》一书来启动你的项目。它提供了包含可用代码自学教程

问题描述

现在您已经知道了如何在 scikit-learn 中使用 PyTorch 模型以及如何在 scikit-learn 中使用网格搜索,接下来让我们看一些示例。

所有示例都将在一个名为 Pima Indians 发病糖尿病分类数据集 的小型标准机器学习数据集上进行演示。这是一个小型数据集,所有属性都是数值型的,易于处理。

在继续阅读本帖中的示例时,您将聚合最佳参数。这不是网格搜索的最佳方法,因为参数会相互影响,但对于演示目的而言是好的。

如何调整批次大小和训练轮数

在第一个简单示例中,您将学习如何调整拟合网络时使用的批次大小和训练轮数。

在迭代梯度下降中,批次大小是指在权重更新之前展示给网络的模式数量。它也是网络训练中的一个优化项,定义了每次读取并保留在内存中的模式数量。

训练轮数是指在训练过程中,整个训练数据集被展示给网络的次数。有些网络对批次大小很敏感,例如 LSTM 循环神经网络和卷积神经网络。

在这里,您将评估从 10 到 100,步长为 20 的一系列不同的最小批次大小。

完整的代码清单如下

运行此示例会产生以下输出

可以看出,批次大小为 10 且训练轮数为 100 时取得了最佳结果,准确率约为 71%(但您也应考虑准确率的标准差)。

如何调整训练优化算法

所有深度学习库都应提供各种优化算法。PyTorch 也不例外。

在本示例中,您将调整用于训练网络的优化算法,每个算法都使用默认参数。

这是一个不寻常的示例,因为通常您会预先选择一种方法,而专注于为您的特定问题调整其参数(请参见下一个示例)。
在这里,您将评估 PyTorch 中可用的一系列优化算法

完整的代码清单如下

运行此示例会产生以下输出

结果表明,Adamax 优化算法效果最好,得分为约 72% 的准确率。

值得一提的是,GridSearchCV 会经常重新创建您的模型,因此每次试验都是独立的。之所以能够这样做,是因为 NeuralNetClassifier 封装器知道您的 PyTorch 模型的类名,并在请求时为您实例化一个。

如何调整学习率和动量

通常会预先选择一个优化算法来训练您的网络并调整其参数。

到目前为止,最常见的优化算法是普通的随机梯度下降(SGD),因为它非常容易理解。在本示例中,您将研究如何优化 SGD 的学习率和动量参数。

学习率控制每次批次结束时权重的更新幅度,动量控制前一次更新对当前权重更新的影响程度。

您将尝试一系列小的标准学习率和动量值,从 0.2 到 0.8,步长为 0.2,以及 0.9(因为它在实践中可能是一个流行的值)。在 PyTorch 中,设置学习率和动量的方法如下:

在 skorch 封装器中,您可以使用 optimizer__ 前缀将参数路由到优化器。

通常,最好也将训练轮数包含在此类优化中,因为学习率(每批次的学习量)、批次大小(每 epoch 的更新次数)和训练轮数之间存在依赖关系。

完整的代码清单如下

运行此示例将产生以下输出。

可以看到,使用 SGD 时,使用学习率为 0.001 和动量为 0.9 取得了最佳结果,准确率为约 68%。

如何调整神经网络权重初始化

神经网络的权重初始化曾经很简单:使用小的随机值。

现在有多种不同的技术可供选择。您可以在 torch.nn.init 文档中找到一个详细列表

在本示例中,您将通过评估所有可用技术来尝试调整神经网络权重初始化的选择。

您将在每个层上使用相同的权重初始化方法。理想情况下,根据每个层使用的激活函数使用不同的权重初始化方案可能会更好。在下面的示例中,您将为隐藏层使用整流器。对于输出层使用 sigmoid,因为预测是二元的。PyTorch 模型中的权重初始化是隐式的。因此,您需要编写自己的逻辑来初始化权重,在层创建之后但在使用之前。让我们按如下方式修改 PyTorch:

PimaClassifier 类中添加了一个 weight_init 参数,它期望 torch.nn.init 中的一个初始化器。在 GridSearchCV 中,您需要使用 module__ 前缀来让 NeuralNetClassifier 将参数路由到模型的类构造函数。

完整的代码清单如下

运行此示例将产生以下输出。

最佳结果是通过 He-uniform 权重初始化方案获得的,性能约为 70%。

如何调整神经元激活函数

激活函数控制单个神经元的非线性和何时激活。

通常,整流器激活函数是最受欢迎的。然而,它以前是 sigmoid 和 tanh 函数,这些函数对于不同的问题可能仍然更合适。

在本示例中,您将评估 PyTorch 中提供的一些激活函数。由于二元分类问题需要在输出层使用 sigmoid 激活函数,因此您只会将这些函数用于隐藏层。与前面的示例类似,这是模型类构造函数的参数,并且您将为 GridSearchCV 参数网格使用 module__ 前缀。

通常,将数据准备到不同转换函数的范围内是一个好主意,但在本例中您不会这样做。

完整的代码清单如下

运行此示例将产生以下输出。

结果表明,ReLU 激活函数取得了最佳结果,准确率约为 70%。

如何调整 Dropout 正则化

在本示例中,您将尝试调整用于深度神经网络正则化的 Dropout 速率,以限制过拟合并提高模型的泛化能力。

为了获得最佳结果,Dropout 与权重约束(如在前向传播函数中实现的 max norm 约束)结合使用效果最佳。

这涉及拟合 dropout 百分比和权重约束。我们将尝试 dropout 百分比在 0.0 到 0.9 之间(1.0 没有意义),以及 MaxNorm 权重约束值在 0 到 5 之间。

完整的代码清单如下。

运行此示例将产生以下输出。

可以看到,10% 的 dropout 速率和 2.0 的权重约束取得了约 70% 的最佳准确率。

如何调整隐藏层中的神经元数量

层中的神经元数量是需要调整的重要参数。通常,层中的神经元数量控制着网络在该拓扑结构中的表示能力。

根据通用逼近定理,一个足够大的单层网络可以逼近任何其他神经网络。

在本示例中,您将尝试调整单个隐藏层中的神经元数量。您将尝试从 1 到 30 的值,步长为 5。
更大的网络需要更多的训练,并且至少应该根据神经元数量来优化批量大小和 epoch 数量。

完整的代码清单如下。

运行此示例将产生以下输出。

可以看到,隐藏层中具有 30 个神经元的网络取得了最佳结果,准确率约为 71%。

超参数优化技巧

本节列出了一些在调整神经网络超参数时可以考虑的有用技巧。

  • k 折交叉验证。您可以看到本帖子示例中的结果存在一些差异。默认使用 3 折交叉验证,但 k=5 或 k=10 可能会更稳定。请仔细选择您的交叉验证配置,以确保结果稳定。
  • 审查整个网格。不要只关注最佳结果,审查整个结果网格并寻找趋势以支持配置决策。当然,会有更多的组合,评估它们需要更长的时间。
  • 并行化。如果可以,使用您的所有核心,神经网络训练速度很慢,我们通常想尝试很多不同的参数。考虑在云平台(如 AWS)上运行。
  • 使用数据集的样本。由于网络训练速度很慢,尝试在较小的训练数据集样本上进行训练,以便对参数的总体方向有所了解,而不是最佳配置。
  • 从粗粒度网格开始。从粗粒度网格开始,一旦您能够缩小范围,就可以进入更细粒度的网格。
  • 不要转移结果。结果通常是特定于问题的。在新问题上尽量避免偏好配置。您在一个问题上发现的最优结果不太可能转移到您的下一个项目中。相反,应该关注更广泛的趋势,例如层数或参数之间的关系。
  • 可复现性是一个问题。尽管我们为 NumPy 的随机数生成器设置了种子,但结果并非 100% 可复现。对于包装 PyTorch 模型的网格搜索,可复现性比本帖子介绍的要复杂得多。

进一步阅读

如果您想深入了解,本节提供了更多关于该主题的资源。

总结

在本帖子中,您了解了如何使用 PyTorch 和 scikit-learn 在 Python 中调整深度学习网络的超参数。
具体来说,你学到了:

  • 如何包装 PyTorch 模型以在 scikit-learn 中使用以及如何使用网格搜索。
  • 如何为 PyTorch 模型进行各种标准神经网络参数的网格搜索。
  • 如何设计自己的超参数优化实验。

开始使用PyTorch进行深度学习!

Deep Learning with PyTorch

学习如何构建深度学习模型

...使用新发布的PyTorch 2.0库

在我的新电子书中探索如何实现
使用 PyTorch进行深度学习

它提供了包含数百个可用代码自学教程,让你从新手变成专家。它将使你掌握:
张量操作训练评估超参数优化等等...

通过动手练习开启你的深度学习之旅


查看内容

6 条对《如何为 PyTorch 模型进行超参数网格搜索》的回复

  1. Aminul 2023 年 10 月 12 日上午 5:49 #

    你好,
    在这种情况下,我可以使用支持 GPU 的 pytorch 模型吗?

  2. Yaswanth 2023 年 11 月 22 日上午 3:33 #

    你好,

    代码在 grid.fit(x,y) 行出错。可能是什么错误?

    • James Carmichael 2023 年 11 月 22 日上午 10:30 #

      你好 Yaswanth……请告知您遇到的确切错误措辞。这将更好地帮助我们。

  3. Lukas 2024 年 1 月 23 日上午 1:22 #

    你好,

    我只想说,machinelearningmastery.com 上的这些指南对我学习机器学习非常有价值。我只从事了 2 年,但我对未来感到兴奋。

    非常感谢。

    祝一切顺利

    • James Carmichael 2024 年 1 月 23 日上午 9:17 #

      感谢您的反馈 Lukas!我们非常感谢您的支持!

留下回复

Machine Learning Mastery 是 Guiding Tech Media 的一部分,Guiding Tech Media 是一家领先的数字媒体出版商,专注于帮助人们了解技术。访问我们的公司网站以了解更多关于我们的使命和团队的信息。