日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Transformer如何用于大规模图像识别?

發布時間:2024/3/13 编程问答 54 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Transformer如何用于大规模图像识别? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

論文鏈接:AN IMAGE IS WORTH 16X16 WORDS: TRANSFORMERS FOR IMAGE RECOGNITION AT SCALE

論文代碼:https://github.com/google-research/vision_transformer


目錄

1、Abstract and background

2、method

2.1、VISION TRANSFORMER (VIT)

2.2、FINE-TUNING AND HIGHER RESOLUTION

3、EXPERIMENTS

3.1、Setup

4、COMPARISON TO STATE OF THE ART(SOTA)

5、Pre-train data requirement

6、SCALING STUDY

7、INSPECTING VISION TRANSFORMER

8、SELF-SUPERVISION

9、conclusion


1、Abstract and background

????????Transformer架構已經成為自然語言處理中取得不錯效果,但它在計算機視覺中的應用仍然有限。在計算機視覺領域,注意力要么與卷積網絡結合使用,要么用于替換卷積網絡的某些組件,同時保持其整體結構。本文擺脫了CNN的束縛,直接將圖像分成塊序列然后輸入到Transformer中執行圖像分類任務。

將一幅圖像分割為多個patch(圖像塊),并將這些patch的線性嵌入序列作為Transformer的輸入。圖像塊與NLP中的token(單詞)的處理方式相同。然后采用有監督的方式對模型進行圖像分類訓練。

圖1、總體流程圖

?圖1總體流程圖。將圖像分割成固定大小的像素塊,線性嵌入(linear projection)每個塊,并添加位置嵌入(position embedding),并將生成的矢量序列輸入到Transformer編碼器中。為了執行分類,向序列中添加額外的可學習“分類標記”。這個視覺transformer encoder的靈感來源文獻:Attention is all you need。

文中提到在中等訓練數據集中,如果沒有采用強正則化,它的效果不如ResNet。

但是如果在大規模的數據集中訓練,就不會出現這種情況。并且將訓練好的Vit模型進行遷移訓練也可以取得很好的效果。

? ? ? ? ?在ImageNet-21k數據集或in-house JFT-300M數據集上進行預訓練時,ViT在多個圖像識別基準上接近或超過了最新水平。最佳模型在ImageNet上的精度達到88.55%,在ImageNet ReaL上的精度達到90.72%,在CIFAR-100上的精度達到94.55%,在VTAB等19項任務上的精度達到77.63%。

主要原因:Transformer?缺乏 CNN 固有的一些歸納偏差,例如:translation equivariance 和 locality。所以當訓練數據不足的情況下,效果不好。

什么是translation equivariance?(平移不變性)

具體可以參考一下面的動態圖,左邊是一張數字圖像,隨著左邊圖像中數字4的位置發生一定量的偏移,右邊特征圖的位置也發生一定量的偏移。

圖2、平移不變性

?如果還不能理解,可以再看一下面這張圖像:

????????輸入圖像 X1,顯示數字“4”,向右平移,得到輸入圖像 X2。F1 和 F2 分別是通過平移等變映射計算得到的特征圖。在這種情況下,通過將 X2 傳遞給 φ 獲得的特征圖 F2 等效于通過將相同的平移 T 應用于特征圖 F1 獲得的特征圖,該平移 T 也已應用于 X1 以獲得 X2。以上這些都是CNN所特有的。主要在于CNN中的卷積是唯一的線性和平移不變的算子。雖然卷積是平移等變的而不是不變的,但通過將卷積與空間池化算子相結合,可以在神經網絡中實現近似的平移不變性。

參考博客:https://chriswolfvision.medium.com/what-is-translation-equivariance-and-why-do-we-use-convolutions-to-get-it-6f18139d4c59

2、method

????????ViT(視覺transformer)盡可能遵循最開始的NLP中的transformer中的結構,最主要的優點就是可以開箱使用,比較方便。

2.1、VISION TRANSFORMER (VIT)

? ? ? ? 完整的ViT結構如圖1總流程圖,原始的transformer是采用1D的token序列作為輸入。

????????為了能夠處理2D圖像,將圖像 X?:格式 {H×W×C} 調整為2D的圖像塊Xp:{N×(P^2*C)},其中(H,W)是原始圖像的分辨率,C是通道數,(P,P)是每個圖像塊的分辨率,N=H*W/p^2是產生的圖像塊數量,N也是Transformer的有效輸入序列長度。

? ? ? ? Transformer所有層中使用恒定的潛在向量大小D,然后將圖像塊(patches)展平,使用可訓練的線性投影將其映射到D維(如下圖公式(1)所示),然后再將投影的輸出稱為:patch embedding

? ? ? ? 和BERT的[class] token類似,為Embedding patch序列()預先準備了一個可學習的嵌入,其在Transformer編碼器()輸出端的狀態用作圖像表示y(公式(4))。在 pre-train 和 fine-tuning 期間,將一個分類頭(head)連接到。分類頭在預訓練時由一個帶有一個隱藏層的MLP實現,在微調時由一個線性層實現。

?????????位置嵌入(position embedding)添加到 patch embedding 以保留位置信息。并且使用標準的可學習一維位置嵌入,因為使用更先進的二維感知位置嵌入帶來的顯著性能提升(附錄D.4)。生成的嵌入向量序列作為編碼器的輸入。

? ? ? ? Transformer編碼器由交替的多頭自我注意(MSA)和 MLP 塊(公式(2)、(3))層組成。在每個塊之前應用LayerNorm(LN),在每個塊之后應用殘差連接。MLP包含兩個具有GELU的非線性層。

????????Inductive bias:transformer比CNN具有更少的圖像特異性歸納偏置。在CNN中,局部性、二維鄰域結構和平移不變性被輸入到整個模型的每一層中。在ViT中,只有MLP層是局部的和平移不變的,而自注意力層(self-attention)是全局的。二維鄰域結構的使用非常少:在模型開始時,通過將圖像切割成小塊,并在微調時調整不同分辨率圖像的位置嵌入(如下所述)。除此之外,初始化時的位置嵌入沒有關于圖像塊的二維位置信息,并且圖像塊之間的所有空間關系都必須從頭開始學習。

????????Hybrid Architecture:作為原始圖像塊的替代,輸入序列可以由CNN的特征圖生成。在這個混合模型中,將圖像塊嵌入投影E(公式(1))應用于從CNN特征圖中提取的patches。patches可以具有空間大小1x1,這意味著通過簡單地展平特征圖的空間維度并投影到Transformer維度來獲得輸入序列。如上所述,添加了分類輸入嵌入和位置嵌入。

2.2、FINE-TUNING AND HIGHER RESOLUTION

????????通常,在大型數據集上預先訓練ViT,并對(較小的)下游任務進行微調。為此,我們移除預先訓練好的預測頭,并附加一個初始化為零的D×K前饋層,其中K是下游類的數量。以比訓練前更高的分辨率進行微調通常是有益的。當輸入更高分辨率的圖像時,保持patch大小不變,這會導致更大的有效序列長度。Vision Transformer可以處理任意序列長度(最多可達內存限制),但是,預先訓練的位置嵌入可能不再有意義。因此,根據預訓練位置嵌入在原始圖像中的位置,對其執行2D插值。這種分辨率調整和patch提取是將圖像2D結構的歸納偏差手動輸入到ViT中。

3、EXPERIMENTS

? ? ? ? 文中評估了ResNet、Vision Transformer(ViT)和hybrid的表征學習能力。為了理解每個模型的數據需求,對不同大小的數據集進行預訓練,并評估許多基準任務。當考慮預訓練模型的計算成本時,ViT表現非常好,以較低的預訓練成本在大多數識別基準上達到了最先進的水平。最后,使用自監督進行了一個小實驗,實驗證明自監督的ViT很有前景。

3.1、Setup

? ? ? ? DataSet:為了探索模型的可擴展性,本文使用ILSVRC-2012 ImageNet數據集,該數據集包含1k類和130萬幅圖像(下文中稱為ImageNet)。并對訓練數據集和下游任務的測試集進行去重操作。再將在這些數據集上訓練的模型轉移到幾個基準任務中:原始驗證標簽和清理后的真實標簽上的ImageNet、CIFAR-10/100、Oxford IIIT Pets和Oxford Flowers-102。對于這些數據集都采用了相應的預處理。

????????評估了19項任務VTAB分類。VTAB評估不同任務的低數據傳輸,每個任務使用1000個訓練樣例。這些任務分為三組:自然任務——如上述的基準任務、Pets、CIFAR等。專業任務——醫學和衛星圖像,以及結構化任務——需要幾何理解的任務,如定位。

這里的VTAB(Visual Task Adaptation Benchmark)是谷歌推出的“視覺領域任務自適應基準”:

VTAB 方案首先將一種算法 (A) 應用到大量獨立的常見視覺任務中。該算法可以利用上游數據進行預訓練,以生成包含視覺表征的模型。但其必須同時定義適應性策略,使用少量樣本對下游任務進行訓練,執行特定任務并返回預測模型。該算法的最終分數是它在各任務中的平均測試分數。

具體可以參考下圖:

?這里參考博客:谷歌大腦推出視覺領域任務自適應基準:VTAB_我愛計算機視覺-CSDN博客

????????Model Variants:本文將ViT配置與BERT的配置保持一致,如Table 1所示。“Base”和“Large”模型直接采用了BERT模型,本文添加了更大的“Huge”模型。下文使用簡短的符號來表示模型大小和輸入patch大小:例如,ViT-L/16表示具有16×16輸入patch大小的“Large”變體。其中transformer的序列長度與patch大小的平方成反比,因此patch越小模型的計算成本就越高。

?????????本文采用ResNet作為基線CNN,但將批量歸一化層(batch normalization)替換為組歸一化層(group normalization),并使用標準化卷積。這些修改改善了Transfer,將修改后的模型稱為“ResNet(BiT)”。

????????對于Hybirds,將中間特征圖以一個“像素”的patch大小提供給ViT。為了對不同的序列長度進行實驗,要么(i)獲取常規ResNet50的第4階段的輸出,要么(ii)移除第4階段,在第3階段放置相同數量的層(保持總層數),然后采用擴展的第3階段的輸出。選項(ii)導致序列長度延長4倍,ViT模型更費時。

????????Training & Fine-tuning:采用β1=0.9、β2=0.999、batchsize為4096的Adam對所有模型(包括Resnet)進行訓練,并應用0.1的high weight decay,這對所有模型的傳輸非常有用(Adam對Resnet的效果略好于SGD)。

????????使用線性學習率warmup和decay。對于微調,使用帶有momentum的SGD,batchsize為512,對于所有模型,請參見附錄B.1.1,如下圖所示。

?????????對于table 2中的ImageNet結果,采用更高的分辨率進行了微調:ViT-L/16為512,ViT-H/14為518,并且使用Polyak&Juditsky(1992:Acceleration of Stochastic Approximation by Averaging)的平均值,系數為0.9999。

???????????Metrics:本文展示了Few-shot和fine-tune在下游數據集的精度。微調精度在各自數據集上微調后得到提升。Few-shot精度通過解決一個正則化最小二乘回歸問題,將訓練圖像子集的(凍結)表示映射到{?1,1}^K目標向量。這個公式允許我們以封閉形式恢復精確解。雖然主要關注微調性能,但有時會使用線性Few-shot精度進行快速動態評估,因為微調成本太高。

4、COMPARISON TO STATE OF THE ART(SOTA)

? ? ? ? 本文將大的模型ViT-H/14和ViT-L/16與最先進的CNN進行比較。

????????第一個:Big Tranfer(BiT),它采用Large ResNets執行有監督的遷移學習。第二個:Noisy?student,在ImageNet和JFT300M數據集上采用半監督學習方式訓練的大型高效網絡,去除了標簽。目前,在ImageNet和BiT-L的其他數據集上,Noisy?Student是最先進的。實驗結果如table 2所示:

? ? ? ? ?從table 2中可以看出,在JFT-300M上預訓練的小模型ViT-L/16在所有任務上的效果都優于BiT-L(ResNet152×4)(在同一個數據集上訓練的),同時訓練所需的計算資源也大大減少。更大的模型ViT-H/14進一步提高了性能,尤其是在更具挑戰性的數據集上—ImageNet、CIFAR-100和VTAB。同時該模型的預訓練所需的計算量仍然大大減少。Pre-train的效率不僅受到模型架構選擇的影響,還受到其他參數的影響,例如training schedule、優化器、權重衰減等。

????????在公共ImageNet-21k數據集上預訓練的ViT-L/16模型在大多數數據集上也表現良好,同時預訓練所需的資源較少:它可以在大約30天內使用8個核心的標準云TPUv3進行訓練。

? ? ? ? Figure 2將VTAB任務分解為各自的組,并與該基準上以前的SOTA方法進行比較:BiT、VIVI(在ImageNet和Youtube上共同培訓的ResNet),以及S4L(在ImageNet上的監督加半監督學習)。在自然任務和結構化任務上,ViT-H/14的性能優于BiT-R152x4和其他方法。在specialized上,前兩個模型的性能相似。

?5、Pre-train data requirement

????????Vision Transformer在對大型JFT-300M數據集進行預訓練時表現良好。與resnet相比,視覺的歸納偏差更少,那么數據集的大小有多重要?文中進行了兩個系列的實驗。

????????首先,在大的數據集上預訓練ViT模型:ImageNet、ImageNet-21k和JFT300M。為了在較小的數據集上提高性能,選擇了三個基本的正則化參數—權重衰減、dropout和標簽平滑。

? ? ? ? ?Figure 3顯示了微調到ImageNet后的結果(其他數據集的結果如Table 5所示,微調過程中分辨率的提高提高了性能)。當在最小的數據集ImageNet上進行預訓練時,ViT大型模型的性能不如ViT基礎模型,盡管(適度)正則化。在ImageNet-21k預訓練中,他們的表現相似。只有使用JFT-300M,才能看到large models的全部好處。

?Figure 3同時展示了不同大小BiT模型跨越的區域的性能表現,BiT CNN在ImageNet上的性能優于ViT,但在更大的數據集上,ViT表現最好。

?????????其次,在9M、30M和90M的隨機子集以及完整的JFT300M數據集上訓練ViT模型。本文不會對較小的子集執行額外的正則化,并對所有設置使用相同的超參數。通過這種方式評估內在的模型屬性,而不是正則化的效果。使用early stopping,并在訓練期間打印達到的最佳驗證的準確率。為了節省計算量,采用few-shot的線性精度,而不是全微調精度。

????????Figure 4展示了結果。在較小的數據集上,Vision Transformers的計算成本比Resnet更高。例如,ViT-B/32比ResNet50稍快;它在9M子集上的性能要差得多,但在90M+子集上的性能更好。ResNet152x2和ViT-L/16也是如此。這一結果強化了一種直覺,即卷積歸納偏差對于較小的數據集是有用的,但對于較大的數據集,直接從數據中學習相關模式就足夠了,甚至是有益的。

?總的來說,ImageNet上的few-shot結果(Figure 4)以及VTAB上的低數據結果(Table 2)似乎有望實現非常低的數據傳輸。進一步分析ViT的few-shot特性是未來工作的一個令人興奮的方向。

6、SCALING STUDY

????????通過評估JFT-300M的Transfer性能,對不同的模型進行scale研究。在這種情況下,數據大小不會限制模型的性能,我們會評估每個模型的性能和預訓練成本。

????????該模型集包括:7個RESNET,R50x1、R50x2、R101x1、R152x1、R152x2,預訓練7個epoch,加上R152x2和R200x3預訓練14個epoch;6個transformer,ViT-B/32、B/16、L/32、L/16,預訓練7個epoch,加上預訓練14個epoch的L/16和H/14;5個hybirds,R50+ViT-B/32、B/16、L/32、L/16,預訓練7個epcoh,再加上R50+ViT-L/16,預訓練14個epoch(對于hybirds,模型名稱末尾的數字代表的不是patch的大小,而是ResNet主干中的總采樣率)。

????????圖5顯示了Transfer性能與總pre-training計算結果的對比。針對不同體系結構的性能與pre-training計算:transformer、resnet和hybird。在計算預算相同的情況下,Transformer的性能通常優于resnet。對于較小的patch尺寸,hybird優于transformer,但對于較大的patch,差距消失了。

Figure 5

?????????每個模型的詳細結果如表6所示。首先,transformer在性能/計算權衡方面占據主導地位。ViT使用大約2個? 4×更少的計算以達到相同的性能(平均超過5個數據集)。其次,Hybird在較小的計算預算下略優于ViT,但在較大的模型中,這種差異消失了。這個結果有點令人驚訝,因為人們可能期望卷積局部特征處理在任何大小的ViT中都能起到輔助作用。第三,transformer似乎不會在嘗試的范圍內飽和,從而推動未來的擴展工作。

?7、INSPECTING VISION TRANSFORMER

?????????為了開始理解transformer如何處理圖像數據,本文分析了它的內部表示。transformer的第一層線性地將平坦的patch投影到較低維度的空間中(公式1)。圖7(左)顯示了學習的嵌入濾波器的頂部主要組件。這些成分類似于每個patch內精細結構的低維表示的合理基函數。

????????投影后,將學習的位置嵌入添加到patch表示中。圖7(中間)展示了該模型學習在位置嵌入的相似性中對圖像內的距離進行編碼,即越近的patch往往具有更相似的位置嵌入。此外,行-列結構出現;同一行/列中的patch具有類似的嵌入。最后,對于較大的網格,正弦結構有時很明顯(附錄D)。位置嵌入學習表示2D圖像拓撲,這解釋了為什么手工制作的2D感知嵌入變體沒有提高(附錄D.4)。

????????自注意力使ViT能夠在整個圖像中整合信息,即使是在最底層。我們調查網絡在多大程度上利用了這種能力。具體來說,根據注意力權重計算圖像空間中整合信息的平均距離(圖7,右圖)。這種“注意距離”類似于CNN中的感受野大小。一些頭部關注的是已經位于最底層的大部分圖像,這表明該模型確實使用了全局集成信息的能力。其他注意頭在低層的注意距離一直很小。這種高度局部化的關注在Tranformer之前應用ResNet的hybird模型中不太明顯(圖7,右圖),這表明它可能與CNN中的早期卷積層具有類似的功能。此外,注意距離隨著網絡深度的增加而增加。在全球范圍內,我們發現該模型關注與分類語義相關的圖像區域(圖6)。

?8、SELF-SUPERVISION

????????Transformers在NLP任務中表現出色。然而,他們的成功不僅源于出色的可擴展性,還源于大規模的自我監督預訓練。本文還模擬了BERT中使用的masked patch 預測模型,對用于自我監督的masked patch預測進行了初步探索。通過自監督預訓練,對于較小的ViT-B/16模型在ImageNet上實現了79.9%的準確率,與從頭開始的訓練相比,顯著提高了2%,但仍落后于監督預訓練4%。附錄B.1.2包含更多詳細信息。

9、conclusion

? ? ? ? Transformer在圖像識別中的直接應用與以前在計算機視覺中使用自我注意的工作不同,除了最初的patch提取步驟外,沒有在體系結構中引入特定于圖像的感應偏差。相反,將圖像解釋為一系列patch,并使用NLP中使用的標準Transformer編碼器對其進行處理。這種簡單但可擴展的策略在與大型數據集的預訓練相結合取得很好的效果。因此,Vision Transformer在許多圖像分類數據集上都達到或超過了最先進的水平,同時預訓練成本相對較低。

????????雖然這些初步結果令人鼓舞,但仍存在許多挑戰。一種是將ViT應用于其他計算機視覺任務,如檢測和分割。另一個挑戰是繼續探索自監督的預訓練方法。初步實驗表明,自監督預訓練效果有所改善,但自監督預訓練與大規模監督預訓練之間仍存在較大差距。最后,進一步擴展ViT可能會提高性能。

10、代碼部分

算法總體流程圖

代碼總流程:代碼中有注釋!

注意:實際代碼并不是按照下面這個順序來的!

1、導入所需的包

import os import math import numpy as np import pickle as p import tensorflow as tf import pandas as pd from tensorflow import keras import matplotlib.pyplot as plt from tensorflow.keras import layers import tensorflow_addons as tfa %matplotlib inline # 使用GPU from tensorflow.compat.v1.keras import backend as K config = tf.compat.v1.ConfigProto() config.gpu_options.per_process_gpu_memory_fraction = 0.7 config.gpu_options.visible_device_list = "0,1" sess = tf.compat.v1.Session(config=config) K.set_session(sess)

2、打印tensorflow的版本

print("tensorflow版本:",tf.__version__) print("tensorflow地址:",tf.__path__)

3、加載訓練數據集:返回images和對應的labels

這里是cifar10數據集,同樣可以換成其他數據集。

參考博客:

from_tensor_sliceshttps://zhuanlan.zhihu.com/p/380141130

代碼如下:

def load_CIFAR_batch(filename):"""filename:對應cifar10中的5個batchreturn:獲取對應的images和對應的labels"""with open(filename,'rb') as f:# 一個樣本由標簽和圖像數據組成# (3072=32x32x3)data_dict = p.load(f,encoding='bytes')# images和對應的labelsimages= data_dict[b'data'] #10000*3072labels = data_dict[b'labels'] #10000*1# 把原始數據結構調整為: BCWHimages = images.reshape(10000,3,32,32)# tensorflow處理圖像數據的結構:BWHC# 調整數據的維度,把通道數據C移動到最后一個維度images = images.transpose(0,2,3,1)# 將list轉換成數組形式labels = np.array(labels)return images,labelsdef load_CIFAR_data(data_dir):"""data_dir:數據地址return:返回完整的數據和對應的標簽"""images_train=[]labels_train=[]for i in range(5):# 5個batch數據f = os.path.join(data_dir,'data_batch_%d'%(i+1))print('loading ',f)# 調用load_CIFAR_batch()獲得批量的圖像及其對應的標簽image_batch,label_batch = load_CIFAR_batch(f)images_train.append(image_batch)labels_train.append(label_batch)# 將所有batch合并Xtrain = np.concatenate(images_train)Ytrain = np.concatenate(labels_train)# 刪除操作del image_batch ,label_batchXtest,Ytest = load_CIFAR_batch(os.path.join(data_dir,'test_batch'))print('finished loadding CIFAR-10 data')# 返回訓練集的圖像和標簽,測試集的圖像和標簽return (Xtrain,Ytrain),(Xtest,Ytest)# 加載數據和標簽 data_dir = r'/content/transformer_classification/data/cifar-10-batches-py' (x_train,y_train),(x_test,y_test) = load_CIFAR_data(data_dir)# 將numpy數據的格式轉換為tf所需的dataset格式 train_dataset = tf.data.Dataset.from_tensor_slices((x_train,y_train)) test_dataset = tf.data.Dataset.from_tensor_slices((x_test,y_test))

4、可視化訓練數據集

# 顯示訓練集中的圖像 import matplotlib.pyplot as plt plt.imshow(x_train[8])

?

import matplotlib.pyplot as pltplt.figure(figsize=(4, 4)) image = x_train[np.random.choice(range(x_train.shape[0]))] # 32*32*3 plt.imshow(image.astype("uint8")) plt.title("origin image") plt.axis("off")# resize resized_image = tf.image.resize(tf.convert_to_tensor([image]), size=(image_size, image_size) #72*72 ) print(resized_image.shape)#(1,72,72,3)patches = Patches(patch_size)(resized_image) print(f"Image size: {image_size} X {image_size}")# 圖像大小 print(f"Patch size: {patch_size} X {patch_size}")# patch塊的大小 print(f"Patches per image: {patches.shape[1]}") # 一張圖總共有多少patches,72/6**2=12*12=144 print(f"Elements per patch: {patches.shape[-1]}") # 108一個patch包含的像素個數 print(f"patches shapes:{patches.shape}") # (1,144,108)n = int(np.sqrt(patches.shape[1])) print(n) # 12=72/6 plt.figure(figsize=(4, 4))for i, patch in enumerate(patches[0]):ax = plt.subplot(n, n, i + 1)patch_img = tf.reshape(patch, (patch_size, patch_size, 3))plt.imshow(patch_img.numpy().astype("uint8"))plt.axis("off")

?5、數據增強模塊

data_augmentation = keras.Sequential([layers.experimental.preprocessing.Normalization(), #歸一化layers.experimental.preprocessing.Resizing(image_size, image_size),#調整圖像尺寸layers.experimental.preprocessing.RandomFlip("horizontal"),#隨機水平翻轉layers.experimental.preprocessing.RandomRotation(factor=0.02),#旋轉layers.experimental.preprocessing.RandomZoom(height_factor=0.2,width_factor=0.2)#隨機調整圖像大小],name="data_augmentation", ) print(data_augmentation) # 使預處理層的狀態與正在傳遞的數據相匹配 # 計算訓練數據集的均值和方差 print(data_augmentation.layers[0].adapt(x_train))

6、模型搭建

num_classes = 10 input_shape = (32, 32, 3)learning_rate = 0.001 weight_decay = 0.0001 batch_size = 128 num_epochs = 10 image_size = 72 # 調整的圖像大小 patch_size = 6 # transformer中的圖像patches num_patches = (image_size // patch_size) ** 2 # 一張圖根據patches的大小計算總的個數 projection_dim = 64 # projection num_heads = 4 # head transformer_units = [projection_dim * 2,projection_dim, ] # Size of the transformer layers transformer_layers = 8 mlp_head_units = [2048, 1024] # Size of the dense layers of the final classifierdef mlp(x, hidden_units, dropout_rate):# 多層感知機"""hidden_unints:隱藏層個數dropout_rate:設置對應的個數"""for units in hidden_units:# mlp_head_unitsx = layers.Dense(units, activation=tf.nn.gelu)(x)x = layers.Dropout(dropout_rate)(x)return x# patchs類別 class Patches(layers.Layer):def __init__(self, patch_size):# patch_size:圖像塊的大小,不同的設置會得到不同的圖像塊數量super(Patches, self).__init__()self.patch_size = patch_sizedef call(self, images):# 圖像的Wbatch_size = tf.shape(images)[0]# 提取圖像并劃分為多個圖像子塊# 參考博客:https://blog.csdn.net/weixin_43935696/article/details/117694657# 返回的是:返回4維tensor,數據類型與輸入的images類型相同patches = tf.image.extract_patches(images=images,# 這個必須滿足[batch, in_rows, in_cols, depth]sizes=[1, self.patch_size, self.patch_size, 1],# patch的大小,[1, size_rows, size_cols, 1]strides=[1, self.patch_size, self.patch_size, 1],# patch的移動步長[1, stride_rows, stride_cols, 1]rates=[1, 1, 1, 1],# [1, rate_rows, rate_cols, 1],表示隔幾個像素點,取一個像素點,直到滿足sizes padding="VALID",# 表示所取的patch區域必須完全包含在原始圖像中.還有一種是"same"是對超出的圖像部分通過補0實現)patch_dims = patches.shape[-1] # 返回最后一個維度patches = tf.reshape(patches, [batch_size, -1, patch_dims])return patchesclass PatchEncoder(layers.Layer):def __init__(self, num_patches, projection_dim):super(PatchEncoder, self).__init__()self.num_patches = num_patches#一個全連接層,其輸出維度為projection_dim,沒有指明激活函數self.projection = layers.Dense(units=projection_dim)#定義一個嵌入層,這是一個可學習的層#輸入維度為num_patches,輸出維度為projection_dimself.position_embedding = layers.Embedding(input_dim=num_patches, output_dim=projection_dim)def call(self, patch):# start->limit(不包括這個),增量為1positions = tf.range(start=0, limit=self.num_patches, delta=1)# patch + position_embeddingencoded = self.projection(patch) + self.position_embedding(positions)return encoded

7、訓練

def create_vit_classifier():inputs = layers.Input(shape=input_shape)# 數據增強augmented = data_augmentation(inputs)# 創建圖像的patches.patches = Patches(patch_size)(augmented)# 對上述創建的patches進行編碼encoded_patches = PatchEncoder(num_patches, projection_dim)(patches)# Create multiple layers of the Transformer block.# 創建transformer塊的多個層# _表示一個占位符,表示不在意使用這個值,只是用于循環for _ in range(transformer_layers):# 對應總流程中的Normx1 = layers.LayerNormalization(epsilon=1e-6)(encoded_patches)# 創建一個多頭注意力層attention_output = layers.MultiHeadAttention(num_heads=num_heads, key_dim=projection_dim, dropout=0.1)(x1, x1)# Skip connection:對應transformer塊中的第一個加號x2 = layers.Add()([attention_output, encoded_patches])# 對應第二個Normx3 = layers.LayerNormalization(epsilon=1e-6)(x2)# MLP.x3 = mlp(x3, hidden_units=transformer_units, dropout_rate=0.1)# Skip connection 2.encoded_patches = layers.Add()([x3, x2])# Create a [batch_size, projection_dim] tensor.representation = layers.LayerNormalization(epsilon=1e-6)(encoded_patches)representation = layers.Flatten()(representation)representation = layers.Dropout(0.5)(representation)# Add MLP.features = mlp(representation, hidden_units=mlp_head_units, dropout_rate=0.5)# Classify outputs:這個參數對應的是數據集中的類別數logits = layers.Dense(num_classes)(features)# 采用keras中的Model進行封裝model = keras.Model(inputs=inputs, outputs=logits)return modeldef run_experiment(model):optimizer = tfa.optimizers.AdamW(learning_rate=learning_rate, weight_decay=weight_decay)model.compile(optimizer=optimizer,loss=keras.losses.SparseCategoricalCrossentropy(from_logits=True),metrics=[keras.metrics.SparseCategoricalAccuracy(name="accuracy"),# 稀疏情況的分類準確率keras.metrics.SparseTopKCategoricalAccuracy(5, name="top-5-accuracy"),],)#checkpoint_filepath = r".\tmp\checkpoint"checkpoint_filepath ="model_bak.hdf5"# 查看訓練模型的狀態checkpoint_callback = keras.callbacks.ModelCheckpoint(checkpoint_filepath,monitor="val_accuracy",save_best_only=True,save_weights_only=True,)# tensorflow提供的可視化工具# usage:tensorboard --logdir=/logstensorboard_callback = keras.callbacks.TensorBoard(log_dir='./logs',#日志文件名histogram_freq=0,#0表示不計算直方圖batch_size=32,write_graph=True,# 是否可視化圖像write_grads=False,# 是否在 TensorBoard 中可視化梯度值直方圖,前提是histogram_freq必須大于0write_images=False, #是否在 TensorBoard 中將模型權重以圖片可視化embeddings_freq=0, embeddings_layer_names=None, #被選中的嵌入層會被保存的頻率(在訓練輪中)embeddings_metadata=None, #一個字典,對應層的名字到保存有這個嵌入層元數據文件的名字。embeddings_data=None, #要嵌入在 embeddings_layer_names 指定的層的數據。update_freq='epoch')history = model.fit(x=x_train,y=y_train,batch_size=batch_size,epochs=num_epochs,validation_split=0.1, # 直接采用訓練集中的一部分數據作為驗證集callbacks=[checkpoint_callback],)# 加載訓練好的模型用于評估model.load_weights(checkpoint_filepath)_, accuracy, top_5_accuracy = model.evaluate(x_test, y_test)print(f"Test accuracy: {round(accuracy * 100, 2)}%")print(f"Test top 5 accuracy: {round(top_5_accuracy * 100, 2)}%")return historyvit_classifier = create_vit_classifier() history = run_experiment(vit_classifier)acc = history.history['accuracy'] val_acc = history.history['val_accuracy']loss = history.history['loss'] val_loss =history.history['val_loss']plt.figure(figsize=(8, 8)) plt.subplot(2, 1, 1) plt.plot(acc, label='Training Accuracy') plt.plot(val_acc, label='Validation Accuracy') plt.legend(loc='lower right') plt.ylabel('Accuracy') plt.ylim([min(plt.ylim()),1.1]) plt.title('Training and Validation Accuracy')plt.subplot(2, 1, 2) plt.plot(loss, label='Training Loss') plt.plot(val_loss, label='Validation Loss') plt.legend(loc='upper right') plt.ylabel('Cross Entropy') plt.ylim([-0.1,4.0]) plt.title('Training and Validation Loss') plt.xlabel('epoch') plt.show()

?

總結

以上是生活随笔為你收集整理的Transformer如何用于大规模图像识别?的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。