基于Keras构建手写识别模型时遇输入为空错误求助
inputs argument cannot be empty 环境配置
- MacOS Sonoma 14.5,Python 3.12.3
- VSCode(最新版本)
- Tensorflow 2.16.1
- Matplotlib 3.9.0
- Keras 3.3.3
问题描述
跟随Keras官方教程构建手写文本识别模型(HTR),训练启动时失败,报错信息如下:
2024-06-02 19:26:11.552695: W tensorflow/core/framework/local_rendezvous.cc:404] Local rendezvous is aborting with status: OUT_OF_RANGE: End of sequence
Traceback (most recent call last):
File "/Volumes/Ugreen SSD/Py/keras-HTR-ENG/model.py", line 355, in
prediction_model = keras.models.Model(
^^^^^^^^^^^^^^^^^^^
File "/Volumes/Ugreen SSD/Py/keras-HTR-ENG/.venv/lib/python3.12/site-packages/keras/src/models/model.py", line 143, in new
return functional.Functional(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Volumes/Ugreen SSD/Py/keras-HTR-ENG/.venv/lib/python3.12/site-packages/keras/src/utils/tracking.py", line 26, in wrapper
return fn(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^
File "/Volumes/Ugreen SSD/Py/keras-HTR-ENG/.venv/lib/python3.12/site-packages/keras/src/models/functional.py", line 162, in init
Function.init(self, inputs, outputs, name=name, **kwargs)
File "/Volumes/Ugreen SSD/Py/keras-HTR-ENG/.venv/lib/python3.12/site-packages/keras/src/ops/function.py", line 62, in init
raise ValueError(
ValueError:inputsargument cannot be empty. Received:
inputs=[]
outputs=<KerasTensor shape=(None, 32, 79), dtype=float32, sparse=False, name=keras_tensor_20>
问题代码片段
class EditDistanceCallback(keras.callbacks.Callback): def __init__(self, pred_model): super().__init__() self.prediction_model = pred_model def on_epoch_end(self, epoch, logs=None): edit_distances = [] for i in range(len(validation_images)): labels = validation_labels[i] predictions = self.prediction_model.predict(validation_images[i]) edit_distances.append(calculate_edit_distance(labels, predictions).numpy()) print( f"Mean edit distance for epoch {epoch + 1}: {np.mean(edit_distances):.4f}" ) epochs = 10 # 要得到好结果至少需要训练50轮 model = build_model() prediction_model = keras.models.Model( model.get_layer(name="image").input, model.get_layer(name="dense2").output ) edit_distance_callback = EditDistanceCallback(prediction_model) # 训练模型 history = model.fit( train_ds, validation_data=validation_ds, epochs=epochs, callbacks=[edit_distance_callback], )
排查情况
猜测是向keras.models.Model传入了空值,但已确认模型能正确识别图像数量,参数输出正常:
Total params: 423,823 (1.62 MB) Trainable params: 423,823 (1.62 MB) Non-trainable params: 0 (0.00 B)
所有图片均为原始未编辑的.png格式,已多次下载数据集排除损坏问题。
模型构建代码
def build_model(): # 模型输入 input_img = keras.Input(shape=(image_width, image_height, 1), name="image") labels = keras.layers.Input(name="label", shape=(None,)) # 第一个卷积块 x = keras.layers.Conv2D( 32, (3, 3), activation="relu", kernel_initializer="he_normal", padding="same", name="Conv1", )(input_img) x = keras.layers.MaxPooling2D((2, 2), name="pool1")(x) # 第二个卷积块 x = keras.layers.Conv2D( 64, (3, 3), activation="relu", kernel_initializer="he_normal", padding="same", name="Conv2", )(x) x = keras.layers.MaxPooling2D((2, 2), name="pool2")(x) # 我们用了两次池化,步长和池化大小都是2,因此特征图缩小为原来的1/4 # 最后一层卷积有64个滤波器,需要先调整形状再传入RNN部分 new_shape = ((image_width // 4), (image_height // 4) * 64) x = keras.layers.Reshape(target_shape=new_shape, name="reshape")(x) x = keras.layers.Dense(64, activation="relu", name="dense1")(x) x = keras.layers.Dropout(0.2)(x) # RNN层 x = keras.layers.Bidirectional( keras.layers.LSTM(128, return_sequences=True, dropout=0.25) )(x) x = keras.layers.Bidirectional( keras.layers.LSTM(64, return_sequences=True, dropout=0.25) )(x) # +2是为了兼容CTC损失引入的两个特殊标记 x = keras.layers.Dense( len(char_to_num.get_vocabulary()) + 2, activation="softmax", name="dense2" )(x) # 添加CTC层计算每一步的损失 output = CTCLayer(name="ctc_loss")(labels, x) # 定义模型 model = keras.models.Model( inputs=[input_img, labels], outputs=output, name="handwriting_recognizer" ) # 优化器 opt = keras.optimizers.Adam() # 编译模型并返回 model.compile(optimizer=opt) return model # 获取模型 model = build_model() model.summary()
解决方案
报错核心原因是Keras 3中获取输入层的方式发生了变化,原代码中model.get_layer(name="image").input无法正确返回输入张量,导致传入keras.models.Model的inputs为空。
修改prediction_model的创建代码,直接从原模型的输入列表中取出图像输入:
# 替换原prediction_model创建代码 prediction_model = keras.models.Model( model.input[0], model.get_layer(name="dense2").output )
或者更清晰的写法:
prediction_model = keras.models.Model( inputs=model.inputs[0], outputs=model.get_layer("dense2").output )
Keras 3中,Model.get_layer().input返回的是该层的输入张量,但由于CTC层的特殊结构,原模型的输入层可能未被正确追踪,直接取model.inputs列表的第一个元素(对应图像输入)是更可靠的方式。
内容的提问来源于stack exchange,提问作者Adwal

