关于深度学习:PixPro自监督论文解读

4次阅读

共计 4214 个字符,预计需要花费 11 分钟才能阅读完成。

PixPro 是第一个通过 像素级比照学习 来进行特色示意学习

上图是整个算法流程图,接下来进行具体解析

前向流传

input是输出图像,维度尺寸是(b, c, h, w)

augmentation:通过对同一张 input 进行随机大小、地位裁剪并缩放到对立大小 224*224,并基于肯定概率下进行随机程度翻转、color distortion、高斯含糊和 solarization 操作,最初生成两张不同视图 view #1 和 view #2,大小都是(b, c, 224, 224)

backbone+projection:view #1 和 view #2 别离送入两个网络分支,高低两分支中都含有雷同构造的 backbone+projection 模块,其中 backbone 模块应用了 Resnet,输入最初一层特色图,大小为(b, c1, 7, 7)。

projection 模块是一个 conv1*1+BN+Relu+conv1* 1 构造,先进行 升维 ,再降维到 256 大小,这样就失去了两个输入大小为(b, 256, 7, 7) 的特色 $x$ 和 $x^{,}$,projection 模块代码如下:

class MLP2d(nn.Module):
    def __init__(self, in_dim, inner_dim=4096, out_dim=256):
        super(MLP2d, self).__init__()

        self.linear1 = conv1x1(in_dim, inner_dim)
        self.bn1 = nn.BatchNorm2d(inner_dim)
        self.relu1 = nn.ReLU(inplace=True)

        self.linear2 = conv1x1(inner_dim, out_dim)

    def forward(self, x):
        x = self.linear1(x)
        x = self.bn1(x)
        x = self.relu1(x)

        x = self.linear2(x)

        return x
        
def conv1x1(in_planes, out_planes):
    """1x1 convolution"""
    return nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=1, padding=0, bias=True)

PPM:是一个自注意力模块,针对 (b, 256, 7, 7) 的输出特色图 $x$

首先依据 cosine 类似度计算出 attention 图,大小为 (b, 49, 49),示意每个特色点与其余特色点的类似度。再对输出特色图进行特色交融,失去输入大小为(b, 256, 7, 7) 的特色图 $y$,PPM 代码如下:

    def featprop(self, feat):
        N, C, H, W = feat.shape

        # Value transformation
        feat_value = self.value_transform(feat)  # 1* 1 卷积操作
        feat_value = F.normalize(feat_value, dim=1)
        feat_value = feat_value.view(N, C, -1)

        # Similarity calculation
        feat = F.normalize(feat, dim=1)

        # [N, C, H * W]
        feat = feat.view(N, C, -1)

        # [N, H * W, H * W]
        attention = torch.bmm(feat.transpose(1, 2), feat)
        attention = torch.clamp(attention, min=self.pixpro_clamp_value)
        if self.pixpro_p < 1.:
            attention = attention + 1e-6
        attention = attention ** self.pixpro_p  # pixpro_p 管制注意力的范畴,默认为 1

        # [N, C, H * W]
        feat = torch.bmm(feat_value, attention.transpose(1, 2))

        return feat.view(N, C, H, W)

Loss:计算 $x^,$ 和 $y$ 之间的 loss。$x^,$ 和 $y$ 的空间地位示意图如下所示:

在数据加强 augmentation 过程中,能够获取裁剪图像的左上角和右下键坐标,因为输入特色图 $x^,$ 和 $y$ 大小为(b, 256, 7, 7),所以每个特色图中有 7 * 7 个特色点,依据插值法就能够获取输入特色图 $x^,$ 和 $y$ 的每个特色点的空间坐标,大小为(b, 2, 7, 7)。

首先计算出不同视图中每个特色点彼此之间的间隔,能够失去大小为 (b, 49, 49) 的间隔矩阵 D,步骤如下:

  1. 特色图 $x^{,}$ 的 x 坐标 $X_{x^{,}}$:(b, 7, 7)->(b, 49, 1),y 坐标 $Y_{x^{,}}$:(b, 7, 7)->(b, 49, 1)
  2. 特色图 $y$ 中 x 坐标 $X_{y}$:(b, 7, 7)->(b, 1, 49),y 坐标 $Y_{y}$:(b, 7, 7)->(b, 1,49)
  3. 间隔矩阵 D =$\sqrt{(X_{x^{,}}-X_{y})^2+(Y_{x^{,}}-Y_{y})^2}/max\_bin$(max_bin 是相邻特色点之间的最大间隔,目标是为了 ” 归一化 ”)

不同视图中距离较近的特色点特色应该具备一致性 consistency,所以对间隔特色 D 依据阈值 ratio 进行二分来获取间隔较近的特色点掩码 M =(D<ratio)

再计算出 $x^,$ 和 $y$ 的特色类似度图 logit,大小为(b, 49, 49),这步与 PPM 中计算注意力类似度相似

最初依据特色类似图和掩码矩阵计算 loss:

$loss = logit * M$

整个 loss 计算残缺过程的代码如下:

def regression_loss(q, k, coord_q, coord_k, pos_ratio=0.5):
    """ q, k: N * C * H * W
        coord_q, coord_k: N * 4 (x_upper_left, y_upper_left, x_lower_right, y_lower_right)
    """
    N, C, H, W = q.shape
    # [bs, feat_dim, 49]
    q = q.view(N, C, -1)
    k = k.view(N, C, -1)

    # generate center_coord, width, height
    # [1, 7, 7]
    x_array = torch.arange(0., float(W), dtype=coord_q.dtype, device=coord_q.device).view(1, 1, -1).repeat(1, H, 1)
    y_array = torch.arange(0., float(H), dtype=coord_q.dtype, device=coord_q.device).view(1, -1, 1).repeat(1, 1, W)
    # [bs, 1, 1]
    q_bin_width = ((coord_q[:, 2] - coord_q[:, 0]) / W).view(-1, 1, 1)
    q_bin_height = ((coord_q[:, 3] - coord_q[:, 1]) / H).view(-1, 1, 1)
    k_bin_width = ((coord_k[:, 2] - coord_k[:, 0]) / W).view(-1, 1, 1)
    k_bin_height = ((coord_k[:, 3] - coord_k[:, 1]) / H).view(-1, 1, 1)
    # [bs, 1, 1]
    q_start_x = coord_q[:, 0].view(-1, 1, 1)
    q_start_y = coord_q[:, 1].view(-1, 1, 1)
    k_start_x = coord_k[:, 0].view(-1, 1, 1)
    k_start_y = coord_k[:, 1].view(-1, 1, 1)

    # [bs, 1, 1]
    q_bin_diag = torch.sqrt(q_bin_width ** 2 + q_bin_height ** 2)
    k_bin_diag = torch.sqrt(k_bin_width ** 2 + k_bin_height ** 2)
    max_bin_diag = torch.max(q_bin_diag, k_bin_diag)

    # [bs, 7, 7]
    center_q_x = (x_array + 0.5) * q_bin_width + q_start_x
    center_q_y = (y_array + 0.5) * q_bin_height + q_start_y
    center_k_x = (x_array + 0.5) * k_bin_width + k_start_x
    center_k_y = (y_array + 0.5) * k_bin_height + k_start_y

    # [bs, 49, 49]
    dist_center = torch.sqrt((center_q_x.view(-1, H * W, 1) - center_k_x.view(-1, 1, H * W)) ** 2
                             + (center_q_y.view(-1, H * W, 1) - center_k_y.view(-1, 1, H * W)) ** 2) / max_bin_diag
    pos_mask = (dist_center < pos_ratio).float().detach()

    # [bs, 49, 49]
    logit = torch.bmm(q.transpose(1, 2), k)

    loss = (logit * pos_mask).sum(-1).sum(-1) / (pos_mask.sum(-1).sum(-1) + 1e-6)

    return -2 * loss.mean()

反向流传

下分支网络不参加间接训练,其中所有的权重参数不具备梯度值。其参数 $param\_k$ 更新形式是基于上分支网络参数 $param\_q$ 动量更新。训练开始前,高低分支网络初始权重保持一致。

$$
param\_k.data = param\_k.data * momentum + param\_q.data * (1-momentum)
$$

其中,momentum 是动量值,整个训练过程从 0.99 逐步增大到 1.0

试验

优化器:LARS,weight_decay=1e-5

lr_scheduler:cosine, warmup

total_batchsize:1024

world size:8 V100 GPUs

与其余基于实例级自监督算法在上游检测宰割工作上的比拟后果

不同超参数下的试验后果

PixPro 和 ProContrast 后果比拟

联合实例级模块的后果

有无 FPN、head、实例级模块的试验比拟后果

正文完
 0