docstr: 对网络的预测数据进行后处理，包括
  （1）根据proposal以及预测的回归参数计算出最终bbox坐标
  （2）对预测类别结果进行softmax处理
  （3）裁剪预测的boxes信息，将越界的坐标调整到图片边界上
  （4）移除所有背景信息
  （5）移除低概率目标
  （6）移除小尺寸目标
  （7）执行nms处理，并按scores进行排序
  （8）根据scores排序返回前topk个目标
  Args:
      class_logits: 网络预测类别概率信息
      box_regression: 网络预测的边界框回归参数
      proposals: rpn输出的proposal
      image_shapes: 打包成batch前每张图像的宽高
  
  Returns:
docstr_tok: ["\u5bf9\u7f51\u7edc\u7684\u9884\u6d4b\u6570\u636e\u8fdb\u884c\u540e\u5904\u7406\uff0c\u5305\u62ec","\uff081\uff09\u6839\u636eproposal\u4ee5\u53ca\u9884\u6d4b\u7684\u56de\u5f52\u53c2\u6570\u8ba1\u7b97\u51fa\u6700\u7ec8bbox\u5750\u6807","\uff082\uff09\u5bf9\u9884\u6d4b\u7c7b\u522b\u7ed3\u679c\u8fdb\u884csoftmax\u5904\u7406","\uff083\uff09\u88c1\u526a\u9884\u6d4b\u7684boxes\u4fe1\u606f\uff0c\u5c06\u8d8a\u754c\u7684\u5750\u6807\u8c03\u6574\u5230\u56fe\u7247\u8fb9\u754c\u4e0a","\uff084\uff09\u79fb\u9664\u6240\u6709\u80cc\u666f\u4fe1\u606f","\uff085\uff09\u79fb\u9664\u4f4e\u6982\u7387\u76ee\u6807","\uff086\uff09\u79fb\u9664\u5c0f\u5c3a\u5bf8\u76ee\u6807","\uff087\uff09\u6267\u884cnms\u5904\u7406\uff0c\u5e76\u6309scores\u8fdb\u884c\u6392\u5e8f","\uff088\uff09\u6839\u636escores\u6392\u5e8f\u8fd4\u56de\u524dtopk\u4e2a\u76ee\u6807","Args",":","class_logits",":","\u7f51\u7edc\u9884\u6d4b\u7c7b\u522b\u6982\u7387\u4fe1\u606f","box_regression",":","\u7f51\u7edc\u9884\u6d4b\u7684\u8fb9\u754c\u6846\u56de\u5f52\u53c2\u6570","proposals",":","rpn\u8f93\u51fa\u7684proposal","image_shapes",":","\u6253\u5305\u6210batch\u524d\u6bcf\u5f20\u56fe\u50cf\u7684\u5bbd\u9ad8","Returns",":"]
code: def postprocess_detections(
      self,
      class_logits,  # type: Tensor
      box_regression,  # type: Tensor
      proposals,  # type: List[Tensor]
      image_shapes,  # type: List[Tuple[int, int]]
  ):
      # type: (...) -> Tuple[List[Tensor], List[Tensor], List[Tensor]]
      """
      对网络的预测数据进行后处理，包括
      （1）根据proposal以及预测的回归参数计算出最终bbox坐标
      （2）对预测类别结果进行softmax处理
      （3）裁剪预测的boxes信息，将越界的坐标调整到图片边界上
      （4）移除所有背景信息
      （5）移除低概率目标
      （6）移除小尺寸目标
      （7）执行nms处理，并按scores进行排序
      （8）根据scores排序返回前topk个目标
      Args:
          class_logits: 网络预测类别概率信息
          box_regression: 网络预测的边界框回归参数
          proposals: rpn输出的proposal
          image_shapes: 打包成batch前每张图像的宽高
  
      Returns:
  
      """
      device = class_logits.device
      # 预测目标类别数
      num_classes = class_logits.shape[-1]
  
      # 获取每张图像的预测bbox数量
      boxes_per_image = [
          boxes_in_image.shape[0] for boxes_in_image in proposals
      ]
      # 根据proposal以及预测的回归参数计算出最终bbox坐标
      pred_boxes = self.box_coder.decode(box_regression, proposals)
  
      # 对预测类别结果进行softmax处理
      pred_scores = F.softmax(class_logits, -1)
  
      # split boxes and scores per image
      # 根据每张图像的预测bbox数量分割结果
      pred_boxes_list = pred_boxes.split(boxes_per_image, 0)
      pred_scores_list = pred_scores.split(boxes_per_image, 0)
  
      all_boxes = []
      all_scores = []
      all_labels = []
      # 遍历每张图像预测信息
      for boxes, scores, image_shape in zip(
          pred_boxes_list, pred_scores_list, image_shapes
      ):
          # 裁剪预测的boxes信息，将越界的坐标调整到图片边界上
          boxes = box_ops.clip_boxes_to_image(boxes, image_shape)
  
          # create labels for each prediction
          labels = torch.arange(num_classes, device=device)
          labels = labels.view(1, -1).expand_as(scores)
  
          # remove prediction with the background label
          # 移除索引为0的所有信息（0代表背景）
          boxes = boxes[:, 1:]
          scores = scores[:, 1:]
          labels = labels[:, 1:]
  
          # batch everything, by making every class prediction be a separate instance
          boxes = boxes.reshape(-1, 4)
          scores = scores.reshape(-1)
          labels = labels.reshape(-1)
  
          # remove low scoring boxes
          # 移除低概率目标，self.scores_thresh=0.05
          # gt: Computes input > other element-wise.
          # inds = torch.nonzero(torch.gt(scores, self.score_thresh)).squeeze(1)
          inds = torch.where(torch.gt(scores, self.score_thresh))[0]
          boxes, scores, labels = (
              boxes[inds],
              scores[inds],
              labels[inds],
          )
  
          # remove empty boxes
          # 移除小目标
          keep = box_ops.remove_small_boxes(boxes, min_size=1.0)
          boxes, scores, labels = (
              boxes[keep],
              scores[keep],
              labels[keep],
          )
  
          # non-maximun suppression, independently done per class
          # 执行nms处理，执行后的结果会按照scores从大到小进行排序返回
          keep = box_ops.batched_nms(
              boxes, scores, labels, self.nms_thresh
          )
  
          # keep only topk scoring predictions
          # 获取scores排在前topk个预测目标
          keep = keep[: self.detection_per_img]
          boxes, scores, labels = (
              boxes[keep],
              scores[keep],
              labels[keep],
          )
  
          all_boxes.append(boxes)
          all_scores.append(scores)
          all_labels.append(labels)
  
      return all_boxes, all_scores, all_labels
  
file_path: deep-learning-for-image-processing/pytorch_object_detection/faster_rcnn/network_files/roi_head.py
imports: from typing import Optional, List, Dict, Tuple
  import torch
  from torch import Tensor
  import torch.nn.functional
  from .None import det_utils
  from .None import boxes
label_desc: Use image node_id 7 for calling the RoIHeads obj's underlying member method code with example usage: obj.postprocess_detections(class_logits, box_regression, proposals, image_shapes) and returns: all_boxes,  all_scores,  all_labels