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

使用tf.keras.utils.Sequence作为数据生成器时ResNet50图像分类器精度下降问题排查

问题分析与解决方案

看起来你遇到的核心问题是使用keras.utils.Sequence生成器后模型精度骤降,结合你的代码和测试结果,我梳理了几个最可能的根源,以及对应的修复和测试方向:

1. ResNet50模型实例化错误(最致命的问题)

从你的模型代码里能看到一个关键错误:你创建了ResNet50的实例但没有将其赋值给变量,反而直接修改了ResNet50类的trainable属性,最后把类本身添加到模型中。这会导致模型初始化一个全新的、未加载预训练权重的ResNet50实例,相当于从头训练随机初始化的网络,精度自然会暴跌。

修复代码:

# 正确实例化ResNet50并赋值给变量
base_model = ResNet50(weights="imagenet", include_top=False, input_shape=(128,128,3), pooling="avg")
base_model.trainable = False  # 修改实例的trainable属性,而不是类的属性

# ...

model.add(layers.Lambda(preprocess_input, input_shape=[128,128,3]))
model.add(base_model)  # 添加预训练好的实例,而不是类本身

2. 生成器未实现epoch级数据打乱

keras.utils.Sequence默认不会在每个epoch结束后打乱数据,而你直接加载数据训练时,model.fit默认开启了shuffle=True。固定的样本顺序会让模型更容易记住数据顺序,无法充分学习泛化特征,进而导致精度下降。

修复生成器:

给DataGeneratorSV添加on_epoch_end方法,实现每个epoch后打乱数据的逻辑:

class DataGeneratorSV(Sequence):
    """ Generates data. """
    def __init__(
        self, x_set, y_set, batch_size=32, size=128, channels=3, shuffle=True
    ):
        self.x, self.y = x_set, y_set
        self.batch_size = batch_size
        self.size = size
        self.channels = channels
        self.shuffle = shuffle
        self.on_epoch_end()  # 初始化时先打乱一次

    def __len__(self):
        return ceil(len(self.x) / self.batch_size)

    def __getitem__(self, idx):
        batch_x = self.x[idx * self.batch_size : (idx + 1) * self.batch_size]
        batch_y = self.y[idx * self.batch_size : (idx + 1) * self.batch_size]

        return np.array(
            [
                cv2.resize(cv2.cvtColor(cv2.imread(file_name),cv2.COLOR_BGR2RGB), (self.size, self.size))
                for file_name in batch_x
            ]
        ), np.array(batch_y)

    def on_epoch_end(self):
        """每个epoch结束后打乱数据"""
        if self.shuffle:
            # 生成随机索引,同时打乱x和y,保证样本与标签的对应关系
            indices = np.arange(len(self.x))
            np.random.shuffle(indices)
            self.x = [self.x[i] for i in indices]
            self.y = [self.y[i] for i in indices]

3. 预处理流程的细微差异

虽然你验证了生成器输出数据无异常,但仍需确认直接加载数据时的预处理流程和生成器完全一致:

  • 直接加载时是否也使用cv2.resize、COLOR_BGR2RGB转换?
  • preprocess_input的调用时机是否相同(都是在输入模型前)?

可以抽取一批样本,分别用直接加载和生成器加载的方式获取数据,逐像素对比,确认两者的预处理结果完全一致。

进一步测试方向

  1. 优先修复ResNet50的实例化错误,重新训练模型,观察精度是否恢复;
  2. 如果修复后精度仍有差距,添加数据打乱逻辑,对比训练效果;
  3. 验证生成器输出的样本数量是否正确:检查__len__返回的步数,确保每个epoch训练的样本总数与直接加载时一致;
  4. 可以尝试关闭生成器的打乱逻辑(shuffle=False),同时直接加载数据时设置shuffle=False,看两者精度是否一致,以此排除打乱逻辑的影响。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 20:37:45