CNN二分类模型全预测为类别0问题排查求助
问题:CNN二分类模型全输出优势类别(类别0)
我正在为大学课程编写首个CNN模型,用于图像二分类任务(类别0或1)。图像存储于data/data路径,训练标签在train_labels.txt中,对应前15000张图像;接下来2000张为验证集,标签在validation_labels.txt;最后5149张图像需预测类别。目前模型输出全部为类别0(该类别为优势类别),已尝试调整epoch数、批次大小、学习率等参数,无任何改善,推测问题出在模型本身,寻求解决方向。
代码示例
import numpy as np import pandas as pd import tensorflow as tf from tensorflow.keras import layers from tensorflow.keras.preprocessing.image import ImageDataGenerator import os from glob import glob from sklearn.utils import class_weight import tensorflow.keras.callbacks as callbacks train_labels = pd.read_csv("data/train_labels.txt", delimiter=",", header=None, names=["id", "class"], skiprows=1) val_labels = pd.read_csv("data/validation_labels.txt", delimiter=",", header=None, names=["id", "class"], skiprows=1) train_labels['id'] = train_labels['id'].apply(lambda x: '{0:0>6}.png'.format(x)) val_labels['id'] = val_labels['id'].apply(lambda x: '{0:0>6}.png'.format(x)) train_labels["class"] = train_labels["class"].astype(str) val_labels["class"] = val_labels["class"].astype(str) train_datagen = ImageDataGenerator(rescale=1./255) val_datagen = ImageDataGenerator(rescale=1./255) test_datagen = ImageDataGenerator(rescale=1./255) test_dir = "data/data/" test_ids = range(17001, 22150) train_generator = train_datagen.flow_from_dataframe( train_labels, directory="data/data/", x_col="id", y_col="class", target_size=(224, 224), batch_size=32, class_mode="binary") val_generator = val_datagen.flow_from_dataframe( val_labels, directory="data/data/", x_col="id", y_col="class", target_size=(224, 224), batch_size=32, class_mode="binary") test_generator = test_datagen.flow_from_dataframe( dataframe=pd.DataFrame({"id": [f"{i:06d}.png" for i in test_ids]}), directory=test_dir, x_col="id", y_col=None, target_size=(224, 224), batch_size=1, class_mode=None, shuffle=False) model = tf.keras.Sequential([ layers.experimental.preprocessing.Rescaling(scale=1./255), layers.Conv2D(32, (3, 3), activation='relu', input_shape=(224, 224, 3)), layers.MaxPooling2D((2, 2)), layers.Conv2D(64, (3, 3), activation='relu'), layers.MaxPooling2D((2, 2)), layers.Conv2D(128, (3, 3), activation='relu'), layers.MaxPooling2D((2, 2)), layers.Flatten(), layers.Dense(128, activation='relu'), layers.Dense(1, activation='sigmoid') ]) optimizer = tf.keras.optimizers.Adam(learning_rate=0.001) model.compile(optimizer=optimizer, loss='binary_crossentropy', metrics=['accuracy']) class_weights = class_weight.compute_class_weight(class_weight='balanced', classes=np.unique(train_labels['class']), y=train_labels['class']) class_weights_dict = dict(enumerate(class_weights)) history = model.fit(train_generator, steps_per_epoch=train_generator.samples//train_generator.batch_size, epochs=10, validation_data=val_generator, validation_steps=val_generator.samples//val_generator.batch_size, class_weight=class_weights_dict, ) model.evaluate(val_generator) preds = model.predict(test_generator) preds = np.where(preds > 0.5, 1, 0) output_df = pd.DataFrame({'id': range(17001, 22150), 'class': preds.flatten()}) output_df.to_csv("data/submission.csv", sep=',', index=False, header=False)
解决方向
1. 修复重复归一化问题
代码中存在两次图像归一化:
ImageDataGenerator已设置rescale=1./255,将像素从0-255缩放到0-1- 模型第一层又添加
layers.experimental.preprocessing.Rescaling(scale=1./255),导致像素被二次缩放至0-0.0039,严重破坏特征分布
建议移除模型中的Rescaling层,保留ImageDataGenerator的归一化即可。
2. 确认类别权重映射正确性
class_weight.compute_class_weight返回的权重顺序基于np.unique(train_labels['class']),而flow_from_dataframe会按类别字符串字典序分配索引(比如"0"对应索引0,"1"对应索引1)。需:
- 打印
train_generator.class_indices查看类别-索引映射 - 确保
class_weights_dict的键与该映射一致,避免权重分配错误
3. 强化模型特征学习能力
当前模型结构较浅,不足以提取有效图像特征:
- 添加更多卷积层(比如增加
Conv2D(256, (3,3), activation='relu')+MaxPooling2D) - 在全连接层后添加
Dropout(0.5)抑制过拟合,增强泛化能力 - 考虑使用预训练模型(如MobileNetV2、VGG16)进行迁移学习,利用预训练图像特征提升分类性能
4. 优化训练策略与监控
- 增加训练轮数(30-50轮),同时添加
EarlyStopping回调,当验证集性能不再提升时自动停止,避免欠拟合 - 监控精确率、召回率、F1分数(而非仅准确率),类别不平衡场景下准确率无法反映真实性能:
from sklearn.metrics import classification_report val_preds = model.predict(val_generator) val_preds = np.where(val_preds > 0.5, 1, 0) print(classification_report(val_labels['class'].astype(int), val_preds)) - 降低学习率至
1e-4,避免权重更新幅度过大导致模型无法收敛到少数类
5. 验证数据加载正确性
- 随机抽取少量训练图像,检查
train_generator加载的图像与标签是否匹配,排除数据加载错误 - 确认验证集和训练集的类别分布是否符合预期,避免数据划分错误
内容的提问来源于stack exchange,提问作者Scooby
相关产品推荐
相关产品推荐

