這篇文章很是重要,我的認爲應該算是cv領域裏面的自注意力機制的核心文章,語義分割裏面引入的各類自注意力機制其實均可以認爲是本文的特殊化例子。分析本文的意義不只僅是熟悉本文,而是瞭解其泛化思想。git
無論是cv仍是NLP任務,都須要捕獲長範圍依賴。在時序任務中,RNN操做是一種主要的捕獲長範圍依賴手段,而在CNN中是經過堆疊多個卷積模塊來造成大感覺野。目前的卷積和循環算子都是在空間和時間上的局部操做,長範圍依賴捕獲是經過重複堆疊,而且反向傳播獲得,存在3個不足:github
(1) 捕獲長範圍依賴的效率過低;網絡
(2) 因爲網絡很深,須要當心的設計模塊和梯度;架構
(3) 當須要在比較遠位置之間來回傳遞消息時,這是局部操做是困難的.app
故做者基於圖片濾波領域的非局部均值濾波操做思想,提出了一個泛化、簡單、可直接嵌入到當前網絡的非局部操做算子,能夠捕獲時間(一維時序信號)、空間(圖片)和時空(視頻序列)的長範圍依賴。這樣設計的好處是:dom
(1) 相比較於不斷堆疊卷積和RNN算子,非局部操做直接計算兩個位置(能夠是時間位置、空間位置和時空位置)之間的關係便可快速捕獲長範圍依賴,可是會忽略其歐式距離,這種計算方法其實就是求自相關矩陣,只不過是泛化的自相關矩陣ide
(2) 非局部操做計算效率很高,要達到同等效果,只須要更少的堆疊層函數
(3) 非局部操做能夠保證輸入尺度和輸出尺度不變,這種設計能夠很容易嵌入到目前的網絡架構中。性能
因爲我主要作2d圖片的CV需求,故本文的大部分分析都是針對圖片而言,而不是時間序列或者視頻序列。學習
本文的非局部操做算子是基於非局部均值操做而提出的,故頗有必要解釋下非局部均值操做。咱們在CNN或者傳統圖片濾波算子中涉及的都是局部操做,例如Sobel算子,均值濾波算子等等,其計算示意圖以下:
能夠看出每一個位置的輸出值都是kernel和輸入的局部卷積計算獲得的,而非局部均值濾波操做是: computes a weighted mean of all pixels in an image,很是簡單。核心思想是在計算每一個像素位置輸出時候,再也不只和鄰域計算,而是和圖像中全部位置計算相關性,而後將相關性做爲一個權重表徵其餘位置和當前待計算位置的類似度。能夠簡單認爲採用了一個和原圖同樣大的kernel進行卷積計算。下圖表示了高斯濾波,雙邊濾波和非局部均值處理過程:
能夠看出對於待計算的中心紅色點,前兩種局部操做都是在鄰域計算,而非局部均值是和整個圖片進行計算的。可是實際上若是採用逐點計算方式,不只計算速度很是慢,並且抗干擾能力不太好,故非局部均值操做是採用Block的思想,計算block和block之間的相關性。
能夠看出,待計算的像素位置是p,故先構造block,而後計算其餘位置block和當前block的相關性,能夠看出q1和q2區域和q很是類似,故計算時候給予一個大權重,而q3給予一個小的權重。這樣的作法能夠突出共性(關心的區域),消除差別(一般是噪聲)。
上面的全部分析都是基於非局部操做來說的,可是實際上在深度學習時代,能夠歸爲自注意力機制Self-attention。在機器翻譯中,自我注意模塊經過關注全部位置並在嵌入空間中取其加權平均值來計算序列(例如,句子)中的位置處的響應,在CV中那就是經過關注圖片中(能夠是特徵圖)全部位置並在嵌入空間中取其加權平均值來表示圖片中某位置處的響應。嵌入空間能夠認爲是一個更抽象的圖片空間表達,目的是匯聚更多的信息,提升計算效率。聽起來很是高級的樣子,到後面能夠看出,是很是簡單的。
下面開始給出非局部操做的具體公式。首先在深度學習中非局部操做能夠表達爲:
i是輸出特徵圖的其中一個位置,通用來講這個位置能夠是時間、空間和時空。j是全部可能位置的索引,x是輸入信號,能夠是圖像、序列和視頻,一般是特徵圖。y是和x尺度同樣的輸出圖,f是配對計算函數,計算第i個位置和其餘全部位置的相關性,g是一元輸入函數,目的是進行信息變換,C(x)是歸一化函數,保證變換先後總體信息不變。以上是一個很是泛化的公式,具體細節見下面。在局部卷積算子中,通常的
因爲f和g都是通式,故結合神經網絡特定,須要考慮其具體形式。
首先g因爲是一元輸出,比較簡單,我能夠採用1x1卷積,表明線性嵌入,其形式爲:
對於f,前面咱們說過其實就是計算兩個位置的相關性,那麼第一個很是天然的函數是Gaussian。
(1) Gaussian
對兩個位置進行點乘,而後經過指數映射,放大差別。
(2) Embedded Gaussian
前面的gaussian形式是直接在當前空間計算,而(2)更加通用,在嵌入空間中計算高斯距離。這裏:
前面兩個:
仔細觀察,若是把C(x)考慮進去,那麼
其實就是softmax形式,完整考慮是:
這個就是目前經常使用的位置注意力機制的表達式,因此說語義分割中大部分通道注意力機制都是本文的特殊化。
(3) Dot product
考慮一種最簡單的非局部操做形式:
其中C(x)=N,像素個數。能夠看出(2) (3)的主要區別是是否含有激活函數softmax。
(4) Concatenation
參考 Relation Networks能夠提出:
前面是基本的非局部操做算子,利用這些算子,下面開始構形成模塊。
能夠看出,上面構形成了殘差形式。上面的作法的好處是能夠隨意嵌入到任何一個預訓練好的網絡中,由於只要設置W_z初始化爲0,那麼就沒有任何影響,而後在遷移學習中學習新的權重。這樣就不會由於引入了新的模塊而致使預訓練權重沒法使用。
下面結合具體實例分析:
因爲咱們考慮的是圖片,故能夠直接設置T=1,或者說不存在。首先網絡輸入是X= (batch, h, w, 1024) ,通過Embedded Gaussian中的兩個嵌入權重變換 ,
獲得(batch, h, w, 512), (batch, h, w, 512), 其實這裏的目的是下降通道數,減小計算量;而後分別對這兩個輸出進行reshape操做,變成(batch, hw, 512),後對這兩個輸出進行矩陣乘(其中一個要轉置),計算類似性,獲得(batch, hw, hw),
而後在第2個維度即最後一個維度上進行softmax操做,獲得(batch, hw, hw), 意這樣作就是通道注意力,至關於找到了當前圖片或特徵圖中每一個像素與其餘全部位置像素的歸一化相關性;而後將g也採用同樣的操做,先通道降維,而後reshape;而後和 (batch, hw, hw)進行矩陣乘,獲得(batch, h, w, 512), 即將通道注意力機制應用到了全部通道的每張特徵圖對應位置上,本質就是輸出的每一個位置值都是其餘全部位置的加權平均值,經過softmax操做能夠進一步突出共性。最後通過一個1x1卷積恢復輸出通道,保證輸入輸出尺度徹底相同。
拷貝的代碼來源:https://github.com/AlexHex7/Non-local_pytorch
能夠看出,具體實現很是簡單,就不細說了。
通讀全文,你會發現思路很是清晰,模塊也很是簡單。其背後的思想實際上是自注意力機制的泛化表達,準確來講本文只提到了位置注意力機制(要計算位置和位置之間的相關性,辦法很是多)。
我的認爲:若是這些自注意模塊的計算開銷優化的很小,那麼應該會成爲CNN的基礎模塊。既然位置和位置直接的相關性那麼重要,那我是否是能夠認爲graph CNN纔是將來?由於圖卷積網絡是基於像素點和像素點之間建模,二者之間的權重是學習到的,性能確定比這種自監督方式更好,後面我會寫文章分析。
本文設計的模塊依然存在如下的不足:
(1) 只涉及到了位置注意力模塊,而沒有涉及經常使用的通道注意力機制
(2) 能夠看出若是特徵圖較大,那麼兩個(batch,hxw,512)矩陣乘是很是耗內存和計算量的,也就是說當輸入特徵圖很大存在效率底下問題,雖然有其餘辦法解決例如縮放尺度,可是這樣會損失信息,不是最佳處理辦法。
Non-local Blocks的高效策略。咱們設置Wg,Wθ,Wϕ的channel的數目爲x的channel數目的一半,這樣就造成了一個bottleneck,可以減小一半的計算量。Wz再從新放大到x的channel數目,保證輸入輸出維度一致。
還有一個subsampling的trick能夠進一步使用,就是將(1)式變爲:yi=1C(x^)∑∀jf(xi,x^j)g(x^j),其中x^是x下采樣獲得的(好比經過pooling),咱們將這個方式在空間域上使用,能夠減少1/4的pairwise function的計算量。這個trick並不會改變non-local的行爲,而是使計算更加稀疏了。這個能夠經過在圖2中的ϕ和g後面增長一個max pooling層實現。
咱們在本文中的全部non-local模塊中都使用了上述的高效策略。
爲了理解non-local networks的操做,咱們在視頻分類任務上進行了一系列的ablation experiments。
2D ConvNet baseline (C2D)。爲了獨立開non-local nets中時間維度的影響vs 3D ConvNets,咱們構造了一個簡單的2D baseline結構。
Table 1給出了ResNet-50 C2D backbone。輸入的video clip是32幀,大小爲224*224。Table 1中的全部卷積都是用的2D的kernel,即逐幀對輸入視頻進行計算。惟一和temporal有關的計算就是pooling,也就是說這個baseline模型簡單地在時間維度上作了一個聚合的操做。
Inflated 3D ConvNet (I3D)。 Table 1中的C2D模型能夠經過inflate的操做轉換成一個3D卷積的結構。具體地,一個2D k*k大小的kernel能夠inflate成3D t*k*k大小的kernel,只要將其權重重複t次,再縮小t倍便可。
咱們討論2種inflate的方式。一種是將residual block中的3*3的kernel inflate成3*3*3的,另外一種是將residual block中的1*1的kernel inflate成3*1*1的。這兩種形式咱們分別用I3D3∗3∗3和I3D3∗1∗1表示。由於3D conv的計算量很大,咱們只對每2個residual blocks中的1個kernel作inflate。對更多的kernel作inflate發現效果反而變差了。另外conv1層咱們inflate成5*7*7。
Non-local network。 咱們將non-local block插入到C2D或I3D中,就獲得了non-local nets。咱們研究了插入1,5,10個non-local blocks的狀況,實現細節將在後面給出。
Training。 咱們的模型是在ImageNet上pretrain的,沒有特殊說明的話咱們使用32幀的輸入。32幀是經過從原始長度的視頻中隨機選擇1個位置取出64個連續幀,而後每隔1幀取1幀獲得的最終的32幀。spatial size是224*224大小,是將原始視頻rescale到短邊爲[256,320]區間的隨機值,而後再random crop 224*224大小。咱們在8卡GPU上進行訓練,每卡上有8 clips(也就是說總的batchsize是64 clips)。咱們一共迭代了400k iterations,初始lr爲0.01,而後每150k iterations lr降低1/10。momentum設爲0.9,weight decay設爲0.0001。dropout在global pooling層後面使用,dropout ratio設爲0.5。
咱們finetune模型的時候 BN是打開的,這和常見的finetune ResNet的操做不一樣,它們一般是frozen BN。咱們發如今咱們的實驗中enable BN有利於減小過擬合。
在最後一個1*1*1 conv層(表示Wz)的後面咱們加了一個BN層,其餘位置咱們沒有增長BN。這個BN層的scale參數初始化爲0,這是爲了保證整個non-local block的初始狀態至關於一個identity mapping,這樣插入到任何預訓練網絡中在一開始都能保持其原來的表現。
Inference。 推理時,在咱們將視頻rescale到短邊256進行推理。時域上咱們從整個視頻中平均採樣10個clip,而後分別計算他們的softmax scores,最後作平均獲得整個視頻的score。
關於視頻分類的實驗,咱們在Kinetics上進行全面的實驗,另外也給出了Charades上的實驗結果,顯示出咱們的模型的泛化性。這裏只給出Kinetics上的結果,更多的請看原文。
Table 2給出了ablation results。
f的表現形式的影響。表2a比較了不一樣的non-local block的形式插入到C2D獲得的結果(插入位置在res4的最後一個residual block以前)。發現即便只加一個non-local block都能獲得~1%的提升。
有意思的是不一樣的non-local block的形式效果差很少,說明是non-local block的結構在起做用,而對具體的表達方式不敏感。本文後面都採用embedded Gaussian進行實驗,由於這個版本有softmax,能夠直接給出[0,1]之間的scores。
哪一個階段加入non-local blocks?表2b比較了一個non-local block加在resnet的不一樣stage的效果,具體加在不一樣stage的最後一個residual block以前。發如今res2,res3,res4層上加non-local block效果相似,加在res5上效果稍差。這個的可能緣由是res5的spatial size比較小,只有7*7,可能沒法提供精確的spatial信息了。
加入更多的non-local blocks。表2c給出了加入更多non-local block的結果,咱們在resnet-50上加1 block(在res4),加5 block(3個在res4,2個在res3,每隔1個residual block加1個non-local block),加10 block(在res3和res4每一個residual block都加non-local block)。在resnet101的相同位置加block。發現更多non-local block一般有更好的結果。咱們認爲這是由於更多的non-local block可以捕獲長距離屢次轉接的依賴。信息能夠在時空域上距離較遠的位置上進行來回傳遞,這是經過local models沒法實現的。
另外須要提到的是增長non-local block獲得的性能提高並不僅是由於它給base model增長了深度。爲了說明這一點,表2c中resnet50 5blocks可以達到73.8的acc,而resnet101 baseline是73.1,同時resnet50 5block只有resnet101的約70%的參數量和80%的FLOPs。說明non-local block獲得的性能提高並不僅是由於它增長了深度。
時空域上作non-local。咱們的方法也能夠處理時空域的信息,這一特性很是好,在視頻中相關的物體可能出如今較遠的空間和較長的時間,它們的相關性也能夠被咱們的模型捕獲。表2d給出了在時間維度,空間維度和時空維度分別作non-local的結果。僅在空間維度上作就至關於non-local的依賴僅在單幀圖像內部發生,也就是說在式(1)上僅對index i的相同幀的index j作累加。僅在時間維度上作也相似。表2d顯示只作時間維度或者只作空間維度的non-local,都比C2D baseline要好,可是沒有同時作時空維度的效果好。
Non-local net vs. 3D ConvNet。表2e比較了咱們的non-local C2D版本和inflated 3D ConvNets的性能。Non-local的操做和3D conv的操做能夠當作是將C2D推廣到時間維度的兩種方式。
表2e也比較了param的數量,FLOPs等。咱們的non-local C2D模型比I3D更加精確(75.1 vs 74.4),而且有更小的FLOPs(1.2x vs 1.5x)。說明單獨使用時non-local比3D conv更高效。
Non-local 3D ConvNet. 無論上面的比較,其實non-local操做和3D conv各有各的優勢:3D conv能夠對局部依賴進行建模。表2f給出了在I3D3∗1∗1上插入5個non-local blocks的結果。發現NL I3D都可以在I3D的基礎上提高1.6個點的acc,說明了non-local和3D conv是能夠相互補充的。
更長的輸入序列。 最後咱們也實驗了更長輸入序列的狀況下模型的泛化性。輸入clip包含128幀連續幀,沒有作下采樣,是通常狀況下取的32幀的4倍長度。爲了將這個模型放入顯存中,每一個GPU上只能放下2 clips。由於這麼小的batchsize的緣由,咱們freeze全部的BN層。咱們從32幀訓練獲得的模型做爲初始化模型,而後用128幀進行finetune,使用相同的iterations數目(雖然batchsize減少了),初始lr爲0.0025,其餘設置和以前保持一致。
表2g給出了128幀的實驗結果,和表2f的32幀的結果相比,全部模型都表現得更好,說明咱們的模型在長序列上的效果也很好。
和state-of-the-art的比較。表3給出了Kinetics上各個方法的結果。
https://www.jianshu.com/p/a9771abedf50
https://blog.csdn.net/u010158659/article/details/78635219