MoCo : 引入对比学习来实现自监督训练

源:MoCo 论文逐段精读【论文精读】_哔哩哔哩_bilibili

对比学习简单理解

将图像通过一个网络提取出特征f,如果图像相似,使得特征尽量靠近,不相似的尽量远离

定义什么是正负样本的规则就理解为代理模式(Pretext Task),用代理模式定义的正负样本来取代标签。

再定义一个损失对提取出的特征操作使得定义的正样本之间的距离靠近,定义的负样本远离即可。

一些思路:

对比学习可以用得很灵活,可以用各种不同思路取各种Pretext Task来替代标签都行

比如rgb图像跟深度图像,或者正面背面作为正样本来对比。或者视频里的任意两帧作为正样本,其他视频的帧视为负样本。nlp中(cimCSE)同一个句子做两次forward每次使用不同的dropout取得两个不同值作为正样本等等

MoCo 

引入对比学习,通过代理任务替代定义的正负样本规则来替代图像标签,从而进行无监督学习

类比nlp中的无监督任务时,需要做一个词嵌入操作,独热向量其他位置全零默认了每个词之间没关系,词嵌入效果更好,构造一个涵盖了大量词汇的字典
有了这个字典,在nlp任务中就可以不需要标签了,比如bert的mask方式,盖住一个词,做预测,原本这个词的词向量作为标签来比对计算损失

 

将这个思路用在cv任务中,但是每个文字本身是具有明确的语义信息的,比如含有猫这个语义信息的文字就是猫,而含有猫这个语义信息的图像有无数张,所以不能直接用图像来做对比,而是提取每张猫图的共有特征,来构造字典
moco中构造的特征字典也是为了在不需要标签的情况下使得损失可算,所以为了涵盖更广构造得越大越好
 

整体理解

MoCo的自监督体现在训练过程,训练的时候不需要标签,通过Pretext Task定义的正负样本来训练,目标是训练出一组权重使得定义的正样本与负样本提出的特征能够很好的区分开,再将训练好的权重拿去在下游任务中做微调。下游任务使用正样本q的encoder,只修改最后的全连接或者输出头即可有一个不错的结果。

本文的Pretext Task

将每个图像x通过增广得到的x1,x2定义为正样本,其他所有图像都作为负样本。

x1,x2通过不同的增广看起来会很不一样,但是他们携带的语义信息是相同的,所以缩减x1,x2之间的距离,增加与其他所有样本的距离。

MoCo : 引入对比学习来实现自监督训练_第1张图片

具体操作

锚点通过encoder E1获取特征f1,所有负样本都和正样本一样通过encoder E2获取特征。

对比特征使得f11与f12相近,与其他负样本在特征空间的距离尽量远。

MoCo : 引入对比学习来实现自监督训练_第2张图片

将encoder E2获取的正负样本的特征都存入一个字典中,每次用f11也就是query去对比字典中的值,最相近的一个key作为正样本。

衡量相似性的方式InfoNCE:

考虑一个编码查询q和一组编码样本{k0, k1, k2, ...},它们是一个字典的键。假设字典中存在一个与q相匹配的键(表示为k+)。对比性损失[29]是一个函数
当q与它的正键k+相似而与所有其他键不相似时,其值为低。
而与所有其他键(被认为是负键
为q)。用点积来衡量相似度,一种形式的
本文考虑了一种对比性损失函数,称为InfoNCE[46]

momentum encoder

所有的key都应该用相同或者尽可能相似的编码器得到,不然q在查询时可能找到的是一个和他的编码方式相似的key从而得到的值相似,而不是真正的语义层面导致的相似

原文的实现引入了队列和动量更新encoder,如下图 

MoCo : 引入对比学习来实现自监督训练_第3张图片

引入队列是受限于显卡内存,字典中的所有k要越大越好,但是显存不够存所有k,用队列的方式存,每次读一个新的mini-batch时就将最早进入的mini-batch读出。队列还是很长的队列由所有k组成,但是每次只操作一小部分数据。

momentum encoder是为了使得每一个batch的编码方式尽可能一致,将m取一个极大的值编码器就基本只由前一个Batch的编码器决定,本文取的0.999

如果直接将\Thetak取\Thetaq中的值,\Thetaq的值每个batch都会随着反向传播更新梯度,相当于这种方式构造的\Thetak一直在不断变化,从而导致每一个batch的特征k提取方式不太一致

 一些之前的方法受限于构造的字典大小或者k的encoder中数据一致性

结合一些之前的方法分析为何会受限。

第一种端到端方式,encoder q和k都通过梯度回传来更新参数

MoCo : 引入对比学习来实现自监督训练_第4张图片

全流程伪代码

将输入x通过不同的encoder获取q k

k.detach是不计算梯度,也可用no_grid实现

计算正样本,也就是q乘k+,和负样本

然后将拼接在一起,拼的时候正样本放第一列,计算交叉熵时所有正样本都是第0类,所以正样本标签直接构造一个0向量即可

然后反向传播跟新q的encoder 动量跟新k的encoder

MoCo : 引入对比学习来实现自监督训练_第5张图片

你可能感兴趣的:(ai学习笔记,深度学习)