Read on Omnivore
Read Original

Highlights&&Note

因此,整个demo的核心实际上是VisualizationDemo

模型处理输入得到输出predictions=self.predictor(image)predictions就是模型(刚刚的self.predictor)输出的结果。阅读机器学习、深度学习代码最重要的就是追踪这类模型处理数据的代码,因为这类代码是理解整体计算模型的关键。

predictor.py9-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_machinesmachine_rank可得知它是负责分布式训练的代码,又有参数中main_func,可以知道launch不涉及detectron2的实际功能
分布式训练,不用管

我们清晰了engine部分的层次关系。具体而言,我们按照如下的顺序阅读代码

  • train_loop.py
  • hook.py
  • defaults.py

HookBaseHook的基类,其中实现了方法before_stepbefore_trainafter_stepafter_train,其主要的作用是在真正做训练之前,做好每一步的准备工作。针对不同的Trainer可以使用不同的Hook。Hook翻译过来叫做“钩子”,所以我们可以形象地理解成Hook像在训练首尾的两个钩子一样挂着负责训练的Trainer

TrainerBase中定义了多个Hook,并且在Trainerbefore_stepafter_step等函数中可以看到需要执行每一个Hook在训练之前的准备动作HookBase.before_step、训练之后的收尾动作HookBase.after_step。具体的训练过程非常正常,就是按照iteration的数量运行before_steprun_stepafter_step三个函数。
在 Python 中,hook通常是指在特定时刻自动执行的函数。

SimpleTrainer中作者实现了一种最基本的训练神经网络的流程,它是作为上一段中TrainerBase的子类出现的。它最主要的工作就是将TrainerBase中没有实现的run_step方法实现。事实上,在SimpleTrainer中实现的过程也是最通用的训练过程:

  • iter(dataloader)读取数据
  • loss_dict = self.model(data)计算每个batch的loss
  • self.optimizer.zero_gradlosses.backward()self.optimizer.step()实现训练的过程
  • 通过统一的结构_write_metrics记录、打印计算的指标。
阅读更多

Read on Omnivore
Read Original

Highlights&&Note

首先介绍detectron2中使用的registry机制

Trainer中初始化模型调用的接口是build_model函数,通过modeling/__init__.py可以知道它是在modeling/meta_arch/build.py中定义的。但是在阅读build.py的过程中,我们发现它使用了一个叫做Registry的东西——那么什么是Registry呢?

Registry机制来自于FaceBook计算机视觉研究组的常用函数库fvcore,其中Registry的源代码和解读可见registry。它的主要作用是提供了用字符串调用类方法的接口,具体的函数是registry中的get方法。个人感觉registry.get()非常像一个getattr方法,它能够通过字符串访问类的方法。

例如我们有一个具体的网络结构,定义在modeling/meta_arch/rcnn.py中的GeneralizedRCNN。注意在它的定义上方有一个修饰器@META_ARCH_REGISTRY.register(),意思就是把GeneralizedRCNN注册到META_ARCH_REGISTRY中。那么在modeling/meta_arch/build.py中的model = META_ARCH_REGISTRY.get(meta_arch)(cfg)中,只要我们设置meta_archGeneralizedRCNN,那么META_ARCH_REGISTRY.get(meta_arch)就调用了GeneralizedRCNN方法,也就因此初始化了模型。

  • 指定名字来调用模型
    用@ 修饰器在META_ARCH_REGISTRY中注册
    再在参数中写入名称即可实现初始化*

registry的几个要点

  • 创建一个registry,设置可能的调用的类的名字
  • 对于想加入到registry中的类,在定义的时候通过修饰器指定
  • 调用类方法的时候通过get(name)
  • 通过fvcore中的源代码,我们可以知道如何写python修饰器。

Faster-RCNN的结构主要包含如下几个部分,而这几个部分也是GeneralizedRCNN在初始化部分的输入:

  • backbone:从图片提取特征表示的卷积神经网络结构,比如说ResNet。
  • proposal_generator:从图片的特征预测“哪里可能有物体”
  • roi_head:以proposal_generator部分预测的有物体区域为基础,预测物体的类别和检测框坐标

__init__功能相似的是from_config函数,它用config文件初始化模型,通过这个函数我们知道了实际构造backbone、proposal_generator和roi_head的函数分别都是来自对应文件夹的build_xxx函数。

RCNN模型处理函数的过程,我们主要关注forward函数,主要包括如下步骤:

阅读更多

Read on Omnivore
Read Original

Highlights&&Note

一般情况下,东大是不愿意在东南亚这片地方谈“历史”的,因为这片地方没有历史,唯一存在的历史,就是东大的历史。

很多人觉得东大的南海九段线太霸道,直接画到了很多国家的家门口,那是你理解错了,因为历史上东大的影响力就是这么大,甚至更大,有这些线的时候,还没有这些所谓的“国家”。
^5fe65c01

举个例子,1946年之前,这里是没有什么狗屁菲律宾的,不存在这个国家,这里只是一些乱七八糟的人类土著部落、割据王国……长达三百年都是西班牙的殖民地,后来又被美国、日本侵略,这是个被创造出来的国家。
^dab1e344

Content

录音记录面前菲官员继续狡辩东大拿出了和菲律宾之间的录音文件,但菲律宾官方居然回应“录音很容易伪造”……

全世界没有几个国家比东大更温和、包容、讲道理,因为东大近代200年曾经也是弱者,也曾饱受强权欺凌,东大明白这种感觉,所以己所不欲,勿施于人。

东大一般不愿意以强权和武力对周边的邻居们说话,但实际上这是全世界大多数人唯一听得懂的沟通方式。

阅读更多