Daily Paper 07 - CrossTransformers
Tilden Ji 菜鸟Lv3

今天这篇是谷歌发在 NeurlIPS 2020 的一项工作,主要是把自监督对比学习和 Transformers 整合进了小样本学习中。对比学习具体用的是很烧显存的 SimCLR… 啊这,瞬间劝退… 不过论文的一些点还是挺有意思的,特别是那个新的 Transformers 结构,这不就是我最近苦苦寻找的针对 feature map 的 Transformers!!!

论文名: Cross Transformers: spatially-aware few-shot transfer
官方代码(Tf): google-research/meta-dataset
热心网友代码(Pt,只有 CrossTransformers): lucidrains/cross-transformers-pytorch

另一份非官方代码(Pt,比较全) skrish13/CrossTransformers-PyTorch

「」

编写记录

  1. 2021 年 6 月 17 日 看论文,写了一点。
  2. 2021 年 6 月 19 日 看了会儿论文,完成初稿。

简介

本文提出了一个很有意思的术语「监督崩溃 Supervision Collapse」,这个之后会提到。大概意思是说对于同一个类别中的两个样本,如果强行同一个优化目标(如独热标签)训练,可能会丧失对一些内在特征的辨别能力。然后说为了解决这个监督崩溃问题,提出了两个方法。一个方法是加入自监督对比学习。这个很好理解,因为对比学习强调的是单个样本的可辨别性,就一定程度上减轻了对传统类别辨别学习的依赖;另一个方法是一个新的 Transformers 方法「Cross Transformers」,来寻找 query 和 support 样本之间的空间对应关系,计算对应特征之间的距离作为类别推断依据。

监督崩溃

监督崩溃?类内过于聚合反而不好?这个概念乍一听有点奇怪。不过听作者掰扯了一下,感觉有点道理!不过看了又看,这不就是把过拟合换了个听起来很厉害的术语吗?(手动狗头)

作者用一个图表解释了什么是监督崩溃,其实我感觉我可能没太看懂,就按照自己的理解先梳理一下吧。上图是这样产生的,首先用训练集学习好一个基线模型「原型网络」。然后对于测试集里的一个 Query 样本,用最近邻算法从测试集与支持集的联合数据集中选取最近的 9 个样本展示出来,其中标小药瓶的 emoji 就表示这个样本来自于测试集(也就是未见类)。注意这里选取的 Query 都是很具有迷惑性的,也就是说它有些很像其他类别的特征。结果发现只有 5% 的最近邻是标签与 Query 相同的,并且错误的样本好多都是来自于同一个错误的类别(图中用红框框出来了)。这是因为传统监督学习过分强调类内内聚和类间分离,导致模型可能过分依赖于某一个特征,而忽略了不同类之间也可能有相似特征这个事实。这最终就导致了模型的泛化能力下降(这不就是过拟合吗?)。

这可能是由于现有训练方式的不足导致的:

  1. 完全依靠类别标签进行特征学习的方式会导致只能学习到跟类别相关的信息,而忽略其他 更加通用的特征表示

  2. 在做图像比较的时候,图像中的一些重要objects 和 scenes 通常是 local 的,直接用整体特征进行比较的效果不一定是最好的;

方法

为了解决模式崩溃问题,作者提出了两个方法:对比学习和 Cross Transformers。其中对比学习通过增加「Instance Level」的辨别性提高 CNN 对通用特征的理解;Cross Transformers 在局部级别度量图像距离。

对比学习

对比学习最近真的是很热门啊。简单解释一下,现在对比学习研究的也比较透彻了,说来说去其实就是去学习一个增广不变性,这也就是为啥对比学习非常依赖图像增广的原因。具体来说就是给一张图片,用不同的增广来处理得到不同的图像,最后通过各种对比损失函数,让 CNN 能够搞懂哪些图像是同一张图像的不同增广的同时也能分辨不同的图像。也就是说,对比学习是学习的「样本级别 Instance level」的辨别性,所以即使是同一类的图像,它也能有一定程度的辨别性,这也就正好能够解决 过拟合(×)监督崩溃(√)的问题。

不过我对这部分不是很感冒… 感觉不是很好玩而且略微有点牵强。就简单介绍下本文是怎么把对比学习加进去的吧~

和其他的工作不同,本文没有用「多任务学习」的方式来植入对比学习,也就是没有用额外附加一个 auxiliary loss 这种方式。而是从 episodic 训练轮次中随机抽一半的 episodic 来训练 SimCLR,具体方法没看,详见论文。

Cross Transformers

这个是本文的核心,可以看作一种度量方式,提供了局部之间的比较。

Cross Transformers 基于 Transformer 构建,Transformer 的基础知识可以参考这篇博客,其结构如下图所示:

首先,模型的 CNN 网络(也就是图中的)去掉了最后一层 Avg Pooling,也就是说输出的是特征图: ,和一般的 Transformers 方法一样,有几个独立的线性预测头(注意后文会提到,本文出于一些目的,让 ):

  1. Key:
  2. Value:
  3. Query:

然后就是通过 keys 和 queries 计算得到点乘注意力权重,权重在所有的支持集样本和空间位置上进行 softmax 归一化。


具体的,对于支持集的某一个类别 ,输出的空间位置 上的原型向量 通过如下公式计算:

其中,,是映射后的位置 上的支持集向量。 是注意力权重,是使用支持集和查询集一同计算的,计算公式如下:

其中,

在得到 后,可以通过如下方式计算查询集与某一个类别之间的距离:

其中,,是空间位置 上的查询样本经过头 映射后的向量。

这里注意,模型让同样的 作用于支持图像和查询图像。考虑一种边界情况,支持集只包含查询集图像。前面的设定能够使得在任何参数下(即使模型未经训练),该情况的距离输出恒定为 0。
另外在实现时,作者让 ,这样在上述边界情况下,注意力权重值会在 时达到最大。

更新:附上知乎大神标注的保姆级别的结构图,可以便于理解:

Cross Transformers 的 PyTorch 实现

下面是 Cross Transformers 的一个非官方简介实现,用 无偏卷积实现空间上的线性映射,如果不能理解可以参考这个材料

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import torch
from torch import nn, einsum
import torch.nn.functional as F

from einops import rearrange

class CrossTransformer(nn.Module):
def __init__(
self,
dim = 512,
dim_key = 128,
dim_value = 128
):
super().__init__()
self.scale = dim_key ** -0.5
self.to_qk = nn.Conv2d(dim, dim_key, 1, bias = False)
self.to_v = nn.Conv2d(dim, dim_value, 1, bias = False)

def forward(self, model, img_query, img_supports):
"""
dimensions names:

b - batch
k - num classes
n - num images in a support class
c - channels
h, i - height
w, j - width
"""

b, k, *_ = img_supports.shape

query_repr = model(img_query)
*_, h, w = query_repr.shape

img_supports = rearrange(img_supports, 'b k n c h w -> (b k n) c h w', b = b)
supports_repr = model(img_supports)

query_q, query_v = self.to_qk(query_repr), self.to_v(query_repr)

supports_k, supports_v = self.to_qk(supports_repr), self.to_v(supports_repr)
supports_k, supports_v = map(lambda t: rearrange(t, '(b k n) c h w -> b k n c h w', b = b, k = k), (supports_k, supports_v))

sim = einsum('b c h w, b k n c i j -> b k h w n i j', query_q, supports_k) * self.scale
sim = rearrange(sim, 'b k h w n i j -> b k h w (n i j)')

attn = sim.softmax(dim = -1)
attn = rearrange(attn, 'b k h w (n i j) -> b k h w n i j', i = h, j = w)

out = einsum('b k h w n i j, b k n c i j -> b k c h w', attn, supports_v)

out = rearrange(out, 'b k c h w -> b k (c h w)')
query_v = rearrange(query_v, 'b c h w -> b () (c h w)')

euclidean_dist = ((query_v - out) ** 2).sum(dim = -1) / (h * w)
return -euclidean_dist

大量使用了 einsum 函数,我摊牌了,没太看懂。不过看起来还挺简洁的…

实验

首先是对注意力的一个可视化:

随机在查询图像上选取了三个空间位置,然后分别在三张支持集上可视化了注意力权重,透明度越低的色块表示数值越大。

然后是在 Meta-Dataset 上的实验结果:

总结

  1. 本文自监督学习的整合方式值得参考。
  2. 通过实验结果也可以看出,CTX 是个非常有效方法,不过他的计算是依赖于小样本设置的,双阶段训练的时候是不是可以直接只加在 finetuning 上?
  3. 值得关注的相关工作:
    • 看看方法和增广方式:Optimized Generic Feature Learning for Few-shot Classification across Domains(ICCV 2019)
    • When Does Self-supervision Improve Few-shot Learning?(ECCV 2020)
    • 新的元学习数据集:Meta-Dataset

Reference

[1]C. Doersch, A. Gupta, and A. Zisserman, “CrossTransformers: spatially-aware few-shot transfer,” arXiv:2007.11498 [cs], Feb. 2021, Accessed: Jun. 16, 2021. [Online]. Available
[8]T. Saikia, T. Brox, and C. Schmid, “Optimized Generic Feature Learning for Few-shot Classification across Domains,” arXiv:2001.07926 [cs], Jan. 2020, Accessed: Jun. 19, 2021. [Online]. Available
[9]J.-C. Su, S. Maji, and B. Hariharan, “When Does Self-supervision Improve Few-shot Learning?,” arXiv:1910.03560 [cs], Jul. 2020, Accessed: Apr. 03, 2021. [Online]. Available
  • 本文标题:Daily Paper 07 - CrossTransformers
  • 本文作者:Tilden Ji
  • 创建时间:2021-06-17 12:58:57
  • 本文链接:https://itiandong.com/2021/daily-paper-07/
  • 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
 评论