文章目录
解决什么问题
提出non-local操作来建立block,来捕捉长距离的依赖
本文创新点\贡献
提出的建立non-local block的方法能方便的插入到很多计算机视觉结构中,在视频分类、位姿估计和图像识别中都有很好的效果
这个图能很好说明什么叫non-local,前两个都是在中心的邻域做一些操作
前人方法
有使用很大的感受野来获取远距离依赖的尝试,之前的方法中长距离依赖只能通过重复的操作卷积、循环,通过数据逐步传播信号,但是这样有局限性:
信号在多次的重复中消失?计算耗时?
-
计算效率低
-
优化困难
作者在这里距离的是残差网络和长短期记忆网络,这俩个都对数据多次重复利用,不过残差网络也有找到response的能力?不同层数的特征图融合,能让相关的特征在一个图中显示出来?
-
在多次跳跃依赖的建模中有困难,比如远距离之间
多次跳跃依赖是指关联的递进? 充电器->手机->人 这样的吗?
本文IDEA来源
没说
方法
方法概述
对每个位置都计算一个response,能更好的获得位置间的联系
相关
和self-attention相关,self-attention通过考虑全部位置,取其在嵌入空间中的加权平均值,来计算一个序列里某个位置的response
解决的点
长距离的相关点的response计算问题,延伸到了图像、视频上
优点
- 可以直接计算两个位置的交互,而不用考虑距离的问题
- 效率高,效果好,只用几个层
- 输入尺度多样,很容易和其他模型结合
原理
和其他方法的比较:
- non-local考虑了全部的位置,而卷积和序列却不能考虑这么多信息
- 虽然考虑了全部的位置信息,但是又和全连接不同:
non-local是基于不同位置之间的联系来计算response的,而全连接使用的是学习到的权重,并且直接多种输入大小,而全连接的输入大小是固定的且没有位置间的对应用的是“ ”来处理不同位置,而不是“ ”
- 位置自由,可以放在深度神经网络的前面或后面,利于将non-local和local信息结合起来
Non-local Neural Networks
方程式
其中
是输出位置的index,
代表全部的可能的位置,
位置的response是和其他的
位置一起计算的
是输入signal,可以是图片、序列、视频,一般是他们的特征
是和
一样大的输出signal
成对函数
计算
和
之间的标量
函数计算在
位置的输入signa 的表达
用来正则化response
多种 表达式
都有多种计算公式,而实验证明,不同的公式算出来的效果差别不是很大
先将
假设成简单的线性嵌入:
其中
是需要学习的权重矩阵,再空间上就是个
的卷积
Gaussian:
其中
也可以用欧式距离,但是点乘更方便深度学习计算
Embedded Gaussian:
Gaussian函数的简单拓展,能计算嵌入空间的相似性
其中 和 是两个嵌入
为什么又加了两个参数就能计算相似性了?
Softmax:
在 Attention is all you need 论文中,使用了softmax,所以这也有个softmax版本的:
但是作者把这个softmax版本的应用到空间/时空间的图像/视频任务上,发现作用并不明显(指softmax),然后提供了其他的版本
前面两个Gaussian可以直接写成softmax
Dot product:
这是采用嵌入的版本, , 就是 的位置的数量,这样能简化梯度计算,而且规范化是很有必要的,因为输入的大小是变化。
这里的 是下采样后的数量
Concatenation:
其中
表示串联,而且
是一个权重向量,能把串联向量映射成标量
之后就适当的选择版本,当成个参数来调吧
Non-local Block
封装到block中,这样能更好的合并到其他的结构中:
这个
就是个残差操作,这个残差的操作可以在不破坏预训练模型的情况下,将non-local block插入到任何预训练的模型中(此时将
初始化为0)
这要怎么操作,虽然按理来说不需要啥权重,但是要怎么让改动的结构和权重对应上?看看6DVNet怎么做的
更高效的改动
通过参数的设置来提高效率:
设置 的通道数是 的通道数的一半,这是根据残差网路的论文来的,这样能减少计算量。
的通道数和 一样,因为之后还要和 相加
通过下采样的trick还能用来进一步减少计算量:
将
的方程式改为:
其中
是
的下采样版本,加个池化层就能做到,能减少
成对计算的
计算量。
在 Non-local Block计算图 后面加个池化层来完成。
训练
backbone: ResNet-50
学习率:共400K次迭代,一开始设置为0.01,每150K除10
动量:0.9
权重衰减:0.0001
dropout:全局池化后使用,比例是0.5
使用BatchNorm来未调模型,能减少过拟合,BN的缩放参数初始化成0
实验
越深的网络,越多的non-local block,效果越好,作者使用了残差块做了消融实验,说明了效果提升并不是网络变深的原因,而是non-local block的功劳
如果添加的太晚的话,特征图较小(
)的话,效果也不好,所以要看特征图的大小
总结
感觉主要是对[ Attention is all you need ]做了些改动, 的公式是相似的,作者又提出了很多版本的 的公式,最终选择哪个公式还是要看应用的环境,亮点应该在与从NLP领域迁移到了CV领域,而且做成了一个容易插入的block
代码
点乘版本的代码,这是源码
import torch
from torch import nn
class NL_block(nn.Module):
def __init__(self,input_dim,sub_sample,bn):
super(NL_block, self).__init__()
self.input_dim = input_dim
self.sub_sample = sub_sample
self.sub_dim = self.input_dim // 2
self.bn = bn
if self.sub_dim == 0:
self.sub_dim = 1
Conv = nn.Conv2d
Maxpool = nn.MaxPool2d
BatchNorm = nn.BatchNorm2d
self.theta = Conv(self.input_dim,self.sub_dim,kernel_size=1,stride=1)
self.phi = Conv(self.input_dim,self.sub_dim,kernel_size=1,stride=1)
self.g = Conv(self.input_dim,self.sub_dim,kernel_size=1,stride=1)
# theta的 HxW 不能取半,否则就回不到原来的维度了
if self.sub_sample:
self.phi = nn.Sequential(
self.phi,
Maxpool(kernel_size=2)
)
self.g = nn.Sequential(
self.g,
Maxpool(kernel_size=2)
)
if self.bn:
self.W = nn.Sequential(
Conv(self.sub_dim,self.input_dim,kernel_size=1,stride=1),
BatchNorm(num_features=self.input_dim)
)
else:
self.W = Conv(self.sub_dim,self.input_dim)
def forward(self,x):
batch = x.shape[0]
# theta并没有下采样,现在是原版的所有元素400个,通道数减少了一般
x_theta = self.theta(x).view((batch,-1,self.sub_dim)) # 5 400 4
# 对phi进行下采样,x的总数变成了100
x_phi = self.phi(x).view((batch,self.sub_dim,-1)) # 5 4 100
# 让原版的特征图的每个元素都和所有的下采样的元素对应起来,这里的100维度代表权值
f = torch.matmul(x_theta,x_phi) # 5 400 100
# g也下采样
g_x = self.g(x).view(batch,-1,self.sub_dim) # 5 100 4
N = x_phi.shape[2]
f_div_c = f / N
# 5 4 20 20
# 如此每个元素都是下采样后所有元素的加权和
y = torch.matmul(f_div_c,g_x).view(batch,self.sub_dim,*x.size()[2:])
z = self.W(y) + x
return z
if __name__ = "__main__":
x = torch.randn((5,8,20,20))
model = NL_block(x.shape[1],True,True)
result = model(x)