c++64位hook代码_目标检测(MMdetection)-HOOK机制

c++64位hook代码_⽬标检测(MMdetection)-HOOK机制
最近做了⼀段时间的⽬标检测,不得不说检测这块还是相对⽐较复杂的,在熟悉项⽬的同时也确实学习到了很多有⽤的东西。MMdetetion 是现在最著名、算法包最多并且使⽤⼈数最多的训练框架,其中的源码⾮常值得学习,今天总结下我对其中HOOK(钩⼦)机制的理解。
MMdetection最近更新很多,我以2.4.0版本的代码进⾏解读,分享⾃⼰的理解,也吸纳观众的点评。HOOK、Runer的定义在MMCV当中,MMdetection和MMCV是版本匹配的,我这⾥使⽤的是MMCV 1.1.2的代码。(HOOK相关的定义主要在MMCV中,下⾯⽤的代码都是摘⾃于MMCV)。
1.HOOK机制的作⽤
MMdetection中的HOOK可以理解为⼀种触发器,也可以理解为⼀种训练框架的架构规范,它规定了在算法训练过程中的种种操作,并且我们可以通过继承HOOK类,然后注册HOOK⾃定义我们想要的操作。
⾸先看⼀下HOOK的基类定义
# Copyright (c) Open-MMLab. All rights reserved.
from mmcv.utils import Registry
HOOKS = Registry('hook')
class Hook:
def before_run(self, runner):
pass
def after_run(self, runner):
pass
def before_epoch(self, runner):
pass
def after_epoch(self, runner):
pass
def before_iter(self, runner):
pass
def after_iter(self, runner):
pass
def before_train_epoch(self, runner):
self.before_epoch(runner)
橡胶还原剂def before_val_epoch(self, runner):
self.before_epoch(runner)
def after_train_epoch(self, runner):
self.after_epoch(runner)
def after_val_epoch(self, runner):
self.after_epoch(runner)
def before_train_iter(self, runner):
self.before_iter(runner)
def before_val_iter(self, runner):
self.before_iter(runner)
def after_train_iter(self, runner):
self.after_iter(runner)
def after_val_iter(self, runner):
self.after_iter(runner)
def every_n_epochs(self, runner, n):
return (runner.epoch + 1) % n == 0 if n > 0 else False
def every_n_inner_iters(self, runner, n):
return (runner.inner_iter + 1) % n == 0 if n > 0 else False
def every_n_iters(self, runner, n):
return (runner.iter + 1) % n == 0 if n > 0 else False
def end_of_epoch(self, runner):
return runner.inner_iter + 1 == len(runner.data_loader)
可以说基类函数中定义了许多我们在模型训练中需要⽤到的⼀些功能,如果想定义⼀些操作我们就可以继承这个类并定制化我们的功能,可以看到HOOK中每⼀个参数都是有runner作为参数传⼊的。关于Runner的作⽤下⼀篇⽂章接着说,简⽽⾔之,Runner是⼀个模型训练的⼯⼚,在其中我们可以加载数据、训练、验证以及梯度backward等等全套流程。MMdetection在设计的时候也为runner传⼊丰富的参数,定义了⼀个⾮常好的训练范式。在你的每⼀个hook函数中,都可以对runner进⾏你想要的操作。
⽽HOOK是怎么嵌套进runner中的呢?其实是在Runner中定义了⼀个hook的list,list中的每⼀个元素就是⼀个实例化的HOOK对象。其中提供了两种注册hook的⽅法,register_hook是传⼊⼀个实例化的HOOK对象,并将它插⼊到⼀个列表中,register_hook_from_cfg是传⼊⼀个配置项,根据配置项来实例化HOOK对象并插⼊到列表中。当然第⼆种⽅法⼜是MMLab的开源⽣态中定义的⼀种基础⽅
法mmcv.build_from_cfg了,⽆论在MMdetection还是其他MMLab开源的算法框架中,都遵循着MMCV的这套基于配置项实例化对象的⽅法。毕竟MMCV是提供了⼀个基础的功能,服务于各个算法框架,这也是为什么MMLab的代码⾼质量的原因。不仅仅是算法的复现,更是架构、编程范式的⼀种体现,真·代码如诗。
def register_hook(self, hook, priority='NORMAL'):
"""Register a hook into the hook list.
The hook will be inserted into a priority queue, with the specified
priority (See :class:`Priority` for details of priorities).
For hooks with the same priority, they will be triggered in the same
order as they are registered.
Args:
hook (:obj:`Hook`): The hook to be registered.
priority (int or str or :obj:`Priority`): Hook priority.
Lower value means higher priority.
"""
assert isinstance(hook, Hook)
if hasattr(hook, 'priority'):
raise ValueError('"priority" is a reserved attribute for hooks')
priority = get_priority(priority)
hook.priority = priority
# insert the hook to a sorted list
inserted = False
# hook是分优先级插⼊到list中的,在MMdetection中不同的HOOK是有优先级的,为什么呢?稍后在hook的调⽤中解释哈
for i in range(len(self._hooks) - 1, -1, -1):
if priority >= self._hooks[i].priority:
self._hooks.insert(i + 1, hook)
inserted = True
break
if not inserted:
self._hooks.insert(0, hook)
如图是某水上打捞船def register_hook_from_cfg(self, hook_cfg):
"""Register a hook from its cfg.
Args:
二联件
hook_cfg (dict): Hook config. It should have at least keys 'type'
and 'priority' indicating its type and priority.
Notes:
The specific hook class to register should not use 'type' and
'priority' arguments during initialization.
"""
hook_cfg = py()
priority = hook_cfg.pop('priority', 'NORMAL')
hook = mmcv.build_from_cfg(hook_cfg, HOOKS)
调⽤HOOK函数
def call_hook(self, fn_name):
"""Call all hooks.
Args:
fn_name (str): The function name in each hook to be called, such as
"before_train_epoch".
"""
for hook in self._hooks:
getattr(hook, fn_name)(self)
可以看到HOOK是调⽤的时候是遍历List,然后根据HOOK的名字来调⽤。这也是为什么要区分优先级的原因,优先级越⾼的放在List的前⾯,这样就能更快地被调⽤。当你想⽤before_run_epoch来做A和B两件事情的时候,在runner⾥⾯就是调⽤⼀
次self.before_run_epoch,但是先做A还是先做B,就是通过不同的HOOK的优先级来决定了。⽐如在evaluation的时候对需要做测试,但是测试前对参数做滑动平均。⽐如emaHOOK中的72⾏,也写明了要在测试之前做指数滑动平均。
def after_train_epoch(self, runner):
"""We load parameter values from ema backup to model before the
结晶器铜管
EvalHook."""
self._swap_ema_parameters()
checkpoint.py的HOOK中,同样也定义了after_train_epoch函数如下:
@master_only
def after_train_epoch(self, runner):
if not self.by_epoch or not self.every_n_epochs(runner, self.interval):
return
runner.logger.info(f'Saving checkpoint at {runner.epoch + 1} epochs')
if not self.out_dir:
管道内衬
self.out_dir = runner.work_dir
runner.save_checkpoint(
self.out_dir, save_optimizer=self.save_optimizer, **self.args)
# remove other checkpoints
if self.max_keep_ckpts > 0:
filename_tmpl = ('filename_tmpl', 'epoch_{}.pth')
current_epoch = runner.epoch + 1
公交车线路牌
for epoch in range(current_epoch - self.max_keep_ckpts, 0, -1):
ckpt_path = os.path.join(self.out_dir,
filename_tmpl.format(epoch))
if ists(ckpt_path):
else:
break
从测试代码中可以看到不同的HOOK虽然都是重写了after_train_epoch函数,但是调⽤的顺序还是先调⽤ema.py中的,然后再调
⽤checkpoint.py中的after_train_epoch。
resume_ema_hook = EMAHook(
momentum=0.5, warm_up=0, resume_from=f'{work_dir}/epoch_1.pth')
runner = _build_demo_runner()
# 设置了HIGHREST的优先级
checkpointhook = CheckpointHook(interval=1, by_epoch=True)
runner.run([loader, loader], [('train', 1), ('val', 1)], 2)
具体的优先级定义有以下7种,作为HOOK的类成员属性。具体定义在链接中。
+------------+------------+
| Level      | Value      |
+============+============+
| HIGHEST    | 0          |
+------------+------------+
| VERY_HIGH  | 10        |
+------------+------------+
| HIGH      | 30        |
+------------+------------+
| NORMAL    | 50        |
+------------+------------+
| LOW        | 70        |
+------------+------------+
| VERY_LOW  | 90        |
+------------+------------+
| LOWEST    | 100        |
+------------+------------+
2.举⼀个简单的例⼦
最近打算好好锻炼⾝体,健康⽣活,努⼒⼯作,我打算让⾃⼰变得更加⾃律。我给⾃⼰定下了⼏个条例,每天吃早饭之前得晨练30分钟
晨练30分钟,
跑上⼀个实验,吃完饭之后回来刚好可以看下中间结果,吃完午饭之后我感觉结果没运动完之后才会感觉充满活⼒。每天吃午饭之前我得跑上⼀个实验
锻炼30分钟。秉承着这样的原则我给⾃⼰定义⼀个HOOK来规范我的⽣活。
问题我需要午休30分钟
午休30分钟, 晚上下班前我如果没什么事再锻炼30分钟
定义我的HOOK
import sys
class HOOK:
def before_breakfirst(self, runner):
print('{}:吃早饭之前晨练30分钟'.format(sys._getframe()._name))
def after_breakfirst(self, runner):
print('{}:吃早饭之前晨练30分钟'.format(sys._getframe()._name))
def before_lunch(self, runner):
print('{}:吃午饭之前跑上实验'.format(sys._getframe()._name))
def after_lunch(self, runner):
print('{}:吃完午饭午休30分钟'.format(sys._getframe()._name))
def before_dinner(self, runner):
print('{}: 没想好做什么'.format(sys._getframe()._name))
def after_dinner(self, runner):
print('{}: 没想好做什么'.format(sys._getframe()._name))
def after_finish_work(self, runner, are_you_busy=False):
if are_you_busy:
print('{}:今天事贼多,还是加班吧'.format(sys._getframe()._name))
else:
print('{}:今天没啥事,去锻炼30分钟'.format(sys._getframe()._name))
定义我的Runner

本文发布于:2024-09-20 19:34:12,感谢您对本站的认可!

本文链接:https://www.17tex.com/tex/1/105382.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:定义   训练   测试   框架   代码   理解
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议