如何用張量分解加速深層神經網路?(附代碼)
本文為雷鋒字幕組編譯的技術博客,原標題Accelerating deep neural networks with tensor decompositions,作者為Jacob。
翻譯 | 林立宏 整理 | 凡江
背景
在這篇文章中,我將介紹幾種低秩張量分解方法,用於在現有的深度學習模型中進行分層並使其更緊湊。我也將分享PyTorch代碼,它使用Tensorly來進行在卷積層上的CP分解和Tucker分解。
儘管希望大部分帖子都是可以獨立閱讀的,關於張量分解的回顧可以在這裡找到。Tensorly的作者也寫了於Tensor的基礎內容非常棒的notebook。這幫助我很好的開始學習這塊內容,建議你閱讀一下這些內容。
加上裁剪(pruning),張量分解是加快現有深度神經網路的實用工具,我希望這篇文章能讓這些內容更加容易理解。
這些方法需要將一個層分解成幾個更小的層。儘管在分解後會有更多的層,但是浮點運算次數和權重的總數會變小。一些報告的結果是整個網路的x8倍的速度提升(不針對像imagenet這樣的大型任務),或者imagenet中的特定層中x4倍的提升。我的結論是用這些分解方式,我能夠獲得x2到x4倍的加速,這取決於我願意犧牲多少的精度。
在這篇文章中我介紹了一些稱為裁剪(pruning)的技術以減少模型中的參數數量。在一個數據集上正向傳遞(有時是反向傳遞)裁剪(pruning),然後根據網路中激活的一些標準對神經元進行排序。
完全不同的是,張量分解的辦法只用到層的權重,假設網路層是參數化的,它的權重能夠用一個矩陣或者是一個低秩的張量來表示。這意味這個它們在參數化的網路下效果最佳。像VGG神經網路設計為完全參數化的。另外一個關於參數化模型的例子是使用更少的類別對網路進行微調以實現更簡單的任務。
和裁剪(pruning)相似,分解之後通過模型需要微調來恢復準確性。
在我們會深入討論細節之前,最後一件要說明的事是,雖然這些方法是實用的,並給出了很好的結果,但它們有一些缺點:
它們能夠在一個線性權重上執行(比如一個卷積或者一個全連接的層),忽略了任何非線性的內容。
它們是貪婪,自認為聰明地分解層,忽略了不同層之間的相互作用。
目前還要試圖解決這些問題,而且它仍然是一個活躍的研究領域。
截斷SVD用於分解完全連接的層
第一份我能找到的使用這個來加速深度神經網路的是在Fast-RNN論文中,Ross Girshick使用它來加速用於檢測的全連接層。代碼可以在這裡找到:pyfaster-rcnn implementation。
SVD概況
奇異值分解使我們能夠分解任何具有n行和m列的矩陣A:
S是一個對角矩陣,其對角線上有非負值(奇異值),並且通常被構造成奇異值按降序排列的。U和V是正交矩陣:
如果我們取最大的奇異值並將其餘的歸零,我們得到A的近似值:
具有作為Frobenius範數最接近於A的秩t矩陣的性質,所以如果t足夠大,
是A的良好近似。
在全連接層上的SVD
一個全連接層通常是做了矩陣乘法,輸入一個矩陣A然後增加一個偏差b:
我們可以取A的SVD,只保留第一個奇異值。
這不是一個完全連接的層,而是指導我們如何實現它作為兩個較小的:
第一個將有一個mxt的形狀,將沒有偏差,其權重將取自
。
第二個將有一個txn的形狀,將有一個等於b的偏差,其權重將取自
。
權重總數從nxm下降到t(n + m)。
在卷積層上張量分解
二維卷積層是一個多維矩陣(後面用-張量),有四個維度:
cols x rows x input_channels x output_channels.
遵循SVD的例子,我們想要以某種方式將張量分解成幾個更小的張量。卷積層轉換為幾個較小近似的卷積層。
為此,我們將使用兩種流行的(至少在Tensor演算法的世界中)張量分解:CP分解和Tucker分解(也稱為高階SVD或其他名稱)。
1412.6553 使用微調CP分解加速卷積神經網路
1412.6553 Speeding-up Convolutional Neural Networks Using Fine-tuned CP-Decomposition這篇論文說明了如果CP分解能夠用於卷積層的加速,正如我們會看到的,這將卷積層納入類似移動網路的東西。
他們使用它來加速網路的速度,而不會明顯降低精度。在我自己的實驗中,我可以使用這個在基於VGG16的網路上獲得x2加速,而不會降低準確度。
我使用這種方法的經驗是,需要非常仔細地選擇學習率,微調以使其工作,學習率通常應該非常小(大約
)。
一個秩R矩陣可以被視為R秩和1矩陣的和,每個秩1矩陣是一個列向量乘以一個行向量:
SVD為我們提供了使用SVD中的U和V列來寫矩陣和的方法:
如果我們選擇一個小於矩陣滿秩的R,那麼這個和就是一個近似值,就像截斷SVD的情況一樣。
CP分解讓我們推廣了張量。
使用CP分解,我們的卷積核,一個四維張量公式,可以近似為一個選定的R:
我們希望R對於有效的分解是小的,但是對保持近似高精度是足夠大的。
帶CP分解的卷積正向傳遞
為了傳遞圖層,我們使用輸入
進行卷積:
這給了我們一個辦法來解決這個問題:
1.首先做一個wise(1x1xS)與
卷積。這減少了從S到R輸入通道的數量。下一步將在較少數量的通道上完成卷積,使其更快。
2.用
在空間維度上執行分離的卷積。就像在移動網路中一樣,卷積是深度可分的,分別在每個通道中完成。與mobilenets不同,卷積在空間維度上也是可分的。
3.做另一個逐點卷積來改變從R到T的通道數量如果原始卷積層有一個偏差,在這一點上加上它。
注意像在移動網中的逐點和深度卷積的組合。在使用mobilenets的時候,你必須從頭開始訓練一個網路來獲得這個結構,在這裡我們可以把現有的圖層分解成這種形式。
與移動網路一樣,為了獲得最快的速度,需要一個有效實現深度可分離卷積的平台。
用PyTorch和Tensorly卷積層CP分解
1511.06530 用於快速和低功率移動應用的深度卷積神經網路的壓縮
1511.06530 Compression of Deep Convolutional Neural Networks for Fast and Low Power Mobile Applications 這一篇非常酷的論文,說明了如何使用Tucker分解來加速卷積層來得到更好的結果。我也在基於VGG的參數化網路用了這種加速,比CP分解的精度要好。作者在論文中指出,它可以讓我們使用更高的學習率(我用
)進行微調。
Tucker分解也稱為高階奇異值分解(HOSVD)或者其他名稱,是對張量進行奇異值分解的一種推廣。
它認為SVD的推廣的原因是
的分量通常是正交的,但這對於我們的目的並不重要。
被稱為核心矩陣,並定義不同的軸如何相互作用。
在上面描述的CP分解中,沿著空間維度
的分解導致空間上可分離的卷積。無論如何,過濾器是非常小的,通常是3x3或5x5,所以可分離的卷積並不節省我們大量的計算,而且是一個積極的近似。
Trucker分解有用的性質是,它不必沿著所有的軸(模式)分解。我們可以沿著輸入和輸出通道進行分解(模式2分解):
卷積正向傳遞與塔克分解
像CP分解一樣,寫一下卷積公式並插入內核分解:
這給了我們以下用Tucker分解進行卷積的配方:
1.與
進行點對點卷積,信道從S減少到
的數量。
2.用
進行正則(不可分)卷積。這個卷積代替了原始層的S輸入通道和T輸出通道,具有
輸入通道和
輸出通道。如果這些等級小於S和T,這就是減少的原因。
3.用
進行點對點卷積以回到原始卷積的T個輸出通道。由於這是最後一次卷積,所以在這一點上,如果有偏差就加上偏差。
我們如何選擇分解行列
一種方法是嘗試不同的值並檢查準確性。嘗試後的啟發是
,效果很好。
理想情況下,選擇行列應該是自動的。
作者提出使用變分貝葉斯矩陣分解(VBMF)(Nakajima等,2013)作為估計等級的方法。
VBMF很複雜,不在本文的討論範圍內,但是在一個非常高層次的總結中,他們所做的是將矩陣
近似為低秩矩陣
和高斯雜訊之和。在找到A和B之後,H是等級的上限。
為了將其用於Tucker分解,我們可以展開原始權重張量的s和t分量來創建矩陣。然後我們可以使用VBMF估計
和
作為矩陣的秩。
我用這個在Python上實現的VBMF,相信它可以工作。
VBMF通常返回的秩,非常接近我之前,仔細和乏味的手動調整得到的結果。
這也可以用於估計完全連接層的截斷SVD加速的等級。
用PyTorch和Tensorly卷積層Tucker分解
總結
在這篇文章中,我們討論了幾個張量分解的方法來加速深度神經網路。
截斷的SVD可用於加速完全連接的層。
CP分解將卷積層分解成類似移動網路的東西,儘管它更具侵略性,因為它在空間維度上也是可分的。
Tucker分解減少了二維卷積層操作的輸入和輸出通道的數量,並且使用逐點卷積來切換2D卷積之前和之後的通道數量。
我覺得有趣的是網路設計中的常見模式,逐點和深度卷積,自然而然出現在這些分解中!
博客原址 https://jacobgil.github.io/deeplearning/tensor-decompositions-deep-learning
推薦閱讀:
※放開二胎的結果是加速老齡化——答南方人物周刊記者問
※促排卵,真的會加速卵巢的衰老嗎?
※加速康復外科的麻醉管理
※廢除科舉是否加速了清王朝的滅亡
※微看台丨趕不上中國戰略節奏,亞洲四小龍將加速衰落!