为新的数据集开发神经网络预测模型可能具有挑战性。
一种方法是首先检查数据集并构思可能适用的模型,然后探索简单模型在数据集上的学习动态,最后使用健壮的测试框架开发和调整模型以适应数据集。
这个过程可以用于开发有效的神经网络模型,用于分类和回归预测建模问题。
在本教程中,您将学习如何为电离层二元分类数据集开发多层感知器(MLP)神经网络模型。
完成本教程后,您将了解:
- 如何加载和总结电离层数据集,并利用这些结果来建议数据准备和模型配置。
- 如何探索简单MLP模型在数据集上的学习动态。
- 如何开发稳健的模型性能估计,调整模型性能,并在新数据上进行预测。
让我们开始吧。

如何开发神经网络来预测电离层扰动
照片作者:Sergey Pesterev,部分权利保留。
教程概述
本教程分为四个部分;它们是
- 电离层二元分类数据集
- 神经网络学习动态
- 评估和调整 MLP 模型
- 最终模型及预测
电离层二元分类数据集
第一步是定义和探索数据集。
我们将使用“电离层”标准二元分类数据集。
该数据集涉及根据雷达回波预测一个结构是否在电离层中。
你可以在此处了解更多关于此数据集的信息:
您可以在下方看到数据集的前几行。
1 2 3 4 5 6 |
1,0,0.99539,-0.05889,0.85243,0.02306,0.83398,-0.37708,1,0.03760,0.85243,-0.17755,0.59755,-0.44945,0.60536,-0.38223,0.84356,-0.38542,0.58212,-0.32192,0.56971,-0.29674,0.36946,-0.47357,0.56811,-0.51171,0.41078,-0.46168,0.21266,-0.34090,0.42267,-0.54487,0.18641,-0.45300,g 1,0,1,-0.18829,0.93035,-0.36156,-0.10868,-0.93597,1,-0.04549,0.50874,-0.67743,0.34432,-0.69707,-0.51685,-0.97515,0.05499,-0.62237,0.33109,-1,-0.13151,-0.45300,-0.18056,-0.35734,-0.20332,-0.26569,-0.20468,-0.18401,-0.19040,-0.11593,-0.16626,-0.06288,-0.13738,-0.02447,b 1,0,1,-0.03365,1,0.00485,1,-0.12062,0.88965,0.01198,0.73082,0.05346,0.85443,0.00827,0.54591,0.00299,0.83775,-0.13644,0.75535,-0.08540,0.70887,-0.27502,0.43385,-0.12062,0.57528,-0.40220,0.58984,-0.22145,0.43100,-0.17365,0.60436,-0.24180,0.56045,-0.38238,g 1,0,1,-0.45161,1,1,0.71216,-1,0,0,0,0,0,0,-1,0.14516,0.54094,-0.39330,-1,-0.54467,-0.69975,1,0,0,1,0.90695,0.51613,1,1,-0.20099,0.25682,1,-0.32382,1,b 1,0,1,-0.02401,0.94140,0.06531,0.92106,-0.23255,0.77152,-0.16399,0.52798,-0.20275,0.56409,-0.00712,0.34395,-0.27457,0.52940,-0.21780,0.45107,-0.17813,0.05982,-0.35575,0.02309,-0.52879,0.03286,-0.65158,0.13290,-0.53206,0.02431,-0.62197,-0.05707,-0.59573,-0.04608,-0.65697,g ... |
我们可以看到所有值都是数值型的,并且可能在 [-1, 1] 的范围内。这表明可能不需要任何类型的缩放。
我们还可以看到标签是字符串(“g”和“b”),这表明在拟合模型之前,需要将这些值编码为 0 和 1。
我们可以直接从 URL 将数据集加载为 pandas DataFrame;例如:
1 2 3 4 5 6 7 8 |
# 加载电离层数据集并总结其形状 from pandas import read_csv # 定义数据集位置 url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/ionosphere.csv' # 加载数据集 df = read_csv(url, header=None) # 总结形状 print(df.shape) |
运行示例将直接从 URL 加载数据集并报告数据集的形状。
在这种情况下,我们可以看到数据集有 35 个变量(34 个输入变量和一个输出变量),并且数据集包含 351 行数据。
对于神经网络来说,这并不算很多行数据,这表明使用小型网络,可能带有正则化,会是比较合适的。
考虑到单个模型拟合只需要几秒钟(而不是最耗时的数据集需要数小时或数天),这还表明使用k 折交叉验证会是一个好主意,因为它可以提供比训练/测试分割更可靠的模型性能估计。
1 |
(351, 35) |
接下来,我们可以通过查看摘要统计信息和数据图来进一步了解数据集。
1 2 3 4 5 6 7 8 9 10 11 12 |
# 显示电离层数据集的统计摘要和图表 from pandas import read_csv from matplotlib import pyplot # 定义数据集位置 url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/ionosphere.csv' # 加载数据集 df = read_csv(url, header=None) # 显示摘要统计信息 print(df.describe()) # plot histograms df.hist() pyplot.show() |
运行示例首先加载数据,然后打印每个变量的摘要统计信息。
我们可以看到每个变量的平均值在十位数,取值范围在 -1 到 1 之间。这证实了数据缩放可能不是必需的。
1 2 3 4 5 6 7 8 9 |
0 1 2 ... 31 32 33 count 351.000000 351.0 351.000000 ... 351.000000 351.000000 351.000000 mean 0.891738 0.0 0.641342 ... -0.003794 0.349364 0.014480 std 0.311155 0.0 0.497708 ... 0.513574 0.522663 0.468337 min 0.000000 0.0 -1.000000 ... -1.000000 -1.000000 -1.000000 25% 1.000000 0.0 0.472135 ... -0.242595 0.000000 -0.165350 50% 1.000000 0.0 0.871110 ... 0.000000 0.409560 0.000000 75% 1.000000 0.0 1.000000 ... 0.200120 0.813765 0.171660 max 1.000000 0.0 1.000000 ... 1.000000 1.000000 1.000000 |
然后为每个变量创建直方图。
我们可以看到许多变量具有高斯或类高斯分布。
使用幂变换可能对每个变量有益,以使概率分布不那么偏斜,这可能会提高模型性能。

电离层分类数据集的直方图
现在我们熟悉了数据集,让我们探索一下如何开发神经网络。
神经网络学习动态
我们将使用 TensorFlow 为数据集开发多层感知机 (MLP) 模型。
我们无法知道什么模型架构或学习超参数最适合这个数据集,因此我们必须进行实验和探索,找出有效的方法。
考虑到数据集较小,使用较小的批量大小可能是个好主意,例如 16 或 32 行。使用随机梯度下降的 Adam 版本在开始时是个好主意,因为它会自动适应学习率,并且在大多数数据集上效果很好。
在我们认真评估模型之前,最好回顾学习动态并调整模型架构和学习配置,直到我们获得稳定的学习动态,然后再考虑如何充分利用模型。
我们可以通过使用简单的训练/测试分割来做到这一点,并查看学习曲线的图表。这将帮助我们了解我们是过度学习还是学习不足;然后我们可以相应地调整配置。
首先,我们必须确保所有输入变量都是浮点值,并将目标标签编码为整数值 0 和 1。
1 2 3 4 5 |
... # 确保所有数据都是浮点值 X = X.astype('float32') # 将字符串编码为整数 y = LabelEncoder().fit_transform(y) |
接下来,我们可以将数据集分割为输入和输出变量,然后分割为 67/33 的训练集和测试集。
1 2 3 4 5 |
... # 分割成输入和输出列 X, y = df.values[:, :-1], df.values[:, -1] # 分割为训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33) |
我们可以定义一个最小的 MLP 模型。在本例中,我们将使用一个具有 10 个节点的隐藏层和一个输出层(任意选择)。我们将在隐藏层中使用ReLU 激活函数,并使用“he_normal”权重初始化,因为它们结合起来是良好的实践。
模型的输出是用于二元分类的 sigmoid 激活,我们将最小化二元交叉熵损失。
1 2 3 4 5 6 7 8 9 |
... # 确定输入特征的数量 n_features = X.shape[1] # 定义模型 model = Sequential() model.add(Dense(10, activation='relu', kernel_initializer='he_normal', input_shape=(n_features,))) model.add(Dense(1, activation='sigmoid')) # 编译模型 model.compile(optimizer='adam', loss='binary_crossentropy') |
我们将为 200 个训练时期(任意选择)以 32 的批量大小拟合模型,因为这是一个小型数据集。
我们使用原始数据来拟合模型,我们认为这可能是个好主意,但这只是一个重要的起点。
1 2 3 |
... # 拟合模型 history = model.fit(X_train, y_train, epochs=200, batch_size=32, verbose=0, validation_data=(X_test,y_test)) |
训练结束后,我们将评估模型在测试集上的性能,并报告分类准确率作为性能指标。
1 2 3 4 5 6 |
... # 预测测试集 yhat = model.predict_classes(X_test) # 评估预测 score = accuracy_score(y_test, yhat) print('Accuracy: %.3f' % score) |
最后,我们将绘制训练过程中训练集和测试集上交叉熵损失的学习曲线。
1 2 3 4 5 6 7 8 9 |
... # 绘制学习曲线 pyplot.title('学习曲线') pyplot.xlabel('Epoch') pyplot.ylabel('交叉熵') pyplot.plot(history.history['loss'], label='train') pyplot.plot(history.history['val_loss'], label='val') pyplot.legend() pyplot.show() |
将所有内容整合起来,评估我们在电离层数据集上的第一个 MLP 的完整示例列在下面。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
# 在电离层上拟合简单的 mlp 模型并回顾学习曲线 from pandas import read_csv from sklearn.model_selection import train_test_split from sklearn.preprocessing import LabelEncoder from sklearn.metrics import accuracy_score from tensorflow.keras import Sequential from tensorflow.keras.layers import Dense from matplotlib import pyplot # 加载数据集 path = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/ionosphere.csv' df = read_csv(path, header=None) # 分割成输入和输出列 X, y = df.values[:, :-1], df.values[:, -1] # 确保所有数据都是浮点值 X = X.astype('float32') # 将字符串编码为整数 y = LabelEncoder().fit_transform(y) # 分割为训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33) # 确定输入特征的数量 n_features = X.shape[1] # 定义模型 model = Sequential() model.add(Dense(10, activation='relu', kernel_initializer='he_normal', input_shape=(n_features,))) model.add(Dense(1, activation='sigmoid')) # 编译模型 model.compile(optimizer='adam', loss='binary_crossentropy') # 拟合模型 history = model.fit(X_train, y_train, epochs=200, batch_size=32, verbose=0, validation_data=(X_test,y_test)) # 预测测试集 yhat = model.predict_classes(X_test) # 评估预测 score = accuracy_score(y_test, yhat) print('Accuracy: %.3f' % score) # 绘制学习曲线 pyplot.title('学习曲线') pyplot.xlabel('Epoch') pyplot.ylabel('交叉熵') pyplot.plot(history.history['loss'], label='train') pyplot.plot(history.history['val_loss'], label='val') pyplot.legend() pyplot.show() |
运行示例首先在训练数据集上拟合模型,然后报告测试数据集上的分类准确率。
注意:由于算法或评估程序的随机性,或数值精度的差异,您的结果可能会有所不同。请考虑运行该示例几次并比较平均结果。
在这种情况下,我们可以看到模型达到了大约 88% 的准确率,这是一个不错的基准性能,我们或许可以改进它。
1 |
Accuracy: 0.888 |
然后创建训练集和测试集上损失的学习曲线图。
我们可以看到模型似乎收敛了,但已经过度拟合了训练数据集。

简单 MLP 在电离层数据集上的学习曲线
让我们尝试增加模型的容量。
这将减慢相同学习超参数的学习速度,并可能提供更好的准确性。
我们将添加一个具有八个节点的第二个隐藏层,任意选择。
1 2 3 4 5 6 |
... # 定义模型 model = Sequential() model.add(Dense(10, activation='relu', kernel_initializer='he_normal', input_shape=(n_features,))) model.add(Dense(8, activation='relu', kernel_initializer='he_normal')) model.add(Dense(1, activation='sigmoid')) |
完整的示例如下所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
# 在电离层上拟合更深层的 mlp 模型并回顾学习曲线 from pandas import read_csv from sklearn.model_selection import train_test_split from sklearn.preprocessing import LabelEncoder from sklearn.metrics import accuracy_score from tensorflow.keras import Sequential from tensorflow.keras.layers import Dense from matplotlib import pyplot # 加载数据集 path = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/ionosphere.csv' df = read_csv(path, header=None) # 分割成输入和输出列 X, y = df.values[:, :-1], df.values[:, -1] # 确保所有数据都是浮点值 X = X.astype('float32') # 将字符串编码为整数 y = LabelEncoder().fit_transform(y) # 分割为训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33) # 确定输入特征的数量 n_features = X.shape[1] # 定义模型 model = Sequential() model.add(Dense(10, activation='relu', kernel_initializer='he_normal', input_shape=(n_features,))) model.add(Dense(8, activation='relu', kernel_initializer='he_normal')) model.add(Dense(1, activation='sigmoid')) # 编译模型 model.compile(optimizer='adam', loss='binary_crossentropy') # 拟合模型 history = model.fit(X_train, y_train, epochs=200, batch_size=32, verbose=0, validation_data=(X_test,y_test)) # 预测测试集 yhat = model.predict_classes(X_test) # 评估预测 score = accuracy_score(y_test, yhat) print('Accuracy: %.3f' % score) # 绘制学习曲线 pyplot.title('学习曲线') pyplot.xlabel('Epoch') pyplot.ylabel('交叉熵') pyplot.plot(history.history['loss'], label='train') pyplot.plot(history.history['val_loss'], label='val') pyplot.legend() |
运行该示例首先在训练数据集上拟合模型,然后报告测试数据集上的准确性。
注意:由于算法或评估程序的随机性,或数值精度的差异,您的结果可能会有所不同。请考虑运行该示例几次并比较平均结果。
在这种情况下,我们可以看到准确率略有提高,达到约 93%,尽管训练/测试分割的高方差意味着此评估不可靠。
1 |
Accuracy: 0.931 |
然后绘制训练和测试集上损失的学习曲线。我们可以看到模型似乎仍然表现出过度拟合的行为。

更深层 MLP 在电离层数据集上的学习曲线
最后,我们可以尝试一个更宽的网络。
我们将第一个隐藏层的节点数从 10 增加到 50,第二个隐藏层的节点数从 8 增加到 10。
这将增加模型的容量,减慢学习速度,并可能进一步提高结果。
1 2 3 4 5 6 |
... # 定义模型 model = Sequential() model.add(Dense(50, activation='relu', kernel_initializer='he_normal', input_shape=(n_features,))) model.add(Dense(10, activation='relu', kernel_initializer='he_normal')) model.add(Dense(1, activation='sigmoid')) |
我们还将训练时期数从 200 减少到 100。
1 2 3 |
... # 拟合模型 history = model.fit(X_train, y_train, epochs=100, batch_size=32, verbose=0, validation_data=(X_test,y_test)) |
完整的示例如下所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
# 在电离层上拟合更宽的 mlp 模型并回顾学习曲线 from pandas import read_csv from sklearn.model_selection import train_test_split from sklearn.preprocessing import LabelEncoder from sklearn.metrics import accuracy_score from tensorflow.keras import Sequential from tensorflow.keras.layers import Dense from matplotlib import pyplot # 加载数据集 path = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/ionosphere.csv' df = read_csv(path, header=None) # 分割成输入和输出列 X, y = df.values[:, :-1], df.values[:, -1] # 确保所有数据都是浮点值 X = X.astype('float32') # 将字符串编码为整数 y = LabelEncoder().fit_transform(y) # 分割为训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33) # 确定输入特征的数量 n_features = X.shape[1] # 定义模型 model = Sequential() model.add(Dense(50, activation='relu', kernel_initializer='he_normal', input_shape=(n_features,))) model.add(Dense(10, activation='relu', kernel_initializer='he_normal')) model.add(Dense(1, activation='sigmoid')) # 编译模型 model.compile(optimizer='adam', loss='binary_crossentropy') # 拟合模型 history = model.fit(X_train, y_train, epochs=100, batch_size=32, verbose=0, validation_data=(X_test,y_test)) # 预测测试集 yhat = model.predict_classes(X_test) # 评估预测 score = accuracy_score(y_test, yhat) print('Accuracy: %.3f' % score) # 绘制学习曲线 pyplot.title('学习曲线') pyplot.xlabel('Epoch') pyplot.ylabel('交叉熵') pyplot.plot(history.history['loss'], label='train') pyplot.plot(history.history['val_loss'], label='val') pyplot.legend() pyplot.show() |
运行该示例首先在训练数据集上拟合模型,然后报告测试数据集上的准确性。
注意:由于算法或评估程序的随机性,或数值精度的差异,您的结果可能会有所不同。请考虑运行该示例几次并比较平均结果。
在这种情况下,模型获得了更好的准确率分数,约为 94%。我们暂时忽略模型性能。
1 |
Accuracy: 0.940 |
绘制学习曲线的折线图显示模型获得了合理的拟合,并且有足够的时间收敛。

更宽 MLP 在电离层数据集上的学习曲线
现在我们对简单 MLP 模型在数据集上的学习动态有了一些了解,我们可以着手评估模型的性能以及调整模型的配置。
评估和调整 MLP 模型
k 折交叉验证过程可以提供更可靠的 MLP 性能估计,尽管它可能非常耗时。
这是因为必须拟合和评估k个模型。当数据集很小时,例如电离层数据集,这不成问题。
我们可以使用 StratifiedKFold 类并手动枚举每个折叠,拟合模型,进行评估,然后在过程结束时报告评估分数的平均值。
1 2 3 4 5 6 7 8 9 10 |
# 准备交叉验证 kfold = KFold(10) # 枚举划分 scores = list() for train_ix, test_ix in kfold.split(X, y): # 拟合和评估模型... ... ... # 汇总所有分数 print('Mean Accuracy: %.3f (%.3f)' % (mean(scores), std(scores))) |
我们可以使用此框架来开发可靠的 MLP 模型性能估计,涉及一系列不同的数据准备、模型架构和学习配置。
在将 k 折交叉验证用于性能估计之前,在上一节中开发对模型在数据集上的学习动态的理解至关重要。如果我们直接开始调整模型,我们可能会得到好的结果,但如果不成功,我们可能不知道原因,例如模型是过度拟合还是欠拟合。
如果我们再次对模型进行大的更改,最好回到并确认模型正在正确收敛。
下面列出了使用此框架评估上一节中基础 MLP 模型的完整示例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
# 基础模型在电离层数据集上的 k 折交叉验证 from numpy import mean from numpy import std from pandas import read_csv from sklearn.model_selection import StratifiedKFold from sklearn.preprocessing import LabelEncoder from sklearn.metrics import accuracy_score from tensorflow.keras import Sequential from tensorflow.keras.layers import Dense from matplotlib import pyplot # 加载数据集 path = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/ionosphere.csv' df = read_csv(path, header=None) # 分割成输入和输出列 X, y = df.values[:, :-1], df.values[:, -1] # 确保所有数据都是浮点值 X = X.astype('float32') # 将字符串编码为整数 y = LabelEncoder().fit_transform(y) # 准备交叉验证 kfold = StratifiedKFold(10) # 枚举划分 scores = list() for train_ix, test_ix in kfold.split(X, y): # 分割数据 X_train, X_test, y_train, y_test = X[train_ix], X[test_ix], y[train_ix], y[test_ix] # 确定输入特征的数量 n_features = X.shape[1] # 定义模型 model = Sequential() model.add(Dense(50, activation='relu', kernel_initializer='he_normal', input_shape=(n_features,))) model.add(Dense(10, activation='relu', kernel_initializer='he_normal')) model.add(Dense(1, activation='sigmoid')) # 编译模型 model.compile(optimizer='adam', loss='binary_crossentropy') # 拟合模型 model.fit(X_train, y_train, epochs=100, batch_size=32, verbose=0) # 预测测试集 yhat = model.predict_classes(X_test) # 评估预测结果 score = accuracy_score(y_test, yhat) print('>%.3f' % score) scores.append(score) # 汇总所有分数 print('Mean Accuracy: %.3f (%.3f)' % (mean(scores), std(scores))) |
运行示例将报告每次评估过程的模型的性能,并在运行结束时报告分类准确率的平均值和标准差。
注意:由于算法或评估程序的随机性,或数值精度的差异,您的结果可能会有所不同。请考虑运行该示例几次并比较平均结果。
在这种情况下,我们可以看到 MLP 模型达到了大约 93.4% 的平均准确率。
我们将使用此结果作为基准,看看是否可以获得更好的性能。
1 2 3 4 5 6 7 8 9 10 11 |
>0.972 >0.886 >0.943 >0.886 >0.914 >0.943 >0.943 >1.000 >0.971 >0.886 Mean Accuracy: 0.934 (0.039) |
接下来,让我们尝试为模型添加正则化以减少过度拟合。
在这种情况下,我们可以在网络的隐藏层之间添加 dropout 层。例如
1 2 3 4 5 6 7 8 |
... # 定义模型 model = Sequential() model.add(Dense(50, activation='relu', kernel_initializer='he_normal', input_shape=(n_features,))) model.add(Dropout(0.4)) model.add(Dense(10, activation='relu', kernel_initializer='he_normal')) model.add(Dropout(0.4)) model.add(Dense(1, activation='sigmoid')) |
带 dropout 的 MLP 模型的完整示例列在下面。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# 带 dropout 的 MLP 在电离层数据集上的 k 折交叉验证 from numpy import mean from numpy import std from pandas import read_csv from sklearn.model_selection import StratifiedKFold from sklearn.preprocessing import LabelEncoder from sklearn.metrics import accuracy_score from tensorflow.keras import Sequential from tensorflow.keras.layers import Dense from tensorflow.keras.layers import Dropout from matplotlib import pyplot # 加载数据集 path = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/ionosphere.csv' df = read_csv(path, header=None) # 分割成输入和输出列 X, y = df.values[:, :-1], df.values[:, -1] # 确保所有数据都是浮点值 X = X.astype('float32') # 将字符串编码为整数 y = LabelEncoder().fit_transform(y) # 准备交叉验证 kfold = StratifiedKFold(10) # 枚举划分 scores = list() for train_ix, test_ix in kfold.split(X, y): # 分割数据 X_train, X_test, y_train, y_test = X[train_ix], X[test_ix], y[train_ix], y[test_ix] # 确定输入特征的数量 n_features = X.shape[1] # 定义模型 model = Sequential() model.add(Dense(50, activation='relu', kernel_initializer='he_normal', input_shape=(n_features,))) model.add(Dropout(0.4)) model.add(Dense(10, activation='relu', kernel_initializer='he_normal')) model.add(Dropout(0.4)) model.add(Dense(1, activation='sigmoid')) # 编译模型 model.compile(optimizer='adam', loss='binary_crossentropy') # 拟合模型 model.fit(X_train, y_train, epochs=100, batch_size=32, verbose=0) # 预测测试集 yhat = model.predict_classes(X_test) # 评估预测结果 score = accuracy_score(y_test, yhat) print('>%.3f' % score) scores.append(score) # 汇总所有分数 print('Mean Accuracy: %.3f (%.3f)' % (mean(scores), std(scores))) |
运行后,在运行结束时报告分类准确率的平均值和标准差。
注意:由于算法或评估程序的随机性,或数值精度的差异,您的结果可能会有所不同。请考虑运行该示例几次并比较平均结果。
在这种情况下,我们可以看到带 dropout 的 MLP 模型取得了更好的结果,准确率约为 94.6%,而没有 dropout 的模型为 93.4%。
1 |
Mean Accuracy: 0.946 (0.043) |
最后,我们将尝试将批量大小从 32 减小到 8。
这将导致更嘈杂的梯度,并且也可能减慢模型学习问题的速度。
1 2 3 |
... # 拟合模型 model.fit(X_train, y_train, epochs=100, batch_size=8, verbose=0) |
完整的示例如下所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# 带 dropout 的 MLP 在电离层数据集上的 k 折交叉验证 from numpy import mean from numpy import std from pandas import read_csv from sklearn.model_selection import StratifiedKFold from sklearn.preprocessing import LabelEncoder from sklearn.metrics import accuracy_score from tensorflow.keras import Sequential from tensorflow.keras.layers import Dense from tensorflow.keras.layers import Dropout from matplotlib import pyplot # 加载数据集 path = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/ionosphere.csv' df = read_csv(path, header=None) # 分割成输入和输出列 X, y = df.values[:, :-1], df.values[:, -1] # 确保所有数据都是浮点值 X = X.astype('float32') # 将字符串编码为整数 y = LabelEncoder().fit_transform(y) # 准备交叉验证 kfold = StratifiedKFold(10) # 枚举划分 scores = list() for train_ix, test_ix in kfold.split(X, y): # 分割数据 X_train, X_test, y_train, y_test = X[train_ix], X[test_ix], y[train_ix], y[test_ix] # 确定输入特征的数量 n_features = X.shape[1] # 定义模型 model = Sequential() model.add(Dense(50, activation='relu', kernel_initializer='he_normal', input_shape=(n_features,))) model.add(Dropout(0.4)) model.add(Dense(10, activation='relu', kernel_initializer='he_normal')) model.add(Dropout(0.4)) model.add(Dense(1, activation='sigmoid')) # 编译模型 model.compile(optimizer='adam', loss='binary_crossentropy') # 拟合模型 model.fit(X_train, y_train, epochs=100, batch_size=8, verbose=0) # 预测测试集 yhat = model.predict_classes(X_test) # 评估预测结果 score = accuracy_score(y_test, yhat) print('>%.3f' % score) scores.append(score) # 汇总所有分数 print('Mean Accuracy: %.3f (%.3f)' % (mean(scores), std(scores))) |
运行后,在运行结束时报告分类准确率的平均值和标准差。
注意:由于算法或评估程序的随机性,或数值精度的差异,您的结果可能会有所不同。请考虑运行该示例几次并比较平均结果。
在这种情况下,我们可以看到带 dropout 的 MLP 模型取得了略微更好的结果,准确率约为 94.9%。
1 |
Mean Accuracy: 0.949 (0.042) |
我们将使用此配置作为我们的最终模型。
我们可以继续测试模型架构(更多或更少的节点或层)、学习超参数(更多或更少的批次)和数据转换的替代配置。
留给您作为练习;请告诉我您的发现。您能获得更好的结果吗?
在下面的评论中发布您的结果,我很想看到您的成果。
接下来,我们看看如何拟合最终模型并使用它来做出预测。
最终模型及预测
选择模型配置后,我们可以使用所有可用数据训练最终模型,并用它来对新数据进行预测。
在此案例中,我们将使用带有 dropout 和小型批次大小的模型作为我们的最终模型。
我们可以像以前一样准备数据并拟合模型,但这次是在整个数据集上,而不是在一个训练子集上。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
... # 分割成输入和输出列 X, y = df.values[:, :-1], df.values[:, -1] # 确保所有数据都是浮点值 X = X.astype('float32') # 将字符串编码为整数 le = LabelEncoder() y = le.fit_transform(y) # 确定输入特征的数量 n_features = X.shape[1] # 定义模型 model = Sequential() model.add(Dense(50, activation='relu', kernel_initializer='he_normal', input_shape=(n_features,))) model.add(Dropout(0.4)) model.add(Dense(10, activation='relu', kernel_initializer='he_normal')) model.add(Dropout(0.4)) model.add(Dense(1, activation='sigmoid')) # 编译模型 model.compile(optimizer='adam', loss='binary_crossentropy') |
然后,我们可以使用此模型对新数据进行预测。
首先,我们可以定义一个新数据行。
1 2 3 |
... # 定义一行新数据 row = [1,0,0.99539,-0.05889,0.85243,0.02306,0.83398,-0.37708,1,0.03760,0.85243,-0.17755,0.59755,-0.44945,0.60536,-0.38223,0.84356,-0.38542,0.58212,-0.32192,0.56971,-0.29674,0.36946,-0.47357,0.56811,-0.51171,0.41078,-0.46168,0.21266,-0.34090,0.42267,-0.54487,0.18641,-0.45300] |
注意:我从数据集中选择了第一行,预期的标签是“g”。
然后我们可以进行预测。
1 2 3 |
... # 进行预测 yhat = model.predict_classes([row]) |
然后对预测结果进行逆向转换,以便使用或解释正确标签的结果。
1 2 3 |
... # 逆变换以获得类别标签 yhat = le.inverse_transform(yhat) |
在这种情况下,我们将只报告预测结果。
1 2 3 |
... # 报告预测结果 print('Predicted: %s' % (yhat[0])) |
总而言之,下面列出了拟合电离层数据集的最终模型并使用它对新数据进行预测的完整示例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
# fit a final model and make predictions on new data for the ionosphere dataset from pandas import read_csv from sklearn.preprocessing import LabelEncoder from sklearn.metrics import accuracy_score from tensorflow.keras import Sequential from tensorflow.keras.layers import Dense from tensorflow.keras.layers import Dropout # 加载数据集 path = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/ionosphere.csv' df = read_csv(path, header=None) # 分割成输入和输出列 X, y = df.values[:, :-1], df.values[:, -1] # 确保所有数据都是浮点值 X = X.astype('float32') # 将字符串编码为整数 le = LabelEncoder() y = le.fit_transform(y) # 确定输入特征的数量 n_features = X.shape[1] # 定义模型 model = Sequential() model.add(Dense(50, activation='relu', kernel_initializer='he_normal', input_shape=(n_features,))) model.add(Dropout(0.4)) model.add(Dense(10, activation='relu', kernel_initializer='he_normal')) model.add(Dropout(0.4)) model.add(Dense(1, activation='sigmoid')) # 编译模型 model.compile(optimizer='adam', loss='binary_crossentropy') # 拟合模型 model.fit(X, y, epochs=100, batch_size=8, verbose=0) # 定义一行新数据 row = [1,0,0.99539,-0.05889,0.85243,0.02306,0.83398,-0.37708,1,0.03760,0.85243,-0.17755,0.59755,-0.44945,0.60536,-0.38223,0.84356,-0.38542,0.58212,-0.32192,0.56971,-0.29674,0.36946,-0.47357,0.56811,-0.51171,0.41078,-0.46168,0.21266,-0.34090,0.42267,-0.54487,0.18641,-0.45300] # 进行预测 yhat = model.predict_classes([row]) # 逆变换以获得类别标签 yhat = le.inverse_transform(yhat) # 报告预测结果 print('Predicted: %s' % (yhat[0])) |
运行示例会将模型拟合到整个数据集,并为新数据的单行进行预测。
注意:由于算法或评估程序的随机性,或数值精度的差异,您的结果可能会有所不同。请考虑运行该示例几次并比较平均结果。
在这种情况下,我们可以看到模型为输入行预测了“g”标签。
1 |
Predicted: g |
进一步阅读
如果您想深入了解,本节提供了更多关于该主题的资源。
教程
总结
在本教程中,您学习了如何为电离层二分类数据集开发多层感知机神经网络模型。
具体来说,你学到了:
- 如何加载和总结电离层数据集,并利用这些结果来建议数据准备和模型配置。
- 如何探索简单MLP模型在数据集上的学习动态。
- 如何开发模型性能的稳健估计,调整模型性能并对新数据进行预测。
你有什么问题吗?
在下面的评论中提出你的问题,我会尽力回答。
哇,这篇教程太棒了,而且是刚发布的!我刚开始学习深度学习,所以时机非常合适。这里有很多需要学习的内容,我有的忙了。
谢谢你,Jason。
不客气。
教程很棒。
谢谢分享,Jason Brownlee
非常欢迎。
太棒了!技术内容很好。要消化这么多内容真的很难。非常感谢您的努力,@Jason Brownlee。
不客气,很高兴能帮到您。
演示太棒了,而且用通俗易懂的语言解释概念的方式值得称赞。请告诉我如何访问 colab notebook。我从 Sachin Dev Duggal(Builder AI 的 CEO 和创始人)的文章中读到过这类概念。
谢谢。
这或许对 colab 有帮助
https://machinelearning.org.cn/faq/single-faq/do-code-examples-run-on-google-colab
好文章!!更容易理解
谢谢。
先生,当我尝试将水平集成应用于电离层数据时,它会报错。
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’)请帮忙解决这个问题
抱歉,我不知道您错误的原因。
也许您可以在 stackoverflow.com 上发布您的代码、数据和错误信息。