數據類型概述


數據類型概述

int、int16、int32、int64、float、float16、float32、float64

在做模型量化的時候,經常遇到這幾個類精度表示,做下記錄:

 

 

 bits:位數

bytes:字節 1bytes = 8 bits

單精度用小數用23位存儲,加上默認的小數點前的1為1,2^(23+1) = 16777216.

因為10^7<16777216<10^8,所以說單精度浮點數的有效位數是7位。

雙精度的小數位數是52位存儲,2^(52+1) = 9007199254740992. 

因為10^16<9007199254740992<10^17,所以雙精度的有效位數是16位。

float16/32/64對神經網絡計算的影響

神經網絡的計算,或者說深度學習的計算,全都是浮點數。浮點數的類型分16/32/64(128位的不再考慮范圍內,numpy和python最大只到float64),選擇哪一種浮點數類型,對神經網絡的計算有不同的影響。

(1)目前業界深度學習的標准是BF16,一種16位的浮點數,據說Google的TPU已經支持,未來Intel的芯片也會支持;

(2)我們在一般計算上的,通過numpy得到的16位浮點數,是FP16,不是BF16FP16是IEEE754-2008的標准;這兩個標准,在能夠表示的數值的范圍上有區別;

(3)對於內存的影響:float64占用的內存是float32的兩倍,是float16的4倍;比如對於CIFAR10數據集,如果采用float64來表示,需要60000*32*32*3*8/1024**3=1.4G,光把數據集調入內存就需要1.4G;如果采用float32,只需要0.7G,如果采用float16,只需要0.35G左右;占用內存的多少,會對系統運行效率有嚴重影響;(因此數據集文件都是采用uint8來存在數據,保持文件最小)

(4)采用numpy的float16,即FP16,來計算深度學習,容易出現runtime warning;因為精度不夠,更容易在計算過程中,產生極限值;(也許有辦法解決這個問題,比如進一步縮小初始化的weights和bias)

(5)如果采用numba來進行計算加速,要求所有計算的數據類型要保持一致;如果不加速,numpy在計算過程中,會自動upcast到數據精度更大的類型上去,這個問題要通過仔細寫代碼來規避;

(6)如果做gradient check,即通過比較網絡計算的梯度和數學定義的方式計算出來的梯度來判斷代碼是否正確,float32的精度可能都不夠,需要比較到小數點后6-8位;

(7)在沒有numba加速的情況下,如果是64位的CPU,float64的計算速度最快;因為對於float32和float16,CPU都需要多條指令來進行數據的轉移,沒有嚴格測試過,有可能float16是最慢的;

(8)基於以上事實,我自己的teapot庫,決定采用float32!並保持在整個計算過程中,全部參與計算的數據,都是float32,不會upcast的情況;並可通過一個全局可變常量,來控制浮點數類型的選擇,默認就是float32;

(9)也可以考慮數據集數據在內存中使用float16,而神經網絡的weights和bias使用float32,這樣在計算過程中,float16和float32並存,即減少了內存占用,也保持了一定的精度;不過這樣做,就無法采用numba加速;

深度學習與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.

深度學習促使了人們對新的浮點數格式的興趣。通常(深度學習)算法並不需要64位,甚至32位的浮點數精度。更低的精度可以使在內存中存放更多數據成為可能,並且減少在內存中移動進出數據的時間。低精度浮點數的電路也會更加簡單。這些好處結合在一起,帶來了明顯了計算速度的提升。

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格式的浮點數已經成為深度學習事實上的標准。已有一些深度學習“加速器”支持了這種格式,比如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浮點數在格式,介於FP16和FP32之間。(FP16和FP32是 IEEE 754-2008定義的16位和32位的浮點數格式。)

 

 

 BF16的指數位比FP16多,跟FP32一樣,不過小數位比較少。這樣設計說明了設計者希望在16bits的空間中,通過降低精度(比FP16的精度還低)的方式,來獲得更大的數值空間(Dynamic Range)。

IEEE 754 浮點數標准

IEEE 754標准的主要起草者是加州大學伯克利分校數學系教授William Kahan,他幫Intel公司設計了8087浮點數處理器(FPU),並以此為基礎形成了IEEE 754標准,Kahan教授也因此獲得了1987年的圖靈獎。目前,幾乎所有計算機都采用IEEE 754標准表示浮點數。

在IEEE 754中,定義了兩種浮點數格式:32位單精度和64位雙精度。

 

 

 IEEE 754浮點數格式

(單精度和雙精度都有一個固定的1bit符號位,因此,浮點數不存在unsigned這個概念,都是有符號的)

IEEE 754 的規定:

32位單精度格式中包含1bit符號位s,8bit階碼e,23bit尾數f;

64位雙精度格式中包含1bit符號位s,11bit階碼e和52bit尾數f;

基數隱含為2;(基數越大,浮點數能夠表示的范圍越大,但是精度越低,數變得更稀疏,選擇2作為隱含的基數,就是為了精度,並通過雙精度來提高表示范圍)

尾數f用原碼表示,第一位總是1,因而可在尾數中省略第一位的1,稱為隱藏位,這樣使得單精度格式的23bit尾數實際表示了24bit有效數字,雙精度格式的52bit的尾數實際上表示了53bit有效數字。IEEE 754規定隱藏位1的位置在小數點之前。

階碼用移碼表示,但偏置常數並不是通常n位移碼所用的2^(n-1),而是2^(n-1)-1;因此,單精度浮點數偏置常數為127,雙精度浮點數偏置常數為1023。因為尾數f中有一位在小數點之前的1的隱藏位中,所以,如果尾數換成用等值的純小數表示的話,階碼就需要加1,相當於偏置常數為128和1024。這樣做帶來兩個好處:

(1)尾數可表示的位數多了一位,因而使浮點數的精度更高;

(2)階碼的可表示范圍更大,因而使浮點數范圍更大。例如:對於單精度浮點數格式,其階碼為8位,當偏置常數用128時,最大機器碼11111111對應的值是255-128=127,當偏置常數用127時,其對應的值為255-127=128。顯然,偏置常數采用127時,階碼的范圍更大。

 

 

 

 

 雖然零有+0和-0,一般情況下,兩者是等效的。

 浮點數的表示范圍和非規划數:

從上面的知識可以看出,浮點數也是由范圍的,雙精度的范圍比單精度呀高。

在計算機表示整數的概念里面,有一個溢出的概念,overflow。浮點數同樣有益處的概念,不過浮點數的溢出稍微復雜一點,浮點數一共有4個溢出區域:正上溢,正下溢,負下溢,負上溢

在IEEE 754標准中,非規格化數(小數點前固定是0)就是用來填補正下溢和負下溢這兩個接近0的空間。

當計算結果非常小的時候,已經小於規格化數(小數點前固定是1)能夠表示的最小值,這時的計算采用“逐級下溢”的方式:

當運算結果的階碼太小,比最小能表示的階碼還小,即小於-126或小於-1022時,尾數右移,價碼加1,如此循環直到尾數為0或階碼達到可表示的最小值(尾數不能為全0,實際看到的效果是,階碼是0,f不等於0,但是f一直在右移,左邊0 的個數越來越多)。

 浮點數的密度問題:

對於n為二進制編碼,所能表示的不同的數據最多有2^n個,因此,浮點數雖然表示范圍擴大了,但與定點數相比,並沒有能夠表示更多的數。實際上,只是這些數在數軸上朝正負兩個方向在更大的范圍內散開,在數軸上的分布變稀疏了。定點數分布是等距且緊密的,而浮點數分布是不等距且稀疏的,越遠離原點越稀疏。

下面這段文字,很好的解釋了浮點數的密度問題,以及非規格化數帶來的范圍變化:

 

 

 浮點數的密度問題

 雙精度浮點數擴展:

IEEE 754規定,雙精度擴展格式必須至少具有64位有效數字,並總共占用至少79位,但沒有規定其具體的格式,處理器廠家可以選擇符合該規定的格式。

例如:Intel x86 FPU采用80位雙精度擴展格式,包含4個字段:1個符號位,15位階碼(偏置常量為16383),一位顯示首位有效位(explicit leading significant bit)和63位尾數。Intel采用的這種擴展浮點數格式與IEEE 754規定的格式有一個重要的區別,它沒有隱藏位,有效位數共64位。Intel 安騰FPU采用82位擴展精度。

又如:SPARC和Power PC處理器中采用128位擴展雙精度浮點數格式,包含一位符號位,15位階碼(偏置常量為16383),和112位尾數,采用隱藏位,所以有效位數為113位。

浮點數在C語言中的表示:

float表示單精度;

double表示雙精度;

long double表示擴展雙精度(長度和格式隨編譯器和處理器類型的不同而有所不同)。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM