首页 文章详情

深度了解自监督学习,就看这篇解读 !Hinton团队力作:SimCLR系列

极市平台 | 895 2021-06-18 11:19 0 0 0
UniSMS (合一短信)
↑ 点击蓝字 关注极市平台

作者丨科技猛兽
编辑丨极市平台

极市导读

 

本文主要介绍Self-Supervised Learning 在 CV 领域 的经典工作之一:SimCLR和SimCLR v2。>>加入极市CV技术交流群,走在计算机视觉的最前沿

本文目录

1 SimCLR 原理分析 (ICML 2020)
1.1 数据增强
1.2 通过Encoder获取图片表征
1.3 预测头
1.4 相似图片输出更接近
1.5 对下游任务Fine-tune

2 SimCLR v2原理分析 (NIPS 2020)
2.1 SimCLR v2 10分钟简介:SimCLR v2 和 SimCLR 相比做了哪些改进?
2.2 SimCLR v2 实验设置

科技猛兽:Self-Supervised Learning系列解读 (目录)

https://zhuanlan.zhihu.com/p/381354026

Self-Supervised Learning,又称为自监督学习,我们知道一般机器学习分为有监督学习,无监督学习和强化学习。而 Self-Supervised Learning 是无监督学习里面的一种,主要是希望能够学习到一种通用的特征表达用于下游任务 (Downstream Tasks)其主要的方式就是通过自己监督自己。作为代表作的 kaiming 的 MoCo 引发一波热议, Yann Lecun也在 AAAI 上讲 Self-Supervised Learning 是未来的大势所趋。所以在这个系列中,我会系统地解读 Self-Supervised Learning 的经典工作。

总结下 Self-Supervised Learning 的方法,用 4 个英文单词概括一下就是:

Unsupervised Pre-train, Supervised Fine-tune.

这段话先放在这里,可能你现在还不一定完全理解,后面还会再次提到它。

在预训练阶段我们使用无标签的数据集 (unlabeled data),因为有标签的数据集它很贵啊,打标签得要多少人工劳力去标注,那成本是相当高的,所以这玩意太贵。相反,无标签的数据集网上随便到处爬,它便宜。在训练模型参数的时候,我们不追求把这个参数用带标签数据从初始化的一张白纸给一步训练到位,原因就是数据集太贵。于是 Self-Supervised Learning 就想先把参数从 一张白纸 训练到 初步成型,再从 初步成型 训练到 完全成型。注意这是2个阶段。所以预训练模型的时候,就是模型参数从 一张白纸初步成型 的这个过程,还是用无标签数据集。等我把模型参数训练个八九不离十,这时候再根据你 下游任务 (Downstream Tasks) 的不同去用带标签的数据集把参数训练到 完全成型,那这时用的数据集量就不用太多了,因为参数经过了第1阶段就已经训练得差不多了。

第1个阶段不涉及任何下游任务,就是拿着一堆无标签的数据去预训练,没有特定的任务,这个话用官方语言表达叫做:in a task-agnostic way。第2个阶段涉及下游任务,就是拿着一堆带标签的数据去在下游任务上 Fine-tune,这个话用官方语言表达叫做:in a task-specific way (这俩英文很重要啊,会不断出现)

以上这些话就是 Self-Supervised Learning 的核心思想,如下图所示,后面还会再次提到它。

Self-Supervised Learning 经典工作的分类如下图1所示。在上篇文章中主要介绍了 Self-Supervised Learning 在 NLP 领域 的经典工作:BERT模型的原理及其变体GPT, MASS, BART, ELECTRA等等,这些方法都是属于 Prediction 类别的。本文主要介绍Self-Supervised Learning 在 CV 领域 的经典工作之一:SimCLR和SimCLR v2,它们都是属于 Contrastive 类别的。

Prediction 类别和 Constractive 类别有什么不同呢?

Prediction 类别比如说BERT,是会用一堆没有label的句子去训练BERT做填空题 (详见上篇文章):给一个句子随机盖住 (mask掉) 一个token,输入这个BERT,期望它输出盖住的部分,使用这种办法让BERT无监督地学习到结合上下文做Embedding的能力,学习的过程是一种Prediction的行为。Contrastive 类别方法并不要求模型能够重建原始输入,而是希望模型能够在特征空间上对不同的输入进行分辨,这也会在SimCLR的训练过程中体现。

图1:Self-Supervised Learning 经典工作的分类

1 SimCLR 原理分析

论文名称:A Simple Framework for Contrastive Learning of Visual Representations

论文地址:

https://arxiv.org/pdf/2002.05709.pdf

SimCLR 是Hinton团队在 Self-Supervised Learning 领域的一个系列的经典工作。先来通过图2直观地感受下它的性能:SimCLR (4×) 这个模型可以在 ImageNet 上面达到 76.5%Top 1 Accuracy,比当时的 SOTA 模型高了7个点。如果把这个预训练模型用 1%的ImageNet的标签Fine-tune 一下,借助这一点点的有监督信息,SimCLR 就可以再达到 85.5%Top 5 Accuracy,也就是再涨10个点。

图2:SimCLR性能

那根据上一篇文章BERT的描述,我们说 Self-Supervised Learning 的目的一般是使用大量的无 label 的资料去Pre-train一个模型,这么做的原因是无 label 的资料获取比较容易,且数量一般相当庞大,我们希望先用这些廉价的资料获得一个预训练的模型,接着根据下游任务的不同在不同的有 label 数据集上进行 Fine-tune 即可

作为 Self-Supervised Learning 的工作之一,SimCLR 自然也遵循这样的思想。我们回忆一下之前 BERT 会用一堆没有label的句子去训练BERT做填空题 (详见上篇文章):给一个句子随机盖住 (mask掉) 一个token,输入这个BERT,期望它输出盖住的部分。这就是BERT进行自监督学习的做法,那么在 SimCLR 里面是如何做的呢?一个核心的词汇叫做:Contrastive

这个词翻译成中文是 对比 的意思,它的实质就是:试图教机器区分相似和不相似的事物

图3:对比学习试图教机器区分相似和不相似的事物

这个话是什么意思呢?比如说现在我们有任意的 4 张 images,如下图4所示。前两张都是dog 这个类别,后两张是其他类别,以第1张图为例,我们就希望它与第2张图的相似性越高越好,而与第3,第4张图的相似性越低越好

但是以上做法其实都是很理想的情形,因为:

  1. 我们只有大堆images,没有任何标签,不知道哪些是 dog 这个类的,哪些是其他类的。
  2. 没办法找出哪些图片应该去 Maximize Similarity,哪些应该去 Minimize Similarity。
图4:试图教机器区分相似和不相似的事物

所以,SimCLR是怎么解决这个问题的呢?它的framework如下图5所示:

假设现在有1张任意的图片  ,叫做Original Image,先对它做数据增强,得到2张增强以后的图片  。注意数据增强的方式有以下3种:

  • 随机裁剪之后再resize成原来的大小 (Random cropping followed by resize back to the original size)。
  • 随机色彩失真 (Random color distortions)。
  • 随机高斯模糊 (Random Gaussian Deblur)。

接下来把增强后的图片  输入到Encoder里面,注意这2个Encoder是共享参数的,得到representation  ,再把  继续通过 Projection head 得到 representation  ,这里的2个 Projection head 依旧是共享参数的,且其具体的结构表达式是:

接下来的目标就是最大化同一张图片得到的 

图5:SimCLR框架

以上是对SinCLR框架的较为笼统的叙述,下面具体地看每一步的做法:

回到起点,一开始我们有的training corpus就是一大堆 unlabeled images,如下图6所示。

图6:我们有的training corpus
  • 1.1 数据增强

比如batch size的大小是  ,实际使用的batch size是8192,为了方便我们假设 

图7:Batch Size=2

注意数据增强的方式有以下3种:

  • 随机裁剪之后再resize成原来的大小 (Random cropping followed by resize back to the original size)。代码:
torchvision:transforms:RandomResizedCrop

  • 随机色彩失真 (Random color distortions)。代码:
from torchvision import transformsdef get_color_distortion(s=1.0):# s is the strength of color distortion.    color_jitter = transforms.ColorJitter(0.8*s, 0.8*s, 0.8*s, 0.2*s)    rnd_color_jitter = transforms.RandomApply([color_jitter], p=0.8)    rnd_gray = transforms.RandomGrayscale(p=0.2)    color_distort = transforms.Compose([    rnd_color_jitter,    rnd_gray])
return color_distort

  • 随机高斯模糊 (Random Gaussian Deblur)。
random (crop + flip + color jitter + grayscale)

图8:对Input Image进行数据增强

对每张图片我们得到2个不同的数据增强结果,所以1个Batch 一共有 4 个 Image。

图9:对1个Batch的数据做增强,每个图片得到2个结果
  • 1.2 通过Encoder获取图片表征

第一步得到的2张图片  会通过Encoder获取图片的表征,如下图10所示。所用的编码器是通用的,可以用其他架构代替。下面显示的2个编码器共享权重,我们得到向量 

图10:通过Encoder获取图片表征

本文使用了 ResNet-50 作为 Encoder,输出是 2048 维的向量 

  • 1.3 预测头

Encoder 得到的2个representation再通过Prediction head (  )进一步提特征,预测头是一个2层的MLP,将2048维的向量  进一步映射到128维隐空间中,得到新的representation 

图11:预测头
  • 1.4 相似图片输出更接近

到这一步以后对于每个Batch,我们得到了如下图12所示的Representation 

图12:最终得到的Representation

首先定义Representation之间的相似度:使用余弦相似度Cosine Similarity:

Cosine Similarity把计算两张 Augmented Images  的相似度转化成了计算两个Projected Representation  的相似度,定义为:

式中,  是可调节的Temperature 参数。它能够scale 输入并扩展余弦相似度[-1, 1]这个范围。

使用上述公式计算batch里面的每个Augmented Images  的成对余弦相似度。如下图13所示,在理想情况下,狗的增强图像之间的相似度会很高,而狗和鲸鱼图像之间的相似度会较低。

图13:Augmented Images的余弦相似度

现在我们有了衡量相似度的办法,但是这还不够,要最终转化成一个能够优化的 Loss Function 才可以。

SimCLR用了一种叫做 NT-Xent loss (Normalized Temperature-Scaled Cross-Entropy Loss)的对比学习损失函数。

我们先拿出Batch里面的第1个Pair:

图14:依次拿出Batch里面的每个Pair

使用 softmax 函数来获得这两个图像相似的概率:

图15:使用 softmax 函数来获得这两个图像相似的概率

这种 softmax 计算等价于获得第2张增强的狗的图像与该对中的第1张狗的图像最相似的概率。在这里,分母中的其余的项都是其他图片的增强之后的图片,也是negative samples。

所以我们希望上面的softmax的结果尽量大,所以损失函数取了softmax的负对数:

图16:损失函数取softmax的负对数

再对同一对图片交换位置以后计算损失:

图17:同一对图片交换位置以后计算损失

最后,计算每个Batch里面的所有Pair的损失之和取平均:

图18:每个Batch里面的所有Pair的损失之和取平均
  • 1.5 对下游任务Fine-tune

至此我们通过对比学习,巧妙地在没有任何标签的情况下训练好了 SimCLR 模型,使得其Encoder的输出可以像正常有监督训练的模型一样表示图片的Representation信息。所以接下来就是利用这些 Representation的时候了,也就是在下游任务上Fine-tune。一旦 SimCLR 模型在对比学习任务上得到训练,它就可以用于迁移学习,如 ImageNet 分类,如下图19所示。此时在下游任务上 Fine-tune 模型时需要labeled data,但是数据量可以很小了。

图19:对下游任务Fine-tune

性能:

SimCLR (4×) 这个模型可以在 ImageNet 上面达到 76.5%Top 1 Accuracy,比当时的 SOTA 模型高了7个点。如果把这个预训练模型用 1%的ImageNet的标签Fine-tune 一下,借助这一点点的有监督信息,SimCLR 就可以再达到 85.5%Top 5 Accuracy,也就是再涨10个点。

FAQ1:这个 76.5% 和 85.5% 是怎么得到的呢?

答1:76.5% 是通过Linear Evaluation得到的。

按照上面的方式进行完Pre-train之后,Encoder部分和Projection head部分的权重也就确定了。那么这个时候我们去掉Projection head的部分,在Encoder输出的  之后再添加一个线性分类器 (Linear Classifier),它其实就是一个FC层。那么我们使用全部的 ImageNet 去训练这个 Linear Classifier,具体方法是把预训练部分,即  之前的权重frozen住,只训练线性分类器的参数,那么 Test Accuracy 就作为 a proxy for representation quality,就是76.5%。

85.5% 是通过Fine-tuning得到的。

按照上面的方式进行完Pre-train之后,Encoder部分和Projection head部分的权重也就确定了。那么这个时候我们去掉Projection head的部分,在Encoder输出的  之后再添加一个线性分类器 (Linear Classifier),它其实就是一个FC层。那么我们使用 1%的ImageNet 的标签 去训练整个网络,不固定 Encoder 的权重了。那么最后的 Test Accuracy 就是85.5%。

Linear Evaluation 和 Fine-tuning的精度的关系如下图20所示:当Linear Evaluation 的精度达到76.5% Top1 Accuracy时,Fine-tuning的精度达到了50多,因为Fine-tuning 只使用了1%的标签,而Linear Evaluation 使用了100%的标签。

图20:Linear Evaluation 和 Fine-tuning的精度的关系

FAQ2:Projection head 一定要使用非线性层吗?

答2: 不一定。作者尝试了3种不同的 Projection head 的办法,分别是:Non-Linear, Linear 层和 Identity mapping,结果如下图21所示。发现还是把Projection head 设置成非线性层 Non-Linear 比较好。Non-Linear 比 Linear 层要涨3%的Top 1 Accuracy,比 Identity mapping 层要涨10%的Top 1 Accuracy。

而且,作者的另一个发现是 Projection head 前面的 hidden layer 相比于 Projection head后面的 hidden layer 更好。那这个更好是什么意思呢?

就是假设我们把 Projection head 前面的 hidden layer  作为图片的representation的话,那么经过线性分类层得到的模型性能是好的。如果把Projection head 后面的 hidden layer 作为图片的representation的话,那么经过线性分类层得到的模型性能不好,如下图22所示,是对  或者  分别训练一个额外的MLP,  或者 的hidden dimension 都是2048,性能如图22。

图21:不同的 Projection head 的办法的结果
图22:Projection head 前面的 hidden layer 相比于 Projection head后面的 hidden layer 更好

FAQ3:NT-Xent loss (Normalized Temperature-Scaled Cross-Entropy Loss)的对比学习损失函数如何代码实现?

答3:

import tensorflow as tfimport numpy as np
def contrastive_loss(out,out_aug,batch_size=128,hidden_norm=False,temperature=1.0): if hidden_norm: out=tf.nn.l2_normalize(out,-1) out_aug=tf.nn.l2_normalize(out_aug,-1) INF = np.inf labels = tf.one_hot(tf.range(batch_size), batch_size * 2) #[batch_size,2*batch_size] masks = tf.one_hot(tf.range(batch_size), batch_size) #[batch_size,batch_size] logits_aa = tf.matmul(out, out, transpose_b=True) / temperature #[batch_size,batch_size] logits_bb = tf.matmul(out_aug, out_aug, transpose_b=True) / temperature #[batch_size,batch_size] logits_aa = logits_aa - masks * INF # remove the same samples in out logits_bb = logits_bb - masks * INF # remove the same samples in out_aug logits_ab = tf.matmul(out, out_aug, transpose_b=True) / temperature logits_ba = tf.matmul(out_aug, out, transpose_b=True) / temperature loss_a = tf.losses.softmax_cross_entropy( labels, tf.concat([logits_ab, logits_aa], 1)) loss_b = tf.losses.softmax_cross_entropy( labels, tf.concat([logits_ba, logits_bb], 1)) loss=loss_a+loss_b return loss,logits_ab
'''假设batch_size=3, out 和 out_aug 分别代码 原始数据和增强数据的representationout : [a1,a2,a3] out_aug : [b1,b2,b3]
labels:[batch_size,2*batch_size] batch_size=3 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0
mask: [batch_size,batch_size]1 0 00 1 00 0 1
logits_aa [batch_size,batch_size]a1*a1, a1*a2, a1*a3 a2*a1, a2*a2, a2*a3 a3*a1, a3*a2, a3*a3
logits_bb [batch_size,batch_size]b1*b1, b1*b2, b1*b3 b2*b1, b2*b2, b2*b3 b3*b1, b3*b2, b3*b3
logits_aa - INF*mask # delete same samples-INF, a1*a2, a1*a3 a2*a1, -INF, a2*a3 a3*a1, a3*a2, -INF
logits_bb - INF*mask # delete same samples-INF, b1*b2, b1*b3 b2*b1, -INF, b2*b3 b3*b1, b3*b2, -INF
logits_ab [batch_size,batch_size]a1*b1, a1*b2, a1*b3 a2*b1, a2*b2, a2*b3 a3*b1, a3*b2, a3*b3
logtis_ba [batch_size,batch_size]b1*a1, b1*a2, b1*a3 b2*a1, b2*a2, b2*a3b3*a1, b3*a2, b3*a3
concat[logits_ab,logits_aa]:a1*b1, a1*b2, a1*b3, -INF, a1*a2, a1*a3 a2*b1, a2*b2, a2*b3, a2*a1, -INF, a2*a3a3*b1, a3*b2, a3*b3, a3*a1, a3*a2, -INFonly a1*b1, a2*b2, a3*b3 are positives
concat [logits_ab,logits_bb]:b1*a1, b1*a2, b1*a3, -INF, b1*b2, b1*b3 b2*a1, b2*a2, b2*a3, b2*b1, -INF, b2*b3b3*a1, b3*a2, b3*a3, b3*b1, b3*b2, -INFonly b1*a1, b2*a2, b3*a3 are positives, so calculate the softmax_cross_entropy with labels
'''

简单分析下代码最后会得到:

a1*b1, a1*b2, a1*b3,  -INF,  a1*a2, a1*a3

对它做softmax,这里的 a1*b1 就代表第1张图片的2个 Augmented Images 的 similarity,a1*b2 第1张图片的第1个 Augmented Images 和第2张图片的第2个Augmented Images 的similarity。

FAQ4:SimCLR 的性能与 Batch size 的大小和训练的长度有关吗?

答4: 有关系。如下图23所示,作者发现当使用较小的 training epochs 时,大的 Batch size 的性能显著优于小的 Batch size 的性能。作者发现当使用较大的 training epochs 时,大的 Batch size 的性能和小的 Batch size 的性能越来越接近。这一点其实很好理解:在对比学习中,较大的 Batch size 提供更多的 negative examples,能促进收敛。更长的 training epochs 也提供了更多的 negative examples,改善结果。

图23:SimCLR 的性能与 Batch size 的大小的关系

2 SimCLR v2原理分析

论文名称:Big Self-Supervised Models are Strong Semi-Supervised Learners

论文地址:

https://arxiv.org/pdf/2006.10029.pdf

  • 2.1 SimCLR v2 10分钟简介:SimCLR v2 和 SimCLR 相比做了哪些改进?

上一节我们介绍了 SimCLR 的原理,结合上篇文章介绍的 BERT 的原理 (再放一遍链接),我们

科技猛兽:Self-Supervised Learning 超详细解读 (一):大规模预训练模型BERT

https://zhuanlan.zhihu.com/p/378360224

可以总结下 Self-Supervised Learning 的方法,用4个英文单词概括一下就是:

Unsupervised Pre-train, Supervised Fine-tune.

在预训练阶段我们使用无标签的数据集 (unlabeled data),因为有标签的数据集它很贵啊,打标签得要多少人工劳力去标注,那成本是相当高的,所以这玩意太贵。相反,无标签的数据集网上随便到处爬,它便宜。在训练模型参数的时候,我们不追求把这个参数用带标签数据从初始化的一张白纸给一步训练到位,原因就是数据集太贵。于是 Self-Supervised Learning 就想先把参数从 一张白纸 训练到 初步成型,再从 初步成型 训练到 完全成型。注意这是2个阶段。所以预训练模型的时候,就是模型参数从 一张白纸初步成型 的这个过程,还是用无标签数据集。等我把模型参数训练个八九不离十,这时候再根据你 下游任务 (Downstream Tasks) 的不同去用带标签的数据集把参数训练到 完全成型,那这时用的数据集量就不用太多了,因为参数经过了第1阶段就已经训练得差不多了。

第1个阶段不涉及任何下游任务,就是拿着一堆无标签的数据去预训练,没有特定的任务,这个话用官方语言表达叫做:in a task-agnostic way。第2个阶段涉及下游任务,就是拿着一堆带标签的数据去在下游任务上Fine-tune,这个话用官方语言表达叫做:in a task-specific way。

Hinton老爷子这个组的第 1 个版本 SimCLR 好像2月份才刚发布不久,在 Hinton 老爷子的带领下,没过几个月立马升级到了 SimCLR v2。v2 相比 v1 将 SOTA 结果提升了大约 22个点左右,这波操作真稳。

问:SimCLR v2 和 SimCLR 相比做了哪些改进?

答: SimCLR v2 的第 1 个发现是:

在使用无标签数据集做 Pre-train 的这一步中,模型的尺寸很重要,用 deep and wide 的模型可以帮助提升性能。

SimCLR v2 的第 2 个发现是:

使用无标签数据集做 Pre-train 完以后,现在要拿着有标签的数据集 Fine-tune 了。之后再把这个 deep and wide 的模型 蒸馏成一个更小的网络。

所以,SimCLR v2 的方法,用8个英文单词概括一下就是:

Unsupervised Pre-train, Supervised Fine-tune,Distillation Using Unlabeled Data.

所以 SimCLR v2 论文里面给出了3个论点:

  • 对于半监督学习来讲,在标签量极少的情况下,模型越大,获益就越多。这很不符合直觉,常识是标签这么少了,模型变大会过拟合。

  • 即使模型越大能够学到越 general 的 representations,但是这是在不涉及下游任务的task-agnostic 的情况下。一旦确定了下游任务,就不再需要大模型了,可以蒸馏成一个小模型。

  • Projection head 很重要,更深的 Projection head 可以学习到更好的representation,在下游任务做 Fine-tune 之后也更好。

这3个论点就是 SimCLR v2 的贡献。那 SimCLR v2 取得的效果如何呢?我们对标一下 SimCLR:

性能:

SimCLR (4×) 这个模型可以在 ImageNet 上面达到 76.5%Top 1 Accuracy,比当时的 SOTA 模型高了7个点。如果把这个预训练模型用 1%的ImageNet的标签Fine-tune 一下,借助这一点点的有监督信息,SimCLR 就可以再达到 85.5%Top 5 Accuracy,也就是再涨10个点。

注意这个 76.5% 是通过 Linear Evaluation 得到的, Linear Evaluation 具体是咋做的请参考上面的 FAQ1。这个 85.5% 是通过 Fine-tune 得到的, Fine-tune 具体是咋做的请参考上面的 FAQ1

SimCLR v2 这个模型可以在 ImageNet 上面达到 79.8%Top 1 Accuracy,比当时的 SOTA 模型 SimCLR 高了 4.3 个点。如果把这个预训练模型用 1%或10% 的 ImageNet的标签Fine-tune 一下,借助这一点点的有监督信息,SimCLR v2 就可以再达到 76.6%或80.9%Top 1 Accuracy。如果再蒸馏一下,迁移到更小的ResNet-50 上面,SimCLR v2 小模型就可以再达到 73.9%或77.5%Top 1 Accuracy。注意 ResNet-50 有监督学习的Accuracy是76.6%。所以 SimCLR v2 在很多时候超越了有监督学习

  • SimCLR v2 具体步骤:

SimCLR v2的具体步骤如下图24所示,这个图是论文里面的图,我自己画了个更细节的图如图25所示。SimCLR v2的具体步骤可以分为以下3步:

  1. Unsupervised Pre-train: 使用无标签数据以一种 Task-agnostic 的方式预训练Encoder,得到比较 general 的 Representations。
  2. Supervised Fine-tune: 使用有标签数据以一种 Task-specific 的方式 Fine-tune Encoder。
  3. Distillation Using Unlabeled Data: 使用无标签数据以一种 Task-specific 的方式蒸馏 Encoder,得到更小的Encoder。
图24:SimCLR v2的具体步骤
图25:SimCLR v2的具体步骤

1) Unsupervised Pre-train

SimCLR v2 的这一步和 SimCLR 是一模一样的,如图25所示,具体的步骤已经在上文的1.1 - 1.4讲解了,这里再简要概述一下:

首先对每张图片先做数据增强,每张图片我们得到2个不同的数据增强结果,假设Batch size大小为2,则1个Batch 一共有 4 个 Image。假设现在有1张任意的图片  ,叫做Original Image,先对它做数据增强,得到2张增强以后的图片  。注意数据增强的方式还是以下3种:

  • 随机裁剪之后再resize成原来的大小 (Random cropping followed by resize back to the original size)。
  • 随机色彩失真 (Random color distortions)。
  • 随机高斯模糊 (Random Gaussian Deblur)。

接下来把增强后的图片  输入到Encoder里面,注意这2个Encoder是共享参数的,得到representation  ,再把  继续通过 Projection head (在 SimCLR v2 里面是3层的MLP) 得到 representation  ,这里的2个 Projection head 依旧是共享参数的,且其具体的结构表达式是:

接下来的目标就是最大化同一张图片得到的  。怎么最大化呢?使用Cosine Similarity把计算两张 Augmented Images 的相似度转化成了计算两个Projected Representation  的相似度,定义为:

式中,  是可调节的Temperature 参数。它能够scale 输入并扩展余弦相似度[-1, 1]这个范围。现在我们有了衡量相似度的办法,但是这还不够,要最终转化成一个能够优化的 Loss Function 才可以。SimCLR用了一种叫做 NT-Xent loss (Normalized Temperature-Scaled Cross-Entropy Loss)的对比学习损失函数。希望上面的softmax的结果尽量大,所以损失函数取了softmax的负对数:

最后,计算每个Batch里面的所有Pair的损失之和取平均:

去优化这个损失函数  即可。

SimCLR v2 也是按照上面的步骤,有哪些不同呢?

  1. Encoder 变长变大: SimCLR v2 用了更大的ResNet架构,把原来的 ResNet-50 (4×) 拓展成了 ResNet-152 (3×) 和 selective kernels (SK),记为 ResNet-152 (3×+SK),变成这样以后,把这个预训练模型用 1%的 ImageNet的标签Fine-tune 一下,借助这一点点的有监督信息,获得了29个点的提升。
  2. Projection head 变深: 使用了更深的  。原来的结构如图5所示是2个FC层+一个激活函数构成。现在的  是3个FC层,并且在Fine-tune的时候要从第1层开始。变成这样以后,把这个预训练模型用 1%的 ImageNet的标签Fine-tune 一下,借助这一点点的有监督信息,获得了14个点的提升。
  3. 加入了MoCo 的内存机制: 因为 SimCLR 本身就能通过数据增强得到很多的负样本,所以说这步只获得了1个点的提升。

2) Supervised Fine-tune

在 SimCLR 中,Projection head 在预训练完以后会被扔掉,不做Fine-tune,只保留Encoder  加一个FC层去做Fine-tune。

而在 SimCLR v2 中,Projection head 在预训练完以后不会被完全扔掉,而是扔掉一半,保留一半做Fine-tune。注意如果只保留一层,那就和 SimCLR 加一个FC层的做法实质上一样了。

3) Distillation Using Unlabeled Data

作者把 Fine-tune 之后的网络作为了 Teacher,去蒸馏一个更小的 Student 网络。

损失函数是:

式中

,  是可调节的Temperature 参数。它能够scale 输入并扩展余弦相似度[-1, 1]这个范围。  是输入图片  网络输出和  的相似度,这样  就代表了输入图片  网络输出和  的相似的概率值。我们希望 Teacher 的这个概率  和 Student 的这个概率  越接近越好,如下图26所示。

图26:Distillation Using Unlabeled Data

上式 1 是只使用蒸馏而不用任何label的情况,当我们也有一些label的时候,也可以在1式的基础上添加一项有监督的损失:


2.2 SimCLR v2 实验设置:

以上这3步就是 SimCLR v2的具体步骤了,接下来就是大量的实验了。下面是一些基本训练的设置:

Unsupervised Pre-train:

  • 模型训练阶段使用 128 Cloud TPUs。
  • Batch size:4096,Global Batch Normalization。
  • 预训练 800 epochs。
  • 学习率在前40个 epochs线性上升到最大值  ,之后使用cosine decay schedule。
  • weight decay rate: 
  • Projection head:3层的MLP。

Supervised Fine-tune:

  • Fine-tuning 阶段,也就是只使用1%或10%的数据时 Projection head 保留1层MLP,扔掉2层。
  • Batch size:1024,Global Batch Normalization。
  • 学习率 不变。对于标准 ResNet 值为  。对于更大的ResNet 值为 
  • Fine-tune 60 epochs (1% label),30 epochs (10% label)。

Distillation Using Unlabeled Data:

  • Distillation 阶段有2种设置:一种是 Teacher 和 Student 模型一样大,取名 self-distillation ,另一种是 Student 模型相比 Teacher 更小,取名 big-to-small distillation。

  • Batch size:4096,Global Batch Normalization。

  • 蒸馏 400 epochs。

  • 学习率在前40个 epochs线性上升到最大值  ,之后使用cosine decay schedule。

  • weight decay rate: 

我们再回顾下 SimCLR v2 论文里面给出的3个论点:

对于半监督学习来讲,在标签量极少的情况下,模型越大,获益就越多。这很不符合直觉,常识是标签这么少了,模型变大会过拟合。

下图27是一个大的汇总,就是在不同大小的模型下,有监督学习的性能和 Self-Supervised Learning 在 Linear Evaluation 和 Fine-tuning 两种情况下的性能。

图27:在不同大小的模型下,有监督学习的性能和 Self-Supervised Learning 在 Linear Evaluation 和 Fine-tuning 两种情况下的性能

对于有监督学习,最大的模型和最小的模型的性能相差仅4个点 (80.5-76.6),但是对于 Self-Supervised Learning Linear Evaluation 来讲,差距达到了8个点 (79.8-71.7),对于 Self-Supervised Learning Fine-tuning (1% label) 来讲,差距达到了17个点 (74.9-57.9)。而且ResNet-152 (3×+SK) 的性能没有比 ResNet-152 (2×+SK) 的性能好多少,说明width带来的提升达到了瓶颈。

下图28是个更直观的展示模型大小,label数量对性能影响的曲线图。我们发现在标签量极少的情况下,模型越大,获益就越多。说明大的模型是更加label-efficient的,对于有监督和自监督学习都是这样。

图28:大的模型是更加label-efficient的

Projection head 很重要,更深的 Projection head 可以学习到更好的representation,在下游任务做 Fine-tune 之后也更好。

如下图29所示,(a) 图是2层,3层,4层的 Projection head 的Top 1 Acc,发现 Projection head 越深越好。(b) 图是在 Fine-tune 阶段使用不同数量的标签时,分别从第0层,第1层,第2层,第3层开始做 Fine-tune时的性能。从第0层开始就相当于是 SimCLR 的做法了。结果发现从 Projection head 的第1层开始做 Fine-tune 的效果是最佳的。

图29:更深的 Projection head 可以学习到更好的representation

另外还有一个发现是:当使用了很大的模型以后,更深的 Projection head 的作用变小了,因为更大的模型的 Projection head 也更宽了。

一旦确定了下游任务,就不再需要大模型了,可以蒸馏成一个小模型。

下图30是使用不同的损失的性能。

  • Label only指使用1%或10%的标签做监督学习,
  • Label+distillation loss (on labeled set)是指使用上式2作为损失函数,训练集只有有标签的数据。
  • Label+distillation loss (on labeled set)是指使用上式2作为损失函数,训练集既有有标签的数据也有无标签的数据。
  • Distillation loss指只使用上面1式作为损失函数,训练集既有有标签的数据也有无标签的数据。

可以发现只使用蒸馏损失,不使用任何标签就能获得不错的性能。

图30:使用不同的损失的性能

下图31的蓝色线代表只执行完上述前两步得到的Fine-tune之后的模型。

  • 如果把它做 self-distillation ,就是把它作为 Teacher 并找一个和它结构一模一样的 Student 进行蒸馏,结果如橘红色线所示。
  • 如果把 Student 蒸馏成更小的模型 big-to-small distillation,效果如绿线所示。
  • 有监督学习如黑色线所示。

从结果可以发现蒸馏成更小的模型的效果是要由于 self-distillation 的,且在10%的标签数量下可以媲美有监督学习的性能。

图31:不同蒸馏方法与有监督学习的性能对比

最后作者对比了在ImageNet数据集上不同的 Self-Supervised Learning方法的性能对比,如下图32所示:

图32:ImageNet数据集上不同的 Self-Supervised Learning方法的性能对比

使用的 Teacher 模型都是 ResNet-152 (3×+SK) ,即 Fine-tune之后的模型是 ResNet-152 (3×+SK),如果第3步采用self-distillation的话,性能分别是76.6%和93.4%。如果第3步采用big-to-small distillation的话,性能分别是75.9%和93.0%。

下图33展示了 Linear Evaluation 和 Fine-tune 的性能对比。二者的区别在前文中已经数次强调,Linear Evaluation 指的是Encoder的参数固定住,在Encoder后面加一个FC层调节输出维度,且只训练最后的FC层参数,使用全部标签。Fine-tune 指的是在Encoder后面加一个FC层调节输出维度,训练Encoder的参数和FC层参数,使用1%或10%的标签。

可以看出二者之间总体上存在一种线性的相关关系。

如果是第1行,即从Projection head的第一层开始做 Fine-tune 或者 Linear Evaluation ,则相关关系较强。

如果是第2行,即直接去掉Projection head之后开始做 Fine-tune 或者 Linear Evaluation ,则相关关系较弱。

图33:Linear Evaluation 和 Fine-tune 的性能对比

总结

之前的使用自监督获得representations需要特定的算法。大牛上来就说之前的方法多数属于生成方法或者判别方法。 告诉我们contrastive learning才是目前的宠儿。过去一年来,相继有CPC, CMC, MoCo 出来,想要解决的共同一个问题就是,如何提高softmax中negatives的数量。其中 CPC 用了patch based方法,CMC 用了一个memory buffer,MoCo 用了momentum update去keep一个negative sample queue。这篇文章告诉大家,只要机子够多,batch size够大,每个batch中除了positive以外的都当negatives就已经足够了。

本文亮点总结


1.Self-Supervised Learning 的目的一般是使用大量的无 label 的资料去Pre-train一个模型,这么做的原因是无 label 的资料获取比较容易,且数量一般相当庞大,我们希望先用这些廉价的资料获得一个预训练的模型,接着根据下游任务的不同在不同的有 label 数据集上进行 Fine-tune 即可。

2.SimCLR v2 和 SimCLR 相比做了哪些改进?
答: 第 1 个发现是:在使用无标签数据集做 Pre-train 的这一步中,模型的尺寸很重要,用 deep and wide 的模型可以帮助提升性能。第 2 个发现是:使用无标签数据集做 Pre-train 完以后,现在要拿着有标签的数据集 Fine-tune 了。之后再把这个 deep and wide 的模型 蒸馏成一个更小的网络。


如果觉得有用,就请分享到朋友圈吧!

△点击卡片关注极市平台,获取最新CV干货

公众号后台回复“目标检测竞赛”获取目标检测竞赛经验资源~


极市干货
YOLO教程:一文读懂YOLO V5 与 YOLO V4大盘点|YOLO 系目标检测算法总览全面解析YOLO V4网络结构
实操教程:PyTorch vs LibTorch:网络推理速度谁更快?只用两行代码,我让Transformer推理加速了50倍PyTorch AutoGrad C++层实现
算法技巧(trick):深度学习训练tricks总结(有实验支撑)深度强化学习调参Tricks合集长尾识别中的Tricks汇总(AAAI2021
最新CV竞赛:2021 高通人工智能应用创新大赛CVPR 2021 | Short-video Face Parsing Challenge3D人体目标检测与行为分析竞赛开赛,奖池7万+,数据集达16671张!


CV技术社群邀请函 #

△长按添加极市小助手
添加极市小助手微信(ID : cvmart2)

备注:姓名-学校/公司-研究方向-城市(如:小极-北大-目标检测-深圳)


即可申请加入极市目标检测/图像分割/工业检测/人脸/医学影像/3D/SLAM/自动驾驶/超分辨率/姿态估计/ReID/GAN/图像增强/OCR/视频理解等技术交流群


每月大咖直播分享、真实项目需求对接、求职内推、算法竞赛、干货资讯汇总、与 10000+来自港科大、北大、清华、中科院、CMU、腾讯、百度等名校名企视觉开发者互动交流~



觉得有用麻烦给个在看啦~  
good-icon 0
favorite-icon 0
收藏
回复数量: 0
    暂无评论~~
    Ctrl+Enter