關於resnet的直覺性解釋

resnet爲什麼能夠這麼深,而性能不發生退化,確實是一件百思不得其解的現象。而最近我終於明白了裏面的深層次的原因。

根本原因是,不用殘差的模型本質上是在將feature在空間中線性變換,然後進行裁剪,如此可將不同的feature映射爲同一個值,發生了坍縮現象,本應不同類別的feature非線性變換爲同一個feature值,從而造成信息丟失,造成欠擬合的現象。那麼爲什麼resnet沒有發生這種情況呢?甚至網絡越深,resnet性能越好。

爲了解釋這個現象,首先讓我們玩一個推箱子的遊戲。

這個遊戲的內容如下:

在二維平面上,有四個箱子,其中兩個爲紅色,記box1,box2,另外兩個爲藍色box3,box4。紅色的其中一個分佈在第一象限,另外一個分佈在第三象限。藍色的其中一個分佈在第二象限,另外一個分佈在第四象限。你可以進行的操作是可以選擇任意一個箱子向任何方向移動一。遊戲的目標是經過不停地移動,使得紅色的箱子在第一象限,藍色的箱子在第三項象限。

這個遊戲的機器學習含義顯而易見,就是一個異或分類。這個遊戲雖然簡單,但事實上,resnet就是在玩這個遊戲。下面具體解釋。

如果在這個遊戲中要進行操作,很明顯,首先要選定一個箱子,然後移動它。假定選定函數爲f(box),移動距離爲offset=(x,y)。比如要將box1移動(1,2)個距離,則

f(box)=1當box=box1; f(box)=0當box!=box1,

offset的值爲(1,2)。

所以這樣一個操作使得

coordinate(box)=coordinate(box)+f(box)*offset。

整個遊戲的操作序列是(f1,offset1),(f2,offset2),(f3,offset3).....

如果要玩這個遊戲,最終要優化的模型是:

box-state1=box-state+f1(box-state)*offset1

box-state2=box-state+f2(box-state1)*offset2

box-state3=box-state+f3(box-state2)*offset3

....

box-staten=fn(box-staten-1)+offsetn

loss函數是使得box-staten爲,紅色的箱子在第一象限,藍色的箱子在第三象限。

可以看出每一個步驟並沒有使得信息有所損失,這纔是resnet的關鍵所在。沒有殘差的網絡是有信息損失的。而resnet完全沒有。

如果,聰明的話,你可以發現,爲什麼要限定每一個步驟中只移動一次呢?每一個步驟我可以移動多次。比方說每一個步驟,我移動2次。

則新的移動函數爲

coordinate(box)=coordinate(box)+f1(box)乘offset1+f2(box)乘offset2

則新的模型變成了

box-state1=box-state+f1(box-state)*offset1+f2(box-state)*offset2

box-state2=box-state+f3(box-state1)*offset3+f4(box-state1)*offset4

box-state3=box-state+f5(box-state2)*offset5+f6(box-state2)*offset3

....

box-staten=box-staten-1+f2n-1(box-staten-1)*offset2n-1+f2n(box-staten-1)*offset2n

loss函數是使得box-staten爲,紅色的箱子在第一象限,藍色的箱子在第三象限。

這個模型如此熟悉,完全可以轉化爲神經網絡語言模型。

如果把每個box理解爲訓練對象的feature,顏色理解爲類別,可以將上面的模型轉化爲一個神經網絡模型。每個box-statei相當於網絡的一層,比方說上面就一共n層。每一層的輸出維度,就是在一層中移動了多少次。比方說inputs爲36維的向量,輸出維度爲72維。就是將36維的箱子移動了72次。

根據上面類比,可以用python語言構建一個神經網絡分類器。

inputs:feature,爲2維向量。

第一層,使用3個分類器對feature進行二分類。假設feature的3次分類結果爲c=[c1,...c3],則第一層的分類輸出爲

outputs=feature+c1 乘offset1+c2乘offset2+c3乘offset3.

其中offset3爲2維向量。

到現在就非常清楚了,如果我假設

offset1=[1,0,0],offset2=[0,1,0],offset3=[0,0,1],

是固定的參數,而非能學習的參數,此時

feature=feature+[c1,c2,c3],

立即可以得到resnet的殘差形式。

所以resnet就是在幹這樣一件事情,每一個殘差塊就是,對於n維的向量,根據[0,0,...,1,0,...,0],做一次決策,決定該向量是否應該執行該移動,共做n次決策。

那爲什麼resnet的性能與層數沒什麼關係呢。因爲每一層做的移動決策完全可以放在下一層做,下一層的移動決策完全可以放在上一層做。就好像移動箱子的遊戲。我可以在一個步驟中移動多次箱子,也可以多個步驟移動一次箱子,有什麼區別呢?事實上,性能只跟做決策的次數有關係,做的決策越多,效果越好。

事實上即便resnet也不過是偶然的產物,真正解決深度問題的模型應當是上面的模型。

1.首先分類器不應該用relu激活,應該用sigmoid激活,否則不是線性移動,會產生偏差,很有可能造成信息丟失。

2.其次不應當假設offset爲固定參數,應該設有專門的offset變量來進行學習。

3.最後對n維特徵向量,每個殘差塊,不僅僅只能做n次決策,事實上可以做任意次決策。

4.上面的模型給出了一種不基於梯度訓練神經網絡的可能。也就是說可能存在類似於訓練決策樹的訓練算法來訓練神經網絡。並且這種訓練方式是可擴展的,也就是說隨時可以增加新的神經元來解決新的問題。

5.殘差中分類器個數與性能的關係。雖然保證了信息的無損失,但是這並不代表模型可以取得高性能。因爲神經網絡權重是隨機採樣,而採樣密度直接決定了模型的性能。假設第一個殘差塊的分類器個數是n,第二個殘差塊的分類器個數是n.則對空間的劃分個數是2^n+2^n.如果分類器個數是2n,則對空間的劃分個數是2^(2n)。可以看出2^(n+1)遠小於2^(2n)。也就是說,分類器個數與性能的關係並不是簡單的加法關係.

6.將最後的offset變量全部初始化爲0(也就是殘差的最後一層升維卷積層的權重全設置爲0),整個網絡仍可訓練。

事實上,因爲上面的實現差異,resnet也無法避免欠擬合的問題,在文本檢測的數據集上,用resnet直接訓練,不用預訓練模型,效果遠遠比不上vgg。說明resnet仍然避免不了信息丟失的情況。

最後給出上面意義上的深度學習殘差公式:

假設

inputs的shape爲[N,H,W,C],

分類結果class=tf.nn.sigmoid(conv(inputs)),shape爲[N,H,W,C1],分類器可以用任意可梯度傳導的模型,不必限於線性模型。

創建offset變量,shape爲[C1,C]

殘差公式爲:

class=tf.reshape(class,[N H W,C1])

offset=tf.matmul(class,offset)

offset=tf.reshape(offset,[N,H,W,C])

outputs=inputs+offset

當C1=C,offset爲單位矩陣,激活函數爲relu時,退化爲resnet網絡。

 

補充:

上面的推導是基於resnet的殘差分支的最後一層是被激活的。如果最後一層沒有被激活,則與選定-移動模型完全等價。此時殘差分支的倒數第二層的輸出是選定結果,最後一層的權重是移動參數offset。

但是resnet有兩個非常嚴重的問題。

第一,因爲只是在做平移變換,如果需要學習旋轉變換就有問題了。即便能做到在數據集上過擬合,也只是用平移變換模擬旋轉變換,不具備泛化能力。理論上,應該學習仿射變換,而不僅僅是平移變換,但是仿射變換參數量爆炸,一個比較好的選擇是學習鏡像變換。理論上可以證明連續的鏡像變換複合可以組成任意不變性操作。

第二,對於取值範圍爲無窮的異或問題,resnet無法解決。resnet只能解決取值範圍有界的異或問題。但是用鏡像變換取代平移變換就可以解決取值範圍爲無窮的異或問題。但是我在cifar100上測試,用鏡像變換的測試集結果低於用平移變換的測試集結果,但是訓練集結果差不多。不知道爲什麼。

其次,如果聰明的話,可以發現作弊的技巧。完全可以創建新的維度,然後在新的維度上進行移動,這就是densenet。

最後,假設激活函數爲relu函數,可以根據這個模型創建一個不受internal corivate shift(ICS)影響的改進版resnet,不受died neuron影響.具體殘差公式如下:

input爲輸入。

output=tf.matmul(OFFSET,tf.nn.relu(tf.matmul(W,input))+tf.matmul(-OFFSET,tf.nn.relu(-tf.matmul(W,input))。

OFFSET爲移動矩陣,W爲選擇矩陣。該殘差公式具有明確的意義。如果x被選中,則將其移動offset距離;如果沒被選中,則將其移動-offset距離。該殘差函數不存在死亡神經元。所以不受ICS的影響。所以不用BN,也能正常訓練,不過需要控制好方差。在具體實驗過程中,發現resnet如果使用leaky_relu激活,也不會受ICS的影響;但是如果VGG使用leaky_relu激活,仍然會受ICS影響。不過總的來說,我覺得使用上面的殘差公式比leaky_relu好一些。畢竟激活函數的導數在全值域上的絕對值都爲1.

下面討論殘差函數與配對函數的關係,以及怎麼設計殘差函數。

配對函數是指三個函數f,f1,f2有如下性質:

1.如果f(a,v)=z,f1(z)=a,f2(z)=v

2.如果a1!=a2,則f(a1,v1)!=f(a2,v2),對於任意v1,v2

3.如果v1!=v2,則f(a1,v1)!=f(a2,v2),對於任意a1,a2

形象化來說,如果n個不同的特徵向量ai具備相同的label v,如果存在一個函數f,f2,使得如果ai!=aj,則f(ai,v)!=f(aj,v)。並且f2(f(ai,v))=v,此時可以說將共性特徵v編碼到了這n個向量中,並且存在解碼函數,解碼出共性特徵。這樣的函數可以使得信息無損失,並且使得具備相同label的特徵向量具備共性特徵。

理論上來說,如果特徵向量集合A={a1,a2,a3..}具備共性特徵向量v.如果存在某個函數f和反解碼函數f1,f2,使得f(a,v)=a',f1(a')=a,f2(a')=v。並且如果a1!=a2,必有f(a1,v)!=f(a2,v),那麼該函數可以作爲殘差函數。

最完美的模型是f(a,v)函數完全爲配對函數。但是理論上不可能實現。但是如果約束A空間和V空間,事實上還是可能達到完全配對函數的效果。不過需要時間去尋找這樣的約束和配對函數。不過,我們可以假設這樣的配對函數存在,設爲f,f1,f2,看看會發生什麼有趣的事情。

inputs爲輸入向量.

第一步:

假設殘差輸出爲res=convolution(inputs)

使用f進行編碼outputs1=f(inputs,res)

第二步:

outputs1作爲第二次殘差卷積的輸入

使用f1,和f2對ouputs解碼得,source=f1(outputs1),res=f2(outputs1)

source2=convolution(source)

res2=convolution(res2)

res2=source2*res2#該乘法具有實際意義,首先在res2空間分類,然後根據分類結果再在source空間中分類。可以想一想densenet。

使用f進行編碼,outputs2=f(source,res2)

依次類推。

會發現整個殘差模塊的函數形式爲:

outputs=f(f1(inputs),convolution(f1(inputs),f2(inputs)))

因爲如果輸入不同,則編碼結果肯定不同,所以劃分不必一定要還原出原空間,可以直接在編碼空間中劃分,所以假定f1爲恆等函數,

此時outputs=f(inputs,convolution(inputs,f2(inputs)),可以看出天然具備跨層連接形式。此時f爲殘差函數。

 

最後請勿將該答案應用於任何學術和商業用途。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章