原代码

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. 随机权重初始化

  • 现象:神经网络层(如 Conv1DDense)在每次创建时会随机初始化权重(如 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 实际模拟的是全连接,但使用卷积层会带来不必要的参数与不稳定性。
  • 建议:使用更简洁、适合该任务的全连接网络

    model = Sequential([
        Dense(16, activation='relu', input_shape=(4,)),
        Dense(8, activation='relu'),
        Dense(3, activation='softmax')
    ])
    

🔹 5. 训练超参数设置

  • 批量大小(batch_size=16:小批量训练会引入更新噪声,导致训练过程波动。
  • 训练轮数(epochs=50:若训练未完全收敛,不同初始化可能导致最终性能有差异。

✅ 稳定准确率的建议方案

  1. 固定随机性

    import numpy as np
    import tensorflow as tf
    np.random.seed(42)
    tf.random.set_seed(42)
    
  2. 替换为全连接网络结构

    model = Sequential([
        Dense(16, activation='relu', input_shape=(4,)),
        Dense(3, activation='softmax')
    ])
    
  3. 增加样本量或使用交叉验证
    提高模型泛化能力,降低划分带来的波动。

  4. 检查损失函数拼写

    • 确保使用的是正确的:

      loss='categorical_crossentropy'
      
    • 拼错可能会导致使用默认损失,进而影响训练效果。


❓ 为什么准确率波动大?

  • 根本原因:1D 卷积结构用于非时序数据本身就不稳定、冗余。
  • 优化建议:切换为更合适的结构(如全连接层)后,模型应稳定在 95%~98% 准确率(鸢尾花数据的常见表现)。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐