使用CNN神经网络分析鸢尾花数据集时,准确率不稳定
·
原代码
import numpy as np
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Conv1D, MaxPooling1D, Flatten
from tensorflow.keras.utils import to_categorical
# 加载鸢尾花数据集
iris = load_iris()
X = iris.data
y = iris.target
# 数据预处理,将标签进行独热编码
y = to_categorical(y)
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 将数据调整为适合1D卷积的形状 (样本数, 时间步长, 特征数),这里时间步长设为1
X_train = np.expand_dims(X_train, axis=1)
X_test = np.expand_dims(X_test, axis=1)
# 构建神经网络模型
model = Sequential()
model.add(Conv1D(16, kernel_size=1, activation='relu', input_shape=(1, 4)))
model.add(MaxPooling1D(pool_size=1))
model.add(Conv1D(8, kernel_size=1, activation='relu'))
model.add(MaxPooling1D(pool_size=1))
model.add(Flatten())
model.add(Dense(3, activation='softmax'))
# 编译模型
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
# 训练模型
model.fit(X_train, y_train, epochs=50, batch_size=16, verbose=1)
# 评估模型
loss, accuracy = model.evaluate(X_test, y_test)
print(f"测试集损失: {loss}")
print(f"测试集准确率: {accuracy}")
多次运行准确率:
测试集准确率: 0.9666666388511658
测试集准确率: 0.8999999761581421
测试集准确率: 0.7666666507720947
测试集准确率: 1.0
🎯 为什么模型每次运行测试集准确率不同?
这主要由以下几个关键因素造成:
🔹 1. 随机权重初始化
-
现象:神经网络层(如
Conv1D和Dense)在每次创建时会随机初始化权重(如 Glorot 正态分布)。 -
影响:初始点不同,优化路径不同,可能收敛到不同的局部最优。
-
示例:
model = Sequential() model.add(Dense(3, activation='softmax')) # 初始权重每次都不同
🔹 2. 数据划分的随机性
-
问题:
train_test_split固定random_state虽有帮助,但若整体脚本中未设定全局随机种子,每次运行仍可能划分不同。 -
建议:在脚本开头固定随机性:
import numpy as np import tensorflow as tf np.random.seed(42) tf.random.set_seed(42)
🔹 3. 优化器(如 Adam)的内部随机性
-
问题:即使固定随机种子,
Adam优化器在某些硬件或浮点运算中仍有非确定性行为。 -
解决方法:强制使用确定性操作(需在脚本开头设定):
import os os.environ['TF_DETERMINISTIC_OPS'] = '1'
🔹 4. 模型结构设计不合理(对于鸢尾花数据)
-
问题:你使用了 1D 卷积网络处理鸢尾花数据(4 个静态特征),但该数据并非时序数据,此设计过于复杂。
-
具体分析:
- 输入被 reshape 成
(n_samples, 1, 4),但这种结构不符合数据本质。 kernel_size=1实际模拟的是全连接,但使用卷积层会带来不必要的参数与不稳定性。
- 输入被 reshape 成
-
建议:使用更简洁、适合该任务的全连接网络:
model = Sequential([ Dense(16, activation='relu', input_shape=(4,)), Dense(8, activation='relu'), Dense(3, activation='softmax') ])
🔹 5. 训练超参数设置
- 批量大小(
batch_size=16):小批量训练会引入更新噪声,导致训练过程波动。 - 训练轮数(
epochs=50):若训练未完全收敛,不同初始化可能导致最终性能有差异。
✅ 稳定准确率的建议方案
-
固定随机性
import numpy as np import tensorflow as tf np.random.seed(42) tf.random.set_seed(42) -
替换为全连接网络结构
model = Sequential([ Dense(16, activation='relu', input_shape=(4,)), Dense(3, activation='softmax') ]) -
增加样本量或使用交叉验证
提高模型泛化能力,降低划分带来的波动。 -
检查损失函数拼写
-
确保使用的是正确的:
loss='categorical_crossentropy' -
拼错可能会导致使用默认损失,进而影响训练效果。
-
❓ 为什么准确率波动大?
- 根本原因:1D 卷积结构用于非时序数据本身就不稳定、冗余。
- 优化建议:切换为更合适的结构(如全连接层)后,模型应稳定在 95%~98% 准确率(鸢尾花数据的常见表现)。
更多推荐
所有评论(0)