Keras中的深度学习-建立深度学习模型

Deep Learning in Keras - Building a Deep Learning Model

介绍

深度学习是当前人工智能(AI)和机器学习中最有趣和最有前途的领域之一。 近年来,随着技术和算法的巨大进步,深度学习为AI应用的新时代打开了大门。

在许多此类应用中,深度学习算法的性能与人类专家相当,有时甚至超过了专家。

Python已成为机器学习的首选语言,并且许多最流行,功能最强大的深度学习库和框架(例如TensorFlow,Keras和PyTorch)都是用Python构建的。

在本系列中,我们将使用Keras进行探索性数据分析(EDA),数据预处理,最后构建一个深度学习模型并对其进行评估。

在这个阶段,我们将建立一个深度神经网络模型,我们将对其进行训练,然后将其用于预测房价。

定义模型

深度学习神经网络只是具有许多隐藏层的神经网络。

定义模型可以分为几个特征:

  • 层数

  • 这些层的类型

  • 每层中的单元(神经元)数

  • 各层的激活功能

  • 输入输出尺寸

  • 深度学习层

    深度学习模型有很多类型的层。 卷积层和池化层用于对图像进行分类或对象检测的CNN中,而递归层用于自然语言处理和语音识别中常见的RNN中。

    我们将使用Dense和Dropout层。 密集层是最常见和最受欢迎的层类型-它只是常规的神经网络层,其中每个神经元都与上一层和下一层的神经元相连。

    每个密集层都有一个激活功能,可以根据输入和突触的权重来确定其神经元的输出。

    辍学层只是正则化层,它们将一些输入单元随机地降低为0。这有助于减少过度拟合神经网络的机会。

    激活功能

    还可以将许多类型的激活功能应用于图层。 它们每个都以不同的方式链接神经元的输入和权重,并使网络的行为不同。

    真正常见的功能是ReLU(整流线性单元),Sigmoid函数和线性函数。 我们将混合几个不同的功能。

    输入和输出层

    除了隐藏层,模型还具有输入层和输出层:

    deep learning neural network architecture

    输入层中神经元的数量与我们数据中要素的数量相同。 我们想教网络对这些功能做出反应。 我们在train_dftest_df数据框中具有67个特征-因此,我们的输入层将具有67个神经元。 这些将成为我们数据的切入点。

    对于输出层-神经元的数量取决于您的目标。 由于我们只是在预测价格-一个单一的值,因此我们将仅使用一个神经元。 分类模型将具有class个输出神经元。

    由于模型的输出将是一个连续的数字,因此我们将使用linear激活函数,因此不会截断任何值。

    定义模型代码

    我们将在前面的代码中使用一些导入:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    import matplotlib.pyplot as plt
    from matplotlib import ticker
    import numpy as np
    import pandas as pd
    import seaborn as sns

    import tensorflow as tf
    from tensorflow import keras
    from tensorflow.keras import layers

    考虑到这些导入和参数,让我们使用Keras定义模型:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    model = keras.Sequential([
        layers.Dense(64, activation='relu', input_shape=[train_df.shape[1]]),
        layers.Dropout(0.3, seed=2),
        layers.Dense(64, activation='swish'),
        layers.Dense(64, activation='relu'),
        layers.Dense(64, activation='swish'),
        layers.Dense(64, activation='relu'),
        layers.Dense(64, activation='swish'),
        layers.Dense(1)
    ])

    在这里,我们使用Keras的Sequential()实例化模型。 它需要一组顺序的层,并将它们堆叠在一起成为一个模型。 进入Sequential()构造函数,我们传递一个包含要在模型中使用的图层的列表。

    在此模型中,我们制作了几个Dense层和一个Dropout层。 我们使input_shape等于数据中的要素数量。 我们在第一层上将其定义为该层的输入。

    每层有64个神经元。 这通常取决于测试-每层放置更多的神经元将有助于提取更多特征,但是有时这些特征也可能对您不利。 经过一些测试,在此示例中,每层64个神经元产生了相当准确的结果。 强烈建议您使用数字!

    为了避免过度拟合,我们迅速删除了30%的输入数据。 seed设置为2,因此我们可以获得更可重复的结果。 如果我们只是完全随机地丢弃它们,则每个模型都会有所不同。

    最后,我们有一个Dense层,其中单个神经元作为输出层。 默认情况下,它具有linear激活功能,因此我们没有进行任何设置。

    编译模型

    定义模型后,下一步是对其进行编译。 编译Keras模型意味着对其进行配置以进行训练。

    要编译模型,我们需要选择:

  • 损失函数-误差越小,模型越接近目标。 不同的问题需要不同的损失函数来跟踪进度。 这是受支持的损失函数的列表。

  • 优化器-帮助我们获得损失函数更好结果的优化算法。

  • 指标-用于评估模型的指标。 例如,如果我们具有均方误差损失函数,则使用均绝对误差作为用于评估的度量是有意义的。

  • 考虑到这些,让我们编译模型:

    1
    2
    3
    4
    5
    optimizer = tf.keras.optimizers.RMSprop(learning_rate=0.001)

    model.compile(loss=tf.keras.losses.MeanSquaredError(),
                  optimizer=optimizer,
                  metrics=['mae'])

    在这里,我们创建了一个RMSprop优化器,学习速率为0.001。 随意尝试使用其他优化器,例如Adam优化器。

    注意:您可以声明优化器并使用该对象,也可以在compile()方法中传递它的字符串表示形式。

    我们将损失函数设置为均方误差。 同样,请随意尝试其他损失函数并评估结果。 由于我们将MSE作为损失函数,因此我们选择了"平均绝对误差"作为评估模型的指标。

    训练模型

    编译模型后,我们可以使用我们的train_df数据集对其进行训练。 这可以通过fit()函数进行拟合来完成:

    1
    2
    3
    4
    history = model.fit(
        train_df, train_labels,
        epochs=70, validation_split=0.2
    )

    在这里,我们传递了训练数据(train_df)和训练标签(train_labels)。

    同样,学习是一个反复的过程。 我们已通知网络,该网络要遍历该训练数据集70次,以从中学习尽可能多的信息。 在最后一个时期的模型结果将比在第一个时期更好。

    最后,我们传递用于验证的训练数据。 具体来说,我们告诉它使用训练数据的0.2(20%)来验证结果。 请勿将其与用于评估它的test_df数据集混淆。

    这20%不会用于培训,而是用于验证以确保其取得进展。

    此函数将打印每个时期的结果-损失函数的值以及我们选择要跟踪的度量。

    完成后,我们可以看一下每个时期的完成情况:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    Epoch 65/70
    59/59 [==============================] - 0s 2ms/step - loss: 983458944.0000 - mae: 19101.9668 - val_loss: 672429632.0000 - val_mae: 18233.3066
    Epoch 66/70
    59/59 [==============================] - 0s 2ms/step - loss: 925556032.0000 - mae: 18587.1133 - val_loss: 589675840.0000 - val_mae: 16720.8945
    Epoch 67/70
    59/59 [==============================] - 0s 2ms/step - loss: 1052588800.0000 - mae: 18792.9805 - val_loss: 608930944.0000 - val_mae: 16897.8262
    Epoch 68/70
    59/59 [==============================] - 0s 2ms/step - loss: 849525312.0000 - mae: 18392.6055 - val_loss: 613655296.0000 - val_mae: 16914.1777
    Epoch 69/70
    59/59 [==============================] - 0s 2ms/step - loss: 826159680.0000 - mae: 18177.8945 - val_loss: 588994816.0000 - val_mae: 16520.2832
    Epoch 70/70
    59/59 [==============================] - 0s 2ms/step - loss: 920209344.0000 - mae: 18098.7070 - val_loss: 571053952.0000 - val_mae: 16419.8359

    训练后,该模型(存储在model变量中)将了解其功能并可以进行预测。 fit()还会在每个时期之后返回包含损失函数值和mae值的字典,因此我们也可以使用它。 我们将其放在history变量中。

    在进行预测之前,让我们直观地看到损失值和mae随时间的变化:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    model_history = pd.DataFrame(history.history)
    model_history['epoch'] = history.epoch

    fig, ax = plt.subplots(figsize=(14,8))
    num_epochs = model_history.shape[0]
    ax.plot(np.arange(0, num_epochs), model_history["mae"],
            label="Training MAE", lw=3, color='#f4b400')
    ax.plot(np.arange(0, num_epochs), model_history["val_mae"],
            label="Validation MAE", lw=3, color='#0f9d58')
    ax.legend()
    plt.tight_layout()
    plt.show()

    mae and loss function over time and training

    我们可以清楚地看到mae和损耗值随时间下降。 这正是我们想要的-随着时间的推移,模型的预测变得更加准确。

    用模型进行预测

    现在我们的模型已经训练完毕,让我们使用它来进行一些预测。 我们从测试数据中提取一个项目(在test_df中):

    1
    test_unit = test_df.iloc[[0]]

    为简便起见,存储在test_unit中的此项具有以下值,仅在7个条目中进行了裁剪:

    这些是要素单元的值,我们将使用该模型预测其售价:

    1
    test_pred = model.predict(test_unit).squeeze()

    我们使用模型的predict()函数,并将test_unit传递给它来预测目标变量-销售价格。

    注意:predict()返回一个NumPy数组,因此我们使用了squeeze(),这是一个NumPy函数,用于"压缩"该数组,并以数字而不是数组的形式获取预测值。

    现在,让我们从test_labels获取单位的实际价格:

    1
    test_lbl = test_labels.iloc[0]

    现在,让我们比较一下预测价格和实际价格:

    1
    2
    print("Model prediction = {:.2f}".format(test_pred))
    print("Actual value = {:.2f}".format(test_lbl))

    1
    2
    Model prediction = 225694.92
    Actual value = 212000.00

    因此,此单元的实际销售价格为212,000美元,我们的模型预测为$ * 225,694 *。 尽管该型号的价格超过了5%,但价格已经相当接近。

    让我们尝试test_df中的另一个单元:

    1
    test_unit = test_df.iloc[[100]]

    我们将重复相同的过程以比较价格:

    1
    2
    3
    4
    test_pred = model.predict(test_unit).squeeze()
    test_lbl = test_labels.iloc[100]
    print("Model prediction = {:.2f}".format(test_pred))
    print("Actual value = {:.2f}".format(test_lbl))

    1
    2
    Model prediction = 330350.47
    Actual value = 340000.00

    因此,对于该单元,实际价格为$ 340,000,而预测价格为?* $ 330,350 *。 再说一次,不是很准确,但这只是约3%的误差。 那是非常准确的。

    评估模型

    这是我们构建Keras深度学习模型的旅程的最后阶段。 在此阶段,我们将使用模型在测试数据(test_df)中的所有单位上生成预测,然后通过将这些预测与实际真实值(test_labels)进行比较来计算这些预测的平均绝对误差。

    Keras提供了evaluate()函数,我们可以将其与模型一起使用来对其进行评估。 evaluate()计算损失值以及我们在编译模型时选择的所有指标的值。

    我们选择MAE作为我们的指标,因为它很容易解释。 MAE值表示模型误差的平均值:
    $$
    egin {equation *}
    ext {MAE}(y,hat {y})= rac {1} {n} sum_ {i = 1} ^ {n} left | y_i-帽子{y} _i
    ight |。
    结束{equation *}
    $$

    为了我们的方便,evaluate()函数为我们解决了这一问题:

    1
    loss, mae = model.evaluate(test_df, test_labels, verbose=0)

    对于这种方法,我们传递模型的测试数据(待评估)和实际数据(进行比较)。 此外,我们使用了verbose参数来避免打印不需要的任何其他数据。

    让我们运行代码,看看它是如何工作的:

    1
    print('MAE = {:.2f}'.format(mae))

    1
    MAE = 17239.13

    平均绝对误差为17239.13。 也就是说,对于所有单位,该模型平均预测的实际价格为高于或低于实际价格17239美元。

    解释模型性能

    结果有多好? 如果我们回顾在SalePrice上完成的EDA,我们可以看到原始数据中这些单元的平均销售价格为$ 180,796。 也就是说,MAE为17,239相当不错。

    为了用另一种方式解释这些结果,让我们将预测与实际价格作图:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    test_predictions_ = model.predict(test_df).flatten()
    test_labels_ = test_labels.to_numpy().flatten()
    fig, ax = plt.subplots(figsize=(14,8))
    plt.scatter(test_labels_, test_predictions_, alpha=0.6,
                color='#ff7043', lw=1, ec='black')
    lims = [0, max(test_predictions_.max(), test_labels_.max())]
    plt.plot(lims, lims, lw=1, color='#00acc1')
    plt.tight_layout()
    plt.show()

    actual vs predicted values

    如果我们的模型在0 MAE情况下是100%准确的,则所有点都将精确显示在对角青色线上。 但是,没有一个模型是100%准确的,并且我们可以看到大多数点都靠近对角线,这意味着预测值接近于实际值。

    有一些离群值,其中一些离得很远。 这些使我们模型的平均MAE大大提高。 实际上,对于这些要点中的大多数而言,MAE远小于17,239。

    我们可以检查这些点并找出是否可以执行更多数据预处理和特征工程,以使模型更准确地预测它们。

    结论

    在本教程中,我们使用Keras构建了一个深度学习模型,对其进行了编译,并使用我们准备的干净数据进行了拟合,最后-根据所学知识进行了预测。

    尽管不是100%准确,但我们设法以少量异常值获得了非常不错的结果。