Generates final detections. Args: raw_boxes: A float tensor of shape [batch, num_boxes, num_classes * 4] representing box coordinates. For boxes shared among classes `num_classes` must be 1. raw_scores: A float tensor of shape [batch, num_boxes, num_c
(
self,
raw_boxes: Tensor,
raw_scores: Tensor,
anchor_boxes: Tensor,
image_shape: Tensor,
)
| 295 | self.box_coder = self.config.box_coder.instantiate() |
| 296 | |
| 297 | def forward( |
| 298 | self, |
| 299 | raw_boxes: Tensor, |
| 300 | raw_scores: Tensor, |
| 301 | anchor_boxes: Tensor, |
| 302 | image_shape: Tensor, |
| 303 | ) -> dict[str, Tensor]: |
| 304 | """Generates final detections. |
| 305 | |
| 306 | Args: |
| 307 | raw_boxes: A float tensor of shape [batch, num_boxes, num_classes * 4] representing box |
| 308 | coordinates. For boxes shared among classes `num_classes` must be 1. |
| 309 | raw_scores: A float tensor of shape [batch, num_boxes, num_classes] representing |
| 310 | logits. |
| 311 | anchor_boxes: A float tensor of shape [batch, num_boxes, 4] representing anchor boxes |
| 312 | corresponding to the raw boxes. |
| 313 | image_shape: A tensor of shape of [batch_size, 2] with the image height and width |
| 314 | that are used to clip detection boxes that exceed the image boundaries. |
| 315 | |
| 316 | Returns: |
| 317 | A dictionary with the following tensors: |
| 318 | detection_boxes: A float tensor of shape [batch, max_num_detections, 4] |
| 319 | representing top detected boxes in [y1, x1, y2, x2]. |
| 320 | detection_scores: A float tensor of shape [batch, max_num_detections] representing |
| 321 | sorted confidence scores for detected boxes. The values are between [0, 1] and |
| 322 | obtained by applying softmax on the raw scores. |
| 323 | detection_classes: An int Tensor of shape [batch, max_num_detections] |
| 324 | representing classes for detected boxes. |
| 325 | num_detections: An int tensor of shape [batch] only the first num_detections |
| 326 | boxes are valid proposals. |
| 327 | |
| 328 | Note that if `apply_nms` is set to False, max_num_detections is equal to |
| 329 | number of input raw boxes. |
| 330 | """ |
| 331 | normalized_scores = jax.nn.softmax(raw_scores) |
| 332 | batch, num_boxes, num_coordinates = raw_boxes.shape |
| 333 | raw_boxes = jnp.reshape(raw_boxes, [batch, num_boxes, num_coordinates // 4, 4]) |
| 334 | scores_without_bg = normalized_scores[..., 1:] |
| 335 | # If raw_boxes contain per class predictions, remove boxes corresponding to background |
| 336 | # class. |
| 337 | if raw_boxes.shape[-2] > 1: |
| 338 | raw_boxes = raw_boxes[..., 1:, :] |
| 339 | # Expand anchors boxes along `num_classes` dimension to be compatible with raw_boxes. |
| 340 | anchor_boxes = anchor_boxes[..., None, :] |
| 341 | decoded_boxes = self.box_coder.decode(encoded_boxes=raw_boxes, anchors=anchor_boxes) |
| 342 | clipped_boxes = utils_detection.clip_boxes_jax( |
| 343 | decoded_boxes, image_shape[..., None, None, :] |
| 344 | ) |
| 345 | if not self.config.apply_nms: |
| 346 | num_detections = jnp.tile(decoded_boxes.shape[1], decoded_boxes.shape[0]) |
| 347 | # [batch, num_detections] |
| 348 | detection_class_ids = jnp.argmax(scores_without_bg, axis=-1) |
| 349 | num_classes_for_boxes = raw_boxes.shape[-2] |
| 350 | # `num_classes_for_boxes - 1` ensures we take the only set of boxes available when |
| 351 | # boxes are shared among classes. |
| 352 | box_class_ids = jnp.minimum(detection_class_ids, num_classes_for_boxes - 1) |
| 353 | return { |
| 354 | "detection_boxes": jnp.take_along_axis( |
nothing calls this directly
no test coverage detected