深度學習神經網絡模型中的量化是指浮點數用定點數來表示,也就是在DSP技術中常說的Q格式。我在以前的文章(Android手機上Audio DSP頻率低 memory小的應對措施 )中簡單講過Q格式,網上也有很多講Q格式的,這里就不細講了。神經網絡模型在訓練時都是浮點運算的,得到的模型參數也是浮點的。通常模型參數較多,在inference時也有非常多的乘累加運算。如果處理器的算力有限,在inference時用浮點運算將導致CPU load很高,極大影響性能。而且通常一個參數用浮點數表示占四個字節,而如果用8比特量化的話,一個參數只占一個字節,memory得到了極大的節約,在memory緊張的處理器上尤為重要。所以通常都要對神經網絡模型進行量化,來降低CPU load和節省memory。由於特征數據(比如智能語音中的MFCC數據)在送入模型前基本都做了歸一化處理,值都壓縮到了【-1,1】的范圍內,所以現在主流的都是用8比特來量化。下表是用8比特來量化的各種Q格式的值的取值范圍。
模型的量化可分為訓練中量化和訓練后量化,還可分為對稱量化和非對稱量化。我們用的是訓練后對稱量化,即先訓練好用浮點表示的模型參數等,然后再去量化,量化某類值(比如weight)時看其絕對值的最大值,從而可以知道用什么定標的Q格式最合適。我們目前用的是主流的8比特量化方式。模型的量化主要包括兩方面的內容:各層參數的量化和各層輸出的量化。先看各層輸出的量化。在評估時把測試集中各個文件每層的輸出保存下來,然后看每層輸出值的絕對值的最大值,比如絕對值最大值為3.6,可以從上面的8比特量化表看出用Q2.5 量化最為合適(也可以用公式 np.ceil(np.log2(max))算出整數的表示位數,然后確定小數的表示位數,從而確定定標)。再來看各層參數的量化。參數主要包括weight和bias,這兩種參數要分別量化,量化方法同上面的每層輸出的量化方法一樣,這里不再贅述。需要注意的是如果當前層是卷積層或者全連接層,為了減少運算量,一般部署模型時都會將BatchNormal(BN)層參數融合到卷積層或者全連接層(只有當卷積層或者全連接層后面緊跟BN層時才可以融合參數,否則不可以)。具體怎么融合如下:假設層的輸入為X,不管是卷積層還是全連接層,運算均可以寫成 WX + b (W為權重weight, b為bias),BN層執行了兩個操作,一個是歸一化,另一個是縮放,兩個階段的操作分別為:
將上面三個式子合並(卷積層或者全連接層的輸出就是BN層的輸入, 原卷積層或者全連接層的參數為Wold和bold),可以得到:
上式等於Wnew * X + bnew,展開得到:
這樣合並后的運算就成了:
在卷積層或者全連接層里用上面得到的新參數(Wnew和bnew)替代舊參數(Wold和bold),inference時BN層就消失啦。
卷積層或全連接層中,主要是乘累加運算,通常格式是output = input*weight + bias。這里input是當前層的輸入(即是上一層的輸出),weight是當前層的權值,bias是當前層的偏置,output是當前層的輸出。這四個值均已定標,在運算過程中要想得到正確的結果,需要做移位處理。怎么移位呢?下面舉例說明。
假設input定標為Q5.2 ,weight定標為Q1.6 ,bias定標為Q4.3 ,output定標為Q2.5 。假定只有一個input和一個weight,input浮點值是28.4,用Q5.2 表示就是01110010 (28.4 * = 113.6,四舍五入就是114),weight浮點值是1.6,用Q1.6 表示就是01100110,bias為12.8,用Q4.3 表示就是01100110。Input * weight = 01110010 * 01100110 = 0010 1101 0110 1100 = 11628(十進制表示)。八位數乘以八位數超出了8位數的表示范圍,要用16位表示。28.4 * 1.6 = 45.44,要讓11628表示45.44,所以11628用Q7.8 表示(11628 / 45.44 約為256 =
)。從上面計算看出,兩個八位數相乘是16位數,16位數的定標小數位數是兩個8位數的定標小數位數相加。這里Q7.8 中的8是Q5.2 中的2加上Q1.6 中的6。定標小數位數知道了,整數位數就是(15 - 小數位數),這里小數位數是8,整數位數就是7(7 = 15 - 8)。不同定標的數也不能直接相加,所以要把bias的Q4.3 表示的值轉換成Q7.8 表示的值。Bias原始為12.8,用Q4.3 表示就是12.8 *
,用Q7.8 表示就是12.8 *
。可以看出bias從Q4.3 轉變為Q7.8 ,只要乘以
即可,即左移5位。再來看上面的式子output =
input*weight + bias,等式右邊經過計算后變成了Q7.8 ,而等式左邊是根據非常多的樣本算出來的層的輸出的絕對值的最大值得到的定標Q2.5 ,所以最后要把Q7.8 格式轉換成Q2.5格式 。對於一個浮點數,假設為a,用Q7.8 表示就是a *
, 用Q2.5 表示就是a *
,可以看出要把Q7.8 格式轉換成Q2.5格式 ,只需右移3位(3 = 8 - 5)即可。
所以每一層計算過程中移位的處理如下:假定input定標為Qa.b,weight定標為Qc.d,bias定標為Qe.f,output定標為Qm.n。這些值均為8比特表示,即a+b=7,c+d=7,e+f=7,m+n=7。input * weight 為16比特Qu.v表示,其中v=b+d,u = 15 - v。計算過程中要把bias從8位表示變成16位表示,若f<v,bias則要左移(v-f)位,若f>v,bias則要右移(f-v)位,若f=v,則不移位。處理后
input*weight + bias是一個16位表示的數,而output是一個8位表示的數,還要把16位表示的數轉換成8位表示的數。若n<v,16位表示的數則要右移(v-n)位,若n>v,16位表示的數則要左移(n-v)位,若n=v,則不移位。
按照上面的方法,各層的模型參數以及輸出都量化好了。量化好后還要對量化進行評估,評估的指標是余弦相似度和歐幾里得距離等。余弦相似度是用向量空間中兩個向量夾角的余弦值作為衡量兩個個體間差異的大小的度量。余弦值越接近1,就表明夾角越接近0度,也就是兩個向量越相似。公式如下:
歐幾里得距離,又稱歐氏距離,是最常見的距離度量,衡量的是多維空間中兩個向量之間的絕對距離。歐氏距離越小,相似度越大;歐氏距離越大,相似度越小。公式如下:
評估時要一層一層的評估,用余弦相似度和歐幾里得距離等比較每層的量化前浮點的輸出的向量和量化后的定點的輸出向量(定點的輸出向量算好后要根據定標轉成浮點數才能比較)。余弦相似度要接近1和歐幾里得距離要接近0,才是一個合格的量化。否則要找出量化中的問題,直到指標達標。