如何开发神经网络来预测电离层扰动

为新的数据集开发神经网络预测模型可能具有挑战性。

一种方法是首先检查数据集并构思可能适用的模型,然后探索简单模型在数据集上的学习动态,最后使用健壮的测试框架开发和调整模型以适应数据集。

这个过程可以用于开发有效的神经网络模型,用于分类和回归预测建模问题。

在本教程中,您将学习如何为电离层二元分类数据集开发多层感知器(MLP)神经网络模型。

完成本教程后,您将了解:

  • 如何加载和总结电离层数据集,并利用这些结果来建议数据准备和模型配置。
  • 如何探索简单MLP模型在数据集上的学习动态。
  • 如何开发稳健的模型性能估计,调整模型性能,并在新数据上进行预测。

让我们开始吧。

How to Develop a Neural Net for Predicting Disturbances in the Ionosphere

如何开发神经网络来预测电离层扰动
照片作者:Sergey Pesterev,部分权利保留。

教程概述

本教程分为四个部分;它们是

  1. 电离层二元分类数据集
  2. 神经网络学习动态
  3. 评估和调整 MLP 模型
  4. 最终模型及预测

电离层二元分类数据集

第一步是定义和探索数据集。

我们将使用“电离层”标准二元分类数据集。

该数据集涉及根据雷达回波预测一个结构是否在电离层中。

你可以在此处了解更多关于此数据集的信息:

您可以在下方看到数据集的前几行。

我们可以看到所有值都是数值型的,并且可能在 [-1, 1] 的范围内。这表明可能不需要任何类型的缩放。

我们还可以看到标签是字符串(“g”和“b”),这表明在拟合模型之前,需要将这些值编码为 0 和 1。

我们可以直接从 URL 将数据集加载为 pandas DataFrame;例如:

运行示例将直接从 URL 加载数据集并报告数据集的形状。

在这种情况下,我们可以看到数据集有 35 个变量(34 个输入变量和一个输出变量),并且数据集包含 351 行数据。

对于神经网络来说,这并不算很多行数据,这表明使用小型网络,可能带有正则化,会是比较合适的。

考虑到单个模型拟合只需要几秒钟(而不是最耗时的数据集需要数小时或数天),这还表明使用k 折交叉验证会是一个好主意,因为它可以提供比训练/测试分割更可靠的模型性能估计。

接下来,我们可以通过查看摘要统计信息和数据图来进一步了解数据集。

运行示例首先加载数据,然后打印每个变量的摘要统计信息。

我们可以看到每个变量的平均值在十位数,取值范围在 -1 到 1 之间。这证实了数据缩放可能不是必需的。

然后为每个变量创建直方图。

我们可以看到许多变量具有高斯或类高斯分布。

使用幂变换可能对每个变量有益,以使概率分布不那么偏斜,这可能会提高模型性能。

Histograms of the Ionosphere Classification Dataset

电离层分类数据集的直方图

现在我们熟悉了数据集,让我们探索一下如何开发神经网络。

神经网络学习动态

我们将使用 TensorFlow 为数据集开发多层感知机 (MLP) 模型。

我们无法知道什么模型架构或学习超参数最适合这个数据集,因此我们必须进行实验和探索,找出有效的方法。

考虑到数据集较小,使用较小的批量大小可能是个好主意,例如 16 或 32 行。使用随机梯度下降的 Adam 版本在开始时是个好主意,因为它会自动适应学习率,并且在大多数数据集上效果很好。

在我们认真评估模型之前,最好回顾学习动态并调整模型架构和学习配置,直到我们获得稳定的学习动态,然后再考虑如何充分利用模型。

我们可以通过使用简单的训练/测试分割来做到这一点,并查看学习曲线的图表。这将帮助我们了解我们是过度学习还是学习不足;然后我们可以相应地调整配置。

首先,我们必须确保所有输入变量都是浮点值,并将目标标签编码为整数值 0 和 1。

接下来,我们可以将数据集分割为输入和输出变量,然后分割为 67/33 的训练集和测试集。

我们可以定义一个最小的 MLP 模型。在本例中,我们将使用一个具有 10 个节点的隐藏层和一个输出层(任意选择)。我们将在隐藏层中使用ReLU 激活函数,并使用“he_normal”权重初始化,因为它们结合起来是良好的实践。

模型的输出是用于二元分类的 sigmoid 激活,我们将最小化二元交叉熵损失

我们将为 200 个训练时期(任意选择)以 32 的批量大小拟合模型,因为这是一个小型数据集。

我们使用原始数据来拟合模型,我们认为这可能是个好主意,但这只是一个重要的起点。

训练结束后,我们将评估模型在测试集上的性能,并报告分类准确率作为性能指标。

最后,我们将绘制训练过程中训练集和测试集上交叉熵损失的学习曲线。

将所有内容整合起来,评估我们在电离层数据集上的第一个 MLP 的完整示例列在下面。

运行示例首先在训练数据集上拟合模型,然后报告测试数据集上的分类准确率。

注意:由于算法或评估程序的随机性,或数值精度的差异,您的结果可能会有所不同。请考虑运行该示例几次并比较平均结果。

在这种情况下,我们可以看到模型达到了大约 88% 的准确率,这是一个不错的基准性能,我们或许可以改进它。

然后创建训练集和测试集上损失的学习曲线图。

我们可以看到模型似乎收敛了,但已经过度拟合了训练数据集。

Learning Curves of Simple MLP on Ionosphere Dataset

简单 MLP 在电离层数据集上的学习曲线

让我们尝试增加模型的容量。

这将减慢相同学习超参数的学习速度,并可能提供更好的准确性。

我们将添加一个具有八个节点的第二个隐藏层,任意选择。

完整的示例如下所示。

运行该示例首先在训练数据集上拟合模型,然后报告测试数据集上的准确性。

注意:由于算法或评估程序的随机性,或数值精度的差异,您的结果可能会有所不同。请考虑运行该示例几次并比较平均结果。

在这种情况下,我们可以看到准确率略有提高,达到约 93%,尽管训练/测试分割的高方差意味着此评估不可靠。

然后绘制训练和测试集上损失的学习曲线。我们可以看到模型似乎仍然表现出过度拟合的行为。

Learning Curves of Deeper MLP on the Ionosphere Dataset

更深层 MLP 在电离层数据集上的学习曲线

最后,我们可以尝试一个更宽的网络。

我们将第一个隐藏层的节点数从 10 增加到 50,第二个隐藏层的节点数从 8 增加到 10。

这将增加模型的容量,减慢学习速度,并可能进一步提高结果。

我们还将训练时期数从 200 减少到 100。

完整的示例如下所示。

运行该示例首先在训练数据集上拟合模型,然后报告测试数据集上的准确性。

注意:由于算法或评估程序的随机性,或数值精度的差异,您的结果可能会有所不同。请考虑运行该示例几次并比较平均结果。

在这种情况下,模型获得了更好的准确率分数,约为 94%。我们暂时忽略模型性能。

绘制学习曲线的折线图显示模型获得了合理的拟合,并且有足够的时间收敛。

Learning Curves of Wider MLP on the Ionosphere Dataset

更宽 MLP 在电离层数据集上的学习曲线

现在我们对简单 MLP 模型在数据集上的学习动态有了一些了解,我们可以着手评估模型的性能以及调整模型的配置。

评估和调整 MLP 模型

k 折交叉验证过程可以提供更可靠的 MLP 性能估计,尽管它可能非常耗时。

这是因为必须拟合和评估k个模型。当数据集很小时,例如电离层数据集,这不成问题。

我们可以使用 StratifiedKFold 类并手动枚举每个折叠,拟合模型,进行评估,然后在过程结束时报告评估分数的平均值。

我们可以使用此框架来开发可靠的 MLP 模型性能估计,涉及一系列不同的数据准备、模型架构和学习配置。

在将 k 折交叉验证用于性能估计之前,在上一节中开发对模型在数据集上的学习动态的理解至关重要。如果我们直接开始调整模型,我们可能会得到好的结果,但如果不成功,我们可能不知道原因,例如模型是过度拟合还是欠拟合。

如果我们再次对模型进行大的更改,最好回到并确认模型正在正确收敛。

下面列出了使用此框架评估上一节中基础 MLP 模型的完整示例。

运行示例将报告每次评估过程的模型的性能,并在运行结束时报告分类准确率的平均值和标准差。

注意:由于算法或评估程序的随机性,或数值精度的差异,您的结果可能会有所不同。请考虑运行该示例几次并比较平均结果。

在这种情况下,我们可以看到 MLP 模型达到了大约 93.4% 的平均准确率。

我们将使用此结果作为基准,看看是否可以获得更好的性能。

接下来,让我们尝试为模型添加正则化以减少过度拟合。

在这种情况下,我们可以在网络的隐藏层之间添加 dropout 层。例如

带 dropout 的 MLP 模型的完整示例列在下面。

运行后,在运行结束时报告分类准确率的平均值和标准差。

注意:由于算法或评估程序的随机性,或数值精度的差异,您的结果可能会有所不同。请考虑运行该示例几次并比较平均结果。

在这种情况下,我们可以看到带 dropout 的 MLP 模型取得了更好的结果,准确率约为 94.6%,而没有 dropout 的模型为 93.4%。

最后,我们将尝试将批量大小从 32 减小到 8。

这将导致更嘈杂的梯度,并且也可能减慢模型学习问题的速度。

完整的示例如下所示。

运行后,在运行结束时报告分类准确率的平均值和标准差。

注意:由于算法或评估程序的随机性,或数值精度的差异,您的结果可能会有所不同。请考虑运行该示例几次并比较平均结果。

在这种情况下,我们可以看到带 dropout 的 MLP 模型取得了略微更好的结果,准确率约为 94.9%。

我们将使用此配置作为我们的最终模型。

我们可以继续测试模型架构(更多或更少的节点或层)、学习超参数(更多或更少的批次)和数据转换的替代配置。

留给您作为练习;请告诉我您的发现。您能获得更好的结果吗?
在下面的评论中发布您的结果,我很想看到您的成果。

接下来,我们看看如何拟合最终模型并使用它来做出预测。

最终模型及预测

选择模型配置后,我们可以使用所有可用数据训练最终模型,并用它来对新数据进行预测。

在此案例中,我们将使用带有 dropout 和小型批次大小的模型作为我们的最终模型。

我们可以像以前一样准备数据并拟合模型,但这次是在整个数据集上,而不是在一个训练子集上。

然后,我们可以使用此模型对新数据进行预测。

首先,我们可以定义一个新数据行。

注意:我从数据集中选择了第一行,预期的标签是“g”。

然后我们可以进行预测。

然后对预测结果进行逆向转换,以便使用或解释正确标签的结果。

在这种情况下,我们将只报告预测结果。

总而言之,下面列出了拟合电离层数据集的最终模型并使用它对新数据进行预测的完整示例。

运行示例会将模型拟合到整个数据集,并为新数据的单行进行预测。

注意:由于算法或评估程序的随机性,或数值精度的差异,您的结果可能会有所不同。请考虑运行该示例几次并比较平均结果。

在这种情况下,我们可以看到模型为输入行预测了“g”标签。

进一步阅读

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

教程

总结

在本教程中,您学习了如何为电离层二分类数据集开发多层感知机神经网络模型。

具体来说,你学到了:

  • 如何加载和总结电离层数据集,并利用这些结果来建议数据准备和模型配置。
  • 如何探索简单MLP模型在数据集上的学习动态。
  • 如何开发模型性能的稳健估计,调整模型性能并对新数据进行预测。

你有什么问题吗?
在下面的评论中提出你的问题,我会尽力回答。

对《如何为预测电离层扰动开发神经网络》的 12 条回复

  1. Brent Janaky 2021 年 2 月 12 日上午 5:28 #

    哇,这篇教程太棒了,而且是刚发布的!我刚开始学习深度学习,所以时机非常合适。这里有很多需要学习的内容,我有的忙了。

    谢谢你,Jason。

  2. Ankur Kumar 2021 年 2 月 12 日上午 6:05 #

    教程很棒。
    谢谢分享,Jason Brownlee

  3. Sachin Dev Duggal CEO Builder AI 2021 年 2 月 12 日下午 4:34 #

    太棒了!技术内容很好。要消化这么多内容真的很难。非常感谢您的努力,@Jason Brownlee。

  4. Alia Sharma 2021 年 2 月 12 日下午 4:47 #

    演示太棒了,而且用通俗易懂的语言解释概念的方式值得称赞。请告诉我如何访问 colab notebook。我从 Sachin Dev Duggal(Builder AI 的 CEO 和创始人)的文章中读到过这类概念。

  5. Sonia Ahlawat 2021 年 2 月 13 日上午 2:46 #

    好文章!!更容易理解

  6. kamal 2021 年 5 月 27 日上午 1:42 #

    先生,当我尝试将水平集成应用于电离层数据时,它会报错。

    File “C:\Users\LENOVO\untitled4.py”, line 79, in
    members = load_all_models(950, 1000)

    File “C:\Users\LENOVO\untitled4.py”, line 38, in load_all_models
    model = load_model(filename)

    File “C:\Users\LENOVO\anaconda3\envs\tensorflow\lib\site-packages\keras\engine\saving.py”, line 492, in load_wrapper
    return load_function(*args, **kwargs)

    File “C:\Users\LENOVO\anaconda3\envs\tensorflow\lib\site-packages\keras\engine\saving.py”, line 584, in load_model
    model = _deserialize_model(h5dict, custom_objects, compile)

    File “C:\Users\LENOVO\anaconda3\envs\tensorflow\lib\site-packages\keras\engine\saving.py”, line 274, in _deserialize_model
    model = model_from_config(model_config, custom_objects=custom_objects)

    File “C:\Users\LENOVO\anaconda3\envs\tensorflow\lib\site-packages\keras\engine\saving.py”, line 627, in model_from_config
    return deserialize(config, custom_objects=custom_objects)

    File “C:\Users\LENOVO\anaconda3\envs\tensorflow\lib\site-packages\keras\layers\__init__.py”, line 168, in deserialize
    printable_module_name='layer')

    File “C:\Users\LENOVO\anaconda3\envs\tensorflow\lib\site-packages\keras\utils\generic_utils.py”, line 147, in deserialize_keras_object
    list(custom_objects.items())))

    File “C:\Users\LENOVO\anaconda3\envs\tensorflow\lib\site-packages\keras\engine\sequential.py”, line 301, in from_config
    custom_objects=custom_objects)

    File “C:\Users\LENOVO\anaconda3\envs\tensorflow\lib\site-packages\keras\layers\__init__.py”, line 168, in deserialize
    printable_module_name='layer')

    File “C:\Users\LENOVO\anaconda3\envs\tensorflow\lib\site-packages\keras\utils\generic_utils.py”, line 149, in deserialize_keras_object
    return cls.from_config(config[‘config’])

    File “C:\Users\LENOVO\anaconda3\envs\tensorflow\lib\site-packages\keras\engine\base_layer.py”, line 1179, in from_config
    return cls(**config)

    File “C:\Users\LENOVO\anaconda3\envs\tensorflow\lib\site-packages\keras\legacy\interfaces.py”, line 91, in wrapper
    return func(*args, **kwargs)

    File “C:\Users\LENOVO\anaconda3\envs\tensorflow\lib\site-packages\keras\layers\core.py”, line 877, in __init__
    self.kernel_initializer = initializers.get(kernel_initializer)

    File “C:\Users\LENOVO\anaconda3\envs\tensorflow\lib\site-packages\keras\initializers.py”, line 515, in get
    return deserialize(identifier)

    File “C:\Users\LENOVO\anaconda3\envs\tensorflow\lib\site-packages\keras\initializers.py”, line 510, in deserialize
    printable_module_name=’initializer’)

    File “C:\Users\LENOVO\anaconda3\envs\tensorflow\lib\site-packages\keras\utils\generic_utils.py”, line 149, in deserialize_keras_object
    return cls.from_config(config[‘config’])

    File “C:\Users\LENOVO\anaconda3\envs\tensorflow\lib\site-packages\keras\initializers.py”, line 30, in from_config
    return cls(**config)

    File “C:\Users\LENOVO\anaconda3\envs\tensorflow\lib\site-packages\keras\initializers.py”, line 204, in __init__
    ‘but got’, distribution)

    ValueError: (‘Invalid distribution argument: expected one of {“normal”, “uniform”} but got’, ‘truncated_normal’)

    请帮忙解决这个问题

    • Jason Brownlee 2021 年 5 月 27 日上午 5:39 #

      抱歉,我不知道您错误的原因。

      也许您可以在 stackoverflow.com 上发布您的代码、数据和错误信息。

Leave a Reply

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