TensorFlow Keras中自定义Sequence生成器配合model.fit训练时的ValueError问题排查
解决自定义Sequence生成器无法适配Keras模型的问题
这个错误的核心原因是你混用了原生Keras和TensorFlow集成的Keras(tf.keras)模块,导致自定义的MyDataGenerator(继承自tf.keras.utils.Sequence)和你创建的keras.Sequential模型属于不同的Keras实例,数据适配器无法识别这种跨模块的组合。
修复步骤
1. 统一使用tf.keras模块
把所有Keras相关的导入替换为tf.keras,彻底避免原生Keras和tf.keras的冲突:
import tensorflow as tf import numpy as np from tensorflow.keras.utils import Sequence from tensorflow.keras import Sequential from tensorflow.keras.layers import InputLayer, Dense, Flatten import math # 补充导入math,你的__len__方法用到了但代码里没写
2. 确保生成器返回的标签类型兼容
虽然你用numpy数组训练时uint32的标签能运行,但为了更稳妥,建议把生成器中y的类型改为int32或float32(符合二分类任务的常规类型):
def __getitem__(self, index): index = self.index[index * self.batch_size:(index + 1) * self.batch_size] batch = [self.indices[k] for k in index] X = np.zeros((self.batch_size, *self.dim), dtype=np.float32) y = np.zeros((self.batch_size,), dtype=np.int32) # 修改标签类型 return X, y
3. 验证生成器的完整性
检查你的MyDataGenerator是否完全符合Sequence的规范:
__len__方法正确计算了每个epoch的步数(你已经用math.ceil实现,记得导入math)__getitem__返回的是(输入数据, 标签)的元组on_epoch_end正确实现了索引打乱逻辑
为什么会出现这个错误?
在TensorFlow 2.x中,官方推荐使用tf.keras而不是原生Keras,两者的内部实现和数据适配逻辑是独立的。你用tf.keras.utils.Sequence写的生成器,无法被原生keras模型的数据适配器识别,所以抛出了"找不到数据适配器"的错误。而直接用numpy数组训练时,numpy数组是通用数据类型,两个模块都能处理,所以没问题。
修复后的完整训练代码示例
# 统一导入tf.keras import tensorflow as tf import numpy as np from tensorflow.keras.utils import Sequence from tensorflow.keras import Sequential from tensorflow.keras.layers import InputLayer, Dense, Flatten import math class MyDataGenerator(Sequence): def __init__(self, df, x_col='filename', y_col='class', batch_size=32, path='./', num_classes=None, shuffle=True, dim=(634,513,1), nfft=1024, hstep=256, sr=16000): self.batch_size = batch_size self.df = df self.indices = self.df.index.tolist() self.num_classes = num_classes self.path = path self.shuffle = shuffle self.x_col = x_col self.y_col = y_col self.on_epoch_end() self.dim = dim self.nfft = nfft self.hstep = hstep self.sr = sr def __getitem__(self, index): index = self.index[index * self.batch_size:(index + 1) * self.batch_size] batch = [self.indices[k] for k in index] X = np.zeros((self.batch_size, *self.dim), dtype=np.float32) y = np.zeros((self.batch_size,), dtype=np.int32) # 后续记得补充实际加载数据的逻辑,当前只是占位 return X, y def __len__(self): return math.ceil(len(self.indices) / self.batch_size) def on_epoch_end(self): self.index = np.arange(len(self.indices)) if self.shuffle == True: np.random.shuffle(self.index) # 假设df_training和df_validation是已定义的DataFrame train_datagen = MyDataGenerator(df_training) valid_datagen = MyDataGenerator(df_validation, shuffle=False) # 用tf.keras创建模型 model = Sequential(name='Test_model') model.add(InputLayer((634, 513, 1), name='Input')) model.add(Flatten(name='Flatten')) model.add(Dense(1, activation='sigmoid', name='Output')) model.summary() model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy']) # 训练模型 model.fit( train_datagen, epochs=1, verbose=1, validation_data=valid_datagen )
这样修改后,你的自定义生成器就能被tf.keras模型正确识别,正常进行训练了。
内容的提问来源于stack exchange,提问作者Spiritgyx
相关产品推荐
相关产品推荐

