使用Keras Tuner时如何避免生成器引发StopIteration?
Keras Random Search Tuner 生成器触发StopIteration问题
使用Keras Random Search Tuner时遇到如下问题:
默认情况下可直接传入训练集x_train和y_train,但因数据特性,需遍历列表逐个向调优器提供数据文件。此前搭建CNN只需遍历一次数据,无问题;但Random Search需在多次试验中迭代寻找最优解,此时使用普通生成器会触发StopIteration,导致无法正常运行。
当前代码:
tuner = RandomSearch(build_model, objective="accuracy", overwrite=True, #project_name="AC1", max_trials = 5, executions_per_trial=5 ) def generate_arrays_from_file(x_train, y_train): for x, y in zip(x_train, y_train): yield (x, y) tuner.search(generate_arrays_from_file(X_train, Y_train), verbose=0)
数据情况:
数据形状为(388, 96, 36, 36, 36),待调优模型为3D CNN,每次需输入形状为(96, 36, 36, 36)的数据文件。数据共包含388个数据点,每个数据点含96个立方体数组及对应二分类标签(0或1)。
解决方案
1. 使用keras.utils.Sequence替代生成器
普通生成器是一次性迭代器,遍历完即抛出StopIteration,而Random Search的每个试验需要多次遍历数据(多epoch训练)。Sequence是Keras提供的可重复迭代的数据结构,完美适配这种场景:
from tensorflow.keras.utils import Sequence class DataSequence(Sequence): def __init__(self, x_data, y_data): self.x_data = x_data self.y_data = y_data self.sample_count = len(x_data) def __len__(self): # 返回每个epoch的训练步数(这里每个batch取1个样本) return self.sample_count def __getitem__(self, idx): # 按索引返回对应样本 return self.x_data[idx], self.y_data[idx]
使用时直接传入Sequence实例:
tuner.search(DataSequence(X_train, Y_train), verbose=0)
每次试验的每个epoch都会从Sequence重新按索引取数据,不会触发StopIteration。
2. 展开数据直接传入
将(388,96,36,36,36)的形状展开为(388*96, 36,36,36),同时将标签对应扩展为(388*96,),这样可直接将展开后的数据传入tuner.search:
import numpy as np # 展开特征数据 x_flat = X_train.reshape(-1, 36, 36, 36) # 重复标签,每个数据点的96个立方体对应同一个标签 y_flat = np.repeat(Y_train, 96) tuner.search(x_flat, y_flat, verbose=0)
这种方法无需自定义数据结构,操作简单,但需注意:
- 展开后样本量变为37248,会增加内存占用,需确保内存足够;
- 需确认任务逻辑允许将每个数据点的96个立方体作为独立样本训练(若原任务中96个立方体是一组关联数据,此方案需谨慎评估合理性)。
内容的提问来源于stack exchange,提问作者Sloxy
相关产品推荐
相关产品推荐

