Link
Highlights&&Note
因此,整个
demo
的核心实际上是VisualizationDemo
。模型处理输入得到输出
predictions=self.predictor(image)
,predictions
就是模型(刚刚的self.predictor
)输出的结果。阅读机器学习、深度学习代码最重要的就是追踪这类模型处理数据的代码,因为这类代码是理解整体计算模型的关键。在
predictor.py
9-12行的import
部分,我们可以学习到很多架构深度学习项目的规范、设计方法,在不同的文件夹中,我们往往会通过功能将不同的模块分开包装。例如在predictor.py
中体现的:
.data
:处理数据相关的类和方法.engine
:对训练、预测逻辑的整体包装,类似于对整体Pipeline的定义,常见于大型项目.utils
:应该是utilities
的简写,一般用来放置常用的工具模块,例如在这里体现出来的可视化部分
总之,对于越大型的项目来说,合理的分区、包装就越有必要,因为这可以从软件工程角度节省大量用来理解、开发、查错(Debug)的成本。在自己的很多小项目中,合理地使用类似的方法也能有效地提升项目质量。
训练代码是
tools/train_net.py
if __name__ == '__main__'
的部分(这里是代码运行的接口),可以看到detectron2
的结构是利用launch
运行了main
函数中的内容。如果我们不关心分布式训练的部分(即在distributed的作用域的部分),那么main
函数的逻辑相当简单:得到模型和运行的参数(在参数cfg中)。利用定义好的类Trainer
,通过传入cfg
参数可以定义出模型,后面的部分均通过Trainer
里面的方法都可以实现,例如train()
顾名思义就是做训练的,test()
就是测试的,build_model()
就是创建模型的。
很有意思的是,过去的detectron2没有封装invoke_main.不知道为什么要封装这么个东西在
Trainer
的定义中我们发现它是一个继承自engine.DefaultTrainer
的子类,而我们通过上面对main
函数的分析发现Trainer
的主要功能其实都来自于DefaultTrainer
trainer看engine.DefaultTrianer就行查看文件名字和每个文件上面
__all__
的部分可以大致猜测出它们之间相互引用的关系和每个文件主要负责的部分
defaults.py
包含了我们在train_net.py
中见到的DefaultTrainer
,也大多是在import别人
launch.py
中的launch
顾名思义是让算法开始运行的代码,我们浏览一下它最主要的函数launch
,根据它的参数num_machines
、machine_rank
可得知它是负责分布式训练的代码,又有参数中main_func
,可以知道launch
不涉及detectron2
的实际功能
分布式训练,不用管我们清晰了
engine
部分的层次关系。具体而言,我们按照如下的顺序阅读代码
train_loop.py
hook.py
defaults.py
HookBase
是Hook
的基类,其中实现了方法before_step
、before_train
和after_step
、after_train
,其主要的作用是在真正做训练之前,做好每一步的准备工作。针对不同的Trainer
可以使用不同的Hook
。Hook翻译过来叫做“钩子”,所以我们可以形象地理解成Hook像在训练首尾的两个钩子一样挂着负责训练的Trainer
。在
TrainerBase
中定义了多个Hook
,并且在Trainer
的before_step
、after_step
等函数中可以看到需要执行每一个Hook
在训练之前的准备动作HookBase.before_step
、训练之后的收尾动作HookBase.after_step
。具体的训练过程非常正常,就是按照iteration的数量运行before_step
、run_step
、after_step
三个函数。
在 Python 中,hook通常是指在特定时刻自动执行的函数。在
SimpleTrainer
中作者实现了一种最基本的训练神经网络的流程,它是作为上一段中TrainerBase
的子类出现的。它最主要的工作就是将TrainerBase
中没有实现的run_step
方法实现。事实上,在SimpleTrainer
中实现的过程也是最通用的训练过程:
iter(dataloader)
读取数据loss_dict = self.model(data)
计算每个batch的lossself.optimizer.zero_grad
、losses.backward()
、self.optimizer.step()
实现训练的过程- 通过统一的结构
_write_metrics
记录、打印计算的指标。