zl程序教程

您现在的位置是:首页 >  后端

当前栏目

对比损失思想设计loss function的方法

方法 设计 对比 Function 思想 损失 Loss
2023-06-13 09:18:42 时间
来源:Kaggle竞赛宝典 PaperWeekly本文约4600字,建议阅读10+分钟本文与你分享Contrastive Loss的定义及应用了对比损失的工作小结。

1、Contrastive Loss简介

对比损失在非监督学习中应用很广泛。最早源于 2006 年Yann LeCun的“Dimensionality Reduction by Learning an Invariant Mapping”,该损失函数主要是用于降维中,即本来相似的样本,在经过降维(特征提取)后,在特征空间中,两个样本仍旧相似;而原本不相似的样本,在经过降维后,在特征空间中,两个样本仍旧不相似。同样,该损失函数也可以很好的表达成对样本的匹配程度。

在非监督学习时,对于一个数据集内的所有样本,因为我们没有样本真实标签,所以在对比学习框架下,通常以每张图片作为单独的语义类别,并假设:同一个图片做不同变换后不改变其语义类别,比如一张猫的图片,旋转或局部图片都不能改变其猫的特性。

因此,假设对于原始图片 X,分别对其做不同变换得到 A 和 B,此时对比损失希望 A、B 之间的特征距离要小于 A 和任意图片 Y 的特征距离。

2、Contrastive Loss定义

定义对比损失函数 L 为:

其中,

 代表两个样本特征的欧式距离, 代表特征的维度, 为两个样本是否匹配的标签( 代表两个样本相似或匹配, 代表两个样本不相似或不匹配), 为设定的阈值(超过  的把其 loss 看作 0,即如果两个不相似特征离得很远,那么对比 loss 应该是很低的), 为样本数量。

通过:

可以发现,对比损失可以很好的描述成对样本的匹配程度,可以很好的用于训练提取特征的模型:

当  时,即两个样本相似或匹配时,损失函数 ,即如果原本相似或匹配的样本如果其被模型提取的特征欧氏距离很大,说明模型效果不好导致 loss 很大。

当  时,即两个样本不相似或不匹配时,损失函数 ,如果这时两个样本被模型提取的特征欧式距离很小,那么 loss 会变大以增大模型的惩罚从而使 loss 减小,如果两个样本被模型提取的特征欧式距离很大,说明两个样本特征离得很远,此时如果超过阈值  则把其 loss 看作 0,此时的 loss 很小。

3、应用了对比损失的工作小结

论文标题:Improved Deep Metric Learning with Multi-class N-pair Loss Objective

论文地址:https://proceedings.neurips.cc/paper/2016/file/6b180037abbebea991d8b1232f8a8ca9-Paper.pdf

N-pair loss,需要从 N 个不同的类中构造 N 对样本,自监督学习。

本文是基于 Distance metric learning,目标是学习数据表征,但要求在 embedding space 中保持相似的数据之间的距离近,不相似的数据之间的距离远。

其实在诸如人脸识别和图片检索的应用中,就已经使用了 contrastive loss 和 triplet loss,但仍然存在一些问题,比如收敛慢,陷入局部最小值,相当部分原因就是因为损失函数仅仅只使用了一个 negative 样本,在每次更新时,与其他的 negative 的类没有交互。之前 LeCun 提出的对比损失只考虑输入成对的样本去训练一个神经网络去预测它们是否属于同一类,上文已经解释了对比损失。

Triplet loss(三元损失函数)是 Google 在 2015 年发表的 FaceNet 论文中提出的,与前文的对比损失目的是一致的,具体做法是考虑到 query 样本和 postive 样本的比较以及 query 样本和 negative 样本之间的比较,Triplet Loss 的目标是使得相同标签的特征在空间位置上尽量靠近,同时不同标签的特征在空间位置上尽量远离,同时为了不让样本的特征聚合到一个非常小的空间中要求对于同一类的两个正例和一个负例,负例应该比正例的距离至少远 m (margin):

该 loss 将促使 query 样本和 positive 样本之间的距离比 query 样本和 negative 样本之间的距离大于 m (margin)。

▲ 可以看出经过 Triplet loss 学习以后同类的 Positive 样本和 Anchor 的距离越来越近而不同类的 Negative 样本和 Anchor 的距离越来越远。

但是三元损失函数考虑的 negative 样本太少了,收敛慢,因此,本文提出了一个考虑多个 negative 样本的方法:(N+1)-tuplet loss,即训练样本为样本 x 以及(N-1)个 negative 样本和一个 positive 样本,当 N=2 时,即是 triplet loss。训练样本为 : 是一个 positive 样本, 是(N-1)个 negative 样本。

由图所示(蓝色代表 positive 样本,红色代表 negative 样本),Triplet loss 在将 positive 样本拉近的同时一次只能推离一个 negative 样本;而 (N+1)-tuplet loss 基于样本之间的相似性,一次可以将(N-1)个 negative 样本推离(提高了收敛速度),而且 N 的值越大,负样本数越多,近似越准确

但是如果直接采用 (N+1)-tuplet loss,batch size 为 N,那么一次更新需要传递 Nx(N+1)个样本,网络层数深的时候会有问题,为了避免过大的计算量,本文提出了 N-pair loss,如下图

N-pair loss 其实就是重复利用了 embedding vectors 的计算来作为 negative 样本(把其他样本的正样本作为当前样本的负样本,这样就不用重复计算不同样本的负样本,只需要计算 N 次即可得出),避免了每一行都要计算新的 negative 样本的 embedding vectors,从而将  的计算量降低为 2N(batch size=N,需要计算 N 次,之前计算负样本需要计算 N 次,所以计算量=N+N=2N)。

上述文章的亮点在于,首先提出了需要在三元损失函数中加入更多的负样本提高收敛速度,然后又想到了一种方式通过将其他样本的正样本当作当前样本的负样本的方法降低了计算复杂度。

论文标题:

Unsupervised Feature Learning via Non-Parametric Instance Discrimination

论文地址:

https://arxiv.org/pdf/1805.01978.pdf

Instance discrimination 区分不同实例,将当前实例于不同实例进行空间划分 memory bank 由数据集中所有样本的表示组成。

本文将 instance discrimination 机智地引入了 memory bank 机制,并且真正地把 loss 用到了 unsupervised learning。该论文主要论述如何通过非参数的 instance discrimination 进行无监督的特征学习。主要的思想是将每个单一实例都看作不同的“类”。

通过 CNN backbone,原始图片输入网络后输出一个经过 L2 标准化的 128 维向量,通过 Non-Parametric Softmax Classifier 计算每个单一样本被识别正确的概率,同时使用 Memory Bank 存储特征向量,通过 NCE(noise-contrastive estimation,噪音对比估计)来近似估计 softmax 的数值减少计算复杂度,最后使用 Proximal Regularization 稳定训练过程的波动性。

实例间的相似度直接从特征中以非参数方式计算,即:每个实例的特征存储在离散的 bank 中,而不是网络的权重。

噪声对比估计是一种采样损失,通常用于训练具有较大输出词汇量的分类器。在大量可能的类上计算 softmax 开销非常大。使用 NCE,我们可以通过训练分类器从“真实”分布和人工生成的噪声分布中区分样本,从而将问题简化为二分类问题。

因此,主要有以下三个问题需要考虑:

  • 能否仅通过特征表示来区分不同的实例。
  • 能否通过纯粹的判别学习(discriminative learning)反应样本间的相似性。
  • 将不同个例都看作不同的“类”,那这个数量将是巨大的,该如何进行处理。

Non-Parametric Softmax Classifier

采用 softmax 的 instance-level 的分类目标,假如有 n 个 images ,即有 n 个类,,它们的特征为 。传统的 parametric 的softmax 可以表示为:

其中  是类别j的权重向量, 用来评价 v 与第 j 个实例的匹配程度。这种 loss 的问题是权重向量只是作为一种类的 prototype,而无法对实例之间进行明确的比较。所以本文通过替换  为 ,并且限制 ,可以得到一种 non-parametric 的 softmax 函数,这样就不用训练权重参数:

 是 temperature 参数,控制 softmax 的平滑程度。

非参数的 softmax 主要思路是每个样本特征除了可以作为特征之外,也可以起到分类器的作用。因为 L2-norm 之后的特征乘积本身就等于 cos 相似性,。学习的目标就是最大化 joint probability:

,即每一个  越大越好,也等同于最小化 negative log-likelihood:

使用 Mermory Bank V 来存储上述的 ,在每个 iteration 对应修改其值 ,在初始化时通过单位随机向量对 V 进行初始化。

NCE Loss

如果直接用上述的 loss function 去训练,当类的数量n很大时,要求的计算量非常大,于是使用 NCE 来估算。其基本思想是将多分类问题转化为一组二分类问题,其中二分类任务是区分数据样本和噪声样本。关于对 NCE loss 的理解如下:

当我们设计一个模型来拟合数据时,经常会遇上指数族分布:

其中分母部分是归一化常数,一个目的是用来让这个分布真的成为一个“分布”要求(分布积分=1)。很多时候,比如计算一个巨大(几十上百万词)的词表在每一个词上的概率得分的时候,计算这个分母会变得非常非常非常消耗资源。 比如一个 language model 最后 softmax 层中,在 inference 阶段其实只要找到 argmax 的那一项就够了,并不需要归一化,但在 training stage,由于分母Z中是包含了模型参数的,所以也要一起参与优化,所以这个计算省不了

而 NCE 做了一件很 intuitive 的事情:用负样本采样的方式,不计算完整的归一化项。让模型通过负样本,估算出真实样本的概率,从而在真实样本上能做得了极大似然。相当于把任务转换成了一个分类任务,然后再用类似交叉熵的方式来对模型进行优化(其实本质上是优化了两个部分:模型本身,和一个负例采样的分布和参数)。 另一方面,NCE 其实证明了这种采样在负例足够多的情况下,对模型梯度优化方向和“完整计算归一化项进行优化”是一致的,这一点证明了 NCE 在用负采样方式解决归一化项的正确性。

Memory bank 中特征表示  对应于第  个样例的概率为:

我们设定噪声分布为一个均匀分布:,假设噪声样本的频率是数据样本的  倍,那么样本  及特征  来自数据分布  的后验概率为:

训练目标为最小化:

其中, 指代真实数据分布,对  而言  是  的特征; 是来自另一幅图片,从噪声分布  中随机采样得到。注: 和  都是从 Memory Bank 中采样得到的。

 的计算量过大,我们把它当作常量,由 Monte Carlo 算法估计得到:

 是 indices 的随机子集,NCE 将每个样例的计算复杂度从  减少到 。

最后一点是,这篇文章加入了近似正则化项 ,来使训练过程更加平滑和稳定。

本文引入 memory bank 把前一个 step 学习到的实例特征存储起来,然后在下一个 step 把这些存储的 memory 去学习。效率有所提升。但是实际在优化的时候当前的实例特征是跟 outdated memory 去对比的,所以学习效果还不是最优的。

论文标题:

Momentum Contrast for Unsupervised Visual Representation Learning

论文地址:

https://arxiv.org/pdf/1911.05722.pdf

解决了一个非常重要的工程问题:如何节省内存节省时间搞到大量的 negative samples?

至于文章的 motivation,之前 contrastive learning 存在两种问题。在用 online 的 dictionary 时,也就是文章中比较的 end-to-end 情形,constrastive learning 的性能会受制于 batch size,或者说显存大小。在用 offline 的 dictionary 时,也就是文章中说的 memory bank(InstDisc)情形,dictionary 是由过时的模型生成的,某种程度上可以理解为 supervision 不干净,影响训练效果。那么很自然的,我们想要一个 trade-off,兼顾 dictionary 的大小和质量。文章给出的解法是对模型的参数空间做 moving average,相当于做一个非常平滑的 update。

MoCo 完全专注在 Contrastive Loss 上,将这个问题想象成有一个很大的字典,神经网络的目的就是一个 Encoder 要将图片 Encode 成唯一的一把 Key,此时要如何做到让 Key Space Large and Consistent 是最重要的。

首先借鉴了 instance discrimination 的文章的 Memory Bank,建一个 Bank 来保存所有的 Key (或称为 Feature)。此方法相对把所有图塞进 Batch 少用很多内存,但对于很大的 Dataset 依旧难以按比例扩大。

因此,MoCo 改进了 Bank,用一个 Dynamic Queue 来取代,但是单纯这样做的话是行不通的,因为每次个 Key 会受到 Network 改变太多,Contrastive Loss 无法收敛。因此 MoCo 将种子 feature extractor 拆成两个独立的 Network:Encoder 和 Momentum Encoder。

:Encoder,:Momentum Encoder,初始化时,它们的参数值一致。Queue 里 maintain 着最新的 K 个 key。

为了结合图 5 对文章中的 Algorithm 进行分析,我们假设 Batch size N=1,同样的 x 经过不同的 augmentation,encode 为 q 和 ,它们俩为 positive pair。将 q 与 Queue 中的 K 个 key (Negative Sample )进行比较,计算 Similarity。

由此,即可按照上述的 N-pair contrastive loss 计算 loss,并对  Encoder 更新parameters。等 Encoder Update 完后,在用 Momentum Update  Momentum Encoder。并将这次的 Batch 放入到 Queue 中。

可以看到 key 对应的  Momentum Encoder 是由 query 对应的  Encoder 来更新的,同时受到 key 对应的 Encoder 上一次的状态(更新后的 Encoder)影响。因此其更新速率,与 query 对应的 encoder 相比要慢,能提供很稳定的 Key,也就是 Momentum Encoder 把这个 Key Space 先摆好。

具体要有多慢呢?慢到 Queue 中最旧 key 依然能够反映出最新的 Momentum encoder 信息。所以文章给出 m=0.999,要远好于 m=0.9。直观的的感受就是,key 对应的 Momentum encoder 基本不动,非常缓慢的更新,Queue 中所有的 key 可以近似的看成由目前的 Momentum encoder 编码得到。

如果  与 Queue 中原本的 Key 比较远,如图 5 所示,再回想一下,MoCo 本质上还是在做 instance discrimination。所以,这时的 Loss 较小,且主要去 Update  Encoder,使得 q 更接近 ,而 Momentum Encoder 更新又很缓慢,它更新后, 依然会与 Queue 中原本的 Key 相距较远。

如果  与 Queue 中原本的 Key容易混淆,这时候的 Loss 较大, Encoder 的更新使得 q 远离 Queue 中原本的 Key,同时尽可能地距离  较近,随后 Momentum Encoder 缓慢更新,倾向于使得  远离 Queue 中原本的 Key,相当于找一个比较空的区域放 , 而不影响原本的 Queue 中原本的 Key。但此处只是直观上的分析,缺乏严谨的理论证明。

近期,何凯明团队推出了 MoCo_V2,效果相对于 V1 有了较大提升,但没有改变 MoCo_V1 的框架。

参考文献:

[1] https://zhuanlan.zhihu.com/p/149748513

[2] https://zhuanlan.zhihu.com/p/103565790

[3] https://zhuanlan.zhihu.com/p/139403505

[4] https://www.zhihu.com/question/355779873/answer/905129680

[5] https://kelispinor.medium.com/%

E7%B0%A1%E4%BB%8B-self-supervised-learning-%E7%9A%84%E8%BF%91%E6%9C%9F%E7%99%BC%E5%B1%95-2018-2020-a3872662727d

编辑:黄继彦

校对:杨学俊‍