使用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的调用时机是否相同(都是在输入模型前)?
可以抽取一批样本,分别用直接加载和生成器加载的方式获取数据,逐像素对比,确认两者的预处理结果完全一致。
进一步测试方向
- 优先修复ResNet50的实例化错误,重新训练模型,观察精度是否恢复;
- 如果修复后精度仍有差距,添加数据打乱逻辑,对比训练效果;
- 验证生成器输出的样本数量是否正确:检查
__len__返回的步数,确保每个epoch训练的样本总数与直接加载时一致; - 可以尝试关闭生成器的打乱逻辑(
shuffle=False),同时直接加载数据时设置shuffle=False,看两者精度是否一致,以此排除打乱逻辑的影响。
内容的提问来源于stack exchange,提问作者Adhx
相关产品推荐
相关产品推荐

