快速矩陣乘法的研究
最近的工作主要在於深度學習框架的性能優化。深度學習框架在工程的優化(內存池、SIMD、彙編、GPU、DSP等等)做到接近極限之後,突破點便集中於算法。
深度學習的性能瓶頸主要在於卷積,卷積的運算方法主要是通過 Im2Col / Winograd / FFT 轉化爲矩陣乘,完成矩陣乘法之後,再轉化爲目標結果。
深度學習框架的輸入是算法工程產出的網絡模型,而目前網絡模型都漸漸地轉變爲 mobilenet 那樣 1x1 convolution + depthwise 的形式,在精度幾乎無損的情況下,既減少了計算量,又減少了模型體積。而這類網絡模型,都以 1x1 卷積爲主要耗時點。
對 1x1 卷積而言,其本身就是一個矩陣乘法,FFT / Winograd 等卷積算法已經失去價值,因此研讀了一些矩陣乘法相關的論文,整理如下。
傳統矩陣乘算法
定義
在 1968 年之前,矩陣乘算法只有按定義實現的傳統算法,:
設:
A=⎝⎜⎜⎛a11a21...an1a12a22...an2............⎠⎟⎟⎞B=⎝⎜⎜⎛b11b21...bn1b12b22...bn2............⎠⎟⎟⎞
AB 爲其乘積,則:
[AB]pq=i=1∑napibiq
很明顯,它是一個 n3複雜度的算法,需要 n3 次乘法和 n3−n2次加法。
矩陣乘表示
設 C=AB,A 爲 e∗l的矩陣,B 爲 l∗h的矩陣,則稱這個矩陣乘是一個 [e,l,h] 的矩陣乘。
快速矩陣乘法的初步探索
Winograd 算法
請注意,這個不是我們通常所說的卷積優化算法,只是同一個人(Winograd大神)在 1968 年提出一種減少乘法數的矩陣乘算法。
其思路是通過兩次 n2 的乘法預處理,將規模大的矩陣乘法減少一半,但相應的加法增加一半。爲了說明簡單,這裏假定n爲偶數。
θp=j=1∑⌊n/2⌋(ap,2j−1ap,2j)γq=j=1∑⌊n/2⌋(b2j−1,qb2j,q)[AB]pq=j=1∑⌊n/2⌋(ap,2j−1+b2j,q)(ap,2j+b2j−1,q)−θp−γq
這個算法沒有降低矩陣乘法的階(還是n3),只是以廉價計算(加法)替代昂貴運算(乘法),需要根據具體的硬件去判斷是否可應用。ARM 架構的 CPU,對量化矩陣乘有幫助,但對浮點矩陣乘沒有用。
Strassen 矩陣乘算法
Strassen 矩陣乘的思路是通過加減變換,將一個 [2,2,2]的矩陣乘法所用的乘法數由8降到7,並且遞歸使用,降低矩陣乘法的階數:n3變成n2.81
A=(a11a21a12a22)B=(b11b21b12b22)AB=(c11c21c12c22)
v1=(a11+a22)(b11+b22)v2=(a21+a22)(b11)v3=(a11)(b12−b22)v4=(a22)(b21−b11)v5=(a11+a12)(b22)v6=(a21−a11)(b11+b12)v7=(a12−a22)(b21+b22)
c11=v1+v4−v5+v7c21=v2+v4c12=v3+v5c22=v1+v3−v2+v6
請注意,其中每個元素(a11,b12,c22等等)不限於實數,可以是一個矩陣。因爲矩陣乘法滿足分配率與結合率。這樣算法就有了脫離硬件的普適價值,因爲矩陣加減的複雜度(n2)遠低於矩陣乘(n3)
Winograd 在 Strassen 的基礎上對它的算法進行了改進,減少了加減數(18->15),這個也成爲最常用的 Strassen 矩陣乘法應用。
三線性表示
爲了方便矩陣乘算法的研究,人們提出一種表示矩陣乘算法的形式,叫“Trilinear-form”,即三線性形式。
我們先以 Strassen 算法爲例,它的三線性形式是:
∑i=12∑j=12∑k=12aijbjkcik=(a11)(b12−b22)(c12+c22)+(a11+a12)(b22)(−c11+c12)+(a21+a22)(b11)(c21−c22)+(a22)(b21+b11)(c11+c21)+(a11+a22)(b11+b22)(c11+c22)+(a12−a22)(b21+b22)(c11)+(a11−a21)(b11+b12)(−c22)
怎麼看這個公式呢,它其實是按 Trace(ABC)=AB 的原理去表示的。兩個矩陣的乘積,等效於三個矩陣乘積的跡。在上面公式中,如果我們要算出 c11 的解法,就將 c11 設成 1,其他的 c 值,c12,c21,c22 全設成 0 ,然後將對應的項相加即可。
這個算式總共有7項,這個 7 我們稱之爲 Rank (階)
APA——矩陣乘算法的突破
APA,即 Any Precision Algorithm,是把矩陣乘法階數繼續往下降的重要思想,基本思路是先給出近似的矩陣乘法表達式,然後在多階張量積之後轉換爲準確的矩陣乘法。
張量積
我們來看 Strassen 矩陣乘法的表達式:
λ=(a11)(b12−b22)(c12+c22)+(a11+a12)(b22)(−c11+c12)+(a21+a22)(b11)(c21−c22)+(a22)(b21+b11)(c11+c21)+(a11+a22)(b11+b22)(c11+c22)+(a12−a22)(b21+b22)(c11)+(a11−a21)(b11+b12)(−c22)
對其平方:
λ2=((a11)(b12−b22)(c12+c22)+(a11+a12)(b22)(−c11+c12)+(a21+a22)(b11)(c21−c22)+(a22)(b21+b11)(c11+c21)+(a11+a22)(b11+b22)(c11+c22)+(a12−a22)(b21+b22)(c11)+(a11−a21)(b11+b12)(−c22))2
這是個多項式乘法,不難知λ2 有 72=49 項,我們來看其中一項:
((a11)(b12−b22)(c12+c22))((a11+a12)(b22)(−c11+c12))=(a11a11+a11a12)(b12b22−b22b22)(−c12c11+c12c12−c22c11+c22c12)
(依然是將a, b, c 分別組合在一起)
a,b,c間的相乘,如a11a12,我們將其替代爲直和:a1112,其含義可以這麼理解,在a11的區域(左上角)中,再劃分爲四塊,取其a12的區域(右上角)。
不難證明,我們通過這個多項式平方後得到的三線性形式,等效於一個 [4,4,4] 的矩陣乘法。
類似地,我們可以對矩陣乘法的三線性形式進行立方,n次方,以及兩個不同的三線性形式乘積,這一系列操作可由“張量積”概括。
APA
Any Precision Algorithm(APA),即任意精度算法,通過在算式中引入一個可配置的實數λ,得到更好的簡化效果。
下面的式子近似用21項表示了一個[3,3,3]的矩陣乘法
F1(λ)=(a11+λ2a12)(λ2b11+b21)c11+(a21+λ2a22)(λ2b12+b22)c22+(a31+λ2a32)(λ2b13+b23)c33−a11(b21+b31)(c11+c12+c13)−a21(b22+b32)(c21+c22+c23)−a31(b23+b33)(c31+c32+c33)+(a11+λ2a22)(b21−λb12)c12+(a21+λ2a12)(b22−λb11)c21+(a11+λ2a32)(b21−λb13)c13+(a31+λ2a12)(b23−λb11)c31+(a21+λ2a32)(b22−λb13)c23+(a31+λ2a22)(b23−λb12)c32+(a11+λ2a23)(b31+λb12)(c12+λc21)+(a21+λ2a13)(b32+λb11)(c21+λc12)+(a11+λ2a33)(b31+λb13)(c13+λc31)+(a31+λ2a13)(b33+λb12)(c31+λc13)+(a21+λ2a33)(b32+λb13)(c23+λc32)+(a31+λ2a23)(b33+λb12)(c32+λc23)+(a11+λ2a13)b31(c11−λc31−λc21)+(a21+λ2a23)b32(c22−λc32−λc12)+(a31+λ2a33)b33(c33−λc13−λc23)=λ2(Trace(ABC)+λG(λ))
當 λ趨於無窮小時,其誤差也趨於無窮小,因此我們可以設定任意的精度去使用它,這就是 APA 的由來。
對於 APA 算法,多項式的個數我們稱之爲 Border Rank,上述算式表示了一個[3,3,3]的矩陣乘法,在λ3的基礎上分出誤差,我們稱之爲一個降解:[3,3,3]⊴321
現在我們來看怎麼把上面的 APA 算法變成準確算法。
直觀的做法就是把λ2項取出來,如:(a11+λ2a12)(λ2b11+b21)c11,取出 λ2a11b11c11+λ2a12b21c11,代價就是增加了多項式,不難證明,我們最多會增加到 2(2+1)/2=3倍的多項式個數。
無疑,這樣做肯定虧了,3∗21=63>3∗3∗3=27,我們需要施個魔法,就是張量積。
對上面APA 算法進行n次張量積之後,我們可以得到3n大小的矩陣乘算法的降解:[3n,3n,3n]⊴2n+121n
這時候我們再來取,就不一樣了,其階數變成了:
n(2n+1)21n
很明顯,當 n 足夠大時,n(2n+1) 和指數項相比可忽略,這樣我們就得到了更好的準確算法,其階數爲:
3ln(21)/ln(27)≈2.77
下篇內容:
1、組合矩陣乘
2、漸近和定理
3、Strassen構造
4、Coppersmith–Winograd 算法