Esempio n. 1
0
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)
Esempio n. 2
0
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)
Esempio n. 3
0
 def _freeze_module(module):
     for p in module.parameters():
         p.requires_grad = False
     return FrozenBatchNorm2d.convert_frozen_batchnorm(module)
Esempio n. 4
0
 def freeze(self):
     for p in self.parameters():
         p.requires_grad = False
     FrozenBatchNorm2d.convert_frozen_batchnorm(self)
     return self
Esempio n. 5
0
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)