首页 > 其他分享 >MoCo论文详解

MoCo论文详解

时间:2024-08-02 22:53:33浏览次数:21  
标签:编码器 论文 更新 详解 参数 动量 MoCo 字典

文章目录


前言

 MoCo是Facebook团队在2020年提出的一篇论文,论文全称是《Momentum Contrast for Unsupervised Visual Representation Learning》通过动量对比进行无监督的视觉表征学习,MoCo就是Momentum Contrast的缩写。MoCo通过使用对比学习的无监督方法在大规模数据集上进行预训练,然后在下游任务上进行迁移,其在下游任务上的表现在分割/检测等7个任务上优于现有的有监督的预训练方法,在视觉领域有监督方法和无监督方法之间的差距被大大减小。接下来将对MoCo这篇论文进行介绍。

一、对比学习简介

 对比学习(Contrastive Learning)是一种无监督或自监督学习方法,它通过比较样本对来学习数据的表示。这种方法的核心思想是,相似的样本应该在表示空间中彼此靠近,而不相似的样本应该彼此远离。对比学习的典型范式就是:代理任务+目标函数。如下图所示:
在这里插入图片描述
 在监督学习中,模型的输出与标签通过目标函数计算出Loss然后进行反向传播更新参数,而在对比学习中,模型的输出通过代理任务计算出Loss然后进行反向传播,可以理解为代理任务起到了标签的作用,监督模型完成我们指定的任务。举一个具体的例子:

假如我们现在有一些图片,其中图片A和图片B是比较相似的,然后我们将这些图片经过编码器,我们希望相似的图片A和B经过编码器后的输出距离较近,而与其他不相似的距离较远。所以我们要做的就是训练这样一个编码器。这里,图片A和图片B(相似的图片)是正样本对,其他图片是负样本。

 那么如何知道哪些图片是相似的,哪些图片是不相似的呢?这个可以通过人为规定代理任务而进行定义,因此对比学习可以看作是一种无监督或者自监督学习。

二、MoCo理论

 MoCo认为之前的这些基于对比学习的工作都可以归纳为构造一个动态的字典。字典中的key是通过在数据集采样然后通过编码器进行编码得到的。然后通过训练这个编码器,让编码后的查询query与字典中对应的key尽可能相似,而与字典中其他的key相似度尽可能低。构造的这个动态字典应该有两个特性:1.大。一个大的字典可以包含更多的样本,在算相似性的时候更具有一般性。2.一致性。这个字典中的key应该是由同一个或相似的编码器编码得到,这样在与query进行比较时才公平。之前的这些方法都很难同时满足这两个特性。
因为如果想让一个很大的字典中的所有元素都是由相同的编码器得到,那么你的batchsize需要很大才行,但是这样的话你的显卡肯定是装不下的,就算能装下也不好更新参数。可能有聪明的小伙伴会说,那我加个循环分好几个batchsize放进去就可以了,比如字典中需要有1280个元素,每次batchsize为128,循环10次放进去就可以了。但是这样在更新编码器参数的时候,是只根据最后一个batchsize更新的,也就是说1280个元素,只有最后的128个元素参与了更新,这是不符合常理的。
 MoCo的思想是使用队列来构建这个很大的字典,首先将一个batch的数据通过编码器,然后更新队列,让最早的那一批batch出去,然后在队尾放入新的batch,这样字典的大小就与batchsize的大小分离开来,接着在根据当前字典中的key与query算loss,更新编码器的参数。这里有个问题,既然每算一个batch就会更新一次参数,那么这个字典中的每一个batch都是由不同的编码器得到的,那就不符合一致性的特点了。为了解决这个问题,MoCo使用动量来进行编码器的缓慢更新,来近似保持一致。并且由于队列先进先出的特性,最早的编码器产生的batch早就被移出去了,所以字典中的元素可以近似看作是同一个编码器产生的。
其具体框架如下图所示:
在这里插入图片描述
 MoCo使用了两个编码器,分别是左边的编码器q和右边的动量编码器。在论文里这两个编码器的结构是一样的,但是更新后的参数是不一样的。首先会进来一个查询 x q u e r y x^{query} xquery和一个batch的数据 [ x 0 k e y , x 1 k e y , x 2 k e y . . . ] [x_0^{key},x_1^{key},x_2^{key}...] [x0key​,x1key​,x2key​...]分别经过编码器得到 q q q和 [ k 0 , k 1 , k 2 . . . ] [k_0,k_1,k_2...] [k0​,k1​,k2​...],接着使用Contrastive loss计算损失,然后使用梯度下降法更新编码器q,使用动量下降法缓慢更新动量编码器,然后将 [ k 0 , k 1 , k 2 . . . ] [k_0,k_1,k_2...] [k0​,k1​,k2​...]放进字典更新队列。

在大规模数据集上训练完成后,可以认为编码器q已经学到了数据之间的差异,可以把不同的输入映射到不同的空间,然后使用编码器q在下游任务上进行迁移学习。

接下来介绍MoCo中的几个关键点。
代理任务
 MoCo使用的是对比学习,其代理任务使用个体判别任务(instance discrimination task)。如下图所示:有一批数据 [ x 1 , x 2 , x 3 , x 4 , x 5 ] [x_1,x_2,x_3,x_4,x_5] [x1​,x2​,x3​,x4​,x5​],数据 x 1 x_1 x1​经过变换后得到两张图片 x 1 1 , x 1 2 x_1^1,x_1^2 x11​,x12​,这两张图片就是正样本对,对于 x 1 1 x_1^1 x11​来说, x 1 2 x_1^2 x12​是与它相似的,而其他所有图片 [ x 2 , x 3 , x 4 , x 5 ] [x_2,x_3,x_4,x_5] [x2​,x3​,x4​,x5​]是不相似的,是负样本。然后 x 1 1 x_1^1 x11​可以充当查询Query,其他图片就是key。
在这里插入图片描述

损失函数
 MoCo的损失函数为InfoNCE,公式如下:

L q = − log ⁡ exp ⁡ ( q ∗ k + / τ ) ∑ i = 0 K exp ⁡ ( q ∗ k i / τ ) L_q = -\log \frac{\exp(q*k_+/\tau)}{\sum_{i=0}^K\exp(q*k_i/\tau)} Lq​=−log∑i=0K​exp(q∗ki​/τ)exp(q∗k+​/τ)​

这个公式可以看作是K分类的交叉熵损失,K为字典的大小,也就是字典中有多少个元素就是多少类, τ \tau τ为温度系数, τ \tau τ越大,那么softmax后的数值分布越集中, τ \tau τ越小,softmax后的数值分布越分散。 q q q为编码器q的输出, k + k_+ k+​为正样本。

动量更新
 使用队列的方法使得字典变大,但是这也使得动量编码器难以进行反向传播,因为进行反向传播的时候梯度应该回传到所有样本中,而显卡很难装下这么多样本。一个简单的方法是每次更新完编码器q后直接把q的参数赋值给动量编码器,但是如此频繁的参数更新影响力字典中的一致性。因此,MoCo使用动量来更新参数。其公式为:

θ k = m θ k + ( 1 − m ) θ q \theta_k = m\theta_{k} + (1-m)\theta_q θk​=mθk​+(1−m)θq​

其中, θ k \theta_k θk​为动量编码器的参数,动量编码器的参数加上编码器q的参数得到更新后的参数。通过 m m m的大小来控制动量编码器的更新程度。在MoCo中 m m m取0.999。

三、MoCo伪代码实现

#f_q,f_k:编码器q和动量编码器
for epoch in range(epochs):
	f_k.params = f_q.params # 初始化,将q的参数赋值给动量编码器k
	for x in loader: # 假设Batchsize为N
		x_q = aug(x) # 进行图像变换  
		x_k = aug(x) # 进行图像变换  
		q = f_q.forward(x_q) # NxC C为编码后的维度
		k = f_k.forward(x_k) # NxC C为编码后的维度
		k = k.detach() # 去掉梯度,因为也不用梯度进行更新
		# 相当于是损失函数的分子 Nx1
		l_pos = bmm(q.view(N,1,C), k.view(N,C,1))
		# 相当于是损失函数的分母 NxK  K为字典中的元素个数
		l_neg = mm(q.view(N,C), queue.view(C,K))
		# logits: Nx(1+K)
		logits = cat([l_pos, l_neg], dim=1)
		# 对于batch中的每个元素正确答案都是在第一个位置上,也就是0
		labels = zeros(N) 
		loss = CrossEntropyLoss(logits/t, labels)
		# 梯度下降法更新编码器q的参数
		loss.backward()
		update(f_q.params)
		# 动量更新编码器k的参数
		f_k.params = m*f_k.params+(1-m)*f_q.params
		# 更新字典队列
		enqueue(queue, k) # 将最新batch的编码后特征送进队列
		dequeue(queue) # 弹出队列最前面的batch

四、疑问

 其实,对于这篇论文我还是有些疑问:

  1. 既然使用动量的目的就是缓慢更新编码器参数,那我直接不更新不好吗。

  2. 在代码中标签都是0,这样在训练的时候不会过拟合吗?

有知道的小伙伴麻烦在评论区告诉我一下。

总结

 MoCo是一种对比学习方法,使用队列构建了一个动态的字典,然后使用动量学习的方法缓慢更新动量编码器的参数,实现了一个又大又一致性的字典,并且在迁移到下游任务的时候取得了很不错的结果。

标签:编码器,论文,更新,详解,参数,动量,MoCo,字典
From: https://blog.csdn.net/m0_64148253/article/details/140828514

相关文章

  • 论文阅读:Most Probable Densest Subgraphs
    摘要本文提出了一种在不确定图中发现最有可能稠密子图(MPDS)的新方法。不确定图中的每条边都有存在概率,使得计算稠密子图变得複杂。作者定义了稠密子图概率,并证明了计算该概率是#P难的。为了解决这个问题,设计了基于抽样的高效近似算法,并提供了准确性保证。实验结果表明,该方法......
  • 【C语言】操作符详解
    目录一、操作符分类二、移位操作符(1)左移位操作符(2)右移位操作符三、位操作符四、移位、位操作符的综合练习(1)不用临时变量,交换两个整数(2)求内存中整数的二进制中1的个数(3)二进制位置0或置1五、单目操作符六、逗号表达式七、结构体成员访问操作符(1)结构体(2)结构体的声明......
  • C语言数据在内存中的存储超详解
    文章目录1.整数在内存中的存储2.大小端字节序和字节序判断2.1什么是大小端?2.2为什么会有大小端?2.3练习3.浮点数在内存中的存储3.1一个代码3.2浮点数的存储3.2.1浮点数存的过程3.2.2浮点数取的过程3.3题目解析1.整数在内存中的存储在操作符......
  • C语言自定义类型结构体与位段超详解
    文章目录1.结构体类型的声明1.1结构体声明1.2结构体变量的创建和初始化1.3结构体的特殊声明1.3结构体的自引用2.结构体内存对齐2.1对齐规则2.2为什么存在内存对齐2.3修改默认对齐数3.结构体传参4.结构体实现位段4.1什么是位段4.2位段成员的内存......
  • Android开发 - RecyclerView 类详解
    什么是RecyclerViewRecyclerView是Android的一个控件,用来展示长列表或网格的内容,它比以前的ListView更加灵活和高效列表展示:想象你在手机上浏览一个长长的商品列表或图片网格。RecyclerView就是用来展示这样的内容的控件高效显示:如果你有一万件商品,RecyclerView不会一......
  • 【数据结构算法经典题目刨析(c语言)】判断链表是否有环(图文详解)
    ......
  • [Java并发]AQS详解之二
    参考资料Java并发之AQS详解一、概述谈到并发,不得不谈ReentrantLock;而谈到ReentrantLock,不得不谈AbstractQueuedSynchronizer(AQS)!类如其名,抽象的队列式的同步器,AQS定义了一套多线程访问共享资源的同步器框架,许多同步类实现都依赖于它,如常用的ReentrantLock/Semaphore/Co......
  • SSM陈氏商城9pd36 带论文文档1万字以上
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表系统内容:用户,商品分类,商品信息开题报告内容一、研究背景与意义随着电子商务的迅猛发展,线上商城已成为人们购物的重要渠道。SSM(Spring+SpringMVC+MyBatis)框架......
  • 程序员进阶架构知识体系、开发运维工具使用、Java体系知识扩展、前后端分离流程详解、
    场景作为一名开发者,势必经历过从入门到自学、从基础到进阶、从学习到强化的过程。当经历过几年企业级开发的磨炼,再回头看之前的开发过程、成长阶段发现确实是走了好多的弯路。作为一名终身学习的信奉者,秉承持续学习、持续优化的信念。不惜耗费无数个日日夜夜,耗费大量时间精力......
  • 解密编程的八大法宝(三)(附贪心算法、动态规划和字符串匹配算法详解)
    算法题中常见的几大解题方法有以下几种:暴力枚举法(BruteForce):这是最基本的解题方法,直接尝试所有可能的组合或排列来找到答案。这种方法适用于问题规模较小的情况,但在大多数情况下效率不高。贪心算法(GreedyAlgorithm):贪心算法在每一步都选择当前看起来最优的解,希望最终能......