TF对象检测:返回推理有效载荷的子集

问题描述

问题

我正在使用TF的对象检测API训练和部署实例细分模型。我能够成功训练模型,将其打包到TF服务Docker映像(截至2020年10月为latest标签)中,并通过REST接口处理推理请求。但是,从推理请求返回的数据量非常大(数百Mb)。当推理请求和处理不在同一台计算机上进行时,这是一个大问题,因为所有返回的数据都必须通过网络传输。

是否有一种方法可以减少输出数量(在模型导出期间或在TF服务图像内),以便在推理过程中缩短往返时间?

详细信息

我正在使用TF OD API(带有TF2)来训练Mask RCNN模型,该模型是this config修改版本。我相信输出的完整列表在代码here中进行了描述。我在推理过程中得到的项目列表也粘贴在下面。对于具有100个对象建议的模型,如果我只是将返回的推论作为json写入磁盘,则该信息约为270 Mb。

inference_payload['outputs'].keys()

dict_keys(['detection_masks','rpn_features_to_crop','detection_anchor_indices','refined_Box_encodings','final_anchors','mask_predictions','detection_classes','num_detections','rpn_Box_predictor_features','class_predictions_with_background','proposal_Boxes','raw_detection_Boxes','rpn_Box_encodings','Box_classifier_features','raw_detection_scores','proposal_Boxes_normalized','detection_multiclass_scores','anchors','num_proposals','detection_Boxes','image_shape','rpn_objectness_predictions_with_background','detection_scores'])

我已经将推理请求中的图像编码为base64,因此通过网络访问时,请求有效负载不会太大。相比之下,推理响应是巨大的。我仅需要此响应中的4或5个项目,因此最好排除其余部分,并避免在网络上传递这么大的比特包。

我尝试过的事情

  1. 我尝试在导出(code example here)期间将score_threshold设置为较高的值,以减少输出数量。但是,这似乎只是对detection_scores作了限制。仍然返回所有无关的推断信息。
  2. 我还尝试通过添加删除here键名来手动排除这些推断输出中的一些。这似乎也没有任何作用,我担心这是个坏主意,因为在评分/评估过程中可能需要其中一些键。
  3. 我也在这里tensorflow/models仓库中搜索,但找不到任何东西。

解决方法

我找到了一个笨拙的解决方法。在导出过程(here)中,预测dict的部分组件被删除。我向 non_tensor_predictions 列表添加了其他项目,其中包含将在后处理步骤中删除的所有键。增加这个列表将我的推理输出从 ~200MB 减少到 ~12MB。

if self._number_of_stages == 3 块的完整代码:

    if self._number_of_stages == 3:

      non_tensor_predictions = [
          k for k,v in prediction_dict.items() if not isinstance(v,tf.Tensor)]

      # Add additional keys to delete during postprocessing
      non_tensor_predictions = non_tensor_predictions + ['raw_detection_scores','detection_multiclass_scores','anchors','rpn_objectness_predictions_with_background','detection_anchor_indices','refined_box_encodings','class_predictions_with_background','raw_detection_boxes','final_anchors','rpn_box_encodings','box_classifier_features']
      
      for k in non_tensor_predictions:
        tf.logging.info('Removing {0} from prediction_dict'.format(k))
        prediction_dict.pop(k)

      return prediction_dict

我认为在创建 TF Serving 映像期间使用签名定义有一种更“正确”的方法来处理此问题,但这适用于快速而肮脏的修复。

,

如果您使用 exporter_main_v2.py 文件导出模型,您可以尝试这种 hack 方式来解决这个问题。

只需在_run_inference_on_images文件的exporter_lib_v2.py函数中添加如下代码:

    detections[classes_field] = (
        tf.cast(detections[classes_field],tf.float32) + label_id_offset)

############# START ##########
    ignored_model_output_names = ["raw_detection_boxes","raw_detection_scores"]
    for key in ignored_model_output_names:
        if key in detections.keys(): del detections[key]
############# END ##########

    for key,val in detections.items():
      detections[key] = tf.cast(val,tf.float32)

因此,生成的模型不会输出ignored_model_output_names的值。

请告诉我这是否可以解决您的问题。

,

我遇到了同样的问题。在exporter_main_v2代码中,声明输出应为:

and the following output nodes returned by the model.postprocess(..):
  * `num_detections`: Outputs float32 tensors of the form [batch]
      that specifies the number of valid boxes per image in the batch.
  * `detection_boxes`: Outputs float32 tensors of the form
      [batch,num_boxes,4] containing detected boxes.
  * `detection_scores`: Outputs float32 tensors of the form
      [batch,num_boxes] containing class scores for the detections.
  * `detection_classes`: Outputs float32 tensors of the form
      [batch,num_boxes] containing classes for the detections.

我已经提交了关于tensorflow对象检测github存储库的问题,希望我们能够从tensorflow开发团队获得反馈。

可以找到here

的github问题