這裡將介紹一篇我認為是比較新穎的一篇文章 ——《An Image Is Worth 16X16 Words: Transformers for Image Recognition at Scale》 。因為還是 ICLR 2021 under review,所以作者目前還是匿名的,但是看其實驗用到的TPU,能夠大概猜出應該是Google爸爸的文章(看著實驗的配置,不得不感慨鈔能力的力量)。
1. Story近年來,Transformer已經成了NLP領域的標準配置,但是CV領域還是CNN(如ResNet, DenseNet等)佔據了絕大多數的SOTA結果。
最近CV界也有很多文章將transformer遷移到CV領域,這些文章總的來說可以分為兩個大類:
將self-attention機制與常見的CNN架構結合;用self-attention機制完全替代CNN。本文采用的也是第2種思路。雖然已經有很多工作用self-attention完全替代CNN,且在理論上效率比較高,但是它們用了特殊的attention機制,無法從硬體層面加速,所以目前CV領域的SOTA結果還是被CNN架構所佔據。
文章不同於以往工作的地方,就是儘可能地將NLP領域的transformer不作修改地搬到CV領域來。但是NLP處理的語言資料是序列化的,而CV中處理的影象資料是三維的(長、寬和channels)。
所以我們需要一個方式將影象這種三維資料轉化為序列化的資料。文章中,影象被切割成一個個patch,這些patch按照一定的順序排列,就成了序列化的資料。(具體將在下面講述)
在實驗中,作者發現,在中等規模的資料集上(例如ImageNet),transformer模型的表現不如ResNets;而當資料集的規模擴大,transformer模型的效果接近或者超過了目前的一些SOTA結果。作者認為是大規模的訓練可以鼓勵transformer學到CNN結構所擁有的translation equivariance (解釋看這裡) 和locality.
2. ModelVision Transformer (ViT)結構示意圖
模型的結構其實比較簡單,可以分成以下幾個部分來理解:
a. 將影象轉化為序列化資料作者採用了了一個比較簡單的方式。如下圖所示。首先將影象分割成一個個patch,然後將每個patch reshape成一個向量,得到所謂的flattened patch。
具體地,如果圖片是維的,用大小的patch去分割圖片可以得到個patch,那麼每個patch的shape就是,轉化為向量後就是維的向量,將個patch reshape後的向量concat在一起就得到了一個Nx(P^2 C) 的二維矩陣,相當於NLP中輸入transformer的詞向量。
分割影象得到patch
從上面的過程可以看出,當patch的大小變化時(即P變化時),每個patch reshape後得到的維向量的長度也會變化。為了避免模型結構受到patch size的影響,作者對上述過程得到的flattened patches向量做了Linear Projection(如下圖所示),將不同長度的flattened patch向量轉化為固定長度的向量(記做維向量)。
對flattened patches做linear projection
綜上,原本維的圖片被轉化為了個維的向量(或者一個維的二維矩陣)。
b. Position embeddingpositiion embedding示意圖
由於transformer模型本身是沒有位置資訊的,和NLP中一樣,我們需要用position embedding將位置資訊加到模型中去。
如上圖所示1,編號有0-9的紫色框表示各個位置的position embedding,而紫色框旁邊的粉色框則是經過linear projection之後的flattened patch向量。文中採用將position embedding(即圖中紫色框)和patch embedding(即圖中粉色框)相加的方式結合position資訊。
c. Learnable embedding如果大家仔細看上圖,就會發現帶星號的粉色框(即0號紫色框右邊的那個)不是透過某個patch產生的。這個是一個learnable embedding(記作),其作用類似於BERT中的[class] token。在BERT中,[class] token經過encoder後對應的結果作為整個句子的表示;類似地,這裡經過encoder後對應的結果也作為整個圖的表示。
至於為什麼BERT或者這篇文章的ViT要多加一個token呢?因為如果人為地指定一個embedding(例如本文中某個patch經過Linear Projection得到的embedding)經過encoder得到的結果作為整體的表示,則不可避免地會使得整體表示偏向於這個指定embedding的資訊(例如影象的表示偏重於反映某個patch的資訊)。而這個新增的token沒有語義資訊(即在句子中與任何的詞無關,在影象中與任何的patch無關),所以不會造成上述問題,能夠比較公允地反映全圖的資訊。
d. Transformer encoderTransformer Encoder結構和NLP中transformer結構基本上相同,所以這裡只給出其結構圖,和公式化的計算過程,也是順便用公式表達了之前所說的幾個部分內容。
Transformer Encoder的結構如下圖所示:
Transformer Encoder結構圖
對於Encoder的第層,記其輸入為,輸出為,則計算過程為:
其中MSA為Multi-Head Self-Attention(即Transformer Encoder結構圖中的綠色框),MLP為Multi-Layer Perceptron(即Transformer Encoder結構圖中的藍色框),LN為Layer Norm(即Transformer Encoder結構圖中的黃色框)。
Encoder第一層的輸入 是透過下面的公式得到的:
其中即為Linear Projection後的patch embedding(都是維),右乘維的矩陣表示Linear Projection,得到的都是維向量;這個維向量和同樣是維向量的concat就得到了維矩陣。加上個維position embedding拼成的維矩陣,即得到了encoder的原始輸入。
3. 混合結構文中還提出了一個比較有趣的解決方案,將transformer和CNN結合,即將ResNet的中間層的feature map作為transformer的輸入。
和之前所說的將圖片分成patch然後reshape成sequence不同的是,在這種方案中,作者直接將ResNet某一層的feature map reshape成sequence,再透過Linear Projection變為Transformer輸入的維度,然後直接輸入進Transformer中。
4. Fine-tuning過程中高解析度影象的處理在Fine-tuning到下游任務時,當影象的解析度增大時(即影象的長和寬增大時),如果保持patch大小不變,得到的patch個數將增加(記解析度增大後新的patch個數為 )。但是由於在pretrain時,position embedding的個數和pretrain時分割得到的patch個數(即上文中的)相同。則多出來的個positioin embedding在pretrain中是未定義或者無意義的。
為了解決這個問題,文章中提出用2D插值的方法,基於原圖中的位置資訊,將pretrain中的個position embedding插值成個。這樣再得到個position embedding的同時也保證了position embedding的語義資訊。
5. 實驗實驗部分由於涉及到的細節較多就不具體介紹了,大家如果感興趣可以參看原文。(不得不說Google的實驗能力和鈔能力不是一般人能比的...)
主要的實驗結論在story中就已經介紹過了,這裡複製貼上一下:在中等規模的資料集上(例如ImageNet),transformer模型的表現不如ResNets;而當資料集的規模擴大,transformer模型的效果接近或者超過了目前的一些SOTA結果。
比較有趣的是,作者還做了很多其他的分析來解釋transfomer的合理性。大家如果感興趣也可以參看原文,這裡放幾張文章中的圖。