这段时间浏览了大量的自监督学习方面的知识,今天就通过本篇博客将这些有关方面的知识进行汇总。本文将从SimCLR,MoCo, BYOL等多个模型为切入点做一个自监督学习的总结, 相对于监督学习,这里的自监督任务是无需要标签的学习,可以很好的进行特征抽取模型训练这样很好的减少人工工作量, 其泛化性能强。相对于有标签的学习,我个人认为强监督学习给的标签过于单一,加入认为认知进入,相对于无监督学习来说,模型可以更好的进行自我理解。这类似于教孩子什么是猫,只需要告诉某个猫的样子下次见到其他猫也可以认识。
这里我会按照文章发表的先后顺序进行介绍上述的几个模型。
这里顺便提一下对比学习与自监督学习的关系。
[通过上述的描述我们可以知道类似于MAE, CAE属于生成式(掩码)自监督(传送门),类似于SimCLR等属于对比式自监督。
在介绍自监督对比学习的过程中我们先看下对比学习的发展历程(参考链接)
第一阶段:百花齐放
: InstDisc,InvaSpread, CPC, CMC
第二阶段:CV双雄
: MoCov1, SimCLRv1, MoCov2, SimCLRv2, SWaV
第三阶段:不用负样本
: BYOL, 针对BYOL的博客和他们的回应, SimSiam
第四阶段:基于Transformer
: MoCov3, DINO
一、 第一阶段 百花齐放
1. InstDisc
paper code
该文章属于个体判别任务,如果说MoCo是里程碑的工作的话,该模型则属与开山鼻祖了,使用的是memory bank的方法,后面可以通过看完MoCo这篇介绍再来看这篇文章可以更好的理解 。该任务就是将每个instance(每个图片)当成一个类别进行分类。具体流程如下图所示:
将所有的图片通过卷积神经网络将其编成128维的特征,希望这些特征在128维(不能太高否则不好存储)的空间特征里面能尽可能的分开,因为每个图片都属于自己的类别,每个图片应该和别的图片尽量分开,这里的正样本为数据本身,负样本为数据集其他图片。该方式将128万张图片也就是将128万个特征存储到MemoryBank中,这里的负样本每次抽取4096个负样本进行学习,所以这里用NCE损失函数计算对比函数的目标函数。每次训练完一次网络,需要重新更新MemoryBank内部的特征。该文章还提出了
Proximal Regularization
使得模型进行动量更新。这里使用的目标函数为NCE,详细介绍可以了解MoCo对其损失函数的介绍。
2. InvaSpread
paper code
该文章可以理解为是simCLR的前身,它没有使用额外的数据结构存储大量的负样本,该负样本为同一个min-batch,且只有唯一的编码器。核心思想就是同样的图片编码特征应该很类似,不同图片编码特征应该不类似,如下图所示:
下面这张画详细解释了该模型原理,假设我们的batch-size为256,这样我们就有图 256张图片数据,通过数据增强操作我们得到图片数据 256张图片,对于图片 来说 为正样本,剩下的图片都是负样本(包括原始的图片以及数据增强后的图片,也就是说你的正样本图片是256,但是你的负样本数量为
(256-1)*2
), 最后如下所示,我们希望最后相同颜色的球离得更近。这里使用的是GPU而非TPU,batch-size不大,也没有mlp projector
导致训练效果没有simCLR(之后介绍)效果好。
3. CPC (生成式对比学习)
paper code
该模型不光可以处理音频数据同时可以处理图片,文字以及强化学习里使用。 文章这里使用音频的方法进行举例。首先我们有一个持续的序列,加入输入为从t-3的时刻到t-2(表示过去时刻)到t(当前时刻)以及t, t+3等时刻表示未来时刻。现在我们用过去时刻的音频信息输入到编码器中得到过去音频特征,把这些特征扔给自回归模型(类似与RNN,LSTM模型),这样就得到类似于上述红色部分特征(表示上下文信息),如果该表征足够好,则可以预测未来时刻的特征输出。对比学习的方式则是可以用未来的输出(正样本)或其他音频输出(负样本)与预测的输出做对比学习。这里预测的音频相当于是query,真正未来时刻的输出由这些输入决定的,我们也可也将该音频转成句子也是可以的。
4. CMC
paper code
该文章表示一个物体的多个视角都可以被当作正样本,该文章目的主要是加大不同视觉的互信息。该模型使用了NYU RGBD数据集,该数据集有4个视角,分别表示1. 原始图像信息,2. 图像对应的深度信息(图像距离观测者远近),3.SwAV ace normal, 4.物体分割图像这些应该都是互为正样本,这4个特征在空间上应该非常接近,但是与其他不配对视角的图片距离应该很远。
二、第二阶段CV双雄
1.SimCLR
参考链接 --- paper 【发表于2020-1】 --- code
效果:
基于SimCLR学习的自监督表示训练的线性分类器达到了百分之76.5的top-1精度,比之前的SOTA方法提高了百分之7,与有监督的ResNet-50的性能相当。当仅在百分之一的标签上进行微调时,我们的方法达到了百分之85.8的top-5精度
下面的图片则是描述batch为2的时候的数据的输入
下图则是表示图片之间相似度情况,可以看出对角线相似度最高位1(因为是一样的图片),这里在训练的时候对角线的损失函数是不参与计算的。
损失函数如下所示:
这里公式中分子表示同类,分母表示非同类
, 这里的τ小于1,使得梯度放大,收敛更快,帮助差异更大。
这里有几点需要注意一下:
1. Batch 大小比较重要,原文这里使用的是8192(相当于一个正样本与其他图片互为负样本), 即一个正样本需要与多个负样本对进行匹配,否则模型很难收敛
--针对这种情况何凯明团队创建了MoCo模型,见本文的第三篇文章。
2. 特征提取模块可以是VIT, Resnet等模型
该模型的增广方式如下:
从上图可以看出来在做
Crop
以及Color
两种增广方式效果最好。
后面也发布了SimCLR v2
的版本, 总结如下所示:
这边的改进有三点:
- 加了更大的骨干模型
- 多加一层mlp
- 用了动量编码器
2. MoCo
参考链接 --- paper【v1->2019-11-13, v2->2019-11-14, v3-2020-4-23】 --- code
我们前面说到了simCLR的方法去做自监督的对比学习方法来训练网络提取网络是不是觉得里面有什么操作是很难做的呢? haha ... ,是的就是 batchsize大小,这里面需要的是batch size大小是需要8192,这对于普通计算机来说是非常大的数字,如果过于小的话模型就很难收敛,这是因为一个batch需要一个正样本与多个负样本对进行特征计算。针对这种问题有什么好的方法呢?何凯明等大神发明了MoCo模型基于动量的方式很好的解决问题,这里我们可以这么理解就是大的数据我们可以切分一部分一部分数据,然后依次训练,但是我们再批次进行训练的时候我们仍然保留上一个批次的部分训练权重,如果这里听不懂可以接着看我下面介绍的。这里主要的原因是为了保持整体一致性的特征
, 这里的一致性特征是整个文章的核心,大家可以再文章后面慢慢理解。该文章通过linear protocol
的方式进行了很多下游任务,即将训练的特征提取网络权值进行冻住,然后接着进行下游任务训练,可以证明之前我们抽取的特征是否很好。下面的文章可以看出MoCo在7个下游任务上,包含检测分割, MoCo这种无监督训练方式能超越用ImageNet去做有监督的预训练方式,有时候甚至大幅度超越,其实基于这种无监督训练方式希望基于更大的模型更大的数据集可以有更好的效果,文章基于FaceBook在Instgram 十亿数据集上进行预训练上进行,效果更好。
这篇文章基于动量的对比学习进行模型训练,所以我们首先需要了解两个概念:1. 什么是动量? 2. 什么是对比学习
首先我们稍微理解下什么是动量,我们可以通过下面这个公式对动量有一定的理解:
这里的是超参数, 是这一时刻你想要改变的输出,为上一时刻的输出, 是当前时刻的输入,实质就是不想当前时刻的输出完全依赖于当前时刻的输入,也希望继承之前的输出的信息。接着我们说下什么是对比学习
对于对比学习在前面simCLR中以及提及过这里再稍微解释下,具体可以看我画出的这张图。从下面可以看出,首先在一个数据集随机取一个图片我们称之为, 这里我们也可以称该为anchor,通过以及分别做增广变化得到特征以及特征,将该两个特征分别经过编码器以及编码器(当然这两个编码器可以一样,但是文章是用不同编码器编码分别得到字典特征, 。同时将其他图片我们设置为负样本这里用, 通过增广变化同时也经过相同的编码器编码得到
字典特征。
- 为
query
特征 - 为正样本字典
key
特征 - 为负样本字典
key
特征
这样就形成字典查询问题,对比学习的要求则是希望特征
与特征
尽可能相近,与特征
尽可能远原理
。
为了让模型训练效果得到保证,这里有两点需要注意:
1. 字典要尽可能大
可有理解为当字典越多,我们获取的视觉信息越丰富),当我们拿query与key做对比的时候我们更可能的把物体区分开更本质的特征抽取, 如果字典非常小的话模型容易学到一个捷径(ShortCut Solution),使得预训练模型不具备很好的泛化性。
2. 在训练的时候要保证字典的一致性
,即我们得到的特征 需要用相似的编码器得到,当你在跟query做比对的时候,才能保证对比的一致性,因为我们的负样本很多,我们采用队列的方式批次去做的,在更新我们上述的 的时候我们特征编码器权重同时也在变化,因此就会导致特征存在抽取不一致性的问题,文章很好的使用动量解决了这个问题,这里我们后面还会详细介绍。
下面的图片就很好的解释了MoCo该论文所描述的与上述传统的对比学习不通的地方与原理:
这里有两点需要考虑一个是
queue
一个是momentum
两个主要机制。
1. 字典尽可能大->用队列存储字典
这是首先机器内存,因为这里的字典非常大,队列很大,但是每次更新这个队列则是一点一点进行的。相当于一个队列有多个mini-batch,每次更新新的min-batch的时候,会将最早的mini-batch移除队列,这样就把训练的min-batch与队列分开了, 这样字典就可以设置很大,因为里面大部分的元素都不是每个iteration中所有的mini-batch都需要更新的, 用同一个普通的gpu也可以训练很好的模型。
队列是FIFO(先进先出的结构)
这样使用队列可以把字典大小和mini-batch大小剥离开,我们这里使用的mini-batch大小选用128,为了和其他文章统一。该字典是所有数据的子集吗,即计算损失是近似,而非整个数据集上计算损失。
2.字典特征一致性->动量编码器
文章中需要强调说这里的key需要保持一致性,也就是说需要相似
的编码器而产生得到,但是现在如果只有一小部分也就是当前batch是从当前的编码器得到的,而这些时刻的key都是用不同时刻的编码去抽取特征那就会导致不一致的情况发生
,下面的动量编码器很好的解决了这个问题,我们需要看图中紫色的字体。首先设置左边的编码器设置为
则右边的编码器为 这边右边的动量编码器更新要对来说就比较缓慢,也会保留原来以往的信息,从而保证由相似的编码器得到,保持其一致性,这里的是不断的更新的,文章使用m=0.999
。
关于文章的损失函数及代理任务是怎么构建的呢?
1) 损失函数
1. 生成式
: 对于生成是来说就是输入一张原图或者被干扰后的图通过编码器和解码器的方式将图重建出来。损失函数可以用L1 损失或者L2 损失用来衡量原图和你现在新建图之间的差异。这里有没有让大家想打一个模型?是的,就是何凯明提出的MAE模型,后面会详细介绍。
2. 判别式
: 比如说eight position,比如说将图片分成九宫格,1-9, 将中间5给你之后,我在随机给你这个图的一个子图你可以预测这个图位于图片什么方位,即这个图序号是几?这就类似于分类任务了。
3. 掩码式
: 如MAE, CAE模型等。
4. 对比式
:
对比学习是一种在高维连续的输入信号(图片)上去构建字典的一种方式,这个字典是动态的
( 1. 因为字典里的key是随机取样的 2. 而且给这些key做编码的编码器也是在训练的过程中不断改变的
)对比式目标函数主要是去一个特征空间里衡量各个样本对之间的相似性,达到目标就是让相似物体的特征拉的更近,不相似的特征拉的更远。相对于生成式以及判别式生成的目标都是固定目标,但是对比式他的目标在训练的过程中是不断的在改变的,也就是这篇MoCo文章所说的生成的key字典。相当于训练一个编码器从而去做一个字典查找的任务。该文具体的损失函数如下图所示:
假设我们已经有了一个编码好的query q,以及特征 相当与字典的key位于下图的位置
1.
: 当query q和唯一的哪个正样本 相似的时候, 损失函数的值应该比较低
2
: 当query q和其他所有的key不相似的时候,损失函数的值也应该较低
因此作者发明了
InfoNCE(Info Noise Contrastive Estimation)
的损失函数来训练模型。(简单理解q与k相乘代表相似度,分母为q与其他正样本相似度越大越好,分母为q与其他负样本相似度越小越好
)
其实上述的图就类似于交叉熵损失函数,只是这里的K不是类别数而是负样本特征字典在一个mini-batch的数量, 否则k就会很大多少图片就是多少类别了,NCE即将这里问题划分为二分类问题有1. 数据类别data Sample, 2. 噪声类别noise Sample, 每次只需要拿data Sample与噪声数据做对比就可以了看是否相似。这里使用estimation表示的是不是在所有数据集上比较相似,而是在部分数据集上进行相似度比较。
NCE损失函数其实就是二分类问题,现在只有两个类别,一个是data Sample, 一个是noise Sample,每次拿data Sample与noise Sample做对比就好了,如下所示:
虽然NCE解决了负样本多的问题,但是计算复杂度还是有的,所以这选取了部分负样本进行损失计算。样本越多和使用整体数据集效果类似,效果越好。
相对于NCE, InfoNCE认为仅仅将该任务转成二分类不是那么友好,在那么多噪声样本中是同一个类别的概率非常低,因此将其转成多分类的问题。
公式中 或 可以理解为logits, 相当于下面Softmax函数中的i与j。
这里的 是一个温度的超参数,用来控制分布的形状,该值越小分布越尖锐,反之越光滑。如果该值越大则对所有的负样本都一视同仁 ,导致对模型的学习没有轻重,如果该温度的值设置过小使得模型值关注哪些特别困难的样本,使得模型不好泛化。分母的和是在一个正样本以及多个负样本呢之间进行的,就是一个k+1类的分类任务,就是希望将q分到 类。
4. 对抗式
:类似于Gan网络,主要是衡量两个概率分布之间的差异性。其主要是用来做无监督的数据生成。
2) 代理任务
1. denoising
: 重建整张图
2. context auto-encoder
: 重建某个patch
3. colorization
: 用给图片上色当自监督信号
4. 生成伪标签(pseudo-label)
:如exemplar image即给同一张图片做不同的数据增广他们都属于一个类别,或用patch ordering像之前说的九宫格的方法要么打乱预测顺序或者随机选一个patch你去预测他的方位。
5. 基于视频的信息做tracking
6. 聚类的方法
3).对比学习与不同代理任务之间的关系
不同的代理任务可以和某种形式的对比学习的目标函数配对使用的。例如MoCo使用的是个体判别的方式跟之前的这个examplar based代理任务有关。
CPC
: 预测性的对比学习,其是利用上下文的信息去预测未来(与上下文自编码很像)。
CMC
: 利用一个物体的不同视角去做对比, 这个类似于给图片上色的代理任务很像了,相当于给图片两个视角黑白和彩色。
4) 前人使用的对比方法总结
1) 对于图a类似于SimCLR了,这里的两个编码器都是resnet50,这是因为他的正负样本都是从同一个mini-batch里面来的。 以及 来自同一个mini-batch,他做一次forward就能得到所有的样本特征。缺点是该字典的大小与mini-batch大小是保持一致的,因此首先设备内存。
2)图b则是更关注字典的大,但牺牲特征的一致性图中可以看出只有query是做梯度回传的但是字典key这边是没有单独的编码器的,memorybank就是将整个数据集特征都存起来。如ImageNet有128万个特征,每个特征128维,600M内存空间,近邻查询效率也很高。然后每次模型训练时,从memory bank中仅从随机采样key,来组成字典,memory bank相当于线下进行的,字典就可以设置的非常大。但是memory bank的特征一致性不好,样本特征每次训练时选中作为key的那些样本特征,会通过编码器q进行更新,更新完之后又会利用已更新的编码器q去预测memorybank的对应选中key进行再次更新。每次更新的特征的差异性会很大,所以memory bank上特征的一致性会很差。另外,由于memory上存放了整个数据集的堂本,也就意味着,模型要训练一整个epoch,memory bank上的特征才能全部更新一次。
3)moco和memory bank方法更相似,都只有一个编码器,都需要额外的内存空间存放字典,memory bank中还提出了proximal optimization损失,目的是让训练变得更加平滑,和moco中的动量更新异曲同工。memory bangk动量更新的是特征,moco动量更新的是编码器k,moco的扩展性很好,可以在亿集数据集上使用,memory bank方法在数据集很大时,还是会受限于内存大小
5) 伪代码
moco中默认使用的batch size大小是256。数据增强得到正样本对。memory bank中query长度(特征维数)128,为了保持一致,moco也用的128。对于当前的mini-batch,我们对 queries 及其相应的 keys进行编码,这些键形成正样本对。负样本来自队列。
6)Shuffling BN
我们的编码器 fq 和 fk 都具有Batch Normalization (BN) [37],如标准 ResNet [33]。在实验中,我们发现使用BN会阻止模型学习良好的表示,如[35]中类似报道的那样(避免使用BN)。该模型似乎“欺骗”了pretext task,并很容易找到一个低损失的解决方案。这可能是因为样本之间的intra-batch communication(由BN引起)泄漏了信息。
我们通过 shuffling BN 来解决此问题。我们使用多个 GPU 进行训练,并针对每个 GPU 在样本上独立执行 BN(如常见做法中所做的那样)。对于key编码器 fk,我们在当前mini-batch中随机排列示例顺序,然后再在 GPU 中分配(并在编码后随机排列);query编码器 fq 的mini-batch的示例顺序不会更改。这可确保用于计算a query and its positive key的batch statistics来自两个不同的子集。这有效地解决了作弊问题,并允许training从BN中受益。
在训练阶段使用grid search
发现学习率在30
表现得效果非常好。
当然后面紧接着出来了MoCov2 以及MoCov3版本
MoCov2主相当于
- 加了更多的MLP层
- 加了更多的数据增强
- 训练的时候见了cosine的learning rate schedule
- 增加了训练时长的epoch(从200加到800)
3. SWaV
paper code
主要原理相当于给定我同样一张图片,如果我生成不同的视角,我希望可以用一个视角得到的特征去预测另外一个视角得到的特征,因为这些视角按道理来说应该是非常接近的,这篇文章的核心思想就是将对比学习与聚类的方法结合在一起,原理图如下所示
左边相当于以前的对比学习的方法 ,该文章使用的是右边的方法。该文章作者说虽然左边的做法比较简单,但是直接拿左右图片的这个特征去跟特征进行对比有点原始并且非常消耗资源,因为所有图片都是一个类别,像MoCo一样去了6万个负样本还只是一个近似,因为所有的负样本理应是128万个图片。SWaV作者在想能不能不需要用近似,通过借助一些先验信息不去跟大量负样本进行比较而是根据更简洁的东西去比较呢,这个简洁的东西就是聚类中心,我们可以跟聚类中心作比较。这里的聚类中心就是右图中的 (prototypes)这个矩阵,维度是d(特征维度,这里是128)*k(聚类中心数量,这里是3000)。具体过程可以理解为首先我们有一mini-batch图片 , 通过数据增强得到 , , 再分别经过编码器 得到特征 , , 再用clustering的方法,让特征 , 与prototype 生成目标 , , 这里的 , 相当于groundtruth的东西,其真正的代理任务就是如果 , 是正样本的话那么特征 与特征 应该很相似(也就是说如果拿 与c去做点乘也可以预测 , 拿 与c去做点乘也可以预测 )。这篇文章的好处就是如果你要是与许多的负样本进行对比的话就需要成千上万的负样本而且得到结果只是近似,而如果之和聚类中心进行对比的话,这里只有3000个聚类中心就足够了不需要上万个负样本。用聚类还有另外一个原因,这些聚类中心是有明确的语义含义的,之前的随机抽样负样本做对比的话,有的负样本也许还有可能是正样本,而且有时候抽出来的负样本呢类别也不均衡,所以聚类中心有效。这里的增广相对于之前使用了multi-crop的方法,相比较以前一张图仅仅crop两张图,则该方法crop了多张图片, crop 的图片也变小了。效果如下
第三阶段: 不用负样本
1、BYOL
参考链接1 参考链接2 52:30 BYOL --> paper-->code
其实之前使用负样本的学习方法相当于给模型提供一个约束。如果模型的输入只有正样本,那么模型需要让正样本之间的距离尽量的缩小,那么模型可能会想到一个捷径从而很好的解决这个问题,就是模型直接对所有样本的数据都是一致的,这样所有正样本之间的距离无限接近,但是模型这样躺平是学习不到实例的特征的,是无效的。因此添加了负样本对模型造成一个约束,就是让正样本之间的距离接近,让负样本之间的距离拉远,这样可以对模型进行约束,不让模型躺平,所以负样本在模型中是一个必须的东西,可以防止模型躺平,学到这个捷径解。但是BYOL的神奇之处在于模型没有使用负样本,仅仅是模型自己和自己去学,但是也实现了很不错的效果。
该对比学习无需负样本就可以进行训练,训练思路图如下所示:
上述方法相当于先将mini-batch输入的图片分别进行两种方式的数据增广得到 以及 。再分别通过编码器 以及 分别得到特征 以及特征 ,
这里需要注意的是
与
架构是一样的但是参数却是不一样的。
是随着梯度更新而更新的,
是用moving average的形式进行去更新的就是使用了动量编码器。
接着使用了mlp的projection得到特征 以及特征 , 接着 经过predictor , 这里的 与 一样都是mlp这样就得到一个新的特征 , 最后希望特征 与特征 尽可能一致。将原来匹配的问题变成了最后预测的问题,这个与SwAV很像。图中sg
表示的是stop gradient是没有梯度的与MoCo很像,上面就是query编码器,下面就是key的编码器它相当于用自己一个视角的特征去预测另外一个视角的特征,通过预测性任务去完成模型的训练,这边使用的损失函数是MSE损失函数,就是基于 与特征 计算损失。
某博客作者认为BYOL的并不是不依赖负样本,而是通过BN依赖于隐式的负样本进行训练。
下图博客图片链接
后面发现BYOL不加BN效果很差,模型坍塌了,总结结果如下:
该博客猜想BN这个操作相当于把batch所有的样本的特征拿过来计算了均值和方差做归一化,也就是说当你在计算某个正样本损失的时候呢其实你也看到了其他样本的特征也就说是有信息泄露的,MoCo也是用了shuffleBN防止信息泄漏,所以认为BYOL加入了隐式的负样本,也就是当前图片与BN产生的平均图片做对比(相当于SwAV的聚类中心)。紧接着作者发表了一篇文章来回应这个说法。
反驳理由1:这里有BN训练还是失败了
理由2:
当编码器和project都没有BN,simCLR也失败了,说明没有BN不仅仅BYOL不行,simCLR也不行。最后作者出来解释了理由,如果一开始初始化比较好不需要BN也可将模型训练效果变好,作者使用了GroupNorm以及weight standardization,这个方法式vit原班作者再BEiT提出来的,也就是现在很多人说的ResNetV2.之后效果也是非常好的。
2. SimSiam
paper code
该文章主要是化繁为简提出了几个点:
- 不需要负样本
- 不需要大的BatchSize
- 不需要动量编码器
该模型使用的损失函数为MSE损失函数,作者得到好的效果的重要结论是使用了stop gradient
的方法,可以类似于EM算法。
第四阶段 基于Transformer
1. MoCov3
paper code
MoCov3相当于MoCov2于SimSiam的合体
resnet网络换成了vit网络
训练经常抖动,发现问题的原因是每当loss有大幅波动的时候导致准确度大幅下降的时候,梯度也会有一个波峰,波峰主要发生在第一层就是在做patch projection的时候,这个属于模型的第一步,这一步是一个可以训练的全连接层,作者就将这一层冻住,发现效果变好了,这种问题得以解决。
2. DINO
paper code
这篇文章表示visionTransformer在自监督的情况下效果非常好,如下图所示
上述的自注意力图可视化后可以看出他能非常准确的抓住每个物体的轮廓可直接媲美物体做分割。具体的方法如下所示:
这是一个自蒸馏的方式,对于MoCo来说,左边的网络是query编码器,右边的是key编码器。右边有一个centering 的工作,相当于每个样本减去一个均值操作,类似于BN操作。