构建Keras模型时如何修改张量值:YOLO自定义Lambda层输出形状报错
问题修复方案
以下是你代码中存在的问题和对应修复方法:
- 静态形状获取错误:你在
yolo_head函数中使用preds.get_shape().as_list()获取张量形状,该方法只能拿到编译阶段的静态形状,当batch维度为动态值(也就是None)时,拿到的形状会包含None,直接索引会报错,应该替换为tf.shape(preds)获取运行时的动态形状。 - 维度拼接逻辑错误:你当前在补全不足10个检测结果的分支里,使用
axis=0拼接preds和current,这是在batch维度拼接,会导致batch数变大,完全不符合你的输出要求。你应该调整为axis=1在第二个维度拼接,且拼接前要保证两个张量的维度匹配,你当前拼接后的preds是2维张量,需要先reshape为(batch_size, num_boxes, 5)的3维结构再补全到10个框的长度。 - Lambda层输出形状未显式声明:Keras在编译阶段无法自动推断Lambda层自定义函数的输出形状,你需要在定义Lambda层时显式指定
output_shape参数。 - 损失函数不匹配:你当前使用的
categorical_crossentropy是分类任务损失,你的输出是检测框坐标、置信度相关的张量,完全不匹配,你需要替换为YOLO对应的检测损失函数。
修改后的核心代码参考:
def yolo_head(x): boxes_ = x[:,:,:,:,1:5] confidence_ = x[:,:,:,:,:1] classes_ = x[:,:,:,:,5:] scores, boxes, classes = yolo_filter_boxes(boxes_, confidence_, classes_, threshold) scores, boxes, classes = yolo_non_max_suppression(scores, boxes, classes, max_box, threshold_iou) classes = tf.cast(classes, tf.float32) preds = scores * classes # 获取运行时动态形状 batch_size = tf.shape(preds)[0] # 拼接得分数值和框坐标,生成(batch, 框数量, 5)的结构:1位得分+4位框坐标 preds = tf.reshape(preds, (batch_size, -1, 1)) boxes = tf.reshape(boxes, (batch_size, -1, 4)) preds = tf.concat([preds, boxes], axis=-1) num_boxes = tf.shape(preds)[1] # 不足10个框则补零,超过10个则截断 def pad_boxes(): pad_tensor = tf.zeros((batch_size, 10 - num_boxes, 5), dtype=tf.float32) return tf.concat([preds, pad_tensor], axis=1) def trunc_boxes(): return preds[:, :10, :] preds = tf.cond(num_boxes < 10, pad_boxes, trunc_boxes) # 固定静态形状帮助Keras推断 preds.set_shape((None, 10, 5)) return preds def create_model(): total_ = 19*19*no_of_anchors*6 pretrained_model = tf.keras.applications.MobileNetV2( input_shape=(512, 512, 3), include_top=False, weights='imagenet', pooling='max' ) pretrained_model.trainable = False inputs = pretrained_model.input x=tf.keras.layers.Flatten()(pretrained_model.output) x = tf.keras.layers.Dense(total_, activation='relu',bias_initializer=tf.zeros_initializer(),kernel_initializer=tf.keras.initializers.Ones())(x) x = tf.keras.layers.Reshape((19, 19, no_of_anchors, 6))(x) # 显式指定Lambda层输出形状 outputs = tf.keras.layers.Lambda(yolo_head, output_shape=(10,5))(x) model = tf.keras.Model(inputs=inputs, outputs=outputs) # 注意此处损失函数需要替换为YOLO对应的检测损失,当前损失不匹配任务 model.compile( optimizer='adam', loss='你的自定义YOLO损失函数', metrics=['accuracy'] ) return model
内容的提问来源于stack exchange,提问作者still refreshing
相关产品推荐
相关产品推荐

