【AI with ML】第 10 章 :创建 ML 模型以预测序列

news2024/11/18 6:45:57

        🔎大家好,我是Sonhhxg_柒,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流🔎

📝个人主页-Sonhhxg_柒的博客_CSDN博客 📃

🎁欢迎各位→点赞👍 + 收藏⭐️ + 留言📝​

📣系列专栏 - 机器学习【ML】 自然语言处理【NLP】  深度学习【DL】

​​

 🖍foreword

✔说明⇢本人讲解主要包括Python、机器学习(ML)、深度学习(DL)、自然语言处理(NLP)等内容。

如果你对这个系列感兴趣的话,可以关注订阅哟👋

文章目录

创建窗口数据集

创建时间序列数据集的窗口版本

创建和训练 DNN 以拟合序列数据

评估 DNN 的结果

探索整体预测

调整学习率

使用 Keras Tuner 探索超参数调整

概括


第9章介绍了序列数据和时间序列的属性,包括季节性、趋势、自相关和噪声。您创建了一个用于预测的合成序列,并探索了如何进行基本统计预测。在接下来的几章中,您将学习如何使用 ML 进行预测。但是在开始创建模型之前,您需要了解如何构建用于训练预测模型的时间序列数据,方法是创建我们称之为 窗口数据集。

要了解为什么需要这样做,请考虑您在第 9 章中创建的时间序列。您可以在图 10-1中看到它的图。

图 10-1。合成时间序列

 如果在任何时候您想预测时间t的值,您需要将其预测为时间t之前的值的函数。例如,假设您要预测时间序列在时间步长 1,200 处的值作为其前面 30 个值的函数。在这种情况下,从时间步长 1,170 到 1,199 的值将确定时间步长 1,200 的值,如图 10-2所示。

图 10-2。影响预测的先前值

现在这看起来很熟悉:您可以将 1,170–1,199 的值视为您的特征,将 1,200 的值视为您的特征 标签。如果你可以让你的数据集进入这样一种情况,你有一定数量的值作为特征,下一个作为标签,并且你对数据集中的每个已知值都这样做,你最终会得到一组相当不错的可用于训练模型的特征和标签。

在对第 9 章的时间序列数据集执行此操作之前,让我们创建一个非常简单的数据集,该数据集具有所有相同的属性,但数据量要少得多。

创建窗口数据集

 tf.data库包含许多可用于操作数据的 API。您可以使用这些创建包含数字 0-9 的基本数据集,模拟时间序列。然后,您将把它变成窗口数据集的开始。这是代码:

dataset = tf.data.Dataset.range(10)
dataset = dataset.window(5, shift=1, drop_remainder=True)
dataset = dataset.flat_map(lambda window: window.batch(5))
for window in dataset:
    print(window.numpy())

首先,它使用范围创建数据集,这只是使数据集包含值 0 到n – 1,其中n在本例中为 10。

接下来,调用 dataset.window并传递5指定的参数将数据集拆分为五个项目的窗口。指定shift=1会导致每个窗口从前一个窗口移动一个位置:第一个窗口将包含从 0 开始的五个项目,下一个窗口将包含从 1 开始的五个项目,等等。设置drop_remainderTrue指定一旦它到达接近数据集末尾的点,在该点窗口将小于所需的五个大小,它们应该被删除。

给定窗口定义,可以进行拆分数据集的过程。你用 flat_map函数,在本例中请求一批五个窗口。

运行这段代码将得到以下结果:

[0 1 2 3 4]
[1 2 3 4 5]
[2 3 4 5 6]
[3 4 5 6 7]
[4 5 6 7 8]
[5 6 7 8 9]

但是之前您已经看到我们想要由此制作训练数据,其中有n 个值定义一个特征,随后的值给出一个标签。您可以通过添加另一个 lambda 函数来完成此操作,该函数将每个窗口拆分为最后一个值之前的所有内容,然后是最后一个值。这给出了一个x和一个y数据集,如下所示:

dataset = tf.data.Dataset.range(10)
dataset = dataset.window(5, shift=1, drop_remainder=True)
dataset = dataset.flat_map(lambda window: window.batch(5))
dataset = dataset.map(lambda window: (window[:-1], window[-1:]))
for x,y in dataset:
    print(x.numpy(), y.numpy())

结果现在符合您的预期。窗口中的前四个值可以被认为是特征,随后的值是标签:

[0 1 2 3] [4]
[1 2 3 4] [5]
[2 3 4 5] [6]
[3 4 5 6] [7]
[4 5 6 7] [8]
[5 6 7 8] [9]

而且因为这是一个数据集,它还可以支持通过洗牌和批处理拉姆达函数。在这里,它被洗牌并以 2 的批大小进行批处理:

dataset = tf.data.Dataset.range(10)
dataset = dataset.window(5, shift=1, drop_remainder=True)
dataset = dataset.flat_map(lambda window: window.batch(5))
dataset = dataset.map(lambda window: (window[:-1], window[-1:]))
dataset = dataset.shuffle(buffer_size=10)
dataset = dataset.batch(2).prefetch(1)
for x,y in dataset:
    print("x = ", x.numpy())
    print("y = ", y.numpy())

结果表明,第一批有两组x(分别从 2 和 3 开始)及其标签,第二批有两组x(分别从 1 和 5 开始)及其标签,依此类推:

x =  [[2 3 4 5]
 [3 4 5 6]]
y =  [[6]
 [7]]

x =  [[1 2 3 4]
 [5 6 7 8]]
y =  [[5]
 [9]]

x =  [[0 1 2 3]
 [4 5 6 7]]
y =  [[4]
 [8]]

使用这种技术,您现在可以将任何时间序列数据集转换为神经网络的一组训练数据。在下一节中,您将探讨如何从第 9 章中获取合成数据并从中创建训练集。从那里开始,您将继续创建一个简单的 DNN,该 DNN 根据此数据进行训练并可用于预测未来值。

创建时间序列数据集的窗口版本

作为回顾一下,这是上一章中用于创建合成时间序列数据集的代码:

def trend(time, slope=0):
    return slope * time

def seasonal_pattern(season_time):
    return np.where(season_time < 0.4,
                    np.cos(season_time * 2 * np.pi),
                    1 / np.exp(3 * season_time))

def seasonality(time, period, amplitude=1, phase=0):
    season_time = ((time + phase) % period) / period
    return amplitude * seasonal_pattern(season_time)

def noise(time, noise_level=1, seed=None):
    rnd = np.random.RandomState(seed)
    return rnd.randn(len(time)) * noise_level

time = np.arange(4 * 365 + 1, dtype="float32")
series = trend(time, 0.1)
baseline = 10
amplitude = 20
slope = 0.09
noise_level = 5

series = baseline + trend(time, slope) 
series += seasonality(time, period=365, amplitude=amplitude)
series += noise(time, noise_level, seed=42)

这将创建一个如图 10-1 所示的时间序列。如果您想更改它,请随意调整各种常量的值。

获得系列后,您可以使用类似于上一节中的代码将其转换为窗口数据集。在这里,它被定义为一个独立的函数:

def windowed_dataset(series, window_size, 
                      batch_size, shuffle_buffer):
    dataset = tf.data.Dataset.from_tensor_slices(series)
    dataset = dataset.window(window_size + 1, shift=1, 
                              drop_remainder=True)
    dataset = dataset.flat_map(lambda window: 
                                 window.batch(window_size + 1))
    dataset = dataset.shuffle(shuffle_buffer).map(
                             lambda window: 
                                 (window[:-1], window[-1]))
    dataset = dataset.batch(batch_size).prefetch(1)
    return dataset

请注意,它使用 的from_tensor_slices方法tf.data.Dataset,它允许您将系列转换为Dataset. 您可以在TensorFlow 文档中了解有关此方法的更多信息。

现在,要获得训练就绪的数据集,您只需使用以下代码即可。首先将系列分成训练和验证数据集,然后指定窗口大小、批量大小和随机缓冲区大小等详细信息:

split_time = 1000
time_train = time[:split_time]
x_train = series[:split_time]
time_valid = time[split_time:]
x_valid = series[split_time:]
window_size = 20
batch_size = 32
shuffle_buffer_size = 1000
dataset = windowed_dataset(x_train, window_size, batch_size, 
                           shuffle_buffer_size)

现在要记住的重要一点是你的数据是一个tf.data.Dataset,所以它可以很容易地model.fit作为一个参数传递给它并tf.keras会处理剩下的事情。

如果您想检查数据的外观,可以使用如下代码:

dataset = windowed_dataset(series, window_size, 1, shuffle_buffer_size)
for feature, label in dataset.take(1):
    print(feature)
    print(label)

这里将batch_size设置为1,只是为了使结果更具可读性。您最终会得到这样的输出,其中批处理中包含一组数据:

tf.Tensor(
[[75.38214  66.902626 76.656364 71.96795  71.373764 76.881065 75.62607
  71.67851  79.358665 68.235466 76.79933  76.764114 72.32991  75.58744
  67.780426 78.73544  73.270195 71.66057  79.59881  70.9117  ]], 
  shape=(1, 20), dtype=float32)
tf.Tensor([67.47085], shape=(1,), dtype=float32)

第一批数字是特征。我们将窗口大小设置为 20,因此它是一个1 × 20的张量。第二个数字是标签(在本例中为 67.47085),模型将尝试将特征拟合到该标签。您将在下一节中看到它是如何工作的。

创建和训练 DNN 以拟合序列数据

现在如果您拥有 a 中的数据,那么在其中tf.data.Dataset创建神经网络模型tf.keras就变得非常简单。让我们首先探索一个简单的 DNN,如下所示:

dataset = windowed_dataset(series, window_size, 
                            batch_size, shuffle_buffer_size)

model = tf.keras.models.Sequential([
    tf.keras.layers.Dense(10, input_shape=[window_size], 
                           activation="relu"), 
    tf.keras.layers.Dense(10, activation="relu"), 
    tf.keras.layers.Dense(1)
])

这是一个超级简单的模型,有两个密集层,第一个接受输入形状,window_size然后输出层将包含预测值。

和以前一样,该模型使用损失函数和优化器进行编译。在在这种情况下,损失函数指定为mse,它代表均方误差,常用于回归问题(这最终归结为!)。为了优化器sgd(随机梯度下降)非常适合。我不会在本书中详细介绍这些类型的函数,但任何关于机器学习的好资源都会教你它们——Andrew Ng 在 Coursera 上开创性的深度学习专业化是一个很好的起点。SGD 采用学习率 ( lr) 和动量参数,这些参数调整优化器的学习方式。每个数据集都是不同的,所以最好有控制权。在下一节中,您将看到如何找出最佳值,但现在,只需像这样设置它们:

model.compile(loss="mse",optimizer=tf.keras.optimizers.SGD(
                                                          lr=1e-6, 
                                                          momentum=0.9))

然后,训练就变得像调用 一样简单model.fit,将您的数据集传递给它,并指定要训练的时期数:

model.fit(dataset,epochs=100,verbose=1)

在训练时,您会看到损失函数报告的数字开始很高,但会稳步下降。这是前 10 个时期的结果:

Epoch 1/100
45/45 [==============================] - 1s 15ms/step - loss: 898.6162
Epoch 2/100
45/45 [==============================] - 0s 8ms/step - loss: 52.9352
Epoch 3/100
45/45 [==============================] - 0s 8ms/step - loss: 49.9154
Epoch 4/100
45/45 [==============================] - 0s 7ms/step - loss: 49.8471
Epoch 5/100
45/45 [==============================] - 0s 7ms/step - loss: 48.9934
Epoch 6/100
45/45 [==============================] - 0s 7ms/step - loss: 49.7624
Epoch 7/100
45/45 [==============================] - 0s 8ms/step - loss: 48.3613
Epoch 8/100
45/45 [==============================] - 0s 9ms/step - loss: 49.8874
Epoch 9/100
45/45 [==============================] - 0s 8ms/step - loss: 47.1426
Epoch 10/100
45/45 [==============================] - 0s 8ms/step - loss: 47.5133

评估 DNN 的结果

一次你有一个训练有素的 DNN,你可以开始用它进行预测。但请记住,您有一个窗口数据集,因此,对给定点的预测是基于它之前一定数量的时间步长的值。

换句话说,由于您的数据位于名为 的列表中series,要预测一个值,您必须将模型值从时间t传递到时间t + window_size。然后它将为您提供下一个时间步长的预测值。

例如,如果您想要预测时间步长 1,020 的值,您可以获取时间步长 1,000 到 1,019 的值,并使用它们来预测序列中的下一个值。要获取这些值,您可以使用以下代码(请注意,您将其指定为series[1000:1020],而不是series[1000:1019]!):

print(series[1000:1020])

然后,要获取第 1,020 步的值,您只需series[1020]像这样使用:

print(series[1020])

要获得对该数据点的预测,然后将系列传递给model.predict. 但是请注意,为了保持输入形状一致,您需要一个[np.newaxis],如下所示:

print(model.predict(series[1000:1020][np.newaxis]))

或者,如果你想要更通用的代码,你可以使用这个:

print(series[start_point:start_point+window_size])
print(series[start_point+window_size])
print(model.predict(
      series[start_point:start_point+window_size][np.newaxis]))

请注意,所有这些都假设窗口大小为 20 个数据点,这非常小。因此,您的模型可能会缺乏一些准确性。如果您想尝试不同的窗口大小,则需要通过再次调用该windowed_dataset函数重新格式化数据集,然后重新训练模型。

以下是该数据集以 1,000 为起点并预测下一个值时的输出:

[109.170746 106.86935  102.61668   99.15634  105.95478  104.503876
 107.08533  105.858284 108.00339  100.15279  109.4894   103.96404
 113.426094  99.67773  111.87749  104.26137  100.08899  101.00105
 101.893265 105.69048 ]

106.258606

[[105.36248]]

第一个张量包含值列表。接下来,我们看到实际的下一个值,即 106.258606。最后,我们看到预测的下一个值 105.36248。我们得到了一个合理的预测,但我们如何衡量随着时间的推移的准确性?我们将在下一节中进行探讨。

探索整体预测

在上一节中,您了解了如何通过基于窗口大小(在本例中为 20)获取前一组值并将它们传递给模型来获得给定时间点的预测。要查看模型的总体结果,您必须对每个时间步执行相同的操作。

你可以用这样一个简单的循环来做到这一点:

forecast = []
for time in range(len(series) - window_size):
    forecast.append(
        model.predict(series[time:time + window_size][np.newaxis]))

首先,您创建一个名为的新数组forecast,它将存储预测值。然后,对于原始系列中的每个时间步,您调用该predict方法并将结果存储在forecast数组中。您不能对数据中的前n 个元素执行此操作,其中nwindow_size,因为此时您将没有足够的数据来进行预测,因为每个预测都需要n 个先前值。

当此循环完成时,forecast数组将具有时间步长 21 之后的预测值。

如果您还记得的话,您还在时间步长 1,000 处将数据集拆分为训练集和验证集。因此,对于下一步,您也应该只从此时开始进行预测。由于您的预测数据已经偏离 20(或任何您的窗口大小),您可以将其拆分并将其转换为 Numpy 数组,如下所示:

forecast = forecast[split_time-window_size:]
results = np.array(forecast)[:, 0, 0]

它现在与预测数据的形状相同,因此您可以像这样将它们相互绘制:

plt.figure(figsize=(10, 6))

plot_series(time_valid, x_valid)
plot_series(time_valid, results)

该图将类似于图 10-3。

图 10-3。根据值绘制预测

通过快速目视检查,您可以看到预测不错。它通常遵循原始数据的曲线。当数据发生快速变化时,预测需要一点时间才能赶上,但总的来说还不错。

但是,在观察曲线时很难做到精确。最好有一个好的指标,在​​第 9 章中您已经了解了一个指标——MAE。现在您有了有效数据和结果,您可以使用以下代码测量 MAE:

tf.keras.metrics.mean_absolute_error(x_valid, results).numpy()

数据中引入了随机性,因此您的结果可能会有所不同,但当我尝试它时,我得到的 MAE 值为 4.51。

你可能会争辩说,让预测尽可能准确的过程就变成了最小化 MAE 的过程。您可以使用一些技术来执行此操作,包括明显更改窗口大小。我将留给您进行试验,但在下一节中,您将对优化器进行一些基本的超参数调整,以改进神经网络的学习方式,并查看这将对 MAE 产生什么影响。

调整学习率

在前面的示例中,您可能还记得您使用如下所示的优化器编译模型:

model.compile(loss="mse",
              optimizer=tf.keras.optimizers.SGD(lr=1e-6, momentum=0.9))

在这种情况下,您使用的学习率为 1 × 10 –6。但这似乎是一个非常随意的数字。如果你改变它呢?你应该如何改变它?需要进行大量实验才能找到最佳比率。

为您提供的一件事tf.keras是回调,可帮助您随时间调整学习率。您在第 2 章了解了回调——在每个纪元结束时调用的函数,当精度达到了期望值。

您还可以使用回调来调整学习率参数,绘制该参数的值与适当时期的损失的关系,并从那里确定要使用的最佳学习率。

为此,只需创建一个tf.keras.callbacks.LearningRateScheduler并让它lr用所需的起始值填充参数。这是一个例子:

lr_schedule = tf.keras.callbacks.LearningRateScheduler(
    lambda epoch: 1e-8 * 10**(epoch / 20))

在这种情况下,您将从 1e–8 开始学习率,然后每个时期都将其增加少量。当它完成一百个 epoch 时,学习率将达到大约 1e–3。

现在您可以使用 1e–8 的学习率初始化优化器,并指定您要在调用中使用此回调model.fit

optimizer = tf.keras.optimizers.SGD(lr=1e-8, momentum=0.9)
model.compile(loss="mse", optimizer=optimizer)
history = model.fit(dataset, epochs=100, 
                     callbacks=[lr_schedule], verbose=0)

正如您使用history=model.fit的那样,训练历史为您存储,包括损失。然后,您可以将其与每个时期的学习率作图,如下所示:

lrs = 1e-8 * (10 ** (np.arange(100) / 20))
plt.semilogx(lrs, history.history["loss"])
plt.axis([1e-8, 1e-3, 0, 300])

这个只需lrs使用与 lambda 函数相同的公式设置值,并将其与 1e-8 和 1e-3 之间的损失进行对比。图 10-4显示了结果。

图 10-4。绘制损失与学习率

因此,虽然之前您将学习率设置为 1e–6,但看起来 1e–5 的损失较小,因此现在您可以返回模型并使用 1e–5 重新定义它作为新的学习率。

训练模型后,您可能会注意到损失有所减少。就我而言,学习率为 1e-6 时,我的最终损失为 36.5,但学习率为 1e-5 时,它减少到 32.9。然而,当我对所有数据进行预测时,结果是图 10-5中的图表,如您所见,它看起来有点偏差。

图 10-5。具有调整后学习率的图表

 而当我测量 MAE 时,它最终为 4.96,所以它退步了一小步!话虽这么说,一旦知道自己拥有最佳学习率,就可以开始探索其他方法来优化网络性能。一个简单的起点是窗口的大小——20 天的数据预测 1 天可能不够,所以您可能想尝试 40 天的窗口。另外,尝试训练更多的时代。通过一些实验,您可以获得接近 4 的 MAE,这还不错。

使用 Keras Tuner 探索超参数调整

在上一节中,您了解了如何对随机梯度下降损失函数的学习率进行粗略优化。这当然是一项非常艰巨的工作,每隔几个时期改变学习率并测量损失。它也受到损失函数已经存在的事实的影响将 epoch 更改为 epoch,因此您实际上可能没有找到最佳值,而是一个近似值。要真正找到最佳值,您必须用每个潜在值训练完整的 epoch 集,然后比较结果。这只是一个超参数,学习率。如果你想找到最好的动量,或者调整其他东西,比如模型架构——每层有多少神经元,有多少层等等——你最终可以有成千上万的选项来测试,并且对所有这些进行训练很难编码。

幸运的是,Keras Tuner 工具使这变得相对容易。pip您可以使用一个简单的命令安装 Keras Tuner :

!pip install keras-tuner

然后,您可以使用它来参数化您的超参数,指定要测试的值范围。Keras Tuner 将训练多个模型,一个模型具有每组可能的参数,根据您想要的指标评估模型,然后报告最佳模型。我不会在这里详细介绍该工具提供的所有选项,但我将向您展示如何将它用于该特定模型。

假设我们只想试验两件事,第一件事是模型架构中输入神经元的数量。一直以来,您都有一个包含 10 个输入神经元的模型架构,然后是 10 个隐藏层,然后是输出层。但是网络可以做得更好吗?例如,如果您可以在输入层中试验多达 30 个神经元会怎么样?

回想一下输入层是这样定义的:

tf.keras.layers.Dense(10, input_shape=[window_size], activation="relu"),

如果你想测试不同于硬编码 10 的值,你可以将它设置为循环遍历多个整数,如下所示:

tf.keras.layers.Dense(units=hp.Int('units', min_value=10, max_value=30, step=2), 
                      activation='relu', input_shape=[window_size])

在这里,您定义该层将使用多个输入值进行测试,从 10 开始,以 2 为步长增加到 30。现在,Keras Tuner 将训练模型 11 次,而不是只训练一次模型并看到损失!

此外,当您编译模型时,您将momentum参数的值硬编码为0.9. 从模型定义中回忆这段代码:

optimizer = tf.keras.optimizers.SGD(lr=1e-5, momentum=0.9)

您可以将其更改为通过几个选项循环,而不是使用hp.Choice构造。这是一个例子:

optimizer=tf.keras.optimizers.SGD(hp.Choice('momentum', 
                                  values=[.9, .7, .5, .3]), 
                                  lr=1e-5)

这提供了四种可能的选择,因此,当结合之前定义的模型架构时,您将最终循环通过 44 种可能的组合。Keras Tuner 可以为您完成这项工作,并报告表现最好的模型。

要完成此设置,首先创建一个为您构建模型的函数。这是一个更新的模型定义:

def build_model(hp):
    model = tf.keras.models.Sequential()
    model.add(tf.keras.layers.Dense(
       units=hp.Int('units', min_value=10, max_value=30, step=2), 
                   activation='relu', input_shape=[window_size]))
    model.add(tf.keras.layers.Dense(10, activation='relu'))
    model.add(tf.keras.layers.Dense(1))

    model.compile(loss="mse", 
                  optimizer=tf.keras.optimizers.SGD(hp.Choice('momentum', 
                                                 values=[.9, .7, .5, .3]), 
                                                 lr=1e-5))

    return model

现在,安装 Keras Tuner 后,您可以创建一个RandomSearch对象来管理该模型的所有迭代:

tuner = RandomSearch(build_model, 
                     objective='loss', max_trials=150, 
                     executions_per_trial=3, directory='my_dir', 
                     project_name='hello')

请注意,您通过将模型传递给您之前描述的函数来定义模型。超参数参数 ( hp) 用于控制更改哪些值。您将 指定objectiveloss,表明您希望最小化损失。您可以使用该参数限制要运行的试验总数max_trials,并指定使用该参数训练和评估模型的次数(在某种程度上消除随机波动)executions_per_trial

要开始搜索,您只需tuner.search像往常一样调用model.fit。这是代码:

tuner.search(dataset, epochs=100, verbose=0)

使用您在本章中一直在研究的合成系列运行它,然后将根据您对要尝试的选项的定义使用每个可能的超参数训练模型。

完成后,您可以调用tuner.results_summary它,它会根据目标为您提供前 10 项试验:

tuner.results_summary()

你应该看到这样的输出:

Results summary
|-Results in my_dir/hello
|-Showing 10 best trials
|-Objective(name='loss', direction='min')
Trial summary
|-Trial ID: dcfd832e62daf4d34b729c546120fb14
|-Score: 33.18723194615371
|-Best step: 0
Hyperparameters:
|-momentum: 0.5
|-units: 28
Trial summary
|-Trial ID: 02ca5958ac043f6be8b2e2b5479d1f09
|-Score: 33.83273440510237
|-Best step: 0
Hyperparameters:
|-momentum: 0.7
|-units: 28

从结果中可以看出,最佳损失分数是在动量为 0.5 和 28 个输入单元时获得的。您可以通过调用并指定您想要的数量来检索此模型和其他顶级模型get_best_models——例如,如果您想要前四名模型,您可以这样调用它:

tuner.get_best_models(num_models=4)

然后您可以测试这些模型。

或者,您可以使用学习到的超参数从头开始创建一个新模型,如下所示:

dataset = windowed_dataset(x_train, window_size, batch_size, 
                           shuffle_buffer_size)

model = tf.keras.models.Sequential([
    tf.keras.layers.Dense(28, input_shape=[window_size], 
                           activation="relu"), 
    tf.keras.layers.Dense(10, activation="relu"), 
    tf.keras.layers.Dense(1)
])

optimizer = tf.keras.optimizers.SGD(lr=1e-5, momentum=0.5)
model.compile(loss="mse", optimizer=optimizer)
history = model.fit(dataset, epochs=100,  verbose=1)

当我使用这些超参数进行训练,并像之前一样对整个验证集进行预测时,我得到了一个如图 10-6 所示的图表。

图 10-6。具有优化超参数的预测图

对此的 MAE 计算得出 4.47,这比原来的 4.51 略有改进,但比上一章的统计方法得到的结果 5.13 有了很大改进。这是在学习率更改为 1e-5 的情况下完成的,这可能不是最佳的。使用 Keras Tuner,您可以调整超参数,调整中间层的神经元数量,甚至可以试验不同的损失函数和优化器。试一试,看看你是否可以改进这个模型!

概括

在本章中,您对第 9 章中的时间序列进行了统计分析,并应用机器学习来尝试更好地进行预测。机器学习实际上就是模式匹配,正如预期的那样,您能够将平均误差降低近 10%,方法是首先使用深度神经网络来发现模式,然后使用 Keras Tuner 进行超参数调整来改进损失并提高准确率。在第 11 章中,您将超越简单的 DNN 并检查使用循环神经网络预测序列值的含义。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/96249.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL底层索引

目录 一、什么是索引&#xff1f; 二、MySQL索引结构分析【MySQL底层采用的是BTree】 1、为什么不使用二叉树&#xff1f; 2、为什么不使用红黑树&#xff1f; 3、为什么不使用Hash&#xff1f; 4、BTree与B-Tree的区别&#xff1f; 三、MySQL数据库的表结构、索引、数据 1、M…

基于Sharfetter-Gummel和改进的Sharfetter-Gummel计算对流扩散方程的通量(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客 &#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜…

1. Arthas的命令

万恶淫为首&#xff0c;百善孝为先 Arthas命令 可以查看相应的文档: https://arthas.aliyun.com/doc/命令.html 如: https://arthas.aliyun.com/doc/grep.html https://arthas.aliyun.com/doc/cat.html 基础命令 help 查看命令帮助信息 cat 查看当前arthas 系统中的任意文件…

【算法】八月算法打卡

2022-08-01 低配版 promise class MyPromise {constructor(executor) {// 成功回调队列this._resolveQueue [];// 失败回调队列this._rejectQueue [];let resolve (val) > {while (this._resolveQueue.length) {const callback this._resolveQueue.shift();callback(v…

【iOS】对象,消息,运行期

文章目录对象&#xff0c;消息&#xff0c;运行期属性属性特质原子性方法名在对象内部尽量直接访问实例变量对象等同性特定类所具有的等同性判断等同性判定的执行深度容器中可变类的等同性以“类族模式”隐藏实现细节创建类族Cocoa里的类族在既有类中使用关联对象存放自定义数据…

原型,原型链,原型的继承

原型的作用? 1.节省内存空间 2.实现数据共享(继承) 什么是原型? 任何一个函数都有propotype属性,它本身是一个对象,我们称之为原型 构造函数,实例化对象与原型之间的关系? 1.任何一个函数都有prototype属性,它本身是一个对象,我们称之为原型 2.构造函数也是函数,也都…

C语言中头文件(.h)编写,头文件的包含<>和““很大不同

头文件书写技巧 1、头文件主要作用&#xff0c;提前声明函数&#xff0c;因为在c语言中必须先声明或定义才能使用 2、在使用到.c文件中需要把这个.h文件进行包含格式是#include <h文件>或#include "h文件名"&#xff0c;但**强烈建议用引号**&#xff0c;尖括…

【码极客精讲】do while语句

上次讲了while语句&#xff0c;这次讲一下do while语句。 do...while 循环是 while 循环的变体。在检查while()条件是否为真之前&#xff0c;该循环首先会执行一次do{}之内的语句&#xff0c;然后在while()内检查条件是否为真&#xff0c;如果条件为真的话&#xff0c;就会重复…

binder调用流程分析

binder是一个非常好的跨进程通信工具&#xff0c;Android对其进行了各种封装&#xff0c;虽然我们用起来简单&#xff0c;但是理解起来却比较困难。 1.自己设计一个跨进程通信机制 在理解binder之前呢&#xff0c;首先我们想一下&#xff0c;如果我们自己设计一个跨进程通信的…

关于树形dp问题的解决

文章目录解决套路案例展示一、二叉树的最大深度二、判断是不是平衡二叉树三、判断是不是二叉搜索树四、判断是否是满二叉树五、二叉树节点间的最大距离六、派对的最大快乐值解决套路 实际上就是设计一个递归函数&#xff0c;该递归函数一定要包含 basecase&#xff0c;即让函数…

[附源码]Python计算机毕业设计高校选课系统Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等…

[附源码]Python计算机毕业设计共享自习室管理系统Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等…

【C++】STL-string的使用

文章目录1.为什么学习string类&#xff1f;1.1 C语言中的字符串OJ题目1&#xff1a;字符串相加2.标准库中的string类2.1 string类(了解)总结&#xff1a;2.2 string类的常用接口说明1. string类对象的常见构造2.string类对象的容量操作max_sizereserve和resize3. string类对象的…

Spirng 痛苦源码学习(三)——Spring中的几个核心老大

文章目录前言一、基础接口1.Resource2.ResourceLoader3.BeanFactory&#xff08;1&#xff09;总览&#xff08;2&#xff09;继承如下&#xff08;3&#xff09;重要的工厂4. ApplicationContext前言 一开始学习spring我们首先还是要搞清楚他的整体架构&#xff0c;就是他是干…

[附源码]Node.js计算机毕业设计互联网教学平台Express

项目运行 环境配置&#xff1a; Node.js最新版 Vscode Mysql5.7 HBuilderXNavicat11Vue。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分离等等。 环境需要 1.运行环境&#xff1a;最好是Nodejs最新版&#xff0c;我…

C++ Reference: Standard C++ Library reference: Containers: map: multimap: end

C官网参考链接&#xff1a;https://cplusplus.com/reference/map/multimap/end/ 公有成员函数 <map> std::multimap::end C98 iterator end(); const_iterator end() const; C11 iterator end() noexcept; const_iterator end() const noexcept;返回指向结束的iterator …

HTTP简介(GET,POST)

HTTP简介(GET,POST) 简介 HyperText Transfer Protocol&#xff0c;超文本传输协议&#xff0c;规定了浏览器和服务器之间数据传输的规则。 演示 HTTP协议的特点 基于TCP协议: 面向连接&#xff0c;安全 TCP是一种面向连接的(建立连接之前是需要经过三次握手)、可靠的、基于…

[附源码]Python计算机毕业设计SSM基于Java家庭财务管理系统(程序+LW)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

LeetCode 297. 二叉树的序列化与反序列化

今天早上睡起来刷了这么一道题&#xff0c;二叉树的序列化和反序列化 大概意思就是给你一个二叉树&#xff0c;把他转成一个字符串&#xff0c;中间的自定义规则由你定&#xff0c;再根据这个字符串去还原这个二叉树&#xff0c;这道题的话思路不难&#xff0c;写起来有的细节…

【云原生 | Kubernetes 实战】13、K8s 常见的存储方案及具体应用场景分析(上)

目录 K8s 持久化存储 一、k8s 持久化存储&#xff1a;emptyDir 二、k8s 持久化存储&#xff1a;hostPath 三、k8s 持久化存储&#xff1a;nfs 3.1 搭建 nfs 服务 3.2 创建Pod&#xff0c;挂载 NFS 共享出来的目录 3.3 测试 pod 挂载 nfs 是否成功 K8s 持久化存储 在 k8s…