【问题标题】:what is the biggest bottleneck in maskrcnn_benchmark repo?maskrcnn_benchmark repo 中最大的瓶颈是什么?
【发布时间】:2020-03-17 21:36:02
【问题描述】:

我正在开发一个使用 maskrcnn_benchmark repo 的存储库。我已经广泛地探索了基准测试库,因为它在 CPU 上相对于enter link description here 的性能较慢。

为了为单个前向传递创建基准,我为每个部分设置了一个时间计数器,它为我提供了计算每个组件所需的时间。我很难准确定位整个架构中最慢的组件。我相信它是 maskrcnn_benchmark/modeling/backbone/resnet.py 文件中的 BottleneckWithFixedBatchNorm 类。

我将非常感谢本地化此架构中最大瓶颈的任何帮助。

【问题讨论】:

  • 没有完全理解你的第一段。你的意思是?您的推理速度是否比某些公共基准报告中的慢,或者您试图了解为什么来自github.com/facebookresearch/maskrcnn-benchmark 的模型比来自github.com/MhLiao/MaskTextSpotter 的模型慢?
  • 我正在尝试确定瓶颈,以便我可以修改代码,或者通过减少残差等来获得更好的时间,而不是在很大程度上损害结果。

标签: tensorflow neural-network artificial-intelligence pytorch


【解决方案1】:

我也遇到过同样的问题,最好的解决方案是查看主代码,检查每个模块的正向传递,并设置一个计时器来记录每个模块的计算时间模块。我们的工作方式是创建一个架构,在其中为每个类创建时间记录器,因此类的每个实例现在都将记录其执行时间,经过比较,至少在我们的案例中,我们发现了延迟是 Resnet 模块的深度,(考虑到 resnet 的计算成本根本不是一个令人惊讶的因素,唯一的解决方案是更多的颚化,所以要么确保更大的 GPU 来执行任务,要么减少深度Resnet 网络)。

我必须通知 maskrcnn_benchmark 已被弃用,其更新版本以detectron2 的形式提供。考虑移动代码以显着提高架构的速度。

BottleneckWithFixedBatchNorm 不是架构中最昂贵的操作,当然也不会像所有操作而不是名称那样造成瓶颈。该类的计算成本不高,即使在低端 CPU 机器上也可以并行计算(至少在推理阶段)。

可以使用以下路径中的代码找到更好地跟踪每个模块的性能的示例:maskrcnn_benchmark/modeling/backbone/resnet.py

class ResNet(nn.Module):
    def __init__(self, cfg):
        super(ResNet, self).__init__()

        # If we want to use the cfg in forward(), then we should make a copy
        # of it and store it for later use:
        # self.cfg = cfg.clone()

        # Translate string names to implementations
        stem_module = _STEM_MODULES[cfg.MODEL.RESNETS.STEM_FUNC]
        stage_specs = _STAGE_SPECS[cfg.MODEL.BACKBONE.CONV_BODY]
        transformation_module = _TRANSFORMATION_MODULES[cfg.MODEL.RESNETS.TRANS_FUNC]

        # Construct the stem module
        self.stem = stem_module(cfg)

        # Constuct the specified ResNet stages
        num_groups = cfg.MODEL.RESNETS.NUM_GROUPS
        width_per_group = cfg.MODEL.RESNETS.WIDTH_PER_GROUP
        in_channels = cfg.MODEL.RESNETS.STEM_OUT_CHANNELS
        stage2_bottleneck_channels = num_groups * width_per_group
        stage2_out_channels = cfg.MODEL.RESNETS.RES2_OUT_CHANNELS
        self.stages = []
        self.return_features = {}
        for stage_spec in stage_specs:
            name = "layer" + str(stage_spec.index)
            stage2_relative_factor = 2 ** (stage_spec.index - 1)
            bottleneck_channels = stage2_bottleneck_channels * stage2_relative_factor
            out_channels = stage2_out_channels * stage2_relative_factor
            stage_with_dcn = cfg.MODEL.RESNETS.STAGE_WITH_DCN[stage_spec.index -1]
            module = _make_stage(
                transformation_module,
                in_channels,
                bottleneck_channels,
                out_channels,
                stage_spec.block_count,
                num_groups,
                cfg.MODEL.RESNETS.STRIDE_IN_1X1,
                first_stride=int(stage_spec.index > 1) + 1,
                dcn_config={
                    "stage_with_dcn": stage_with_dcn,
                    "with_modulated_dcn": cfg.MODEL.RESNETS.WITH_MODULATED_DCN,
                    "deformable_groups": cfg.MODEL.RESNETS.DEFORMABLE_GROUPS,
                }
            )
            in_channels = out_channels
            self.add_module(name, module)
            self.stages.append(name)
            self.return_features[name] = stage_spec.return_features

        # Optionally freeze (requires_grad=False) parts of the backbone
        self._freeze_backbone(cfg.MODEL.BACKBONE.FREEZE_CONV_BODY_AT)

    def _freeze_backbone(self, freeze_at):
        if freeze_at < 0:
            return
        for stage_index in range(freeze_at):
            if stage_index == 0:
                m = self.stem  # stage 0 is the stem
            else:
                m = getattr(self, "layer" + str(stage_index))
            for p in m.parameters():
                p.requires_grad = False

    def forward(self, x):
        start_timer=time.time()
        outputs = []
        x = self.stem(x)
        for stage_name in self.stages:
            x = getattr(self, stage_name)(x)
            if self.return_features[stage_name]:
                outputs.append(x)
        print("ResNet time :: ", time.time()-start_timer,file=open("timelogger.log","a"))
        return outputs

只有在前向传递中必须进行更改,并且从此类创建的所有实例都将继承属性和日志时间(选择将其写入文件而不是简单的标准输出)

【讨论】:

  • 是否也可以计算出这种变化对准确性的影响????
  • 讨论中的 repo 确实提供了这一点,您可以结合不同的架构来完成准确性方面,更多关于此类权衡的内容您可以查看论文,这里 arxiv.org/abs/1904.01906
猜你喜欢
  • 2018-07-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-19
  • 1970-01-01
  • 1970-01-01
  • 2012-10-29
相关资源
最近更新 更多