卷积神经网络训练异常:初始准确率高随轮次下降且测试集准确率为0
多标签分类训练异常排查
任务与代码
使用Tensorflow/Keras开展多标签分类任务(共3个二分类标签,取值0/1),模型结构和训练代码如下:
模型结构
model.add(layers.Conv2D(32, kernel_size=3, padding='same', activation='relu', input_shape=(64, 64, 1))) model.add(layers.MaxPooling2D(pool_size=2)) model.add(layers.Conv2D(24, kernel_size=3, padding='same', activation='relu')) model.add(layers.MaxPooling2D(pool_size=2)) model.add(layers.Conv2D(16, kernel_size=3, padding='same', activation='relu')) model.add(layers.Flatten()) model.add(layers.Dense(144, activation='relu')) model.add(layers.Dense(3, activation='sigmoid'))
训练代码
model.compile(optimizer='sgd', loss = tf.keras.losses.BinaryCrossentropy(), metrics=['accuracy']) history = model.fit(train_images, train_labels, epochs=50, validation_data=(val_images, val_labels))
异常表现
- 第一个epoch准确率超90%
- 训练轮次增加后,准确率逐渐降至50%左右,偶尔随机回升至70%
- 训练集、验证集均呈现此规律
- 测试集准确率为0
问题分析与解决办法
1. 替换默认accuracy指标
默认accuracy计算的是样本所有标签全对的比例,完全不适合多标签任务。初始高准确率是因为数据集标签分布极端(比如多数样本标签全0/全1),模型瞎蒙就蒙对了,后续训练学特征反而打破了这种巧合,导致准确率下降。
改用多标签专用指标:
model.compile(optimizer='sgd', loss=tf.keras.losses.BinaryCrossentropy(), metrics=[tf.keras.metrics.BinaryAccuracy(name='binary_acc'), tf.keras.metrics.Precision(), tf.keras.metrics.Recall()])
BinaryAccuracy会统计每个标签的分类准确率,能真实反映模型性能。
2. 排查数据集问题
测试集准确率为0肯定是数据集环节出了问题:
- 检查训练/验证/测试集的标签分布是否一致,避免测试集标签与训练集完全脱节
- 确认所有数据集的预处理统一:比如图像是否归一化、通道数是否匹配输入的(64,64,1)单通道
- 检查测试集标签加载是否正确,有没有出现标签全0/全1的错误
3. 调低SGD学习率
SGD默认学习率0.01可能过高,导致模型参数更新幅度过大,训练过程震荡,准确率忽高忽低。试试调低学习率:
optimizer=tf.keras.optimizers.SGD(learning_rate=0.001)
4. 优化模型结构
在卷积层后加入BatchNormalization稳定训练,全连接层加入Dropout防止过拟合:
model.add(layers.Conv2D(32, kernel_size=3, padding='same', activation='relu', input_shape=(64, 64, 1))) model.add(layers.BatchNormalization()) model.add(layers.MaxPooling2D(pool_size=2)) model.add(layers.Conv2D(24, kernel_size=3, padding='same', activation='relu')) model.add(layers.BatchNormalization()) model.add(layers.MaxPooling2D(pool_size=2)) model.add(layers.Conv2D(16, kernel_size=3, padding='same', activation='relu')) model.add(layers.BatchNormalization()) model.add(layers.Flatten()) model.add(layers.Dense(144, activation='relu')) model.add(layers.Dropout(0.5)) model.add(layers.Dense(3, activation='sigmoid'))
5. 调整标签判断阈值
sigmoid输出默认用0.5作为标签判断阈值,但如果数据集标签不平衡,这个阈值可能不合适。可以根据验证集的Precision-Recall曲线确定最优阈值。
内容的提问来源于stack exchange,提问作者Ann
相关产品推荐
相关产品推荐

