编写模型

如果您尝试进行全新的任务开发,可能需要从头开始完全实现一个模型。但在许多情况下,您可能更希望对现有模型的某些组件进行修改或扩展。因此,我们也提供了相关机制,允许用户覆盖标准模型中特定内部组件的行为。

注册新组件

对于用户经常希望自定义的常见概念,例如“骨干特征提取器”、“边界框头部”,我们提供了一种注册机制,让用户可以注入自定义实现,这些实现将立即可在配置文件中使用。

例如,要添加一个新的主干网络,请在代码中导入以下内容:

from detectron2.modeling import BACKBONE_REGISTRY, Backbone, ShapeSpec

@BACKBONE_REGISTRY.register()
class ToyBackbone(Backbone):
  def __init__(self, cfg, input_shape):
    super().__init__()
    # create your own backbone
    self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=16, padding=3)

  def forward(self, image):
    return {"conv1": self.conv1(image)}

  def output_shape(self):
    return {"conv1": ShapeSpec(channels=64, stride=16)}

在这段代码中,我们按照Backbone类的接口实现了一个新的主干网络,并将其注册到BACKBONE_REGISTRY中,该注册表要求是Backbone的子类。导入这段代码后,detectron2就能将类名与其实现关联起来。因此你可以编写如下代码:

cfg = ...   # read a config
cfg.MODEL.BACKBONE.NAME = 'ToyBackbone'   # or set it in the config file
model = build_model(cfg)  # it will find `ToyBackbone` defined above

再举一个例子,要向广义R-CNN元架构中的ROI头部添加新功能,您可以实现一个新的ROIHeads子类并将其放入ROI_HEADS_REGISTRY中。DensePoseMeshRCNN就是两个实现了新ROIHeads来执行新任务的示例。而projects/目录下还包含了更多实现不同架构的示例。

完整的注册表列表可在API文档中查看。 您可以在这些注册表中注册组件,以自定义模型的不同部分或整个模型。

使用显式参数构建模型

Registry(注册表)是连接配置文件中名称与实际代码的桥梁。它们旨在覆盖用户经常需要替换的几个主要组件。然而,基于文本的配置文件功能有时有限,某些更深层次的定制可能只能通过编写代码来实现。

detectron2中的大多数模型组件都有一个清晰的__init__接口,用于记录其所需的输入参数。使用自定义参数调用它们将获得模型的定制变体。

例如,要在Faster R-CNN的边界框头部使用自定义损失函数,我们可以执行以下操作:

  1. 损失计算目前是在FastRCNNOutputLayers中进行的。我们需要实现它的一个变体或子类,使用自定义的损失函数,命名为MyRCNNOutput

  2. 使用box_predictor=MyRCNNOutput()参数调用StandardROIHeads,而非内置的FastRCNNOutputLayers。 若需保持其他参数不变,可通过可配置的__init__机制轻松实现:

    roi_heads = StandardROIHeads(
      cfg, backbone.output_shape(),
      box_predictor=MyRCNNOutput(...)
    )
    
  3. (可选)如果我们想通过配置文件启用这个新模型,需要进行注册:

    @ROI_HEADS_REGISTRY.register()
    class MyStandardROIHeads(StandardROIHeads):
      def __init__(self, cfg, input_shape):
        super().__init__(cfg, input_shape,
                         box_predictor=MyRCNNOutput(...))