逐字稿 | 对比学习论文综述【论文精读】

对比学习在计算机视觉领域的发展历程,4个阶段:

  1. 百花齐放:方法、模型、目标函数、代理任务都还没有统一。
  2. CV双雄:MOCOv1、SimCLRv1、MOCOv2、SimCLRv2、CPC和CMC的延伸工作、SwaV,这个阶段发展非常迅速,以上这些工作间隔时间都很短,ImageNet上的最好成绩,基本上每个月都在被刷新。
  3. 不用负样本:BYOL及其后续改进,SimSima把所有方法都归纳总结,融入到SimSima框架之中,算是卷积神经网络做对比学习的总结性工作。
  4. transformer:MOCOv3、DINO,用vision transformer开展工作。

        来到了 Transformer 时代,这里我们会提到 MOCO V3 和Dino,因为 vision Transformer 的爆火,我感觉估计有一半儿的视觉的这个研究者都投入了 vision Transformer 的怀抱。所以说对于自监督学习来说,不论你是对比学习还是最新的掩码学习,大家接下来都是用 vision Transformer 去做的.

        当然肯定还有很多其他优秀的工作了。鉴于时间关系,我们这里只是把最有联系的一些工作串到一起,讲讲一下它们的相似之处和不同之处。每篇论文我们也不会精读,只会花 3- 5 分钟就大概讲一下它的研究动机,它的方法以及它的贡献

阶段一:百花齐放 18年-19年中

1、instdisc:提出了代理任务,个体判别任务

        其实这篇论文是没有给它的方法起名字的,但是因为太经典,后面的人都要跟他比,所以没办法,为了简单起见,后面的论文就给他起了个名字叫 Insta DISK,也就是这篇论文提出了我们在上次在 MOCO 讲到过的那个代理任务,也就是个体判别任务。        

        就是MOCO中反复提到的文献61,如果MOCO是一篇里程碑式的工作,那么InstDisc就是巨人的肩膀,就是MOCO提到的memory bank方法的论文

创新点:

        用个体判别+NCEloss,做对比学习,取得了不错的无监督表征学习的结果。同时它还提出了用别的数据结构,去存大量的负样本。以及如何对特征进行动量的更新。

对后来的对比学习的工作起到了至关重要的推进作用。

图1,动机

        受到有监督学习结果的启发:让相似图片聚集在一起的原因,并不是他们有相似的语义标签,而是图片确实长得太像了。基于此提出了个体判别任务,这种无监督学习方式,就是把按类别走的有监督信号推到了极致,就是把每个instance(图片)都看成一个类别,目标是能学一种特征,让我们能把每一张图片都区分开。

图2,方法3

        简单来说就是想通过一个CNN把图片都编码成一个特征,希望这个特征能在最后的特征空间中尽可能的分开(每个图片都是自己的类)

        训练CNN的方法:对比学习,正样本是图片本身,负样本是数据集中所有其他的图片(用memory bank存放大量的负样本)那如果做对比学习,那大量的这个负样本特征到底应该存在哪儿?这篇论文就用了这个 memory bank 的形式,就是说我把所有图片的特征全都存到这个 memory bank 里,也就是一个字典。那对于 image net 这个数据集来说,它有 128 万的图片,那意味着就是说这个 memory bank 里要存 128 万行,也就意味着你每个特征的维度不能太高,否则这个存储代价就太大了,所以这篇论文里就选择了是 128 维,那我们现在走一下这个前向过程,那假如说我们现在的 batch size 是256,就是说有 256 个图片从这块进来,进到这个编码器里面,通过一个 rise 50。所以说最后的这个特征维度是 2048 维,然后把它降维,降到 128 维,这就是每个图片的这个特征大小了。

前向过程:

  1. batch size 是 256 的话,也就意味着我们有 256 个正样本
  2. 编码器:res50(生成2048维度的特征)
  3. 降维:128维(每个图片的特征大小)
  4. 负样本:从memory bank中随机抽(文中抽了4096个负样本)
  5. 用NCEloss去算对比学习的目标函数,一旦更新完网络,就用这个minibatch中的数据样本所对应的特征,去更换原来memory bank中的特征,这样memory bank就得到了更新。

反复这个过程,不停的更新memory bank,让最后学到的特征尽可能的有区分性。

3.3. Proximal Regularization

给模型训练加了一个约束,让memory bank中的特征进行动量式的更新

4.2 实验超参数的设定

算loss的时候,温度设置是0.07,选了4000个负样本,训练200个epoch,bs是256,起始的lr是0.03(MOCO延续了这些超参数的设定)

评价

        所以说 Insta DISK 这篇论文也是一个里程碑式的工作,它不仅提出了个体判别这个代理任务,而且用这个代理任务和 NCE loss 去做对比学习,从而取得了不错的无监督表征学习的结果。同时他还提出了用别的数据结构去存这种大量的负样本,以及如何对这个特征进行动量的更新,所以真的是对后来的对比学习的工作起到了至关重要的推进作用。

2、InvaSpread:可以看做SimCLR的前身

        没有使用额外的数据结构去存储大量的负样本,正负样本来自同一个minibatch,而且只用一个编码器进行端到端的学习。

没有TPU,所以bs设置为256,负样本数量只有(256-1)×2个;缺少SimCLR强大的数据增广;SimCLR提出的mlp projector;所以效果不如SimCLR。

  1. 对比学习的思想:同样的图片通过编码器,特征应该很类似,不同图片的特征应该不类似。
  2. Invariant:相似的图片,特征应该保持不变性
  3. Spreading:不相似的图片和物体,特征应该尽可能的分散开

代理任务:个体判别

正负样本的选取:

        它如何选取正样本和负样本以及正负样本的个数。那我们先看一下前项过程如果 batch size 是256,也就是说上面一共有 256 个图片经过这个数据增强,下面又得到了 256 张图片。那对于 X1 这张图片来说,这个 X1 撇就是它的正样本,它的负样本是所有剩下的这些图片,包括原始的图片以及经过数据增强后的图片。也就是说这个时候你的正样本数量是256,但你的负样本是 256 - 1 乘以2,就是除去这个样本本身之外,这个 mini batch 剩下的所有样本,以及它经过数据增强后的样本,也就是这里为什么要乘 2 都是负样本?

        那这个就跟我们刚才说过的 Insta DISC 那个方法不太一样了,因为对于 Insta DISC 来说,它的正样本虽然是256,那它的负样本是从一个 memory bank 里抽出来的,它用的负样本是4096,甚至还可以更大。

        那这篇论文为什么要从同一个 mini batch 里去选正负样本?是因为这样你就可以用一个编码器去做端到端的训练了,这也就是我们之前 MOCO 里讲过的那个端到端的学习方式。那个图里的方法 a 就是这个方法,那剩下的前向过程都是差不多的,就是说过完编码器以后,再过一层这个全连接层,就把这个特征的维度降得很低,就 low dimension 就变成 128 了。那正样本,比如说就是这个绿色的球在这个最后的特征空间上就应该尽可能的接近,但是这个绿色的球跟别的这些颜色的特征就应该尽可能的拉远。他用的目标函数也是 NCE loss 的一个变体。        

  1. 256张图片经过数据增强,又得到了256张图片。正样本是当前图片数据增强后对应的图片,其余所有图片都是负样本(包括原始图片和经过数据增强后的图片)对于一个batch来说,正样本:256,负样本:(256-1)×2。【和InstDisc不同,InstDisc正样本256,但负样本是从一个memory bank中抽出来的,负样本是4096,甚至可以更大】为了能用一个编码器做端到端的训练,本文从同一个minibatch中选正负样本。【这就是MOCO中讲到的端到端的学习方式】
  2. 编码器+FC(降维),相似的特征在特征空间中尽可能的接近,与其他的特征应该尽可能的拉远。目标函数式NCEloss的变体。

        所以说之所以讲这篇论文,就是因为它刚好属于另一个流派,也就是端到端的学习,而且只用一个编码器,不需要借助外部的数据结构去存储大量的负样本,它的正负样本都来自于同一个 mini batch,那既然它跟 same clear 这么像,为什么它没有取得那么好的结果?那这就是我们之前在 MOCO 那篇论文里反复强调过的,就是这个字典必须足够大,也就是说在你做对比学习的时候,这个负样本最好是足够多,而在这里本文的作者是没有 TPU 的,所以说它的 batch size 就是256,也就意味着它的负样本只有 500 多个。再加上它还缺少像 same clear 那样那么强大的数据增广,以及最后提出的那个 MLP Projector,所以说这篇论文的结果没有那么炸裂,自然也就没有吸引大梁的关注。但事实上,它是可以理解成 same clear 的前身的。

        那前两个工作都是用个体判别这个代理任务去做对比学习的,接下来我们就提一个用别的代理任务做对比学习的工作,也就是 CPC contrasted Predictive coding。那这也很好理解,因为一般机器学习它就分为判别式模型和生成式模型,那个体判别显然是属于判别式范畴的,那肯定就会有一些生成式的代理任务,比如说最常见的这种预测型的任务。

3、CPC:contrastive predictive coding,用预测的代理任务做对比学习。

        CPC 这篇论文其实非常厉害,因为它是一个很通用的结构,它是个图一里说它不光可以处理音频,而且还可以处理图片、文字,以及在强化学习里使用

        这里为了简单起见,它用的是一个音频的信号作为输入。

        它大概的想法是什么呢?就说我们有一个时序的序列,假如说有一个输入x,它从 t 减 3 的时刻到 t 减2, t 减一t,它就当前时刻,这些都是未来时刻。我们现在把之前时刻的这些输入全都扔给一个编码器,而这个编码器就会返回给我们一些特征,然后我们把这些特征给一个自回归的模型,也就这里的 g AR 就是 auto regressive,一般常见的自回归模型就是这种 RNN 或者 LSTM 的模型,所以每一步最后的输出我们就会得到这个红色的东西,也就是它的 CT 就是 context representation,就是代表上下文的一个特征表示。

        接下来他说如果这个上下文的特征表示足够好,就它真的包含了当前和之前所有的这些信息的话,那它应该可以做出一些合理的预测,所以就可以用这个 CT 啊去预测未来时刻的这个 ZT 加1, ZT 加 2 就是未来时刻的这个特征输出。

        那对比学习又是在哪里体现的?你不是总得跟什么东西去对比着学吗?那这里的正样本其实就是这里未来的输入通过编码器以后得到的未来时刻的特征输出,就相当于你做出来的这些预测是query,而真正未来时刻的输出是由这些输入决定的,也就是说它们相对于你的预测来说是正样本。

        那负样本的定义其实很广泛了,比如你可以任意选取输入,然后通过这个编码器得到输出,那它都应该跟你的预测是不相似的,所以这就是 CPC 定义正负样本的方式。那当然了,这套思想是很普适的,你把底下这个输入序列换成一个句子,你当然也可以说我用前面的单词来去预测后面的单词的特征输出,那如果你把这个序列想象成一个图片的这个图片 patch 这个块儿从左上到右下形成一个序列,那你就可以用上半部分的图片特征去预测后半部分的图片特征,总之是非常灵活。

大概想法:有一个持续的序列,把之前时刻的输入给编码器,得到一些特征,把这些特征喂给一个自回归的模型(auto regression,常见的自回归模型就是RNN、LSTM),得到红色的方块(context representation一个代表上下文的特征表示),如果这个上下文的特征表示足够好,就是它真的包含了当前和之前所有的信息的话,那它应该可以做出一些合理的预测,用它来预测未来时刻的特征输出。

对比学习体现在:正样本是未来时刻的特征输出(预测的特征是query),真正未来时刻的输出是由输入决定的。负样本的定义很广泛,比如,可以任选输入,通过编码器得到输出,那预测应该是不相似的。这套思想是很普适的,输入可以换成句子,用前面的单词去预测后面的单词的特征的输出;可以换成一系列的图片patch,左上到右下,可以用上半部分的图片特征预测下半部分的图片特征。

4、CMC:contrastive multiview coding

        这篇论文定义正样本的方式就更为广泛了,说一个物体的很多个视角都可以被当作正样本。 CM seed GL 写得非常好,我们可以来看一下他写的前几句话,他说我们人观察这个世界是通过很多个这个传感器的,比如说我们的眼睛或者我们的耳朵,这些都充当着不同的传感器来给我们的大脑提供不同的信号,然后每一个视角都是带有噪声的,而且有可能是不完整的,但是最重要的那些信息其实是在所有的这些视角中间共享。比如说基础的物理定律或者几何形状,或者说他们的语义信息,这些都是共享的。这里举了一个很好的例子,比如说一个狗既可以被看见的,也可以被听到的,也可以被感受到的。

        所以说基于这个现象,作者就提出了我们是想要学一个非常强大的特征,它具有这种视角的,就是说不管你给我看哪个视角,到底是看到了一只狗,还是听到了狗叫声,你都能判断出这是个狗。所以说 CMC 这篇工作的目的就是去增大这个互信息,就是所有的视角之间的这个互信息,那如果能学到一种特征,能够抓住所有视角下的这个关键的因素,那这个特征就很好了,至少解决一个分类问题不在话下。

        那说了这么多, CMC 到底是怎么样去形成这个正样本和负样本,从而去做对比学习的?它这里用图一来解释一下:它们选取的是 NYURGBD 这个数据集,这个数据集有同时有四个view,就有四个视角,分别是原始的图像以及这个图像对应的深度信息,就是说每个物体离你这个观察者到底有多远,还有就是 surface normal,最后就是这个物体的分割图像

        CMC意思就是说所以你这些不同的输入来自于不同的传感器,或者说不同的模态。但是你所有的这些输入其实对应的都是一整图片,都是一个东西,那它们就应该互为正样本。也就是说当你有一个特征空间的时候,比如说这个特征空间的话,那这 4 个绿色的点在这个特征空间里就应该非常的接近。

        那这时候如果你随机再去挑一张图片,不论你是用图片还是用分割的图像什么的,总之你属于一个不配对的视角的话,那你这个特征就应该跟这些绿色的特征远离。

        所以这就是 CMC 定义正负样本的方式,它的正样本是来自于多个视角的,那一旦定义好了正负样本,剩下的工作就大差不差了。

        那这里我还想再说两个点,首先 CMC 是第一个或者说比较早的工作,去做这种多视角的这种对比学习,它不仅证明了对比学习的这个灵活性,而且证明了这种多视角多模态的这种可行性。所以说接下来 OpenAI 很快就出了 clip 这个模型。也就是说,如果你有一个图片,还有一个描述这个图片的文本,那这个图像和文本就可以当成是一个正样本对,就可以拿来做多模态的对比学习。

        同时, CMC 的这个原班作者人马利用对比学习的思想做了一篇蒸馏的工作,它的意思是说,不论你用什么网络,不论这个网络是好是坏,是大是小,那只要你的输入是同一张图片,那我们得到的这个特征就应该尽可能的类似。也就意味着说,我们想让 teacher 模型的输出跟 student 模型的输出尽可能的相似,他就通过这种方式把 teacher 和 student 做成了一个正样本。从而可以去做对比学习还真的是要大开脑洞。所以说让大家意识到对比学习如此灵活,可以应用到不同的领域, CMC 功不可没。

        另外一个要提的点可能算是一个小小的局限性,就是说当你在处理不同的视角或者说不同的模态时候,你有可能需要不同的这个编码器,因为不同的输入可能长得很不一样,这就有可能会导致就是你使用几个视角,你有可能就得配几个编码器那在训练的时候,这个计算代价就有点高。比如说在 CLIP 这篇论文里,它的文本端就是用一个大型的语言模型,比如说bert,那它的图像端就是用一个VIT,就需要有两个编码器。但这儿其实又回到了我们刚开始讲 VIT 时候,说这个 Transformer 的一个好处,就是说 Transformer 真的有可能同时处理不同的这个模态的数据。而事实上现在已经有人这么做了。今年 i clear 就有一篇投稿叫做MA-CLIP: Towards Modality-Agnostic Contrastive Language-Image Pre-training 用一个transformer同时处理两个模态,效果反而更好。所以说这个可能才是 Transformer 真正吸引人的地方,就是一个网络能处理很多类型的数据,而不用去做针对每个数据特有的改进。


本文定义正样本的方式很广泛,一个物体的多个视角都可以被当做正样本。

第一个做多视角的对比学习,不仅证明了对比学习的灵活性,也证明了多视角、多模态的可行性。【接下来OpenAI就出了clip模型:如果有一个图片以及描述它的文本,这就是一个正样本对,用来做多模态的对比学习】

摘要精彩:人类观察世界是通过多个传感器的,眼睛、耳朵都充当不同的传感器,给我们的大脑提供不同的信号,每个视角都是带有噪声而且带有噪声的,但是最重要的那些信息是在所有视角中共享的,比如基础的物理定律、几何形状、语义信息都是共享的。例:狗既可以被看见,也可以被听见和感受到。基于这个现象,作者提出,我们想要学习一个非常强大的特征,它具有视角不变性。CMC的目的就是增大所有视角的互信息。如果能学习到一个特征,能抓住所有视角下的关键因素,这个特征就很好了。

正负样本的定义:

数据集:NYU RGBD,有四个视角,原始图像、深度信息(距离观察者的远近)、surface normal(表面法线)、物体的分割图像

正样本:虽然不同的输入来自不同的传感器,或者来自不同的模态,但是所有的输入都对应的一个东西,他们就应该互为正样本,也就是,绿色的点在特征空间中应该非常接近。

负样本:如果随机选择一张图片,不配对的,得到的特征就应该远离。

局限性:在处理不同视角/模态的时候,可能需要不同的编码器,因为不同的输入可能长得很不一样,这样计算代价就会高。比如在CLIP中,文本端用的是bert,图像用的是vit。transformer有可能同时处理不同模态的数据【MA-CLIP: Towards Modality-Agnostic Contrastive Language-Image Pre-training 用一个transformer同时处理两个模态,效果反而更好】不用针对每个数据去做特有的改进。


第一阶段的四篇论文,使用的代理任务不同(个体判别、预测未来、多视角多模态)、目标函数不同(NCE、InfoNCE、NCE的其他变体)、模型不同(InvaSpread仅用一个编码器、InstDisc用一个编码器和memory bank、CPC是一个编码器和一个自回归模型、CMC有两个甚至多个编码器)任务不同(图像、视频、音频、文字、强化学习)所以说第一阶段是一个百花齐放的时代,大概是从 18 年到 19 年中的这个样子。

阶段二:CV双雄19年中-20年中

CV双雄指的就是MOCO和SimCLR

1、MoCo

        主要贡献:把之前的对比学习方法归纳总结成一个字典查询的问题。提出队列和动量更新的编码器构造一个又大又一致的字典,能帮助更好的对比学习。

        实现上和InstDisc非常相似,可以说是它的一个改进工作。但是改进简单有效,而且有很大的影响力,这个动量编码器的改进一直沿用到了最新的工作,带来好的效果。

        比如说它就是用这个队列去取代了原来的 member bank 作为一个额外的数据结构去存这些负样本,然后他用这个动量编码器去取代了原来的那个 loss 里的约束项,从而能达到动量的更新编码器的目的,而不是动量的去更新那个特征,从而能得到更好的结果。

        但是整体的出发点以及一些实现的细节都是非常类似的。到底有多类似?我们可以先来看一下 MOCO 的这个实现细节。首先从模型的角度上来说,它们就用的是个残差网络,它的这些基线模型都用的是 rise 50,那其实 insert DIS 连也用的是 rise 50,模型上是一样的。最后每个图片的特征维度也沿用了 128 维,然后这里像 61 一样,它也对所有的特征做了这个 l two 归一化

        至于目标函数 MOCO 采用的是 info NCE,而不是像 Insta DISK 一样是NCE,但是算 loss 的时候用的温度也是 0. 07

        至于说数据增强的方式,也是从 61 直接借鉴过来的,包括后面训练的这个学习率 0. 03,还有训练 200 个epoch,这些也都是跟 61 保持一致的。所以你说 MOCO 是 insidisc 的一个改进型工作也不为过。

        但是 MOCO 真正出色的地方其实在我看来有两点,一个就是它的改进真的是简单有效,而且有很大的影响力的,比如说它的动量编码器在后面的Semcare, v two, B Y O L 1,直到最新的对比学习的工作都还在使用。就是它提出的这个技术不仅在当时帮助 MOCO 第一次证明了使用无监督特征学习,也能比有监督特征学习的预训练模型好,而且还能产生持续的影响力,帮助之后的工作取得更好的结果,所以它的改进是很深刻而且很有效的。

        另外一个可圈可点的地方就是 MOCO 的写作真的是高人一等,非常不一样。其实如果一个简单直白的写作方式,就是说在引言里我们先介绍对比学习是什么,然后再介绍之前的工作有哪些,比如说有端到端的工作,然后有 insidice 这个 memory bank 的这个工作,然后它们各自都有各自的缺点和局限性。所以说我们提出 MOCO 用队列去解决这个大字典的问题,用动量编码器去解决这个字典特征不一致的问题。最后我们结果很好,第一次证明了在下游任务中,我们用一个无监督训预训练的模型也会比有监督预训练的模型好。那这种写法也是一种很简洁直白明了的写作方式,大部分论文的写作都是按照这个套路来的,但是 Moco 的作者明显就高了一个层次:引言中,第一段写CV和NLP的区别,以及到底为什么无监督学习在CV这边做的不好;第二段开始讲对比学习,直接把对比学习的方法总结成一个字典查找的问题;然后在CV和NLP大一统、对比学习被看做字典查找也大一统的大框架下,提出了MOCO这个框架,希望能用一个又大又一致的字典,去整体的提高对比学习的性能。

        而且这样的写作风格还延续到了这个方法部分,没有模型总览图、没有说模型、任务。而是从目标函数入手,说我们用的是InfoNCE,先定义正负样本,然后网络结构,然后实现细节和伪代码。3.1中,为了让MOCO看起来更普适,没有直接定义输入是什么,也没有定义网络结构是什么样

  • 什么样的输入都可以(图片、图片块CPC、上下文的图片块)
  • 网络:query和key的编码器既可以相同(InvaSpread)、部分共享和完全不同的(CMC多个视角所以多个编码器)

所以说 MOCO 的这种写作方式,这种自顶向下的写作方式也是非常值得借鉴的,但这个真的是需要功力,稍有把握不慎别人可能就看不懂了。

2、SimCLR:simple contrastive learning ICML

        介绍对比学习常用SimCLR当例子,因为它概念上更容易理解,方法也很容易解释,只不过就是bs太大,一般人不好上手。

        那我们先来看一下 same clear 到底有多简单。

        我们来看图2。图 2 里说如果你有一个 mini bash 的图片,那假如说是x,那对这个 Mini batch 里的所有图片做这个数据增强,就是不同的数据增强就会得到 XI 和XJ,那同一个图片延伸得到的两个图片就是正样本。也就是说如果你的 batch size 是 n 的话,那你的正样本个数就是n,那负样本的个数就是这个 batch size剩下所有的样本以及它们数据增强过后的样本,也就跟我们InvaSpread 里讲的一样,是 2 倍的 n 减一。

        然后当你有了正负样本之后,你就要对它进行编码,所以说通过一个编码器f,这两个 f 是共享权重了,也就是说其实只有一个编码器了。如果这里你把它想象成是一个 rise 50 的话,你这里得到的 h 也就是你得到的特征表示它是 2048 尾的

        然后 same clear 的一个重大的创新点,就是在这个特征之后又加了一个叫 projector 的东西,也就是这里的 g 函数。这个 g 函数说白了非常简单,它就是一个 MLP 层,就是说只有一个全连接层,后面跟一个 Redu 的激活函数但是就这么简简单单的一层MLP,能让最后学到的特征在 Imagenet 这个分类任务上直接提点将近 10 个点。这个效果是在别的任何的任务里,或者说在有监督学习那边儿是很难观测到的。很少有说加一个全连接层就能直接提点 10 个点,所以说是一个非常有趣而且非常惊讶的结果。

        但是在这个框架里,你可以想象出我有一个特征之后,我再做一个非线性变换就得到了另外一个特征,也就是最后去做对比学习的那个特征,一般这个特征 z 它的维度就会小一点,为了跟之前的工作保持一致性,他们也用了 128 倍。

        最后就是要衡量一下就是这个正样本之间是不是能达到最大的这个一致性。他们采用的是一个叫 normalized temperature skill 的交叉商函数。 normalize 就是说在这个特征后面进行了 l two 归一化, temperature skill 就是说在这个 loss 上成了个套,所以说其实这个 loss 跟之前说的 influence a loss 也是非常接近的。

        那这里还要强调的一个点是这个 projection head 这个 g 函数只有在训练的时候才用,而当你在做下游任务的时候,我们是把这个 projection head 记函数扔掉了,我们还是只用这个 h 这个特征去做下游任务,这样的话我们跟之前的工作也还是公平对比,因为之前他们如果用 raise 50,我们还是用 raise 50,我们并没有多加一层,加上这个 projection head g 函数只是为了能让模型训练得更好。

        到这儿整个方法就讲完了,那确实是很简单。跟 MOCO 比起来,这里只有一个编码器,既不需要 memory bank,也不需要队列,也不需要动量编码器正负样本全都是从同一个 mini batch 里来的,整个前向过程非常的直接,就是图片进入编码器编码,然后 projector 降维,最后算个对比学习的 loss ,非常符合大家对深度学习工作的这个期待。

那我们开始的时候说过之前那个 C a P R 19 的工作,因为 spread 可以看作是 same clear 的前身,那为什么这么说?其实整体的这个思路和结构跟 same clear 是基本一致的,SImCLR 跟InvaSpread的区别其实都写在 same clear 的这个贡献列表里了。

  1. 首先第一个就是他们用了更多的这个数据增强,他们发现对比学习真的是需要很强的数据增强的技术。
  2. 第二个就是他们加了一个这个 g 函数,就是一个可以学习的分线性的变换,就是一个 MLP 层。
  3. 第三个就是他们用了更大的这个 batch size,而且训练的时间更久,他们发现这两个策略都能让网络学到的特征变得更好。

        那乍一看这些贡献,有些读者可能就会觉得这些技术不都或多或少在之前的工作里被提出来过吗?所以说在这篇论文里,作者专门把这个相关工作放到了第七节,相当于文章的最后才去讲这个相关工作。它比较细致的跟之前的这种手工的代理任务做了对比,然后跟最近的这种对比学习的也做了对比。而且作者最后还非常谦虚地写了这么一段话,就是说他们知道基本上所有的这些单个的这些贡献,在之前的工作里都被提出来过了。虽然有的时候这个实现的形式可能不太一样,但是作者强调说 simplier 的这个优越之处就是在于它的成功不是由任何一个单一的设计决定,而是把所有的这些技术结合起来而得到的一个结果。而且作者把详细的消融实验以及他们的这个设计选择全都放到了附录里,所以说作者团队真的是非常贴心而且非常谦虚了。

        而事实上, same clear 这篇文章中提出来的很多技术都对后续的工作产生了长远的影响力。比如说在编码器之后加这么一个 MLP 层,那在之后的MOCO, v two, BYOL 这些工作里全都有使用,还有它使用的这个数据增强的策略在之后的工作里也是被广泛地使用。还有就是它使用 Lors 这个优化器,它去做大 batch size 下的这个模型训练之后, BIOL 也采用了同样的策略,总之 same clear 真的是够简单,而且为后续的很多研究铺平了道路。

        最后我想稍微讲一下 same clear 这篇论文里的这些贡献。第一个就是更多的数据增强,那像这个图 4 里就是 same clear 这篇论文就使用了这么多的这个数据增强的方法,从最开始的这个原始图片,到裁剪到改变色彩到旋转,到使用 cut out,还有使用高新的噪声和高新Blur,以及最后使用 Sober 的这种滤波器。真的是把前人想到的这些数据增强的方式全都用了个遍。

        然后为了让读者知道到底哪些数据增强有用,哪些数据增强没用,作者还做了详细的这个消融实验,在这个图里除了最后一列是average,我们先不看那剩下的数字,就是这 7 种数据增强,也就底下这 7 种数据增强,它们两两互相合并之后的这个效果如何?比如说中间的对角线其实就是使用一个数据增强了,就是说,比如说这个就是使用crop, crop 就一个数据增强,那不是对角线上的那些数字。比如说这个数字就意思就是说同时用了 crop 和 cut out,我们这里会发现其实最有效的两个数据增强就是这个 crop 和这个color,也就是随机的裁剪和随机的这种色彩变换。其他的数据增强其实最后都是锦上添花,可有可无的,但这两个是必须得有的。

        另外一个我很想提的点,就是说 SImCLR 这篇文章提出的这个非线性变换,也就是说在编码器后面加一层MLP,我们可以看它这里画的这个图8,就是说如果 h 是一个 rise 50 出来的特征,也就是 2048 尾的话,z = g(h)那这个 z 就是经过了这个 projector 之后的维度一般是128。然后这里的这个 projection had 就 projector 这个 g 函数,其实里面就包含了一个全连接层,还有一个relu的激活函数,那这个 projection head 就指的是这里的这个 non linear。之所以是 non linear 是因为它有这个 Rellu 的激活层, Rellu 就会把一个线性函数变成非线性。那它这里的这个 Linear 是这个线性是说我不要这个Rellu,加一层全连接层就可以了。那这个 none 呢?其实就是说像 invaspread 或者像 MOCO 一样,就是直接编码器出来的特征,拿去做对比学习,我们就不要这个 projection head。

        然后我们就会发现两个很有意思的现象,第一个现象就是说如果你用这个 NON linear 的层,相比原来什么都不用,这个结果提了十几个点,比如说这里是50,这块都已经是 60 多的这个准确率了,所以说起点是非常显著的。

        第二个观察就是说你这个 z 最后的维度,不论是 3264 还是2048,其实都没太大区别,这也就是为什么对比学习现在一般都选一个比较低的这个特征维度,因为 128 就够了,再高再低,其实最后的结果也没有太大的变化。那因为这里提升 10 个点实在是太过诡异,所以作者还做了很多实验去验证这个想法,比如说在这个表 3 里就又做了一些实验,但是也仅仅是一些实验,并不一定能真的证明这个事,所以这里我也就不多说了。


方法:

  • x:一个minibatch的图片。
  • xi和xj:x经过不同的数据增强,他俩就是正样本。正样本个数就是bs,负样本就是剩下的样本以及他们数据增强后的样本2(bs-1)。
  • f函数:是编码器,两个编码器共享权重。
  • h:编码器得到的特征。
  • g函数:projector,就是一个全连接层跟着一个relu的激活函数。(就是这么的一个简单的,能让最后学到的特征在imagenet这个分类任务上提10个点)。只有在训练的时候用,做下游任务的时候,只用特征。这个g函数只是为了让模型训练的更好,为了公平对比在下游任务上不使用。
  • 最后衡量(名为normalized temperature-scaled的交叉熵函数:normalized是指在特征后面做了L2归一化,temperature-scaled:在loss上乘一个τ)正样本之间是否能达到最大一致性。

前向过程:图片进入编码器编码,然后projector降维,最后算一个对比学习的loss。

SimCLR和InvaSpread的区别:

  1. SimCLR用了更多的数据增强(裁剪、改变色彩、旋转、cutout、高斯噪声、高斯模糊、sobel滤波器)
  2. 加了一个g函数(可学习的非线性变换),就是一个MLP层。
  3. 用了更大的bs,而且训练的时间更久

SimCLR框架中几乎所有单独的组件都出现在以前的工作中,尽管具体的实现可能有所不同。但SimCLR的优势不是任何单一设计的选择,而是把所有的技术结合起来得到的结果。我们提供了一个全面的比较,非常详细的消融实验,在附录C。

SimCLR中提出的很多技术,都对后续的工作产生了长远的影响:

  1. 在编码器之后加一个MLP层(MOCOv2,BYOL)
  2. 数据增强技术
  3. 用LARS优化器去做大bs的模型训练(BYOL)

  • Linear:不要relu,只要一个全连接层
  • Non-Linear(projection head):加了relu激活层,把线性函数变成非线性了
  • None:就像MOCO和InvaSpread,直接拿编码器出来的特征去做对比学习

可以发现:Non-Linear提点效果非常显著;特征维度的大小效果没什么区别,选128就够了。


        读完了 MOCO 和 same clear,接下来就该说 MOCO v two 和 same clear v two 了。因为 MOCO 和 same clear 的结果实在是太过惊艳,所以从 2020 年开始就掀起了一波对比学习的狂潮,基本上每天你只要去刷 archive 都会有对比学习的论文。这波热浪一直到 20 年年底vit出来以后才逐渐消退,那现在我们来看 MOCO way two。 Moco way two 其实是一个只有两页的一个技术报告,严格意义上不算是一篇论文了,但即使只有两页,给我们的这个信息量也是相当大的。

3、MOCOv2 CV的会议

        发现SimCLR的效果很好,技术都是即插即用型。就在MOCO上做很简单的改动:把MLP projection head和更多的数据增强用起来,就刷新了imagenet上的最好成绩,比过了SimCLR。

        具体改进如表1:加了MLP层、更多数据增强、训练的时候用了learning rate schedule、训练更长的epoch

        我们现在先来看在 Imagenet 上的这个结果, image net 上结果就首先它把这个就是灰色了一点的,这个结果就 76. 5,属于是有监督的这个基线模型,然后 MOCO V1 只能达到 60.6,就差的还是比较远的。然后我们可以看到,就在上面加上这个 projection head, MLP 层一下,这个准确率就提高到 66 点儿二了,就一下涨了 6 个点。所以说加这个 projection head 不光是对 SImCLR 有用,对 MOCO 也有用,其实对其之后的很多方法都有用,像 SWAV 里也用了, b l l 里也用了,大家都用。然后如果使用更强的这个数据增强,就是也能提三个点,从 60 到63,但是是不如 MLP 提升的多的。然后如果把这个 MLP 和 augmentation 一起用,就已经到 67. 3 了,就非常高了,再加上这个 cosine 的这个学习率,就是说到 67. 5,还能再提 0. 2 个点,那这个提升就很小了,可以忽略不计。

        最后就是如果训练更长的时间,训练 800 亿 POC 就能再提高很多的 71. 1。 Simpear 的结果也是这样,就是如果它训练更久的话,它的结果也会提升很多。其实一直到现在为止,就连凯明最新的这个 Mae 这个工作,他们也是训练了 1600 个epoch,而且的这个效果还在继续往上涨。就这个无监督学习,它真的是训练的越久或者模型越大,它的结果就会越好

        接下来作者主要就是跟 Sota 去比一下,其实也就是 MOCO VE 和 SIM clear 这些工作了。在只训练 200 个 epoch 的情况下, MOCO v two 比 same clear 高了大概一个点。如果在训练更长的时间,就是说在训练 800 个 epoch 的时候, MOCO v two 能到 71. 1,比 SIM clear 训练了 1000 个 epoch 还要好将近两个点,所以就意味着 MOKO v two 能更好地利用数据,能在更短的时间内取得更好的结果。

        那接下来作者又再次强调了一下为什么要用 MOCO ,以及MOCO相比于 simplier 的这个优越性,其实这个优越性就在于这个硬件你玩不玩得动。接下来他在这个表 3 里说了,这个机器的这个内存以及这个训练的时长是我们接下来要比的。这里面 MOCO v two 的作者使用的机器配置是八张 V100 的这个显卡,我们可以看到的, MOCO 在普通这个 batch size 256 的情况下就能训练,内存只消耗 5 个g,就其实你还有很多的剩余空间,你还可以再加大 batch size 或者再增大这个模型都可以,就它非常省内存,而且训练一个模型也只需要 53 个小时

        在 Imagenet 的这种规模的数据集上来说,两天多的时间已经算是很快了。然后如果这个时候换成 n to n 这种端到端的学习,也就我们之前说的这种英文 spread 或者 same clear,这里主要指的就是 same clear。我们如果只用小 batch size, 256 的时候,其实我们可以看下面这个表 2 same clear 在小 batch size 的情况下只有 61. 9 的结果,相对 MOCO v two 来说就差很多了,为什么呢?因为就是之前说过的就字典不够大,提供的负样本不够多,所以导致对比学习这个对比不是很有效,而且不光是效果低,它的这个内存占用也 7. 4G 也明显高,训练的时长也多了十几个小时,就是全方位都不划算。

        那如果我们想让端到端的这个学习走 4096 的这个 batch size,就是说让它的 performance 变好,就变成 6 十六点儿6,虽然说还没有 MOCO v two 好,但差不多了,就是说像性能上差不多,那它对硬件的要求就太高了。比如说对 GPu 的这个内存要求,它就需要 93 个 g 的内存,他这里画了个角,注意思就是说这只是他们的估计,那因为现在也没有这么大内存的GPU,所以说他只能估计一下,那这个训练时长当然也就不得而知了,因为这种端到端的学习方式,包括same、clear、BIOL、 swap 这些,他们其实默认的都是用 8 台 8 卡机去做训练的。也就是有 64 张GPU,你才能在一两天这个合理的时间内把这个训练完成,而 Moco 只需要一台把卡机就可以在两天的时间内完成。

        所以就像我上次说一样,大佬真的是给我们送福利了,真的是把我们能玩得动的这种对比学习呢,送给了我们。

那说完了 MOCO way too,接下来我们就读一下 simplier way too。但其实 simpler v two 只是这篇论文的一个很小的部分,它只是说了一下怎么从 V1 变到V2,就是一个模型上的改进,而事实上这篇论文大部分的内容都在讲如何去做这个半监督的学习,他主要想说的一个事儿就体现在这个它的这个标题里了,就是说非常大的这种自监督训练出来的这个模型,非常适合去做这种半监督学习。



4、SimCLRv2:Big Self-Supervised Models are Strong Semi-Supervised Learners

Neural IPS 非常大的自监督模型非常适合去做半监督学习

        我们也可以从它的这个模型总览图里看出来,它这个图 3 里就大概说了一下,它们这篇文章分了三个部分,第一个部分就是 same clear v two 了,就是怎样自监督或者说自监督的对比学习去训练一个大的模型出来。然后第二步就是说一旦你有了这么好的一个模型,你只需要一小部分的这个有标签的数据,然后去做一下这个有监督的微调,然后你一旦微调结束了,就相当于你有一个 teacher 模型,你就可以用这个 teacher 模型去生成很多伪标签,这样你就可以在更多的这个无标签的数据上去做这种自学习了。它整个这个框架其实也是受启发于 Google 的另外一篇工作,就 19 年的一篇叫 Noisy student 的工作。

        Noy z student 就是在 Imagenet 的数据集上先训练了一个 teacher 模型,然后在 GFT 300 million 那个数据集上生成了好多好多的伪标签,然后最后一起训练了一个这个 student 模型,而这个 student 模型算是 Imagenet 上的Sota,这大概是 88 点多的这个准确率霸占了 Imagenet 上这个 Sota 了很长时间,可能大概有一年的时间。

        我们其实在讲 vision Transformer 那篇论文的时候, vision Transformer 就跟这个 Noy z student 比过,因为截止到那个时候 Noy z student 还是 image net 上的Sota。

        但这个就跟我们今天要说的对比,学习串烧了就跑偏得很远了,所以我们不会说这个第二部分和第三部分,我们主要就说一下这篇论文的作者是怎么把 same clear V1 变成 same clear V2 的。作者其实就在第三页,大概花了半页的篇幅来讲了一讲怎么把 V1 变成 V2 了,其实大概就是提高了这三个点。第一个就是大家其实都公认的一个事实,就是用更大的模型,无监督训练就会训练的更好,所以他们这里就换了一个更大的模型,就是换了一个 152 层的这个残差网络,同时用了这个 select kernel,就 SK net 就这个骨干网络变得非常的强。这是他做的这个第一点改进。

        然后第二点改进,就是说之前 same clear 说这个 projection had 就是那个 MLP 层,不是特别有用吗?而且 MOCO v two 也证明了特别的有用。最 same clear 的作者就想,那一层都这么有用了,我要把它再变深点儿,会不会更有用?所以它就试了试,变成两层,变成 3 层,这个性能会不会继续提升。最后它发现其实就是两层就够了,就是原来是FCLU,那现在就是 FC red Lu, FC red Lu 将一层变成两层的MLP,这个效果就最好了。所以这个是第二点改进,就是加深了这个 projection head。

        第三点就是他们也使用了动量编码器,他这里说 motivated by 29,29 就是 MOKO v two,这个 20 就是MOCO,就是 simpler 的。作者发现 MOCO 的这个动量编码器诶,真的是很管用,所以他们也想试一试。而事实上这个动量编码器真的管用,后面这个 BOL 他都用了动量编码器。但在这里作者说这个动量编码器在 simplier 里的这个提升并不是很大,可能就提了一个点。具体原因,他们解释说,因为他们已经有非常大的这个 mini batch 了,就要么是4096,要么是8192,所以他们的负样本已经相当多了。所以不论是从字典的大小还是从字典里特征一致性来说, Simpear 都已经做得很好了,所以说你再加这种队列或者加这种这个动量编码器,其实都不会带来很大的提升。

        那其实到这儿呢, same clear v two 就也讲完了,它也是快速的很简单的做了三个改进,第一个就是用更大的模型,第二个就是加深了 projection head,第三个就是也用了动量编码器。所以如果不算半监督学习的内容的话, same clear v two 也是一个两页儿的技术报告。

        而且不论是 same clear V1 还是V2,它都只做了分类这个任务但是 MOCO 就广泛的很多了,我们之前也讲过,至少做了四五个下游的任务,而且刷了很多的数据集,所以 MOCO 系列工作就更 CV friendly,所以它投的都是 CV 的会议,而 same clear、 same clear V1 就是ICML,而 same clear v two 就是 Neuls。所以说投对口的会议也很重要。


  1. 第一部分:SimCLRv2,怎样自监督或自监督的对比学习,去训练一个大的模型出来。
  2. 第二部分:一旦有了一个很好的模型,只需要一小部分有标签的数据,去做一下有监督的微调。
  3. 第三部分:微调结束了就相当于有了一个teacher模型,就可以用这个teacher模型去生成很多伪标签,这样就可以在更多的无标签数据上做自学习了。

我们要看的是第一部分,看作者怎么把SimCLR改进了。

  1. 用更大的模型,无监督训练就会训练的更好。(152层的残差网络,selective kernels网络,骨干网络变得非常强)。
  2. SimCLR证明了projection head很有用(fc relu),那么变深可能会更有用,经过验证发现两层就够了(fc relu fc relu)。
  3. 动量编码器在SimCLR就提升了一个点,可能是因为它本身已经有很大的bs了(4096或8192),负样本已经相当多了。

5、SwAV:Unsupervised Learning of Visual Features by Contrasting Cluster Assignments

        那讲完了 CV 双雄 Moco 和 same clear 之后,我们就来简单的说一下 swab 这个工作。这个 swab 的缩写就是这个是swapped,这个是assignment,这个是wheels。

        它的意思就是说你给定我同样一张图片,如果我去生成不同的视角,就是不同的 views 的话,我希望可以用一个视角得到的特征去预测另外一个视角得到的特征,因为所有这些视角的特征按道理来说都应该是非常接近。

        然后这篇文章具体的做法就是把对比学习和之前的聚类的方法合在了一起,当然这么想也不是偶然,因为首先聚类的方法也是一种无监督的特征表示学习方式,而且它也是希望相似的物体都聚集在某一个聚类中心附近,不相似的物体尽量推开推到别的聚类中心,所以跟对比学习的目标和做法都比较接近。

        另外就是这篇文章的一座,其实之前一直也是做聚类的,他之前就做过 deep cluster 这篇工作,也是一篇非常好的无监督学习的论文。那具体 swap 是怎么和聚类的方法融合起来的?我们来看图一,它就把之前对比学习的方法总结了一下,画到了这个左边,然后把它们的 SwAV的方法画到了右边,这样就比较好对比,看这两种方法到底区别在哪里?

        那左边当然很好理解了,我们已经讲过很多次了,就是同一个图片做两次这个数据增强就得到了X1,X2,然后所有的样本通过一个编码器,那这个编码器里有可能就是一个 raise 50,也有可能是一个 raise 50 加了一个 projection head。它这里没有明说,那反正就是所有的这些都属于一个模型。最后这个模型就给我一个特征,一旦你有了这个特征,你用它去做一个对比学习的 loss 就可以了。

        但是 swab 说你这么做虽然比较简单,但是你直接拿所有图片的这个特征去跟特征去做这个对比,有点儿原始,而且有点儿废资源,因为所有的图片都是自己的类,所以即使我们像 MOCO 一样取了6万个负样本,这还只是个近似。因为其实你所有的数据集,所有的负样本,那理应是 128 万个图片的。

        那 swamped 作者就是想,那我们能不能不去做近似呢?我们能不能借助一些先验信息,不去跟大量的负样本比,而去跟一些更简洁的东西比?然后 swap 的作者就想出来了,那我们可以去跟这个聚类的中心比,那剧烈中心就是右图里画的这个c,也就这个prototype,它其实就是个矩阵,它的维度是 d 乘以k, d 就是特征的维度,这里的 d 和这里特征的这个 d 是一样的。比如说就是我们之前说的 128 维,这个 k 就是说你有多少个聚类中心,那在这篇文章中他们选的是3000,也就是说你有 3000 个 cluster center。 3000 这个数字也是之前的一些聚类方法,在 image net 这个数据集上常用的一个参数。

        那一旦有了这个 c 之后,我们来看一下 swap 的这个前向过程,那前面还是都一样的。你有一个 mini bash 的图片,你做两次数据增强,得到X1,X2,分别通过编码器,然后得到最后的特征z, e 和there。当你有了z, e 和 there 之后,你并不是直接在这个特征上去做对比学习的loss,而是说你先通过一个 clustering 的方法,让你这个特征 z 和这个 prototype c 去生成一个目标,也就是这里的Q1Q2,那这个 Q1Q2 就相当于是一个 ground truth 一样的东西

        那它真正要做的这个代理任务是什么呢?它的意思是说,如果你这个X1、 X2 是正样本的话,那你这个 Z1 和 Z2 的特征就应该很相似。也就跟之前对比学习这块儿说的是一个事儿,就你这个 Z1 和 Z2 要尽可能的相似,那如果说你这个两个特征非常相似,或者说含有等量的信息的时候,你按道理来说应该是可以互相去做预测的。也就是说,如果我现在拿 Z1 这个特征去跟 c 去做点乘古,按道理来说也是可以去预测Q2,反之亦然。就这个 Z2 和这个 c 去做点乘,你也可以去预测这个 Q1 的,所以说这个点成之后的结果就是我们的预测,而 ground truth 就是之前按照 clustering 分类而得到的这个 Q1 和Q2,所以通过这种 swap to prediction 就是换位预测的方法, swap 可以对这个模型进行训练。

那我们现在来强调一下用聚类的好处到底有哪些。首先就像 swab 这篇论文里讲过的一样,如果你是要跟很多的负样本去做类比,你可能就需要成千上万的负样本,而且即使如此,你也只是一个近似。而如果我们现在只是跟聚类中心去做对比,我们可以用几百或者最多 3000 个聚类中心就足以表示了,因为其实也并没有那么多类,你看 Imagenet 也就 1000 类, Coco 才 80 类,所以说 3000 个聚类中心就足够用了,那这个相对于几万个负样本来说还是小了很多的。

那第二个用聚类的原因就是说这些聚类中心它是有明确的语义含义的。而如果你之前只是随机抽样负样本去做对比的话,那些负样本有的可能还是正样本,而且有的时候抽出来的负样本这个类别也不均衡,所以不如使用聚类中心有效。那其实这个就是 swab 的基本思想了。如果对聚类算法比较感兴趣的同学,我推荐你们可以先去看 deep cluster, deep plaster two,然后再来看这篇 swap 的论文,相信你肯定会有很多收获。那之前几篇论文我们都没有看结果,因为如果每次都看,结果就有点多余,因为其实都是一条线的工作,那是swab,因为它的结果非常好,它不仅比我们之前讲过的方法这个效果好,它其实比我们之后要讲的BIOR, same Sam 这些都好。

算是卷积神经网络里用 rise 50 分刷的最高的一篇工作了,也就是这里看到的 75. 3。这个表里的性能其实做的还是 image net 上的这个 linear evaluation。也就我们之前说的就是你提前预训练好一个模型以后,我们把这个模型的 backbone 冻住,我们只训练最后的那个全连接层。

我们可以看一下,之前不是对比,学习的方法都还比较低,可能都是在 60 以下。那有了对比学习以后,从 MOCO 开始基本上就上 60 了,然后 c p c VR 刷到 63. 8, same clear 刷到70, MOCO VR 刷到 70 一点儿一之后我们讲的 BIOL 就是 7 十四点儿几, same Sam 好像也是七十四点儿几,所以说 swab 的这个 7 十五点儿三就算是最高的了。而且这个七十五点儿三是你把 backbone 冻住的情况下去做的。

如果你跟这里有监督的基线模型去比的话,这个有监督的基线模型可是从头到尾都在 Imagenet 上训练的,那最后的结果也就是 76. 5,所以说 swam 已经是非常逼近这个结果。而且当你使用更大的模型的时候,也就是像这个右图里说的一样,就是你把一个 rise 50 它变宽,也就是这里的两倍,四倍五倍这么宽的时候, swab 的结果还能不停地涨,当用最大的模型就是用 5 倍的模型的时候, swab 已经跟有监督的模型差距非常的小。而且 swab 也是要被 semclear 乘2, semclear 乘 4 也要高的,所以说从性能上来讲, SWAB 是真的不错。

但其实让 SWAB 有这么好的性能,不光是因为它和聚类的方法融合在了一起,它另外一个主要的性能提升点来自于一个 trick 叫 Multi crop,它的意思就是说你之前的那些对比的学习方法都是用的两个crop,也就是说你就是一个正样本,对X1, X2 就两个图片。比如像我们左下角这个图画的一样,本来我们有一个图片,先 resize 到 256 * 256,然后我们就随机 crop 两个 224 * 24 的图片当成X1,X2,那因为这两张图片都非常大,所以它们重叠的区域也非常多,于是它们就应该代表是一个正样本。但总之就是两个crop。

那 swap 的作者就想了,你用这么大的这个crop,你明显抓住的是整个场景的这个特征,如果我更想学习这些局部物体的特征,又该怎么办?所以说最好我们是能多个crop,也就是说我去这个图片里去多去 crop 一些区域,那这样不就能关注到一些局部的物体了吗?但是你增加这个crop,也就是说你增加这个wheel,你这个模型的计算复杂度一下就上去,因为你相当于使用了更多的正样本。那如何能同时使用更多的正样本,而又不增加太多的这个计算成本,那作者就想了这么一个招,就是说我做点儿取舍。原来我不是取了两个 224 * 224 的这个 crop 吗?那我现在把这个 crop 变得小一点,我变成160,也就是说我取两个这个 160 的这个crop,去争取学这个全局的特征,然后为了增加正样本的数量,为了学一些局部的特征,我再去随机选 4 个这个小一点,它就叫crab。

然后这四个 crab 的大小是 96 * 96,那这样的话就意味着你现在有 6 个视角了,而不是像原来一样只有两个视角,所以你的正样本的数量增多了。但是通过这么一种取舍,你整体的这个计算代价还是差不多的。别看这个想法很简单,但这个 Multi crop 的技术真的很有用,而且它不光是对 swap 有用,它对其它的这个对比学习的方法也有用。

作者其实在后面这个图丧里就做了一些实验,这里我们可以看到这个基线模型就是 2 * 24,然后他们用了 Multi crab 的这个技术,就是 2 * 160 加上 4 * 96。那如果现在我们把这个 Multi crab 的技术用到 same clear 上会如何?你会发现它涨了 2 点儿四个点,这个涨幅还是非常明显。所以说其实我觉得如果把 Multi crop 这个技术用到 BYOL 上,有可能 BYOL 会比 swap 的效果高。

给定同一张图片,如果去生成不同视角的话,希望可以用一个视角得到的特征去预测另一个视角得到的特征,因为所有视角得到的特征应该都是非常接近的。

本文方法:对比学习+聚类。

聚类也是一种无监督表征方式,希望相似的物体都聚集在某一个聚类中心,不相似的物体尽量推开到别的聚类中心,所以和对比学习的方法也比较接近。

  1. 左边是过去的对比学习方法:图片经过不同的数据增强,通过编码器得到特征,然后对特征做一个对比学习的loss。
  2. 右边是SwAV:认为特征和特征作对比,有点费资源,因为每个图片都是自己的类,那么剩下的都是负样本,负样本太大只能取近似,能不能不做近似?能不能借助一些先验信息,不去和大量的负样本比,而去跟一些更简洁的东西比呢?

去跟聚类中心比,就是右图中的 prototypes C(矩阵,维度是D×K,D是特征的维度,K聚类中心的个数)

前向过程:一个minibatch的图片,做两次数据增强,分别通过编码器得到两个特征,让特征和prototype C去生成一个目标,也就是Q1和Q2(相当于ground truth)。

Swapped prediction:按道理x1和x2是同一张图片,他们是一对正样本,那么生成的特征应该很相似,Z1·C可以预测Q2,点乘的结果就是预测;ground truth就是聚类分类得到的Q1和Q2。通过换位预测的方法,SwAV可以对模型进行训练。

用聚类的好处是什么?

  1. 如果要和很多的负样本作类比,可能就需要成千上万的负样本,即使如此,也只是个近似。而现在如果只是和聚类中心对比,用几百甚至3000个聚类中心就足以表示了,因为其实也并没有那么多类,imagenet也就1000类,COCO才80类,所以3000个聚类中心就足够用了,这相当于几万个负样本来说,是小了很多的。
  2. 这些聚类中心是有明确的语义含义的,之前只是随机抽样负样本做对比的话,可能类别不均衡甚至可能是个正样本的,所以不如使用聚类中心有效。

不仅比之前讲过的方法效果好,还要比接下来要讲的BYOL和SimSiam效果都要好。算是卷积神经网络里,用res50分刷的最高的一篇工作了。

对比做的是imagenet上的Linear classification,就是提前预训练好的模型,冻住主干网络,只训练最后的分类头(MLP层)。前六个不是对比学习的方法,结果都比较低。有了对比学习开始,MOCO就开始上60了。

SwAV是把主干网络冻住情况下做的,都已经非常逼近从头到尾都在imagenet上训练的有监督基线模型。

右图是只把res50变宽,SwAV的结果还能不停的涨。当用5倍的模型的时候,SwAV的结果已经和有监督的模型差距非常小。

SwAV的性能这么好的原因:

  1. 和聚类的方法融合。
  2. multi-crop:一个trick。之前的对比学习方法用的是两个crop,就是一个正样本对就是两个图片x1和x2,如图所示,图片先resize到256*256,然后随机crop两个224*224的图片当成x1和x2,因为两张图片都非常大,所以重叠的区域也非常多,他们代表一个正样本,总之就是两个crop。这么大的crop抓住的是整个场景的特征,如果想学习局部物体的特征该怎么办?

所以最好能多个crop,就能关注到局部的物体了。但是增加crop(文中的view)模型的计算复杂度一下就提高了,相当于使用了更多的正样本,如何能使用更多的正样本,而又不增加更多的计算成本?

方法:把crop变小,取两个较大的crop争取学到全局特征,然后为了增加正样本的数量,为了学习局部特征,再去随机选4个小一点的crop。正样本数量增多了,但是通过取舍,整体的计算代价是差不多的。

这个multi-crop技术很有用,而且不仅对SwAV有效。

如图,基线模型就是2*224,用了multi-crop技术的效果。

  • SimCLR涨了2.4个点。
  • 聚类的方法用了这个技术,提点效果更显著。

如果不用multi-crop这个技术,SwAV的效果和mocov2是差不多的,也就是说一个纯聚类的方法,或者聚类和对比学习结合的方法,其实并没有什么优势,真正提点的是multi-crop这个技术,而且这个技术非常普适,思想也很简单,就是全局和局部的特征都要关注。所以接下来的很多工作借鉴的都是multi-crop这个技术,而不是SwAV这篇工作本身。



50:03



  • CPCv2:用了更大的模型、用了更大的图像块、做了更多方向上的预测任务、把BN换成了LN、使用了更多的数据增强
  • infoMin:What Makes for Good Views for Contrastive Learning,到底选择什么样的视角才能对对比学习更好。infomin原则:最小化互信息,以前都是最大化互信息,都是想要两个视角之间的互信息达到最大,本文是想要恰好合适的互信息,如果最后互信息比你所需要的互信息要多,那也是一种浪费,而且有可能泛化做的不好。如果互信息比需要的少,可能就达不到最优的性能。所以作者的意思就是,不能一味的最大化互信息,而是要不多不少刚刚好,按照infomin的原则,去选择合适的数据增强,然后拿到合适的对比学习视角,作者发现对于很多的方法都有提升。

第二阶段,很多细节已经趋于统一了

  • 目标函数都是infoNCE或者其变体
  • 模型都是用一个编码器后面加一个projection head
  • 更强的数据增强
  • 动量编码器
  • 训练的更久
  • 准确度逐渐逼近有监督的基线模型



52:08



第三阶段:transformer,不用负样本的对比学习。

第二阶段讲的SwAV已经有这个趋势了,算是承上启下的工作,因为他也没有用负样本,用的是聚类中心,但还是有一个明确的对比的对象的。但这个阶段的工作,已经没有负样本或者聚类中心了,就是正样本自己在玩。



52:35



BYOL:自己跟自己学

Bootstrap Your Own Latent

A New Approach to Self-Supervised Learning

  • Bootstrap:在一定基础上改造
  • Latent/hidden/feature/embedding:特征

为什么不用负样本这么新奇?

因为在对比学习中负样本是一个约束,在算目标函数的时候,只有正样本,那么目标只有一个:让所有相似的物体的特征也尽可能的相似,这时候就有一个很明显的捷径解,就是说如果一个模型,不论什么样的输入,都会返回相同的输出,那么出来的所有特征都是一模一样的,那这个去算对比学习的loss就都是0,意思就是模型直接躺平了根本不用学,直接用这个捷径解trivial solution,就能完美解决你的问题。只有加上负样本这个约束,不光相似的物体要有相似的特征,不相似的物体要有不相似的特征,这样模型才有动力继续学,因为如果输出的所有特征都一样,那么负样本这边loss就无穷大,所以模型必须想办法让正样本和负样本的loss都往下降,达到一个最优解。所以负样本在对比学习里是个必须的东西,能防止模型学到这个捷径解(model collapse或learning collapse)。

前向过程:

  • 一个minibatch的输入x
  • 经过两次的数据增强后得到了v和v'
  • 通过编码器得到特征,两个编码器使用同样的架构,但是参数不同,上侧的参数随梯度更新而更新,下侧编码器用动量更新的方式更新参数
  • projection head,通过g函数来降维,网络结构相同参数不同,下侧动量更新。得到两个特征。
  • BYOL在上侧加了一个层(MLP)得到一个新的特征。让这个新的特征和下侧特征尽可能一致,把一个匹配问题变成了一个预测问题。(和SwAV有点像,就是换成预测问题,但是借助了聚类中心去帮助做预测任务)相当于用一个视角的特征去预测另一个视角的特征。通过这种预测性的任务去完成模型的训练。

代理任务是对比学习为了预训练模型所定义的任务,为了训练模型。

  • 个体判别任务:自成一类,让两个特征尽可能接近。
  • 预测型的任务:预测对比

和其他工作同样的,训练完成之后只留下编码器,用上侧一次编码的特征yθ去做下游任务

目标函数:MSE loss,让预测的特征和下侧的特征尽可能的接近。



58:23



博客复现BYOL,因为BN的一个细节复现不出来

SimCLR的projection head的细节:fc bn relu fc bn第一个全连接层2048*2048,第二个全连接层2048*128就把维度降下去了,这个128的特征就是最后用来做对比学习的那个特征。

MOCOv2的projection head细节:fc relu fc 2048*2048→2048*128

BYOL的projection head细节:fc BN relu fc 2048*2048→2048*128

这篇博客复现借鉴了写的非常漂亮的MOCOv2代码,MLP中少了一个BN,模型的学习就坍塌了

projection MLP norm:projector中是否用BN,还是其他归一化方式

prediction MLP norm:训练中是否用BN,还是其他归一化方式

Loss function:目标函数

contrastive:对比

  • random:随机初始化的残差网络,用这个残差网络抽特征,在特征上训练一个全连接层,最后的结果是28.8。随机结果(没有学习)
  • BYOL:如果做的是正确的BYOL,就是在projection head和prediction head中都用了BN,结果是57.7最高。
  • no normalization:这是他们做错了的,在projection head和prediction head中都没有用BN,结果只有28.3,就是模型坍塌了什么都没学到
  • 仅在projection head中用BN,和仅在prediction head中用BN,效果都还可以,说明模型没有坍塌,有在学习。
  • 如果把projection head和prediction head中的BN换成LN,效果又不行了

作者就知道BYOL模型没有坍塌肯定和BN有关系:

注:BN是什么,就是把一个batch里所有样本的特征拿来算均值和方差(running mean和running variance)。然后用这个整个batch算来的均值和方差去做归一化,在算某个样本的loss的时候,其实也看到了其他样本的特征,这里面是有泄露的。MOCO中就做了一个shuffle BN,为了防止信息泄露。

作者说因为BN中有信息泄露,所以你可以把batch里的其他样本想成一种隐式的负样本。换句话说,当你有了bn的时候,BYOL其实并不是只是正样本在自己和自己学,其实也在做对比,BYOL做的对比任务就是:当前正样本的图片,和BN产生的平均图片的差别(这和SwAV的不用负样本而是聚类中心去对比是相似的,就是一种聚类中心的意思)

BYOL的作者就急了,因为如果这么解释的话,BYOL就是还是没有逃脱对比学习的范畴,于是BYOL就做了其他实验证明为什么模型没有坍塌。



01:05:32



BYOL works even without batch statistics:BYOL即使没有BN也可以工作,想说明BYOL的成功不是因为BN

BYOL是基于SimCLR上做的,这个详细的消融实验,

  1. BN确实比较关键,没有BN的BYOL确实就不学了,但SimCLR还在学
  2. 有一组实验:Projector有BN,BYOL还是训练失败了,这就不能说明BN关键了。因为如果BN能提供隐式负样本的话,这里训练就不应该失败。
  3. 当编码器和Projector都没有BN的时候,SimCLR也失败了,因为SimCLR没有predictor所以无所谓的。说明没有归一化的时候,不光BYOL,SimCLR也不行了,即使用了负样本也训练不出来。这就说明BN不是提供了一个隐式负样本,因为SimCLR提供了显式的负样本也训练不出来。

于是BYOL作者和博客作者达成一致:BN跟它原来的设计初衷一样,主要的作用是帮助模型稳定训练,提高模型训练的稳健性,让模型不会坍塌。

BYOL在本文的3.3中给出解释:如果一开始就能让模型初始化的比较好,那么后面的训练即使离开了BN也没问题。

weight standardization :一种模型初始化的方式

group norm:一种归一化的方式

这两个方法是VIT的原班作者在它们之前的论文BEIT中提出来的,Resnet v2就是用这种方式做训练。

BYOL(+GN+wS) achieves 73.9%:BYOL换上GN和WS之后也能达到用BN的结果,而这两个方法都没有计算batch统计量。所以这个BYOL是没有跟minibatch中的其他样本做对比的,也就是没有隐式对比。说明BYOL还是一个全新的方式,能自己跟自己学就能学的很好。



01:09:35



Exploring Simple Siamese Representation Learning,SimSiam对对比学习进行分析,化繁为简

SimSiam

  1. 不用负样本,基本上和BYOL很相似
  2. 不需要大的bs
  3. 不需要动量编码器

不仅不会模型坍塌,而且效果还很好。

为什么叫孪生网络:两个编码器网络结构相同且共享参数,整体架构和BYOL非常像,不同只在于SimSiam没有用动量编码器。

前向过程:得到两个视角之后先过编码器得到特征,然后通过predictor去得到预测,两边都预测,所以是一个对称性的loss:既可以做p1预测z2,也可以做p2预测z1的任务,但因为加了两次,所以要除以2

然后就是梯度回传更新网络

D函数表示loss的计算:MSEloss

结论:之所以SimSiam可以训练,不会模型坍塌,主要就是因为有stop gradient这个操作

做了一个假设:因为有了stop gradient这个操作,所以可以把SimSiam想象成一个expectation-maximization算法。因为有了stop gradient这个操作,这一个训练过程或者说这一套模型参数其实就被人为的劈成了两份,相当于在解决两个子问题,模型的更新也是在交替进行的。

可以理解成一个k-means的聚类问题,Kmeans就是分两步走的,每次先要把所有的点分配给一些聚类中心,分配好了以后再去更新聚类中心,再重复做这个操作。从这个角度说,SimSiam和SwAV就有关系了。如图归纳总结了所有孪生网络的做法

  1. SimCLR两边都有梯度回传,做的是一个对比任务
  2. SwAV也是做对比任务,但并没有跟负样本比,而是和聚类中心比,聚类中心是通过SK算法得到的
  3. BYOL不是对比任务,加了predictor变成一个预测任务,用左边去预测右边,同时他们还使用了动量编码器
  4. SimSiam的整个左边和BYOL一模一样,不同的是右边没有用动量编码器而是共享参数了

在imagenet上的Linear classification

  • 只用MOCOv2和SimSiam能用256的bs,其他的工作都要用更大的bs
  • SimCLR和MOCOv2都要用负样本,BYOL完全没用,SwAV用的聚类中心
  • 100epoch的时候SimSiam学的最好,说明学的很快,但是随着训练推进涨幅就小了,动量编码器很好用,很好提点。但是本文主要是把这些trick都拿掉,证明没有这些trick也能训练。

下游任务上,前三个是物体检测,最后一个实例分割(CV人必做的两个下游任务)

  • 针对下游任务的迁移来说,MOCOv2和SimSiam是表现最好的。如果想尝试一些对比学习的工作,会用MOCOv2作为基线模型,因为训练快训练稳而且下游任务迁移的好。



01:17:14



第四阶段:transformer怎么和对比学习有机结合起来



01:17:23mocov3



An Empirical Study of Training Self-Supervised Vision Transformers 自监督的vision transformer,mocov3只是一种架构,卷积神经网络也可以用vision transformer也可以用。

贡献:做了一个很直接、很小的改动,让自监督的vit训练变得更稳定了

mocov3其实相当于mocov2和SimSiam的合体

整体框架:query编码器(backbone+projection head+prediction head,就是BYOL/SimSiam)和key编码器(动量编码器)

目标函数:对称的,既算q2到k1,也算q1到k2,对比学习的loss

因为vision transformer的出现,作者就很想把卷积神经网络换成vit,看看自监督学习+vit就能取得NLP那边的成功呢?

实验:把骨干网络从Resnet换成vit,如图是vit自监督训练的训练曲线,作者发现:

  • 当bs比较小的时候,曲线比较平滑,效果也还行
  • 当bs变大之后,准确度会突然掉下来又恢复,但是就不如原来的高了,最后的准确度也会差很多。按道理说大bs应该会有更好的结果,但是这里大bs的结果却只有69.7

如果能解决这个问题,有可能就能使用更大的bs去训练一个更大的vit,从而得到更好的结果。

4.2 针对这个普遍出现的问题,提出一个小trick,非常普适

如何想到的这个解决方式:观察训练的时候每一层的回传梯度的情况(一般网络训练的不好,不知道为什么的时候,一般首先就是要去查梯度)。作者发现每次loss有大幅的震动,导致准确度大幅下降的时候,梯度也会有一个波峰,这个波峰发生在第一层,就是做patch Projection的时候(patch Projection就是vit论文中的第一步,属于tokenization的阶段,就是如何把一个图片打成patch,然后给它一个特征,做法就是:一个可以训练的全连接层)这个可以训练的全连接层,每次梯度都不正常,那还不如不训练。所以作者就尝试把这个MLP冻住,看结果。(就是随机初始化了patch Projection层,然后就冻住,整个训练过程都不变)问题就解决了。

这个trick不仅对mocov3有用,对BYOL也有用(用BYOL的框架,把残差网络换成vit),把patch Projection层冻住也能获得更平滑的训练曲线,获得更好的训练结果。

因为transformer简单扩展性又好,不改它就只能改开始的tokenization阶段,和结尾的目标函数



01:23:12dino



Emerging Properties in Self-Supervised Vision Transformers

也是自监督训练vit的方式,但是主要卖点在于vit在自监督训练的情况下出现的有趣特性

  • 一个完全不用标签信息训练出来的vit,如果把自注意力图拿出来进行可视化的话,会发现它能非常准确的抓住每个物体的轮廓,效果甚至能媲美直接对物体做分割

dino具体做法:延续了BYOL

self-distillation:和BYOL一样自己和自己学

用student去预测teacher

centering:减掉batch样本的均值。为了避免模型坍塌,把整个batch里的样本算一个均值,减掉这个均值。

和MOCOv3非常像,前向过程一模一样,目标函数多了一个centering操作防止模型坍塌。

第四阶段,



01:25:42



c从方法和模型角度上讲,和第三阶段一模一样,主要是融合了transformer



01:26:01整体过一遍



第一阶段:

  • InstDisc提出了个体判别任务,提出用一个memory bank的外部数据结构去存储负样本,从而得到一个又大又一致的字典去做对比学习
  • InvaSpread不用外部结构的另一条路,端到端学习。只用一个编码器,从而可以端到端学习,但因为受限于bs太小,所以性能不够好。
  • CPCv1提出了infoNCEloss,CPCv1是一个预测型的代理任务,不仅可以做图像,还可以做音频、视频、文字和强化学习,是一个非常全能的结构。
  • CMC把两个视角的任务扩展到了多个视角,给接下来的多视角或者多模态的对比学习打下了铺垫。
  • deep cluster是基于聚类学习的,当时还没有对比学习

第二阶段:

  • MOCOv1是InstDisc的延伸工作,把memory bank变成一个队列,把动量更新特征变成了动量更新编码器,从而能预训练一个很好的模型。moco也是第一个在很多视觉的下游任务上,让一个无监督预训练的模型比有监督预训练模型表现好的方法。属于使用外部数据结构的。
  • SimCLRv1是端到端的延伸性工作,和InvaSpread很像,但是用了很多的技术:加大bs、用了更多数据增强、加了一个Projection head、训练更长时间。所有的技术堆起来,让SimCLR在imagenet上取得了非常好的结果。
  • CPCv2,也把这些技术用了一遍,直接比CPCv1在imagenet上的结果高了三十几个点。
  • CMC把这些都分析了一下,提出了一个infomin的原则:两个视角之间的互信息要不多不少才是最好的

  • MOCOv2发现这些即插即用的技术效果很好,就拿来用。
  • SimCLRv2主要做半监督学习。
  • SwAV把聚类学习和对比学习结合起来的一个工作,取得了不错的效果,这个不错的结果主要来自于它提出的multicrop的技术,如果没有这个技术就和mocov2或者SimCLR结果差不多。

第三阶段:

  • BYOL提出处理负样本太麻烦,不要负样本了,不用负样本做对比了。把对比任务变成预测任务,自己跟自己学就行了。目标函数也很简单就是MSEloss就训练出来了
  • BN BLOG:说BYOL能工作是因为用BN,BN提供了隐式负样本,所以BYOL才能正常训练而不会模型坍塌。
  • BYOLv2:说BN只是帮助了模型训练,如果用另一种方式能提供更好的模型初始化,BYOL不需要BN提供的batch的统计量也可以工作。
  • SimSiam总结了之前的工作,因为之前的工作一直在堆技术,堆多了不好分析,领域就不好推进了。所以SimSiam化繁为简提出来一个很简单的孪生网络的学习方法,既不需要大的bs,也不需要动量编码器,也不需要负样本,照样能取得不错的结果。SImSiam提出的假设就是,stop gradient这个操作至关重要,因为有这个操作的存在,SImSiam可以看作是一种EM算法,通过逐步更新的方式避免模型坍塌。
  • barlos twins更换了一个目标函数,把之前大家做的对比和预测变成了两个矩阵之间比相似性。但因为是21年3月提出的,很快就淹没在vit的洪流之中。

第四阶段:这两个工作都是把骨干网络换成了vit。但是换成vit之后训练不稳定或者不好训练。他们提出了各自的解决方法。两种方法都能有效的提高模型训练的稳健性,防止模型坍塌,让vit用自监督的方式也能训练的很好。

  • MOCOv3:把patch Projection layer冻住
  • DINO:把teacher网络的输出先做一下归一化(centering)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/105226.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

云上攻防-云原生篇Docker安全系统内核版本漏洞CDK自动利用容器逃逸

文章目录 云原生-Docker安全-容器逃逸&内核漏洞云原生-Docker安全-容器逃逸&版本漏洞-CVE-2019-5736 runC容器逃逸-CVE-2020-15257 containerd逃逸 云原生-Docker安全-容器逃逸&CDK自动化 云原生-Docker安全-容器逃逸&内核漏洞 细节部分在权限提升章节会详解&…

SQLite4Unity3d安卓 在手机上创建sqlite失败解决

总结 要在Unity上运行一次出现库,再打包进APK内 问题 使用示例代码的创建库 var dbPath string.Format("Assets/StreamingAssets/{0}", DatabaseName); #else// check if file exists in Application.persistentDataPathvar filepath string.Format…

idea插件开发javax.net.ssl.SSLException: No PSK available. Unable to resume.

idea插件开发,编译出错 javax.net.ssl.SSLException: No PSK available. Unable to resume.at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:129)at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:117)at java.base/sun.security.ssl.…

通讯网关软件024——利用CommGate X2Access实现Modbus TCP数据转储Access

本文介绍利用CommGate X2ACCESS实现从Modbus TCP设备读取数据并转储至ACCESS数据库。CommGate X2ACCESS是宁波科安网信开发的网关软件,软件可以登录到网信智汇(http://wangxinzhihui.com)下载。 【案例】如下图所示,实现从Modbus TCP设备读取数据并转储…

Ubuntu 上传项目到 GitHub

一、前言 GitHub 作为时下最大的开源代码管理项目,广泛被工程和科研人员使用,本文主要介绍如何如何将自己的项目程序上传到 GitHub 上。 要上传本地项目到 GitHub 上,主要分为两步,第一步是 二、创建 SSH keys 首先登录 GitHu…

Jenkins+Gitlab+Docker(Dockerfile)部署

Docker部署运行 ​ 上一篇内容中使用Jenkins(运行服务器)Gitlab(代码存储库)Webhook(网络钩子)的方式部署运行我们的项目。需要我们在服务器上做好很多相关的环境配置及依赖。 ​ 那么假如有这样一个场景:需要把不同技术栈的项目部署到同一台服务器上运行。比如PH…

如何开始使用 Kubernetes RBAC

基于角色的访问控制 (RBAC) 是一种用于定义用户帐户可以在 Kubernetes 集群中执行的操作的机制。启用 RBAC 可以降低与凭证盗窃和帐户接管相关的风险。向每个用户授予他们所需的最低权限集可以防止帐户拥有过多的特权。 大多数流行的 Kubernetes 发行版都从单个用户帐户开始,…

【MySQL × SpringBoot 突发奇想】全面实现流程 · 数据库导出Excel表格文件的接口

文章目录 【MySQL SpringBoot 小点子】全面实现流程 数据库导出Excel表格文件的接口1. 什么是VO(View Object)对象2. BeanCopyUtils进行两个对象的数据转移3. mapper层实现4. service层实现5. vo对象创建6. 保存路径配置7. controller层核心代码实现8.…

JavaFX: 使用本地openjfx包

JavaFX: 使用本地openjfx包 1、注释配置2、下载openjfx包3、导入openjfx的jar包 1、注释配置 build.gradle配置注释: 2、下载openjfx包 下载javaFx地址:https://gluonhq.com/products/javafx/ 3、导入openjfx的jar包

elasticsearch安装

安装elasticsearch 1.部署单点es 1.1.创建网络 因为我们还需要部署kibana容器,因此需要让es和kibana容器互联。这里先创建一个网络: docker network create es-net1.2.加载镜像 elasticsearch的镜像的tar包:点击下载 将其上传到虚拟机中…

电源集成INN3270C-H215-TL、INN3278C-H114-TL、INN3278C-H215-TL简化了反激式电源转换器的设计和制造。

一、概述 InnoSwitch™3-CP系列IC极大地简化了反激式电源转换器的设计和制造,特别是那些需要高效率和/或紧凑尺寸的产品。InnoSwitch3-CP系列将初级和次级控制器以及安全额定反馈集成到单个IC中。 InnoSwitch3-CP系列器件集成了多种保护功能,包括线路过…

gRPC之gRPC Gateway

1、gRPC Gateway etcd3 API全面升级为gRPC后,同时要提供REST API服务,维护两个版本的服务显然不太合理,所以 grpc-gateway 诞生了。通过protobuf的自定义option实现了一个网关,服务端同时开启gRPC和HTTP服务, HTTP服…

京东数据接口:京东数据分析怎么做?

电商运营中数据分析的重要性不言而喻,而想要做数据分析,就要先找到数据,利用数据接口我们能够更轻松的获得比较全面的数据。因此,目前不少品牌商家都选择使用一些数据接口来获取相关电商数据、以更好地做好数据分析。 鲸参谋电商…

2023年中国云计算软件市场规模、市场结构及市场份额情况分析[图]

云计算是分布式计算的一种,指的是通过网络“云”将巨大的数据计算处理程序分解成无数个小程序,然后,通过多部服务器组成的系统进行处理和分析这些小程序得到结果并返回给用户。云计算软件类型分为三类,即基础设施即服务、平台即服…

Python算法练习 10.14

leetcode 2095 删除链表的中间节点 给你一个链表的头节点 head 。删除 链表的 中间节点 ,并返回修改后的链表的头节点 head 。 长度为 n 链表的中间节点是从头数起第 ⌊n / 2⌋ 个节点(下标从 0 开始),其中 ⌊x⌋ 表示小于或等于…

非类型模板参数+模板的特化

目录 一、非类型模板参数 二、模板的特化 (一)函数模板特化 (二)类模板举例 1. 全特化 2. 偏特化 一、非类型模板参数 模板参数分类:类型形参与非类型形参。类型形参即:出现在模板参数列表中&#x…

使用docker搭建kafka集群、可视化操作台

单机搭建 1 拉取zookeeper镜像 docker pull wurstmeister/zookeeper 2 启动zookeeper容器 docker run -d --name zookeeper -p 2181:2181 -v /etc/localtime:/etc/localtime wurstmeister/zookeeper 3 拉取kafka镜像 docker pull wurstmeister/kafka 4 启动kafka镜像 docker…

【玩机】如何修改iPhone充电提示音!最详细简单保姆级教程~ 学费了可替换任意音频做你的专属充电提示音!——后厂村路灯

其实方法很简单,利用快捷指令,获得base64 位的音频文本,然后再充电时播放即可。 视频教程 【玩机】如何修改iPhone充电提示音!最详细简单保姆级教程 具体操作如下: 1.首先,网上找到需要设定的音频&#xf…

Flutter笔记:电商中文货币显示插件Money Display

Flutter笔记 电商中文货币显示插件 Money Display 作者:李俊才 (jcLee95):https://blog.csdn.net/qq_28550263 邮箱 :291148484163.com 本文地址:https://blog.csdn.net/qq_28550263/article/details/1338…

Pulsar 之架构,客户端以及多区域容灾

Pulsar 之架构,客户端以及多区域容灾 架构BrokersClusters元数据存储配置存储区持久存储Apache BookKeeperLedgersLedgers读一致性托管Ledgers 日志存储 Pulsar 代理服务发现 Pulsar client(客户端)客户端设置阶段Reader interface 多区域容灾备份(GEO-REPLICATION)…