CoolFace
Apppublic

Mjolnir65/FasterRCNN

sourceHugging Faceupdated 1y agoView on Hugging Face
0likes
generalized_rcnn.py128 linesDownload Raw Back to detection
1"""2Implements the Generalized R-CNN framework3"""4 5import warnings6from collections import OrderedDict7from typing import Dict, List, Optional, Tuple, Union8 9import torch10from torch import nn, Tensor11 12from torchvision.utils import _log_api_usage_once13 14 15class GeneralizedRCNN(nn.Module):16    """17    Main class for Generalized R-CNN.18 19    Args:20        backbone (nn.Module):21        rpn (nn.Module):22        roi_heads (nn.Module): takes the features + the proposals from the RPN and computes23            detections / masks from it.24        transform (nn.Module): performs the data transformation from the inputs to feed into25            the model26    """27 28    def __init__(self, backbone: nn.Module, rpn: nn.Module, roi_heads: nn.Module, transform: nn.Module) -> None:29        super().__init__()30        _log_api_usage_once(self)31        self.transform = transform32        self.backbone = backbone33        self.rpn = rpn34        self.roi_heads = roi_heads35        # used only on torchscript mode36        self._has_warned = False37 38    @torch.jit.unused39    def eager_outputs(self, losses, detections):40        # type: (Dict[str, Tensor], List[Dict[str, Tensor]]) -> Union[Dict[str, Tensor], List[Dict[str, Tensor]]]41        if self.training:42            return losses43 44        return detections45 46    def forward(self, images, targets=None):47        # type: (List[Tensor], Optional[List[Dict[str, Tensor]]]) -> Tuple[Dict[str, Tensor], List[Dict[str, Tensor]]]48        """49        Args:50            images (list[Tensor]): images to be processed51            targets (list[Dict[str, Tensor]]): ground-truth boxes present in the image (optional)52 53        Returns:54            result (list[BoxList] or dict[Tensor]): the output from the model.55                During training, it returns a dict[Tensor] which contains the losses.56                During testing, it returns list[BoxList] contains additional fields57                like `scores`, `labels` and `mask` (for Mask R-CNN models).58 59        """60        if self.training:61            if targets is None:62                torch._assert(False, "targets should not be none when in training mode")63            else:64                for target in targets:65                    boxes = target["boxes"]66                    if isinstance(boxes, torch.Tensor):67                        torch._assert(68                            len(boxes.shape) == 2 and boxes.shape[-1] == 4,69                            f"Expected target boxes to be a tensor of shape [N, 4], got {boxes.shape}.",70                        )71                    else:72                        torch._assert(False, f"Expected target boxes to be of type Tensor, got {type(boxes)}.")73 74        original_image_sizes: List[Tuple[int, int]] = []75        for img in images:76            val = img.shape[-2:]77            torch._assert(78                len(val) == 2,79                f"expecting the last two dimensions of the Tensor to be H and W instead got {img.shape[-2:]}",80            )81            original_image_sizes.append((val[0], val[1]))82 83        images, targets = self.transform(images, targets)84 85        # Check for degenerate boxes86        # TODO: Move this to a function87        if targets is not None:88            for target_idx, target in enumerate(targets):89                boxes = target["boxes"]90                degenerate_boxes = boxes[:, 2:4] <= boxes[:, :2]91                if degenerate_boxes.any():92                    # print the first degenerate box93                    bb_idx = torch.where(degenerate_boxes.any(dim=1))[0][0]94                    degen_bb: List[float] = boxes[bb_idx].tolist()95                    torch._assert(96                        False,97                        "All bounding boxes should have positive height and width."98                        f" Found invalid box {degen_bb} for target at index {target_idx}.",99                    )100 101        features = self.backbone(images.tensors)102        if isinstance(features, torch.Tensor):103            features = OrderedDict([("0", features)])104        105        # modify targets to remove theta for rpn106        # print(f"{len(targets)=}")107        # print(f"{targets[0]=}")108        # targets_rpn = []109        # for target in targets:110        #     target_rpn = target.copy()111        #     target_rpn['boxes'] = target_rpn['boxes'][:, :-1]112        #     targets_rpn.append(target_rpn)113        # print(f"{targets_rpn[0]=}")114        proposals, proposal_losses = self.rpn(images, features, targets)115        detections, detector_losses = self.roi_heads(features, proposals, images.image_sizes, targets)116        detections = self.transform.postprocess(detections, images.image_sizes, original_image_sizes)  # type: ignore[operator]117 118        losses = {}119        losses.update(detector_losses)120        losses.update(proposal_losses)121 122        if torch.jit.is_scripting():123            if not self._has_warned:124                warnings.warn("RCNN always returns a (Losses, Detections) tuple in scripting")125                self._has_warned = True126            return losses, detections127        else:128            return self.eager_outputs(losses, detections)