目录
参考资料
论文:
An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale
博客:
视频:
第1章 引言
由于在图像分类任务中,输入一般最小为 224 × 224 × 3 224\times 224\times 3 224×224×3 ,如果把每个像素点作为Transformer的输入,会导致序列长度过长,那么计算量会变得非常大;因为一般在NLP领域输入的单词个数一般也就几百,而这里 224 × 224 = 50176 224\times 224=50176 224×224=50176 ,所以要想把Transformer运用到CV领域,并不能直接对像素点进行操作。
作者提出了一种方法,通过将图像变成多个 Patch
的方式,将CV任务变成和NLP任务一样的训练方式。
第2章 主要方法
下图是Vision Transformer(ViT)的整体框图,是谷歌首次将transformer应用在图像分类任务的模型。
思路并不复杂,对应到下图分别是:
- 将图像化整为零,切分成
patch
,例如 14 × 14 = 196 14\times14=196 14×14=196 份; - 将
patch
通过线性投影,转换为patch embedding
; - 获得
position(位置)embbeding
,为每个patch
加入位置信息; - 输入到Tranformer编码器,其结构详见右子图;
- 输出到MLP(多层感知机)做分类任务;
2.1 Patch spilt
对于图像数据而言,其数据格式通常为3维 [ H , W , C = 3 ] ( 长、宽、通道数 ) [H,W,C=3](长、宽、通道数) [H,W,C=3](长、宽、通道数)。
对于标准transformer,输入应该是1维的token序列,token本身可以有1个维度,故需要将图片数据降低到2维。
ViT采用的方法是:将[224,224,3]的输入图像,按照16x16x3的大小,划分成14x14=196个patch。
那么每个patch块的大小为: 16 × 16 × 3 = 768 16\times 16\times 3=768 16×16×3=768 ,然后将大小为 [ 16 , 16 , 3 ] [16,16,3] [16,16,3] 的patch数据,拉平为长度为 768 768 768 的向量。
即经过patch划分后,输入变为了 196 × 768 196\times 768 196×768 。
可以看作196个单词,每个单词维度为768。
2.2 Path embedding
这里的embedding主要就是通过一个线性层实现,将输入映射到另一个语义空间中,将上面得到 196 × 768 196\times 768 196×768 的向量与一个尺寸为 768 × 768 768\times 768 768×768 的矩阵相乘,得到一个长度为 196 × 768 196\times 768 196×768 的输出向量,即token。
2.3 Position embedding
图片中注释了,在Patch + Position embedding外,还需要考虑:额外可学习的 class embedding
。
这里加入class embedding的目的是为了最终做分类,作者解释是参考BERT,本文对动机不做赘述。
Class embedding和其他token一样都是向量,大小为[1, 768]。和token数据拼接(cat)后:
[
1
,
768
]
+
[
196
,
768
]
=
>
[
197
,
768
]
[1, 768] + [196, 768] => [197, 768]
[1,768]+[196,768]=>[197,768]
然后, 让我们回归到Position embedding上。由于transformer的核心self-attention(自注意力机制)不区分输入数据的顺序:
- 现象:打乱tokens顺序不影响计算结果;
- 问题:如果不给模型提供patch在原图[224, 224, 3]中的位置信息,会额外增加学习成本,导致精度下降。
为了解决该问题,采用一个可训练的向量[197],add
于拼接后的数据 [197, 768] 上,故叠加后的数据依然是 [197, 768] 。
对于使用何种 Positition embedding
,原论文进行了若干对比实验,结果是:
- 使用Position embedding相比于不使用,准确率有显著提升;
- 使用何种Position embedding方式,其效果差距不大。
2.4 Transformer Encoder
如图所示,Transformer Encoder左上角处有:[L x]。代表灰色框出的部分,可以叠加L次。
输入数据为 [197, 768] 格式,输出数据仍然为 [197, 768]。
详细细节和Transformer的Encoder一样。
第3章 实验和总结
作者对比了ViT和CNN(卷积神经网络)在不同数据集上的表现:
- 在比较小的数据集上训练,ViT不优于ResNet(CNN模型);而在大数据集上,ViT效果优于ResNet;
- 在比较大的数据集上做预训练后,然后在小数据集上做fine-tune,效果也可以超过ResNet。
第4章 Pytorch实现VIT
参考博客:
"未来"的经典之作ViT:transformer is all you need!
参考代码: