特征图上采样:CARAFE

CARAFE: Content-Aware ReAssembly of FEatures

CARAFE: 轻量级通用上采样算子

其他上采样方法的不足

  • 最近邻或者双线性上采样
    仅通过像素点的空间位置来决定上采样核,并没有利用到特征图的语义信息,可以看作是一种“均匀”的上采样,而且感知域通常都很小(最近邻 1x1,双线性 2x2);
  • Deconvolution
    上采样核并不是通过像素间的距离计算,而是通过网络学出来的,但对于特征图每个位置都是应用相同的上采样核,不能捕捉到特征图内容的信息,另外引入了大量参数和计算量,尤其是当上采样核尺寸较大的时候;
  • Dynamic filter
    对于特征图每个位置都会预测一组不同的上采样核,但是参数量和计算量更加爆炸,而且公认比较难学习

理想上采样算子的特性

  • Large receptive field:需要具有较大的感受野,这样才能更好地利用周围的信息;
  • Content-aware:上采样核应该和特征图的语义信息相关,基于输入内容进行上采样;
  • Lightweight:轻量化,不能引入过多的参数和计算量;

CARAFE

在这里插入图片描述
CARAFE 分为两个主要模块,分别是上采样核预测模块特征重组模块。假设上采样倍率为 σ \sigma σ,给定一个形状为 H × W × C H\times W\times C H×W×C的输入特征图,CARAFE首先利用上采样核预测模块预测上采样核,然后利用特征重组模块完成上采样,得到形状为 σ H × σ W × C \sigma H\times \sigma W\times C σH×σW×C的输出特征图。

上采样核预测模块

在这里插入图片描述

  1. 特征图通道压缩
    对于形状为 H × W × C H\times W\times C H×W×C的输入特征图,首先用一个 1 × 1 1\times 1 1×1卷积将它的通道数压缩到 H × W × C m H\times W\times C_m H×W×Cm,这一步的主要目的是减小后续步骤的计算量。

  2. 内容编码及上采样核预测
    假设上采样核尺寸为 k u p × k u p k_{up}\times k_{up} kup×kup(越大的上采样核意味着更大的感受野和更大的计算量),如果希望对输出特征图的每个位置使用不同的上采样核,那么需要预测的上采样核形状为 σ H × σ W × k u p × k u p \sigma H\times \sigma W\times k_{up}\times k_{up} σH×σW×kup×kup
    对于第一步中压缩后的输入特征图,利用一个 k e n c o d e r × k e n c o d e r k_{encoder}\times k_{encoder} kencoder×kencoder的卷积层来预测上采样核,输入通道数为 C m C_m Cm,输出通道数为 σ 2 k u p 2 \sigma^2 k_{up}^2 σ2kup2,然后将通道维在空间维展开,得到形状为 σ H × σ W × k u p 2 \sigma H\times \sigma W\times k_{up}^2 σH×σW×kup2的上采样核。

  3. 上采样核归一化
    对第二步中得到的上采样核利用 softmax 进行归一化,使得卷积核权重和为 1。

特征重组模块

在这里插入图片描述
对于输出特征图中的每个位置,将其映射回输入特征图,取出以之为中心的 k u p × k u p k_{up}\times k_{up} kup×kup的区域,和预测出的该点的上采样核作点积,得到输出值。相同位置的不同通道共享同一个上采样核。

参数量计算

参 数 量 = 2 ( C i n + 1 ) C m + 2 ( C m k e n c o d e r 2 σ 2 k e n c o d e r 2 + 1 ) σ 2 k u p 2 + 2 σ 2 k u p 2 C i n 参数量=2(C_{in}+1)C_m+2(C_mk_{encoder}^2 \sigma^2k_{encoder}^2+1)\sigma^2k_{up}^2+2\sigma^2k_{up}^2C_{in} =2(Cin+1)Cm+2(Cmkencoder2σ2kencoder2+1)σ2kup2+2σ2kup2Cin
(不太懂2是什么意思)

超参

  • C m C_m Cm: 压缩通道数,论文中设为64,继续增大并不会带来性能提升
    但是这里没有说明原本的通道数是多少,应该按照比例进行压缩,而不是直接定64
    在这里插入图片描述
  • k e n c o d e r , k u p k_{encoder}, k_{up} kencoder,kup
    只有同步增加 k e n c o d e r , k u p k_{encoder}, k_{up} kencoder,kup才能提升性能,单独增加一个无法提升性能;
    遵循 k e n c o d e r = k u p − 2 k_{encoder}=k_{up}-2 kencoder=kup2
    推荐 k e n c o d e r = 3 , k u p = 5 k_{encoder}=3, k_{up}=5 kencoder=3,kup=5,(性能与计算量的折中)
    在这里插入图片描述
  • 归一化的方法
    Softmax与Sigmoid Normalized 性能相同
    在这里插入图片描述

pytorch 实现

import torch
import torch.nn as nn
import torch.nn.functional as F


class CARAFE(nn.Module):
    def __init__(self, inC, outC, kernel_size=3, up_factor=2):
        super(CARAFE, self).__init__()
        self.kernel_size = kernel_size
        self.up_factor = up_factor
        self.down = nn.Conv2d(inC, inC // 4, 1)
        self.encoder = nn.Conv2d(inC // 4, self.up_factor ** 2 * self.kernel_size ** 2,
                                 self.kernel_size, 1, self.kernel_size // 2)
        self.out = nn.Conv2d(inC, outC, 1)

    def forward(self, in_tensor):
        N, C, H, W = in_tensor.size()

        # N,C,H,W -> N,C,delta*H,delta*W
        # kernel prediction module
        kernel_tensor = self.down(in_tensor)  # (N, Cm, H, W)
        kernel_tensor = self.encoder(kernel_tensor)  # (N, S^2 * Kup^2, H, W)
        kernel_tensor = F.pixel_shuffle(kernel_tensor, self.up_factor)  # (N, S^2 * Kup^2, H, W)->(N, Kup^2, S*H, S*W)
        kernel_tensor = F.softmax(kernel_tensor, dim=1)  # (N, Kup^2, S*H, S*W)
        kernel_tensor = kernel_tensor.unfold(2, self.up_factor, step=self.up_factor) # (N, Kup^2, H, W*S, S)
        kernel_tensor = kernel_tensor.unfold(3, self.up_factor, step=self.up_factor) # (N, Kup^2, H, W, S, S)
        kernel_tensor = kernel_tensor.reshape(N, self.kernel_size ** 2, H, W, self.up_factor ** 2) # (N, Kup^2, H, W, S^2)
        kernel_tensor = kernel_tensor.permute(0, 2, 3, 1, 4)  # (N, H, W, Kup^2, S^2)

        # content-aware reassembly module
        # tensor.unfold: dim, size, step
        in_tensor = F.pad(in_tensor, pad=(self.kernel_size // 2, self.kernel_size // 2,
                                          self.kernel_size // 2, self.kernel_size // 2),
                          mode='constant', value=0) # (N, C, H+Kup//2+Kup//2, W+Kup//2+Kup//2)
        in_tensor = in_tensor.unfold(2, self.kernel_size, step=1) # (N, C, H, W+Kup//2+Kup//2, Kup)
        in_tensor = in_tensor.unfold(3, self.kernel_size, step=1) # (N, C, H, W, Kup, Kup)
        in_tensor = in_tensor.reshape(N, C, H, W, -1) # (N, C, H, W, Kup^2)
        in_tensor = in_tensor.permute(0, 2, 3, 1, 4)  # (N, H, W, C, Kup^2)

        out_tensor = torch.matmul(in_tensor, kernel_tensor)  # (N, H, W, C, S^2)
        out_tensor = out_tensor.reshape(N, H, W, -1)
        out_tensor = out_tensor.permute(0, 3, 1, 2)
        out_tensor = F.pixel_shuffle(out_tensor, self.up_factor)
        out_tensor = self.out(out_tensor)
        return out_tensor


if __name__ == '__main__':
    data = torch.rand(4, 20, 10, 10)
    carafe = CARAFE(20, 10)
    print(carafe(data).size())

  • 23
    点赞
  • 206
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值