本文是对论文 A Survey on Visual Transformer 的阅读,以及自己对相关引文的理解。论文标题:
A Survey on Visual Transformer
论文链接:
https://arxiv.org/pdf/2012.12556.pdf
Transformer 作为 NLP 领域的大杀器,目前已经在 CV 领域逐渐展露锋芒,大有替代 CNN 的趋势,在图像分类,视频处理,low/high level 的视觉任务都有相应的 transformer 刷榜。这篇文章在介绍这些工作的同时,讨论了他们的 challenges 和今后可能的研究方向。上图基本上就是本文的主要内容了,作者首先对 attention,transformer 做一个简单介绍,然后介绍 transformer 在 NLP 中的应用,最后将其在 CV 中的应用分为四类加以介绍。这四类分别为 classification, high-level vision, low-level vision 和video processing.Classification 顾名思义就是分类任务,High-level vision 作者定义为:“对图像中所见内容的解释和使用”,包括目标检测、分割等。Low-level vision 定义为“为图像提取描述信息”,典型应用包括超分,图像去噪,风格迁移等。
Formulation of Transformer
Transformer 由一个 encoder,一个 decoder 模块组成。每个 encoder 是一个 self-attention 层加一个全连接层,每个 decoder 由两种 attention 层加一个全连接层组成,在对句子进行处理前,首先要将每个单词转化为 维的 embedding。自注意力机制先将一个 embedding 转化为三个向量,query,key 和 value (),三者的维度都与原始 embedding 一致。所有的 embedding 放在一起组成三个大矩阵 ,然后注意力机制计算过程如下这整个过程可以被统一为一个简单的函数:
直观来看,第 1 步计算两个不同向量之间的分数,这个分数用来确定我们在当前位置编码单词时对其他单词的注意程度。步骤 2 标准化得分,使其具有更稳定的梯度,以便更好地训练;步骤 3 将得分转换为概率。最后,将每个值向量乘以概率的总和,概率越大的向量将被下面几层更多地关注。
encoder-decoder attention layer 其实和自注意力机制非常类似,不同之处在于,key,value 矩阵 是从 encoder 那里继承来的, 是从上一层继承来的。到目前为止,我们所描述的模型中缺少的一件事是解释输入序列中单词顺序的方法。因此一般都会显式的将位置信息进行编码然后加入原始的词向量中,如下图所示:开始看到这两个式子,会觉得很莫名其妙,这个 sin,cos,10000 都是从哪冒出来的?这里的 pos 表示 token 在 sequence 中的位置,例如第一个 token 就是 0。,或者准确意义上是 和 表示了 Positional Encoding 的维度,。所以当 pos 为 1 时,对应的 Positional Encoding 可以写成:在 single-head 的模型中,我们最终得到的 embedding 融合了其他各个位置,但是他很有可能被单词本身 dominate(自身对自身的 attention 一般很大),而且我们不能确保随机初始化后不断学习得到 这些矩阵带来的 attention 一定对。因此 multi-head 可以看作是一种 ensemble,我们现在有多组矩阵 ,他们将同一个输入 embedding 映射到不同的表达空间以此来提高模型的表达能力。不过此时 query,key,value 的维度不再与原始 embedding 一致,而是变为 ,因此每个 head 经过 self-attention 将 word 映射为 维的embedding,将这些 embedding 连接在一起就变为原始维度,数学定义如下:对于 decoder 来讲,我们注意到有两个与 encoder 不同的地方,一个是第一级的 Masked Multi-head,另一个是第二级的 Multi-Head Attention 不仅接受来自前一级的输出,还要接收 encoder 的输出,下面分别解释一下是什么原理。
第一级 decoder 的 key, query, value 均来自前一层 decoder 的输出,但加入了 Mask 操作,即我们只能attend到前面已经翻译过的输出的词语,因为翻译过程我们当前还并不知道下一个输出词语,这是我们之后才会推测到的。
而第二级 decoder 也被称作 encoder-decoder attention layer,即它的 query 来自于之前一级的 decoder 层的输出,但其 key 和 value 来自于 encoder 的输出,这使得 decoder 的每一个位置都可以 attend 到输入序列的每一个位置。
总结一下,k 和 v 的来源总是相同的,q 在 encoder 及第一级 decoder 中与 k,v 来源相同,在 encoder-decoder attention layer 中与 k,v 来源不同。1.3 Other Parts in TransformerResidual in the encoder and decoder:在上面的结构图中可以看到,每个 encoder,decoder 模块都是会有一个残差连接+ layerNorm 的,具体而言就是:Feed-forward neural network:这个模块不是简单的 FCN,而是两层 FCN 加一个非线性的激活函数,即 。Final layer in decoder:解码器的最后一层旨在将向量转为一个字。这是通过一个线性层和一个 softmax 层来实现的。线性层将向量投影到一个 维的 logit 向量中,其中 是词汇表中的单词数。然后,使用 softmax 层将 logits 向量转换为概率。大多数用于计算机视觉任务的 Transformer 都使用原编码器模块。总之,它可以被视为一种不同于 CNN 和递归神经网络 RNN 的新型特征选择器。与只关注局部特征的 CNN 相比,transformer 能够捕捉到长距离特征,这意味着 transformer 可以很容易地获得全局信息。
与 RNN 的隐态计算顺序相比较,Transformer 的自注意层和全连接层的输出可并行计算,且速度快。因此,进一步研究 Transformer 在自然语言处理和计算机视觉领域的应用具有重要意义。
Revisiting Transformers for NLP
Transformers 出现后,克服了RNN训练速度慢的缺陷,使得大规模预训练模型成为可能。BETR 及其变种(SpanBERT,RoBERTa)等都是基于 transformer 的模型。在 BERT 的预训练阶段,对 BookCorpus 和英语维基百科数据集进行了两个任务
Generative Pre-Trained Transformer(GPT2,GPT3)是另一种基于 Transformer 解码器架构的预训练模型,它使用了带掩码的自我注意机制。
GPT 和 Bert 系列最重要的区别在于与训练的方式,GPT 是单向 Transformer 模型,这种单向的性质使其在文本生成方面具有强大的能力,今年 Google 使用“钞”能力造出的 GPT3 更是在各种任务都有非常优越的表现,而且不再需要 fine-tune。当然还有其他的一些 PTM 模型,但这并不是改文章的主题,因此作者只是列出来以供参考。还有一些多模态的 transformer 和这篇文章比较相关,可以简单了解一下。VideoBERT 使用基于 CNN 的 module 将图像转化为 token,然后使用 transformer 的 encoder 来为下游任务学习一个 video-text representation。
VisualBERT 和 VL-BERT 提出了 single-stream unified transformer,用于捕获视觉元素和图像-文本关系,用于像视觉问题回答(VQA)和视觉常识推理(VCR)的下游任务。此外,Speech bert 探索了用 transformer 编码器编码音频和文本 pair 的可能性,以处理自动文本任务,如语音问题回答(SQA)。图像作为一种高维、噪声大、冗余度高的形态,被认为是生成建模的难点,这也是为什么过了好几年,transformer 才应用到视觉领域。比较初始的应用是在 Visual Transformer 一文中,作者使用 CNN 提取 low-level 的特征,然后将这些特征输 入Visual Transformer [1](VT)。
在 VT 中,作者设计了一个 tokenizer 将各个 pixel 分成少量的 visual tokens,每个 token 代表了图像中的某些语义信息。然后使用 transformer 来建模 token 之间的关系。最后输出的 tokens 直接被用来做分类或者处理一下恢复成特征图用于实例分割。与这项工作不同的是,最近出现的 iGPT , ViT 和 DeiT 都是只使用 transformer 的文章。
在 CV 中使用 transformer,目前来看主要的两个问题,以及下列文章的核心区别在于:
得到 Token 的方式
训练的方式
评估 representation 的方式
只要得到 token,我们就能像 NLP 一样使用 transformer;有训练目标我们就能 train 我们的 model;有评估方式我们才知道自己的 model 好还是坏。接下来的几篇文章我也会从这几个方面进行讲解。3.1.1 iGPT
论文标题:Generative Pretraining from Pixels
论文链接:https://cdn.openai.com/papers/Generative_Pretraining_from_Pixels_V2.pdf
代码链接:https://github.com/openai/image-gptToken:iGPT 使用一种比较暴力的方式得到 token:原始图像()进行预处理,将其调整为低分辨率,并将其重塑为一维序列(从左到右,从上到小)。对于 RGB 数据,我们的字典大小为 (文中采取了比较有趣的手段减小字典),每个像素相当于一个 word,即对每个 pixel,我们采用nn.Embedding(num_vocab, embed_dim)
提取每个像素 embedding。至此图片数据已经完全转化为了 transformer 的输入形式 。其中 seq_len 取决于 down sample 保留了多少 pixel。
Pretrain:iGPT 有两种预训练方式:1)像自编码器一样进行逐像素预测;2)像 Bert 一样 mask 一部分 pixel 然后预测。其实第一种方式的实现与 bert 也很类似,就是预测第 个 pixel 的时候,mask 掉 之后的所有 pixel。attn_mask = torch.full(
(len(x), len(x)), -float("Inf"), device=x.device, dtype=x.dtype
)
attn_mask = torch.triu(attn_mask, diagonal=1)#[784, 784]
#attn_mask = [[0,-inf,-inf...,-inf],
# [0,0,-inf,...,-inf],
# [0,0,0,...,-inf],
# [0,0,0,...,0]]
Evaluation:两种评估方式:1)fine-tune:增加了一个小的分类头,用于优化分类目标并 adapt 所有权重;2)Linear-probe:将 pretraining 的模型视作特征提取器,增加一个分类头,只训练这个分类头。第二种方式的直觉在于“一个好的特征应该能够区分不同的类”,除此之外,fine-tune 效果好有可能是因为架构很适合下游任务,但是 linear-probe 只取决于特征质量。
主要过程的代码如下,数字只是为了示例,下面假设字典长度为 16(pixel 一共 16 种)。
# x:原始图像处理后得到的序列 [32*32, 64],64为batchsize,32是下采样后的长款
length, batch = x.shape
# 将每个pixel作为token求embedding,128为embedding的维度
h = self.token_embeddings(x) # [32*32, 64, 128]
# 添加位置编码
h = h + self.position_embeddings(positions).expand_as(h)
# transformer
for layer in self.layers:
h = layer(h)
# 自回归编码需要输出logits,映射回字典长度
logits = self.head(h) # [32*32,64,16]
# 16类的cross_entropy,对每个pixel计算损失
loss = self.criterion(logits.view(-1, logits.size(-1)), x.view(-1))
3.1.2 ViT
论文标题:An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale
论文链接:https://arxiv.org/abs/2010.11929
代码链接:https://github.com/google-research/vision_transformer
上文我们提到过,BERT 在执行序列级的任务时使用第一个 token 作为特征得到分类结果。比如下面这句,他会在第一个位置加上 CLS token,([CLS] 谷歌和 [MASK][MASK] 都是不存在的。[SEP] 同时,[MASK] 也是不存在的。[SEP])最后使用该 CLS token 得到的结果进行分类。那么我们是不是也可以参照这种方式直接进行分类呢?答案是肯定。Token:一个图像 将被处理为一个 patch 序列 。(H,W)是原始分辨率,(P,P)是每个 patch 的分辨率, 是序列长度。由于 transformer 在所有层中使用恒定宽度,一个可训练的线性投影将每个 映射到 D 维向量,其输出称为 patch embeddings。Pretrain:传统情况下 ViT 也是要预训练的,不同于 iGPT,这不是一个生成式的模型,只采用了 transformer 的 encoder,因此直接在 imagenet 做分类任务进行 pretrain。文章显示数据集小的时候效果一般,数据集大的时候因为 data bias 已经被消除了很多,此时效果非常好。
Evaluation:分类任务的评价不再多说。
3.2.1 Generic Object Detection
基于 transformer 的目标检测可以分为两类,也即下图的 (a)(b):Transformer-based set prediction for detection. DETR [2] 是这类工作的先驱,其将目标检测视为集合预测问题,去掉了目标检测种很多手工的组件像 NMS,anchor generation 等。
Token:CNN 将图像 downsample 为 ,然后将 的空间维度压缩为一维,造成一个序列 。这个 token 的获取方式挺有意思,空间维度塌缩。当然也要加上位置编码。Train:如何将 object detection 转化为 set prediction 然后进行训练,这是一个非常有意思的问题。作者使用了 object queries,这实际上是另一组可学习的 positional embedding,其功能类似于 anchor。之后每个 query 进过 decoder 后算一个 bbox 和 class prob。
DETR 也大方地承认了他的缺点:训练周期长,对小物体检测效果差。
Transformer-based backbone for detection.与 DETR 不同,ViT-FRCNN [3] 将 ViT 与传统的检测框架融合,直接使用 transformer 的 encoder 作为 backbone 提取特征,与 ViT 处理图像的方式一致,但是输出的 patch feature 重新调整为一个图像的特征图送入传统检测模型。总结一下,目前 transformer 已经在很多视觉应用中展现出了强大的实力。使用 transformer 最重要的两个问题是如何得到输入的 embedding(妥善处理position embedding),模型的训练与评估。
目前还有很多非常有价值的课题值得我们探索,例如,对于最终的性能,像 CNN 或 PointNet 这样的特征提取模块是必要的吗?如何让 visual transformer 受益于像 BERT 或 GPT-3 在 NLP 社区做的大规模的预训练数据。是否有可能预先训练单个 transformer 模型,并通过几次微调来针对不同的下游任务进行微调(人民币玩家们加油)?这里所谓的 low-level,其实就是输出并不是标签这种形式,而是超分,或者生成模型,直接输出图片。这一类应用的大体框架如下,transformer 编码器将图像作为像素序列或小块,以该序列作为输入语句,transformer 解码器就能成功地生成所需的图像。在未来的工作中,为不同的图像处理任务设计合适的体系结构将是一个有意义的方向。Image transformer 一文最先使用完整的 transformer 做图像生成的工作。他将每个值为 的像素编码成一个 维向量,作为编码器的输入。特殊之处在于 decoder,每个输出像素 是经过计算输入像素 以及已经生成像素 之间的 attention 得到的。到这里用于图像的 transformer 基本算是搞完了,还有一些基于视频的,多模态的,self-attention 在 CV 中的应用都不是我关注的重点。最后再看一看目前存在的问题以及未来可能的发展方向
Conclusions and Discussions
4.1 Challenges
目前来看,大多数应用都保留了 transformer 在 NLP 任务中的原始形态,这一形态不一定适合 images,因此是否会有改进版本,更加适合视觉任务的 transformer 尚且未知。除此之外,transformer 需要的数据量太大,缺少像 CNN 一样的 inductive biases,我们也很难解释他为什么 work,在本就是黑盒的DL领域又套了一层黑盒。
最后也是大多数非人民币玩家关注的点在于,基本的 ViT 模型需要 180 亿次浮点运算来处理一个图像。相比之下,轻量级的 CNN 模型 GhostNet 只需约 6 亿次 FLOPs 就能达到类似的性能,这个运算消耗实在太过昂贵。- 像 NLP 一样的大一统模型,一个 transformer 解决所有下游任务。
[1] https://arxiv.org/abs/2006.03677[2] https://arxiv.org/abs/2005.12872[3] https://arxiv.org/abs/2012.09958
推荐阅读
GPU底层优化 | 如何让Transformer在GPU上跑得更快?
如何看待Transformer在CV上的应用前景,未来有可能替代CNN吗?