def build_trident_resnet_backbone(cfg, input_shape): """ Create a ResNet instance from config for TridentNet. Returns: ResNet: a :class:`ResNet` instance. """ # need registration of new blocks/stems? norm = cfg.MODEL.RESNETS.NORM activation = cfg.MODEL.RESNETS.ACTIVATION deep_stem = cfg.MODEL.RESNETS.DEEP_STEM if not deep_stem: assert getattr(cfg.MODEL.RESNETS, "RADIX", 1) <= 1, \ "cfg.MODEL.RESNETS.RADIX > 1: {}".format(cfg.MODEL.RESNETS.RADIX) stem = BasicStem( in_channels=input_shape.channels, out_channels=cfg.MODEL.RESNETS.STEM_OUT_CHANNELS, norm=norm, activation=activation, deep_stem=deep_stem, ) freeze_at = cfg.MODEL.BACKBONE.FREEZE_AT if freeze_at >= 1: for p in stem.parameters(): p.requires_grad = False stem = FrozenBatchNorm2d.convert_frozen_batchnorm(stem) # fmt: off out_features = cfg.MODEL.RESNETS.OUT_FEATURES depth = cfg.MODEL.RESNETS.DEPTH num_groups = cfg.MODEL.RESNETS.NUM_GROUPS width_per_group = cfg.MODEL.RESNETS.WIDTH_PER_GROUP bottleneck_channels = num_groups * width_per_group in_channels = cfg.MODEL.RESNETS.STEM_OUT_CHANNELS out_channels = cfg.MODEL.RESNETS.RES2_OUT_CHANNELS stride_in_1x1 = cfg.MODEL.RESNETS.STRIDE_IN_1X1 res5_dilation = cfg.MODEL.RESNETS.RES5_DILATION num_branch = cfg.MODEL.TRIDENT.NUM_BRANCH branch_dilations = cfg.MODEL.TRIDENT.BRANCH_DILATIONS trident_stage = cfg.MODEL.TRIDENT.TRIDENT_STAGE test_branch_idx = cfg.MODEL.TRIDENT.TEST_BRANCH_IDX # fmt: on assert res5_dilation in { 1, 2 }, "res5_dilation cannot be {}.".format(res5_dilation) num_blocks_per_stage = { 18: [2, 2, 2, 2], 34: [3, 4, 6, 3], 50: [3, 4, 6, 3], 101: [3, 4, 23, 3], 152: [3, 8, 36, 3], }[depth] res_stage_idx = {"res2": 2, "res3": 3, "res4": 4, "res5": 5, "linear": 5} out_stage_idx = [res_stage_idx[f] for f in out_features] trident_stage_idx = res_stage_idx[trident_stage] max_stage_idx = max(out_stage_idx) deform_on_per_stage = getattr(cfg.MODEL.RESNETS, "DEFORM_ON_PER_STAGE", [False] * (max_stage_idx - 1)) stages = [] if depth in [18, 34]: assert out_channels == 64, "Must set MODEL.RESNETS.RES2_OUT_CHANNELS = 64 for R18/R34" assert not any( deform_on_per_stage ), "MODEL.RESNETS.DEFORM_ON_PER_STAGE unsupported for R18/R34" assert res5_dilation == 1, "Must set MODEL.RESNETS.RES5_DILATION = 1 for R18/R34" assert num_groups == 1, "Must set MODEL.RESNETS.NUM_GROUPS = 1 for R18/R34" for idx, stage_idx in enumerate(range(2, max_stage_idx + 1)): dilation = res5_dilation if stage_idx == 5 else 1 first_stride = 1 if idx == 0 or (stage_idx == 5 and dilation == 2) else 2 stage_kargs = { "num_blocks": num_blocks_per_stage[idx], "first_stride": first_stride, "in_channels": in_channels, "out_channels": out_channels, "norm": norm, "activation": activation, } # Use BasicBlock for R18 and R34. if depth in [18, 34]: stage_kargs["block_class"] = BasicBlock else: stage_kargs["bottleneck_channels"] = bottleneck_channels stage_kargs["stride_in_1x1"] = stride_in_1x1 stage_kargs["dilation"] = dilation stage_kargs["num_groups"] = num_groups if stage_idx == trident_stage_idx: assert not deform_on_per_stage[ idx], "Not support deformable conv in Trident blocks yet." stage_kargs["block_class"] = TridentBottleneckBlock stage_kargs["num_branch"] = num_branch stage_kargs["dilations"] = branch_dilations stage_kargs["test_branch_idx"] = test_branch_idx stage_kargs.pop("dilation") elif deform_on_per_stage[idx]: stage_kargs["block_class"] = DeformBottleneckBlock # Use True to use modulated deform_conv (DeformableV2); # Use False for DeformableV1. stage_kargs[ "deform_modulated"] = cfg.MODEL.RESNETS.DEFORM_MODULATED # Number of groups in deformable conv. stage_kargs[ "deform_num_groups"] = cfg.MODEL.RESNETS.DEFORM_NUM_GROUPS elif hasattr(cfg.MODEL.RESNETS, "RADIX"): # Radix in ResNeSt radix = cfg.MODEL.RESNETS.RADIX # Apply avg after conv2 in the BottleBlock # When AVD=True, the STRIDE_IN_1X1 should be False avd = cfg.MODEL.RESNETS.AVD or (radix > 1) # Apply avg_down to the downsampling layer for residual path avg_down = cfg.MODEL.RESNETS.AVG_DOWN or (radix > 1) # Bottleneck_width in ResNeSt bottleneck_width = cfg.MODEL.RESNETS.BOTTLENECK_WIDTH stage_kargs["block_class"] = AVDBottleneckBlock stage_kargs["avd"] = avd stage_kargs["avg_down"] = avg_down stage_kargs["radix"] = radix stage_kargs["bottleneck_width"] = bottleneck_width else: stage_kargs["block_class"] = BottleneckBlock blocks = (make_trident_stage(**stage_kargs) if stage_idx == trident_stage_idx else make_stage(**stage_kargs)) in_channels = out_channels out_channels *= 2 bottleneck_channels *= 2 if freeze_at >= stage_idx: for block in blocks: block.freeze() stages.append(blocks) return ResNet(stem, stages, out_features=out_features)
def build_resnet_backbone(cfg, input_shape): """ Create a ResNet instance from config. Returns: ResNet: a :class:`ResNet` instance. """ depth = cfg.MODEL.RESNETS.DEPTH stem_width = { 18: 32, 34: 32, 50: 32, 101: 64, 152: 64, 200: 64, 269: 64 }[depth] radix = cfg.MODEL.RESNETS.RADIX deep_stem = cfg.MODEL.RESNETS.DEEP_STEM or (radix > 1) # need registration of new blocks/stems? norm = cfg.MODEL.RESNETS.NORM activation = cfg.MODEL.RESNETS.ACTIVATION stem = BasicStem( in_channels=input_shape.channels, out_channels=cfg.MODEL.RESNETS.STEM_OUT_CHANNELS, norm=norm, activation=activation, deep_stem=deep_stem, stem_width=stem_width, ) freeze_at = cfg.MODEL.BACKBONE.FREEZE_AT if freeze_at >= 1: for p in stem.parameters(): p.requires_grad = False stem = FrozenBatchNorm2d.convert_frozen_batchnorm(stem) # fmt: off out_features = cfg.MODEL.RESNETS.OUT_FEATURES num_groups = cfg.MODEL.RESNETS.NUM_GROUPS width_per_group = cfg.MODEL.RESNETS.WIDTH_PER_GROUP bottleneck_channels = num_groups * width_per_group in_channels = cfg.MODEL.RESNETS.STEM_OUT_CHANNELS out_channels = cfg.MODEL.RESNETS.RES2_OUT_CHANNELS stride_in_1x1 = cfg.MODEL.RESNETS.STRIDE_IN_1X1 res5_dilation = cfg.MODEL.RESNETS.RES5_DILATION deform_on_per_stage = cfg.MODEL.RESNETS.DEFORM_ON_PER_STAGE deform_modulated = cfg.MODEL.RESNETS.DEFORM_MODULATED deform_num_groups = cfg.MODEL.RESNETS.DEFORM_NUM_GROUPS num_classes = cfg.MODEL.RESNETS.NUM_CLASSES zero_init_residual = cfg.MODEL.RESNETS.ZERO_INIT_RESIDUAL avd = cfg.MODEL.RESNETS.AVD or (radix > 1) avg_down = cfg.MODEL.RESNETS.AVG_DOWN or (radix > 1) bottleneck_width = cfg.MODEL.RESNETS.BOTTLENECK_WIDTH # fmt: on assert res5_dilation in { 1, 2 }, "res5_dilation cannot be {}.".format(res5_dilation) num_blocks_per_stage = { 18: [2, 2, 2, 2], 34: [3, 4, 6, 3], 50: [3, 4, 6, 3], 101: [3, 4, 23, 3], 152: [3, 8, 36, 3], 200: [3, 24, 36, 3], 269: [3, 30, 48, 8], }[depth] if depth in [18, 34]: assert out_channels == 64, "Must set MODEL.RESNETS.RES2_OUT_CHANNELS = 64 for R18/R34" assert not any( deform_on_per_stage ), "MODEL.RESNETS.DEFORM_ON_PER_STAGE unsupported for R18/R34" assert res5_dilation == 1, "Must set MODEL.RESNETS.RES5_DILATION = 1 for R18/R34" assert num_groups == 1, "Must set MODEL.RESNETS.NUM_GROUPS = 1 for R18/R34" stages = [] # Avoid creating variables without gradients # It consumes extra memory and may cause allreduce to fail out_stage_idx = [{ "res2": 2, "res3": 3, "res4": 4, "res5": 5, "linear": 5 }[f] for f in out_features] max_stage_idx = max(out_stage_idx) in_channels = 2 * stem_width if deep_stem else in_channels for idx, stage_idx in enumerate(range(2, max_stage_idx + 1)): dilation = res5_dilation if stage_idx == 5 else 1 first_stride = 1 if idx == 0 or (stage_idx == 5 and dilation == 2) else 2 stage_kargs = { "num_blocks": num_blocks_per_stage[idx], "first_stride": first_stride, "in_channels": in_channels, "out_channels": out_channels, "norm": norm, "activation": activation, "avd": avd, "avg_down": avg_down, "radix": radix, "bottleneck_width": bottleneck_width, } # Use BasicBlock for R18 and R34. if depth in [18, 34]: stage_kargs["block_class"] = BasicBlock else: stage_kargs["bottleneck_channels"] = bottleneck_channels stage_kargs["stride_in_1x1"] = stride_in_1x1 stage_kargs["dilation"] = dilation stage_kargs["num_groups"] = num_groups if deform_on_per_stage[idx]: stage_kargs["block_class"] = DeformBottleneckBlock stage_kargs["deform_modulated"] = deform_modulated stage_kargs["deform_num_groups"] = deform_num_groups else: stage_kargs["block_class"] = BottleneckBlock blocks = make_stage(**stage_kargs) in_channels = out_channels out_channels *= 2 bottleneck_channels *= 2 if freeze_at >= stage_idx: for block in blocks: block.freeze() stages.append(blocks) return ResNet(stem, stages, num_classes=num_classes, out_features=out_features, zero_init_residual=zero_init_residual)
def _freeze_module(module): for p in module.parameters(): p.requires_grad = False return FrozenBatchNorm2d.convert_frozen_batchnorm(module)
def freeze(self): for p in self.parameters(): p.requires_grad = False FrozenBatchNorm2d.convert_frozen_batchnorm(self) return self
def build_resnet_backbone(cfg, input_shape): """ Create a ResNet instance from config. Returns: ResNet: a :class:`ResNet` instance. """ depth = cfg.MODEL.RESNETS.DEPTH deep_stem = cfg.MODEL.RESNETS.DEEP_STEM in_channels = input_shape.channels out_channels = cfg.MODEL.RESNETS.STEM_OUT_CHANNELS activation = cfg.MODEL.RESNETS.ACTIVATION norm = cfg.MODEL.RESNETS.NORM if deep_stem: stem_width = { 18: 32, 34: 32, 50: 32, 101: 64, 152: 64, 200: 64, 269: 64 }[depth] stem = DeepStem( in_channels, out_channels, norm, activation, deep_stem=deep_stem, stem_width=stem_width, ) else: assert getattr(cfg.MODEL.RESNETS, "RADIX", 1) <= 1, \ "cfg.MODEL.RESNETS.RADIX: {} > 1".format(cfg.MODEL.RESNETS.RADIX) stem = BasicStem(in_channels, out_channels, norm=norm, activation=activation) freeze_at = cfg.MODEL.BACKBONE.FREEZE_AT if freeze_at >= 1: for p in stem.parameters(): p.requires_grad = False stem = FrozenBatchNorm2d.convert_frozen_batchnorm(stem) # fmt: off out_features = cfg.MODEL.RESNETS.OUT_FEATURES num_groups = cfg.MODEL.RESNETS.NUM_GROUPS width_per_group = cfg.MODEL.RESNETS.WIDTH_PER_GROUP bottleneck_channels = num_groups * width_per_group in_channels = cfg.MODEL.RESNETS.STEM_OUT_CHANNELS out_channels = cfg.MODEL.RESNETS.RES2_OUT_CHANNELS stride_in_1x1 = cfg.MODEL.RESNETS.STRIDE_IN_1X1 res5_dilation = cfg.MODEL.RESNETS.RES5_DILATION num_classes = cfg.MODEL.RESNETS.NUM_CLASSES zero_init_residual = cfg.MODEL.RESNETS.ZERO_INIT_RESIDUAL # fmt: on assert res5_dilation in { 1, 2 }, "res5_dilation cannot be {}.".format(res5_dilation) num_blocks_per_stage = { 18: [2, 2, 2, 2], 34: [3, 4, 6, 3], 50: [3, 4, 6, 3], 101: [3, 4, 23, 3], 152: [3, 8, 36, 3], 200: [3, 24, 36, 3], 269: [3, 30, 48, 8], }[depth] # Avoid creating variables without gradients # which consume extra memory and may cause allreduce to fail out_stage_idx = [{ "res2": 2, "res3": 3, "res4": 4, "res5": 5, "linear": 5 }[f] for f in out_features] max_stage_idx = max(out_stage_idx) # Apply Deformable Convolution in stages # Specify if apply deform_conv on Res2, Res3, Res4, Res5 deform_on_per_stage = getattr(cfg.MODEL.RESNETS, "DEFORM_ON_PER_STAGE", [False] * (max_stage_idx - 1)) if depth in [18, 34]: assert out_channels == 64, "Must set MODEL.RESNETS.RES2_OUT_CHANNELS = 64 for R18/R34" assert not any( deform_on_per_stage ), "MODEL.RESNETS.DEFORM_ON_PER_STAGE unsupported for R18/R34" assert res5_dilation == 1, "Must set MODEL.RESNETS.RES5_DILATION = 1 for R18/R34" assert num_groups == 1, "Must set MODEL.RESNETS.NUM_GROUPS = 1 for R18/R34" stages = [] # See cvpods/configs/base_detection_config.py for details if not stride_in_1x1 and "torchvision" not in cfg.MODEL.WEIGHTS: logger.warning( "Using pretrain weight not from torchvision with MODEL.RESNETS.STRIDE_IN_1X1 == False" ) elif stride_in_1x1 and "torchvision" in cfg.MODEL.WEIGHTS and cfg.MODEL.WEIGHTS: logger.warning( "Using pretrain weight from torchvision with MODEL.RESNETS.STRIDE_IN_1X1 == True" ) in_channels = 2 * stem_width if deep_stem else in_channels for idx, stage_idx in enumerate(range(2, max_stage_idx + 1)): dilation = res5_dilation if stage_idx == 5 else 1 first_stride = 1 if idx == 0 or (stage_idx == 5 and dilation == 2) else 2 stage_kargs = { "num_blocks": num_blocks_per_stage[idx], "first_stride": first_stride, "in_channels": in_channels, "out_channels": out_channels, "norm": norm, "activation": activation, } # Use BasicBlock for R18 and R34. if depth in [18, 34]: stage_kargs["block_class"] = BasicBlock else: stage_kargs["bottleneck_channels"] = bottleneck_channels stage_kargs["stride_in_1x1"] = stride_in_1x1 stage_kargs["dilation"] = dilation stage_kargs["num_groups"] = num_groups if deform_on_per_stage[idx]: stage_kargs["block_class"] = DeformBottleneckBlock # Use True to use modulated deform_conv (DeformableV2); # Use False for DeformableV1. stage_kargs[ "deform_modulated"] = cfg.MODEL.RESNETS.DEFORM_MODULATED # Number of groups in deformable conv. stage_kargs[ "deform_num_groups"] = cfg.MODEL.RESNETS.DEFORM_NUM_GROUPS elif hasattr(cfg.MODEL.RESNETS, "RADIX"): # Radix in ResNeSt radix = cfg.MODEL.RESNETS.RADIX # Apply avg after conv2 in the BottleBlock # When AVD=True, the STRIDE_IN_1X1 should be False avd = cfg.MODEL.RESNETS.AVD or (radix > 1) # Apply avg_down to the downsampling layer for residual path avg_down = cfg.MODEL.RESNETS.AVG_DOWN or (radix > 1) # Bottleneck_width in ResNeSt bottleneck_width = cfg.MODEL.RESNETS.BOTTLENECK_WIDTH stage_kargs["block_class"] = AVDBottleneckBlock stage_kargs["avd"] = avd stage_kargs["avg_down"] = avg_down stage_kargs["radix"] = radix stage_kargs["bottleneck_width"] = bottleneck_width else: stage_kargs["block_class"] = BottleneckBlock blocks = make_stage(**stage_kargs) in_channels = out_channels out_channels *= 2 bottleneck_channels *= 2 if freeze_at >= stage_idx: for block in blocks: block.freeze() stages.append(blocks) return ResNet(stem, stages, num_classes=num_classes, out_features=out_features, zero_init_residual=zero_init_residual)