文章目录
0. 前言
- 一直没有完全理解Non-Local,这次配合代码,一定要百分百搞定。
1. 论文笔记
1.1. 要解决什么问题?
- 主要提出了local/non local两类操作的定义。
- 现在一般的操作,如cnn/rnn都是local操作。
- local 操作
- 每次只能处理一个邻域内的数据(process one local neightborhood at a time)
- 普通的CNN/RNN都属于local操作
- 主要缺陷有:计算效率低(computationally inefficient),优化较为困难(cause optimization difficulties),使得multihop dependency modeling(数据需要前后依赖的情况)更困难。
- non local 操作:
- 主要优势:能够获取long-range dependencies,效率高且需要的层数少,输入与输出的尺寸相同(可较为方便地嵌入模块)。
- 从下图中理解一下non-local操作的优势
- 提问:在进行行为识别任务的时候,与
X
i
X_i
Xi(即左一图片中的足球位置)相关的位置是在哪里?
- 实际情况:与 X i X_i Xi相关的位置就是箭头指向的位置。
- 目前情况:如果是用local操作,如CNN操作,那与 X i X_i Xi相关的位置就是以改点为中心的矩形区域。
- 也就是说,目前的CNN并不能满足实际情况下的需求。
- 提问:在进行行为识别任务的时候,与
X
i
X_i
Xi(即左一图片中的足球位置)相关的位置是在哪里?
1.2. 用了什么方法解决?
- 定义了 non local 操作:
- 注意:对于non-local操作,输入与输出的尺寸是一样的。
- 参考下论文解读中的描述,很清楚了:
- 输入是x,输出是y,i和j分别代表输入的某个空间位置,x_i是一个向量,维数跟x的channel数一样。
- 最终结果y是
- f是一个计算任意两点相似关系的函数,输出的是标量,shape就是
[]
- g是一个映射函数,将一个点映射成一个向量,可以看成是计算一个点的特征,比如最简单的1*1卷积。
- 也就是说,为了计算输出层的一个点,需要将输入的每个点都考虑一遍
- 很像attention:输出的某个点在原图上的attention,而mask则是相似性给出。
- 参看下图:
- 具体实现方式参考下图:
- Softmax分支代表的是mask。
- 另外一路代表的就是transformed image。
1.3. 效果如何?
- 在当时,进将non-local作为一个trick添加到行为识别网络中就能达到SOTA的效果。
1.4. 还存在什么问题?
- 这类操作一般是添加在原有3D网络基础上的,是用运行时间换准确率。
- 还有一个缺陷(其实是看了新论文才知道的,详情参考Region-based Non-local Operation)
- Non-local 计算两个点之间的依赖关系的时候,只使用了这两个点的信息,而没有充分利用周围小区域的信息。
2. mmaction2 源码分析
2.1. Non-local 模块的实现
- mmaction2 中的Non-local实现代码,定义在
mmcv
中……- 具体源码位置是
mmcv/cnn/bricks/non_local.py
。
- 具体源码位置是
- 实现了1D/2D/3D三种non-local操作。
- 主要就是实现了上面图中的结构。
- 提供了
sub_sample
选项,主要就是对除batch size以及channel外的特征图进行max pool操作。 - 1D/2D/3D的实现方式都相同。
- 配合上图非常清晰了,源码里用的都是
g, theta, phi
这样的变量名。
2.2. Non-local 模块如何添加到现有网络中
- Non-local 相关的参数
model.backbone.non_local
和model.backbone.non_local_cfg
,前者指定那些block要用non local操作,后者设置具体non local操作的参数- 参数举例如下
non_local=((0, 0, 0), (1, 0, 1, 0), (1, 0, 1, 0, 1, 0), (0, 0, 0)),
non_local_cfg=dict(
sub_sample=True,
use_scale=False,
norm_cfg=dict(type='BN3d', requires_grad=True),
mode='embedded_gaussian'),
shift_div=8),
-
Non-local的位置
- TSM-Resnet中:
- 普通的block通过
NL3DWrapper
包裹。 - 该模块中,先调用原始block,再调用non-local模块。
- 普通的block通过
- Resnet3d中:
- 对两类block分别添加non-local参数。
- 每类block,在原先运行完成后,添加non-local模块。
- TSM-Resnet中: