1. 前言
在深度学习中,自监督学习或半监督学习是一个很有意思并且非常吸引人的领域。监督学习的损失函数比较直观和简洁,跟真值有直接的联系。而自监督学习或半监督学习的误差函数的构建比较复杂,需要从原始数据中挖掘出有价值的信息作为损失函数。并且损失函数的设计高度依赖于领域知识。但是这一类学习方法的好处是可以在标注数据较少甚至没有的场合完成网络的训练。对比学习(Contrastive Learning
)是近年来在自监督学习中比较火热的领域。相关知识可以参考这篇知乎。这篇博文主要去简单分析一篇对比学习的论文“A Simple Framework for Contrastive Learning of Visual Representations”。这篇文章用对比学习做图像目标分类。在讲解这篇文章的时候,我们以图像目标分类作为讲解例子。
2. 对比学习
对比学习归属于自监督学习,所以对比学习是没有真值标签的。对比学习的示意图如下所示。以图像目标分类为例子讲解下图。假设 x x x是一张印有小狗的图像。我们要设计一个网络 Net ( ⋅ ) \text {Net}(\cdot) Net(⋅),使得它有图像分类的能力,即 z = N e t ( x ) z={Net}(x) z=Net(x), z z z表示小狗所在的那一类。由上图所示,网络的结构是 Net ( ⋅ ) = g ( ⋅ ) ∘ f ( ⋅ ) \text {Net}(\cdot)=g(\cdot) \circ f(\cdot) Net(⋅)=g(⋅)∘f(⋅)。其中 h = f ( x ) h=f(x) h=f(x)表示图像的特征。
图1:对比学习的示意图
上图可见
x
i
=
t
(
x
)
x_i=t(x)
xi=t(x)以及
x
j
=
t
′
(
x
)
x_j=t'(x)
xj=t′(x)。以及
t
,
t
′
∈
T
t,t' \in T
t,t′∈T。
T
T
T表示二维图像数据增强的操作集合。这个集合包括,图像旋转,图像对称,图像噪声,图像剪裁等等操作,示意图如下所示。举个例子,比如
t
t
t可以是图像旋转,
t
′
t'
t′可以是图像噪声。那么数据增强后的图像
x
i
x_i
xi和
x
j
x_j
xj对应下图中的(f)
和(h)
。当然,原始图像
x
x
x对应下图中的(a)
。
图2:二维图像数据增强的种种操作
把数据增强后的图像 x i x_i xi和 x j x_j xj放入网络里面,可以输出 z i = Net ( x i ) z_i=\text{Net}(x_i) zi=Net(xi)和 z j = Net ( x j ) z_j=\text{Net}(x_j) zj=Net(xj),表示网络从这些图像中预测的结果。因为对比学习没有真值,那应该怎样设计误差函数,指导 z i z_i zi和 z j z_j zj趋于正确的分类呢?论文作者认为,误差函数应该设计为 z i z_i zi和 z j z_j zj的差异度。不管 z i z_i zi和 z j z_j zj预测成什么,我只希望 z i = z j z_i=z_j zi=zj,除此之外别我他求。要么这两张图都预测为猫,要么这两张图都预测为狗。论文作者认为,只有当 z i = z j z_i=z_j zi=zj的时候,网络才能真正地从两幅数据增强的图像中学到它们之间的通用特征。而通用特征则是目标识别的关键。
肯定会有读者质疑,如果仅仅是以 z i = z j z_i=z_j zi=zj作为误差函数标准,万一训练结果是 z i = z j = 猫 z_i=z_j=猫 zi=zj=猫,这该怎么办呢?别着急。后面会去讲它(在讲后面对比学习的伪代码的时候会做出交代)!
怎样去设计一个误差函数去衡量
z
i
z_i
zi和
z
j
z_j
zj的差异度呢?在多分类问题里面,
z
i
z_i
zi和
z
j
z_j
zj都是指one-hot
向量。论文中使用余弦距离/向量积来衡量它们之间的差异,定义
s
i
,
j
=
z
i
T
z
j
/
(
∥
z
i
∥
∥
z
j
∥
)
s_{i,j}=z_i^Tz_j/(\Vert z_i\Vert \Vert z_j \Vert)
si,j=ziTzj/(∥zi∥∥zj∥)。如果
z
i
z_i
zi和
z
j
z_j
zj越发地相近,那么
s
i
,
j
→
1
s_{i,j}\rightarrow 1
si,j→1。
接下来,看一下对比学习计算的伪代码:
看到计算
s
i
,
j
s_{i,j}
si,j这段代码为止,差不多都能理解。
l
(
i
,
j
)
l(i,j)
l(i,j)是
−
log
(
Softmax
(
⋅
)
)
-\log(\text{Softmax}(\cdot))
−log(Softmax(⋅))的变体,也能去理解。在训练过程中,需要使
L
→
0
L \rightarrow 0
L→0,这意味着
l
(
2
k
−
1
,
2
k
)
→
0
l(2k-1,2k) \rightarrow 0
l(2k−1,2k)→0以及
l
(
2
k
,
2
k
−
1
)
→
0
l(2k,2k-1) \rightarrow 0
l(2k,2k−1)→0。结合
l
(
i
,
j
)
l(i,j)
l(i,j)的定义,
l
(
2
k
−
1
,
2
k
)
→
0
l(2k-1,2k) \rightarrow 0
l(2k−1,2k)→0表示
s
2
k
−
1
,
2
k
→
1
s_{2k-1,2k} \rightarrow 1
s2k−1,2k→1并且
s
2
k
−
1
,
m
→
0
(
m
≠
2
k
−
1
,
2
k
)
s_{2k-1,m}\rightarrow 0 (m \not= 2k-1,2k)
s2k−1,m→0(m=2k−1,2k)。这说明网络会强制要求:同一张图片经过数据增强变形后得到两张增强图片,必须要从这两张图片中挖掘出共同的特征(误差函数告诉我们:非得是这两张同源图片,其他图片都是不行的)。经过这般学习后,
f
(
⋅
)
f(\cdot)
f(⋅)会有泛化能力很强的表征能力。对于一张图片,不管这个图片做了怎样的数据增强处理,
f
(
⋅
)
f(\cdot)
f(⋅)都会稳定地提取到这张图片最为本质的特征。
伪代码的最后一行也是个骚操作,保留 f ( ⋅ ) f(\cdot) f(⋅),丢掉 g ( ⋅ ) g(\cdot) g(⋅)。丢掉 g ( ⋅ ) g(\cdot) g(⋅)其实是可以理解的。这对应着前面讲的那个问题:如果仅仅是以 z i = z j z_i=z_j zi=zj作为误差函数标准,万一训练结果是 z i = z j = 猫 z_i=z_j=猫 zi=zj=猫,这该怎么办呢?因为缺乏真值作为监督, g ( ⋅ ) g(\cdot) g(⋅)会产生一些奇怪的结果,比如把所有狗的照片识别为猫,所有猫的照片识别为猪,所有猪的照片识别为狗。所以丢掉 g ( ⋅ ) g(\cdot) g(⋅)是正确的。保留 f ( ⋅ ) f(\cdot) f(⋅)的原因前面也已经讲了, f ( ⋅ ) f(\cdot) f(⋅)有泛化能力很强的表征能力。
注意看这篇论文的标题A Simple Framework for Contrastive Learning of Visual Representations
。这篇论文主要的目的是学习提取特征(Learning of Visual Representations
),所以说它的核心目的即是获取
f
(
⋅
)
f(\cdot)
f(⋅)。
3. 结束语
当然,对于一个完整的图片目标分类算法,通过对比学习得到 f ( ⋅ ) f(\cdot) f(⋅)后,可以通过监督学习的方法重新训练 g ( ⋅ ) g(\cdot) g(⋅)。因为 f ( ⋅ ) f(\cdot) f(⋅)拥有强大且稳定的表示特征的能力,那么整体网络 Net \text{Net} Net也是泛化能力强的。这大概是这篇文章的意思。