utils.py 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. # Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. from __future__ import absolute_import
  15. from __future__ import division
  16. from __future__ import print_function
  17. import paddle
  18. import paddle.nn.functional as F
  19. __all__ = [
  20. 'pad_gt', 'gather_topk_anchors', 'check_points_inside_bboxes',
  21. 'compute_max_iou_anchor', 'compute_max_iou_gt',
  22. 'generate_anchors_for_grid_cell'
  23. ]
  24. def pad_gt(gt_labels, gt_bboxes, gt_scores=None):
  25. r""" Pad 0 in gt_labels and gt_bboxes.
  26. Args:
  27. gt_labels (Tensor|List[Tensor], int64): Label of gt_bboxes,
  28. shape is [B, n, 1] or [[n_1, 1], [n_2, 1], ...], here n = sum(n_i)
  29. gt_bboxes (Tensor|List[Tensor], float32): Ground truth bboxes,
  30. shape is [B, n, 4] or [[n_1, 4], [n_2, 4], ...], here n = sum(n_i)
  31. gt_scores (Tensor|List[Tensor]|None, float32): Score of gt_bboxes,
  32. shape is [B, n, 1] or [[n_1, 4], [n_2, 4], ...], here n = sum(n_i)
  33. Returns:
  34. pad_gt_labels (Tensor, int64): shape[B, n, 1]
  35. pad_gt_bboxes (Tensor, float32): shape[B, n, 4]
  36. pad_gt_scores (Tensor, float32): shape[B, n, 1]
  37. pad_gt_mask (Tensor, float32): shape[B, n, 1], 1 means bbox, 0 means no bbox
  38. """
  39. if isinstance(gt_labels, paddle.Tensor) and isinstance(gt_bboxes,
  40. paddle.Tensor):
  41. assert gt_labels.ndim == gt_bboxes.ndim and \
  42. gt_bboxes.ndim == 3
  43. pad_gt_mask = (
  44. gt_bboxes.sum(axis=-1, keepdim=True) > 0).astype(gt_bboxes.dtype)
  45. if gt_scores is None:
  46. gt_scores = pad_gt_mask.clone()
  47. assert gt_labels.ndim == gt_scores.ndim
  48. return gt_labels, gt_bboxes, gt_scores, pad_gt_mask
  49. elif isinstance(gt_labels, list) and isinstance(gt_bboxes, list):
  50. assert len(gt_labels) == len(gt_bboxes), \
  51. 'The number of `gt_labels` and `gt_bboxes` is not equal. '
  52. num_max_boxes = max([len(a) for a in gt_bboxes])
  53. batch_size = len(gt_bboxes)
  54. # pad label and bbox
  55. pad_gt_labels = paddle.zeros(
  56. [batch_size, num_max_boxes, 1], dtype=gt_labels[0].dtype)
  57. pad_gt_bboxes = paddle.zeros(
  58. [batch_size, num_max_boxes, 4], dtype=gt_bboxes[0].dtype)
  59. pad_gt_scores = paddle.zeros(
  60. [batch_size, num_max_boxes, 1], dtype=gt_bboxes[0].dtype)
  61. pad_gt_mask = paddle.zeros(
  62. [batch_size, num_max_boxes, 1], dtype=gt_bboxes[0].dtype)
  63. for i, (label, bbox) in enumerate(zip(gt_labels, gt_bboxes)):
  64. if len(label) > 0 and len(bbox) > 0:
  65. pad_gt_labels[i, :len(label)] = label
  66. pad_gt_bboxes[i, :len(bbox)] = bbox
  67. pad_gt_mask[i, :len(bbox)] = 1.
  68. if gt_scores is not None:
  69. pad_gt_scores[i, :len(gt_scores[i])] = gt_scores[i]
  70. if gt_scores is None:
  71. pad_gt_scores = pad_gt_mask.clone()
  72. return pad_gt_labels, pad_gt_bboxes, pad_gt_scores, pad_gt_mask
  73. else:
  74. raise ValueError('The input `gt_labels` or `gt_bboxes` is invalid! ')
  75. def gather_topk_anchors(metrics, topk, largest=True, topk_mask=None, eps=1e-9):
  76. r"""
  77. Args:
  78. metrics (Tensor, float32): shape[B, n, L], n: num_gts, L: num_anchors
  79. topk (int): The number of top elements to look for along the axis.
  80. largest (bool) : largest is a flag, if set to true,
  81. algorithm will sort by descending order, otherwise sort by
  82. ascending order. Default: True
  83. topk_mask (Tensor, bool|None): shape[B, n, topk], ignore bbox mask,
  84. Default: None
  85. eps (float): Default: 1e-9
  86. Returns:
  87. is_in_topk (Tensor, float32): shape[B, n, L], value=1. means selected
  88. """
  89. num_anchors = metrics.shape[-1]
  90. topk_metrics, topk_idxs = paddle.topk(
  91. metrics, topk, axis=-1, largest=largest)
  92. if topk_mask is None:
  93. topk_mask = (topk_metrics.max(axis=-1, keepdim=True) > eps).tile(
  94. [1, 1, topk])
  95. topk_idxs = paddle.where(topk_mask, topk_idxs,
  96. paddle.zeros_like(topk_idxs))
  97. is_in_topk = F.one_hot(topk_idxs, num_anchors).sum(axis=-2)
  98. is_in_topk = paddle.where(is_in_topk > 1,
  99. paddle.zeros_like(is_in_topk), is_in_topk)
  100. return is_in_topk.astype(metrics.dtype)
  101. def check_points_inside_bboxes(points, bboxes, eps=1e-9):
  102. r"""
  103. Args:
  104. points (Tensor, float32): shape[L, 2], "xy" format, L: num_anchors
  105. bboxes (Tensor, float32): shape[B, n, 4], "xmin, ymin, xmax, ymax" format
  106. eps (float): Default: 1e-9
  107. Returns:
  108. is_in_bboxes (Tensor, float32): shape[B, n, L], value=1. means selected
  109. """
  110. points = points.unsqueeze([0, 1])
  111. x, y = points.chunk(2, axis=-1)
  112. xmin, ymin, xmax, ymax = bboxes.unsqueeze(2).chunk(4, axis=-1)
  113. l = x - xmin
  114. t = y - ymin
  115. r = xmax - x
  116. b = ymax - y
  117. bbox_ltrb = paddle.concat([l, t, r, b], axis=-1)
  118. return (bbox_ltrb.min(axis=-1) > eps).astype(bboxes.dtype)
  119. def compute_max_iou_anchor(ious):
  120. r"""
  121. For each anchor, find the GT with the largest IOU.
  122. Args:
  123. ious (Tensor, float32): shape[B, n, L], n: num_gts, L: num_anchors
  124. Returns:
  125. is_max_iou (Tensor, float32): shape[B, n, L], value=1. means selected
  126. """
  127. num_max_boxes = ious.shape[-2]
  128. max_iou_index = ious.argmax(axis=-2)
  129. is_max_iou = F.one_hot(max_iou_index, num_max_boxes).transpose([0, 2, 1])
  130. return is_max_iou.astype(ious.dtype)
  131. def compute_max_iou_gt(ious):
  132. r"""
  133. For each GT, find the anchor with the largest IOU.
  134. Args:
  135. ious (Tensor, float32): shape[B, n, L], n: num_gts, L: num_anchors
  136. Returns:
  137. is_max_iou (Tensor, float32): shape[B, n, L], value=1. means selected
  138. """
  139. num_anchors = ious.shape[-1]
  140. max_iou_index = ious.argmax(axis=-1)
  141. is_max_iou = F.one_hot(max_iou_index, num_anchors)
  142. return is_max_iou.astype(ious.dtype)
  143. def generate_anchors_for_grid_cell(feats,
  144. fpn_strides,
  145. grid_cell_size=5.0,
  146. grid_cell_offset=0.5):
  147. r"""
  148. Like ATSS, generate anchors based on grid size.
  149. Args:
  150. feats (List[Tensor]): shape[s, (b, c, h, w)]
  151. fpn_strides (tuple|list): shape[s], stride for each scale feature
  152. grid_cell_size (float): anchor size
  153. grid_cell_offset (float): The range is between 0 and 1.
  154. Returns:
  155. anchors (List[Tensor]): shape[s, (l, 4)]
  156. num_anchors_list (List[int]): shape[s]
  157. stride_tensor_list (List[Tensor]): shape[s, (l, 1)]
  158. """
  159. assert len(feats) == len(fpn_strides)
  160. anchors = []
  161. num_anchors_list = []
  162. stride_tensor_list = []
  163. for feat, stride in zip(feats, fpn_strides):
  164. _, _, h, w = feat.shape
  165. cell_half_size = grid_cell_size * stride * 0.5
  166. shift_x = (paddle.arange(end=w) + grid_cell_offset) * stride
  167. shift_y = (paddle.arange(end=h) + grid_cell_offset) * stride
  168. shift_y, shift_x = paddle.meshgrid(shift_y, shift_x)
  169. anchor = paddle.stack(
  170. [
  171. shift_x - cell_half_size, shift_y - cell_half_size,
  172. shift_x + cell_half_size, shift_y + cell_half_size
  173. ],
  174. axis=-1).astype(feat.dtype)
  175. anchors.append(anchor.reshape([-1, 4]))
  176. num_anchors_list.append(len(anchors[-1]))
  177. stride_tensor_list.append(
  178. paddle.full([num_anchors_list[-1], 1], stride))
  179. return anchors, num_anchors_list, stride_tensor_list