Detectron2源码阅读笔记-(二)Registry&build_*方法
Trainer解析
我们继续Detectron2代码阅读笔记-(一)中的内容。

上图画出了detectron2文件夹中的三个子文件夹(tools,config,engine)之间的关系。那么剩下的文件夹又是如何起作用的呢?
def main(args):
cfg = setup(args)
if args.eval_only:
...
trainer = Trainer(cfg)
trainer.resume_or_load(resume=args.resume)
if cfg.TEST.AUG.ENABLED:
trainer.register_hooks(
[hooks.EvalHook(0, lambda: trainer.test_with_TTA(cfg, trainer.model))]
)
return trainer.train()
build_*方法
我们从trainer = Trainer(cfg)开始进一步了解。
Detectron2代码阅读笔记-(一)中已经提到过一连串的Trainer的继承关系如下:
tools.train_net.Trainer->detectron2.engine.default.DefaultTrainer->detectron2.engine.train_loop.SimpleTrainer->detectron2.engine.train_loop.TrainerBase,而detectron2.engine.default.DefaultTrainer在其__init__(self, cfg)函数中定义了解析cfg。如下面代码所示,cfg会作为参数倍若干个build_*方法解析,得到解析后的model,optimizer,data_loader等。
from detectron2.modeling import build_model
class DefaultTrainer(SimpleTrainer):
def __init__(self, cfg):
"""
Args:
cfg (CfgNode):
"""
# Assume these objects must be constructed in this order.
model = self.build_model(cfg)
optimizer = self.build_optimizer(cfg, model)
data_loader = self.build_train_loader(cfg)
...
self.register_hooks(self.build_hooks())
@classmethod
def build_model(cls, cfg):
"""
Returns:
torch.nn.Module:
"""
model = build_model(cfg)
logger = logging.getLogger(__name__)
logger.info("Model:\n{}".format(model))
return model
下面我们以DefaultTrainer.build_model为例来介绍注册机制,该方法调用了detectron2/modeling/meta_arch/build_model.py的build_model函数,其源代码如下:
from detectron2.utils.registry import Registry
META_ARCH_REGISTRY = Registry("META_ARCH")
META_ARCH_REGISTRY.__doc__ = """
def build_model(cfg):
"""
Built the whole model, defined by `cfg.MODEL.META_ARCHITECTURE`.
"""
meta_arch = cfg.MODEL.META_ARCHITECTURE
return META_ARCH_REGISTRY.get(meta_arch)(cfg)
- meta_arch = cfg.MODEL.META_ARCHITECTURE: 根据超参数获得网络结构的名字
- return META_ARCH_REGISTRY.get(meta_arch)(cfg):META_ARCH_REGISTRY是一个
Registry类(这个在后面会详细介绍),可以将这一行代码拆成如下几个步骤:
model = META_ARCH_REGISTRY.get(meta_arch)
return model(cfg)
注册机制Registry
那么Registry到底是什么呢?在分析源代码之前我们先了解一下如何使用它,假如你想自己实现一个新的backbone网络,那么你可以这样做:
首先在detectron2中定义好如下(实际上已经定义了):
# detectron2/modeling/backbone/build.py
BACKBONE_REGISTRY = Registry('BACKBONE')
之后在你创建的新的文件下按如下方式创建你的backbone
# detectron2/modeling/backbone/your_backbone.py
from .build import BACKBONE_REGISTRY
# 方式1
@BACKBONE_REGISTRY.register()
class MyBackbone():
...
# 方式2
class MyBackbone():
...
BACKBONE_REGISTRY.register(MyBackbone)
Registry源代码如下(有删减):
class Registry(object):
def __init__(self, name):
self._name = name
self._obj_map = {}
def _do_register(self, name, obj):
assert (
name not in self._obj_map
), "An object named '{}' was already registered in '{}' registry!".format(name, self._name)
self._obj_map[name] = obj
def register(self, obj=None):
if obj is None:
# used as a decorator
def deco(func_or_class):
name = func_or_class.__name__
self._do_register(name, func_or_class)
return func_or_class
return deco
# used as a function call
name = obj.__name__
self._do_register(name, obj)
def get(self, name):
ret = self._obj_map.get(name)
if ret is None:
raise KeyError("No object named '{}' found in '{}' registry!".format(name, self._name))
return ret
- 首先是
__init__部分:self._name则是你要注册的名字,例如对于完整的模型而言,name一般取META_ARCH。当然如果你需要自定义backbone网络,你也可以定义一个Registry('BACKBONE')self._obj_map:其实就是一个字典。以模型为例,key就是你的模型名字,而value就是对应的模型类。这样你在传参时只需要修改一下模型名字就能使用不同的模型了。具体实现方法就是后面这几个函数。
register: 可以看到该方法定义了注册的两种方式,一种是当obj==None的时候,使用装饰器的方式注册,另外一种就是直接将obj作为参数调用_do_register进行注册。_do_register:真正注册的函数,可以看到它首先会判断name是否已经存在于self._obj_map了。什么意思呢?还是以backbone为例,我们定义了一个BACKBONE_REGISTRY = Registry('BACKBONE'),然后又定义了很多种backbone,而这些backbone都使用@BACKBONE_REGISTRY.register()的方式注册到了BACKBONE_REGISTRY._obj_map中了,所以才取名为Registry,还是蛮形象的吼。get: 这个其实就是根据key值对字典进行取值。
Detectron2 整体代码架构
虽然Detectron2还有很多部分没有介绍到,但是源代码分析到这应该对整体架构有了一定的理解了,具体的一些细节会在后续的文章中进行分析。现对Detectron2 整体代码架构总结一下:

Detectron2源码阅读笔记-(二)Registry&build_*方法的更多相关文章
- Detectron2源码阅读笔记-(一)Config&Trainer
代码结构概览 核心部分 configs:储存各种网络的yaml配置文件 datasets:存放数据集的地方 detectron2:运行代码的核心组件 tools:提供了运行代码的入口以及一切可视化的代 ...
- werkzeug源码阅读笔记(二) 下
wsgi.py----第二部分 pop_path_info()函数 先测试一下这个函数的作用: >>> from werkzeug.wsgi import pop_path_info ...
- Detectron2源码阅读笔记-(三)Dataset pipeline
构建data_loader原理步骤 # engine/default.py from detectron2.data import ( MetadataCatalog, build_detection ...
- werkzeug源码阅读笔记(二) 上
因为第一部分是关于初始化的部分的,我就没有发布出来~ wsgi.py----第一部分 在分析这个模块之前, 需要了解一下WSGI, 大致了解了之后再继续~ get_current_url()函数 很明 ...
- Android源码阅读笔记二 消息处理机制
消息处理机制: .MessageQueue: 用来描述消息队列2.Looper:用来创建消息队列3.Handler:用来发送消息队列 初始化: .通过Looper.prepare()创建一个Loope ...
- Apollo源码阅读笔记(二)
Apollo源码阅读笔记(二) 前面 分析了apollo配置设置到Spring的environment的过程,此文继续PropertySourcesProcessor.postProcessBeanF ...
- 【原】FMDB源码阅读(二)
[原]FMDB源码阅读(二) 本文转载请注明出处 -- polobymulberry-博客园 1. 前言 上一篇只是简单地过了一下FMDB一个简单例子的基本流程,并没有涉及到FMDB的所有方方面面,比 ...
- Three.js源码阅读笔记-5
Core::Ray 该类用来表示空间中的“射线”,主要用来进行碰撞检测. THREE.Ray = function ( origin, direction ) { this.origin = ( or ...
- jdk源码阅读笔记-LinkedHashMap
Map是Java collection framework 中重要的组成部分,特别是HashMap是在我们在日常的开发的过程中使用的最多的一个集合.但是遗憾的是,存放在HashMap中元素都是无序的, ...
随机推荐
- Solr7.x学习(7)-JAVA操作
maven依赖 <dependency> <groupId>org.apache.solr</groupId> <artifactId>solr-sol ...
- window 运行spark报错
Using Spark's default log4j profile: org/apache/spark/log4j-defaults.properties // :: ERROR Shell: F ...
- SQL Server ----- 还原数据库,将另一台电脑上的数据库装在本机
1.创建好数据库,记住安装位置,,和需要还原的数据库的位置 还原数据库的意思就是 根据创建的数据库,还原备份的数据库,如果数据库中没有数据库要新建数据库. 2.进来后如图 3.找你需要的还原数据库的位 ...
- Golang解析、验证、修改URL之Host、Port、Path
URL解析验证问题 net.ParseIP()只能解析不带冒号以及端口号的IP4/IP6 ✔: 127.0.0.1.2001:db8::68 ✖: 127.0.0.1:8080.www.baidu.c ...
- web开发-心路历程
从事web开发已经有几年了,感触颇多,在此记录一下. 对于学习: 几年的经历让我认识到了,学习确实是一个持续永恒的过程.目前的社会发展很快,各种新的思想,新的机会不断刷新我的认知,也让我体会到了自己能 ...
- shell-快速入门_批处理脚本编程语言
1. Shell概述 1.1. Shell是什么 Shell是一门批处理脚本编程语言. 批处理是什么? 操作系统都分为(GUI)图形界面,命令界面(command). 命令操作的可以不用一一条执行.可 ...
- Git新建分支,分支合并,版本回退详解
一.git基本命令 git拉取仓库代码 #拉取master代码 git clone git仓库地址 #拉取分支代码 git clone -b 分支名称 git仓库地址 2.git添加代码到本地仓库 g ...
- springMVC中controller层方法中使用private和public问题
楼主一直习惯使用public,偶尔手误也可能使用private,但是发觉也没啥区别,都能调用service层,注入bean. 后来做一个新项目时,发觉自己以前的写的部分功能报错,当时有点懵逼,,找了半 ...
- Python基础之shutil模块、random模块
1.shutil模块 shutil模块是对os模块的功能补充,包含移动.复制.打包.压缩.解压等功能. 1)shutil.copyfileobj() 复制文件内容到另一个文件,可指定大小内容,如len ...
- 我碰到的stackoverflow error
出现这种问题,首先需要检查自己的代码: 要么代码小错误:或者逻辑错误: 如果出现循环调用更要仔细检查: 我的问题: 循环调用:一个实体他有自己的父栏目,含有子栏目的list集合:两者结果映射resul ...