训练CNN时accuracy与val_accuracy无变化的解决方案咨询
解决CNN训练中准确率几乎无变化的问题
问题现象
使用TensorFlow和Keras训练卷积神经网络时,训练全程accuracy和val_accuracy数值几乎没有提升,初始训练准确率就达到96%以上,后续epoch中仅维持在该水平。
相关代码
模型定义代码
from keras.models import Sequential from keras.layers import Dense, Dropout, Activation, Flatten, Conv2D, MaxPooling2D import pickle X = pickle.load(open("X.pickle", "rb")) y = pickle.load(open("y.pickle", "rb")) X = X/255.0 model = Sequential() model.add(Conv2D(64, (3, 3), input_shape=X.shape[1:])) model.add(Activation("relu")) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Conv2D(64, (3, 3), activation="relu")) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Flatten()) model.add(Dense(64, activation="relu")) model.add(Dense(1, activation="sigmoid")) model.compile(loss="binary_crossentropy", optimizer="adam", metrics=["accuracy"]) model.fit(X, y, batch_size=10, epochs=10, validation_split=0.1)
训练数据生成代码
def create_training_data(): for category in CATEGORIES: path = os.path.join(DATADIR, category) class_num = CATEGORIES.index(category) for img in os.listdir(path): try: img_array = cv2.imread(os.path.join(path, img), cv2.IMREAD_GRAYSCALE) new_array = cv2.resize(img_array, (IMG_SIZE, IMG_SIZE)) training_data.append([new_array, class_num]) except Exception as e: pass create_training_data() random.shuffle(training_data) X = [] y = [] for features, label in training_data: X.append(features) y.append(label) X = np.array(X).reshape(-1, IMG_SIZE, IMG_SIZE, 1) y = np.array(y)
训练日志
2023-01-15 00:36:42.368335: I tensorflow/core/platform/cpu_feature_guard.cc:193] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations: AVX To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags. Epoch 1/10 70/70 [==============================] - 45s 619ms/step - loss: 0.3039 - accuracy: 0.9627 - val_loss: 0.1211 - val_accuracy: 0.9744 Epoch 2/10 70/70 [==============================] - 42s 600ms/step - loss: 0.1524 - accuracy: 0.9670 - val_loss: 0.1189 - val_accuracy: 0.9744 Epoch 3/10 70/70 [==============================] - 42s 600ms/step - loss: 0.1537 - accuracy: 0.9670 - val_loss: 0.1622 - val_accuracy: 0.9744 Epoch 4/10 70/70 [==============================] - 44s 627ms/step - loss: 0.1563 - accuracy: 0.9670 - val_loss: 0.1464 - val_accuracy: 0.9744 Epoch 5/10 70/70 [==============================] - 42s 604ms/step - loss: 0.1591 - accuracy: 0.9670 - val_loss: 0.1185 - val_accuracy: 0.9744 Epoch 6/10 70/70 [==============================] - 42s 605ms/step - loss: 0.1511 - accuracy: 0.9670 - val_loss: 0.1338 - val_accuracy: 0.9744 Epoch 7/10 70/70 [==============================] - 49s 698ms/step - loss: 0.1623 - accuracy: 0.9670 - val_loss: 0.1188 - val_accuracy: 0.9744 Epoch 8/10 70/70 [==============================] - 50s 709ms/step - loss: 0.1480 - accuracy: 0.9670 - val_loss: 0.1397 - val_accuracy: 0.9744 Epoch 9/10 70/70 [==============================] - 45s 637ms/step - loss: 0.1508 - accuracy: 0.9670 - val_loss: 0.1203 - val_accuracy: 0.9744 Epoch 10/10 70/70 [==============================] - 47s 665ms/step - loss: 0.1716 - accuracy: 0.9670 - val_loss: 0.1238 - val_accuracy: 0.9744 Process finished with exit code 0
问题分析
从日志可见,模型初始训练准确率就极高,后续无提升,核心原因大概率是数据集类别严重不平衡——模型只需预测占比极高的类别就能获得高准确率,无需学习有效特征。此外,模型容量不足、过拟合也可能导致该现象。
解决方法
- 检查数据集类别分布:执行
np.bincount(y)统计两类样本数量,确认是否存在某类占比过高的情况。 - 处理类别不平衡:
- 重采样:对少数类样本进行过采样(复制样本),或对多数类进行欠采样(随机删除部分样本);
- 类别权重:在
model.fit()中添加class_weight参数,按类别数量反比计算权重,示例:count0 = np.sum(y == 0) count1 = np.sum(y == 1) total = count0 + count1 class_weight = {0: total/(2*count0), 1: total/(2*count1)} model.fit(X, y, batch_size=32, epochs=10, validation_split=0.1, class_weight=class_weight)
- 调整模型结构:
- 提升模型容量:增加卷积层数量、扩大卷积核规模(如将64改为128),或增加全连接层神经元数量;
- 添加Dropout层:在
Flatten()后或全连接层后加入Dropout(0.5),抑制过拟合;
- 优化训练参数:
- 增大batch size:将当前的10调整为32或64,让梯度更新更稳定;
- 调整学习率:降低Adam默认学习率(如改为0.0001),或使用学习率调度器动态调整;
- 数据增强:通过随机翻转、旋转、缩放等操作扩充数据多样性,避免模型记忆训练样本,示例:
from keras.preprocessing.image import ImageDataGenerator datagen = ImageDataGenerator( rotation_range=15, width_shift_range=0.1, height_shift_range=0.1, horizontal_flip=True ) datagen.fit(X) model.fit(datagen.flow(X, y, batch_size=32), epochs=15, validation_split=0.1) - 验证数据正确性:检查标签是否与样本正确对应,排除错误标注或混入的无效数据。
内容的提问来源于stack exchange,提问作者Necromancer04
相关产品推荐
相关产品推荐

