对比表征学习(Contrastive Representation Learning)

111

文章目录

  1. 对比训练目标
    1. 对比损失 (Contrastive Loss)
    2. 三元组损失
    3. 结构加强损失 (Lifted Structured Loss)
    4. N对损失 (N-pair Loss)
    5. NCE
    6. InfoNCE
    7. Soft-Nearest Neighbors Loss
    8. 通用设定
  2. 关键部分
    1. 数据加强
    2. 使用大的批大小 (Large Batch Size)
    3. 高难度负样本挖掘
  3. 视觉类:图片嵌入
    1. 图片增强
      1. 基本图片增强方法
      2. 增强策略
      3. 图片混合
    2. 并行增强
      1. SimCLR
      2. Barlow Twins
      3. BYOL
    3. 内存库
      1. 实例间区分(应用内存库)
      2. MoCo & MoCo-V2
      3. CURL
    4. 特征聚类
      1. DeepCluster
      2. SwAV
    5. 使用监督数据集
      1. CLIP
      2. 监督对比学习
  4. 语言类:句子嵌入
    1. 文本增强
      1. 词法编辑 (Lexical Edits)
      2. 回译 (Back-translation)
      3. Dropout 和 切除 (Cutoff)
    2. 自然语言推理
      1. Sentence-BERT
      2. BERT-flow
      3. 白化操作(Whitening Operation)
    3. 非监督句子嵌入学习
      1. 上下文预测
      2. 互信息最大化
  5. 引用

本文为翻译文章,原文链接为:https://lilianweng.github.io/lil-log/2021/05/31/contrastive-representation-learning.html。感谢作者Lilian Weng的辛苦工作。


对比学习(Contrastive Learning)的主要思想是让相似样本表征间的距离相近,而差别很大样本表征间的距离较远。对比学习在监督学习和非监督学习中都可以使用,在许多的计算机视觉和自然语言处理相关的任务中都有很好的性能表现。

对比学习的目标是学习得到一个嵌入空间 (Embedding Space),在此空间中相似样本的表征间距离较近,不同样本的表征间距离较远。对比学习可以在监督学习和非监督学习的环境中使用,在使用非监督数据时,对比学习是自监督学习中最强大的算法之一。

对比训练目标

在对比学习出现之初,对应的损失函数(loss functions)中,只包含一个正、负样本对。而在近期的研究中,包含多个正负样本对成了一个趋势。

对比损失 (Contrastive Loss)

对比损失 (Chopra 等人, 2005 是以对比学习方式呈现的深度学习方法中最早的目标函数之一。

给定一个样本列表$\{ \mathbf{x}_i \}$以及相对应的标签$y_i \in \{1, \dots, L\}$,我们希望学习到一个函数$f_\theta(.): \mathcal{X}\to\mathbb{R}^d$,它可以将$x_i$编码成一个嵌入向量 (embedding vector)。这些嵌入向量满足:同一分类的样本具有相似的嵌入向量,而不同分类样本的嵌入向量则差异较大。因此,对比损失使用一对输入$(x_i, x_j)$作为输入,当这两个样本为同一分类时,目标函数就最小化它们对应嵌入表征间的距离,反之则最大化他们间的距离。损失函数公式如下:

$$ \mathcal{L}_\text{cont}(\mathbf{x}_i, \mathbf{x}_j, \theta) = \mathbb{1}[y_i=y_j] \| f_\theta(\mathbf{x}_i) - f_\theta(\mathbf{x}_j) \|^2_2 + \mathbb{1}[y_i\neq y_j]\max(0, \epsilon - \|f_\theta(\mathbf{x}_i) - f_\theta(\mathbf{x}_j)\|_2)^2 $$

其中 $\epsilon$ 是超参数,定义了相同样本间距离的下界(若距离小于这个值则会进行优化,一旦不同类别样本间的距离已经超过了$\epsilon$,则不必再优化)。

三元组损失

三元组损失函数最早在FaceNet提出,被用于识别不同图像是否属于同一个人。

译著:我们之前介绍过这篇文章,感兴趣可参考:https://paperexplained.cn/articles/article/detail/16/

下图(论文截图)展示了三元组损失函数的基本思想。

三元组损失:每个标定样本会给出与其对应的一个正样本、一个负样本

给定一个标定(anchor input)输入$\mathbf{x}$,我们会选择一个正样本$\mathbf{x}^+$和一个负样本$\mathbf{x}^-$,正样本的类别与标定样本属于同一类别,而负样本属于不同类别。三元组损失的目标是最小化$\mathbf{x}$与$\mathbf{x}^+$之间的距离,同时最大化$\mathbf{x}$与$\mathbf{x}^-$间的距离,表示如下:

$$ \mathcal{L}_\text{triplet}(\mathbf{x}, \mathbf{x}^+, \mathbf{x}^-) = \sum_{\mathbf{x} \in \mathcal{X}} \max\big( 0, \|f(\mathbf{x}) - f(\mathbf{x}^+)\|^2_2 - \|f(\mathbf{x}) - f(\mathbf{x}^-)\|^2_2 + \epsilon \big) $$

其中 $\epsilon$ 是一个超参数,用于指示不同类别样本间距离与相同类别样本间距离之差的期望值,一旦训练得到的表示可以让不同类别的样本之间距离足够远 ($\epsilon$那么远),就无需继续优化了(这个距离可以看作是足够让我们区分不同样本的最小距离)。

该方法中,我们选择一个具有挑战性的负样本对于改善模型性能非常重要(试想一下,如果你每次都选择了一个非常容易区分的样本,那么最终效果肯定不理想)。

结构加强损失 (Lifted Structured Loss)

结构加强损失将一个训练batch中所有样本对都用于训练,以此改善计算效率。下图可以清晰的展示对比损失、三元组损失与结构加强损失之间的联系。

对比损失 vs 三元组损失 vs 结构加强损失

令两个样本间的距离为:$D_{ij} = \| f(\mathbf{x}_i) - f(\mathbf{x}_j) \|_2$,那么结构加强损失函数定义为:

$$ \begin{aligned} \mathcal{L}_\text{struct} &= \frac{1}{2\vert \mathcal{P} \vert} \sum_{(i,j) \in \mathcal{P}} \max(0, \mathcal{L}_\text{struct}^{(ij)})^2 \\ \text{其中 } \mathcal{L}_\text{struct}^{(ij)} &= D_{ij} + \color{red}{\max \big( \max_{(i,k)\in \mathcal{N}} \epsilon - D_{ik}, \max_{(j,l)\in \mathcal{N}} \epsilon - D_{jl} \big)} \end{aligned} $$

其中$\mathcal{P}$为正样本集合,$\mathcal{N}$为负样本集合。注意每个批次数据训练时,样本间的距离矩阵可以很容易计算得到。

上式$\mathcal{L}_\text{struct}^{(ij)}$中红色部分用于寻找到比较困难的样本,但这个操作不是平滑的,并且可能会导致训练最终收敛到一个局部最优值。因此,对其稍作修改:

$$ \mathcal{L}_\text{struct}^{(ij)} = D_{ij} + \log \Big( \sum_{(i,k)\in\mathcal{N}} \exp(\epsilon - D_{ik}) + \sum_{(j,l)\in\mathcal{N}} \exp(\epsilon - D_{jl}) \Big) $$

论文中,作者还提出在每批数据训练时,在给定一些随机的正样本对时,通过主动包含一些困难的负样本这样的方法来加强负样本的质量。

N对损失 (N-pair Loss)

N对损失 (Multi-Class N-pair loss)对三元组损失进行了推广,该损失函数中包含了多个负样本。

给定一组样本,包含$(N+1)$个样本$\{ \mathbf{x}, \mathbf{x}^+, \mathbf{x}^-_1, \dots, \mathbf{x}^-_{N-1} \}$,它包含一个标定样本$\mathbf{x}$,一个正样本$\mathbf{x}^+$和$N-1$个负样本$\mathbf{x}^-_i$,那么 $N$对损失函数 定义为:

$$ \begin{aligned} &\ \mathcal{L}_\text{N-pair}(\mathbf{x}, \mathbf{x}^+, \{\mathbf{x}^-_i\}^{N-1}_{i=1}) \\ =&\ \log\big(1 + \sum_{i=1}^{N-1} \exp(f(\mathbf{x})^\top f(\mathbf{x}^-_i) - f(\mathbf{x})^\top f(\mathbf{x}^+))\big) \\ =&\ -\log\frac{\exp(f(\mathbf{x})^\top f(\mathbf{x}^+))}{\exp(f(\mathbf{x})^\top f(\mathbf{x}^+)) + \sum_{i=1}^{N-1} \exp(f(\mathbf{x})^\top f(\mathbf{x}^-_i))} \end{aligned} $$

如果我们给每个分类都采样出一个负样本,那么上面的损失函数就和多分类任务的softmax损失函数一样。

NCE

噪声对比估计 (Noise Contrastive Estimation, NCE)是一种估计统计模型参数的方法,由Gutmann & Hyvarinen于2010年提出。它的主要思想就是使用逻辑回归来区分目标数据与噪声数据。这里https://lilianweng.github.io/lil-log/2017/10/15/learning-word-embedding.html#noise-contrastive-estimation-nce介绍了如何使用 NCE 进行词嵌入学习。

令$\mathbf{x}$为目标样本$\mathbf{x}\sim P(\mathbf{x} \vert C=1; \theta) = p_\theta(\mathbf{x})$,$\tilde{\mathbf{x}}$为噪声样本$\tilde{\mathbf{x}} \sim P(\tilde{\mathbf{x}} \vert C=0) = q(\tilde{\mathbf{x}})$。我们定义样本$u$相对于噪声分布的logit为:

$$ \ell_\theta(\mathbf{u}) = \log \frac{p_\theta(\mathbf{u})}{q(\mathbf{u})} = \log p_\theta(\mathbf{u}) - \log q(\mathbf{u}) $$

我们将概率表示为sigmoid形式$\sigma(.)$后,可以使用交叉熵损失:

$$ \begin{aligned} \mathcal{L}_\text{NCE} &= - \frac{1}{N} \sum_{i=1}^N \big[ \log \sigma (\ell_\theta(\mathbf{x}_i)) + \log (1 - \sigma (\ell_\theta(\tilde{\mathbf{x}}_i))) \big] \\ \text{ 其中 }\sigma(\ell) &= \frac{1}{1 + \exp(-\ell)} = \frac{p_\theta}{p_\theta + q} \end{aligned} $$

我们这里给出的是NCE损失函数的原始形式,其中仅包含了单个正样本和单个噪声样本。NCE后续的许多工作的损失函数中都包含了多个负样本 (这些方法也叫NCE)。

InfoNCE

InfoNCE (Contrastive Predictive Coding, CPC; Van Den Oord 等, 2018受到NCE的启发,使用分类交叉熵损失将某个正样本从一个噪声样本集合中识别出来。

给定一个背景向量$c$,正样本应该从条件分布$p(x|c)$中采样得到,而负样本应该从设定分布$p(x)$中采样得到,设定分布$p$与背景向量$c$无关。为了简洁,我们将所有样本标记为$X=\{ \mathbf{x}_i \}_{i=1}^N$,这些样本中仅有一个$\mathbf{x}_{pos}$为正样本。那么我们正确预测正样本的概率为:

$$ p(C=\texttt{pos} \vert X, \mathbf{c}) = \frac{p(x_\texttt{pos} \vert \mathbf{c}) \prod_{i=1,\dots,N; i \neq \texttt{pos}} p(\mathbf{x}_i)}{\sum_{j=1}^N \big[ p(\mathbf{x}_j \vert \mathbf{c}) \prod_{i=1,\dots,N; i \neq j} p(\mathbf{x}_i) \big]} = \frac{ \frac{p(\mathbf{x}_\texttt{pos}\vert c)}{p(\mathbf{x}_\texttt{pos})} }{ \sum_{j=1}^N \frac{p(\mathbf{x}_j\vert \mathbf{c})}{p(\mathbf{x}_j)} } = \frac{f(\mathbf{x}_\texttt{pos}, \mathbf{c})}{ \sum_{j=1}^N f(\mathbf{x}_j, \mathbf{c}) } $$

其中打分函数(scoring function) $f(\mathbf{x}, \mathbf{c}) \propto \frac{p(\mathbf{x}\vert\mathbf{c})}{p(\mathbf{x})}$。

InfoNCE损失函数为:

$$ \mathcal{L}_\text{InfoNCE} = - \mathbb{E} \Big[\log \frac{f(\mathbf{x}, \mathbf{c})}{\sum_{\mathbf{x}' \in X} f(\mathbf{x}', \mathbf{c})} \Big] $$

实际上$f(x, c)$给出了概率密度比$\frac{p(x\vert c)}{p(x)}$的一个估计,这和互信息(mutual information)优化有点关联。为了最大化输入$x$和背景向量$c$之间的互信息,我们有:

$$ I(\mathbf{x}; \mathbf{c}) = \sum_{\mathbf{x}, \mathbf{c}} p(\mathbf{x}, \mathbf{c}) \log\frac{p(\mathbf{x}, \mathbf{c})}{p(\mathbf{x})p(\mathbf{c})} = \sum_{\mathbf{x}, \mathbf{c}} p(\mathbf{x}, \mathbf{c})\log\color{blue}{\frac{p(\mathbf{x}|\mathbf{c})}{p(\mathbf{x})}} $$

其中蓝色部分的对数项由$f$估计得到。

对于序列预测任务,CPC并不直接对未来的观察值$p_k(\mathbf{x}_{t+k} \vert \mathbf{c}_t)$进行建模,而是对一个密度函数建模,以保留$x_{t+k}$和$c_t$之间的互信息:

$$ f_k(\mathbf{x}_{t+k}, \mathbf{c}_t) = \exp(\mathbf{z}_{t+k}^\top \mathbf{W}_k \mathbf{c}_t) \propto \frac{p(\mathbf{x}_{t+k}\vert\mathbf{c}_t)}{p(\mathbf{x}_{t+k})} $$

其中$z_{t+k}$为输入编码,$W_k$为训练参数矩阵。

Soft-Nearest Neighbors Loss

Soft-Nearest Neighbors Loss (SNNLoss) (Salakhutdinov & Hinton 2007Frosst 等,2019 中引入了多个正样本。

给定一批训练样本 $\{\mathbf{x}_i, y_i)\}^B_{i=1}$和一个用于衡量两个样本间相似度的函数$f(.,.)$, SNNLoss 定义为:

$$ \mathcal{L}_\text{snn} = -\frac{1}{B}\sum_{i=1}^B \log \frac{\sum_{i\neq j, y_i = y_j, j=1,\dots,B} \exp(- f(\mathbf{x}_i, \mathbf{x}_j) / \tau)}{\sum_{i\neq k, k=1,\dots,B} \exp(- f(\mathbf{x}_i, \mathbf{x}_k) /\tau)} $$

其中$\tau$为表示温度的超参数,它用于控制特征在表征空间中的集中程度。在温度较低时,损失由小的距离主导,分隔较远的样本对对于损失函数的贡献不多。

通用设定

我们可以将SNN损失中"类别"和"标签"的定义弱化,这样我们就可以从非监督数据中创建正负样本:比如,我们可以使用类似数据增强的方法去创建原始数据的带噪声版本。

近期大多数对比学习相关的研究工作中,目标函数都符合下面的定义,它们都会同时使用多个正负样本对。依照论文Wang & Isola, 2020中的设定,定义$p_\texttt{data}(.)$为$\mathbb{R}^n$上的数据分布,$p_\texttt{pos}(.,.)$为$\mathbb{R}^{n\times n}$上的正样本对的分布,这两个分布应该满足:

  • 对称性:$\forall \mathbf{x}, \mathbf{x}^+, p_\texttt{pos}(\mathbf{x}, \mathbf{x}^+) = p_\texttt{pos}(\mathbf{x}^+, \mathbf{x})$
  • 边缘分布匹配性:$\forall \mathbf{x}, \int p_\texttt{pos}(\mathbf{x}, \mathbf{x}^+) d\mathbf{x}^+ = p_\texttt{data}(\mathbf{x})$

如果我们让编码器去学习一个L2归一化之后的特征向量编码,那么我们的对比学习目标为:

$$ \begin{aligned} \mathcal{L}_\text{contrastive} &= \mathbb{E}_{(\mathbf{x},\mathbf{x}^+)\sim p_\texttt{pos}, \{\mathbf{x}^-_i\}^M_{i=1} \overset{\text{i.i.d}}{\sim} p_\texttt{data} } \Big[ -\log\frac{\exp(f(\mathbf{x})^\top f(\mathbf{x}^+) / \tau)}{ \exp(f(\mathbf{x})^\top f(\mathbf{x}^+) / \tau) + \sum_{i=1}^M \exp(f(\mathbf{x})^\top f(\mathbf{x}_i^-) / \tau)} \Big] & \\ &\approx \mathbb{E}_{(\mathbf{x},\mathbf{x}^+)\sim p_\texttt{pos}, \{\mathbf{x}^-_i\}^M_{i=1} \overset{\text{i.i.d}}{\sim} p_\texttt{data} }\Big[ - f(\mathbf{x})^\top f(\mathbf{x}^+) / \tau + \log\big(\sum_{i=1}^M \exp(f(\mathbf{x})^\top f(\mathbf{x}_i^-) / \tau)\big) \Big] & \scriptstyle{\text{; Assuming infinite negatives}} \\ &= -\frac{1}{\tau}\mathbb{E}_{(\mathbf{x},\mathbf{x}^+)\sim p_\texttt{pos}}f(\mathbf{x})^\top f(\mathbf{x}^+) + \mathbb{E}_{ \mathbf{x} \sim p_\texttt{data}} \Big[ \log \mathbb{E}_{\mathbf{x}^- \sim p_\texttt{data}} \big[ \sum_{i=1}^M \exp(f(\mathbf{x})^\top f(\mathbf{x}_i^-) / \tau)\big] \Big] & \end{aligned} $$

关键部分

数据加强

给定一系列训练样本,我们可以使用数据加强技术来创建数据的带噪声版本,这些噪声样本也可以被用做正样本。合理的数据加强技术对于学习到一个好的、通用的特征嵌入表示非常重要。它将一些非核心的变化引入到样本中去而保持了样本原本的含义 ,这就可以让模型只去学习那些样本中至关重要的本质部分。举例来说,在SimCLR的实验中,随机裁剪和随机颜色调整的组合使用对于图片的表示学习性能至关重要。

使用大的批大小 (Large Batch Size)

在许多对比学习的成功案例中,使用大的批大小是另外一个非常重要的部分(比如:SimCLR, CLIP),这一点在算法需要依赖于批内的负样本数据时尤为突出。只有当批大小足够大时,损失函数才能够覆盖到足够量的负样本,这样才能让学习器最终学习到足够具有代表性的表征方法。

高难度负样本挖掘

高难度的负样本虽然与标定样本有着不同的标签,但是它们在特征空间中的嵌入表示却与标定样本距离很近。在监督学习的数据集中,我们可以得到真实的数据标签,我们很容易就可以识别出高难度的负样本。举例来说,我们在训练一个句子嵌入(sentence embedding)任务,我们可以将NLI数据集中被标记为"contradiction"的句子对视为高难度样本(比如:SimCSE),或者使用BM25返回的错误的候选项作为困难样本(DPR; Karpukhin 等,2020

然而,在无监督学习的环境中进行高难度负样本挖掘是很棘手的。虽然增加训练批大小或内存库(memory bank)大小可以让我们包含更多的(高难度)负样本,但是这会带来大量内存占用的负担。

Chuang 等人,2020研究了对比学习中采样偏差问题,并提出了去偏差(debiased)损失函数。在非监督学习的设定下,由于我们并不知道样本的真实标签,我们可能会偶然采样到非负样本。这样的错误采样带来的偏差会导致模型最终性能的严重下降。

错误的负样本采样带来性能下降

假设标定类别$c$是一个均匀分布$\rho(c)=\eta^+$,这样观察到一个不同类别的概率就为$\eta^- = 1-\eta^+$。

  • 得到样本$\mathbf{x}$的一个正样本的概率为 $p^+_x(\mathbf{x}')=p(\mathbf{x}'\vert \mathbf{h}_{x'}=\mathbf{h}_x)$
  • 得到样本$\mathbf{x}$的一个负样本的概率为 $p^-_x(\mathbf{x}')=p(\mathbf{x}'\vert \mathbf{h}_{x'}\neq\mathbf{h}_x)$

我们在采样$\mathbf{x}^-$的时候,我们不知道真实的$p^-_x(\mathbf{x}^-)$,因此$\mathbf{x}^-$可能会以概率$\eta^+$采样到类别$c$。实际的数据采样分布为:

$$ p(\mathbf{x}') = \eta^+ p^+_x(\mathbf{x}') + \eta^- p_x^-(\mathbf{x}') $$

这样我们可以使用$p^-_x(\mathbf{x}') = (p(\mathbf{x}') - \eta^+ p^+_x(\mathbf{x}'))/\eta^-$来对样本$\mathbf{x}^-$进行采样,以去除偏差。假设我们使用概率$p$采样了$N$个样本$\{\mathbf{u}_i\}^N_{i=1}$,使用概率$p_x^+$采样了$M$个样本$\{ \mathbf{v}_i \}_{i=1}^M$,我们可以估计对比学习损失函数公式的分母中后一项的期望$\mathbb{E}_{\mathbf{x}^-\sim p^-_x}[\exp(f(\mathbf{x})^\top f(\mathbf{x}^-))]$:

$$ \begin{align} & \ g(\mathbf{x}, \{\mathbf{u}_i\}^N_{i=1}, \{\mathbf{v}_i\}_{i=1}^M) \\ =& \ \max\Big\{\frac{1}{\eta^-}\Big( \frac{1}{N}\sum_{i=1}^N \exp(f(\mathbf{x})^\top f(\mathbf{u}_i)) - \frac{\eta^+}{M}\sum_{i=1}^M \exp(f(\mathbf{x})^\top f(\mathbf{v}_i)) \Big), \exp(-1/\tau) \Big\} \end{align} $$

其中,$\tau$为温度参数,$exp(-1/\tau)$为 $\mathbb{E}_{\mathbf{x}^-\sim p^-_x}[\exp(f(\mathbf{x})^\top f(\mathbf{x}^-))]$的理论下界。

最终的去偏差损失函数为:

$$ \mathcal{L}^{N,M}_\text{debias}(f) = \mathbb{E}_{\mathbf{x},\{\mathbf{u}_i\}^N_{i=1}\sim p;\;\mathbf{x}^+, \{\mathbf{v}_i\}_{i=1}^M\sim p^+} \Big[ -\log\frac{\exp(f(\mathbf{x})^\top f(\mathbf{x}^+)}{\exp(f(\mathbf{x})^\top f(\mathbf{x}^+) + N g(x,\{\mathbf{u}_i\}^N_{i=1}, \{\mathbf{v}_i\}_{i=1}^M)} \Big] $$

使用去偏差损失函数效果 (t-SNE表征可视化)

接上,Robinson等人,2021以高难度负样本为目标,重新调整了负样本的权重,将采样概率权重$p^-_x(x')$增加到与标定样本的相似度成正比(这样困难样本,即相似度高的负样本采样概率高),新的采样概率$q_\beta(x^-)$为:

$$ q_\beta(\mathbf{x}^-) \propto \exp(\beta f(\mathbf{x})^\top f(\mathbf{x}^-)) \cdot p(\mathbf{x}^-) $$

其中$\beta$为超参数。

我们可以通过使用重要性采样来估计分母中的第二项$\mathbb{E}_{\mathbf{x}^- \sim q_\beta} [\exp(f(\mathbf{x})^\top f(\mathbf{x}^-))]$,其中两个配分函数$Z_\beta, Z^+_\beta$都可以通过经验估计。

$$ \begin{aligned} \mathbb{E}_{\mathbf{u} \sim q_\beta} [\exp(f(\mathbf{x})^\top f(\mathbf{u}))] &= \mathbb{E}_{\mathbf{u} \sim p} [\frac{q_\beta}{p}\exp(f(\mathbf{x})^\top f(\mathbf{u}))] = \mathbb{E}_{\mathbf{u} \sim p} [\frac{1}{Z_\beta}\exp((\beta + 1)f(\mathbf{x})^\top f(\mathbf{u}))] \\ \mathbb{E}_{\mathbf{v} \sim q^+_\beta} [\exp(f(\mathbf{x})^\top f(\mathbf{v}))] &= \mathbb{E}_{\mathbf{v} \sim p^+} [\frac{q^+_\beta}{p}\exp(f(\mathbf{x})^\top f(\mathbf{v}))] = \mathbb{E}_{\mathbf{v} \sim p} [\frac{1}{Z^+_\beta}\exp((\beta + 1)f(\mathbf{x})^\top f(\mathbf{v}))] \end{aligned} $$

NCE损失,去偏对比损失,M=1时的高难度负样本损失($M=1$)伪代码如下:

# 参数说明
# pos      : 正样本内积的指数值 ( exp(x1 * x2) )
# neg      : 负样本内积的指数值 ( exp(x1 * x2) )
# N        : 负样本数量
# t        : 温度
# tau_plus : 类别概率
# beta     : 集中调节超参数

# 原始目标函数
standard_loss = -log(pos.sum() / (pos.sum() + neg.sum()))

# 去偏对比损失目标函数
Neg = max((-N * tau_plus * pos + neg).sum() / (1 - tau_plus),
          e ** (-1/t))
debiased_loss = -log(pos.sum() / (pos.sum() + Neg))

# 高难度样本目标函数 M = 1
reweight = (beta * neg) / neg.mean()
Neg = max((-N * tau_plus * pos + reweight * neg).sum() / (1 - tau_plus),
          e ** (-1/t))
hard_loss = -log( pos.sum() / (pos.sum() + Neg))

视觉类:图片嵌入

图片增强

大多数在视觉方面应用的对比学习方法会应用一些列的数据增强技术来创建一系列样本的噪声版本。数据增强的方法应该在很大程度上改变图片的视觉效果,但是却可以保持语义上的不变性。

基本图片增强方法

现有许多种方法可以在保持图片语义的情况下改变一张图片。我们可以使用如下的一种或者几种方法的组合:

  • 随机裁剪并将图片缩放到原始大小
  • 随机颜色失真调节
  • 随机高斯模糊
  • 随机颜色抖动
  • 随机水平翻转
  • 随机灰度转换
  • 多裁剪增强 (Multi-crop augmentation):使用两个标准分辨率进行裁剪,并且额外进行一系列的低分辨率的裁剪(仅覆盖小部分图片)。使用低分辨率裁剪可以降低计算消耗。(SwAV
  • 还有很多其它...

增强策略

有许多框架专门被设计用于学习好的数据增强策略(也就是多种变换方法的组合)。下面是常用的一些策略:

  • AutoAugment ( Cubuk 等人, 2018: 受到NAS的启发,AutoAugment把学习图片增强操作(用于分类任务)的过程看作是一个强化学习问题,问题的目标是寻找到一个可以让最终测试数据的准确率达到最高的策略
  • RandAugment ( Cubuk 等人, 2019: RandAugment通过引入一个超数来控制不同变换的幅度,以此来大大降低AutoAugment的搜索空间
  • PBA ( Population baased augmentation; Ho等人, 2019: PBA 将PBT ( [Jaderberg等人](Jaderberg et al, 2017和AutoAugment结合起来,使用进化算法并行训练,并最终演化出最优的加强策略
  • UDA (Unsupervised Data Augmentation; Xie等人, 2019: 在一些列的数据增强策略中,UDA 选择那些可以最小化两个分布之间KL散度的策略,这两个分布为:(1) 无标签数据的预测分布;(2) 无标签数据的增强版本的分布

图片混合

图片混合方法可以为现有数据构建出新的训练样本出来。

  • Mixup ( Zhang 等人, 2018: 它将两张图片$I_1, I_2$进行像素级的全局混合:$I_\text{mixup} \gets \alpha I_1 + (1-\alpha) I_2$,其中$\alpha \in [0, 1]$
  • Cutmix ( Yun 等人, 2019: Cutmix进行的是局部混合,它通过将一张图片的某个区域与另一张图片的其余部分进行混合来生成一个新的样本:$I_\text{cutmix} \gets \mathbf{M}_b \odot I_1 + (1-\mathbf{M}_b) \odot I_2$,其中$\mathbf{M}_b \in \{0, 1\}^I$是二值掩码矩阵,$\odot$表示按元素乘。这个方法相当于在一张图片上挖个洞( DeVries & Taylor, 2017,然后用另外一张图片的相同部分将其填补以生成一个新的图片
  • MoCHi ("Mixing of Contrastive Hard Negatives"; Kalantidis等人, 2020: 给定一个查询$q$,MoCHi维护了一个包含$K$个负特征的队列 $Q=\{\mathbf{n}_1, \dots, \mathbf{n}_K \}$,这些特征按照与查询之间的相似度$\mathbf{q}^\top \mathbf{n}$进行降序排序。队列中前$N$个样本被看作难度最高的负样本,记为$Q^N$。而后可以通过$\mathbf{h} = \tilde{\mathbf{h}} / \|\tilde{\mathbf{h}}\|$(其中$\tilde{\mathbf{h}} = \alpha\mathbf{n}_i + (1-\alpha) \mathbf{n}_j, \alpha \in (0, 1)$)来合成高难度样本。难度更高的样本可以通过与查询特征进行混合来创建:$\mathbf{h}' = \tilde{\mathbf{h}'} / \|\tilde{\mathbf{h}'}\|_2$(其中$\tilde{\mathbf{h}'} = \beta\mathbf{q} + (1-\beta) \mathbf{n}_j, \beta \in (0, 0.5)$ )

并行增强

这类方法对于一张标定图片生成两个版本的噪声图片,它们旨在让两个增强样本共享同一个嵌入表征。

SimCLR

SimCLR(Chen 等人, 2020为视觉表征相关的对比学习任务提供了一个简洁的框架。它通过最大化同一样本的不同加强版本在隐空间中的对比损失间的一致性来学习表征。

视觉表征对比学习框架 SimCLR

我们重点关注SimCLR的以下几个点:

1) 随机采样一小批样本(包含$N$个样本),每个样本应用两个不同的增强操作,这样就产生了$2N$个增强样本:$\tilde{\mathbf{x}}_i = t(\mathbf{x}),\quad\tilde{\mathbf{x}}_j = t'(\mathbf{x}),\quad t, t' \sim \mathcal{T}$,其中$t, t^\prime$为两个增强操作,它们从加强操作族$\mathcal{T}$中采样得到。数据加强操作包含随机裁剪、随机反转+缩放,颜色调节和高斯模糊

2) 给定一个正样本对,其余$2(N-1)$个数据点被看作是负样本。数据表征通过编码器$f(\cdot)$产生:$\mathbf{h}_i = f(\tilde{\mathbf{x}}_i),\quad \mathbf{h}_j = f(\tilde{\mathbf{x}}_j)$

3) 对比学习损失函数使用余弦相似度$sim(.,.)$来定义。这里需要注意的是loss操作是在表征的一个映射层输出$g(.)$上进行的,而不是直接作用于表征空间。但是在下游任务中,我们仅会使用到表征$h$$$\begin{aligned}\mathbf{z}_i &= g(\mathbf{h}_i),\quad\mathbf{z}_j = g(\mathbf{h}_j) \\\mathcal{L}_\text{SimCLR}^{(i,j)} &= - \log\frac{\exp(\text{sim}(\mathbf{z}_i, \mathbf{z}_j) / \tau)}{\sum_{k=1}^{2N} \mathbb{1}_{[k \neq i]} \exp(\text{sim}(\mathbf{z}_i, \mathbf{z}_k) / \tau)}\end{aligned}$$其中,$\mathbb{1}_{[k \neq i]}$为指示函数,$k\ne i$时为1,否则为0

SimCLR算法需要一个大的批大小(batch size)来保证有足够多的负样本,以获取一个好的性能表现。算法结构截图图下:

SimCLR算法

Barlow Twins

Barlow Twins (Zbontar 等人, 2021算法将两个增强后的样本输入到同样的网络中进行特征提取,让网络学习如何让两组输出特征间的互相关矩阵接近单位矩阵。该算法的目标是让样本的不同增强版本样本对应的表征间保持相似,并同时最小化这些向量间的冗余。

Barlow Twins 示意图

设$\mathcal{C}$为两个网络输出间的互相关矩阵(沿batch维度)。$\mathcal{C}$是一个方阵,维度和特征网络输出的维度数量一样。矩阵中的每一个值$\mathcal{C}_{ij}$是网络输出向量在索引$i, j$处的余弦相似度;$b$为批(batch)样本索引;$\mathbf{z}_{b,i}^A$和$\mathbf{z}_{b,j}^B$为 -1(表示完全不相关)到1(表示完全相关)间的值。

$$ \begin{aligned} \mathcal{L}_\text{BT} &= \underbrace{\sum_i (1-\mathcal{C}_{ii})^2}_\text{invariance term} + \lambda \underbrace{\sum_i\sum_{i\neq j} \mathcal{C}_{ij}^2}_\text{redundancy reduction term} \\ \text{其中 } \mathcal{C}_{ij} &= \frac{\sum_b \mathbf{z}^A_{b,i} \mathbf{z}^B_{b,j}}{\sqrt{\sum_b (\mathbf{z}^A_{b,i})^2}\sqrt{\sum_b (\mathbf{z}^B_{b,j})^2}} \end{aligned} $$

就监督学习来说,Barlow Twins与SOTA方法相比是有一战之力的。它很自然地避免了一些幼稚的常量表征(也就是崩溃表征(collapsed representations),比如所有的特征值都为0),并且在不同批大小(batch size)下训练都很稳定。

Pytorch 风格的伪代码如下:

# Algorithms 1: Barlow Twins
# ==========================
# f: 编码网络
# lmbda: 非对角项全中
# N: 批大小
# D: 表征维度
#
# mm: 矩阵乘法
# off_diagonal: 矩阵非对角元素
# eye: 单位矩阵

for x in loader:      # 加载单批数据(N个样本)
    # 生成两个随机的增强样本
    y_a, y_b = augment(x)
    
    # 计算表征
    z_a = f(y_a)
    z_b = f(y_b)
    
    # 沿着批维度进行归一化
    z_a_norm = (z_a - z_a.mean(0)) / z_a.std(0)
    z_b_norm = (z_b - z_b.mean(0)) / z_b.std(0)
    
    # 互相关矩阵
    c = mm(z_a_norm.T, z_b_norm) / N
    
    # 损失函数
    c_diff = (c - eye(D)).pow(2)
    # 非对角元素乘以 lmbda
    off_diagonal(c_diff).mul_(lmbda)
    loss = c_diff.sum()
    
    # 优化
    loss.backward()
    optimizer.step()

BYOL

有趣的是,和上面的方法不一样,BYOL (Bootstrap Your Own Latent; Grill等人, 2020声称可以在 不使用负样本的情况下 取得当前最好的结果。BYOL 使用两个神经网络,分别表示在线(online)网络和目标网络,这两个网络相互联系、相互学习。目标网络(参数为$\xi$)和在线网络(参数为$\theta$)结构一样,但是它的权重计算方式为:$\xi \leftarrow \tau \xi + (1-\tau) \theta$。

BYOL的目标是学习到一个可以用于下游任务的表征$y$。在线网络包含三部分:

  • 编码器 $f_\theta$
  • 映射器 $g_\theta$
  • 预测器 $q_\theta$

目标网络结构一样,参数不同。下图展示了BYOL的模型结构。训练完成后,我们仅需要编码器$f_\theta$来产生表征 $y = f_\theta(x)$,其余部分都可释放。$sg$表示 stop gradient

BYOL模型结构

给定一张图片$\mathbf{x}$,BYOL的损失函数通过如下方式构建:

  • 生成两个强化版:$\mathbf{v}=t(\mathbf{x}), \mathbf{v}^\prime=t^\prime(\mathbf{x})$,其中加强方法分别采样于$\mathcal{T}, \mathcal{T}^\prime$: $t \sim \mathcal{T}, t' \sim \mathcal{T}'$
  • 编码:$\mathbf{y}_\theta=f_\theta(\mathbf{v}), \mathbf{y}'=f_\xi(\mathbf{v}')$
  • 映射:$\mathbf{z}_\theta=g_\theta(\mathbf{y}_\theta), \mathbf{z}'=g_\xi(\mathbf{y}')$
  • 在线网络输出一个预测:$q_\theta(\mathbf{z}_\theta)$
  • $q_\theta(\mathbf{z}_\theta)$和$\mathbf{z}^\prime$都进行了L2归一化,这样我们有:$\bar{q}_\theta(\mathbf{z}_\theta) = q_\theta(\mathbf{z}_\theta) / \| q_\theta(\mathbf{z}_\theta) \|$ 以及 $\bar{\mathbf{z}'} = \mathbf{z}' / \|\mathbf{z}'\|$
  • 损失函数$\mathcal{L}^\text{BYOL}_\theta$是$\bar{q}_\theta(\mathbf{z})$与$\bar{\mathbf{z}'}$间的均方误差(MSE)
  • 另外一个对应的损失函数$\tilde{\mathcal{L}}^\text{BYOL}_\theta$可以通过交换$\mathbf{v}$和$\mathbf{v}^\prime$得到;也就是将$\mathbf{v}^\prime$喂给在线网络,将$\mathbf{v}$喂给目标网络
  • 最终的损失函数为 $\mathcal{L}^\text{BYOL}_\theta + \tilde{\mathcal{L}}^\text{BYOL}_\theta$ (只有参数$\theta$会被优化)

和大多数流行的对比学习方法不同,BYOL没有使用负样本对。大多数提升(bootstrapping)类的方法依赖于伪标签或者聚类索引,但是BYOL直接对隐空间中的表征进行提升。

非常有趣并令人惊讶的是,不使用负样本BYOL算法仍然可以很好地工作。后来我偶然看到Abe Fetterman & Josh Albrecht的文章,他们重点强调了在复现BYOL算法时的两个令人惊奇的发现:

  1. BYOL算法在移除批归一化(batch normalization, BN)之后表现不会比随机方法更好
  2. BN的存在隐式地引入了另外一种形式的对比学习。他们认为使用负样本对于防止模型崩溃(model collapse)很重要(也就是:如果所有数据都用全0的表征会怎么样?)。BN非显式地引入了算法对负样本的依赖,因为无论单批次中的数据如何相似,它们的值总是会被归一化(服从$\sim \mathcal{N}(0, 1)$)。因此BN阻止了模型崩溃。如果你在这个领域进行研究,我强烈建议你阅读整篇文章

内存库

计算每个批次数据中大量负样本的嵌入表示是非常昂贵的。一个常用的方法是将计算出的表征存储在内存中,以此来降低计算消耗。

实例间区分(应用内存库)

实例对比学习(Wu等人, 2018通过将每个实例都视为它们自己独特的分类,将分类监督学习推向极致。这意味着有多少样本就有多少分类。在这种情况下,使用softmax来训练是不可行的,我们可以使用NCE方法来近似。

实例对比学习训练流水线

令$\mathbf{v} = f_\theta(x)$为需要学习的嵌入函数,输出$\mathbf{v}$进行了归一化操作以满足$\|\mathbf{v}\|=1$。非参数分类器预测样本$\mathbf{v}$术语类别$i$的概率为:

$$ P(C=i\vert \mathbf{v}) = \frac{\exp(\mathbf{v}_i^\top \mathbf{v} / \tau)}{\sum_{j=1}^n \exp(\mathbf{v}_j^\top \mathbf{v} / \tau)} $$

其中$\tau$为温度参数。

算法不会每次都去计算所有样本的表征,而是实现了一个用于存储样本表征的数据库用于存储历史迭代数据,称之为内存库 (Memory Bank)。令$V=\{ \mathbf{v}_i \}$为内存库,$\mathbf{f}_i = f_\theta(\mathbf{x}_i)$为由前往网络推导得到的特征表示,我们可以在比较数据对相似度的时候使用内存库中的表示$\mathbf{v}_i$来替代网络计算得到的$\mathbf{f}_i$。

公式中的分母理论上需要得到所有样本的表征,但是在实际中这个计算太昂贵了。我们可以使用一个大小为$M$的随机样本子集,通过蒙特卡洛近似的方法来预测这个值,记被选中样本的下标为:$\{j_k\}_{k=1}^M$。

$$ P(i\vert \mathbf{v}) = \frac{\exp(\mathbf{v}^\top \mathbf{f}_i / \tau)}{\sum_{j=1}^N \exp(\mathbf{v}_j^\top \mathbf{f}_i / \tau)} \simeq \frac{\exp(\mathbf{v}^\top \mathbf{f}_i / \tau)}{\frac{N}{M} \sum_{k=1}^M \exp(\mathbf{v}_{j_k}^\top \mathbf{f}_i / \tau)} $$

由于每个样本仅有一个实例,训练过程是很不稳定的。为了让训练过程更加平滑,基于近似优化方法,算法为损失函数中的正样本引入了一个额外项。最终的NCE损失函数为:

$$ \begin{aligned} \mathcal{L}_\text{instance} &= - \mathbb{E}_{P_d}\big[\log h(i, \mathbf{v}^{(t-1)}_i) - \lambda \|\mathbf{v}^{(t)}_i - \mathbf{v}^{(t-1)}_i\|^2_2\big] - M\mathbb{E}_{P_n}\big[\log(1 - h(i, \mathbf{v}'^{(t-1)})\big] \\ h(i, \mathbf{v}) &= \frac{P(i\vert\mathbf{v})}{P(i\vert\mathbf{v}) + MP_n(i)} \text{ 其中噪声分布为均匀分布 }P_n = 1/N \end{aligned} $$

其中$\{ \mathbf{v}^{(t-1)} \}$为内存库中的嵌入表示。随着迭代过程不断进行,嵌入表示趋于收敛后,不同轮 $\|\mathbf{v}^{(t)}_i - \mathbf{v}^{(t-1)}_i\|^2_2$ 间的差异会逐渐消失。

MoCo & MoCo-V2

MoCo (Momentum Contrast; He等人, 2019) 提供了一种非监督学习的算法框架,它将视觉表征任务看作是一个动态字典查找任务。字典以一种FIFO队列的形式组织,其元素为数据样本的表征。

给定一个查询样本$\mathbf{x}_q$,我们通过编码器得到样本表征 $\mathbf{q} = f_q(\mathbf{x}_q)$。字典中的表征列表$\{\mathbf{k}_1, \mathbf{k}_2, \dots \}$由动量编码器(momentum encoder)编码得到:$\mathbf{k}_i = f_k (\mathbf{x}^k_i)$。我们假设列表中仅存在一个与查询$q$匹配的正样本表征$\mathbf{k}^+$。论文中,作者使用不同的加强方法生成原样本$\mathbf{x}_q$的一个噪声样本,并以此创建$\mathbf{k}^+$。而后,InfoNCE对比损失被应用在一个正样本和$N-1$个负样本上:

$$ \mathcal{L}_\text{MoCo} = - \log \frac{\exp(\mathbf{q} \cdot \mathbf{k}^+ / \tau)}{\sum_{i=1}^N \exp(\mathbf{q} \cdot \mathbf{k}_i / \tau)} $$

相比于内存库,MoCo中基于队列的字典让我们可以重用上一批数据的表征。

MoCo的字典作为一个队列是不可导的,所以我们无法使用反向传播来更新键值编码器 $f_k$。一种最简单的方式就是对于$f_q$和$f_k$使用同样的编码器。MoCo使用了一种不同的方式,它使用了一种基于动量的更新方法,动量系数$m \in [0, 1)$。我们将$f_q, f_k$的系数分别计为$\theta_q, \theta_k$,则有:

$$ \theta_k \leftarrow m \theta_k + (1-m) \theta_q $$

MoCo工作方式示意图

相比于SimCLR,MoCo将批大小与负样本的个数进行了解耦合,而SimCLR需要大的批大小来保证足够的负样本数量。SimCLR在批大小减少的时候,性能会下降很多。

SimCLR中的两个设计:(1) 一个MLP映射头;(2) 加强的数据增强 被证明非常高效。MoCo V2 (Chen等人, 2020中融入了这两个设计,并且在不依赖于大的批大小的情况下取得了更好的性能。

CURL

CURL (Srinivas 等人, 2020将我们上面的思想应用到强化学习中去。它通过对比损失函数来匹配某个观察值$o$的两个数据增强版本$o_q, o_k$来为强化学习任务学习一个视觉表征方法。CURL中使用的数据增强方法主要是随机数据裁剪。和Moco中一样,CURL中的编码器也使用了一个动量编码器,其权重为查询编码器(query encoder)权重的指数滑动平均。

强化学习和视觉监督学习任务的一个重要不同就是强化学习依赖于连续帧在时间上的一致性。因此,算法在每一组连续帧上都应用了同样的数据增强方法以保证观察(observation)值的时间结构。

CURL架构

特征聚类

DeepCluster

DeepCluster (Caron等人, 2018) 使用k-means方法不断对特征进行迭代聚类,使用聚类结果作为样本的伪标签来进行监督学习。

DeepCluster示意图

在每次迭代过程中,DeepCluster使用先验表示对数据点进行聚类,然后产生新的聚类标签用于分类学习的目标。但是这种迭代过程很容易导致很幼稚的解决方案(模型崩溃问题)。虽然算法中避免了使用负样本,但是它需要一个非常耗时的聚类阶段,并且特别需要注意避免模型崩溃问题。

SwAV

SwAV (Swapping Assignments between multiple Views; Caron等人, 2020)是一个在线对比学习算法。它为一张图片的增强版本计算出一个编码,并且使用同一图片的另一个增强版本来预测这个编码。

SwAV vs 实例对比学习

给定图片的特征及两个不同的数据增强方法,我们得到两个增强样本$\mathbf{z}_t, \mathbf{z}_s$,SwAV计算出两个相应的编码$q_t, q_s$。损失函数通过交换两个样本的编码,并使用$\ell(.)$来量化它们之间的匹配度来评估图片特征和编码间的匹配度:

$$ \mathcal{L}_\text{SwAV}(\mathbf{z}_t, \mathbf{z}_s) = \ell(\mathbf{z}_t, \mathbf{q}_s) + \ell(\mathbf{z}_s, \mathbf{q}_t) $$

这种交换匹配预测依赖于预测得到的编码和K个可训练原型向量$\mathbf{C} = \{\mathbf{c}_1, \dots, \mathbf{c}_K\}$间的交叉熵。原型向量矩阵会在不同批次数据间共享,它们代表了每个实例所属的类别(anchor clusters)(由聚类得到)。

$$ \ell(\mathbf{z}_t, \mathbf{q}_s) = - \sum_k \mathbf{q}^{(k)}_s\log\mathbf{p}^{(k)}_t \text{ where } \mathbf{p}^{(k)}_t = \frac{\exp(\mathbf{z}_t^\top\mathbf{c}_k / \tau)}{\sum_{k'}\exp(\mathbf{z}_t^\top \mathbf{c}_{k'} / \tau)} $$

在每个包含$B$个特征向量$\mathbf{Z} = [\mathbf{z}_1, \dots, \mathbf{z}_B]$的一批数据中,特征和原型向量间的映射矩阵定义为:$\mathbf{Q} = [\mathbf{q}_1, \dots, \mathbf{q}_B] \in \mathbb{R}_+^{K\times B}$。我们希望最大化特征和原型之间的相似度:

$$ \begin{aligned} \max_{\mathbf{Q}\in\mathcal{Q}} &\text{Tr}(\mathbf{Q}^\top \mathbf{C}^\top \mathbf{Z}) + \varepsilon \mathcal{H}(\mathbf{Q}) \\ \text{其中 }\mathcal{Q} &= \big\{ \mathbf{Q} \in \mathbb{R}_{+}^{K \times B} \mid \mathbf{Q}\mathbf{1}_B = \frac{1}{K}\mathbf{1}_K, \mathbf{Q}^\top\mathbf{1}_K = \frac{1}{B}\mathbf{1}_B \big\} \end{aligned} $$

公式中$\mathcal{H}$表示熵 $\mathcal{H}(\mathbf{Q}) = - \sum_{ij} \mathbf{Q}_{ij} \log \mathbf{Q}_{ij}$,它控制了编码的平滑性。系数$\epsilon$不可以太大,否则所有样本都会被以同等概率放到不同的聚类中去。Q的候选解决方案要求每个映射矩阵的每行之和为$1/K$,每列之和为$1/B$,这就强制要求每个原型平均都至少被选择$B/K$次。

SwAB依赖迭代Sinkhorn-Knopp算法(Cuturi 2013来为$Q$求解。

使用监督数据集

CLIP

CLIP (Contrastive Language-Image Pre-training; Radford等人, 2021)在预训练任务(预测图片与标题之间的匹配)上联合训练了一个文本编码器和一个图片特征提取器。

CLIP示意图

给定一个批次的数据,其中包含$N$个(图片,文本)对,CLIP计算出$N \times N$个可能的(图片,文本)对的余弦相似度矩阵。文本编码器和图片编码器同时进行训练,训练目标在于最大化$N$个匹配的(图片,文本)对的相似度,而最小化$N(N-1)$个不匹配的(图片,文本)对间的相似度,使用的损失函数为相似度矩阵上的对称交叉熵损失。下图给出了一个numpy风格的伪代码:

# image_encoder - ResNet 或 视觉Transformer
# text_encoder  - CBOW 或者 文本Transformer
# I[n, h, w, c] - 单批次图片数据
# T[n, l]       - 单批次的文本数据
# W_i[d_i, d_e] - 图片到嵌入表征的变换矩阵
# W_t[d_t, d_e] - 文本到嵌入表征的变换矩阵
# t             - 学习到的温度参数

# 特征提取
I_f = image_encoder(I)     # [n, d_i]
T_f = text_encoder(T)      # [n, d_t]

# 将图片和文本的嵌入映射到多模空间中去 [n, d_e]
I_e = np.linalg.norm(np.dot(I_f, W_i), axis=1)
T_t = np.linalg.norm(np.dot(T_f, W_t), axis=1)

# 计算余弦相似度矩阵 [n, n]
logits = np.dot(I_t, T_e.T) * np.exp(t)

# 对称损失函数
labels = np.arange(n)
loss_i = cross_entropy_loss(logits, labels, axis=0)
loss_t = cross_entropy_loss(logits, labels, axis=1)
loss = (loss_i + loss_t) / 2

与上面其它的视觉表征方法相比,CLIP的特别之处在于“使用自然语言作为训练信号”。CLIP的训练依赖于监督数据集,数据集中图片和文本间的匹配关系需要预先知道。论文中的训练数据采集于互联网,其中包含了400万个(文本,图片)数据对。查询列表中包含了在英文维基百科中所有出现超过100次的单词。有趣的是,在zero-shot的ImageNet分类任务上,他们发现基于transformer模型的编码器比基于词袋(Bag of Words)模型的慢了3倍。在实验中,如果使用对比目标(contrastive objective)函数取代去直接预测单词(此法在图片标题生成任务中常被使用),那么可以将数据效率进一步提高4倍。

CLIP 不同模型性能对比

CLIP可以生成高质量的图片表示,在许多CV基准数据集中都得到了与监督学习有竞争力的性能表现。实验还发现,CLIP很难处理那些非常细粒度或者那些比较抽象和系统的任务(比如:目标对象计数任务 (counting the number of objects))。此外,CLIP模型的迁移表现与模型的计算量有着非常平滑的相关性。

监督对比学习

交叉熵损失有几个已知的问题,比如对于噪声标签以及模糊边界(poor margins)缺乏鲁棒性。现有的改进包括使用更好的训练数据处理方法,比如标签平滑和数据增强。监督对比损失(Khosla等人, 2021旨在更加高效地利用标签信息(相比交叉熵损失),它让同类别数据的嵌入表示间的距离比不同类数据的嵌入表示间的距离更近。

监督和自监督对比损失

监督对比损失不仅将样本的数据增强版本作为正样本,同时还将同一类别的样本作为正样本。

给定一个随机采样的$n$个(图片,标签)对$\{\mathbf{x}_i, y_i\}_{i=1}^n$,我们可以使用对每个样本随机应用两个数据增强算法来产生两个增强样本,这样我们可以生成$2n$个训练样本,记为$\{\tilde{\mathbf{x}}_i, \tilde{y}_i\}_{i=1}^{2n}$。

监督对比损失$\mathcal{L}_\text{supcon}$和我们前文介绍的soft nearest-neighbor loss很相似,都使用了多个正、负样本:

$$ \mathcal{L}_\text{supcon} = - \sum_{i=1}^{2n} \frac{1}{2 \vert N_i \vert - 1} \sum_{j \in N(y_i), j \neq i} \log \frac{\exp(\mathbf{z}_i \cdot \mathbf{z}_j / \tau)}{\sum_{k \in I, k \neq i}\exp({\mathbf{z}_i \cdot \mathbf{z}_k / \tau})} $$

其中$\mathbf{z}_k=P(E(\tilde{\mathbf{x}_k}))$,$E(.)$为一个编码器网络(将增强后的数据映射到向量)。$P(.)$为一个投影网络(将一个向量映射到另外一个向量)。$N_i= \{j \in I: \tilde{y}_j = \tilde{y}_i \}$是一个下标的集合,下标对应的样本标签与$y_i$一样,增加$N_i$中包含的正样本个数有助于改善结果。

根据论文的实验结果,监督对比损失:

  • 确实可以超越基础的交叉熵,但是仅能超越一点点
  • 在一些非常鲁棒的基线任务中优于交叉熵(比如在数据集 ImageNet-C上,该数据集在ImageNet的基础上进行了一些很自然地扰动变化,比如添加噪声、调节对比度等等)
  • 对于超参数的变化相对不敏感

语言类:句子嵌入

本节我们重点介绍如何学习句子嵌入。

文本增强

大多数在视觉方面应用的对比学习方法依赖于创建每个图片的增强版本。但是,对于文本来说,在不改变文本语义的情况下进行文本的增强确实一项非常具有挑战性的任务。本小节我们介绍下三种文本增强方法:词法编辑、回译和使用切除或dropout。

词法编辑 (Lexical Edits)

EDA (Easy Data Augmentation; Wei & Zou 2019中定义了一系列非常简单但是强大的文本增强操作。给定一个句子,EDA随机选择应用下面四个操作中的一个:

  1. 同义替换:随机选择n个非停用词进行近义词替换
  2. 随机插入:在句子的一个随机位置插入一个非停用词的近义词
  3. 随机交换:随机交换两个词,并重复$n$次
  4. 随机删除:以概率$p$随机删除句子中的每个词

其中$p=\alpha, n=\alpha \times \text{句子长度}$,这是因为直觉上更长的句子应该可以在维持原本语义的情况下容忍更多的噪声。超参数$\alpha$对于每次增强操作可以改变的单词的百分比进行了一个初略的估计。

EDA的应用可以改善许多分类基线任务的准确率,它的性能提升在一个较小的数据集上尤为突出。EDA中的4个操作都可以改善分类的准确率,而调节超参数$\alpha$可以让准确率达到最优。下图为EDA在一些分类任务上的性能表现。

EDA性能表现

上下文增强 (Sosuke Kobayashi, 2018中,位置$i$处的单词$w_i$的替换词可以从给定的概率分布$p(.\mid S\setminus\{w_i\})$中采样得到。这个概率分布由一个类似BERT的双向语言模型得到。

回译 (Back-translation)

CERT (Contrastive self-supervised Encoder Representations from Transformers; Fang等人, 2020; 代码通过回译来生成句子的增强版本。对于不同的语言,不同的翻译模型可以被使用来创建不同版本的文本增强。一旦我们有了一个文本的噪声版本,我们上文介绍的许多对比学习框架,比如:MoCo,都可以被用来学习句子嵌入。

Dropout 和 切除 (Cutoff)

受到[cross-view](cross-view training训练的启发,[Shen等人, 2020](Shen et al. (2020)提出将截断(Cutoff)操作应用到文本增强中去。他们提出了三个截断增强策略:

  1. Token 切除:移除一些被选定token的所有信息。为了确保没有数据泄漏,输入、位置以及其它相关的嵌入表示中token相关信息都需要置零
  2. 特征切除:移除一些特征列
  3. 区域切除(span cutoff):移除一段连续的文本

下图给出了这三种切除方法的示意图。

切除方法示意图

一个样本可以创建多个加强版本。训练时,文中([Shen等人, 2020](Shen et al. (2020)应用了额外的KL散度项来衡量不同增强样本的预测值之间的一致性。

SimCSE (Gao等人, 2021; 代码中仅使用了非监督数据集,文中将句子中的单词进行dropout,使用dropout后的句子去预测原来的句子。换句话说,他们将dropout作为一种数据增强的方法。同一个批次的数据中,同一个句子通过dropout生成的增强版本被当作正样本,而其它不同的句子被用作负样本。这看起来就和切除法(cutoff)很类似,但是dropout不拘泥于保持寓意,可以更加自由地进行词语丢弃。

SimCSE 监督和非监督版本示意图

作者们在7个文本语义相似度 (STS, Semantic Text Similarity)数据集上进行了实验,并且计算了不同句子嵌入间的余弦相似度。他们还尝试了MLM辅助目标损失函数以避免忘记token级的知识。这个辅助损失函数可以帮助改善算法在迁移任务上的性能,但在主要的STS任务上表现一致拉垮。

SimCES 性能表现

自然语言推理

使用原始BERT得到的句子嵌入在许多语义相似度任务上表现欠佳。我们不应该直接使用原始版本,而是应该使用经过进一步微调后的版本。

Sentence-BERT

译著:这篇论文我们之前介绍过,详细参考这里 https://paperexplained.cn/articles/article/detail/20/,或公众号之前的文章

SBERT (Sentence-BERT) (Reimers & Gurevych, 2019依赖孪生网络和三元组网络来学习句子嵌入。句子间的相似度可以通过句子嵌入间的余弦相似度来衡量。注意SBERT依赖于监督数据集,它是在一些NLI数据集上进行微调操作的。

他们在BERT模型的基础上实验了几个不同的输出层 (prediction heads)

  • Softmax 目标函数:孪生网络的输出层构建在两个嵌入表示之上:$f(x), f(x^\prime)$,再加上额外的$\vert f(\mathbf{x}) - f(\mathbf{x}') \vert$。输出层公式表达为:$\hat{y}=\text{softmax}(\mathbf{W}_t [f(\mathbf{x}); f(\mathbf{x}'); \vert f(\mathbf{x}) - f(\mathbf{x}') \vert])$。他们发现最重要的部分是按元素求差的那一部分$\vert f(\mathbf{x}) - f(\mathbf{x}') \vert$
  • 回归目标函数:这是个基于$\cos(f(\mathbf{x}), f(\mathbf{x}'))$的回归损失函数,模型结构中的池化策略对最终性能有很大影响。在实验中,他们发现max操作相比于meanCLS-token性能表现差很多
  • 三元组目标函数:$\max(0, \|f(\mathbf{x}) - f(\mathbf{x}^+)\|- \|f(\mathbf{x}) - f(\mathbf{x}^-)\| + \epsilon)$,其中$\mathbf{x}, \mathbf{x}^+, \mathbf{x}^-$分别为标定样本、正样本和负样本的嵌入表示

实验中,哪一个目标函数工作的最好与数据集相关,没有全局赢家。

使用Softmax 和 回归目标函数的SBERT结构示意图

SentEval库 (Conneau & Kiela, 2018是评估句子嵌入质量的一个常用库。SBERT当时在7个任务中的5个任务中的表现超过了其它的基线算法,具体数据如下(截图于论文 Reimers & Gurevych, 2019)。

SBERT性能表现

BERT-flow

如果嵌入表示在每个维度上都是均匀分布的,那么我们称嵌入表征空间为各向同性的;否则称之为各向异性的。Li等人, 2020的研究表明BERT预训练模型学习出了一个非平滑的各向异性的嵌入语义空间,因此在不进行微调的情况下,对于文本相似度任务,BERT性能表现不佳。他们根据经验总结出BERT句子嵌入的两个问题:

  • 单词频率会引起嵌入空间的偏差。高频单词会离原点较近,而低频单词会离原点较远。
  • 低频单词会分布得更加分散。低频单词更趋向于远离它们的kNN邻居,而高频单词恰恰相反。

BERT-flow (Li等人, 2020, 代码的提出旨在通过流归一化来将嵌入表征空间转换为一个平滑的、各向同性的高斯分布空间。

BERT-flow 空间变换

设$\mathcal{U}$为原BERT嵌入表征空间,$\mathcal{Z}$为所期望的标准高斯隐空间,$p_\mathcal{Z}$为高斯概率密度函数,$f_\phi: \mathcal{Z}\to\mathcal{U}$为一个可逆变换:

$$ \mathbf{z}\sim p_\mathcal{Z}(\mathbf{z}) \quad \mathbf{u}=f_\phi(\mathbf{z}) \quad \mathbf{z}=f^{-1}_\phi(\mathbf{u}) $$

BERT-flow通过一个基于流的生成模型去学习这里的可逆映射函数,目标函数为最大化如下$\mathcal{U}$的边缘概率的似然估计:

$$ \max_\phi\mathbb{E}_{\mathbf{u}=\text{BERT}(s), s\sim\mathcal{D}} \Big[ \log p_\mathcal{Z}(f^{-1}_\phi(\mathbf{u})) + \log\big\vert\det\frac{\partial f^{-1}_\phi(\mathbf{u})}{\partial\mathbf{u}}\big\vert \Big] $$

其中$s$为从语料库$\mathcal{D}$中采样的一个句子。训练过程中仅有流参数$\phi$会被优化,预训练的BERT参数保持不变。

BERT-flow在大多数STS任务上可以改善性能(无论有没有使用NLI监督数据集)。由于学习校准流(normalizing flows for calibration)无需标签,所以训练过程中验证集和测试集都可以使用。

白化操作(Whitening Operation)

Su等人, 2021应用白化操作来改善表征的各向同性,并同时降低句子嵌入的维度。

他们将句子向量的均值变换为0,将相关矩阵变换为单位阵。给定样本集合$\{\mathbf{x}_i\}_{i=1}^N$,令$\tilde{\mathbf{x}}_i, \tilde{\Sigma}$分别为变换后的样本和相应的相关矩阵:

$$ \begin{aligned} \mu &= \frac{1}{N}\sum_{i=1}^N \mathbf{x}_i \quad \Sigma = \frac{1}{N}\sum_{i=1}^N (\mathbf{x}_i - \mu)^\top (\mathbf{x}_i - \mu) \\ \tilde{\mathbf{x}}_i &= (\mathbf{x}_i - \mu)W \quad \tilde{\Sigma} = W^\top\Sigma W = I \text{ 即 } \Sigma = (W^{-1})^\top W^{-1} \end{aligned} $$

如果我们得到$\Sigma$的SVD分解$\Sigma = U\Lambda U^\top$,则有$W^{-1}=\sqrt{\Lambda} U^\top$以及$W=U\sqrt{\Lambda^{-1}}$。注意,在SVD分解中,$U$为正交矩阵,列为特征向量;$\Lambda$为对角阵,对角元素为降序特征值。

降维操作可以通过仅保留$W$的前$k$列来实现,我们称之为Whitening-k

whitening-k 伪代码

白化操作显示出了超过BERT-flow的性能,并且在许多STS基线任务上(使用256维特征)取得了SOTA的成绩(使用或者不使用NLI数据都行)。

非监督句子嵌入学习

上下文预测

QT (Quick-Thought)向量(Logeswaran & Lee, 2018将句子表示学习看作一个分类问题:给定一个句子和它的上下文,分类器根据它们的向量表示将上下文语句与其它语句区分开来(完形填空)。QT移除了模型的softmax层,导致了训练速度变慢。

Quick-Thought句子嵌入

设$f(.), g(.)$为两个句子编码器,用于将句子编码为一个固定长度的向量。设$C(s)$为句子$s$上下文中的句子的集合。$S(s)$为候选句子集合,其中仅包含了一个句子$s_c\in C(s)$,$S(s)$中的其它句子都用作负样本。QT模型对于预测正确的上下文句子$s_c$的概率进行优化。如果将句子对$(s, s_c)$看作正样本对,其余的$(s, s^\prime)(其中s^\prime \ne s_c)$看作负样本对,其实所用损失函数就是NCE损失函数:

$$ \mathcal{L}_\text{QT} = - \sum_{s \in \mathcal{D}} \sum_{s_c \in C(s)} \log p(s_c \vert s, S(s)) = - \sum_{s \in \mathcal{D}} \sum_{s_c \in C(s)}\frac{\exp(f(s)^\top g(s_c))}{\sum_{s'\in S(s)} \exp(f(s)^\top g(s'))} $$

互信息最大化

IS-BERT (Info-Sentence BERT)(zhang等人, 2020; 代码中使用了一个基于互信息最大化的自监督学习目标函数,它以非监督的形式来学习句子嵌入。

IS BERT 示意图

IS-BERT工作方式如下:

  1. 使用BERT对句子$s$进行编码,得到一个长度为$l$的token嵌入表示序列 $h_{1:l}$
  2. 应用不同核大小的一维卷积来处理token嵌入序列,以得到n-gram本地上下文依赖:$\mathbf{c}_i = \text{ReLU}(\mathbf{w} \cdot \mathbf{h}_{i:i+k-1} + \mathbf{b})$。输出序列被填充到和输入一样的大小
  3. 最终第$i$个token的本地表征由不同大小卷积核所输出的表征连接(concatenation)得到
  4. 最终的句子表征$\mathcal{E}_\theta(\mathbf{x})$通过对token的表征$\mathcal{F}_\theta(\mathbf{x}) = \{\mathcal{F}_\theta^{(i)} (\mathbf{x}) \in \mathbb{R}^d\}_{i=1}^l$应用一个mean-over-time池化层得到

由于互信息估计通常无法处理连续、高维的随机变量,IS-BERT依赖于Jensen-Shannon估计(Nowozin等人, 2016, Hjelm等人, 2019来最大化$\mathcal{E}_\theta(\mathbf{x})$和$\mathcal{F}_\theta^{(i)} (\mathbf{x})$间的互信息。

$$ I^\text{JSD}_\omega(\mathcal{F}_\theta^{(i)} (\mathbf{x}); \mathcal{E}_\theta(\mathbf{x})) = \mathbb{E}_{\mathbf{x}\sim P} [-\text{sp}(-T_\omega(\mathcal{F}_\theta^{(i)} (\mathbf{x}); \mathcal{E}_\theta(\mathbf{x})))] \\ - \mathbb{E}_{\mathbf{x}\sim P, \mathbf{x}' \sim\tilde{P}} [\text{sp}(T_\omega(\mathcal{F}_\theta^{(i)} (\mathbf{x}'); \mathcal{E}_\theta(\mathbf{x})))] $$

其中$T_\omega: \mathcal{F}\times\mathcal{E} \to \mathbb{R}$为一个可学习的网络(参数为$\omega$),它用于输出判别器得分。负样本$\mathbf{x}'$从分布$\tilde{P}=P$中采样得到。$\text{sp}(x)=\log(1+e^x)$为softplus激活函数。

IS-BERT在SentEval上的非监督学习的表现超过了大多数其它非监督的基线(2020年9月),但是不出意外不如监督学习的表现。当使用带标签的NLI数据集时,IS-BERT的结果同SBERT相当 (可以将下表与上面SBERT的对比)。

IS-BERT在SentEval上的性能表现


引用本文:

@article{weng2021contrastive,
  title   = "Contrastive Representation Learning",
  author  = "Weng, Lilian",
  journal = "lilianweng.github.io/lil-log",
  year    = "2021",
  url     = "https://lilianweng.github.io/lil-log/2021/05/31/contrastive-representation-learning.html"
}

引用

[1] Sumit Chopra, Raia Hadsell and Yann LeCun. “Learning a similarity metric discriminatively, with application to face verification.” CVPR 2005.

[2] Florian Schroff, Dmitry Kalenichenko and James Philbin. “FaceNet: A Unified Embedding for Face Recognition and Clustering.” CVPR 2015.

[3] Hyun Oh Song et al. “Deep Metric Learning via Lifted Structured Feature Embedding.” CVPR 2016. [code]

[4] Ruslan Salakhutdinov and Geoff Hinton. “Learning a Nonlinear Embedding by Preserving Class Neighbourhood Structure” AISTATS 2007.

[5] Michael Gutmann and Aapo Hyvärinen. “Noise-contrastive estimation: A new estimation principle for unnormalized statistical models.” AISTATS 2010.

[6] Kihyuk Sohn et al. “Improved Deep Metric Learning with Multi-class N-pair Loss Objective” NIPS 2016.

[7] Nicholas Frosst, Nicolas Papernot and Geoffrey Hinton. “Analyzing and Improving Representations with the Soft Nearest Neighbor Loss.” ICML 2019

[8] Tongzhou Wang and Phillip Isola. “Understanding Contrastive Representation Learning through Alignment and Uniformity on the Hypersphere.” ICML 2020. [code]

[9] Zhirong Wu et al. “Unsupervised feature learning via non-parametric instance-level discrimination.” CVPR 2018.

[10] Ekin D. Cubuk et al. “AutoAugment: Learning augmentation policies from data.” arXiv preprint arXiv:1805.09501 (2018).

[11] Daniel Ho et al. “Population Based Augmentation: Efficient Learning of Augmentation Policy Schedules.” ICML 2019.

[12] Ekin D. Cubuk & Barret Zoph et al. “RandAugment: Practical automated data augmentation with a reduced search space.” arXiv preprint arXiv:1909.13719 (2019).

[13] Hongyi Zhang et al. “mixup: Beyond Empirical Risk Minimization.” ICLR 2017.

[14] Sangdoo Yun et al. “CutMix: Regularization Strategy to Train Strong Classifiers with Localizable Features.” ICCV 2019.

[15] Yannis Kalantidis et al. “Mixing of Contrastive Hard Negatives” NeuriPS 2020.

[16] Ashish Jaiswal et al. “A Survey on Contrastive Self-Supervised Learning.” arXiv preprint arXiv:2011.00362 (2021)

[17] Jure Zbontar et al. “Barlow Twins: Self-Supervised Learning via Redundancy Reduction.” arXiv preprint arXiv:2103.03230 (2021) [code]

[18] Alec Radford, et al. “Learning Transferable Visual Models From Natural Language Supervision” arXiv preprint arXiv:2103.00020 (2021)

[19] Mathilde Caron et al. “Unsupervised Learning of Visual Features by Contrasting Cluster Assignments (SwAV).” NeuriPS 2020.

[20] Mathilde Caron et al. “Deep Clustering for Unsupervised Learning of Visual Features.” ECCV 2018.

[21] Prannay Khosla et al. “Supervised Contrastive Learning.” NeurIPS 2020.

[22] Aaron van den Oord, Yazhe Li & Oriol Vinyals. “Representation Learning with Contrastive Predictive Coding” arXiv preprint arXiv:1807.03748 (2018).

[23] Jason Wei and Kai Zou. “EDA: Easy data augmentation techniques for boosting performance on text classification tasks.” EMNLP-IJCNLP 2019.

[24] Sosuke Kobayashi. “Contextual Augmentation: Data Augmentation by Words with Paradigmatic Relations.” NAACL 2018

[25] Hongchao Fang et al. “CERT: Contrastive self-supervised learning for language understanding.” arXiv preprint arXiv:2005.12766 (2020).

[26] Dinghan Shen et al. “A Simple but Tough-to-Beat Data Augmentation Approach for Natural Language Understanding and Generation.” arXiv preprint arXiv:2009.13818 (2020) [code]

[27] Tianyu Gao et al. “SimCSE: Simple Contrastive Learning of Sentence Embeddings.” arXiv preprint arXiv:2104.08821 (2020). [code]

[28] Nils Reimers and Iryna Gurevych. “Sentence-BERT: Sentence embeddings using Siamese BERT-networks.” EMNLP 2019.

[29] Jianlin Su et al. “Whitening sentence representations for better semantics and faster retrieval.” arXiv preprint arXiv:2103.15316 (2021). [code]

[30] Yan Zhang et al. “An unsupervised sentence embedding method by mutual information maximization.” EMNLP 2020. [code]

[31] Bohan Li et al. “On the sentence embeddings from pre-trained language models.” EMNLP 2020.

[32] Lajanugen Logeswaran and Honglak Lee. “An efficient framework for learning sentence representations.” ICLR 2018.

[33] Joshua Robinson, et al. “Contrastive Learning with Hard Negative Samples.” ICLR 2021.

[34] Ching-Yao Chuang et al. “Debiased Contrastive Learning.” NeuriPS 2020.