為什麼要用可逆網絡呢?
因為編碼和解碼使用相同的參數,所以 model 是輕量級的。可逆的降噪網絡 InvDN 只有 DANet 網絡參數量的 4.2%,但是 InvDN 的降噪性能更好。由於可逆網絡是信息無損的,所以它能保留輸入數據的細節信息。無論網絡的深度如何,可逆網絡都使用恆定的內存來計算梯度。其中最主要目的就是為了減少內存的消耗,當前所有的神經網絡都採用反向傳播的方式來訓練,反向傳播算法需要存儲網絡的中間結果來計算梯度,而且其對內存的消耗與網絡單元數成正比。這也就意味着,網絡越深越廣,對內存的消耗越大,這將成為很多應用的瓶頸。下面是 Pytorch summary 的結果,Forward/backward pass size(MB): 218.59就是需要保存的中間變量大小,可以看出這部分占據了很大部分顯存(隨着網絡深度的增加,中間變量占據顯存量會一直增加,resnet152(size=224)的中間變量更是占據總共內存的606.6÷836.79≈0.725)。如果不存儲中間層結果,那麼就可以大幅減少 GPU 的顯存占用,有助於訓練更深更廣的網絡。
import torchfrom torchvision import modelsfrom torchsummary import summarydevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')vgg = models.vgg16().to(device)summary(vgg, (3, 224, 224))---------------------------------------------------------------- Layer (type) Output Shape Param #================================================================ Conv2d-1 [-1, 64, 224, 224] 1,792 ReLU-2 [-1, 64, 224, 224] 0 Conv2d-3 [-1, 64, 224, 224] 36,928 ReLU-4 [-1, 64, 224, 224] 0 MaxPool2d-5 [-1, 64, 112, 112] 0 Conv2d-6 [-1, 128, 112, 112] 73,856 ReLU-7 [-1, 128, 112, 112] 0 Conv2d-8 [-1, 128, 112, 112] 147,584 ReLU-9 [-1, 128, 112, 112] 0 MaxPool2d-10 [-1, 128, 56, 56] 0 Conv2d-11 [-1, 256, 56, 56] 295,168 ReLU-12 [-1, 256, 56, 56] 0 Conv2d-13 [-1, 256, 56, 56] 590,080 ReLU-14 [-1, 256, 56, 56] 0 Conv2d-15 [-1, 256, 56, 56] 590,080 ReLU-16 [-1, 256, 56, 56] 0 MaxPool2d-17 [-1, 256, 28, 28] 0 Conv2d-18 [-1, 512, 28, 28] 1,180,160 ReLU-19 [-1, 512, 28, 28] 0 Conv2d-20 [-1, 512, 28, 28] 2,359,808 ReLU-21 [-1, 512, 28, 28] 0 Conv2d-22 [-1, 512, 28, 28] 2,359,808 ReLU-23 [-1, 512, 28, 28] 0 MaxPool2d-24 [-1, 512, 14, 14] 0 Conv2d-25 [-1, 512, 14, 14] 2,359,808 ReLU-26 [-1, 512, 14, 14] 0 Conv2d-27 [-1, 512, 14, 14] 2,359,808 ReLU-28 [-1, 512, 14, 14] 0 Conv2d-29 [-1, 512, 14, 14] 2,359,808 ReLU-30 [-1, 512, 14, 14] 0 MaxPool2d-31 [-1, 512, 7, 7] 0 Linear-32 [-1, 4096] 102,764,544 ReLU-33 [-1, 4096] 0 Dropout-34 [-1, 4096] 0 Linear-35 [-1, 4096] 16,781,312 ReLU-36 [-1, 4096] 0 Dropout-37 [-1, 4096] 0 Linear-38 [-1, 1000] 4,097,000================================================================Total params: 138,357,544Trainable params: 138,357,544Non-trainable params: 0----------------------------------------------------------------Input size (MB): 0.57Forward/backward pass size (MB): 218.59Params size (MB): 527.79Estimated Total Size (MB): 746.96----------------------------------------------------------------接下來我將先從可逆神經網絡講起,然後是神經網絡的反向傳播,最後是標準殘差網絡。對反向傳播算法和標準殘差網絡比較熟悉的小夥伴,可以只看第一節:可逆神經網絡。如果各位小夥伴不熟悉反向傳播算法和標準殘差網絡,建議先看第二節:反向傳播(BP)算法和第三節:殘差網絡(Residual Network)。本文1.2和1.3.4摘錄自 @阿亮。網絡的輸入、輸出的大小必須一致。
網絡的雅可比行列式不為 0。
1.1 什麼是雅可比行列式?雅可比行列式通常稱為雅可比式(Jacobian),它是以 n 個 n 元函數的偏導數為元素的行列式 。事實上,在函數都連續可微(即偏導數都連續)的前提之下,它就是函數組的微分形式下的係數矩陣(即雅可比矩陣)的行列式。若因變量對自變量連續可微,而自變量對新變量連續可微,則因變量也對新變量連續可微。這可用行列式的乘法法則和偏導數的連鎖法則直接驗證。也類似於導數的連鎖法則。偏導數的連鎖法則也有類似的公式;這常用於重積分的計算中。



1.2 雅可比行列式與神經網絡的關係為什麼神經網絡會與雅可比行列式有關係?這裡我借用李宏毅老師的 ppt(12-14頁)。想看視頻的可以到 b 站上看。



簡單的來講就是,他們的分布之間的關係就變為,又因為有,所以這個網絡的雅可比行列式不為 0 才行。順便提一下,flow-based Model 優化的損失函數如下:

其實這裡跟矩陣運算很像,矩陣可逆的條件也是矩陣的雅可比行列式不為 0,雅可比矩陣可以理解為矩陣的一階導數。


1.3 可逆殘差網絡(Reversible Residual Network)

論文標題:The Reversible Residual Network: Backpropagation Without Storing Activations論文鏈接:https://arxiv.org/abs/1707.04585多倫多大學的 Aidan N.Gomez 和 Mengye Ren 提出了可逆殘差神經網絡,當前層的激活結果可由下一層的結果計算得出,也就是如果我們知道網絡層最後的結果,就可以反推前面每一層的中間結果。這樣我們只需要存儲網絡的參數和最後一層的結果即可,激活結果的存儲與網絡的深度無關了,將大幅減少顯存占用。令人驚訝的是,實驗結果顯示,可逆殘差網絡的表現並沒有顯著下降,與之前的標準殘差網絡實驗結果基本旗鼓相當。
可逆神經網絡將每一層分割成兩部分,分別為和,每一個可逆塊的輸入是,輸出是。其結構如下:




其中 F 和 G 都是相似的殘差函數,參考上圖殘差網絡。可逆塊的跨距只能為 1,也就是說可逆塊必須一個接一個連接,中間不能採用其它網絡形式銜接,否則的話就會丟失信息,並且無法可逆計算了,這點與殘差塊不一樣。如果一定要採取跟殘差塊相似的結構,也就是中間一部分採用普通網絡形式銜接,那中間這部分的激活結果就必須顯式的存起來。為了更好地計算反向傳播的步驟,我們修改一下上述正向計算和逆向計算的公式:
儘管和的值是相同的,但是兩個變量在圖中卻代表不同的節點,所以在反向傳播中它們的總體導數是不一樣的。的導數包含通過產生的間接影響,而的導數卻不受的任何影響。在反向傳播計算流程中,先給出最後一層的激活值和誤差傳播的總體導數,然後要計算出其輸入值和對應的導數,以及殘差函數 F 和 G 中權重參數的總體導數,求解步驟如下:一個 N 個連接的神經網絡,正向計算的理論加乘開銷為 N,反向傳播求導的理論加乘開銷為 2N(反向求導包含複合函數求導連乘),而可逆網絡多一步需要反向計算輸入值的操作,所以理論計算開銷為 4N,比普通網絡開銷約多出 33% 左右。但是在實際操作中,正向和反向的計算開銷在 GPU 上差不多,可以都理解為 N。那麼這樣的話,普通網絡的整體計算開銷為 2N,可逆網絡的整體開銷為 3N,也就是多出了約 50%。
其編碼公式如下:


其解碼公式如下:


為了計算雅可比矩陣,我們更直觀的寫成下面的編碼公式:


它的雅可比矩陣為:

其實上面這個雅可比行列式也是 1,因為這裡,它們的係數是一樣的。




反向傳播(BP)算法

:表示從 t-1 層到 t 層的權重參數,j 表示 t 層的第 j 個節點,i 表示 t-1 層的第 i 個節點。
正向傳播計算過程:
隱藏層(網絡的第二層)

輸出層(網絡的最後一層)

以單個樣本為例,假設輸入向量是 [x1,x2,x3],目標輸出值是 [y1,y2],代價函數用 L 表示。反向傳播的總體原理就是根據總體輸出誤差,反向傳播回網絡,通過計算每一層節點的梯度,利用梯度下降法原理,更新每一層的網絡權重 w 和偏置 b,這也是網絡學習的過程。誤差反向傳播的優點就是可以把繁雜的導數計算以數列遞推的形式來表示, 簡化了計算過程。
以平方誤差來計算反向傳播的過程,代價函數表示如下:
根據導數的鏈式法則反向求解隱藏 -> 輸出層、輸入層 -> 隱藏層的權重表示:

l=2,3 表示第幾層,j 表示某一層的第幾個節點。替換表示後如下:

從上述公式可以看出,如果神經單元誤差 δ 可以求出來,那麼總誤差對每一層的權重 w 和偏置 b 的偏導數就可以求出來,接下來就可以利用梯度下降法來優化參數了。
輸出層

隱藏層

也就是說,我們根據輸出層的神經誤差單元 δ 就可以直接求出隱藏層的神經誤差單元,進而省去了隱藏層的繁雜的求導過程,我們可以得出更一般的計算過程:
從而得出 l 層神經單元誤差和 l+1 層神經單元誤差的關係。這就是誤差反向傳播算法,只要求出輸出層的神經單元誤差,其它層的神經單元誤差就不需要計算偏導數了,而可以直接通過上述公式得出。
殘差網絡(Residual Network)
梯度消失問題;
網絡退化問題。

上述結構就是一個兩層網絡組成的殘差塊,殘差塊可以由 2、3 層甚至更多層組成,但是如果是一層的,就變成線性變換了,沒什麼意義了。上述圖可以寫成公式如下:
所以在第二層進入激活函數 ReLU之 前 F(x)+x 組成新的輸入,也叫恆等映射。
恆等映射就是在這個殘差塊輸入是 x 的情況下輸出依然是 x,這樣其目標就是學習讓 F(X)=0。
這裡有一個問題哈,為什麼要額外加一個 x 呢,而不是讓模型直接學習 F(x)=x?
因為讓 F(x)=0 比較容易,初始化參數 W 非常小接近 0,就可以讓輸出接近 0,同時輸出如果是負數,經過第一層 Relu 後輸出依然 0,都能使得最後的 F(x)=0,也就是有多種情況都可以使得 F(x)=0;但是讓 F(x)=x 確實非常難的,因為參數都必須剛剛好才能使得最後輸出為 x。
恆等映射就可以解決網絡退化的問題,當網絡層數越來越深的時候,網絡的精度卻在下降,也就是說網絡自身存在一個最優的層度結構,太深太淺都能使得模型精度下降。有了恆等映射存在,網絡就能夠自己學習到哪些層是冗餘的,就可以無損通過這些層,理論上講再深的網絡都不影響其精度,解決了網絡退化問題。
以兩個殘差塊的結構實例圖來分析,其中每個殘差塊有 2 層神經網絡組成,如下圖:

假設激活函數 ReLU 用 g(x) 函數來表示,樣本實例是 [x1,y1],即輸入是 x1,目標值是 y1,損失函數還是採用平方損失函數,則每一層的計算如下:
下面我們對第一個殘差塊的權重參數求導,根據鏈式求導法則,公式如下:
我們可以看到求導公式中多了一個+1項,這就將原來的鏈式求導中的連乘變成了連加狀態,可以有效避免梯度消失了。
[1] PPThttps://speech.ee.ntu.edu.tw/~tlkagk/courses/ML_2019/Lecture/FLOW%20(v7).pdf[2] 神經網絡的可逆形式https://zhuanlan.zhihu.com/p/268242678[3] 大幅減少GPU顯存占用:可逆殘差網絡(The Reversible Residual Network) https://www.cnblogs.com/gczr/p/12181354.html[4] 雅可比行列式https://baike.baidu.com/item/雅可比行列式/4709261?fr=aladdin[5] The Reversible Residual Network: Backpropagation Without Storing Activations[6] pytorch-summaryhttps://github.com/sksq96/pytorch-summary想要了解更多資訊,請掃描下方二維碼,關注機器學習研究會

轉自:PaperWeekly