为视频分类设计的基于区域的非局部网络.
使用CNN处理问题时,感受野被限制在kernel里。多层CNN的感受野也都是同一个形状。CNN通过深度堆叠具有小窗口尺寸的卷积运算来对 long-range 依存关系进行建模,这使优化变得困难。
为了解决上面的问题,可以用 Non-local 结构,但该结构也存在问题:计算两个点之间相互依赖关系的时候,只用了这两个点的信息,而没有充分利用点周围的信息。
本文作者设计了基于区域的non-local操作(RNL),这是一种自注意力机制,可以直接捕获远程依赖性,而无需深入的local操作堆栈。
non-local操作可以被写作一般的形式:
\[y_i=\frac{1}{C\left(x_i\right)} \sum_j f\left(x_i, x_j\right) h\left(x_j\right)\]其中相似度函数$f(\cdot,\cdot)$计算两个特征位置$x_i,x_j$的相似程度,输出被权重因子$C(x_i)$归一化。然而计算位置$x_i$的特征时,每次只与一个位置$x_j$交互。作为改进,RNL中两个点之间的相互关系不仅仅与这两个点本身有关,还与其周边region有关。记以点$i$为中心的区域为\(\mathcal{N}_i\),则RNL的表达式为:
\[y_i=\frac{1}{C\left(x_i\right)} \sum_j f\left( \theta(\mathcal{N}_i),\theta(\mathcal{N}_j)\right) x_j\]class RNL(nn.Module):
def __init__(self, in_channels, k=2):
super(RNL, self).__init__()
self.k = k
self.g = nn.Conv2d(in_channels, in_channels//self.k, 1)
self.F = nn.Conv2d(in_channels//self.k, in_channels//self.k, 3, 1, 1)
self.o = nn.Conv2d(in_channels//self.k, in_channels, 1)
def forward(self, x):
b, c, h, w = x.shape
fx = self.g(x) # [b, c/2, h, w]
hx = fx.view(b, -1, h*w).permute(0, 2, 1) # [b, hw, c/2]
gx = self.F(fx) # [b, c/2, h, w]
gx = gx.view(b, -1, h*w) # [b, c/2, hw]
attn = torch.bmm(gx.permute(0, 2, 1), gx) # [b, hw, hw]
attn = F.softmax(attn, dim=2) # 按行归一化
y = torch.matmul(attn, hx) # [b, hw, c/2]
y = y.permute(0, 2, 1).contiguous() # [b, c/2, hw]
y = y.view(b, -1, h, w)
return x + self.o(y)