def test_default_anchor_generator_centered(self): cfg = BaseDetectionConfig() cfg.MODEL.ANCHOR_GENERATOR.SIZES = [[32, 64]] cfg.MODEL.ANCHOR_GENERATOR.ASPECT_RATIOS = [[0.25, 1, 4]] cfg.MODEL.ANCHOR_GENERATOR.OFFSET = 0.5 anchor_generator = DefaultAnchorGenerator(cfg, [ShapeSpec(stride=4)]) # only the last two dimensions of features matter here num_images = 2 features = {"stage3": torch.rand(num_images, 96, 1, 2)} anchors = anchor_generator([features["stage3"]]) expected_anchor_tensor = torch.tensor( [ [-30.0, -6.0, 34.0, 10.0], [-14.0, -14.0, 18.0, 18.0], [-6.0, -30.0, 10.0, 34.0], [-62.0, -14.0, 66.0, 18.0], [-30.0, -30.0, 34.0, 34.0], [-14.0, -62.0, 18.0, 66.0], [-26.0, -6.0, 38.0, 10.0], [-10.0, -14.0, 22.0, 18.0], [-2.0, -30.0, 14.0, 34.0], [-58.0, -14.0, 70.0, 18.0], [-26.0, -30.0, 38.0, 34.0], [-10.0, -62.0, 22.0, 66.0], ] ) for i in range(num_images): assert torch.allclose(anchors[i][0].tensor, expected_anchor_tensor)
def __init__(self, cfg, input_shape: Dict[str, ShapeSpec]): super().__init__() # fmt: off self.min_box_side_len = cfg.MODEL.PROPOSAL_GENERATOR.MIN_SIZE self.in_features = cfg.MODEL.RPN.IN_FEATURES self.nms_thresh = cfg.MODEL.RPN.NMS_THRESH self.nms_type = cfg.MODEL.RPN.NMS_TYPE self.batch_size_per_image = cfg.MODEL.RPN.BATCH_SIZE_PER_IMAGE self.positive_fraction = cfg.MODEL.RPN.POSITIVE_FRACTION self.smooth_l1_beta = cfg.MODEL.RPN.SMOOTH_L1_BETA self.loss_weight = cfg.MODEL.RPN.LOSS_WEIGHT # fmt: on # Map from self.training state to train/test settings self.pre_nms_topk = { True: cfg.MODEL.RPN.PRE_NMS_TOPK_TRAIN, False: cfg.MODEL.RPN.PRE_NMS_TOPK_TEST, } self.post_nms_topk = { True: cfg.MODEL.RPN.POST_NMS_TOPK_TRAIN, False: cfg.MODEL.RPN.POST_NMS_TOPK_TEST, } self.boundary_threshold = cfg.MODEL.RPN.BOUNDARY_THRESH self.anchor_generator = DefaultAnchorGenerator( cfg, [input_shape[f] for f in self.in_features]) self.box2box_transform = Box2BoxTransform( weights=cfg.MODEL.RPN.BBOX_REG_WEIGHTS) self.anchor_matcher = Matcher(cfg.MODEL.RPN.IOU_THRESHOLDS, cfg.MODEL.RPN.IOU_LABELS, allow_low_quality_matches=True) self.rpn_head = StandardRPNHead( cfg, [input_shape[f] for f in self.in_features])
def test_default_anchor_generator(self): cfg = BaseDetectionConfig() cfg.MODEL.ANCHOR_GENERATOR.SIZES = [[32, 64]] cfg.MODEL.ANCHOR_GENERATOR.ASPECT_RATIOS = [[0.25, 1, 4]] anchor_generator = DefaultAnchorGenerator(cfg, [ShapeSpec(stride=4)]) # only the last two dimensions of features matter here num_images = 2 features = {"stage3": torch.rand(num_images, 96, 1, 2)} anchors = anchor_generator([features["stage3"]]) expected_anchor_tensor = torch.tensor( [ [-32.0, -8.0, 32.0, 8.0], [-16.0, -16.0, 16.0, 16.0], [-8.0, -32.0, 8.0, 32.0], [-64.0, -16.0, 64.0, 16.0], [-32.0, -32.0, 32.0, 32.0], [-16.0, -64.0, 16.0, 64.0], [-28.0, -8.0, 36.0, 8.0], # -28.0 == -32.0 + STRIDE (4) [-12.0, -16.0, 20.0, 16.0], [-4.0, -32.0, 12.0, 32.0], [-60.0, -16.0, 68.0, 16.0], [-28.0, -32.0, 36.0, 32.0], [-12.0, -64.0, 20.0, 64.0], ] ) for i in range(num_images): assert torch.allclose(anchors[i][0].tensor, expected_anchor_tensor)
def __init__(self, cfg, input_shape: List[ShapeSpec]): super().__init__() # Standard RPN is shared across levels: in_channels = [s.channels for s in input_shape] assert len( set(in_channels)) == 1, "Each level must have the same channel!" in_channels = in_channels[0] # RPNHead should take the same input as anchor generator # NOTE: it assumes that creating an anchor generator does not have unwanted side effect. anchor_generator = DefaultAnchorGenerator(cfg, input_shape) num_cell_anchors = anchor_generator.num_cell_anchors box_dim = anchor_generator.box_dim assert (len(set(num_cell_anchors)) == 1 ), "Each level must have the same number of cell anchors" num_cell_anchors = num_cell_anchors[0] # 3x3 conv for the hidden representation self.conv = nn.Conv2d(in_channels, in_channels, kernel_size=3, stride=1, padding=1) # 1x1 conv for predicting objectness logits self.objectness_logits = nn.Conv2d(in_channels, num_cell_anchors, kernel_size=1, stride=1) # 1x1 conv for predicting box2box transform deltas self.anchor_deltas = nn.Conv2d(in_channels, num_cell_anchors * box_dim, kernel_size=1, stride=1) for l in [self.conv, self.objectness_logits, self.anchor_deltas]: nn.init.normal_(l.weight, std=0.01) nn.init.constant_(l.bias, 0)
def build_anchor_generator(cfg, input_shape): return DefaultAnchorGenerator(cfg, input_shape)