数据类型概述
數(shù)據(jù)類型概述
int、int16、int32、int64、float、float16、float32、float64
在做模型量化的時候,經(jīng)常遇到這幾個類精度表示,做下記錄:
bits:位數(shù)
bytes:字節(jié) 1bytes = 8 bits
單精度用小數(shù)用23位存儲,加上默認(rèn)的小數(shù)點前的1為1,2^(23+1) = 16777216.
因為107<16777216<108,所以說單精度浮點數(shù)的有效位數(shù)是7位。
雙精度的小數(shù)位數(shù)是52位存儲,2^(52+1) = 9007199254740992.
因為1016<9007199254740992<1017,所以雙精度的有效位數(shù)是16位。
float16/32/64對神經(jīng)網(wǎng)絡(luò)計算的影響
神經(jīng)網(wǎng)絡(luò)的計算,或者說深度學(xué)習(xí)的計算,全都是浮點數(shù)。浮點數(shù)的類型分16/32/64(128位的不再考慮范圍內(nèi),numpy和python最大只到float64),選擇哪一種浮點數(shù)類型,對神經(jīng)網(wǎng)絡(luò)的計算有不同的影響。
(1)目前業(yè)界深度學(xué)習(xí)的標(biāo)準(zhǔn)是BF16,一種16位的浮點數(shù),據(jù)說Google的TPU已經(jīng)支持,未來Intel的芯片也會支持;
(2)我們在一般計算上的,通過numpy得到的16位浮點數(shù),是FP16,不是BF16;FP16是IEEE754-2008的標(biāo)準(zhǔn);這兩個標(biāo)準(zhǔn),在能夠表示的數(shù)值的范圍上有區(qū)別;
(3)對于內(nèi)存的影響:float64占用的內(nèi)存是float32的兩倍,是float16的4倍;比如對于CIFAR10數(shù)據(jù)集,如果采用float64來表示,需要60000323238/1024**3=1.4G,光把數(shù)據(jù)集調(diào)入內(nèi)存就需要1.4G;如果采用float32,只需要0.7G,如果采用float16,只需要0.35G左右;占用內(nèi)存的多少,會對系統(tǒng)運行效率有嚴(yán)重影響;(因此數(shù)據(jù)集文件都是采用uint8來存在數(shù)據(jù),保持文件最小)
(4)采用numpy的float16,即FP16,來計算深度學(xué)習(xí),容易出現(xiàn)runtime warning;因為精度不夠,更容易在計算過程中,產(chǎn)生極限值;(也許有辦法解決這個問題,比如進(jìn)一步縮小初始化的weights和bias)
(5)如果采用numba來進(jìn)行計算加速,要求所有計算的數(shù)據(jù)類型要保持一致;如果不加速,numpy在計算過程中,會自動upcast到數(shù)據(jù)精度更大的類型上去,這個問題要通過仔細(xì)寫代碼來規(guī)避;
(6)如果做gradient check,即通過比較網(wǎng)絡(luò)計算的梯度和數(shù)學(xué)定義的方式計算出來的梯度來判斷代碼是否正確,float32的精度可能都不夠,需要比較到小數(shù)點后6-8位;
(7)在沒有numba加速的情況下,如果是64位的CPU,float64的計算速度最快;因為對于float32和float16,CPU都需要多條指令來進(jìn)行數(shù)據(jù)的轉(zhuǎn)移,沒有嚴(yán)格測試過,有可能float16是最慢的;
(8)基于以上事實,我自己的teapot庫,決定采用float32!并保持在整個計算過程中,全部參與計算的數(shù)據(jù),都是float32,不會upcast的情況;并可通過一個全局可變常量,來控制浮點數(shù)類型的選擇,默認(rèn)就是float32;
(9)也可以考慮數(shù)據(jù)集數(shù)據(jù)在內(nèi)存中使用float16,而神經(jīng)網(wǎng)絡(luò)的weights和bias使用float32,這樣在計算過程中,float16和float32并存,即減少了內(nèi)存占用,也保持了一定的精度;不過這樣做,就無法采用numba加速;
深度學(xué)習(xí)與bfloat16(BF16)
Deep learning has spurred interest in novel floating point formats. Algorithms often don’t need as much precision as standard IEEE-754 doubles or even single precision floats. Lower precision makes it possible to hold more numbers in memory, reducing the time spent swapping numbers in and out of memory. Also, low-precision circuits are far less complex. Together these can benefits can give significant speedup.
深度學(xué)習(xí)促使了人們對新的浮點數(shù)格式的興趣。通常(深度學(xué)習(xí))算法并不需要64位,甚至32位的浮點數(shù)精度。更低的精度可以使在內(nèi)存中存放更多數(shù)據(jù)成為可能,并且減少在內(nèi)存中移動進(jìn)出數(shù)據(jù)的時間。低精度浮點數(shù)的電路也會更加簡單。這些好處結(jié)合在一起,帶來了明顯了計算速度的提升。
BF16 (bfloat16) is becoming a de facto standard for deep learning. It is supported by several deep learning accelerators (such as Google’s TPU), and will be supported in Intel processors two generations from now.
bfloat16,BF16格式的浮點數(shù)已經(jīng)成為深度學(xué)習(xí)事實上的標(biāo)準(zhǔn)。已有一些深度學(xué)習(xí)“加速器”支持了這種格式,比如Google的TPU。Intel的處理與在未來也可能支持。
The BF16 format is sort of a cross between FP16 and FP32, the 16- and 32-bit formats defined in the IEEE 754-2008 standard, also known as half precision and single precision.
BF16浮點數(shù)在格式,介于FP16和FP32之間。(FP16和FP32是 IEEE 754-2008定義的16位和32位的浮點數(shù)格式。)
BF16的指數(shù)位比FP16多,跟FP32一樣,不過小數(shù)位比較少。這樣設(shè)計說明了設(shè)計者希望在16bits的空間中,通過降低精度(比FP16的精度還低)的方式,來獲得更大的數(shù)值空間(Dynamic Range)。
IEEE 754 浮點數(shù)標(biāo)準(zhǔn)
IEEE 754標(biāo)準(zhǔn)的主要起草者是加州大學(xué)伯克利分校數(shù)學(xué)系教授William Kahan,他幫Intel公司設(shè)計了8087浮點數(shù)處理器(FPU),并以此為基礎(chǔ)形成了IEEE 754標(biāo)準(zhǔn),Kahan教授也因此獲得了1987年的圖靈獎。目前,幾乎所有計算機(jī)都采用IEEE 754標(biāo)準(zhǔn)表示浮點數(shù)。
在IEEE 754中,定義了兩種浮點數(shù)格式:32位單精度和64位雙精度。
IEEE 754浮點數(shù)格式
(單精度和雙精度都有一個固定的1bit符號位,因此,浮點數(shù)不存在unsigned這個概念,都是有符號的)
IEEE 754 的規(guī)定:
32位單精度格式中包含1bit符號位s,8bit階碼e,23bit尾數(shù)f;
64位雙精度格式中包含1bit符號位s,11bit階碼e和52bit尾數(shù)f;
基數(shù)隱含為2;(基數(shù)越大,浮點數(shù)能夠表示的范圍越大,但是精度越低,數(shù)變得更稀疏,選擇2作為隱含的基數(shù),就是為了精度,并通過雙精度來提高表示范圍)
尾數(shù)f用原碼表示,第一位總是1,因而可在尾數(shù)中省略第一位的1,稱為隱藏位,這樣使得單精度格式的23bit尾數(shù)實際表示了24bit有效數(shù)字,雙精度格式的52bit的尾數(shù)實際上表示了53bit有效數(shù)字。IEEE 754規(guī)定隱藏位1的位置在小數(shù)點之前。
階碼用移碼表示,但偏置常數(shù)并不是通常n位移碼所用的2(n-1),而是2(n-1)-1;因此,單精度浮點數(shù)偏置常數(shù)為127,雙精度浮點數(shù)偏置常數(shù)為1023。因為尾數(shù)f中有一位在小數(shù)點之前的1的隱藏位中,所以,如果尾數(shù)換成用等值的純小數(shù)表示的話,階碼就需要加1,相當(dāng)于偏置常數(shù)為128和1024。這樣做帶來兩個好處:
(1)尾數(shù)可表示的位數(shù)多了一位,因而使浮點數(shù)的精度更高;
(2)階碼的可表示范圍更大,因而使浮點數(shù)范圍更大。例如:對于單精度浮點數(shù)格式,其階碼為8位,當(dāng)偏置常數(shù)用128時,最大機(jī)器碼11111111對應(yīng)的值是255-128=127,當(dāng)偏置常數(shù)用127時,其對應(yīng)的值為255-127=128。顯然,偏置常數(shù)采用127時,階碼的范圍更大。
雖然零有+0和-0,一般情況下,兩者是等效的。
浮點數(shù)的表示范圍和非規(guī)劃數(shù):
從上面的知識可以看出,浮點數(shù)也是由范圍的,雙精度的范圍比單精度呀高。
在計算機(jī)表示整數(shù)的概念里面,有一個溢出的概念,overflow。浮點數(shù)同樣有益處的概念,不過浮點數(shù)的溢出稍微復(fù)雜一點,浮點數(shù)一共有4個溢出區(qū)域:正上溢,正下溢,負(fù)下溢,負(fù)上溢。
在IEEE 754標(biāo)準(zhǔn)中,非規(guī)格化數(shù)(小數(shù)點前固定是0)就是用來填補(bǔ)正下溢和負(fù)下溢這兩個接近0的空間。
當(dāng)計算結(jié)果非常小的時候,已經(jīng)小于規(guī)格化數(shù)(小數(shù)點前固定是1)能夠表示的最小值,這時的計算采用“逐級下溢”的方式:
當(dāng)運算結(jié)果的階碼太小,比最小能表示的階碼還小,即小于-126或小于-1022時,尾數(shù)右移,價碼加1,如此循環(huán)直到尾數(shù)為0或階碼達(dá)到可表示的最小值(尾數(shù)不能為全0,實際看到的效果是,階碼是0,f不等于0,但是f一直在右移,左邊0 的個數(shù)越來越多)。
浮點數(shù)的密度問題:
對于n為二進(jìn)制編碼,所能表示的不同的數(shù)據(jù)最多有2^n個,因此,浮點數(shù)雖然表示范圍擴(kuò)大了,但與定點數(shù)相比,并沒有能夠表示更多的數(shù)。實際上,只是這些數(shù)在數(shù)軸上朝正負(fù)兩個方向在更大的范圍內(nèi)散開,在數(shù)軸上的分布變稀疏了。定點數(shù)分布是等距且緊密的,而浮點數(shù)分布是不等距且稀疏的,越遠(yuǎn)離原點越稀疏。
下面這段文字,很好的解釋了浮點數(shù)的密度問題,以及非規(guī)格化數(shù)帶來的范圍變化:
浮點數(shù)的密度問題
雙精度浮點數(shù)擴(kuò)展:
IEEE 754規(guī)定,雙精度擴(kuò)展格式必須至少具有64位有效數(shù)字,并總共占用至少79位,但沒有規(guī)定其具體的格式,處理器廠家可以選擇符合該規(guī)定的格式。
例如:Intel x86 FPU采用80位雙精度擴(kuò)展格式,包含4個字段:1個符號位,15位階碼(偏置常量為16383),一位顯示首位有效位(explicit leading significant bit)和63位尾數(shù)。Intel采用的這種擴(kuò)展浮點數(shù)格式與IEEE 754規(guī)定的格式有一個重要的區(qū)別,它沒有隱藏位,有效位數(shù)共64位。Intel 安騰FPU采用82位擴(kuò)展精度。
又如:SPARC和Power PC處理器中采用128位擴(kuò)展雙精度浮點數(shù)格式,包含一位符號位,15位階碼(偏置常量為16383),和112位尾數(shù),采用隱藏位,所以有效位數(shù)為113位。
浮點數(shù)在C語言中的表示:
float表示單精度;
double表示雙精度;
long double表示擴(kuò)展雙精度(長度和格式隨編譯器和處理器類型的不同而有所不同)。
總結(jié)
- 上一篇: Lidar激光雷达市场
- 下一篇: GPU特征处理技术