CNN模型训练与评估阶段准确率差距过大的原因分析
CNN训练与评估准确率差距过大的原因分析
问题描述
训练CNN模型时,训练准确率(training accuracy)达到68%,验证准确率(validation accuracy)为63%;但使用相同数据集评估同一模型时,结果却大幅下降:
- 训练损失:1.86870,训练准确率:36.16%
- 验证损失:1.89060,验证准确率:36.54%
- 测试损失:1.86273,测试准确率:36.36%
两者准确率差距极大,求问题原因。
模型代码
import tensorflow as tf from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Activation, Dropout, Normalization, AveragePooling2D, BatchNormalization from tensorflow.keras.optimizers import Adam, Adamax from tensorflow.python.keras import regularizers from tensorflow.keras.models import Sequential from tensorflow.keras.preprocessing.image import ImageDataGenerator model = Sequential() model.add(Conv2D(32, (3, 3), input_shape=(height, width, 3), padding='same', activation="relu")) model.add(MaxPooling2D(pool_size=(2, 2), padding='same', strides=(2))) model.add(Conv2D(32, (3, 3), padding='same', activation="relu")) model.add(MaxPooling2D(pool_size=(2, 2), padding='same', strides=(2))) model.add(Conv2D(32, (3, 3), padding='same', activation="relu")) model.add(MaxPooling2D(pool_size=(2, 2), padding='same', strides=(2))) model.add(Conv2D(32, (3, 3), padding='same', activation="relu")) model.add(MaxPooling2D(pool_size=(2, 2), padding='same', strides=(2))) model.add(Conv2D(64, (3, 3), padding='same', activation="relu")) model.add(MaxPooling2D(pool_size=(2, 2), padding='same', strides=(2))) model.add(Dropout(.2)) model.add(Conv2D(64, (3, 3), padding='same', activation="relu")) model.add(MaxPooling2D(pool_size=(2, 2), padding='same', strides=(2))) model.add(Dropout(.2)) model.add(Conv2D(64, (3, 3), padding='same', activation="relu")) model.add(MaxPooling2D(pool_size=(2, 2), padding='same', strides=(2))) model.add(Dropout(.2)) model.add(Conv2D(64, (3, 3), padding='same', activation="relu")) model.add(MaxPooling2D(pool_size=(2, 2), padding='same', strides=(2))) model.add(Flatten()) # 转换3D特征图为1D特征向量 model.add(Dense(256, activation="relu")) model.add(BatchNormalization()) model.add(Dropout(.5)) model.add(Dense(126, activation="relu")) model.add(BatchNormalization()) model.add(Dropout(.5)) model.add(Dense(4,activation='softmax')) # 原代码未将实例化的Adam赋值,此处修正 optimizer = Adam(learning_rate=0.001, name='Adam') model.compile(optimizer=optimizer, loss='categorical_crossentropy', metrics=['accuracy']) epochs = 50 from tensorflow.keras import callbacks import time import keras from keras.callbacks import EarlyStopping es_callback = keras.callbacks.EarlyStopping(monitor='val_accuracy', patience=20) datagen = ImageDataGenerator( horizontal_flip=True, vertical_flip=True, featurewise_std_normalization=True, samplewise_std_normalization=True ) checkpoint = callbacks.ModelCheckpoint( filepath='/content/drive/MyDrive/model.{epoch:02d}-{accuracy:.2f}-{val_accuracy:.2f}.h5', monitor='val_accuracy', verbose=1, save_best_only=True, mode='auto' ) datagen.fit(X_train) history5 = model.fit(datagen.flow(X_train,y_train, batch_size=batch_size), epochs=epochs, validation_data=datagen.flow(X_val,y_val, batch_size=batch_size), callbacks=[checkpoint] ) stop = time.time()
评估结果截图

核心原因分析
1. 数据预处理不一致(最可能)
训练时通过datagen.flow()实时应用了数据增强(翻转)和标准化,但评估时如果直接调用model.evaluate(X_train, y_train),数据没有经过datagen的预处理,导致输入数据分布和训练时完全不同,模型无法正确预测,准确率骤降。
解决:评估时也要用datagen.flow()处理数据(注意关闭数据增强,仅保留标准化逻辑),或手动对评估数据应用与训练一致的预处理。
2. ImageDataGenerator参数冲突
同时开启featurewise_std_normalization=True和samplewise_std_normalization=True是错误的,这两个参数互斥:
featurewise基于整个训练集的均值/标准差做标准化samplewise基于单张图片的均值/标准差做标准化
同时开启会导致预处理逻辑混乱,模型学习到的特征分布与评估输入分布不匹配。
解决:仅保留其中一个标准化参数,推荐用featurewise_std_normalization=True,并确保评估时使用训练集计算的均值和标准差(datagen.mean_和datagen.std_)。
3. 模型加载错误
你用ModelCheckpoint设置了save_best_only=True,保存的是验证准确率最高的模型,但评估时如果没有加载这个最优模型,而是用了训练最后一轮的模型,就会出现结果不符的情况。
解决:评估前加载保存的最优模型文件,示例:
from tensorflow.keras.models import load_model best_model = load_model('/content/drive/MyDrive/[最优模型文件名].h5') best_model.evaluate(...)
4. 代码细节bug
原代码存在两处影响训练的细节问题:
- 后续
Conv2D层重复设置input_shape,这是多余的,仅第一层需要 - 实例化
Adam优化器后未赋值,直接用model.compile(optimizer='Adam')会调用默认参数的Adam,而非你设置的learning_rate=0.001版本,可能导致训练效率低下。
内容的提问来源于stack exchange,提问作者Rezuana Haque
相关产品推荐
相关产品推荐

