为视频分类设计的基于区域的非局部网络.

使用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)