Detectron2 公共 LazyConfig 组件库完全指南:以 configs/common 复用模型、数据加载器、学习率调度器与优化器
2026/9/9 12:45:50 网站建设 项目流程

Detectron2 公共 LazyConfig 组件库完全指南:以 configs/common 复用模型、数据加载器、学习率调度器与优化器

【免费下载链接】detectron2Detectron2 is a platform for object detection, segmentation and other visual recognition tasks.项目地址: https://gitcode.com/GitHub_Trending/de/detectron2

Detectron2 的configs/common/目录沉淀了一套基于 LazyConfig(懒实例化)体系封装的"公共积木":常用模型结构、COCO 数据加载器、多阶段学习率调度器与优化器,以及配套的训练流程约定。本文围绕这份官方 README 展开,结合底层LazyConfig.load/instantiate实现与多个真实配置文件,说明这套公共组件的设计动机、每个组件的字段含义,以及如何在自有训练配置中 import 后按需覆盖,快速拼出 Mask R-CNN、Cascade R-CNN、RetinaNet、FCOS、Keypoint R-CNN 等训练任务。

一、目录定位:给"可编辑后再构造"的对象提供一个仓库级公共命名空间

configs/common/README.md用三句话阐明了该目录的核心价值:

  • 它集中定义了训练中经常被复用的模型(models)、数据加载器(dataloaders)、调度器(scheduler)与优化器(optimizers)
  • 这些对象全部以lazy instantiation(懒实例化)的形式描述——即用户可以在真正构造对象之前,先用 Python 语句自由修改其参数;
  • 它们既可以被其他配置文件通过**相对导入(import)**引用,也可以通过model_zoo.get_configAPI加载。

换句话说,configs/common/不是一个独立可运行的任务配置,而是一套"官方预置的部件仓库",真正的任务配置文件(如configs/COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_1x.pyconfigs/new_baselines/*_LSJ.py)都从这里取料并做增量覆盖。整个目录由四类文件组成:

类别文件(相对仓库根目录)对外导出的对象
数据data/coco.pydataloader(含dataloader.train/dataloader.test/dataloader.evaluator
数据常量data/constants.pyconstants(ImageNet 像素均值/标准差)
模型models/mask_rcnn_fpn.py、models/retinanet.pymodel
调度器coco_schedule.pylr_multiplier_1x / _2x / _3x / _6x / _9x
优化器optim.pySGDAdamW
训练约定train.pytrain(纯字典,非懒调用)
复合模型models/cascade_rcnn.py、models/fcos.py、models/keypoint_rcnn_fpn.py、models/mask_rcnn_c4.py、models/mask_rcnn_vitdet.py、models/panoptic_fpn.py基于基底模型二次改造得到的model

二、底层机制:LazyCall 与递归实例化(instantiate)

要理解configs/common/,必须先理解它所谓的"lazy instantiation"具体指什么。官方教程 lazyconfigs.md 给出了完整背景。

2.1 字典描述一次"调用"

懒实例化的核心思想是:用一个字典来描述"调用某个类/函数并传入若干参数"这件事,而不立即执行调用。字典包含两类键:

  1. _target_:可调用对象的路径字符串,例如detectron2.modeling.meta_arch.GeneralizedRCNN
  2. 其余键:要传给该可调用对象的参数,参数本身也可以递归地用同构字典描述。

辅助函数LazyCall(定义于 detectron2/config/lazy.py,LazyCall.__call__会把_target_注入并返回一个带allow_objects=True标志的omegaconf.DictConfig)可以帮我们生成这类字典。例如 optim.py 中:

from detectron2.config import LazyCall as L SGD = L(torch.optim.SGD)( params=L(get_default_optimizer_params)(weight_decay_norm=0.0), lr=0.02, momentum=0.9, weight_decay=1e-4, )

L(torch.optim.SGD)(...)并不真正创建优化器,而是生成一个形如{"_target_": "torch.optim.SGD", "lr": 0.02, ...}的配置字典。这些字典被写入模块全局变量后,LazyConfig.load会收集模块顶层所有"字典值"并把它们统一转成omegaconf.DictConfig(参见 lazy.py 中LazyConfig.load对返回值的过滤逻辑),从而获得 omegaconf 的属性访问语法与变量插值(interpolation)能力。

2.2 instantiate:递归地把配置变回对象

真正执行构造的是 detectron2/config/instantiate.py 中的instantiate(cfg):它递归遍历配置树,遇到含_target_的节点就先实例化所有子参数、再locate出目标类并执行cls(**cfg)。因此:

optim = instantiate(cfg.optimizer) # 真正创建 torch.optim.SGD model = instantiate(cfg.model) # 真正创建 GeneralizedRCNN train_loader = instantiate(cfg.dataloader.train)

这套机制的价值在于:配置在"加载——覆盖——实例化"三个阶段彻底解耦,用户可以先 import 公共组件、用普通 Python 代码任意改字段,再一次性实例化,这正是 lazyconfigs.md 中强调的"dict 可编辑性"优于传统 YAML 的地方。

三、公共数据配置(configs/common/data/)

3.1 coco.py:train / test 加载器与评估器的"三件套"

data/coco.py 是最常用的公共组件,它在顶层导出一个用OmegaConf.create()创建的空配置dataloader,随后挂上三个子键:

训练加载器dataloader.train:由build_detection_train_loader描述,包含

  • datasetget_detection_dataset_dicts(names="coco_2017_train")
  • mapperDatasetMapperis_train=True),其augmentations列表使用了经典的多尺度短边抖动ResizeShortestEdge(short_edge_length=(640, 672, 704, 736, 768, 800), sample_style="choice", max_size=1333),配合RandomFlip(horizontal=True)image_format="BGR"use_instance_mask=True
  • total_batch_size=16num_workers=4。注意这里的 16 是整个训练的全局 batch size(与后方调度器以 batch 16 为基准计算迭代数呼应)。

测试加载器dataloader.testbuild_detection_test_loader+DatasetMapper(is_train=False),测试仅做单尺度ResizeShortestEdge(short_edge_length=800, max_size=1333),且图像格式通过 omegaconf 插值引用训练 mapper:image_format="${...train.mapper.image_format}"——即"父配置的 train 分支下的 mapper 的 image_format",避免重复定义。

评估器dataloader.evaluatorCOCOEvaluator,其数据集名同样用插值${..test.dataset.names}从测试加载器同步,保证评估数据与测试数据一致。

这种"插值引用而非复制值"的写法是公共组件的关键设计,让后续覆盖test.dataset.names时评估器自动跟随。

3.2 constants.py:像素归一化常量

data/constants.py 导出constants字典,集中存放 ImageNet 预训练权重所需的像素统计量,共四组:

  • imagenet_rgb256_mean/imagenet_rgb256_std(标准 RGB 顺序,std 为真实 ImageNet 标准差[58.395, 57.12, 57.375]);
  • imagenet_bgr256_mean/imagenet_bgr256_std(BGR 顺序,供input_format="BGR"的骨干使用)。注释特别说明:使用 Detectron1 或 MSRA 系列预训练模型时,std 已被吸收进 conv1 权重,必须置为[1.0, 1.0, 1.0],因此这里的 BGR std 默认取 1;若自训练从头开始,可换回真实 ImageNet 标准差[57.375, 57.120, 58.395]

这些常量随后被 models/mask_rcnn_fpn.py 与 models/retinanet.py 通过from ..data.constants import constants引用并填充模型的pixel_mean/pixel_std/input_format字段。

四、公共模型定义(configs/common/models/)

4.1 基石:mask_rcnn_fpn.py 组装了一条完整的 Mask R-CNN 流水线

models/mask_rcnn_fpn.py 是整套模型的"地基",用不到 100 行字典嵌套完整描述了 Detectron2 标准 Mask R-CNN + FPN(R-50)结构,顶层modelL(GeneralizedRCNN),内部自底向上分层:

  • backboneFPN,其bottom_upResNet——stem 用BasicStem(in_channels=3, out_channels=64, norm="FrozenBN"),主干阶段由ResNet.make_default_stages(depth=50, stride_in_1x1=True, norm="FrozenBN")生成,out_features=["res2","res3","res4","res5"];FPN 的in_features用插值${.bottom_up.out_features}复用同一列表,top_block=LastLevelMaxPool负责在 P5 之上追加 P6;
  • proposal_generatorRPN+StandardRPNHead(in_channels=256, num_anchors=3)+DefaultAnchorGenerator(5 个金字塔层,anchor sizes[32,64,128,256,512],纵横比[0.5,1.0,2.0],strides[4,8,16,32,64]);Matcher(thresholds=[0.3, 0.7], labels=[0, -1, 1], allow_low_quality_matches=True)区分背景/忽略/前景;每图 256 个 proposal 样本,pre_nms_topk=(2000, 1000)post_nms_topk=(1000, 1000)nms_thresh=0.7
  • roi_headsStandardROIHeads(num_classes=80, ...),内部box_in_features=["p2","p3","p4","p5"]+ROIPooler(output_size=7, ..., pooler_type="ROIAlignV2")+FastRCNNConvFCHead(无卷积、两层 1024 维 FC)+FastRCNNOutputLayers(test_score_thresh=0.05, box2box_transform=Box2BoxTransform(weights=(10,10,5,5)));分割分支mask_in_features同四层、mask_pooler输出 14×14、mask_head=MaskRCNNConvUpsampleHead(5 层 256 通道卷积)。两个 head 的num_classes均通过${..num_classes}插值跟随 ROIHeads 顶层设置;
  • 输入归一化pixel_mean/pixel_std取自constants.imagenet_bgr256_mean / _stdinput_format="BGR"

注意RPNStandardROIHeadsbatch_size_per_imagepositive_fraction等采样超参全部显式列出,便于后续配置直接点改。这份完整定义也被官方教程 lazyconfigs.md 以 "A Full Mask R-CNN described in recursive instantiation" 的折叠块直接引用,作为递归实例化的教学样例。

4.2 派生模型:在基底上做"增删改"

公共目录真正的威力在于派生:其他模型文件以mask_rcnn_fpn.model为基底,用纯 Python 对配置树做操作即可变换模型族。

  • Cascade R-CNN(models/cascade_rcnn.py):先[model.roi_heads.pop(k) for k in ["box_head", "box_predictor", "proposal_matcher"]]移除单级 box 部件,再用model.roi_heads.update(_target_=CascadeROIHeads, ...)替换目标类,并分别用列表推导构造 3 个级联的FastRCNNConvFCHead、3 个FastRCNNOutputLayers(回归权重依次(10,5)/(20,10)/(30,15))与 3 个Matcher(IoU 阈值 0.5/0.6/0.7)。
  • Keypoint R-CNN(models/keypoint_rcnn_fpn.py):pop 掉 mask 分支三个键后update为 keypoint 分支(KRCNNConvDeconvUpsampleHead,17 个关键点、8 层 512 通道卷积、loss_normalizer="visible"),并把 RPN 的post_nms_topk提到(1500, 1000)——注释解释 Detectron2 中该参数按图计算,1000 会损伤 box AP;同时smooth_l1_beta=0.5改善关键点 AP。
  • RetinaNet(models/retinanet.py):独立从零定义L(RetinaNet):ResNet 只保留res3..res5,FPN top 换成LastLevelP6P7,5 层特征图上接RetinaNetHead(每个空间位置 9 个 anchor,prior_prob=0.01初始化前景概率,focal lossalpha=0.25gamma=2.0)。
  • FCOS(models/fcos.py):直接 import RetinaNet 的model后做减法和替换——model._target_ = FCOSdel掉 anchor 相关键,top_block 改从 P5 上采样出 P6/P7(对应论文 Sec 2.2),阈值换为基于sqrt(cls_score * centerness)的 0.2/0.6,head 换成FCOSHead(norm="GN")

每一层改造都在 import 处即时生效,且不需要理解 YAML 继承的覆盖规则,这正是公共组件选择 Python 配置的根本原因。

五、调度器与优化器

5.1 coco_schedule.py:1x/3x 等"论文调度"的工厂函数

coco_schedule.py 把论文中常见的 "1x / 3x" 等训练协议实现为一个带参函数default_X_scheduler(num_X),并在模块末尾一次性导出lr_multiplier_1x / _2x / _3x / _6x / _9x五个成品。核心逻辑:

  • "1x" 以 batch size 16 下的90,000 次迭代(对应约 1,440,000 张训练图像、约 12 个 COCO epoch)为基准,故总迭代数total_steps_16bs = num_X * 90000
  • LR 按三段阶梯衰减:MultiStepParamScheduler(values=[1.0, 0.1, 0.01])。当num_X <= 2时直接用固定里程碑[60000, 80000, 90000](注释指出该调度对迭代数具有尺度不变性,等价于 YAML 配置里的milestones=[6, 8, 9]epoch);num_X > 2时则改为[total_steps_16bs - 60000, total_steps_16bs - 20000, total_steps_16bs]——即把最后两次衰减固定在距训练结束 60k/20k 迭代处,保证尾段衰减节奏不随总长度漂移,这也是 "Rethinking ImageNet Pre-training"(Sec 4)所提倡的策略;
  • 最外层套WarmupParamScheduler:线性 warmup,长度1000 / total_steps_16bs(恒为 1000 次迭代的相对比例),warmup_factor=0.001

也就是说"1x"本身包含 1000 步线性预热与两次阶梯式降 LR;任务配置只需from ..common.coco_schedule import lr_multiplier_1x即可复用完整协议。

5.2 optim.py:内置 SGD 与 AdamW 两套出厂优化器

optim.py 提供SGDAdamW两个成品:

  • SGD:lr=0.02、momentum=0.9、weight_decay=1e-4(ResNet 系标准的 1x 学习率与正则);
  • AdamW:lr=1e-4、betas=(0.9, 0.999)、weight_decay=0.1(适合 ViT / MViT 系主干)。

两者的params都由L(get_default_optimizer_params)(weight_decay_norm=0.0)描述。注释点明关键约定:params.model留待真正实例化优化器前,由训练脚本把已构造的 model 对象填进去。该脚本即 tools/lazyconfig_train_net.py,其do_train中顺序执行:

model = instantiate(cfg.model) # 1. 先构造模型 cfg.optimizer.params.model = model # 2. 把模型塞进优化器配置 optim = instantiate(cfg.optimizer) # 3. 再构造优化器,以获取参数分组

get_default_optimizer_params定义于 detectron2/solver/build.py,负责按模块名把参数分成"含 norm 的"(weight_decay_norm=0.0,即 norm 层不做权重衰减)等若干组,从而保证weight_decay_norm这类参数能在公共文件里被预置、而在实例化时针对真实模型结构生效。

六、train.py:训练入口约定的"最小公共契约"

train.py 导出的train是一个普通 Python 字典(刻意不用 LazyCall,因为它不是某个类的参数,而是训练脚本直接读取的字段集)。文件头部注释声明它是为tools/lazyconfig_train_net.py设计的通用约定,使用者完全可以定义自己的结构并配套自己的 train_net.py。字段含:

字段默认值说明
output_dir"./output"输出目录
init_checkpoint""初始权重(可指向 detectron2:// 托管的 ImageNet 预训练)
max_iter90000训练总迭代数
amp.enabledFalse是否启用自动混合精度(决定用AMPTrainer还是SimpleTrainer
ddp见源码传给create_ddp_model的参数(broadcast_buffersfind_unused_parametersfp16_compression
checkpointerperiod=5000, max_to_keep=100PeriodicCheckpointer参数
eval_period/log_period5000/20评估与日志周期(迭代)
device"cuda"训练设备

对照 tools/lazyconfig_train_net.py 的 docstring 与do_train实现可见,该脚本对配置对象的期望恰好是:cfg.modelcfg.dataloader.{train,test,evaluator}cfg.optimizercfg.lr_multipliercfg.train,与configs/common/各文件导出的对象一一对应——common目录其实是该训练脚本的"官方配套零件包"

七、实战:三种使用姿势与完整命令

7.1 姿势一:import + 少量覆盖(官方任务配置的标准写法)

configs/COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_1x.py全文件仅 5 行业务代码,其余全是 import:

from ..common.optim import SGD as optimizer from ..common.coco_schedule import lr_multiplier_1x as lr_multiplier from ..common.data.coco import dataloader from ..common.models.mask_rcnn_fpn import model from ..common.train import train model.backbone.bottom_up.freeze_at = 2 # 冻结 res2 之前的层 train.init_checkpoint = "detectron2://ImageNetPretrained/MSRA/R-50.pkl" # 使用 ImageNet 预训练

同目录下mask_rcnn_R_50_C4_1x.pymask_rcnn_R_50_FPN_3x.py,以及configs/COCO-Detection/fcos_R_50_FPN_1x.pyconfigs/COCO-Keypoints/keypoint_rcnn_R_50_FPN_1x.pyconfigs/COCO-PanopticSegmentation/panoptic_fpn_R_50_1x.pyconfigs/Misc/cascade_mask_rcnn_R_50_FPN_3x.yaml对应的cascade_mask_rcnn_R_50_FPN_1x/3x系列均遵循此模式。要点:公共配置通过相对导入路径..common.xxx获取,Detectron2 的LazyConfig在加载时会重写导入逻辑(见 lazy.py 的_patch_import:相对导入只允许加载同仓库的其他配置 .py 文件,不要求目录有__init__.py),保证任何位置的配置都能按相对位置解析文件。

7.2 姿势二:深度改造(以 new_baselines 的 LSJ 大尺度抖动方案为例)

configs/new_baselines/mask_rcnn_R_50_FPN_100ep_LSJ.py 展示了在同一套公共组件上做"换骨干训练范式"级别的改造:

  • 重写数据增强为 LSJ:dataloader.train.mapper.augmentations = [ResizeScale(min_scale=0.1, max_scale=2.0, ...), FixedSizeCrop(crop_size=(1024, 1024)), RandomFlip],并recompute_boxes=True(裁剪需重算框);
  • 全程 SyncBN:一次性把 stem、stages、FPN 的 norm 全部置"SyncBN",box/mask head 换NaiveSyncBatchNorm
  • 换 4conv1fc box head(conv_dims=[256,256,256,256]+fc_dims=[1024])、2conv RPN head、从头训练freeze_at=0
  • 放大 batch:dataloader.train.total_batch_size = 64train.max_iter = 184375(100 epoch),train.amp.enabled=Truetrain.ddp.fp16_compression=True
  • 重写调度器lr_multiplier与优化器超参optimizer.lr=0.1weight_decay=4e-5

这些改动全程使用"点路径赋值"与 Python 推导式,任何一处都能精准落到公共组件定义的具体字段上——这正是懒配置相比传统 YAML 无法做到、却是公共组件被大量项目采用的原因。

7.3 姿势三:通过 model_zoo.get_config 以编程方式加载

官方教程 lazyconfigs.md 明确说明这些 lazy 配置在安装后被视作模型库的一部分,可由 model_zoo.get_config 加载(其get_config.py配置会走LazyConfig.load分支;若传入trained=True,还会把官方权重地址写入cfg.train.init_checkpoint,前提是配置中含train字段——这正说明为什么 common 的train.py是模型库 lazy 配置的共同基础)。典型用法:

from detectron2 import model_zoo cfg = model_zoo.get_config( "COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_1x.py", trained=True ) cfg.train.output_dir = "./my_output" cfg.train.max_iter = 90000

之后即可用instantiate(cfg.model)等构建对象,或直接python tools/lazyconfig_train_net.py --config-file <路径>启动训练。

7.4 运行:训练 / 评估 / 命令行覆盖

针对任意基于 common 组件的 lazy 配置,训练入口统一为 tools/lazyconfig_train_net.py:

# 单机多卡训练(使用公共组件组合出的 Mask R-CNN 1x 配置) python tools/lazyconfig_train_net.py \ --config-file configs/COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_1x.py \ --num-gpus 8 # 仅评估:加载配置中 train.init_checkpoint 指定的权重 python tools/lazyconfig_train_net.py \ --config-file configs/new_baselines/mask_rcnn_R_50_FPN_100ep_LSJ.py \ --eval-only \ --num-gpus 8 # 用 --opts 做命令行覆盖(等价于 Python 内调用 LazyConfig.apply_overrides) python tools/lazyconfig_train_net.py \ --config-file configs/COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_1x.py \ --num-gpus 1 \ train.max_iter=1000 dataloader.train.total_batch_size=8 \ train.eval_period=500

其中--optsa.b=c语法由 lazy.py 的LazyConfig.apply_overrides支持(优先借助 Hydra 的覆盖语法解析,缺失时回退到ast.literal_eval简单解析);脚本在main中会依次执行LazyConfig.loadapply_overrides,并在评估模式下直接instantiate(cfg.model)后调用do_test

八、最佳实践与注意事项

  • 公共组件是"基底"而非"成品":像mask_rcnn_fpn.model这样的基底对象被多个配置文件 import 后各自独立覆盖,互不影响,因为每个配置 .py 在被LazyConfig.load时都会在新命名空间重新执行(见 lazy.py 中_patch_import的"不缓存模块、全局修改无副作用"设计)。
  • 优先用插值而非复制data/coco.py${...train.mapper.image_format}${..test.dataset.names}等 omegaconf 插值保证了派生配置改一处、相关字段同步,应沿用此习惯。
  • 增加新组件只需遵守契约:若给common/增加新的公共模型或数据配置,保证导出model/dataloader/train等约定键名,即可无缝接入lazyconfig_train_net.pymodel_zoo.get_config
  • 阅读延伸:完整设计理念见 lazyconfigs.md;configs/common/README.md同时被官方教程引用为 "common baselines" 的示例入口;new_baselines/目录下的全部*_LSJ.py与各任务目录下的.py配置都是"common 组件 × 任务差异"的现成范本,可对照 configs 逐一阅读。

【免费下载链接】detectron2Detectron2 is a platform for object detection, segmentation and other visual recognition tasks.项目地址: https://gitcode.com/GitHub_Trending/de/detectron2

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询