Navigation

    Gpushare.com

    • Register
    • Login
    • Search
    • Popular
    • Categories
    • Recent
    • Tags
    1. Home
    2. 189****6672
    3. Best
    • Profile
    • Following 0
    • Followers 4
    • Topics 104
    • Posts 106
    • Best 56
    • Groups 0

    Best posts made by 189****6672

    • 何恺明团队新作VitDET:用于目标检测的Vit主干

      何恺明团队新作VitDET:用于目标检测的Vit主干

      论文:Exploring Plain Vision Transformer Backbones for Object Detection

      论文地址:https://arxiv.org/pdf/2203.16527.pdf

      代码地址: 代码将开源

      2022-03-31-22-20-32.png


      摘要

      1. 现存问题: 为了基于Vit主干网络的预训练模型能够更好的适应下游任务,本文探索基于Vit的目标检测模型。
      2. 实验发现: (i)从单一尺寸的特征图(没有常见的FPN设计)构建一个简单的特征金字塔就能获取足够的信息特征;(ii)仅使用窗口注意(不使用swin中的窗口shift)并辅助很少的跨窗口传播块就能实现足够的信息交流。
      3. 实验结果: 使用MAE进行预训练的Vit主干,ViTDet可以与之前所有基于分层主干的领先方法竞争,另外,仅使用ImageNet-1K预训练即可在COCO数据集上达到61.3 AP

      方法

      本文并没有提出新的组件,目标是通过微小的模型调整,实现vit这种单尺度主干能够很好的使用目标检测任务。论文基于Mask RCNN类似模型进行修改。

      简单的特征金字塔

      2022-03-31-22-20-44.png

      FPN在下游模型中很常见。
      如果主干网络是多尺度的,FPN模块就是将早期阶段的更高分辨率特征与后期的更强特征相结合。这在FPN中是通过自上而下和横向连接实现(图1左)

      但是,如果主干网络不是多尺度的(每一层具有相同的分辨率),FPN该如何生成?

      文章提出了三个思路:

      1. 将vit模型人为的分成四个block,每个block通过不同stride的卷积和反卷积操作获取多尺度特征金字塔
      2. 仅仅使用vit最后一层特征,通过不同stride的反卷积操作获取多尺度金字塔
      3. 同样仅仅使用vit最后一层特征,但获取的多尺度金字塔中没有自上而下的信息流

      2022-03-31-22-20-57.png

      全局信息

      目标检测器受益于高分辨率的输入图像,但在整个主干中计算全局自注意需要消耗很大的内存,而且速度很慢

      本文将研究重点放在这样一个场景上:通过预先训练好的主干网络来执行全局自我注意,然后在微调过程中适应更高分辨率的输入。就是不去修改主干网络来获取全局信息

      那么这就带来了一个矛盾点:想不修改vit模型结构来获取全局信息(保证预训练权重可用),又不想计算全局注意力

      文章提出了思路:

      类似swin transformer,将特征图平分为不重叠的窗口,但不使用shift窗口滑动。
      将vit平均分为4个子block(例如vit-L一共有24个block,那么将其分为4个子block,那么每个子block中含有6个小模块)

      方法1:
      每个子block中的最后一个注意力模块设置为全局注意力计算,这样能够保证内存和计算量

      方法2:
      每个子block后添加一个带跳跃连接的卷积模块(包含多个卷积层和一个residual层),卷积模块中的最后一个卷积层初始权重全为0,这样通过residual层能够保证整个卷积模块不影响vit的初始状态

      实验

      消融实验

      在COCO数据集上进行消融实验。在train2017数据集上进行训练,并在val2017上进行评估。得到目标检测边框(APbox)和实例分割(APmask)的结果。
      使用MAE来初始化vit主干网络,在IN-1K上预训练

      简单的特征金字塔是足够的
      对图2中的金字塔策略进行实验,如表1所示,结果显示简单的特征金字塔足以让普通ViT主干享受金字塔的好处

      2022-03-31-22-21-10.png

      研究表明,多层特征尺度结构,而不是自上而下/横向连接,是特征金字塔能够极大地有利于多尺度目标检测的主要原因。

      少量全局模块是足够的
      表2显示了各种形式的信息传播是有帮助的,而我们可以在大多数或所有块中使用窗口注意。重要的是,所有这些架构调整仅在微调期间执行;它们不需要重新设计预训练架构

      2022-03-31-22-21-49.png

      2022-03-31-22-21-58.png

      MAE提供高性能预训练主干网络

      2022-03-31-22-22-10.png

      与多尺度主干网络对比

      2022-03-31-22-22-44.png

      2022-03-31-22-22-23.png

      2022-03-31-22-22-54.png

      2022-03-31-22-23-05.png

      posted in CV领域
      189****6672
      189****6672
    • 混合精度训练Automatic mixed precision(AMP)加速训练

      混合精度训练Automatic mixed precision(AMP)加速训练

      使用amp基本代码流程:

      # amp依赖Tensor core架构,所以model参数必须是cuda tensor类型
      model = Net().cuda()
      optimizer = optim.SGD(model.parameters(), ...)
      amp = True # 控制是否使用amp
      # GradScaler对象用来自动做梯度缩放
      scaler = torch.cuda.amp.GradScaler() if amp
      
      for epoch in epochs:
          model.train()
          for input, target in dataloader:
              optimizer.zero_grad()
              # 在autocast enable 区域运行forward
              if amp and scaler is not None:
              	with torch.cuda.amp.autocast():
                  	# model做一个FP16的副本,forward
                  	output = model(input)
                  	loss = loss_fn(output, target)
              	# 用scaler,scale loss(FP16),backward得到scaled的梯度(FP16)
             	 	scaler.scale(loss).backward()
              	# scaler 更新参数,会先自动unscale梯度
              	# 如果有nan或inf,自动跳过
              	scaler.step(optimizer)
              	# scaler factor更新
              	scaler.update()
               else:
                  output = model(input)
                  loss = loss_fn(output, target)
                  loss.backward
                  optimizer.step()
           
          if (epoch + 1) % val_interval == 0:  # 多长时间验证一次
              model.eval()
              with torch.no_grad():
                  for input, target in valdataloader:
                      if amp:
                          with torch.cuda.amp.autocast():
                              output = model(input)
                      else:
                          output = model(input)
              
      

      内存占用对比

      使用AMP会节约cuda内存

      不使用AMP

      使用AMP

      损失曲线和验证metric曲线

      使用AMP能够加快收敛速度

      训练总时长和每个epoch时长

      使用AMP大大缩短训练时长

      posted in 技术分享📚有奖励
      189****6672
      189****6672
    • 医学图像分割——Mixed Transformer UNet(MT-UNet)

      医学图像分割——Mixed Transformer UNet(MT-UNet)

      论文地址:https://arxiv.org/pdf/2111.04734.pdf

      代码地址:https://github.com/Dootmaan/MT-UNet

      Mixed Transformer U-Net For Medical Image Segmentation

      表现SOTA!性能优于Swin-Unet、TransUNet等网络


      摘要

      存在问题 虽然U-Net在医学图像分割方面取得了巨大的成功,但它缺乏对长期依赖关系进行显式建模的能力。视觉Transformer由于其固有的通过自注意(SA)捕捉长程相关性的能力,近年来成为一种可替代的分割结构。
      存在问题 然而,Transformer通常依赖于大规模的预训练,具有较高的计算复杂度。此外,SA只能在单个样本中建模self-affinities,忽略了整个数据集的潜在相关性
      论文方法 提出了一种新的混合Transformer模块(MTM),用于同时进行inter-affinities学习和intra-affinities学习。MTM首先通过局部-全局高斯加权自注意(LGG-SA)有效地计算窗口内部affinities。然后,通过外部注意挖掘数据样本之间的联系。利用MTM算法,构造了一种用于医学图像分割的MT-UNet模型

      Method

      如图1所示。该网络基于编码器-解码器结构

      1. 为了降低计算成本,MTMs只对空间大小较小的深层使用,
      2. 浅层仍然使用经典的卷积运算。这是因为浅层主要关注局部信息,包含更多高分辨率的细节。

      MTM

      如图2所示。MTM主要由LGG-SA和EA组成。

      LGG-SA用于对不同粒度的短期和长期依赖进行建模,而EA用于挖掘样本间的相关性。

      该模块是为了替代原来的Transformer编码器,以提高其在视觉任务上的性能和降低时间复杂度

      LGG-SA(Local-Global Gaussian-Weighted Self-Attention)

      传统的SA模块对所有tokens赋予相同的关注度,而LGG -SA则不同,利用local-global自注意力和高斯mask使其可以更专注于邻近区域。实验证明,该方法可以提高模型的性能,节省计算资源。该模块的详细设计如图3所示

      local-global自注意力

      在计算机视觉中,邻近区域之间的相关性往往比遥远区域之间的相关性更重要,在计算注意图时,不需要为更远的区域花费相同的代价。

      因此,提出local-global自注意力。

      1. 上图stage1中的每个局部窗口中含有四个token,local SA计算每个窗口内的内在affinities。
      2. 每个窗口中的token被aggregate聚合为一个全局token ,表示窗口的主要信息。对于聚合函数,轻量级动态卷积(Lightweight Dynamic convolution, LDConv)的性能最好。
      3. 在得到下采样的整个特征图后,可以以更少的开销执行global SA(上图stage2)。

      其中X∈RH×W×CX \in R^{H \times W \times C}X∈RH×W×C

      其中,stage1中的局部窗口自注意力代码如下:

      class WinAttention(nn.Module):
          def __init__(self, configs, dim):
              super(WinAttention, self).__init__()
              self.window_size = configs["win_size"]
              self.attention = Attention(dim, configs)
      
          def forward(self, x):
              b, n, c = x.shape
              h, w = int(np.sqrt(n)), int(np.sqrt(n))
              x = x.permute(0, 2, 1).contiguous().view(b, c, h, w)
              if h % self.window_size != 0:
                  right_size = h + self.window_size - h % self.window_size
                  new_x = torch.zeros((b, c, right_size, right_size))
                  new_x[:, :, 0:x.shape[2], 0:x.shape[3]] = x[:]
                  new_x[:, :, x.shape[2]:,
                        x.shape[3]:] = x[:, :, (x.shape[2] - right_size):,
                                         (x.shape[3] - right_size):]
                  x = new_x
                  b, c, h, w = x.shape
              x = x.view(b, c, h // self.window_size, self.window_size,
                         w // self.window_size, self.window_size)  
              x = x.permute(0, 2, 4, 3, 5,
                            1).contiguous().view(b, h // self.window_size,
                                                 w // self.window_size,
                                                 self.window_size * self.window_size,
                                                 c).cuda()
              x = self.attention(x)  #  (b, p, p, win, c) 对局部窗口内的tokens进行自注意力计算
              return x
      

      聚合函数代码如下

      class DlightConv(nn.Module):
          def __init__(self, dim, configs):
              super(DlightConv, self).__init__()
              self.linear = nn.Linear(dim, configs["win_size"] * configs["win_size"])
              self.softmax = nn.Softmax(dim=-1)
      
          def forward(self, x):  # (b, p, p, win, c)
              h = x
              avg_x = torch.mean(x, dim=-2)  # (b, p, p, c)
              x_prob = self.softmax(self.linear(avg_x))  # (b, p, p, win)
      
              x = torch.mul(h,
                            x_prob.unsqueeze(-1))  # (b, p, p, win, c) 
              x = torch.sum(x, dim=-2)  # (b, p, p, c)
              return x
      

      Gaussian-Weighted Axial Attention

      与使用原始SA的LSA不同,提出了高斯加权轴向注意(GWAA)的方法。GWAA通过一个可学习的高斯矩阵增强了相邻区域的感知全权重,同时由于具有轴向注意力而降低了时间复杂度。

      1. 上图中stage2中特征图的第三行第三列特征进行linear projection得到qi,jq_{i, j}qi,j​
      2. 将该特征点所在行和列的所有特征分别进行linear projection得到Ki,jK_{i, j}Ki,j​和Vi,jV_{i, j}Vi,j​
      3. 将该特征点与所有的K和V的欧式距离定义为Di,jD_{i, j}Di,j​

      最终的高斯加权轴向注意力输出结果为

      并简化为

      轴向注意力代码如下:

      class Attention(nn.Module):
          def __init__(self, dim, configs, axial=False):
              super(Attention, self).__init__()
              self.axial = axial
              self.dim = dim
              self.num_head = configs["head"]
              self.attention_head_size = int(self.dim / configs["head"])
              self.all_head_size = self.num_head * self.attention_head_size
      
              self.query_layer = nn.Linear(self.dim, self.all_head_size)
              self.key_layer = nn.Linear(self.dim, self.all_head_size)
              self.value_layer = nn.Linear(self.dim, self.all_head_size)
      
              self.out = nn.Linear(self.dim, self.dim)
              self.softmax = nn.Softmax(dim=-1)
      
          def transpose_for_scores(self, x):
              new_x_shape = x.size()[:-1] + (self.num_head, self.attention_head_size)
              x = x.view(*new_x_shape)
              return x
      
          def forward(self, x):
              # first row and col attention
              if self.axial:
                   # x: (b, p, p, c)
                  # row attention (single head attention)
                  b, h, w, c = x.shape
                  mixed_query_layer = self.query_layer(x)
                  mixed_key_layer = self.key_layer(x)
                  mixed_value_layer = self.value_layer(x)
      
                  query_layer_x = mixed_query_layer.view(b * h, w, -1)
                  key_layer_x = mixed_key_layer.view(b * h, w, -1).transpose(-1, -2)  # (b*h, -1, w)
                  attention_scores_x = torch.matmul(query_layer_x,
                                                    key_layer_x)  # (b*h, w, w)
                  attention_scores_x = attention_scores_x.view(b, -1, w,
                                                               w)  # (b, h, w, w)
      
                  # col attention  (single head attention)
                  query_layer_y = mixed_query_layer.permute(0, 2, 1,
                                                            3).contiguous().view(
                                                                b * w, h, -1)
                  key_layer_y = mixed_key_layer.permute(
                      0, 2, 1, 3).contiguous().view(b * w, h, -1).transpose(-1, -2)  # (b*w, -1, h)
                  attention_scores_y = torch.matmul(query_layer_y,
                                                    key_layer_y)  # (b*w, h, h)
                  attention_scores_y = attention_scores_y.view(b, -1, h,
                                                               h)  # (b, w, h, h)
      
                  return attention_scores_x, attention_scores_y, mixed_value_layer
      
              else:
                
                  mixed_query_layer = self.query_layer(x)
                  mixed_key_layer = self.key_layer(x)
                  mixed_value_layer = self.value_layer(x)
      
                  query_layer = self.transpose_for_scores(mixed_query_layer).permute(
                      0, 1, 2, 4, 3, 5).contiguous()  # (b, p, p, head, n, c)
                  key_layer = self.transpose_for_scores(mixed_key_layer).permute(
                      0, 1, 2, 4, 3, 5).contiguous()
                  value_layer = self.transpose_for_scores(mixed_value_layer).permute(
                      0, 1, 2, 4, 3, 5).contiguous()
      
                  attention_scores = torch.matmul(query_layer,
                                                  key_layer.transpose(-1, -2))
                  attention_scores = attention_scores / math.sqrt(
                      self.attention_head_size)
                  atten_probs = self.softmax(attention_scores)
      
                  context_layer = torch.matmul(
                      atten_probs, value_layer)  # (b, p, p, head, win, h)
                  context_layer = context_layer.permute(0, 1, 2, 4, 3,
                                                        5).contiguous()
                  new_context_layer_shape = context_layer.size()[:-2] + (
                      self.all_head_size, )
                  context_layer = context_layer.view(*new_context_layer_shape)
                  attention_output = self.out(context_layer)
      
              return attention_output
      

      高斯加权代码如下:

      class GaussianTrans(nn.Module):
          def __init__(self):
              super(GaussianTrans, self).__init__()
              self.bias = nn.Parameter(-torch.abs(torch.randn(1)))
              self.shift = nn.Parameter(torch.abs(torch.randn(1)))
              self.softmax = nn.Softmax(dim=-1)
      
          def forward(self, x): 
              x, atten_x_full, atten_y_full, value_full = x  #x(b, h, w, c) atten_x_full(b, h, w, w)   atten_y_full(b, w, h, h) value_full(b, h, w, c)
              new_value_full = torch.zeros_like(value_full)
      
              for r in range(x.shape[1]):  # row
                  for c in range(x.shape[2]):  # col
                      atten_x = atten_x_full[:, r, c, :]  # (b, w)
                      atten_y = atten_y_full[:, c, r, :]  # (b, h)
      
                      dis_x = torch.tensor([(h - c)**2 for h in range(x.shape[2])
                                            ]).cuda()  # (b, w)
                      dis_y = torch.tensor([(w - r)**2 for w in range(x.shape[1])
                                            ]).cuda()  # (b, h)
      
                      dis_x = -(self.shift * dis_x + self.bias).cuda()
                      dis_y = -(self.shift * dis_y + self.bias).cuda()
      
                      atten_x = self.softmax(dis_x + atten_x)
                      atten_y = self.softmax(dis_y + atten_y)
      
                      new_value_full[:, r, c, :] = torch.sum(
                          atten_x.unsqueeze(dim=-1) * value_full[:, r, :, :] +
                          atten_y.unsqueeze(dim=-1) * value_full[:, :, c, :],
                          dim=-2)
              return new_value_full
      

      local-global自注意力完整代码如下:

      class CSAttention(nn.Module):
          def __init__(self, dim, configs):
              super(CSAttention, self).__init__()
              self.win_atten = WinAttention(configs, dim)
              self.dlightconv = DlightConv(dim, configs)
              self.global_atten = Attention(dim, configs, axial=True)
              self.gaussiantrans = GaussianTrans()
              #self.conv = nn.Conv2d(dim, dim, 3, padding=1)
              #self.maxpool = nn.MaxPool2d(2)
              self.up = nn.UpsamplingBilinear2d(scale_factor=4)
              self.queeze = nn.Conv2d(2 * dim, dim, 1)
      
          def forward(self, x):
              '''
              :param x: size(b, n, c)
              :return:
              '''
              origin_size = x.shape
              _, origin_h, origin_w, _ = origin_size[0], int(np.sqrt(
                  origin_size[1])), int(np.sqrt(origin_size[1])), origin_size[2]
              x = self.win_atten(x)  # (b, p, p, win, c)
              b, p, p, win, c = x.shape
              h = x.view(b, p, p, int(np.sqrt(win)), int(np.sqrt(win)),
                         c).permute(0, 1, 3, 2, 4, 5).contiguous()
              h = h.view(b, p * int(np.sqrt(win)), p * int(np.sqrt(win)),
                         c).permute(0, 3, 1, 2).contiguous()  # (b, c, h, w)
      
              x = self.dlightconv(x)  # (b, p, p, c)
              atten_x, atten_y, mixed_value = self.global_atten(
                  x)  # (b, h, w, w) (b, w, h, h) (b, h, w, c)这里的h w就是p
              gaussian_input = (x, atten_x, atten_y, mixed_value)
              x = self.gaussiantrans(gaussian_input)  # (b, h, w, c)
              x = x.permute(0, 3, 1, 2).contiguous()  # (b, c, h, w)
      
              x = self.up(x)
              x = self.queeze(torch.cat((x, h), dim=1)).permute(0, 2, 3,
                                                                1).contiguous()
              x = x[:, :origin_h, :origin_w, :].contiguous()
              x = x.view(b, -1, c)
      
              return x
      

      EA

      外部注意(External Attention, EA),是用于解决SA无法利用不同输入数据样本之间关系的问题。

      与使用每个样本自己的线性变换来计算注意分数的自我注意不同,在EA中,所有的数据样本共享两个记忆单元MK和MV(如图2所示),描述了整个数据集的最重要信息。

      ​

      EA代码如下:

      class MEAttention(nn.Module):
          def __init__(self, dim, configs):
              super(MEAttention, self).__init__()
              self.num_heads = configs["head"]
              self.coef = 4
              self.query_liner = nn.Linear(dim, dim * self.coef)
              self.num_heads = self.coef * self.num_heads
              self.k = 256 // self.coef
              self.linear_0 = nn.Linear(dim * self.coef // self.num_heads, self.k)
              self.linear_1 = nn.Linear(self.k, dim * self.coef // self.num_heads)
      
              self.proj = nn.Linear(dim * self.coef, dim)
      
          def forward(self, x):
              B, N, C = x.shape
              x = self.query_liner(x)  # (b, n, 4c)
              x = x.view(B, N, self.num_heads, -1).permute(0, 2, 1,
                                                           3)  #  (b, h, n, 4c/h)
      
              attn = self.linear_0(x)  # (b, h, n, 256/4)
      
              attn = attn.softmax(dim=-2)  # (b, h, 256/4)
              attn = attn / (1e-9 + attn.sum(dim=-1, keepdim=True))  # (b, h, 256/4)
      
              x = self.linear_1(attn).permute(0, 2, 1, 3).reshape(B, N, -1)
      
              x = self.proj(x)
      
              return x
      

      EXPERIMENTS

      posted in CV领域
      189****6672
      189****6672
    • typora中gitee图床配置

      typora中gitee图床配置

      下载Picgo

      需要通过Picgo软件上传到gitee图床中

      1. Picgo软件github下载地址:https://github.com/Molunerfinn/PicGo/releases

      image-20220419214041063

      1. 选择PicGo-2.3.0.AppImage进行下载并进行双击安装

      如果无法安装,右击选择属性->权限->勾选“允许文件作为程序执行”,再进行双击安装

      1. 弹出小窗口,右击选择“打开详细窗口”

        image-20220419214947540

      2. 安装nodejs环境

      通过以下命令直接安装

      sudo apt install nodejs npm -y
      

      并进行验证是否安装成功

      node -v
      npm -v
      
      1. 在Picgo软件中安装gitee插件

      image-20220419215738827

      创建gitee图床

      1. 注册登录你的gitee账号,点击右上角+号,新建仓库

      image-20220419220332499

      1. 填写仓库名称…

      image-20220419220858979

      1. 设置仓库开源

      image-20220419221110817

      1. 初始化readme文件

      image-20220419221331135

      1. 创建开源许可

      image-20220419221527630

      image-20220419221639631

      image-20220419221800882

      1. 添加私人令牌

      image-20220419221951571

      image-20220419222207730

      image-20220419222333507

      保存好私人令牌

      设置Picgo

      image-20220419222713996

      其中,repo:gitee用户名/仓库名;token:私人令牌

      设置Typora

      image-20220419222928971

      image-20220419223052142

      注意:PicGo路径是你下载picgo安装包的路径

      最后,点击“验证图片上传选项”来验证配置是否成功


      这样,你就可以直接复制本地图片或网络图片到Typora(可能需要打开Picgo软件),它会自动上传到你的gitee仓库

      posted in 技术分享📚有奖励
      189****6672
      189****6672
    • MaskFormer:语义分割可以不全是像素级分类

      MaskFormer:语义分割可以不全是像素级分类

      论文:Per-Pixel Classification is Not All You Need for Semantic Segmentation

      论文地址:https://arxiv.org/pdf/2107.06278.pdf

      代码地址: https://bowenc0221.github.io/maskformer

      2022-03-20-16-43-52.png

      摘要

      1. 目前研究多将语义分割算法作为一种像素级的分类算法,而将实例分割作为一种mask分类算法
      2. 论文的重要观点是:mask分类任务能够同时有效解决语义和实例级的分割任务
      3. 基于上述观念,提出了MaskFormer,一种预测二值mask(每个mask用于预测一个类别)的mask分类模型
      4. 实验显示,MaskFormer在ADE20K和COCO分割任务上实现state-of-the-art

      从像素级分类到mask级分类

      1. 首先介绍像素级分类和mask级分类
      2. 随后介绍本文的mask级分类算法
      3. 最后提出了两个不同的前向传播算法

      像素级分类

      大家应该对像素级分类很熟悉了,可以用公式表达为2022-03-20-17-16-16.png,其中ΔK\Delta^{K}ΔK,具体含义就是一张图像上每个像素点的K类别概率分布

      最后使用cross entropy对每个像素进行loss计算

      mask级分类

      2022-03-20-16-45-02.png

      mask级分类将分割任务拆分为两个部分:

      1. 将图像分割成N个区域(N不需要等于类别K),使用二进制2022-03-20-17-16-33.png表示
      2. 这N个区域的每个区域内部是属于同一个类别,所以还需要对其进行类别预测,可以表示为2022-03-20-17-16-49.png,这里的类别概率分布pi∈ΔK+1p_{i} \in \Delta^{K+1}pi​∈ΔK+1包含无对象no object 类别

      由于N不需要等于类别K,这就意味着会存在多个区域属于同一个类别,这时mask级分类可以适用于语义分割和实例级分割任务

      上述就是mask级分类的两个组成部分,但这会引出下一个问题,如何构造标签?

      1. 将一般标签改造成2022-03-20-17-16-59.png ,其中NgtN^{gt}Ngt可以认为是类别个数
      2. 预测生成的区域块数量N一般会大于标签中的区域块NgtN^{gt}Ngt,为了后续能够进行对一对匹配,所以两者数量需要一致,因此添加一系列无对象tokens使两者数量相同

      进一步就是要考虑如何将标签和预测结果中的不同区域进行匹配

      1. 作者发现使用二值匹配算法bipartite matching 比使用固定匹配算法trivial fixed matching 算法要好
      2. 借鉴DETR的匹配思路,联合类别和mask预测对i和j进行匹配:2022-03-20-17-17-10.png

      基于匹配的结果,最终的损失函数为2022-03-20-17-17-18.png

      MaskFormer

      2022-03-20-16-45-46.png

      整个模型分成三个模块(如上图所示):

      1. 像素级模块用于提取像素级特征嵌入
      2. Transformer模块,用于计算N个区域嵌入
      3. 分割模块,基于上述两个嵌入计算预测类别

      像素级模块

      就是一个编码器-解码器结构,输入大小为H×W的图像,输出为2022-03-20-17-18-49.png的特征图

      Transformer模块
      将像素级模块中编码器的输出特征图和N个可学习的位置嵌入作为Transformer解码器的输入, 输出为Q∈RCQ×N\mathcal{Q} \in \mathbb{R}^{C_{\mathcal{Q}} \times N}Q∈RCQ​×N

      分割模块

      1. 对于Transformer模块的输出Q,使用线性分类层和softmax进行类别输出,得到类别概率2022-03-20-17-19-06.png
      2. 使用带有两个隐藏层的MLP将Q转化为2022-03-20-17-19-14.png,并与2022-03-20-17-28-35.png进行点乘和sigmoid操作,得到二值mask预测,2022-03-20-17-19-24.png,其中每个预测值为mi∈[0,1]H×Wm_{i} \in[0,1]^{H \times W}mi​∈[0,1]H×W,一共有N个

      训练过程中,联合使用cross entropy classification loss 和binary mask loss Lmask \mathcal{L}_{\text {mask }}Lmask ​(与DETR一样,联合focal loss和dice loss权重求和)

      前向传播过程

      提出了两种前向传播算法

      1. 针对全景和语义分割,提出了general inference
      2. 专门针对语义分割,提出了semantic inference
        作者并发现,前向传播的策略更大程度上依赖于评价指标而不是任务

      General inference
      上文所述,我们知道2022-03-20-17-19-57.png, 通过公式2022-03-20-17-20-10.png来确定其所属类别,可以通过如下步骤进行理解

      1. 对于N个区域,每个区域有K+1个类别概率,首先确定每个区域中最大概率的类别
      2. 当前像素点同样具有属于每个区域的概率,也就是mim_imi​
      3. 将上述两者相结合就可以获取当前像素点所属的类别和所属的区域

      这样对于语义分割而言,根据所属类别进行分割
      而对于实例分割而言,根据所属类别和所属区域进行区分不同实例

      Semantic inference
      同样对于图像上的一点[h,w][h, w][h,w],其类别计算公式为2022-03-20-17-20-56.png,可以理解为将N作为特征维度

      1. p表示K+1个类别,每个类别有N长度的类别特征
      2. m表示每个像素点同样都有N长度的维度特征
      3. 将m与每个类别的特征进行乘积求和,并比较每个类别的结果,取最大值作为所属类别

      实验

      通过在四个公开数据集上进行了实验对比,证明了MaskFormer无缝统一了语义分割和实例分割,并实现了最优性能
      并通过消融实验,发现语义分割上性能的提升确实来自于从像素级分类到mask级分类的转变

      对比实验

      2022-03-20-16-46-18.png

      语义分割对比实验
      2022-03-20-16-46-33.png

      全景分割对比实验
      2022-03-20-16-46-46.png

      消融实验

      像素级分类和mask级分类比较结果
      使用两个不同的匹配策略之间的比较结果
      2022-03-20-16-47-00.png
      使用不同queries(区域数量N)之间的比较
      2022-03-20-16-47-10.png

      posted in CV领域
      189****6672
      189****6672
    • 高分论文! 高效时空表征学习的统一Transformer--UNIFormer

      高分论文! 高效时空表征学习的统一Transformer–UNIFormer

      UniFormer: Unified Transformer for Efficient Spatial-Temporal Representation Learning

      论文地址:https://arxiv.org/pdf/2201.04676.pdf

      代码地址:https://github.com/Sense-X/UniFormer


      摘要
      引出主题 由于视频具有大量的局部冗余和复杂的全局依赖关系,因此从视频中学习丰富的、多尺度的时空语义是一项具有挑战性的任务
      现有问题 最近的研究主要是由三维卷积神经网络和Vision Transformer驱动的。虽然三维卷积可以有效地聚集局部上下文来抑制来自小三维邻域的局部冗余,但由于感受域有限,它缺乏捕获全局依赖的能力。另外,vision Transformer通过自注意机制可以有效地捕获长时间依赖,但由于各层tokens之间存在盲目相似性比较,限制了减少局部冗余
      本文思路 提出了一种新型的统一Transformer(UniFormer),它以一种简洁的形式,将三维卷积和时空自注意的优点集成在一起,并在计算和精度之间取得了较好的平衡。与传统的Transformer不同的是,关系聚合器通过在浅层和深层中分别局部和全局tokens相关性来处理时空冗余和依赖关系

      Method

      由上图可知,UniFormer模型其中的特色组件是:动态位置嵌入(DPE)、多头关系聚合器(MHRA)和前馈网络(FFN)
      2022-03-26-18-48-25.png

      MHRA

      首先介绍多头关系聚合器

      设计了一种替代的关系聚合器(RA),它可以将三维卷积和时空自注意灵活地统一在一个简洁的Transformer中,分别解决了浅层和深层的视频冗余和依赖问题。具体来说,MHRA通过多头融合进行tokens关系学习:
      2022-03-26-18-48-35.png

      1. 输入张量为X∈RC×T×H×W\mathbf{X} \in \mathbb{R}^{C \times T \times H \times W}X∈RC×T×H×W,reshape为X∈RL×C\mathbf{X} \in \mathbb{R}^{L \times C}X∈RL×C,L=T×H×WL=T \times H \times WL=T×H×W
      2. 通过线性转换,可以将X\mathbf{X}X转换为上下文信息Vn(X)∈RL×CN\mathrm{V}_{n}(\mathbf{X}) \in \mathbb{R}^{L \times \frac{C}{N}}Vn​(X)∈RL×NC​,n表示第几个head
      3. 然后关系聚合器RA通过token affinity An∈RL×LA_{n} \in \mathbb{R}^{L \times L}An​∈RL×L来融合上下文信息得到Rn(X)∈RL×CNR_{n} (\mathbf{X}) \in \mathbb{R}^{L \times \frac{C}{N}}Rn​(X)∈RL×NC​
      4. 最后concat所有head的信息,并通过U∈RC×C\mathbf{U} \in \mathbb{R}^{C \times C}U∈RC×C聚合所有head的信息

      根据上下文的域大小,可以将MHRA分为 local MHRA 和global MHRA

      Local MHRA

      在网络浅层中,目标是学习小三维时空中局部时空背景下的详细视频表示,这个观点与3D卷积也有相似之处

      将作用域限制在Ωit×h×w\Omega_{i}^{t \times h \times w}Ωit×h×w​中

      那么将Anlocal∈Ωit×h×wA_{n}^{local} \in \Omega_{i}^{t \times h \times w}Anlocal​∈Ωit×h×w​作为局部可学习参数,值仅依赖于token之间的相对3D位置
      2022-03-26-18-48-46.png

      Global MHRA

      在网络深层中,关注于在全局视频帧中捕获长远token依赖关系。这与自注意的设计有着相似的见解。

      因此,通过比较全局视图中所有token的内容相似性来设计Anglobal\mathrm{A}_{n}^{global} Anglobal​:
      2022-03-26-18-48-54.png

      其中,Xj\mathbf{X}_jXj​从T×H×WT \times H \times WT×H×W全局进行取值

      DPE

      之前的方法主要采用图像任务的绝对或相对位置嵌入。

      然而,当测试较长的输入帧时,绝对位置嵌入应该通过微调插值到目标输入大小。相对位置嵌入由于缺乏绝对位置信息而修改了自注意,表现较差。

      为了克服上述问题,扩展了条件位置编码(CPE)来设计DPE
      2022-03-26-18-49-01.png

      其中DWConv表示简单的三维深度卷积与零填充。由于卷积的共享参数和局部性,DPE可以克服置换不变性,并且对任意输入长度都很友好。此外,在CPE中已经证明,零填充可以帮助边界上的token意识到自己的绝对位置,因此所有token都可以通过查询其邻居来逐步编码自己的绝对时空位置信息

      模型结构

      分层堆叠UniFormer模块来构建时空学习网络

      1. 如图3所示,网络分为四个阶段,通道数分别为64、128、256和512。

      2. 对每个阶段执行不同个数的block,有以下两种选择:UniFormer- S的{3,4,8,3}和UniFormer- B的{5,8,20,7}。

      3. 在前两个阶段,利用local MHRA来减少局部时空冗余。设置局部域的尺寸为5×5×5,head个数N =通道数。

      4. 在最后两个阶段,应用global MHRA来捕获长期依赖,其每个head的维度为64。

      5. 对 local MHRA使用BN,对global MHRA使用LN 。

      6. DPE的核大小为3×3×3

      7. 利用时空平均池化和全连通层输出最终预测结果

      实验

      COMPARISON TO STATE-OF-THE-ART

      ABLATION STUDIES


      posted in CV领域
      189****6672
      189****6672
    • NUS和字节跳动CVPR 2022 Oral新作SSA:基于多尺度特征提取的全新Transformer主干模型

      NUS和字节跳动CVPR 2022 Oral新作SSA:基于多尺度特征提取的全新Transformer主干模型

      论文地址:https://arxiv.org/pdf/2111.15193.pdf

      代码地址:https://github.com/OliverRensu/Shunted-Transformer

      摘要

      1. 研究背景:ViT模型在各种计算机视觉任务中显示了令人鼓舞的结果,这归功于它们通过自注意力对图像patches或tokens的长期依赖性建模的能力。
      2. 现存问题:这些模型通常会计算每一层内每个token特征的相似性感受野。然而这种方法不可避免地限制了每个自注意层捕捉多尺度特征的能力,从而导致处理多个不同尺度对象时的性能下降。
      3. 解决方法:论文提出了一种新的通用策略,称为分流自注意力shunted self-attention(SSA),该策略允许VIT在每个注意层的多尺度上对注意力进行建模。
      4. 实验结果:跨各种任务的大量实验证明了SSA的优越性。具体而言,基于SSA的Transformer在ImageNet上能够达到84.0%的顶级精度,而且仅参数和计算成本仅仅为其他最优模型的一半。在相同的参数和计算成本下,在COCO数据集上比Focal Transformer高1.3个mAP,在ADE20K数据集上高2.9mIOU。

      2022-04-07-14-46-53.png

      介绍

      下图是对Vision Transformer(ViT)、Pyramid Vision Transformer(PVT)和具有相同特征图大小的SSA中的注意力机制示意图对比。其中圆的个数表示自注意计算中涉及的tokens数,反映了计算成本。圆圈的大小表示相应token的感受野大小。

      从图中可以看出:与ViT和PVT不同,SSA自适应地合并大目标对象上的圆以提高计算效率,并同时考虑不同尺度的对象

      igTo4imH.png

      从下图注意力图可视化可以看出,PVT 只倾向于沙发和床之类的大对象,而SSA相比之下可以精确地捕捉了大对象旁边的灯光之类的小对象

      2022-04-07-14-47-17.png

      具体方法

      2022-04-07-14-47-32.png

      整个模型如上图所示,整个backbone主干网络是一个多层次结构,分为四层,每一层中有一个线性embedding和本文创新模块shunted Transformer。

      上右图中显示该模块的细节,有两个创新层:shunted self-attention和Detail specific FeedForward,接下来进行详细介绍

      shunted self-attention

      2022-04-07-14-47-42.png

      上图就很简洁的反映了不同注意力的差异:

      1. vit是对每个token,进行全局范围的注意力计算。

      2. swin是基于窗口的注意力,对每个窗口中的所有tokens进行注意力计算。

      3. PVT是对全局K和V进行融合缩小,相当于计算某一个token与一个区域特征的相似度。

      4. 而本文的注意力是在PVT的思路上进一步创新,使用不同大小的K V来表示不同大小区域的特征,所以能够融合多尺度的信息特征。

      本文注意力机制的数学表达式为

      2022-04-07-17-19-00.png

      其中K和V通过MTA模块进行大小缩放的,其实就是一个stride为rir_iri​的卷积层,可以通过rir_iri​来控制尺度大小。

      LE是一个增强模块,本质上就是一个depth-wise卷积层。

      然后自注意力计算方法与传统方法一致,为

      Detail-specific Feedforward Layers

      2022-04-07-14-48-04.png

      传统的feed forward layer一般如上图左所示,简单堆叠FC模块,不同tokens之间没有了信息交流。本文使用了Detail Specific模块来进行cross token信息,其数学表达式如下

      其中DS是一个depth-wise卷积层,用于cross token信息的。

      Patch Embedding

      论文认为将图像处理为一个序列tokens是个很重要的事,ViT直接将输入图像分割为不重叠的16×16个patches。最近研究表明使用卷积操作能够获取更高质量的token序列。

      本论文使用步长为2的7×7卷积层+步长为1的3×3卷积层+步长为2的非重叠projection层来获取下采样率为4的输入特征

      Architecture Details and Variants

      如上图4所示,每个层次中有一个Linear embedding连接,这个Linear embedding是一个步长为2的卷积层,用于下采样。

      为了公正的与其他模型进行比较,本文根据head个数和每个层次中含有block的个数NiN_iNi​设计了下表中的三种变体

      2022-04-07-14-47-55.png

      实验

      为了评估模型的有效性,论文在ImageNet-1K分类任务、COCO目标检测和实例分割任务以及ADE20K语义分割任务上进行对比实验,并进行了一系列消融实验来评估各个模块的有效性

      ImageNet-1K分类对比实验

      2022-04-07-20-11-06.png

      COCO目标检测和实例分割对比实验

      2022-04-07-20-11-18.png

      ADE20K语义分割对比实验

      2022-04-07-20-11-34.png

      2022-04-07-20-11-44.png

      Patch Embedding消融实验

      2022-04-07-20-12-00.png

      token融合(尺度缩放)消融实验

      2022-04-07-20-12-08.png

      Feed-Forward消融实验

      2022-04-07-20-12-26.png

      posted in CV领域
      189****6672
      189****6672
    • FAIR CVPR2022新作DVT:用于视频的可变形Transformer

      FAIR CVPR2022新作DVT:用于视频的可变形Transformer

      论文地址:https://arxiv.org/pdf/2203.16795.pdf

      代码地址:未开源

      Deformable Video Transformer

      摘要

      1. 引入主题:在视频分类领域,视频Transformer最近作为一种有效的卷积网络替代品出现。
      2. 现存问题:大多数以前的视频Transformer采用全局时空注意或利用手动定义的策略来比较帧内和帧间的patch。这些固定注意力方案不仅计算成本高,而且通过比较预定位置的patch,忽略了视频中的运动动力学。
      3. 解决方案:该论文介绍了可变形视频Transformer(DVT),它根据运动信息动态预测每个查询位置的一小部分视频Patch,从而允许模型根据帧间的对应关系来决定在视频中查看的位置。关键的是,这些基于运动的对应关系是从以压缩格式存储的视频信息中以零成本获得的。
      4. 实验结果:在四个大型视频基准(Kinetics-400、Something-Something-V2、EPIC-KITCHENS和Diving-48)上的实验表明,该论文模型在相同或更低的计算成本下实现了更高的精度,并在这四个数据集上获得了最优结果。

      算法

      视频Transformer

      视频数据的输入大小一般可以表示为X∈RH×W×3×TX\in R^{H×W×3×T}X∈RH×W×3×T,T表示帧数,3表示每一帧是RGB图像

      因为使用的是Transformer架构,所以首先需要将输入数据转换为一个S⋅TS \cdot TS⋅T tokens,S表示每一帧中的patch个数,每个token可以表示为xst∈RDx_s^t \in R^Dxst​∈RD。整个过程可以表示如下:

      1. 将每一帧图像进行非重叠分割,生成S个patch。
      2. 将每个patch投影到D个通道维度上。
      3. 添加空间位置编码ese_ses​和时间编码ete^tet

      最终得到zst=xst+es+etz_s^t = x_s^t + e_s + e^tzst​=xst​+es​+et

      然后通过多头自注意力,layer norm(LN)和MLP计算,可以表示如下:

      fU0Wk.png

      其中具体的自注意力可以表示如下(使用单头进行简化说明)

      fUsnd.png

      根据以往的视频Transformer算法,自注意力机制可以分为Global space-time attention和Divided space-time attention

      Global space-time attention

      简单来说就是将时空联合起来进行注意力计算,公式如下:

      2022-04-10-17-23-26.png

      其中注意力权重计算公式如下:

      2022-04-10-17-23-34.png

      整个计算过程的计算复杂度为O(S2T2)O(S^2T^2)O(S2T2),最大的问题就是计算量很大。

      Divided space-time attention

      顾名思义,就是将时间和空间的注意力进行分开计算,用来减少计算量

      空间注意力计算公式如下:

      2022-04-10-17-23-42.png

      计算复杂度为O(S2T)O(S^2T)O(S2T)

      对应的时间注意力计算公式如下:

      2022-04-10-17-23-50.png

      计算复杂度为O(ST2)O(ST^2)O(ST2)

      需要注意的是,时间注意力只对不同时间帧上的同一个空间位置进行注意力计算!这就是其最大的问题,因为其没有考虑到不同帧之间目标的运动。

      可变形视频Transformer

      主要分为以下三个部分(创新点)

      Deformable Space-time Attention(D-ST-A)

      2022-04-10-19-47-04.png

      这个注意力机制和上文Divided space-time attention中的时间注意力机制很相似,但是有两个主要不同点:

      1. 对于每个查询qstq_s^tqst​,使用不同帧上的N个空间位置s(n)∣n=1,…Ns(n)|n=1,…Ns(n)∣n=1,…N进行相似度计算,而不是一个固定位置,这虽然带来相对较大的计算量,但会获取更大空间上的特征信息,性能会提高很多。文中使用N=8。
      2. 这N个位置是数据驱动的,而不是人为定义的,这在后面进行细说。

      该注意力机制的数学表达式如下:

      2022-04-10-20-00-30.png

      其中每一帧上的N个空间位置是如何计算的呢?

      ——是根据查询点特征和运动嵌入特征经过投影生成的相对偏置计算的,公式如下:

      2022-04-10-20-00-37.png

      2022-04-10-20-00-44.png

      其中运动嵌入mst,t′m_s^{t, t^\prime}mst,t′​是根据存储在压缩视频中的运动位移和RGB residuals确定的,详细步骤可以查看论文。

      其中的相似度矩阵αst,t′∈RN{\boldsymbol{\alpha}}_{s}^{t, t^{\prime}} \in R^Nαst,t′​∈RN与之前的计算方式不同,而是根据查询点特征和运动嵌入特征计算而来的,公式如下:

      2022-04-10-20-00-53.png

      2022-04-10-20-01-03.png

      Deformable Multi-Scale Attention (D-MS-A)

      上述D-ST-A是一个时间上的注意力机制,而D-MS-A是一个空间上的注意力机制,用于编码同一帧上的注意力。

      但对于每一帧图像,这里引入了多尺度注意力——计算F个不同分辨率下的空间信息,不同分辨率图像中采样N′N^\primeN′个patch进行注意力计算,多分辨率可以通过不同步长的3D卷积层来实现,数学表达式如下:

      2022-04-10-20-00-04.png

      其中不同分辨率图像中的patch采样也是通过根据其中对应查询点特征计算偏置得到的,计算公式如下:

      2022-04-10-21-29-21.png

      2022-04-10-20-17-47.png

      Attention Fusion

      可以仅使用可变形时空注意(D-ST-A)、仅使用可变形多尺度注意(D-MS-A)以及两者的组合(D-ST+MS-A)。

      在最后一种情况下,将由这两种注意策略独立计算出的两个token zsSTtz_s^{ST^t}zsSTt​和zsMStz_s^{MS^t}zsMSt​馈送到一个注意力融合层u()进行信息融合,Zst=u(ZsSTt,ZsMSt)\mathbf{Z}_{s}^{t}=u\left(\mathbf{Z}_s^{S T^{t}}, \mathbf{Z}_s^{M S^{t}}\right)Zst​=u(ZsSTt​,ZsMSt​)。

      论文给出了两种形式的注意力融合方式,一种基于简单的线性投影,另一种基于MLP-Mixer模型。

      实验

      在四个标准视频分类基准上评估DVT:Kinetics-400(K400)、Something-Something-V2(SSv2)、EPIC-KITCHENS-100(EK100)和Diving-48(D48)

      消融实验

      Choice of motion cues

      2022-04-10-21-16-12.png

      Attention and fusion blocks

      2022-04-10-21-16-19.png

      Number of patches in the deformable attention

      Number of sub-clips in D-ST-A

      2022-04-10-21-11-08.png

      Per-Class Comparison

      2022-04-10-21-11-42.png

      Comparison to the state-of-the-art

      2022-04-10-21-17-42.png

      posted in CV领域
      189****6672
      189****6672
    • CVPR 2022 | Restormer: 用于高分辨率图像重建的高效Transformer

      CVPR 2022 | Restormer: 用于高分辨率图像重建的高效Transformer

      论文标题:Restormer: Efficient Transformer for High-Resolution Image Restoration

      论文地址:https://arxiv.org/pdf/2111.09881.pdf

      论文代码: https://github.com/swz30/Restormer

      image-20220505093432910

      摘要

      1. 引入主题: 由于卷积神经网络(CNNs)能够从大规模数据中学习到图像的generalizable特征,所以被广泛应用于图像重建和相关任务。最近,另一类神经结构,Transformer,在自然语言和高水平的视觉任务已经显示出显著性能增益。
      2. 现存问题: 虽然 Transformer 模型弥补了 CNNs 的不足(即感受域有限和inadaptability to input content) ,但其计算复杂度随着空间分辨率的增加而二次增长,因此不适用于大多数涉及高分辨率图像的图像重建任务。
      3. 解决方法: 论文提出了一个有效的Transformer模型,Restoration Transformer,Restormer,通过对基础模块(多头前馈网络)的几个关键设计,使它能够捕捉远距离像素间的相互作用,同时仍然适用于大图像。
      4. 实验结果: 在多个图像重建任务上实现最先进的结果,包括图像去噪、单图像运动去模糊、散焦去模糊(单图像和双像素数据)和图像去噪(高斯灰度/颜色去噪和真实图像去噪)

      image-20220505141756596

      算法

      image-20220505141728017

      Overall Pipline

      1. 输入图像大小为I∈RH×W×3I \in R^{H×W×3}I∈RH×W×3,首先利用一个卷积操作获得特征嵌入F0∈RH×W×CF_0 \in R^{H×W×C}F0​∈RH×W×C
      2. F0F_0F0​通过一个对称的4层编码-解码结构,得到高维特征Fd∈RH×W×2CF_d \in R^{H×W×2C}Fd​∈RH×W×2C,每一层编码/解码都包括多个Transformer 模块,从上到下,每一层中的Transformer模块数量逐渐递增,分辨率逐渐递减。
      3. 编码-解码器之间使用跳跃连接来传递低维特征信息。
      4. FdF_dFd​进一步经过Refinement模块来提取细节特征
      5. 最后经过一个卷积层,并与输入图像进行叠加,得到最后的输出图像

      如上图所示,每个Transformer模块中包括MDTA和GDFN模块,接下来进行详细介绍。

      MDTA(Multi-Dconv Head Transposed Attention)

      image-20220505105834085

      一般Transformer模块中的多头自注意力机制具有较大的计算量,在应用到高分辨率图像上是不合适的,所以该论文提出了MDTA模块。

      有两个与众不同的方法:

      1. MDTA是计算通道上的自注意力而不是空间上,通过计算通道上的注意力来隐式编码全局上下文信息。
      2. 在计算自注意力map之间,使用depth-wise卷积操作生成Q、K、V,这样可以强调局部信息。

      公式如下:

      image-20220505141655069

      GDFN( Gated-Dconv Feed-Forward Network)

      image-20220505141625376

      一般的Transformer模块中使用FN进行逐像素特征操作,扩展和减小通道数。

      该论文与之不同,使用了(1)门控机制和(2)depthwise卷积

      如上图所示,下分支是一个门控单元,用于获取每个像素点的激活状态,使用1×1卷积层来扩展通道数,再使用3×3depthwise卷积层和GELU生成gate map。

      并与上分支进行点乘,公式如下:

      image-20220505141558294

      各层的GDFN通过控制信息流来允许每个层次关注与其他层次互补的细微细节。也就是说,与MDTA相比,GDFN提供了一个独特的角色(专注于丰富上下文信息)。

      Progressive Learning

      另外,论文还提出了一种渐进式训练方法。

      基于CNN的重建模型通常在固定大小的图像patch上进行训练。然而,在小裁剪patch上训练Transformer模型可能不会编码全局图像统计信息,从而在测试时在全分辨率图像上提供次优性能。

      为此,论文采用渐进式学习的方式,在早期阶段,网络在较小的图像块上进行训练,在后期的训练阶段,网络在逐渐增大的图像块上进行训练。

      通过渐进学习在混合大小的patch上训练的模型在测试时表现出更好的性能。

      由于在大patch上进行训练需要花费更长的时间,所以会随着patch大小的增加而减少batch大小,以保持相同的训练时间。

      实验

      Image Deraining Results

      image-20220505141528526

      Single-image Motion Deblurring Results

      image-20220505141502829

      image-20220505141439022

      Defocus Deblurring Results

      image-20220505141403206

      Image Denoising Results

      image-20220505141334799

      Ablation Studies

      image-20220505141252666

      posted in CV领域
      189****6672
      189****6672
    • Facebook新作NAT:具有局部归纳偏置的Transformer

      Facebook新作NAT:具有局部归纳偏置的Transformer

      NAT将每个query的感受野设定为其一个邻域区域,通过叠加操作和分层结构从而实现感受野逐步增大,并具有局部归纳偏置性能。

      image-20220508151546862

      论文标题:Neighborhood Attention Transformer

      论文地址:https://arxiv.org/pdf/2204.07143.pdf

      代码地址:https://github.com/SHI-Labs/Neighborhood-Attention-Transformer

      image-20220508135959665

      摘要

      1. 引出问题: ViT的计算量是具有二次复杂度的,过高的复杂度和计算量大大影响下游视觉任务。另外,ViT中的自注意力操作是一个全局操作,其归纳偏置能力较差,必须通过大量数据来弥补。
      2. 论文提出了Neighborhood Attention(NA),NA是一个局部化的自注意力机制,将query tokens限制一个邻近的区域内,很好的控制了平移不变性和平移等方差。
      3. NAT的性能不仅优于Swin Transformer,还优于ConvNeXt。NAT-Tiny模型在ImageNet上仅用4.3 GFLOPs和28M参数就能达到83.2%的top-1精度,在MS-COCO上达到51.4%的Box mAP,在ADE20k上达到48.4%的多尺度mIoU。

      image-20220508143458673

      算法

      image-20220508143726621

      整体模型结构如上图所示。

      1. 对输入图像进行两次重叠卷积操作来生成分辨率大小1/4的输入嵌入。
      2. 通过四个层次的不同分辨率level自注意力操作,每层最后进行下采样操作(3×3卷积),减小分辨率,增加通道数。

      由上可知,论文中最突出的创新点是每层中的NAT模块。接下来进行介绍。

      NAT block

      image-20220508145039105

      如图4右图所示,NAT模块与多头自注意力模块很相似,主要区别是使用了NA模块来代替了全局自注意力操作。

      NA模块主要受卷积操作中的局部性启发。NA模块中,每个query只查询其邻域区域的key和value(如上图所示),这与卷积操作很相似。当邻域区域为整张特征图时,NA模块就等同于全局自注意力模块了。公式表示如下:

      image-20220508145446403

      其中,ρ(i,j)\rho(i, j)ρ(i,j)表示点(i,j)(i, j)(i,j)的一个邻域,可以通过Raster-Scan Sliding Window操作产生,这与卷积操作类似;Bi,jB_{i, j}Bi,j​表示相对位置偏差。

      NA模块的计算复杂度相对于图像分辨率是呈线性关系。

      image-20220508151111804

      另外,与卷积操作有所不同的是,但滑动窗口操作到图像边缘时,NA模块没有使用padding操作,具体操作如下图所示:

      image-20220508150553610

      这种操作能够使邻域大小扩展到全局时,与全局自注意力操作保持一致。

      实验

      分类实验

      image-20220508151308314

      目标检测和实例分割

      image-20220508151403482

      语义分割

      image-20220508151413588

      消融实验

      image-20220508151453484

      可视化分析

      image-20220508151507097

      posted in CV领域
      189****6672
      189****6672
    • vscode远程调试

      vscode远程调试

      vscode远程调试相对pycharm要麻烦些,但vscode胜在轻量,而且pycharm远程连接需要专业版支持。

      恒源云官网文档对于vscode远程调试内容较少,本文进行补充

      开始部分与官方文档一致(复制了官方的图),具体步骤如下:

      1. 安装Remote-SSH扩展

      首先需要在vscode软件上安装Remote-SSH扩展

      替代文字

      2. 添加远程主机

      安装完成后,vscode软件左侧边栏就会新出现一个图标,这就是远程资源管理器,然后点击加号来添加远程主机

      替代文字

      这时右侧出现一个输入框,复制已经开启的实例登录命令输入到框中,并回车

      替代文字

      替代文字

      然后出现如下的信息,直接选择第一项(windows和linux都选第一项),然后回车

      替代文字

      3. 连接远程主机

      这时就已经添加好了远程主机,点击如下按钮进行远程主机连接(可以右击选择 是否打开新窗口)

      替代文字

      这时会出现新的输入框,输入实例中的密码(在登录指令下方),然后回车

      替代文字
      替代文字

      这时应该就连接成功了

      替代文字

      4. 选择调试代码

      点击上图中的“打开文件夹”按钮,出现如下窗口,你的文件一般在hy-nas或者hy-tmp中,再点击选项中最上面的两个点‘…’

      2022-04-02-15-17-41.png

      可逐步打开你的文件,例如我的文件就在hy-nas中

      2022-04-02-15-18-02.png

      2022-04-02-15-18-58.png

      可能还会要求输入密码

      5. 配置调试

      进入你的代码文件中,点击左侧栏中的调试按钮,再点击“创建launch.json文件”

      2022-04-02-15-20-18.png

      会跳出如下窗口,进行调试配置,可能第一次没有下图中的python选项,但会有“安装python扩展”,点击安装,通过vscode安装python扩展,如果有python选项,可直接点击python选项

      2022-04-02-15-25-10.png

      2022-04-02-16-31-43.png

      会得到一个launch.json文件,不用管它,直接关掉

      2022-04-02-16-28-16.png

      6. 进行调试

      最后就可以在代码中添加断点,再点击下图中绿色的三角形进行调试啦

      2022-04-02-15-27-13.png

      posted in 技术分享📚有奖励
      189****6672
      189****6672
    • deformable_conv变形卷积底层C++源码解析

      deformable_conv变形卷积底层C++源码解析

      注意:本文源码来源于openlab中的mmcv

      变形卷积源码主要有三个文件:

      • deform_conv.cpp: 位于/mmcv/ops/csrc/pytorch/deform_conv.cpp
      • deform_conv_cuda.cu:位于/mmcv/ops/csrc/pytorch/deform_conv_cuda.cu
      • deform_conv_cuda_kernel.cuh:位于/mmcv/ops/csrc/deform_conv_cuda_kernel.cuh

      前向传播

      首先查看deform_conv.cpp中的函数deform_conv_forward()

      函数输入主要有特征图input,卷积权重weight, 偏置offset,输出特征图output等

      函数调用了deform_conv_forward_cuda()函数

      void deform_conv_forward(Tensor input, Tensor weight, Tensor offset,
                               Tensor output, Tensor columns, Tensor ones, int kW,
                               int kH, int dW, int dH, int padW, int padH,
                               int dilationW, int dilationH, int group,
                               int deformable_group, int im2col_step) {
        if (input.device().is_cuda()) {
      #ifdef MMCV_WITH_CUDA
          CHECK_CUDA_INPUT(input);
          CHECK_CUDA_INPUT(offset);
          CHECK_CUDA_INPUT(weight);
          CHECK_CUDA_INPUT(output);
          CHECK_CUDA_INPUT(columns);
          CHECK_CUDA_INPUT(ones);
      
          deform_conv_forward_cuda(input, weight, offset, output, columns, ones, kW,
                                   kH, dW, dH, padW, padH, dilationW, dilationH,
                                   group, deformable_group, im2col_step);
      #else
          AT_ERROR("DeformConv is not compiled with GPU support");
      #endif
        } else {
          AT_ERROR("DeformConv is not implemented on CPU");
        }
      }
      

      进一步调用了函数DeformConvForwardCUDAKernelLauncher(),位于文件deform_conv_cuda.cu中

      void deform_conv_forward_cuda(Tensor input, Tensor weight, Tensor offset,
                                    Tensor output, Tensor columns, Tensor ones,
                                    int kW, int kH, int dW, int dH, int padW,
                                    int padH, int dilationW, int dilationH, int group,
                                    int deformable_group, int im2col_step) {
        DeformConvForwardCUDAKernelLauncher(
            input, weight, offset, output, columns, ones, kW, kH, dW, dH, padW, padH,
            dilationW, dilationH, group, deformable_group, im2col_step);
      }
      

      这是变形卷积核心函数,常规卷积是特征图上每个点与邻域点进行卷积操作,而变形卷积多了一个offset偏置,重新获取新的邻域点特征,再进行卷积,而不是邻接的点,所以变形卷积主要分为两个步骤:

      1)根据offset收集新的邻域特征;

      2)再进行卷积。

      其中第一步骤收集邻域特征相对比较麻烦,主要思路是根据offset找到新的邻域点,再拼接到中心点特征上,使得通道数由C变成C*kh*kw,是由下文代码中的deformable_im2col()函数实现。

      第二步就很简单了,用一个维度为(C2, C1, 1, 1)卷积就可以实现。

      void DeformConvForwardCUDAKernelLauncher(Tensor input, Tensor weight,  //输入特征图 input:(B, C1, H, W),卷积权重 weight:(C2, C1/group, kh, kw)
                                               Tensor offset, Tensor output,  // 坐标偏置offset:(B, deform_group*2*kh*kw, h, w), 输出特征output:(B, C2, h, w)
                                               Tensor columns, Tensor ones, int kW, // kW,Kh为卷积核大小
                                               int kH, int dW, int dH, int padW, // dW,dH为卷积步长stride
                                               int padH, int dilationW, int dilationH, // 
                                               int group, int deformable_group, //  变形卷积中一般每个通道公用一个坐标偏置,也可以几个通道维度公用一个坐标偏置,那么每个通道就会分为deformable_group个组数
                                               int im2col_step) {  // step
        // todo: resize columns to include im2col: done
        // todo: add im2col_step as input
        // todo: add new output buffer and transpose it to output (or directly
        // transpose output) todo: possibly change data indexing because of
        // parallel_imgs
      
        deform_conv_shape_check(input, offset, NULL, weight, kH, kW, dH, dW, padH,
                                padW, dilationH, dilationW, group, deformable_group);
        at::DeviceGuard guard(input.device());
      
        int batch = 1;
        if (input.ndimension() == 3) {
          // Force batch
          batch = 0;
          input.unsqueeze_(0);
          offset.unsqueeze_(0);
        }
      
        // todo: assert batchsize dividable by im2col_step
      
        long batchSize = input.size(0); // B
        long nInputPlane = input.size(1); // 输入通道数 C1
        long inputHeight = input.size(2); //输入高 H
        long inputWidth = input.size(3); // 输入宽 W
      
        long nOutputPlane = weight.size(0); // 输出通道数 C2
      
        long outputWidth =
            (inputWidth + 2 * padW - (dilationW * (kW - 1) + 1)) / dW + 1; // 输出宽 w
        long outputHeight =
            (inputHeight + 2 * padH - (dilationH * (kH - 1) + 1)) / dH + 1; // 输入 h
      
        TORCH_CHECK((offset.size(0) == batchSize), "invalid batch size of offset");
      
        output = output.view({batchSize / im2col_step, im2col_step, nOutputPlane,
                              outputHeight, outputWidth}); //  (B, C2, h, w)->(B/step, step, C2, h, w)
        columns = at::zeros(
            {nInputPlane * kW * kH, im2col_step * outputHeight * outputWidth},
            input.options());  // (C1*kw*kh, step*h*w),其中 C1*kw*kh可以看作将输入特征图每个点的邻域特征汇聚在一起,邻域个数是kw*kh,每个邻域点的通道数都是C1,所以总的就是C1*kw*kh
      
        if (ones.ndimension() != 2 ||
            ones.size(0) * ones.size(1) < outputHeight * outputWidth) {
          ones = at::ones({outputHeight, outputWidth}, input.options()); // (h, w)
        }
      
        input = input.view({batchSize / im2col_step, im2col_step, nInputPlane,
                            inputHeight, inputWidth}); // (B, C1, H, W)->(B/step, step, C1, H, W)
        offset = offset.view({batchSize / im2col_step, im2col_step,
                         deformable_group * 2 * kH * kW, outputHeight, outputWidth});  // (B, deform_group*2*kh*kw, h, w)->(B/step, step, deform_group*2*kh*kw, h, w)
      
        Tensor output_buffer = at::zeros({batchSize / im2col_step, nOutputPlane,
                                          im2col_step * outputHeight, outputWidth},
                                         output.options()); // (B/step, C2, step*h, w),元素全为0
      
        output_buffer = output_buffer.view(
            {output_buffer.size(0), group, output_buffer.size(1) / group,
             output_buffer.size(2), output_buffer.size(3)}); // (B/step, C2, step*h, w)->(B/step, group, C2/group, step*h, w)
      
      // 分成B/step个分别进行运算
        for (int elt = 0; elt < batchSize / im2col_step; elt++) {
            // 该函数的详细分析见后文,是为了获取columns值, columns可以理解为输入特征图上每个特征点根据offset汇总邻域点特征到自己维度上
          deformable_im2col(input[elt], offset[elt], nInputPlane, inputHeight,  //input[elt]:(step, C1, H, W), offset[elt]:(step, deform_group*2*kw*kh, h, w)
                            inputWidth, kH, kW, padH, padW, dH, dW, dilationH,  
                            dilationW, im2col_step, deformable_group, columns); //  columns:(C1*kw*kh, step*h*w)
      
          columns = columns.view({group, columns.size(0) / group, columns.size(1)});  // (C1*kw*kh, step*h*w)->(group, C1*kh*kw/group, step*h*w)
          weight = weight.view({group, weight.size(0) / group, weight.size(1), 
                                weight.size(2), weight.size(3)});  //(C2, C1/group, kh, kw)-> (group, C2/group, C1/group, kh, kw)
      
         // 分成group个分别进行运算
          for (int g = 0; g < group; g++) {
              //columns是汇总的特征,再与weight进行卷积来获取输出特征output_buffer
              //addmm_()是对内部矩阵乘积结果进行相加
              // flatten(1)对1维和之后维度进行展平
            output_buffer[elt][g] = output_buffer[elt][g]
                                        .flatten(1) // (C2/group, step*h, w)->(C2/group, step*h*w)
                                        .addmm_(weight[g].flatten(1), columns[g])  // (C2/group, C1/group*kh*kw) mm (C1/group*kh*kw, step*h*w)->(C2/group, step*h*w)
                                        .view_as(output_buffer[elt][g]);  // (C2/group, step*h*w)->(C2/group, step*h, w)
          }
          columns =
              columns.view({columns.size(0) * columns.size(1), columns.size(2)}); // (group, C1*kh*kw/group, step*h*w)->(C1*kw*kh, step*h*w) 
        }
      
      
        output_buffer = output_buffer.view(
            {output_buffer.size(0), output_buffer.size(1) * output_buffer.size(2),
             output_buffer.size(3), output_buffer.size(4)});  // (B/step, group, C2/group, step*h, w)->(B/step, C2, step*h, w)
      
        output_buffer = output_buffer.view({batchSize / im2col_step, nOutputPlane,
                                            im2col_step, outputHeight, outputWidth});  //(B/step, C2, step*h, w)-> (B/step, C2, step, h, w)
        output_buffer.transpose_(1, 2);  //(B/step, C2, step, h, w)-> (B/step, step, C2, h, w)
        output.copy_(output_buffer); // 复制output_buffer到output
        output = output.view({batchSize, nOutputPlane, outputHeight, outputWidth});  // (B/step, step, C2, h, w)->(B, C2, h, w)
      
        input = input.view({batchSize, nInputPlane, inputHeight, inputWidth}); // (B/step, step, C1, H, W)->(B,  C1, H, W)
        offset = offset.view(
            {batchSize, deformable_group * 2 * kH * kW, outputHeight, outputWidth});  // (B/step, step, deform_group*2*kh*kw, h, w)->(B, deform_group*2*kh*kw, h, w)
      
        if (batch == 0) {
          output = output.view({nOutputPlane, outputHeight, outputWidth});
          input = input.view({nInputPlane, inputHeight, inputWidth});
          offset = offset.view({offset.size(1), offset.size(2), offset.size(3)});
        }
      }
      

      上文代码中的函数deformable_im2col(),变形卷积前向传播重点代码,实现邻域特征的汇总

      void deformable_im2col(Tensor data_im, Tensor data_offset, const int channels,//输入特征 data_im:(step, C1, H, W), 偏置data_offset:(step, deform_group*2*kw*kh, h, w), channels: C1
                             const int height, const int width, const int ksize_h, // height=H,  width: W,
                             const int ksize_w, const int pad_h, const int pad_w, 
                             const int stride_h, const int stride_w, 
                             const int dilation_h, const int dilation_w,
                             const int parallel_imgs, const int deformable_group, // 通道数parallel_imgs=step
                             Tensor data_col) { //  data_col:(C1*kw*kh, step*h*w)
        // num_axes should be smaller than block size
        // todo: check parallel_imgs is correctly passed in
          //获取columns的高和宽
        int height_col =
            (height + 2 * pad_h - (dilation_h * (ksize_h - 1) + 1)) / stride_h + 1; // h
        int width_col =
            (width + 2 * pad_w - (dilation_w * (ksize_w - 1) + 1)) / stride_w + 1; // w
        int num_kernels = channels * height_col * width_col * parallel_imgs; // C1*h*w*step
        int channel_per_deformable_group = channels / deformable_group; // C1/deform_group, 是指每个group占据多少通道数
      
        AT_DISPATCH_FLOATING_TYPES_AND_HALF(
            data_im.scalar_type(), "deformable_im2col_gpu", ([&] {               //[&]匿名函数:用到的任何外部变量都隐式按引用捕获
              const scalar_t *data_im_ = data_im.data_ptr<scalar_t>();          // 获取指针,地址位置
              const scalar_t *data_offset_ = data_offset.data_ptr<scalar_t>();
              scalar_t *data_col_ = data_col.data_ptr<scalar_t>();
      
                // 用在cuda上的内核函数,后文分析
              deformable_im2col_gpu_kernel<<<GET_BLOCKS(num_kernels),
                                             THREADS_PER_BLOCK, 0,
                                             at::cuda::getCurrentCUDAStream()>>>(
                  num_kernels, data_im_, data_offset_, height, width, ksize_h,
                  ksize_w, pad_h, pad_w, stride_h, stride_w, dilation_h, dilation_w,
                  channel_per_deformable_group, parallel_imgs, channels,
                  deformable_group, height_col, width_col, data_col_);
            }));
        AT_CUDA_CHECK(cudaGetLastError());
      }
      

      函数deformable_im2col_gpu_kernel()在deform_conv_cuda_kernel.cuh文件中

      template <typename T>
      __global__ void deformable_im2col_gpu_kernel(
          const int n, const T *data_im, const T *data_offset, const int height,  // n=C1*h*w*step,;data_im:(step, C1, H, W)的起始地址,为输入特征,;data_offset:(step, deform_group*2*kw*kh, h, w)的起始地址,为坐标偏置; height=H
          const int width, const int kernel_h, const int kernel_w, const int pad_h, //输入特征宽 width=W 
          const int pad_w, const int stride_h, const int stride_w,
          const int dilation_h, const int dilation_w,
          const int channel_per_deformable_group, const int batch_size, //  batch_size=step
          const int num_channels, const int deformable_group, const int height_col, //num_channels=C1, 输出特征的高height_col=h
          const int width_col, T *data_col) { //width_col=w,  data_col:(C1*kw*kh, step*h*w)的起始地址,为columns
        CUDA_1D_KERNEL_LOOP(index, n) {  // index从0到n进行遍历
          // index index of output matrix
            // index为0到C1*step*h*w遍历,可以理解为columns上特征点的索引,但比columns维度少了kh*kw,所以一个index对应一个kh*kw
          const int w_col = index % width_col;  // 特征点的w坐标
          const int h_col = (index / width_col) % height_col;   // 特征点的h坐标
          const int b_col = (index / width_col / height_col) % batch_size;  // 特征点所在的batch数
          const int c_im = (index / width_col / height_col) / batch_size; // 特征点对应输入图imput上的通道数,输出特征columns和输入特征data_im上的特征点具有对应关系
          const int c_col = c_im * kernel_h * kernel_w;  // 特征点对应输出特征图columns的通道数,因为columns的通道为C1*kw*kh,而data_im的通道为C1
      
          // compute deformable group index
          const int deformable_group_index = c_im / channel_per_deformable_group;
      
          const int h_in = h_col * stride_h - pad_h;    // 输入特征图上的特征点坐标映射在输入特征图上的高度值h
          const int w_in = w_col * stride_w - pad_w; // 输入特征图上的特征点坐标映射在输入特征图上的宽度值w
            // 获得该特征点在columns上的地址
          T *data_col_ptr =  
              data_col +
              ((c_col * batch_size + b_col) * height_col + h_col) * width_col + w_col;
            //  获得该特征点在data_im上的对应通道的特征面上的起始地址,因为只考虑了b_col和c_im,还没有包括特征点具体的高和宽
          const T *data_im_ptr = 
              data_im + (b_col * num_channels + c_im) * height * width;
            // 只考虑了b_col和deformable_group_index,还没有包括特征点对应的坐标和偏置
          const T *data_offset_ptr =
              data_offset + (b_col * deformable_group + deformable_group_index) * 2 *
                                kernel_h * kernel_w * height_col * width_col;
      // 因为一个index对应一个kh*kw,所以要进一步遍历kh*kw
          for (int i = 0; i < kernel_h; ++i) {
            for (int j = 0; j < kernel_w; ++j) {
              const int data_offset_h_ptr =
                  ((2 * (i * kernel_w + j)) * height_col + h_col) * width_col + w_col;  // 得到完整的偏置高度地址
              const int data_offset_w_ptr =
                  ((2 * (i * kernel_w + j) + 1) * height_col + h_col) * width_col + w_col; // 得到完整的偏置宽度地址
              const T offset_h = data_offset_ptr[data_offset_h_ptr]; // 偏置高度
              const T offset_w = data_offset_ptr[data_offset_w_ptr]; // 偏置宽度
              T val = static_cast<T>(0);
              const T h_im = h_in + i * dilation_h + offset_h;    //对应的输入特征图上该点邻域点的偏置高度值h
              const T w_im = w_in + j * dilation_w + offset_w; //对应的输入特征图上该点邻域点的偏置宽度值w
              if (h_im > -1 && w_im > -1 && h_im < height && w_im < width)
                 // 因为h_im和w_im为小数, 所以需要插值计算,后文分析
                val = deformable_im2col_bilinear(data_im_ptr, width, height, width,
                                                 h_im, w_im);
              *data_col_ptr = val;
              data_col_ptr += batch_size * height_col * width_col;  // 因为columns的维度为(C1*kw*kh, step*h*w),kw和kh在step*h*w前面,所以每个偏移点中间相隔step*h*w个点
            }
          }
        }
      }
      

      函数deformable_im2col_bilinear()根据偏置获取特征点,双线性插值,比较简单

      template <typename T>
      __device__ T deformable_im2col_bilinear(const T *input, const int data_width,  // input:输入图当前通道特征面的起始地址
                                              const int height, const int width, T h,
                                              T w) {
        if (h <= -1 || height <= h || w <= -1 || width <= w) {
          return 0;
        }
      
          // 上下取整
        int h_low = floor(h);
        int w_low = floor(w);
        int h_high = h_low + 1;
        int w_high = w_low + 1;
      
        T lh = h - h_low;
        T lw = w - w_low;
        T hh = 1 - lh, hw = 1 - lw;
      
        T v1 = 0;
        if (h_low >= 0 && w_low >= 0) v1 = input[h_low * data_width + w_low];
        T v2 = 0;
        if (h_low >= 0 && w_high <= width - 1)
          v2 = input[h_low * data_width + w_high];
        T v3 = 0;
        if (h_high <= height - 1 && w_low >= 0)
          v3 = input[h_high * data_width + w_low];
        T v4 = 0;
        if (h_high <= height - 1 && w_high <= width - 1)
          v4 = input[h_high * data_width + w_high];
      
        T w1 = hh * hw, w2 = hh * lw, w3 = lh * hw, w4 = lh * lw;
      
        T val = (w1 * v1 + w2 * v2 + w3 * v3 + w4 * v4);
        return val;
      }
      

      到此前向传播分析结束,下文分析梯度反传

      梯度反传

      需要对输入特征Input和偏置offset以及参数权重weight进行梯度反传计算

      输入特征Input和偏置offset的梯度计算

      梯度反传是由前向传播计算的gradOutput进行反向计算梯度

      查看deform_conv.cpp中的函数deform_conv_backward_input()

      该函数调用了deform_conv_forward_cuda()函数

      void deform_conv_backward_input(Tensor input,  // (B, C1, H, W)
                                      Tensor offset, // 
                                      Tensor gradOutput,
                                      Tensor gradInput, Tensor gradOffset,
                                      Tensor weight, Tensor columns, int kW, int kH,
                                      int dW, int dH, int padW, int padH,
                                      int dilationW, int dilationH, int group,
                                      int deformable_group, int im2col_step) {
        if (input.device().is_cuda()) {
      #ifdef MMCV_WITH_CUDA
          CHECK_CUDA_INPUT(input);
          CHECK_CUDA_INPUT(offset);
          CHECK_CUDA_INPUT(gradOutput);
          CHECK_CUDA_INPUT(gradInput);
          CHECK_CUDA_INPUT(gradOffset);
          CHECK_CUDA_INPUT(weight);
          CHECK_CUDA_INPUT(columns);
      
          deform_conv_backward_input_cuda(input, offset, gradOutput, gradInput,
                                          gradOffset, weight, columns, kW, kH, dW, dH,
                                          padW, padH, dilationW, dilationH, group,
                                          deformable_group, im2col_step);
      #else
          AT_ERROR("DeformConv is not compiled with GPU support");
      #endif
        } else {
          AT_ERROR("DeformConv is not implemented on CPU");
        }
      }
      

      函数deform_conv_backward_input_cuda()

      进一步调用了函数DeformConvBackwardInputCUDAKernelLauncher()

      void deform_conv_backward_input_cuda(Tensor input, Tensor offset,
                                           Tensor gradOutput, Tensor gradInput,
                                           Tensor gradOffset, Tensor weight,
                                           Tensor columns, int kW, int kH, int dW,
                                           int dH, int padW, int padH, int dilationW,
                                           int dilationH, int group,
                                           int deformable_group, int im2col_step) {
        DeformConvBackwardInputCUDAKernelLauncher(
            input, offset, gradOutput, gradInput, gradOffset, weight, columns, kW, kH,
            dW, dH, padW, padH, dilationW, dilationH, group, deformable_group,
            im2col_step);
      }
      

      函数DeformConvBackwardInputCUDAKernelLauncher()位于文件deform_conv_cuda.cu中,这是核心代码

      void DeformConvBackwardInputCUDAKernelLauncher(
          Tensor input,  //  (B, C1, H, W)
          Tensor offset, // (B, deform_group*2*kw*kh, h, w)
          Tensor gradOutput, // (B, C2, h, w)
          Tensor gradInput,  // (B, C1, H, W)
          Tensor gradOffset, // (B, deform_group*2*kw*kh, h, w)
          Tensor weight,  // (C2, C1/group, kh, kw)
          Tensor columns,
          int kW, int kH, int dW, 
          int dH, int padW, int padH, int dilationW, int dilationH, int group,
          int deformable_group, int im2col_step) { 
        deform_conv_shape_check(input, offset, &gradOutput, weight, kH, kW, dH, dW,
                                padH, padW, dilationH, dilationW, group,
                                deformable_group);
        at::DeviceGuard guard(input.device());
      
        int batch = 1;
      
        if (input.ndimension() == 3) {
          // Force batch
          batch = 0;
          input = input.view({1, input.size(0), input.size(1), input.size(2)});
          offset = offset.view({1, offset.size(0), offset.size(1), offset.size(2)});
          gradOutput = gradOutput.view(
              {1, gradOutput.size(0), gradOutput.size(1), gradOutput.size(2)});
        }
      
        long batchSize = input.size(0);  // B
        long nInputPlane = input.size(1); // C!
        long inputHeight = input.size(2);// H
        long inputWidth = input.size(3);// W
      
        long nOutputPlane = weight.size(0); //C2
      
        long outputWidth =
            (inputWidth + 2 * padW - (dilationW * (kW - 1) + 1)) / dW + 1;  //h
        long outputHeight =
            (inputHeight + 2 * padH - (dilationH * (kH - 1) + 1)) / dH + 1; // w
      
        TORCH_CHECK((offset.size(0) == batchSize), 3, "invalid batch size of offset");
        gradInput = gradInput.view({batchSize, nInputPlane, inputHeight, inputWidth});  // (B, C1, H, W)
        columns = at::zeros(
            {nInputPlane * kW * kH, im2col_step * outputHeight * outputWidth},
            input.options());  // (C1*kw*kh, step*h*w),全为0
      
        // change order of grad output
        gradOutput = gradOutput.view({batchSize / im2col_step, im2col_step,
                                      nOutputPlane, outputHeight, outputWidth}); //(B, C2, h, w)-> (B/step, step, C2, h, w)
        gradOutput.transpose_(1, 2);  // (B/step, step, C2, h, w)->(B/step, C2, step, h, w)
      
        gradInput = gradInput.view({batchSize / im2col_step, im2col_step, nInputPlane,
                                    inputHeight, inputWidth});  // (B, C1, H, W)->(B/step, step, C1, H, W)
        input = input.view({batchSize / im2col_step, im2col_step, nInputPlane,
                            inputHeight, inputWidth});  // (B, C1, H, W)->(B/step, step, C1, H, W)
        gradOffset = gradOffset.view({batchSize / im2col_step, im2col_step,
                                      deformable_group * 2 * kH * kW, outputHeight,
                                      outputWidth});  // (B, deform_group*2*kw*kh, h, w)->(B/step, step, deform_group*2*kh*kw, h, w)
        offset =
            offset.view({batchSize / im2col_step, im2col_step,
                         deformable_group * 2 * kH * kW, outputHeight, outputWidth});  // (B, deform_group*2*kw*kh, h, w)->(B/step, step, deform_group*2*kh*kw, h, w)
      
        for (int elt = 0; elt < batchSize / im2col_step; elt++) {
          // divide into groups
          columns = columns.view({group, columns.size(0) / group, columns.size(1)}); // (C1*kw*kh, step*h*w)->(group, C1*kw*kh/group, step*h*w)
          weight = weight.view({group, weight.size(0) / group, weight.size(1),
                                weight.size(2), weight.size(3)});  // (C2, C1/group, kh, kw)->(group, C2/group, C1/group, kh kw)
          gradOutput = gradOutput.view(
              {gradOutput.size(0), group, gradOutput.size(1) / group,
               gradOutput.size(2), gradOutput.size(3), gradOutput.size(4)});  //(B/step, C2, step, h, w)-> (B/step, group, C2/group, step, h, w)
      
          for (int g = 0; g < group; g++) {
             // 根据gradOutput获取columns的梯度, 矩阵乘积的梯度计算
            columns[g] = columns[g].
                                           addmm_(weight[g].flatten(1).transpose(0, 1),  //(C2/group, C1/group, kh kw)-> (  C2/group, C1/group*kh*kw)-> (C1/group*kh*kw, C2/group)
                                           gradOutput[elt][g].flatten(1), 0.0f, 1.0f);  // (C2/group, step, h, w)->(C2/group, step*h*w)
          }
      
          columns =
              columns.view({columns.size(0) * columns.size(1), columns.size(2)}); //(group, C1*kw*kh/group, step*h*w)-> (C1*kh*kw, step*h*w)
          gradOutput = gradOutput.view(
              {gradOutput.size(0), gradOutput.size(1) * gradOutput.size(2),
               gradOutput.size(3), gradOutput.size(4), gradOutput.size(5)}); // (B/step, group, C2/group, step, h, w)->(B/step, C2, step, h, w)
      
            // 计算偏置的梯度gradOffset,见后文分析
          deformable_col2im_coord(columns, input[elt], offset[elt], nInputPlane,  // columns:  (C1*kh*kw, step*h*w), input[elt]: (step, C1, H, W), offset[elt]: (step, deform_group*2*kw*kh, h, w), nInputPlane:C1
                                  inputHeight, inputWidth, kH, kW, padH, padW, dH, dW,
                                  dilationH, dilationW, im2col_step, deformable_group,
                                  gradOffset[elt]); // gradOffset[elt]: (step, deform_group*2*kw*kh, h, w)
      
            // 计算输入特征的梯度gradInput, 见后文分析
          deformable_col2im(columns, offset[elt], nInputPlane, inputHeight,   //  columns:  (C1*kh*kw, step*h*w),  offset[elt]: (step, deform_group*2*kw*kh, h, w), nInputPlane:C1
                            inputWidth, kH, kW, padH, padW, dH, dW, dilationH,
                            dilationW, im2col_step, deformable_group, gradInput[elt]);  // (step, C1, H, W)
        }
      
        gradOutput.transpose_(1, 2);
        gradOutput =
            gradOutput.view({batchSize, nOutputPlane, outputHeight, outputWidth});
      
        gradInput = gradInput.view({batchSize, nInputPlane, inputHeight, inputWidth});
        input = input.view({batchSize, nInputPlane, inputHeight, inputWidth});
        gradOffset = gradOffset.view(
            {batchSize, deformable_group * 2 * kH * kW, outputHeight, outputWidth});
        offset = offset.view(
            {batchSize, deformable_group * 2 * kH * kW, outputHeight, outputWidth});
      
        if (batch == 0) {
          gradOutput = gradOutput.view({nOutputPlane, outputHeight, outputWidth});
          input = input.view({nInputPlane, inputHeight, inputWidth});
          gradInput = gradInput.view({nInputPlane, inputHeight, inputWidth});
          offset = offset.view({offset.size(1), offset.size(2), offset.size(3)});
          gradOffset =
              gradOffset.view({offset.size(1), offset.size(2), offset.size(3)});
        }
      }
      

      函数 deformable_col2im_coord(), 计算偏置的梯度gradOffset, 函数调用了 deformable_col2im_coord_gpu_kernel()内核函数

      void deformable_col2im_coord(
          Tensor data_col, Tensor data_im, Tensor data_offset, const int channels, // data_col:  (C1*kh*kw, step*h*w), data_im: (step, C1, H, W), data_offset: (step, deform_group*2*kw*kh, h, w), channels:C1
          const int height, const int width, const int ksize_h, const int ksize_w,  // height=H
          const int pad_h, const int pad_w, const int stride_h, const int stride_w,
          const int dilation_h, const int dilation_w, const int parallel_imgs, // parallel_imgs: step
          const int deformable_group, Tensor grad_offset) {  // grad_offset: (step, deform_group*2*kw*kh, h, w)
        int height_col =
            (height + 2 * pad_h - (dilation_h * (ksize_h - 1) + 1)) / stride_h + 1;  // h
        int width_col =
            (width + 2 * pad_w - (dilation_w * (ksize_w - 1) + 1)) / stride_w + 1; //w
        int num_kernels = height_col * width_col * 2 * ksize_h * ksize_w *
                          deformable_group * parallel_imgs;  // h*w*2*kh*kw*deform_group*step
        int channel_per_deformable_group =
            channels * ksize_h * ksize_w / deformable_group;  // C1*kh*kw/deform_group
      
        AT_DISPATCH_FLOATING_TYPES_AND_HALF(
            data_col.scalar_type(), "deformable_col2im_coord_gpu", ([&] {
              const scalar_t *data_col_ = data_col.data_ptr<scalar_t>();
              const scalar_t *data_im_ = data_im.data_ptr<scalar_t>();
              const scalar_t *data_offset_ = data_offset.data_ptr<scalar_t>();
              scalar_t *grad_offset_ = grad_offset.data_ptr<scalar_t>();
      
              deformable_col2im_coord_gpu_kernel<<<
                  GET_BLOCKS(num_kernels), THREADS_PER_BLOCK, 0,
                  at::cuda::getCurrentCUDAStream()>>>(
                  num_kernels, data_col_, data_im_, data_offset_, channels, height,
                  width, ksize_h, ksize_w, pad_h, pad_w, stride_h, stride_w,
                  dilation_h, dilation_w, channel_per_deformable_group, parallel_imgs,
                  2 * ksize_h * ksize_w * deformable_group, deformable_group,
                  height_col, width_col, grad_offset_);
            }));
        AT_CUDA_CHECK(cudaGetLastError());
      }
      

      deformable_col2im_coord_gpu_kernel()内核函数

      template <typename T>
      __global__ void deformable_col2im_coord_gpu_kernel(
          const int n,  // h*w*2*kh*kw*deform_group*step
          const T *data_col,  // (C1*kh*kw, step*h*w)
          const T *data_im, // (step, C1, H, W)
          const T *data_offset,  //  (step, deform_group*2*kw*kh, h, w), 
          const int channels, const int height, const int width, const int kernel_h, //channels: C1
          const int kernel_w, const int pad_h, const int pad_w, const int stride_h,
          const int stride_w, const int dilation_h, const int dilation_w,
          const int channel_per_deformable_group, const int batch_size,  // batch_size=step
          const int offset_channels,  //  deform_group*2*kw*kh
          const int deformable_group, const int height_col,  
          const int width_col, T *grad_offset) {   //grad_offset: (step, deform_group*2*kw*kh, h, w)
          // index从0到h*w*2*kh*kw*deform_group*step进行遍历,也就是遍历整个offset
        CUDA_1D_KERNEL_LOOP(index, n) {
          T val = 0;
          int w = index % width_col;
          int h = (index / width_col) % height_col;
          int c = (index / width_col / height_col) % offset_channels;
          int b = (index / width_col / height_col) / offset_channels;
          // compute the start and end of the output
      
          const int deformable_group_index = c / (2 * kernel_h * kernel_w);  //  c/(2*kh*kw) 表示第几个group
          const int col_step = kernel_h * kernel_w;
          int cnt = 0;
          const T *data_col_ptr = data_col + deformable_group_index *
                                                 channel_per_deformable_group *
                                                 batch_size * width_col * height_col;
          const T *data_im_ptr =
              data_im + (b * deformable_group + deformable_group_index) *
                            channel_per_deformable_group / kernel_h / kernel_w *
                            height * width;
          const T *data_offset_ptr =
              data_offset + (b * deformable_group + deformable_group_index) * 2 *
                                kernel_h * kernel_w * height_col * width_col;
      
          const int offset_c = c - deformable_group_index * 2 * kernel_h * kernel_w;  // c
      
          for (int col_c = (offset_c / 2); col_c < channel_per_deformable_group;
               col_c += col_step) {
            const int col_pos =
                (((col_c * batch_size + b) * height_col) + h) * width_col + w;
            const int bp_dir = offset_c % 2;
      
            int j = (col_pos / width_col / height_col / batch_size) % kernel_w;
            int i =
                (col_pos / width_col / height_col / batch_size / kernel_w) % kernel_h;
            int w_out = col_pos % width_col;
            int h_out = (col_pos / width_col) % height_col;
            int w_in = w_out * stride_w - pad_w;
            int h_in = h_out * stride_h - pad_h;
            const int data_offset_h_ptr =
                (((2 * (i * kernel_w + j)) * height_col + h_out) * width_col + w_out);
            const int data_offset_w_ptr =
                (((2 * (i * kernel_w + j) + 1) * height_col + h_out) * width_col +
                 w_out);
            const T offset_h = data_offset_ptr[data_offset_h_ptr];
            const T offset_w = data_offset_ptr[data_offset_w_ptr];
            T inv_h = h_in + i * dilation_h + offset_h;
            T inv_w = w_in + j * dilation_w + offset_w;
            if (inv_h <= -1 || inv_w <= -1 || inv_h >= height || inv_w >= width)
              inv_h = inv_w = -2;
            const T weight = get_coordinate_weight(inv_h, inv_w, height, width,
                                                   data_im_ptr + cnt * height * width,
                                                   width, bp_dir);
            val += weight * data_col_ptr[col_pos];
            cnt += 1;
          }
      
          grad_offset[index] = val;
        }
      }
      
      posted in CV领域
      189****6672
      189****6672
    • 前沿分享

      转载:爱可可-爱生活(知乎)

      摘要:YOLOv7:基于可训练bag-of-freebies方法的实时目标检测新标杆、基于标准Transformer的强大图学习器、面向3D场景风格化的神经隐表示、基于局部流形平滑度的域外泛化预测、迁移学习中偏差何时迁移、基于CLIP的反事实图像处理研究、基于线性稳定性的SGD平坦最小趋向性定量表征、面向半监督LiDAR语义分割的LaserMix、基于Grounded语言代理的可扩展现实世界Web交互

      1、[CV] YOLOv7: Trainable bag-of-freebies sets new state-of-the-art for real-time object detectors

      C Wang, A Bochkovskiy, H M Liao
      [Academia Sinica]
      YOLOv7:基于可训练bag-of-freebies方法的实时目标检测新标杆。本文提出一种新的实时目标检测器的结构和相应的模型扩展方法,研究过程中,发现重参数化模块的替换问题和动态标签分配的分配问题,为解决该问题,提出了可训练bag-of-freebies方法来提高目标检测的精度。在此基础上,开发了YOLOv7系列目标检测系统。YOLOv7在5 FPS到160 FPS范围内的速度和精度超过了所有已知的目标检测器,在GPU V100上30 FPS或更高的所有已知实时目标检测器中具有最高的精度56.8% AP。YOLOv7-E6目标检测器(56 FPS V100, 55.9% AP)比基于Transformer的检测器SWINL Cascade-Mask R-CNN(9.2 FPS A100, 53. 9%)速度和精度都有所提高,比基于卷积的检测器ConvNeXt-XL Cascade-Mask R-CNN(8.6 FPS A100, 55.2% AP)速度和精度也有所提高。YOLOv7同时也超过了:YOLOR、YOLOX、Scaled-YOLOv4、YOLOv5、DETR、Deformable DETR、DINO-5scale-R50、ViT-Adapter-B和其他许多目标检测器,在速度和精度方面都有所体现。只在MS COCO数据集上从头开始训练YOLOv7,没有使用任何其他数据集或预训练权重。
      YOLOv7 surpasses all known object detectors in both speed and accuracy in the range from 5 FPS to 160 FPS and has the highest accuracy 56.8% AP among all known real-time object detectors with 30 FPS or higher on GPU V100. YOLOv7-E6 object detector (56 FPS V100, 55.9% AP) outperforms both transformer-based detector SWINL Cascade-Mask R-CNN (9.2 FPS A100, 53.9% AP) by 509% in speed and 2% in accuracy, and convolutionalbased detector ConvNeXt-XL Cascade-Mask R-CNN (8.6 FPS A100, 55.2% AP) by 551% in speed and 0.7% AP in accuracy, as well as YOLOv7 outperforms: YOLOR, YOLOX, Scaled-YOLOv4, YOLOv5, DETR, Deformable DETR, DINO-5scale-R50, ViT-Adapter-B and many other object detectors in speed and accuracy. Moreover, we train YOLOv7 only on MS COCO dataset from scratch without using any other datasets or pre-trained weights. Source code is released in https://github.com/WongKinYiu/yolov7.
      https://arxiv.org/abs/2207.02696

      img

      img

      img

      img

      img

      2、[LG] Pure Transformers are Powerful Graph Learners

      J Kim, T D Nguyen, S Min, S Cho, M Lee, H Lee, S Hong
      [KAIST & LG AI Research]
      基于标准Transformer的强大图学习器。本文表明,不论理论上还是实践上,标准Transformer无需对图进行特定修改,就可以在图学习中取得很好的结果。给定一个图,简单地把所有节点和边当作独立token,用token嵌入来增强它们,并输入到Transformer中。通过对token嵌入的适当选择,本文证明这种方法在理论上至少与由等变线性层组成的不变图网络(2-IGN)一样具有表达能力,而后者已经比所有消息传递图神经网络(GNN)更具表达能力。当在大规模图数据集(PCQM4Mv2)上训练时,所提出方法(Tokenized Graph Transformer,TokenGT)与GNN基线相比,取得了明显更好的结果,与具有复杂的图特定归纳偏差的Transformer变体相比,也取得了有竞争力的结果。
      We show that standard Transformers without graph-specific modifications can lead to promising results in graph learning both in theory and practice. Given a graph, we simply treat all nodes and edges as independent tokens, augment them with token embeddings, and feed them to a Transformer. With an appropriate choice of token embeddings, we prove that this approach is theoretically at least as expressive as an invariant graph network (2-IGN) composed of equivariant linear layers, which is already more expressive than all message-passing Graph Neural Networks (GNN). When trained on a large-scale graph dataset (PCQM4Mv2), our method coined Tokenized Graph Transformer (TokenGT) achieves significantly better results compared to GNN baselines and competitive results compared to Transformer variants with sophisticated graph-specific inductive bias. Our implementation is available at https://github.com/jw9730/tokengt.
      https://arxiv.org/abs/2207.02505

      img

      img

      img

      img

      img

      3、[CV] SNeRF: Stylized Neural Implicit Representations for 3D Scenes

      T Nguyen-Phuoc, F Liu, L Xiao
      [Meta]
      SNeRF:面向3D场景风格化的神经隐表示。本文提出一种风格化新视图合成方法。由于缺乏跨视图的一致性,将先进的风格化方法逐帧应用于新视图往往会导致抖动伪影。因此,本文研究了3D场景风格化,为一致新视图合成提供了强大的归纳偏差。采用新的神经辐射场(NeRF)作为3D场景表示,其有能力为各种场景渲染高质量的新视图。然而,由于从NeRF渲染新视图需要大量样本,训练一个风格化NeRF需要大量的GPU内存,超出了既有的GPU容量。本文提出一种新的训练方法,通过交替进行NeRF和风格化的优化步骤来解决该问题。该方法能充分利用硬件内存容量,既能以更高的分辨率生成图像,又能采用更具表现力的图像风格迁移方法。实验表明,所提出方法能为广泛的内容(包括室内、室外和动态场景)生成风格化的NeRF,并且能合成高质量的具有跨视角一致性的新视图。
      This paper presents a stylized novel view synthesis method. Applying stateof-the-art stylization methods to novel views frame by frame often causes jittering artifacts due to the lack of cross-view consistency. Therefore, this paper investigates 3D scene stylization that provides a strong inductive bias for consistent novel view synthesis. Specifically, we adopt the emerging neural radiance fields (NeRF) as our choice of 3D scene representation for their capability to render high-quality novel views for a variety of scenes. However, as rendering a novel view from a NeRF requires a large number of samples, training a stylized NeRF requires a large amount of GPU memory that goes beyond an off-the-shelf GPU capacity. We introduce a new training method to address this problem by alternating the NeRF and stylization optimization steps. Such a method enables us to make full use of our hardware memory capacity to both generate images at higher resolution and adopt more expressive image style transfer methods. Our experiments show that our method produces stylized NeRFs for a wide range of content, including indoor, outdoor and dynamic scenes, and synthesizes high-quality novel views with cross-view consistency.
      https://arxiv.org/abs/2207.02363

      img

      img

      img

      img

      img

      4、[LG] Predicting Out-of-Domain Generalization with Local Manifold Smoothness

      N Ng, K Cho, N Hulkund, M Ghassemi
      [MIT & New York University]
      基于局部流形平滑度的域外泛化预测。了解机器学习模型如何泛化到新环境是安全部署的一个关键部分。最近的工作提出了各种复杂度,直接预测或从理论上约束模型的泛化能力。然而,这些方法依赖于一系列强有力的假设,而这些假设在实践中并不总是满足。出于对现有测量方法有限应用的考虑,本文提出一种基于分类器局部流形平滑度的新的复杂性测量方法。将局部流形平滑度定义为分类器的输出对给定测试点周围流形邻域扰动的敏感性。直观上,一个对这些扰动不太敏感的分类器,应该有更好的泛化性。为了估计平滑性,用数据增强对点进行采样,测量这些点中被归入多数类的部分。所提出方法只需要选择一种数据增强方法,对模型或数据分布不做其他假设,这意味着它甚至可以应用于现有方法无法应用的域外(OOD)环境中。在图像分类、情感分析和自然语言推理的鲁棒性基准实验中,证明了在100多个训练/测试域对上评估的3000多个模型上,流形平滑度测量和实际的OOD泛化之间有很强的关联性。
      Understanding how machine learning models generalize to new environments is a critical part of their safe deployment. Recent work has proposed a variety of complexity measures that directly predict or theoretically bound the generalization capacity of a model. However, these methods rely on a strong set of assumptions that in practice are not always satisfied. Motivated by the limited settings in which existing measures can be applied, we propose a novel complexity measure based on the local manifold smoothness of a classifier. We define local manifold smoothness as a classifier’s output sensitivity to perturbations in the manifold neighborhood around a given test point. Intuitively, a classifier that is less sensitive to these perturbations should generalize better. To estimate smoothness we sample points using data augmentation and measure the fraction of these points classified into the majority class. Our method only requires selecting a data augmentation method and makes no other assumptions about the model or data distributions, meaning it can be applied even in out-of-domain (OOD) settings where existing methods cannot. In experiments on robustness benchmarks in image classification, sentiment analysis, and natural language inference, we demonstrate a strong and robust correlation between our manifold smoothness measure and actual OOD generalization on over 3,000 models evaluated on over 100 train/test domain pairs.
      https://arxiv.org/abs/2207.02093

      img

      img

      img

      img

      5、[LG] When does Bias Transfer in Transfer Learning?

      H Salman, S Jain, A Ilyas, L Engstrom, E Wong, A Madry
      [MIT]
      迁移学习中偏差何时迁移?用迁移学习使预训练的"源模型"适应下游的"目标任务",可以极大地提高性能,而且似乎没什么缺点。本文证明了仍然可能存在的一个缺点:偏差迁移,或者说,即使在适应了目标类别的模型之后,源模型的偏差仍然存在的趋势。通过合成实验和自然实验的结合表明,偏差迁移:(a)在现实环境中出现(如在ImageNet或其他标准数据集上进行预训练时),(b)甚至在目标数据集明确去偏的情况下也会发生。随着迁移学习模型越来越多地被部署在现实世界中,本文强调了理解预训练源模型局限性的重要性。
      Using transfer learning to adapt a pre-trained “source model” to a downstream “target task” can dramatically increase performance with seemingly no downside. In this work, we demonstrate that there can exist a downside after all: bias transfer, or the tendency for biases of the source model to persist even after adapting the model to the target class. Through a combination of synthetic and natural experiments, we show that bias transfer both (a) arises in realistic settings (such as when pre-training on ImageNet or other standard datasets) and (b) can occur even when the target dataset is explicitly de-biased. As transfer-learned models are increasingly deployed in the real world, our work highlights the importance of understanding the limitations of pre-trained source models. https://arxiv.org/abs/2207.02842

      img

      img

      img

      img

      另外几篇值得关注的论文:

      [CV] Towards Counterfactual Image Manipulation via CLIP

      基于CLIP的反事实图像处理研究
      Y Yu, F Zhan, R Wu, J Zhang, S Lu, M Cui, X Xie, X Hua, C Miao
      [Nanyang Technological University & Max Planck Institute for Informatics & Alibaba Group]
      https://arxiv.org/abs/2207.02812

      img

      img

      img

      img

      img

      [LG] When does SGD favor flat minima? A quantitative characterization via linear stability

      SGD何时倾向平坦最小值?基于线性稳定性的定量表征
      L Wu, M Wang, W Su
      [Peking University & University of Pennsylvani]
      https://arxiv.org/abs/2207.02628

      img

      img

      img

      img

      img

      [CV] LaserMix for Semi-Supervised LiDAR Semantic Segmentation

      面向半监督LiDAR语义分割的LaserMix
      L Kong, J Ren, L Pan, Z Liu
      [Nanyang Technological University]
      https://arxiv.org/abs/2207.00026

      img

      img

      img

      img

      img

      [CL] WebShop: Towards Scalable Real-World Web Interaction with Grounded Language Agents

      WebShop:基于Grounded语言代理的可扩展现实世界Web交互
      S Yao, H Chen, J Yang, K Narasimhan
      [Princeton University]
      https://arxiv.org/abs/2207.01206

      img

      img

      img

      img

      img

      posted in 技术分享📚有奖励
      189****6672
      189****6672
    • 百度-中科院CVPR 2022 Oral新作MixFormer:窗口特征和通道特征融合

      百度-中科院CVPR 2022 Oral新作MixFormer:窗口特征和通道特征融合

      论文地址:https://arxiv.org/pdf/2204.02557.pdf

      代码地址:https://github.com/PaddlePaddle/PaddleClas

      2022-04-08-14-18-26.png

      摘要

      1. 现存问题:虽然局部窗口自注意在视觉任务中表现显著,但它存在感受野有限和建模能力弱的问题。这主要是因为它在非重叠窗口内形成自注意力,并在通道维度上共享权重。
      2. 解决方法:论文提出了一种窗口和通道的混合模式来解决以上问题。
      3. 实验结果:模型在图像分类方面取得了与EfficientNet相当的结果,并且显示出比RegNet和Swin Transformer更好的结果。在MS COCO,ADE20k上的5个密集预测任务中性能显著提升,且计算成本较低。

      介绍

      2022-04-08-14-18-42.png

      论文提出了一种并行设计,将局部窗口自注意力与depth-wise卷积相结合。通过这两个分支来获取窗口内和窗口之间的信息特征,最后进行cat连接起来,并发送到前馈网络(FFN)以获得输出特征。

      在上图中,标有通道交互和空间交互的蓝色箭头是论文提出的的双向交互,为更好地在这两个分支中进行表征学习提供了补充信息。

      方法

      整体架构

      2022-04-08-14-19-06.png

      模型的整体架构如上图所示,是一个层级模块,每一层具有不同的分辨率特征,每层之间通过一个步长为2的卷积操作进行下采样。

      最后使用了一个Projection Layer(一个线性层+激活层)增加通道数到1280来保存更多的特征信息,能够实现更好的分类性能。

      架构变体

      根据每层中的通道数C和Mixing Block 个数以及自注意力中的head个数设计不同变体

      每层中Mixing Block个数的设计原则:最后两层中设计更多的Block,能够实现更好的性能

      每层中最重要的就是Mixing Block,接下来进行详细分析。

      The Mixing Block

      2022-04-08-14-18-42.png

      论文中的Mixing Block有两个创新点:

      1. 采用并行设计parallel design来融合局部窗口自注意力和depth-wise卷积操作
      2. 提出了两分支双向交互Bi-directional Interactions方案

      这两个创新点有效解决了局部窗口自注意力中的感受野小和建模能力弱的限制。

      The Parallel Design

      局部窗口自注意力虽然能够有效减小计算量,但是限制了感受野的大小,现已经有很多方案用于解决这个问题,如shift、shuffle和卷积等。该论文使用depth-wise卷积来进行窗口间的信息交流。

      之前有论文将窗口自注意力和depth-wise卷积顺序操作,该论文认为这样减少了不同特征之间的交互,因此提出了并行设计。并行设计有着两个优势:

      1. 能够有效解决窗口自注意力机制的较小感受野的限制
      2. 同时建模窗口内和窗口间的信息联系,更能学习较好的特征表示

      具体操作是:使用7×7的窗口大小进行自注意力,使用3×3卷积核大小进行高效卷积操作。

      Bi-directional Interactions

      2022-04-08-14-19-22.png

      窗口自注意力机制只在通道上分为几个head,每个head公用一个全局相似度权重,限制了其建模能力,该论文尝试去生成一个channel-wise动态权重,就是为每个通道赋予独有的权重,并考虑到depth-wise卷积重点关注通道信息,所以论文选择了depth-wise卷积进行通道层面上的信息交互。

      由上图可以看出,双向交互包括通道交互和空间交互。

      通道交互:

      包括一个全局平均池化生成一个一维向量,随后带有BN和GELU激活层的两个1×1的卷积层,最后使用sigmoid生成一个通道注意力,并与窗口注意力分支中的向量V相乘,修正其通道权重。整个过程与SE layer类似。

      空间交互:

      同样使用带有BN和GELU的两个1×1卷积层,然后通过sigmoid生成一个通道数为1的空间注意力map,并与depth-wise卷积层分支输出特征进行乘积以修正其空间注意力。

      整个过程的数学表达式如下:

      LN:线性层

      W-MSA:Window-based Multi-Head Self-Attention

      CONV:Depth-wise Convolution

      实验

      在ImageNet-1K,MSCOCO和ADE20K数据集上进行了对比实验,并进行了消融实验

      Image分类对比实验

      COCO目标检测和分割对比实验

      ADE20K语义分割对比实验

      双向信息交互消融实验

      posted in CV领域
      189****6672
      189****6672
    • 前沿分享

      转载:爱可可-爱生活(知乎)

      摘要:利用稀疏性将卷积核扩大到51×51以上、K均值掩码Transformer、基于编译器中间表示的代码翻译、面向行动定位的协同微调、目标检测中是否该对所有候选区一致看待、哈佛USPTO专利申请数据集、神经语言模型并非天然能拟合大脑数据但训练仍有帮助、现实半监督学习研究、基于图拓扑采样的图卷积网络训练泛化保证

      1、[CV] More ConvNets in the 2020s: Scaling up Kernels Beyond 51x51 using Sparsity

      S Liu, T Chen, X Chen, X Chen, Q Xiao, B Wu, M Pechenizkiy, D Mocanu…
      [Eindhoven University of Technology & University of Texas at Austin]
      利用稀疏性将卷积核扩大到51×51以上。自从视觉Transformer(ViT)提出后,Transformer迅速在计算机视觉领域大放异彩。卷积神经网络(CNN)的主导作用似乎受到了越来越有效的基于Transformer的模型的挑战。最近,一些先进的卷积模型在局部强注意力机制的激励下,以大核的方式进行了反击,显示了吸引人的性能和效率。其中的一个,RepLKNet,令人印象深刻地设法将核大小扩展到31×31,并提高了性能,但与Swin Transformer等高级ViT的扩展趋势相比,随着核大小的继续增长,性能开始饱和。本文探索了训练大于31×31的极端卷积的可能性,并测试了是否可以通过战略性扩展卷积来消除性能差距。这项研究最后从稀疏性的角度提出了一个应用极端大核的方案,可顺利地将核扩大到61×61,且性能更好。在此方案基础上,提出了稀疏大核网络(SLaK),一种配备了51×51核的纯CNN架构,在ImageNet分类以及典型的下游任务上,可以与最先进的分层Transformer和现代ConvNet架构(如ConvNeXt和RepLKNet)的性能相当或更好。
      Transformers have quickly shined in the computer vision world since the emergence of Vision Transformers (ViTs). The dominant role of convolutional neural networks (CNNs) seems to be challenged by increasingly effective transformer-based models. Very recently, a couple of advanced convolutional models strike back with large kernels motivated by the local but large attention mechanism, showing appealing performance and efficiency. While one of them, i.e. RepLKNet, impressively manages to scale the kernel size to 31×31 with improved performance, the performance starts to saturate as the kernel size continues growing, compared to the scaling trend of advanced ViTs such as Swin Transformer. In this paper, we explore the possibility of training extreme convolutions larger than 31×31 and test whether the performance gap can be eliminated by strategically enlarging convolutions. This study ends up with a recipe for applying extremely large kernels from the perspective of sparsity, which can smoothly scale up kernels to 61×61 with better performance. Built on this recipe, we propose Sparse Large Kernel Network (SLaK), a pure CNN architecture equipped with 51×51 kernels that can perform on par with or better than state-of-the-art hierarchical Transformers and modern ConvNet architectures like ConvNeXt and RepLKNet, on ImageNet classification as well as typical downstream tasks. Codes: https://github.com/VITA-Group/SLaK
      https://arxiv.org/abs/2207.03620

      img

      img

      img

      img

      img

      2、[CV] k-means Mask Transformer

      Q Yu, H Wang, S Qiao, M Collins, Y Zhu, H Adam, A Yuille, L Chen
      [Johns Hopkins University & Google Research]
      K均值掩码Transformer。Transformer在视觉任务中的兴起,不仅推进了网络骨干设计,也为实现端到端图像识别(如目标检测和全景分割)开启了崭新的篇章。源于自然语言处理(NLP),由自注意力和交叉注意力组成的Transformer架构,可有效地学习序列中元素间的长程交互。然而,大多数现有的基于Transformer的视觉模型只是简单借用了NLP的想法,忽略了语言和图像之间的关键区别,特别是空间扁平化像素特征的极大序列长度,进一步阻碍了像素特征和目标查询间交叉注意力的学习。本文重新思考了像素和目标查询间的关系,提出将交叉注意力的学习重新表述为一个聚类过程。受传统的k均值聚类算法的启发,提出一种用于分割任务的k-means Mask Xformer(kMaX-DeepLab),不仅改进了最先进的算法,还具有简单优雅的设计。通过用单头k-means聚类取代多头交叉注意力,简化了掩码-Transformer模型。所提出的kMaX-DeepLab在COCO估值集上取得了58.0%的PQ,在Cityscapes估值集上取得了68.4%的PQ、44.0%的AP和83.5%的mIoU的新的最先进的性能,而无需测试时增强或外部数据集。
      The rise of transformers in vision tasks not only advances network backbone designs, but also starts a brand-new page to achieve end-to-end image recognition (e.g ., object detection and panoptic segmentation). Originated from Natural Language Processing (NLP), transformer architectures, consisting of self-attention and cross-attention, effectively learn long-range interactions between elements in a sequence. However, we observe that most existing transformer-based vision models simply borrow the idea from NLP, neglecting the crucial difference between languages and images, particularly the extremely large sequence length of spatially flattened pixel features. This subsequently impedes the learning in cross-attention between pixel features and object queries. In this paper, we rethink the relationship between pixels and object queries, and propose to reformulate the cross-attention learning as a clustering process. Inspired by the traditional k-means clustering algorithm, we develop a k-means Mask Xformer (kMaX-DeepLab) for segmentation tasks, which not only improves the state-of-the-art, but also enjoys a simple and elegant design. As a result, our kMaX-DeepLab achieves a new state-of-the-art performance on COCO val set with 58.0% PQ, and Cityscapes val set with 68.4% PQ, 44.0% AP, and 83.5% mIoU without test-time augmentation or external dataset. We hope our work can shed some light on designing transformers tailored for vision tasks. Code and models are available at https://github.com/google-research/deeplab2.
      https://arxiv.org/abs/2207.04044

      img

      img

      img

      img

      img

      3、[CL] Code Translation with Compiler Representations

      M Szafraniec, B Roziere, H L F Charton, P Labatut, G Synnaeve
      [Meta AI]
      基于编译器中间表示的代码翻译。本文利用低级编译器中间表示(IR)来改进代码翻译,具体来说,就是利用LLVM的IR来改善源代码的神经机器翻译。传统的转译器依赖于句法信息和人工制定的规则,限制了其适用性并产生了不自然的代码。将神经机器翻译(NMT)方法应用于代码,成功扩大了可以获得自然翻译的程序集。然而,它们将代码视为文本Token的序列,仍然不能很好地区分在不同语言中具有不同语义的类似代码片断。其结果是低质量的翻译,降低了NMT的实用性,并强调需要一种方法来显著提高其准确性。本文提出用IR来增强代码翻译,特别是LLVM IR,并在C++、Java、Rust和Go语言上取得了成果。任何IR都可以通过将代码表示与语义相联系来帮助改善代码表示。所提出方法改进了无监督代码翻译的最先进水平,使正确的翻译数量平均增加了11%,对于Java→Rust语言对,正确率高达79%。通过增加数百个Go和Rust函数,扩展了之前的代码翻译测试集。此外,在IR反编译问题上训练出高性能的模型,从IR生成编程源码,并研究使用IR作为翻译的中间支点。
      In this paper, we leverage low-level compiler intermediate representations (IR) to improve code translation. Traditional transpilers rely on syntactic information and handcrafted rules, which limits their applicability and produces unnaturallooking code. Applying neural machine translation (NMT) approaches to code has successfully broadened the set of programs on which one can get a naturallooking translation. However, they treat the code as sequences of text tokens, and still do not differentiate well enough between similar pieces of code which have different semantics in different languages. The consequence is low quality translation, reducing the practicality of NMT, and stressing the need for an approach significantly increasing its accuracy. Here we propose to augment code translation with IRs, specifically LLVM IR, with results on the C++, Java, Rust, and Go languages. Our method improves upon the state of the art for unsupervised code translation, increasing the number of correct translations by 11% on average, and up to 79% for the Java→ Rust pair. We extend previous test sets for code translation, by adding hundreds of Go and Rust functions. Additionally, we train models with high performance on the problem of IR decompilation, generating programming source code from IR, and study using IRs as intermediary pivot for translation.
      https://arxiv.org/abs/2207.03578

      img

      img

      img

      img

      img

      4、[CV] Beyond Transfer Learning: Co-finetuning for Action Localisation

      A Arnab, X Xiong, A Gritsenko, R Romijnders, J Djolonga, M Dehghani, C Sun, M Lučić, C Schmid
      [Google Research]
      超越迁移学习:面向行动定位的协同微调。迁移学习是在小型目标数据集上训练深度网络的主要范式。模型通常在大型的"上游"数据集上进行分类训练,因为这些标记很容易收集,然后在"下游"任务上进行微调,如动作定位,由于其标注更精细,这些任务的数据更少。本文对这种方法提出质疑,并提出协同微调——在多个"上游 "和"下游"任务上同时训练一个模型。本文证明了在使用相同总量的数据时,协同微调的效果优于传统的迁移学习,同时也表明可以很容易地将所提出方法扩展到多个"上游 "数据集以进一步提高性能。特别是,协同微调极大提高了下游任务中稀有类的性能,因为其具有正则效应,使网络能学习在不同数据集之间迁移的特征表示。本文观察了与公共视频分类数据集的系统微调,能在具有挑战性的AVA和AVA-Kinetics数据集上取得最先进的空间-时间动作定位结果,超过了最近开发复杂模型的工作。
      Transfer learning is the predominant paradigm for training deep networks on small target datasets. Models are typically pretrained on large “upstream” datasets for classification, as such labels are easy to collect, and then finetuned on “downstream” tasks such as action localisation, which are smaller due to their finer-grained annotations. In this paper, we question this approach, and propose co-finetuning — simultaneously training a single model on multiple “upstream” and “downstream” tasks. We demonstrate that co-finetuning outperforms traditional transfer learning when using the same total amount of data, and also show how we can easily extend our approach to multiple “upstream” datasets to further improve performance. In particular, co-finetuning significantly improves the performance on rare classes in our downstream task, as it has a regularising effect, and enables the network to learn feature representations that transfer between different datasets. Finally, we observe how co-finetuning with public, video classification datasets, we are able to achieve state-of-the-art results for spatio-temporal action localisation on the challenging AVA and AVA-Kinetics datasets, outperforming recent works which develop intricate models.
      https://arxiv.org/abs/2207.03807

      img

      img

      img

      img

      5、[CV] Should All Proposals be Treated Equally in Object Detection?

      Y Li, Y Chen, X Dai, D Chen, M Liu, P Yu, J Yin, L Yuan, Z Liu, N Vasconcelos
      [Microsoft & UC San Diego, La Jolla]
      **目标检测中是否该对所有候选区一致看待?对于资源受限的视觉任务来说,目标检测器的复杂性和精确性的权衡是一个关键问题。之前的工作强调用高效的骨干网来实现检测器。本文研究了检测头的候选区处理对这种权衡的影响。假设提高检测效率需要一个范式的转变,即对候选区进行不平等的处理,对好的候选区比差的候选区分配更多的计算。这将导致更好地利用可用的计算预算,在相同的FLOPS下实现更高的精度。本文将其表述为一个学习问题,目标是在检测头中为候选区分配操作器,从而使总的计算成本受到限制,并使精度达到最大化。该框架包含一个简单的选择器监督和两个损失函数,即IoU损失和复杂性损失。关键的发现是,这种匹配可以作为一个函数来学习,该函数将每个候选区嵌入到运算符上的一个热码。虽然这个函数引起了一个复杂的动态网络路由机制,但它可以由一个简单的MLP实现,并通过现成的目标检测器进行端到端的学习。动态候选区处理(DPP)框架在广泛的复杂度范围内,对不同类型的骨干网的目标检测实现了最先进的复杂度-精度权衡。

      **The complexity-precision trade-off of an object detector is a critical problem for resource constrained vision tasks. Previous works have emphasized detectors implemented with efficient backbones. The impact on this trade-off of proposal processing by the detection head is investigated in this work. It is hypothesized that improved detection efficiency requires a paradigm shift, towards the unequal processing of proposals, assigning more computation to good proposals than poor ones. This results in better utilization of available computational budget, enabling higher accuracy for the same FLOPS. We formulate this as a learning problem where the goal is to assign operators to proposals, in the detection head, so that the total computational cost is constrained and the precision is maximized. The key finding is that such matching can be learned as a function that maps each proposal embedding into a one-hot code over operators. While this function induces a complex dynamic network routing mechanism, it can be implemented by a simple MLP and learned end-to-end with off-the-shelf object detectors. This dynamic proposal processing (DPP) is shown to outperform state-of-the-art end-to-end object detectors (DETR, Sparse R-CNN) by a clear margin for a given computational complexity. Source code is at https://github.com/liyunsheng13/dpp
      https://arxiv.org/abs/2207.03520

      img

      img

      img

      img

      img

      另外几篇值得关注的论文:

      [CL] The Harvard USPTO Patent Dataset: A Large-Scale, Well-Structured, and Multi-Purpose Corpus of Patent Applications

      哈佛USPTO专利数据集:大规模、结构良好、用途广泛的专利申请语料库
      M Suzgun, L Melas-Kyriazi…
      [Stanford University & Oxford University & Harvard University]
      https://arxiv.org/abs/2207.04043

      img

      img

      img

      img

      img

      [CL] Neural Language Models are not Born Equal to Fit Brain Data, but Training Helps

      神经语言模型并非天然能拟合大脑数据,但训练仍有帮助
      A Pasquiou, Y Lakretz, J Hale, B Thirion, C Pallier
      [INSERM & INRIA & U. of Georgia]
      https://arxiv.org/abs/2207.03380

      img

      img

      img

      img

      img

      [CV] Towards Realistic Semi-Supervised Learning

      现实半监督学习研究
      M N Rizve, N Kardan, M Shah
      [UCF]
      https://arxiv.org/abs/2207.02269

      img

      img

      img

      img

      img

      [LG] Generalization Guarantee of Training Graph Convolutional Networks with Graph Topology Sampling

      基于图拓扑采样的图卷积网络训练泛化保证
      H Li, M Wang, S Liu…
      [Rensselaer Polytechnic Institute & Michigan State University & IBM & University at Buffalo]
      https://arxiv.org/abs/2207.03584

      img

      img

      img

      img

      img

      posted in 技术分享📚有奖励
      189****6672
      189****6672
    • 北大CVPR 2022 Oral新作Video K-Net:视频全景分割模型

      北大CVPR 2022 Oral新作Video K-Net:视频全景分割模型

      论文标题:Video K-Net: A Simple, Strong, and Unified Baseline for Video Segmentation

      论文地址:https://arxiv.org/pdf/2204.04656.pdf

      代码地址:https://github.com/lxtGH/Video-K-Net

      2022-04-16-10-46-20.png

      摘要

      1. 引出主题: K-Net是一种通过一组可学习的内核来统一图像分割(语义分割、实例分割)的方法。论文观察到,这些来自K-Net的可学习内核可以在视频帧中自然地关联相同的实例。

      2. 创新点:基于K-Net的基础上,该论文介绍了Video K-Net,一个简单、强大、统一的端到端视频全景分割框架。Video K-Net通过简单的基于内核的外观建模和跨时间内核交互,学会了同时分割和跟踪视频中的“things”和“stuff”(语义分割和实例分割)。

      3. 实验结果: 在Citscapes VPS和KITTI-STEP上实现了最先进的视频全景分割结果。特别是在KITTI-STEP上,与以前的方法相比,可以提高近**12%**的相对改进。还验证了它在视频语义分割中的泛化能力,在VSPW数据集上,将各种基线提高了2%。

      背景介绍

      2022-04-16-10-59-57.png

      K-Net部分可以查看上一篇论文

      论文先做了几个实验来说明工作动机。

      论文将K-Net直接用于视频分割任务。图3给出了一个Cityscapes-VSP的视觉示例。直接在两个数据集上训练K-Net,而不添加跟踪组件。在四个帧中,几个内核都表示一致性的目标,比如person和car,说明内核中已经包含了位置信息。并认为更新后的内核包含目标鉴别信息,即使不添加额外的跟踪头,也可以直接用于跟踪视频中的实例。具体分析如下:

      1. 每个输出实例掩码对应一个特定的内核。
      2. 在自适应特征更新期间,每个内核吸收位置感知特征,其中实例感知信息已经合并到每个内核中。因此,可以从之前的内核解码相同的实例。

      算法

      尽管原始K-Net具有竞争性的性能,但在几种情况下出现失效,例如图3所示的快速移动对象。

      因此,论文在K-Net上设计了三个改进,分别包括:

      1. 通过改进的对比学习损失学习内核关联嵌入
      2. 学习链接跟踪内核
      3. 学习融合内核

      整体模型架构如图4所示,给定用于训练的key图像IkeyI_{key}Ikey​,从其邻域帧中随机选择参考图像IrefI_{ref}Iref​。然后通过K-Net,最终得到两个核:KkeyK_{key}Kkey​和KrefK_{ref}Kref​

      学习内核关联嵌入Kernel Association Embeddings

      模块如图4右下角

      学习内核关联嵌入的目的是对两帧之间的实例内核嵌入进行跟踪实例对比学习。

      1. 在原来的K-Net解码器之后添加了一个额外的轻量级嵌入头,以提取每个内核的嵌入特征。嵌入头通过几个完全连接层实现。
      2. 将实例内核对应的mask prediction MiM_iMi​与GT掩码进行比较,如果对象对应的掩码的IoU高于α1\alpha_1α1​,则内核嵌入被定义为对象的正嵌入;如果IoU低于α2\alpha_2α2​,则内核嵌入被定义为负嵌入
      3. 只考虑与GT掩码匹配的内核进行训练,如果两个采样帧上两个区域与同一对象关联,则这两个内核匹配为positive,否则为negative。

      假设key帧上有 V 个匹配核作为训练样本,参考帧上有K个匹配核作为对比目标。那么跟踪损失如下:

      其中v,k+,k−是训练样本的内核嵌入、positive target和negative target。

      此外,还采用L2损失作为辅助损失。

      其中如果两个样本的匹配是正的,则 c 等于1,否则为0。

      学习链接跟踪内核Learning to Link Kernels

      模块如图4右下角黄色区域

      在训练和推理过程中将跟踪内核KkeyK_{key}Kkey​和KrefK_{ref}Kref​联系起来。这迫使内核沿时间维度执行交互作用。

      采用一个带有前馈网络(FFN)的自注意力层(MHSA:多头自注意力)将内核特征沿时间维度进行交互,进而更新内核特征。该过程如下所示:

      其中,查询、键和值分别为KkeyK_{key}Kkey​、KrefK_{ref}Kref​和KrefK_{ref}Kref​。

      这样,来自参考帧的内核通过内核之间的相似矩阵传播到关键帧。

      学习融合内核Learning to Fuse Kernels

      模块如图4中间下方

      前面的Link步骤可能只关注跟踪一致性,而忽略了分割的一致性。

      为了解决这个问题,在 K-Net 的帧之间进行内核融合。具体步骤如K-Net一致。

      实验

      Main Results

      KITTI-STEP数据集实验

      Cityscape-VPS数据集实验

      VSPW数据集实验

      Youtube-VIS-2019数据集实验

      Ablation Study

      可视化

      posted in CV领域
      189****6672
      189****6672
    • VSA:可变形尺寸窗口自注意力模型

      VSA:可变形尺寸窗口自注意力模型

      论文标题:VSA: Learning Varied-Size Window Attention in Vision Transformers

      论文地址:https://arxiv.org/pdf/2204.08446.pdf

      论文代码:https://github.com/ViTAE-Transformer/ViTAE-VSA

      image-20220424170556997


      摘要

      1. 引入主题: 窗口自注意力已经在视觉Transformer中得到了广泛的探索,以平衡性能、计算复杂度和内存占用。

      2. 现存问题: 目前的模型采用预先定义的固定大小窗口设计,限制了它们建模长期依赖关系和适应不同大小对象的能力。

      3. 解决方法: 提出了可变尺寸窗口注意(VSA)来从数据中学习自适应窗口配置。具体来说,基于每个默认窗口中的token,VSA 使用了一个窗口回归模块来预测目标窗口的大小和位置。通过对每个注意头独立采用 VSA,可以建立长期依赖关系模型,从不同窗口捕获丰富的上下文,促进窗口之间的信息交换。

      4. 实验结果: VSA 是一个易于实现的模块,它可以用较小的修改和可以忽略的额外计算成本来替代最先进的代表性模型中的窗口注意力,同时大幅度地提高它们的性能,例如,在ImagNet 分类任务中,分类性能相对Swin-T提高了1.1% ,使用较大的图像训练和测试时,性能增益增加更大。另外,在目标检测分割、实例分割和语义分割任务中,处理不同大小的对象时,VSA 比普通窗口注意力更有优势。

      image-20220424192905455

      算法

      image-20220424192956731

      模型整体框架如上图(a)所示,是基于swin模型进行修改的,最主要的创新点是使用VSA(VWA) Transfomer blocks替代swin中的窗口自注意力block。

      VSA Transformer模块如上图©所示,与传统的窗口自注意力模块不同,其中使用了VSA(VWA)(上图(b)所示)和CPE模块。接下来进行分别介绍。

      VSA模块

      上图(b)所示,可以简要看出,VSA module修改了每个窗口的大小和位置,提高模型对长远依赖的建模以及不同大小目标对象的检测。具体操作步骤如下:

      1. 给定VSA模块的输入特征XXX,首先将其平分成大小一样的不重叠窗口XwX_wXw​,这与传统方法一样

      2. 对每个窗口进行线性操作得到对应的查询QwQ_wQw​,Qw=Linear(Xw)Q_w = Linear(X_w)Qw​=Linear(Xw​)

      3. 为了获得每个窗口的长宽两个方向上的缩放和位置偏置,需要进行如下操作:

        1). 对XwX_wXw​使用核大小和步长与窗口大小一样的平均池化操作,并附加LeakyRelu激活层

        2). 进一步使用1 ×1的卷积层,输出SwS_wSw​和OwO_wOw​,大小均为R2×NR^{2×N}R2×N,其中2表示长宽两个方向,N表示head个数

        image-20220424200019111

      4. 获得了缩放和偏置,那就要提取特征了,首先基于输入特征XXX进行线性操作获取特征图KKK和VVV

      image-20220424200452692

      1. 然后,VSA模块根据缩放和偏置在KKK和VVV上进行特征提取,得到Kk,v,Vk,v∈RM×N×C′K_{k, v}, V_{k, v} \in R^{M×N×C^{\prime}}Kk,v​,Vk,v​∈RM×N×C′
      2. 最后将Kk,v,Vk,v,QwK_{k, v}, V_{k, v}, Q_wKk,v​,Vk,v​,Qw​输入到多头自注意力模块MHSA中

      CPE模块

      由于窗口变形会导致位置信息的变化,使得Q和K V的位置信息出现偏差,论文使用了条件位置编码CPE(来自CPVT论文)来解决这个问题

      image-20220424201741400

      实验

      ImageNet分类任务

      image-20220424204156151

      MS COCO目标检测和实例分割任务

      image-20220424204243417

      image-20220424204330097

      Cityscapes语义分割任务

      image-20220424204345150

      消融实验

      image-20220424204430100

      image-20220424204511886

      可视化

      image-20220424204548277

      posted in CV领域
      189****6672
      189****6672
    • 商汤-上交CVPR2022新作|U2PL: 基于伪标签的半监督语义分割算法

      商汤-上交CVPR2022新作|U2PL: 基于伪标签的半监督语义分割算法

      论文标题: Semi-Supervised Semantic Segmentation Using Unreliable Pseudo-Labels

      论文地址: https://arxiv.org/pdf/2203.03884.pdf

      论文代码: https://haochen-wang409.github.io/U2PL

      image-20220427144301210


      摘要

      1. 引出主题:半监督语义分割的关键是对未标注图像中的像素点分配足够的伪标签。

      2. 现存问题: 一种常见的做法是选择高置信度的预测作为伪标签,但这会导致一个问题,即大多数像素由于其不可靠性而可能无法使用。

      3. 解决方法: 论文认为每个像素对模型训练都很重要,即使它的预测是模糊的。从直观上看,可能对某个像素是否属于某个类别不是很确定,但对于它不属于某些类应该是比较确定的。基于这一认识,开发了一个有效的pipeline,以充分利用无标签数据集。

      4. 实验结果: 在各种基准和训练环境下的实验结果表明,该方法优于当前最先进的方法。

      背景介绍

      可以通过对图像每个像素点的类别预测结果进行熵计算(后文介绍)来判断其可靠性。

      image-20220427145935039

      如上图所示,图a表示一个熵图,图b是通过对熵图进行阈值得到的伪标签,其中白色区域表示不确定区域。

      图c表示图a中黄色十字架位置像素点的类别预测,由于其预测结果可靠性很高,可以直接作为标签用于训练。

      图d表示图a中白色十字架位置像素点的类别预测,由于其预测结果可靠性很高,不能作为标签进行训练,但是,很清楚的是,该像素不属于car和train这两类,所以可以将其作为这两个类的负样本参与训练。

      这样就能够有效利用所有像素点。

      算法

      image-20220427151432734

      由上图可以看出,整个模型结构基本与基于momentum自监督一致

      分为student和teacher分支,两分支具有相同的网络结构,teacher分支的网络权重是根据student分支网络权重进行EMA修正的。

      有所不同的是,student分支同时进行监督训练,更重要的创新点在于损失函数的设置。

      image-20220427160621034

      整个损失函数由LsL_sLs​、LuL_uLu​和LcL_cLc​三部分组成

      Ls\mathcal{L}_{s}Ls​是用于监督训练的交叉熵损失函数

      image-20220427160942129

      其中,hhh表示backbone,fff表示分割头

      Lu\mathcal{L}_{u}Lu​是依赖于teacher可靠预测伪标签进行训练的交叉熵损失函数

      image-20220427161433455

      Lc\mathcal{L}_{c}Lc​是依赖于teacher不可靠预测伪标签进行训练的对比损失函数(基于InfoNCE模型)

      image-20220427161545436

      接下来进行分别介绍。

      可靠伪标签

      首先需要对可靠性进行衡量,上文已经简单介绍是使用熵进行计算,熵的定义如下:

      image-20220427162306481

      其中c表示通道,P表示像素值

      再通过阈值来打上伪标签

      image-20220427162527062

      阈值γt\gamma_{t}γt​计算公式如下:

      image-20220427162806476

      其中,H表示熵图,αt\alpha_{t}αt​表示计算熵大小的几分位数值,大家可以查看np.percentitle定义

      随着训练的进展,模型性能不断提升,可靠伪标签的比重肯定是逐渐增大的,所以需要动态调节αt\alpha_{t}αt​的大小,论文使用线性调节方式

      image-20220427163706405

      不可靠伪标签

      使用不可靠伪标签进行对比学习

      本论文这一部分是借鉴ReCo模型,其对比学习需要正负样本:

      正样本

      1. 对于有标签和无标签的数据集,根据每个类别的预测概率筛选出相应的集合AclA_c^lAcl​、AcuA_{c}^{u}Acu​

      image-20220427165712714

      image-20220427165730053

      1. 根据两个集合的合集均值特征作为该类别的anchor pixel

      image-20220427165751066

      image-20220427165806308

      负样本

      对于有标签的数据集,其余类别都是负样本

      对于无标签的数据集,将其作为预测概率低的类别的负样本

      image-20220427170205061

      实验

      Comparison with Existing Alternatives

      image-20220427170432059

      image-20220427170455863

      Ablation Studies

      image-20220427170535831

      可视化

      image-20220427170609121

      posted in CV领域
      189****6672
      189****6672
    • ICLR2022 | IBOT:使用online tokenier进行mask预测的自监督框架

      ICLR2022 | IBOT:使用online tokenier进行mask预测的自监督框架

      论文标题:IBOT : IMAGE BERT PRE-TRAINING WITH ONLINE TOKENIZER

      论文地址:https://arxiv.org/pdf/2111.07832.pdf

      论文代码:https://github.com/bytedance/ibot

      image-20220514200921681

      摘要

      1. 引出主题: 语言Transformer的成功主要归功于mask语言建模(MLM)的前置任务(Devlin et al.,2019),在这项任务中,文本首先被tokenized成语义上有意义的片段。
      2. 现存问题: 该论文研究了mask图像建模(MIM),并指出了视觉tokenizer的优势和挑战。
      3. 解决方法: 论文提出了一个自监督的框架iBOT,它可以通过online tokenizer执行掩码预测。具体来说,在mask patch tokens上形成自蒸馏,并将教师网络作为在online tokenizer。
      4. 实验结果: 通过在ImageNet-1K上实现82.3%的linear probing精度和87.8%的fine-tuning精度,并在密集的下游任务(例如,对象检测、实例分割和语义分割)上取得领先的结果。

      image-20220514202424660

      算法

      image-20220514202737374

      整体模型架构如上图所示:

      1. 首先对输入图像进行两种数据增强得到视图uuu和视图vvv

      2. 分别对uuu和vvv进行mask操作得到他们的masked view u^\hat{\boldsymbol{u}}u^和v^\hat{\boldsymbol{v}}v^

      3. 然后对u^\hat{\boldsymbol{u}}u^和v^\hat{\boldsymbol{v}}v^进行patch embedding操作image-20220514213203787

      4. online tokenizer不进行mask操作,相应的输入patch为image-20220514213225261

      5. mask patch输入到学生分支,unmask patch输入到教师/online分支,另外,教师分支不进行梯度反传,通过EMA根据学生分支中的网络权重进行动态更新

      6. 对输出结果进行LMIML_{MIM}LMIM​和LCLS\mathcal{L}_{\mathrm{CLS}}LCLS​损失计算

      其中,LMIM\mathcal{L}_{\mathrm{MIM}}LMIM​ 是比较教师分支输出和学生分支输出中的unmask token部分,公式如下:

      image-20220514204150379

      为了确定online tokenizer是具有语义意义的,对CLS token进行自蒸馏计算。论文借鉴DINO论文中的算法,使用如下公式进行LCLS\mathcal{L}_{\mathrm{CLS}}LCLS​损失计算

      image-20220514204537167

      网络结构:

      1. 使用具有不同数量的参数的ViT(Dosovitskiy et al.,2021)和Swin Transformer(Liu et al.,2021b):ViT-S/16、ViT-B/16、ViT-L/16和Swin-T/{7,14}作为主干网络fff。对于ViT,/16表示面片大小为16。对于Swins,/{7,14}表示窗口大小为7或14。
      2. 使用大小为224的图像对Transformer进行预训练和微调,patch总数是196。
      3. 投影头hhh是一个三层MLP,并使用l2l_2l2​正则化的bottleneck,与在DINO(Caron等人,2021年)一致

      预训练设置:

      1. 使用AdamW优化器和1024个batchsize在ImageNet-1K训练集上预先培训iBOT。
      2. 使用ViT-S/16预训练iBOT800个epochs,用ViT-B/16预训练400个epochs,用ViT-L/16预训练250个epochs,用Swin-T/{7,14}预训练iBOT300个epochs。还使用了ViT-B/16对ImageNet-22K训练集进行80个epochs的预训练,并使用ViT-L/16进行了50个epochs预训练。
      3. 在前10个epochs,学习率线性上升至其基准值,基准值与batchsize成比例:lr=5e−4×batchsize/256\mathrm{lr}=5 e^{-4} \times batchsize / 256lr=5e−4×batchsize/256 。

      实验

      ImageNet-1K上的分类任务

      image-20220514210019111

      image-20220514210159884

      下游任务

      COCO数据集中的目标检测和实例分割任务以及ADE20K数据集中的语义分割任务

      image-20220514210218660

      迁移任务

      image-20220514210406721

      可视化

      image-20220514210618745

      消融实验

      image-20220514210556956

      posted in CV领域
      189****6672
      189****6672
    • 自监督学习效果差?Meta AI 提出 Q-score 快速过滤错误样本!

      自监督学习效果差?Meta AI 提出 Q-score 快速过滤错误样本!

      文章来源于夕小瑶的卖萌屋,作者jxyxiangyu

      自监督学习指的是不依靠人工标注数据,直接从数据中学习到有用的特征表示。自监督学习中所采用的监督信息可以是“是否属于同一实例样本”的二分类标签(对比学习),也可以是一段连续的自然语言文本的下一个词(自回归语言模型)。

      然而自监督学习相关的论文看多了,感觉也就那么回事。除了可以减少对标注数据的依赖,下游任务中该分错类的case,照样会分错类。

      那么究竟有没有什么灵丹妙药可以缓解自监督模型在下游任务中出现分错类的情况呢?

      最近 meta AI 的一篇工作研究了自监督模型在下游任务错误分类的原因,并且提出了缓解这一问题的方法,让我们一起来看看吧。

      论文标题:
      Understanding Failure Modes of Self-Supervised Learning

      论文链接:
      https://arxiv.org/pdf/2203.01881.pdf

      自监督模型下游错误分类的潜在原因

      为了研究自监督模型学习到的特征表示中哪些特征可以有助于下游任务的正确分类,作者用 ImageNet-100 预训练了 SimCLR 模型作为 baseline ,并且在学习到的特征表示后面接了个线性分类器用于下游任务的分类。

      img

      图1 是训练学到的 ImageNet-100 中每个类的平均特征表示(部分特征),其中每个类是按照该类别的分类准确度(acc)排序的。图中用颜色深浅表示平均特征表示的值的绝对大小,左边是在下游任务中可以被正确分类的样本,右边是错误分类的样本的平均特征表示。

      可以看到,

      1. 表征空间几乎是稀疏的,每个类的大部分特征都接近0;
      2. 在正确分类的样本中,每个类的平均特征表示都有十分明显的几个特征,这些特征是类别所独有的,不同类别的可区分特征都不一致,且不同类别的可区分特征有着高度的差异性,而这一点在错误分类的样本中并不明显,错误分类的样本其特征表示没有明显突出变化较大的特征;
      3. 在所有样本中都存在或者都激活的特征不太可能是下游任务中用于区分某个类别的特征。

      为了研究单个特征对分类正确与否的影响,作者进一步绘制了主要特征和噪声特征的热图,如下所示:

      img

      可以看到对于正确分类的样本,主要特征能够捕捉到类别相关的特征,而分类错误的样本,主要特征则包含了太多的噪音和错误的信息;噪声特征的热图则侧重于样本中无信息的部分。因此,作者指出特征表示中包含了很多噪声特征,这些特征对正确分类没有太多的贡献。

      综上所述,作者指出了错误分类的两个原因:

      1. 训练得到的特征表示中缺少类别特定的主要特征;
      2. 主要特征映射到了样本中错误的部分

      基于上述几点,作者希望可以通过利用特征表示的特点用无监督的方式对特征表示进行分类,而不需要下游任务中的标签。

      自监督表征的质量指标

      为了衡量自监督模型学到的特征表示的质量,作者定义了一系列质量指标。

      假定一个 SimCLR 模型,由 ResNet 基本编码器(base encoder,记作 f() )和多层感知机投影层(记作 g() )组成。 这里作者用到的数据增强方式是随机裁剪、随机水平翻转等方式的组合。与 SimCLR 类似,将样本输入基本编码器,分别得到自监督模型的特征表示,用投影层的输出来计算损失函数和训练模型。模型的优化目标是:

      img

      其中, θ\thetaθ是模型参数,

      因为 hih_ihi​会应用到下游任务,为评估特征表示的好坏,作者给出了以下几个质量指标:

      • 均值 :计算每一个特征表示 hih_ihi​ 的均值
      • 标准差 :计算每一个特征表示 hih_ihi​ 的标准差
      • 软稀疏性(Soft Sparsity):计算 hih_ihi​ 中特征小于η\etaη的百分占比
      • L1范数 :计算每一个特征表示 hih_ihi​ 的L1范数
      • max(hi)max(h_i)max(hi​)的Z 分数:逐元素地计算 hih_ihi​ 中最大值并计算 Z 分数,

      为评估以上指标在衡量下游任务中分类效果的好坏,作者研究并绘制了多个sota自监督模型(包括SimCLR、 SwaV、MoCo V2和BYOL)的特征表示关于上述指标的ROC(receiver operating characteristic)曲线和PR曲线。此外,作者还计算了相应的AUROC(ROC曲线下的面积)和AUPRC(PR曲线下的面积)。

      imgimg

      可以看到,L1范数 和 max(hi)max(h_i)max(hi​) 的 分数在各个模型上面都有较为一致的表现,作者进一步可视化了 ImageNet-100 中5000个样本的L1范数和Z 分数。

      img

      可以看到,分类正确的样本的 Z分数普遍高于分类错误的样本,而L1范数则普遍低于分类错误的样本。

      自监督Q分数

      根据前面的实验结果,作者设计了评判特征表示能否容易在下游任务分类正确的质量指标—— Q分数。第 i个样本的 Q分数定义如下:

      img

      Q分数既能衡量出特征表示的稀疏性,又可以判单表示中是否有较高的偏差值的特征(由 Z−SZ-SZ−S core (max⁡(hi))\left(\max \left(h_{i}\right)\right)(max(hi​)) 计算得到)。图 4 和表 1 都展示了作者提出的 Q 分数的性能,可以看出 Q分数在识别下游任务中是否分类正确的特征表示上确实效果明显。

      此外,作者还将 Q分数应用到正则项上面,用于改善自监督模型特征表示的质量

      image-20220522212929433

      其中, α\alphaα是用于选择 Q分数过小的样本的阈值, λ1\lambda_{1}λ1​是正则项系数

      上述公式是常见的正则化公式,但作者指出了这种目标函数会导致特征表示中的某个特征在所有样本中都被激活的情况出现,使得下游任务中很难正确分类,如下图所示:

      img

      为避免这种情况,作者提出了修改后的带正则化的优化目标:

      image-20220522213025877

      其中, H∈R2N×lH \in \mathbb{R}^{2 N \times l}H∈R2N×l是特征表示, ∣H∗,k∣1\left|H_{*, k}\right|_{1}∣H∗,k​∣1​是所有特征表示的第 k个特征(按列)的L1范数, β\betaβ是阈值

      实验

      准确率

      作者将上述 Q分数正则化应用到用 ImageNet-100 预训练的 SimCLR 模型上,正如下表所示,下游分类任务获得了 3.26% 的相对acc提升

      imgimg作者还展示了在应用Q 分数正则化前后每一类的acc变化,发现在 ImageNet-100 的某些类中,应用了 Q分数正则化后,其acc比没有应用Q 分数正则化有明显提高,而某些类会有些下降,acc下降的这些类多是动物超类,这些类别的特征表示存在很多共同特征,比较容易分错类,而应用 Q 分数正则化则进一步放大了错误的特征,促使在下游任务中分错类。

      特征表示

      作者展示了 Q 分数正则化后的自监督模型的特征表示,如下所示:

      img

      img

      和没有用 Q分数正则化的特征表示(图 1 )相比,图 2 的特征表示中的主要特征更加明显;图 7 显示的没有区分分类正确与否的类平均特征表示,其中的特征有了明显清晰的区分;在表 2 中,作者给出了使用 Q 分数正则化前后的AUROC和AUPRC的对比,可以看到,使用 Q 分数正则化后,这两个指标都有明显的下降。以上都证明了 Q 分数正则化的有效性。

      可解释性

      自监督模型的表示空间是稀疏的,大部分特征都接近于0,而这些接近于0的特征几乎在所有样本中都激活,属于噪音特征。作者展示了应用Q 分数正则化前后的特征表示稀疏度的对比,如下所示:

      img

      img

      可以看到,应用Q 分数正则化后,特征表示的平均稀疏度从35%增加到52%,正因为剔除了这些噪音特征,使得特征表示的可解释性得到了提升。

      总结

      作者提出的 Q 分数可以在无监督的方式下预估自监督模型得到的特征表示在下游任务中正确分类的可能性,同时 Q 分数正则化也可以一定程度上改善低质量的特征表示,有助于提高下游任务的分类准确率。

      但是,从论文中看到,作者貌似是用自监督模型学习到的特征表示,或者冻结模型参数,或者直接使用特征表示,用于下游任务的分类。在nlp领域,尤其是大规模预训练语言模型上,一般是fine tuning下游任务,不清楚作者提出的思路在fine tuning上面是否也work呢?

      posted in CV领域
      189****6672
      189****6672