乐趣区

关于人工智能:自监督对比损失和监督对比损失的对比

作者 |Samrat Saha
编译 |VK
起源 |Towards Datas Science

Supervised Contrastive Learning 这篇论文在有监督学习、穿插熵损失与有监督比照损失之间进行了大量的探讨,以更好地实现图像示意和分类工作。让咱们深刻理解一下这篇论文的内容。

论文指出能够在 image net 数据集有 1% 的改良。

就架构而言,它是一个非常简单的网络 resnet 50,具备 128 维的头部。如果你想,你也能够多加几层。

Code

self.encoder = resnet50()

self.head = nn.Linear(2048, 128)

def forward(self, x):
 feat = self.encoder(x)
 #须要对 128 向量进行标准化
 feat = F.normalize(self.head(feat), dim=1)
 return feat

如图所示,训练分两个阶段进行。

  • 应用比照损失的训练集(两种变动)
  • 解冻参数,而后应用 softmax 损失在线性层上学习分类器。(来自论文的做法)

以上是不言自明的。

本文的次要内容是理解自监督的比照损失和监督的比照损失。

从下面的 SCL(监督比照损失)图中能够看出,猫与任何非猫进行比照。这意味着所有的猫都属于同一个标签,都是负数对,任何非猫都是负的。这与三元组数据以及 triplet loss 的工作原理十分类似。

每一张猫的图片都会被放大,所以即便是从一张猫的图片中,咱们也会有很多猫。

监督比照损失的损失函数,尽管看起来很可怕,但其实很简略。

稍后咱们将看到一些代码,但首先是非常简单的解释。每个 z 是标准化的 128 维向量。

也就是说 ||z||=1

重申一下线性代数中的事实,如果 u 和 v 两个向量正规化,意味着 u.v=cos(u 和 v 之间的夹角)

这意味着如果两个标准化向量雷同,它们之间的点乘 =1

# 尝试了解上面的代码

import numpy as np
v = np.random.randn(128)
v = v/np.linalg.norm(v)
print(np.dot(v,v))
print(np.linalg.norm(v))

损失函数假如每幅图像都有一个加强版本,每批有 N 幅图像,生成的 batch 大小 = 2*N

在 i!=j,yi=yj 时,分子 exp(zi.zj)/tau 示意一批中所有的猫。将 i 个第 128 个 dim 向量 zi 与所有的 j 个第 128 个 dim 向量点积。

分母是 i 个猫的图像点乘其余不是猫的图像。取 zi 和 zk 的点,使 i!= k 示意它点乘除它本人以外的所有图像。

最初,咱们取对数概率,并将其与批处理中除本身外的所有猫图像相加,而后除以 2 *N-1

所有图像的总损失和

咱们应用一些 torch 代码能够了解下面的内容。

假如咱们的批量大小是 4,让咱们看看如何计算单个批次的损失。

如果批量大小为 4,你在网络上的输出将是 8x3x224x224,在这里图像的宽度和高度为 224。

8=4×2 的起因是咱们对每个图像总是有一个对比度,因而须要相应地编写一个数据加载程序。

比照损失 resnet 将输入 8 ×128 维的矩阵,你能够宰割这些维度以计算批量损失。

#batch 大小
bs = 4

这个局部能够计算分子

temperature = 0.07

anchor_feature = contrast_feature

anchor_dot_contrast = torch.div(torch.matmul(anchor_feature, contrast_feature.T),
    temperature)

咱们的特色形态是 8 ×128,让咱们采取 3 ×128 矩阵和转置,上面是可视化后的图片。

anchor_feature=3×128 和 contrast_feature=128×3,后果为 3 ×3,如下所示

如果你留神到所有的对角线元素都是点自身,这实际上咱们不想要,咱们将删除他们。

线性代数有个性质:如果 u 和 v 是两个向量,那么当 u = v 时,u.v 是最大的。因而,在每一行中,如果咱们取锚点对比度的最大值,并且取雷同值,则所有对角线将变为 0。

让咱们把维度从 128 降到 2

#bs 1 和 dim 2 意味着 2*1x2 
features = torch.randn(2, 2)

temperature = 0.07 
contrast_feature  = features
anchor_feature = contrast_feature
anchor_dot_contrast = torch.div(torch.matmul(anchor_feature, contrast_feature.T),
    temperature)
print('anchor_dot_contrast=\n{}'.format(anchor_dot_contrast))

logits_max, _ = torch.max(anchor_dot_contrast, dim=1, keepdim=True)
print('logits_max = {}'.format(logits_max))
logits = anchor_dot_contrast - logits_max.detach()
print('logits = {}'.format(logits))

#输入看看对角线产生了什么

anchor_dot_contrast=
tensor([[128.8697, -12.0467],
        [-12.0467,  50.5816]])
 logits_max = tensor([[128.8697],
        [50.5816]])
 logits = tensor([[0.0000, -140.9164],
        [-62.6283,    0.0000]])

创立人工标签和创立适当的掩码进行比照计算。这段代码有点简单,所以要仔细检查输入。

bs = 4
print('batch size', bs)
temperature = 0.07
labels = torch.randint(4, (1,4))
print('labels', labels)
mask = torch.eq(labels, labels.T).float()
print('mask = \n{}'.format(logits_mask))

#对它进行硬编码,以使其更容易了解
contrast_count = 2
anchor_count = contrast_count

mask = mask.repeat(anchor_count, contrast_count)

#屏蔽 self-contrast 的状况
logits_mask = torch.scatter(torch.ones_like(mask),
    1,
    torch.arange(bs * anchor_count).view(-1, 1),
    0
)
mask = mask * logits_mask
print('mask * logits_mask = \n{}'.format(mask))

让咱们了解输入。

batch size 4
labels tensor([[3, 0, 2, 3]])

#以上的意思是在这批 4 个种类的葡萄中,咱们有 3,0,2,3 个标签。以防你们忘了咱们在这里只做了一次比照所以咱们会有 3_c 0_c 2_c 3_c 作为输出批处理中的比照。mask = 
tensor([[0., 1., 1., 1., 1., 1., 1., 1.],
        [1., 0., 1., 1., 1., 1., 1., 1.],
        [1., 1., 0., 1., 1., 1., 1., 1.],
        [1., 1., 1., 0., 1., 1., 1., 1.],
        [1., 1., 1., 1., 0., 1., 1., 1.],
        [1., 1., 1., 1., 1., 0., 1., 1.],
        [1., 1., 1., 1., 1., 1., 0., 1.],
        [1., 1., 1., 1., 1., 1., 1., 0.]])
        
#这是十分重要的,所以咱们创立了 mask = mask * logits_mask,它通知咱们在第 0 个图像示意中,它应该与哪个图像进行比照。# 所以咱们的标签就是标签张量([[3,0,2,3]])
# 我重新命名它们是为了更好地了解张量([[3_1,0_1,2_1,3_2]])

mask * logits_mask = 
tensor([[0., 0., 0., 1., 1., 0., 0., 1.],
        [0., 0., 0., 0., 0., 1., 0., 0.],
        [0., 0., 0., 0., 0., 0., 1., 0.],
        [1., 0., 0., 0., 1., 0., 0., 1.],
        [1., 0., 0., 1., 0., 0., 0., 1.],
        [0., 1., 0., 0., 0., 0., 0., 0.],
        [0., 0., 1., 0., 0., 0., 0., 0.],
        [1., 0., 0., 1., 1., 0., 0., 0.]])

锚点比照代码

logits = anchor_dot_contrast — logits_max.detach()

损失函数

数学回顾

咱们曾经有了第一局部的点积除以 tau 作为 logits。

# 上述等式的第二局部等于 torch.log(exp_logits.sum(1, keepdim=True))

exp_logits = torch.exp(logits) * logits_mask
log_prob = logits - torch.log(exp_logits.sum(1, keepdim=True))

# 计算对数似然的均值
mean_log_prob_pos = (mask * log_prob).sum(1) / mask.sum(1)

# 损失
loss = - mean_log_prob_pos

loss = loss.view(anchor_count, 4).mean()
print('19. loss {}'.format(loss))

我认为这是监督下的比照损失。我认为当初很容易了解自监督的比照损失,因为它比这更简略。

依据本文的钻研后果,contrast_count 越大,模型越清晰。须要批改 contrast_count 为 2 以上,心愿你能在上述阐明的帮忙下尝试。

参考援用

  • [1] : Supervised Contrastive Learning
  • [2] : Florian Schroff, Dmitry Kalenichenko, and James Philbin. Facenet: A unified embedding for face recognition and clustering. In Proceedings of the IEEE conference on computer vision and pattern recognition, pages 815–823, 2015.
  • [3] : A Simple Framework for Contrastive Learning of Visual Representations, Ting Chen, Simon Kornblith Mohammad Norouzi, Geoffrey Hinton
  • [4] : https://github.com/google-res…

原文链接:https://towardsdatascience.co…

欢送关注磐创 AI 博客站:
http://panchuang.net/

sklearn 机器学习中文官网文档:
http://sklearn123.com/

欢送关注磐创博客资源汇总站:
http://docs.panchuang.net/

退出移动版