You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ResNet50二分类模型全部预测为同一类的问题排查求助

使用ResNet50做二分类时模型全预测为0类的问题排查

我正在使用ResNet50模型进行二分类任务,混淆矩阵显示模型将所有图像都预测为0类,我的代码是否存在错误?

import os
import pandas as pd
from keras.applications.resnet50 import preprocess_input
from sklearn.model_selection import train_test_split
from keras.preprocessing.image import ImageDataGenerator
import matplotlib.pyplot as plt
import PIL
from sklearn.preprocessing import LabelEncoder
import numpy as np
from keras.models import Sequential, Model
from tqdm.auto import tqdm
tqdm.pandas()

train_dir = "/content/drive/MyDrive/DefectDetection/splitDefectData"
file_list = os.listdir(train_dir)
DEFECTUEUX = "Defectueux"  # 有缺陷类
NONDEFECTUEUX = "NonDefectueux"  # 无缺陷类
TRAIN_TOTAL = len(file_list)
labels = []
df_train = pd.DataFrame()

idx = 0
img_sizes = []
for filename in file_list:
    if "NonDefectueux" in filename:
        labels.append(NONDEFECTUEUX)
    else:
        labels.append(DEFECTUEUX)
    img = PIL.Image.open(f"{train_dir}/{filename}")
    img.close()
    idx += 1

df_train["filename"] = file_list
df_train["classes"] = labels
label_encoder = LabelEncoder()
df_train["DND_label"] = label_encoder.fit_transform(df_train["classes"])  # {Defectueux:0, NonDefectueux:1}

batch_size = 10
img_size = 224 
epochs = 10

"""测试Keras生成器"""


def create_generators(valid_perc, test_perc, shuffle=False,preprocess_func=None):
    
    # 将数据分为训练集和临时集(70%训练,30%临时)
    train_data, temp_data = train_test_split(df_train, test_size=valid_perc, random_state=42)
    # 将临时集分为验证集和测试集(15%验证,15%测试)
    valid_data, test_data = train_test_split(temp_data, test_size=test_perc, random_state=42)
    
    # 归一化将像素从0-255整数转换为0-1浮点数,适合神经网络输入
    rescale = 1./255
    if preprocess_func is not None:
        # 如果使用Keras内置的ResNet50预处理函数,则无需归一化
        rescale = None

    train_datagen = ImageDataGenerator(
        rescale = rescale, 
        preprocessing_function=preprocess_func
    )

    # Keras生成器分为两步定义:
    # 首先定义通用属性,然后基于文件名等创建实际生成器
    train_generator = train_datagen.flow_from_dataframe(
        dataframe=train_data,
        directory=train_dir,
        x_col="filename",  # 数据框中包含图像文件名的列名
        y_col="classes",  # 数据框中的标签列
        batch_size=batch_size, 
        shuffle=shuffle,
        class_mode="binary",  # 多分类时用categorical,此时y_col可以是列表或元组
        target_size=(img_size,img_size),
        seed=42
    )

    valid_generator = train_datagen.flow_from_dataframe(
        dataframe=valid_data,
        directory=train_dir,
        x_col="filename",
        y_col="classes",
        batch_size=batch_size,
        shuffle=shuffle,
        class_mode="binary",
        target_size=(img_size,img_size),
        seed=42
    )

    test_generator = train_datagen.flow_from_dataframe(
        dataframe=test_data,
        directory=train_dir,
        x_col="filename",
        y_col="classes",
        batch_size=batch_size,
        shuffle=shuffle,
        class_mode="binary",
        target_size=(img_size,img_size),
        seed=42
    )

    return train_generator, valid_generator, test_generator, train_datagen

train_generator, valid_generator, test_generator, train_datagen = create_generators(0.3,0.5,shuffle = True)

运行上述代码后输出:

已验证314个图像文件名,分属2个类别。
已验证67个图像文件名,分属2个类别。
已验证68个图像文件名,分属2个类别。

接着执行模型定义与编译代码:

# 获取图像总数
train_size = len(train_generator.filenames)
# train_steps是Keras每个 epoch 运行生成器的步数,一步对应batch_size张图像
train_steps = len(train_generator)
# 用2倍图像数可以获得更多增强样本,可选操作
# 验证集同理
valid_size = len(valid_generator.filenames)
valid_steps = len(valid_generator)

from keras.regularizers import l2
from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential, load_model
from keras.layers import ( Dropout, Dense, Input, GlobalAveragePooling2D)
from keras.applications.resnet50 import ResNet50

def create_model(trainable_layer_count):
    input_tensor = Input(shape=(img_size, img_size, 3))
    base_model = ResNet50(include_top=False,weights='imagenet',input_tensor=input_tensor)
    if trainable_layer_count == "all":
        # 全预训练模型将被微调
        for layer in base_model.layers:
            layer.trainable = True
    else:
        # 如果不是所有层都可训练,先将所有层设为不可训练(固定)
        for layer in base_model.layers:
            layer.trainable = False
        # 最后将最后N层设为可训练
        # 思路是复用高层特征,微调细节
        for layer in base_model.layers[-trainable_layer_count:]:
            layer.trainable = True
    print("基础模型共有{}层".format(len(base_model.layers)))
    # 在预训练层之上构建自定义分类头
    x = GlobalAveragePooling2D()(base_model.output)
    x = Dropout(0.5)(x)
    x = Dense(64, activation='relu', kernel_regularizer=l2(5e-4))(x)
    x = Dropout(0.5)(x)
    # 二分类只需要1个神经元
    final_output = Dense(1, activation='sigmoid', name='final_output')(x)
    model = Model(input_tensor, final_output)
    
    return model

model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])

注:此处原问题附带两张训练过程的损失与准确率曲线图片

在验证数据上执行预测的代码:

valid_generator.reset()
df_valid = pd.DataFrame()

np.set_printoptions(suppress=True)
diffs = []
predictions = []
classes = []
DND_labels = []
for filename in tqdm(valid_generator.filenames):
    img = PIL.Image.open(f'{train_dir}/{filename}')
    resized = img.resize((img_size, img_size))
    np_img = np.array(resized)
    if "NonDefectueux" in filename:
        reference = 1 
        classes.append(NONDEFECTUEUX)
    else:
        reference = 0 
        classes.append(DEFECTUEUX)
    DND_labels.append(reference)
    score_predict = model.predict(preprocess_input(np_img[np.newaxis]))
    diffs.append(abs(reference-score_predict[0][0]))
    predictions.append(score_predict)

df_valid["filename"] = valid_generator.filenames
df_valid["classes"] = classes
df_valid["DND_label"] = DND_labels
df_valid["diff"] = diffs
df_valid["prediction"] = predictions

from sklearn.metrics import confusion_matrix

# 假设真实标签在df_valid["DND_label"],预测标签在df_valid["prediction"]
threshold = 0.5
df_valid['probability'] = predictions
df_valid['category'] = np.where(df_valid['probability'] > threshold, 1,0)
# 计算混淆矩阵
conf_matrix = confusion_matrix(df_valid["DND_label"], df_valid["category"])

# 打印混淆矩阵
print("Confusion Matrix:")
print(conf_matrix)

得到的混淆矩阵结果:

Confusion Matrix:
[[30 0]
[37 0]]

我尝试了一些修改,但仍然得到相同的结果,请求帮助!
该问题是由不平衡数据(unbalanced data)导致的还是其他原因?

感谢您的帮助


内容的提问来源于stack exchange,提问作者Hanane

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 12:14:55