百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分类 > 正文

自监督对比损失和监督对比损失的对比

ztj100 2024-11-03 16:15 23 浏览 0 评论

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=4x2的原因是我们对每个图像总是有一个对比度,因此需要相应地编写一个数据加载程序。

对比损失resnet将输出8x128维的矩阵,你可以分割这些维度以计算批量损失。

#batch大小
bs = 4

这个部分可以计算分子

temperature = 0.07

anchor_feature = contrast_feature

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

我们的特征形状是8x128,让我们采取3x128矩阵和转置,下面是可视化后的图片。

anchor_feature=3x128和contrast_feature=128x3,结果为3x3,如下所示

如果你注意到所有的对角线元素都是点本身,这实际上我们不想要,我们将删除他们。

线性代数有个性质:如果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-research/simclr

相关推荐

sharding-jdbc实现`分库分表`与`读写分离`

一、前言本文将基于以下环境整合...

三分钟了解mysql中主键、外键、非空、唯一、默认约束是什么

在数据库中,数据表是数据库中最重要、最基本的操作对象,是数据存储的基本单位。数据表被定义为列的集合,数据在表中是按照行和列的格式来存储的。每一行代表一条唯一的记录,每一列代表记录中的一个域。...

MySQL8行级锁_mysql如何加行级锁

MySQL8行级锁版本:8.0.34基本概念...

mysql使用小技巧_mysql使用入门

1、MySQL中有许多很实用的函数,好好利用它们可以省去很多时间:group_concat()将取到的值用逗号连接,可以这么用:selectgroup_concat(distinctid)fr...

MySQL/MariaDB中如何支持全部的Unicode?

永远不要在MySQL中使用utf8,并且始终使用utf8mb4。utf8mb4介绍MySQL/MariaDB中,utf8字符集并不是对Unicode的真正实现,即不是真正的UTF-8编码,因...

聊聊 MySQL Server 可执行注释,你懂了吗?

前言MySQLServer当前支持如下3种注释风格:...

MySQL系列-源码编译安装(v5.7.34)

一、系统环境要求...

MySQL的锁就锁住我啦!与腾讯大佬的技术交谈,是我小看它了

对酒当歌,人生几何!朝朝暮暮,唯有己脱。苦苦寻觅找工作之间,殊不知今日之事乃我心之痛,难道是我不配拥有工作嘛。自面试后他所谓的等待都过去一段时日,可惜在下京东上的小金库都要见低啦。每每想到不由心中一...

MySQL字符问题_mysql中字符串的位置

中文写入乱码问题:我输入的中文编码是urf8的,建的库是urf8的,但是插入mysql总是乱码,一堆"???????????????????????"我用的是ibatis,终于找到原因了,我是这么解决...

深圳尚学堂:mysql基本sql语句大全(三)

数据开发-经典1.按姓氏笔画排序:Select*FromTableNameOrderByCustomerNameCollateChinese_PRC_Stroke_ci_as//从少...

MySQL进行行级锁的?一会next-key锁,一会间隙锁,一会记录锁?

大家好,是不是很多人都对MySQL加行级锁的规则搞的迷迷糊糊,一会是next-key锁,一会是间隙锁,一会又是记录锁。坦白说,确实还挺复杂的,但是好在我找点了点规律,也知道如何如何用命令分析加...

一文讲清怎么利用Python Django实现Excel数据表的导入导出功能

摘要:Python作为一门简单易学且功能强大的编程语言,广受程序员、数据分析师和AI工程师的青睐。本文系统讲解了如何使用Python的Django框架结合openpyxl库实现Excel...

用DataX实现两个MySQL实例间的数据同步

DataXDataX使用Java实现。如果可以实现数据库实例之间准实时的...

MySQL数据库知识_mysql数据库基础知识

MySQL是一种关系型数据库管理系统;那废话不多说,直接上自己以前学习整理文档:查看数据库命令:(1).查看存储过程状态:showprocedurestatus;(2).显示系统变量:show...

如何为MySQL中的JSON字段设置索引

背景MySQL在2015年中发布的5.7.8版本中首次引入了JSON数据类型。自此,它成了一种逃离严格列定义的方式,可以存储各种形状和大小的JSON文档,例如审计日志、配置信息、第三方数据包、用户自定...

取消回复欢迎 发表评论: