MobileNet SSD目标检测维度错误:能否用1024x33图像训练?
尝试使用TensorFlow Object Detection API实现ssd_mobilenet_v2_fpnlite_320x320目标检测算法,输入图像尺寸设置为1024x33,运行训练脚本时触发如下ValueError:
ValueError: Dimensions must be equal, but are 4 and 3 for '{{node ssd_mobile_net_v2_fpn_keras_feature_extractor/FeatureMaps/top_down/add}} = AddV2[T=DT_FLOAT](ssd_mobile_net_v2_fpn_keras_feature_extractor/FeatureMaps/top_down/nearest_neighbor_upsampling/nearest_neighbor_upsampling/Reshape_1, ssd_mobile_net_v2_fpn_keras_feature_extractor/FeatureMaps/top_down/projection_2/BiasAdd)' with input shapes: [16,4,64,128], [16,3,64,128]. Call arguments received: • image_features=[("'layer_7'", 'tf.Tensor(shape=(16, 5, 128, 32), dtype=float32)'), ("'layer_14'", 'tf.Tensor(shape=(16, 3, 64, 96), dtype=float32)'), ("'layer_19'", 'tf.Tensor(shape=(16, 2, 32, 1280), dtype=float32)')] Call arguments received: • inputs=tf.Tensor(shape=(16, 33, 1024, 3), dtype=float32) • kwargs={'training': 'False'}
对应的pipeline.config配置如下:
# SSD with Mobilenet v2 FPN-lite (go/fpn-lite) feature extractor, shared box # predictor and focal loss (a mobile version of Retinanet). # Retinanet: see Lin et al, https://arxiv.org/abs/1708.02002 # Trained on COCO, initialized from Imagenet classification checkpoint # Train on TPU-8 # # Achieves 22.2 mAP on COCO17 Val model { ssd { inplace_batchnorm_update: true freeze_batchnorm: false num_classes: 1 box_coder { faster_rcnn_box_coder { y_scale: 10.0 x_scale: 10.0 height_scale: 5.0 width_scale: 5.0 } } matcher { argmax_matcher { matched_threshold: 0.5 unmatched_threshold: 0.5 ignore_thresholds: false negatives_lower_than_unmatched: true force_match_for_each_row: true use_matmul_gather: true } } similarity_calculator { iou_similarity { } } encode_background_as_zeros: true anchor_generator { multiscale_anchor_generator { min_level: 3 max_level: 7 anchor_scale: 4.0 aspect_ratios: [1.0, 2.0, 0.5] scales_per_octave: 2 } } image_resizer { fixed_shape_resizer { height: 33 width: 1024 } } box_predictor { weight_shared_convolutional_box_predictor { depth: 128 class_prediction_bias_init: -4.6 conv_hyperparams { activation: RELU_6, regularizer { l2_regularizer { weight: 0.00004 } } initializer { random_normal_initializer { stddev: 0.01 mean: 0.0 } } batch_norm { scale: true, decay: 0.997, epsilon: 0.001, } } num_layers_before_predictor: 4 share_prediction_tower: true use_depthwise: true kernel_size: 3 } } feature_extractor { type: 'ssd_mobilenet_v2_fpn_keras' use_depthwise: true fpn { min_level: 3 max_level: 7 additional_layer_depth: 128 } min_depth: 16 depth_multiplier: 1.0 conv_hyperparams { activation: RELU_6, regularizer { l2_regularizer { weight: 0.00004 } } initializer { random_normal_initializer { stddev: 0.01 mean: 0.0 } } batch_norm { scale: true, decay: 0.997, epsilon: 0.001, } } override_base_feature_extractor_hyperparams: true } loss { classification_loss { weighted_sigmoid_focal { alpha: 0.25 gamma: 2.0 } } localization_loss { weighted_smooth_l1 { } } classification_weight: 1.0 localization_weight: 1.0 } normalize_loss_by_num_matches: true normalize_loc_loss_by_codesize: true post_processing { batch_non_max_suppression { score_threshold: 1e-8 iou_threshold: 0.6 max_detections_per_class: 100 max_total_detections: 100 } score_converter: SIGMOID } } } train_config: { fine_tune_checkpoint_version: V2 fine_tune_checkpoint: "/content/models/mymodel/ssd_mobilenet_v2_fpnlite_320x320_coco17_tpu-8/checkpoint/ckpt-0" fine_tune_checkpoint_type: "detection" batch_size: 16 sync_replicas: true startup_delay_steps: 0 replicas_to_aggregate: 8 num_steps: 100 data_augmentation_options { random_horizontal_flip { } } data_augmentation_options { random_crop_image { min_object_covered: 0.0 min_aspect_ratio: 0.75 max_aspect_ratio: 3.0 min_area: 0.75 max_area: 1.0 overlap_thresh: 0.0 } } optimizer { momentum_optimizer: { learning_rate: { cosine_decay_learning_rate { learning_rate_base: .08 total_steps: 50000 warmup_learning_rate: .026666 warmup_steps: 1000 } } momentum_optimizer_value: 0.9 } use_moving_average: false } max_number_of_boxes: 100 unpad_groundtruth_tensors: false } train_input_reader: { label_map_path: "/content/labelmap.pbtxt" tf_record_input_reader { input_path: "/content/train.tfrecord" } } eval_config: { metrics_set: "coco_detection_metrics" use_moving_averages: false } eval_input_reader: { label_map_path: "/content/labelmap.pbtxt" shuffle: false num_epochs: 1 tf_record_input_reader { input_path: "/content/val.tfrecord" } }
核心疑问:是否可以使用1024x33这个图像尺寸进行该模型的训练?
错误原因
报错源于FPN(特征金字塔网络)的top-down特征融合环节:上层特征图经过上采样后,高度维度为4,而对应下层特征图的高度维度为3,两者无法进行逐元素相加操作。
这是因为输入图像高度33无法被多次2倍下采样整除:33经过第一次下采样变为16(取整),第二次8,第三次4,第四次2;但部分中间层特征(比如layer_14)的高度是3,和上采样后的特征高度4不匹配,导致维度冲突。原模型ssd_mobilenet_v2_fpnlite_320x320的输入尺寸320是2的幂次,下采样后所有层级特征图的尺寸都是整数,不会出现这类问题。
是否能用该尺寸训练?
不是完全不可行,但不推荐直接使用33作为高度,原因是需要修改API源码调整特征融合逻辑,成本很高。更高效的解决方式如下:
1. 修改输入高度为可被多次下采样整除的数值
把输入高度从33改为32(宽度1024保持不变),32是2的5次方,经过多次下采样后所有层级的特征图尺寸都会是整数,FPN融合时维度能完美对齐,直接解决报错问题。
修改pipeline.config中image_resizer的配置:
image_resizer { fixed_shape_resizer { height: 32 width: 1024 } }
2. 若必须保留33高度(不推荐)
需要修改TensorFlow Object Detection API中ssd_mobilenet_v2_fpn_keras_feature_extractor.py里的特征融合逻辑,手动调整上采样或特征图裁剪的尺寸,让对应层级的特征图维度匹配。这种方式需要对模型结构有深入理解,且后续维护成本高,仅适合有定制化需求的开发者。
内容的提问来源于stack exchange,提问作者mj01

