自监督对比损失和监督对比损失的对比
ztj100 2024-11-03 16:15 10 浏览 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
相关推荐
- Vue 技术栈(全家桶)(vue technology)
-
Vue技术栈(全家桶)尚硅谷前端研究院第1章:Vue核心Vue简介官网英文官网:https://vuejs.org/中文官网:https://cn.vuejs.org/...
- vue 基础- nextTick 的使用场景(vue的nexttick这个方法有什么用)
-
前言《vue基础》系列是再次回炉vue记的笔记,除了官网那部分知识点外,还会加入自己的一些理解。(里面会有部分和官网相同的文案,有经验的同学择感兴趣的阅读)在开发时,是不是遇到过这样的场景,响应...
- vue3 组件初始化流程(vue组件初始化顺序)
-
学习完成响应式系统后,咋们来看看vue3组件的初始化流程既然是看vue组件的初始化流程,咋们先来创建基本的代码,跑跑流程(在app.vue中写入以下内容,来跑流程)...
- vue3优雅的设置element-plus的table自动滚动到底部
-
场景我是需要在table最后添加一行数据,然后把滚动条滚动到最后。查网上的解决方案都是读取html结构,暴力的去获取,虽能解决问题,但是不喜欢这种打补丁的解决方案,我想着官方应该有相关的定义,于是就去...
- Vue3为什么推荐使用ref而不是reactive
-
为什么推荐使用ref而不是reactivereactive本身具有很大局限性导致使用过程需要额外注意,如果忽视这些问题将对开发造成不小的麻烦;ref更像是vue2时代optionapi的data的替...
- 9、echarts 在 vue 中怎么引用?(必会)
-
首先我们初始化一个vue项目,执行vueinitwebpackechart,接着我们进入初始化的项目下。安装echarts,npminstallecharts-S//或...
- 无所不能,将 Vue 渲染到嵌入式液晶屏
-
该文章转载自公众号@前端时刻,https://mp.weixin.qq.com/s/WDHW36zhfNFVFVv4jO2vrA前言...
- vue-element-admin 增删改查(五)(vue-element-admin怎么用)
-
此篇幅比较长,涉及到的小知识点也比较多,一定要耐心看完,记住学东西没有耐心可不行!!!一、添加和修改注:添加和编辑用到了同一个组件,也就是此篇文章你能学会如何封装组件及引用组件;第二能学会async和...
- 最全的 Vue 面试题+详解答案(vue面试题知识点大全)
-
前言本文整理了...
- 基于 vue3.0 桌面端朋友圈/登录验证+60s倒计时
-
今天给大家分享的是Vue3聊天实例中的朋友圈的实现及登录验证和倒计时操作。先上效果图这个是最新开发的vue3.x网页端聊天项目中的朋友圈模块。用到了ElementPlus...
- 不来看看这些 VUE 的生命周期钩子函数?| 原力计划
-
作者|huangfuyk责编|王晓曼出品|CSDN博客VUE的生命周期钩子函数:就是指在一个组件从创建到销毁的过程自动执行的函数,包含组件的变化。可以分为:创建、挂载、更新、销毁四个模块...
- Vue3.5正式上线,父传子props用法更丝滑简洁
-
前言Vue3.5在2024-09-03正式上线,目前在Vue官网显最新版本已经是Vue3.5,其中主要包含了几个小改动,我留意到日常最常用的改动就是props了,肯定是用Vue3的人必用的,所以针对性...
- Vue 3 生命周期完整指南(vue生命周期及使用)
-
Vue2和Vue3中的生命周期钩子的工作方式非常相似,我们仍然可以访问相同的钩子,也希望将它们能用于相同的场景。...
- 救命!这 10 个 Vue3 技巧藏太深了!性能翻倍 + 摸鱼神器全揭秘
-
前端打工人集合!是不是经常遇到这些崩溃瞬间:Vue3项目越写越卡,组件通信像走迷宫,复杂逻辑写得脑壳疼?别慌!作为在一线摸爬滚打多年的老前端,今天直接甩出10个超实用的Vue3实战技巧,手把...
- 怎么在 vue 中使用 form 清除校验状态?
-
在Vue中使用表单验证时,经常需要清除表单的校验状态。下面我将介绍一些方法来清除表单的校验状态。1.使用this.$refs...
你 发表评论:
欢迎- 一周热门
- 最近发表
-
- Vue 技术栈(全家桶)(vue technology)
- vue 基础- nextTick 的使用场景(vue的nexttick这个方法有什么用)
- vue3 组件初始化流程(vue组件初始化顺序)
- vue3优雅的设置element-plus的table自动滚动到底部
- Vue3为什么推荐使用ref而不是reactive
- 9、echarts 在 vue 中怎么引用?(必会)
- 无所不能,将 Vue 渲染到嵌入式液晶屏
- vue-element-admin 增删改查(五)(vue-element-admin怎么用)
- 最全的 Vue 面试题+详解答案(vue面试题知识点大全)
- 基于 vue3.0 桌面端朋友圈/登录验证+60s倒计时
- 标签列表
-
- idea eval reset (50)
- vue dispatch (70)
- update canceled (42)
- order by asc (53)
- spring gateway (67)
- 简单代码编程 贪吃蛇 (40)
- transforms.resize (33)
- redisson trylock (35)
- 卸载node (35)
- np.reshape (33)
- torch.arange (34)
- node卸载 (33)
- npm 源 (35)
- vue3 deep (35)
- win10 ssh (35)
- exceptionininitializererror (33)
- vue foreach (34)
- idea设置编码为utf8 (35)
- vue 数组添加元素 (34)
- std find (34)
- tablefield注解用途 (35)
- python str转json (34)
- java websocket客户端 (34)
- tensor.view (34)
- java jackson (34)