我使用keras-tuner来获得模型的最佳超参数集。我可以在随机数据集上重现我的问题:
def generate_data(n_windows, n_timesteps):
feature_vector_list = []
label_list = []
for i in range(10):
x = tf.random.normal((n_windows, n_timesteps))
feature_vector = [x]
choices = [np.array([1, 0]), np.array([0, 1]),
np.array([0, 0]), np.array([1,1])]
labels = np.array([random.choice(choices) for i in range(n_windows)])
feature_vector_list.append(feature_vector)
label_list.append(labels)
return feature_vector_list, label_list
def custom_generator(feat_vector_list, label_list):
assert len(feat_vector_list) == len(label_list), \
"Number of feature vectors inconsistent with the number of labels"
counter = 0
while True:
feat_vec = feat_vector_list[counter]
list_labels = label_list[counter]
counter = (counter + 1) % len(feat_vector_list)
yield feat_vec, list_labels
以下是模型:
def model_builder(hp):
n_timesteps, n_features, n_outputs = 60, 1, 2
hp_units = hp.Int("units", min_value=50, max_value=500, step=50)
hp_filters = hp.Int("filters", 4, 32, step=4, default=8)
hp_kernel_size = hp.Int("kernel_size", 3, 50, step=1)
hp_pool_size = hp.Int("pool_size", 2, 8, step=1)
hp_dropout = hp.Float("dropout", 0.1, 0.5, step=0.1)
input1 = Input(shape=(n_timesteps, n_features))
conv1 = Conv1D(filters=hp_filters,
kernel_size=hp_kernel_size,
activation='relu')(input1)
drop1 = Dropout(hp_dropout)(conv1)
if hp.Choice("pooling", ["max", "avg"]) == "max":
pool1 = MaxPooling1D(pool_size=hp_pool_size)(drop1)
else:
pool1 = AveragePooling1D(pool_size=hp_pool_size)(drop1)
flatten1 = Flatten()(pool1)
# hidden layers
dense1 = Dense(hp_units, activation='relu')(flatten1)
outputs = Dense(n_outputs, activation='softmax')(dense1)
model = Model(inputs=[input1, input2], outputs=outputs)
model.compile(loss='categorical_crossentropy',
optimizer=tf.keras.optimizers.Adam(learning_rate=hp.Float("learning_rate",
0.01,
0.1,
step=0.2)),
metrics=['accuracy'])
return model
以下是训练脚本:
if __name__ == '__main__':
x_train, y_train = generate_data(350, 60)
x_val, y_val = generate_data(80, 60)
training_generator = custom_generator(x_train, y_train)
validation_generator = custom_generator(x_val, y_val)
tuner = kt.Hyperband(
model_builder,
objective="val_accuracy",
max_epochs=70,
factor=3,
directory="Results",
project_name="cnn_tunning"
)
stop_early = tf.keras.callbacks.EarlyStopping(monitor='val_loss',
patience=5,
min_delta=0.002)
tuner.search(
training_generator,
steps_per_epoch=N_WINDOWS,
validation_data=validation_generator,
validation_steps=75,
callbacks=[stop_early],
)
现在我发现,在hyperband开始使用相当数量的迭代之后,我设置的回调应该开始发挥作用,我得到这个错误:
W tensorflow/core/framework/op_kernel.cc:1733] INVALID_ARGUMENT: ValueError: Could not find callback with key=pyfunc_530 in the registry.
Traceback (most recent call last):
File "/home/diogomota/.cache/pypoetry/virtualenvs/WUAle-Z1-py3.7/lib/python3.7/site-packages/tensorflow/python/ops/script_ops.py", line 259, in __call__
raise ValueError(f"Could not find callback with key={token} in the "
ValueError: Could not find callback with key=pyfunc_530 in the registry.
W tensorflow/core/kernels/data/generator_dataset_op.cc:107] Error occurred when finalizing GeneratorDataset iterator: INVALID_ARGUMENT: ValueError: Could not find callback with key=pyfunc_530 in the registry.
Traceback (most recent call last):
File "/home/diogomota/.cache/pypoetry/virtualenvs/WUAle-Z1-py3.7/lib/python3.7/site-packages/tensorflow/python/ops/script_ops.py", line 259, in __call__
raise ValueError(f"Could not find callback with key={token} in the "
ValueError: Could not find callback with key=pyfunc_530 in the registry.
然而,它只是继续到下一个审判,所以我不知道是怎么回事,有人能解释为什么它不能找到回调?
我使用的是tensorflow 2.8
和keras-tuner 1.1.2
我只能在网上找到一个类似问题的地方,但没有提供解决方案:https://issuemode.com/issues/tensorflow/tensorflow/72982126
编辑:
1.提供完整的错误消息
1.经过进一步的调试,问题完全来自使用生成器作为.search()
的输入。我不知道这是一个问题的原因。使用.fit()
进行常规训练没有任何问题
1.增加了数据集生成代码,用于重现性
1条答案
按热度按时间kx7yvsdv1#
查看错误的源代码,并查看提供的similar error,看起来这个问题不是由于实际的模型回调引起的(
tf.keras.callbacks.EarlyStoppingCallback
)。错误发生在FuncRegistry
类中,这是一个帮助器,它维护了一个唯一标记到注册的python函数的Map,在这两种情况下,看起来都是这样,该令牌(pyfunc_XXX
)不Map到函数。当调用_internal_py_func
时,函数插入此处,在 Package Python函数时(要作为渴望的Tensorflow操作执行)或在计算渴望函数的梯度时。(FuncRegistry
对象)被提供给initialize_py_trampoline
,initialize_py_trampoline
通过PyBind绑定到C中的InitializePyTrampoline
函数,因此标记到函数Map的引用也在C运行时中维护。在这个级别上,从日志中跟踪错误到C++源代码,它发生在内部类
Iterator
的析构函数中,GeneratorDatasetOp
的字段。析构函数在对象超出范围或显式删除时被调用-这意味着它将在生成器完成其任务时被调用,这听起来可能与错误发生时您所做的观察一致。总而言之,如果没有数据集就无法进一步探测,那么听起来自定义生成器可能有问题。我建议尝试在没有
keras-tuner
和相同的生成器实现的情况下执行训练,以确定问题是否与其他链接的观察一致,因为他们没有使用keras-tuner
,而是使用自定义生成器。如果错误仍然存在,如果以前的版本(例如,Tensorflow 2.7或更低版本)的生成器也存在同样的问题。如果它一直失败,则可能需要向Tensorflow Github存储库提交实际问题,因为它实际上可能是一个核心错误,需要进一步研究。此外,如果你不需要使用生成器(比如,数据可以放入内存),我建议尝试直接提供数据集(使用numpy数组列表或numpy数组调用
fit
,而不是提供生成器函数),因为该路径不会触及当前失败的DatasetGenerator
代码,这应该不会影响你的超参数搜索。更新
感谢您提供的额外信息,包括复制生成器函数的代码。我能够在CPU上重现Python 3.7/Tensorflow 2.8/keras-tuner 1.1.2中的问题。如果您检查
_funcs
(全局注册表中的字段,用于维护对函数的弱引用的标记字典),它实际上是空的。进一步检查后,看起来每次开始新的试用时,_funcs
都会被清除并重新填充,如果keras-tuner每次都创建新的图形(模型),则这是一致的(尽管始终使用相同的注册表FuncRegistry
)。如果省略了
EarlyStopping
回调,则不会发生错误,因此您说错误与回调有关是正确的。此外,错误似乎是不确定的,因为每次运行的尝试和出现的时期都不同。随着错误原因的缩小,另一个人经历了the same issue,他们的观察结果是错误的原因与在回调中显式设置
min_delta
参数有关,正如您所做的那样,其他keras-tuner
示例都没有这样做(例如;在文档中的这个example和这个example中,它们只设置了monitor
和/或patience
)。在
EarlyStopping
回调中设置min_delta
的影响,默认设置为0,可以在这里看到。具体来说,当min_delta
设置为某个非零值时,_is_improvement
计算为True的频率会降低:请注意,在您的示例中,
self.monitor_op
是np.less
,因为您监视的指标是val_loss
:当
self._is_improvement
的计算频率较低时,patience
标准(self.wait >= self.patience
)将更频繁地得到满足,因为self.wait
的重置频率较低(因为默认情况下self.baseline
为None):随着范围的缩小,它似乎与模型更频繁地停止训练有关,并且当
keras-tuner
运行试验时,图中的操作引用不再存在。简单地说,这似乎是
keras-tuner
中需要提交的一个bug,我用这个响应中的所有细节做了here。为了在此期间继续进行,如果min_delta
条件不是必要的,我建议从EarlyStopping
中删除该参数并再次运行脚本,看看是否仍然遇到这个问题。更新2
谢谢你的额外信息。如果不使用生成器,我能够重现成功的运行,而且看起来other case I referenced也使用了与
EarlyStopping
一起使用的生成器,并提供了min_delta
。经过进一步检查,在注册表中找不到的函数是
finalize_py_func
,因为在清除_funcs
之前,每个导致错误Map到finalize_py_func
的标记中。它 Package 了一个python函数作为Tensorflow op使用。finalize_py_func
被定义并作为Tensorflow op返回的函数finalize_fn
在构建生成器时提供,在这里可以看到。查看生成器中finalize函数的文档,它说“在此数据集上的C++迭代器被销毁之前,将在init_func`的结果上调用的TensorFlow函数。”总的来说,错误与生成器有关,而不是min_delta参数。虽然设置
min_delta
可以加快错误发生的速度,但如果patience
降低到足以强制更频繁地触发提前停止回调,即使省略min_delta
也会发生错误。以您的示例为例,如果你设置patience
为1并删除min_delta
,错误很快就会出现。我已经修改了github issue以包含该细节。看起来错误仍然存在于Tensorflow 2.7中,但如果您降级到Tensorflow 2.6(和Keras 2.6),则不会发生错误。如果降级是可能的,这可能是继续进行直到问题得到解决的最佳选择。