近日,F(xiàn)acebook 發(fā)布文章,介紹了一項新研究,該研究提出了一種使人工智能模型高效運行的方法,從根本上優(yōu)化了浮點運算。
近年來,計算密集型的人工智能任務推動了各種用于高效運行這些強大的新型系統(tǒng)的定制化硬件的出現(xiàn)。我們采用浮點運算來訓練深度學習模型,如 ResNet-50 卷積神經(jīng)網(wǎng)絡。但是,由于浮點數(shù)十分消耗資源,真正部署的人工智能系統(tǒng)通常依賴于使用 int8/32 數(shù)學運算的少數(shù)幾個流行的整型量化技術。
Facebook 開發(fā)了一種使人工智能模型高效運行的方法。基于 70 多年前計算機科學發(fā)展初期的思想,該方法從根本上優(yōu)化了浮點運算。
Facebook 對浮點數(shù)進行了徹底的改造,使它比 int8/32 數(shù)學運算的效率高出 16%。該方法用于卷積神經(jīng)網(wǎng)絡時,網(wǎng)絡仍能達到很高的準確率,此外它還具備以下優(yōu)勢:
該技術可以提高人工智能研發(fā)的速度。當該方法被應用于人工智能模型訓練中使用的更高精度的浮點數(shù)時,模型訓練的效率能夠提高 69%。
如今,模型通常使用浮點數(shù)進行訓練,但是之后它們必須轉(zhuǎn)換成更高效的、可以部署到生產(chǎn)環(huán)境中的量化格式。如果使用該方法,在部署模型時就不需要重新訓練或重新學習。這樣一來,人工智能開發(fā)者就可以更容易地部署高效的新模型。
現(xiàn)在的整型量化方法正變得越來越復雜。在某些情況下,這些方法可能對某些特定任務「過擬合」(因此不能維持通用性)。高效的通用浮點運算可以在保持準確率的情況下避免過擬合問題。
論文「Rethinking float point for deep learning」詳細介紹了 Facebook 的這項技術。開發(fā)使用這些新技術執(zhí)行浮點運算的新芯片需要耗費一定的時間。但這樣做可能得到的好處包括使數(shù)據(jù)中心的人工智能計算速度更快,在移動設備上獲得更好的人工智能運算性能的低功耗設計,以及在進行較少的軟件更改的情況下以更簡單、迅速的方法達到性能目標。摩爾定律正在逐漸減速,而「暗硅」(dark silicon)時代即將到來。持續(xù)的性能提升需要重新考慮幾十年前的底層硬件設計決策(比如 IEEE 754 浮點標準),以及在合適的情況下使用數(shù)學近似(mathematical approximation)。尤其是神經(jīng)網(wǎng)絡的出現(xiàn)成為對它們進行重新評估的絕佳契機,因為神經(jīng)網(wǎng)絡對數(shù)值運算的變化和實驗具有相當大的容忍度。
Facebook 為 ASIC/FPGA 做出的硬件設計和為評估編寫的 C++/PyTorch 代碼已經(jīng)向人工智能社區(qū)開放。
地址:http://github.com/facebookresearch/deepfloat
傳統(tǒng)的浮點運算
眾所周知,浮點數(shù)可以在合理的計算機存儲空間中表示大小實數(shù),其使用的系統(tǒng)與科學計數(shù)法大體相似。這種格式可用于以固定寬度的編碼和基數(shù)(通常是二進制)表示 1,000,000 和 0.0625 這樣的值。需要注意的是,浮點數(shù)只能精確地表示有限的實數(shù),因為我們擁有的比特位數(shù)是有限的。所有其他值都可以用一種四舍五入的形式表示為最接近的可以表示出來的浮點值。
傳統(tǒng)的二進制浮點格式包含符號(sign)、尾數(shù)(significand)和指數(shù)(exponent)。符號位表示數(shù)字是正的還是負的。尾數(shù)(其小數(shù)部分通常稱為尾數(shù))是形如 0.bbb... 或 1.bbb... 的二進制定點數(shù),其中小數(shù)部分 bbb… 由若干二進制位在基數(shù)點之后表示的。(在十進制運算中,基數(shù)點也稱為小數(shù)點,將整數(shù)與小數(shù)部分分開。)指數(shù)是一個有符號整數(shù),它表示尾數(shù)需要乘以 2 的多少次冪。尾數(shù)有前導二進制 1(1.bbb…)的情況是規(guī)格化的,而尾數(shù)有前導二進制 0(0.bbb…)的情況是非規(guī)格化的(二者可以相互轉(zhuǎn)化)。現(xiàn)代計算機中常用的 IEEE 754 浮點標準有規(guī)格化和非規(guī)格化兩種尾數(shù)表示方法。尾數(shù)的前導位不需要被顯式存儲;在 IEEE 754 中,指數(shù)域決定前導位是 1 還是 0。
下圖顯示了以 16 位 IEEE 754 的 binary16 半精度浮點數(shù)對 -1.625 進行的編碼,它具有固定大小的 5 位指數(shù)和 10 位的尾數(shù)部分。IEEE 指數(shù)的偏置值為 -15,因此下面編碼的指數(shù) 15 實際上表示(15-15)即 0。
人工智能運算的現(xiàn)狀和未來
為許多人工智能系統(tǒng)賦能的神經(jīng)網(wǎng)絡通常使用 32 位 IEEE 754 binary32 單精度浮點數(shù)進行訓練。將位數(shù)降低到 16 位(半精度浮點數(shù)或類似 bfloat16 的格式)會獲得一定的性能提升,但與同樣位寬整數(shù)運算的效率相比,它仍然相形見絀。這些浮點變量可以很容易地使用原來的 32 位浮點神經(jīng)網(wǎng)絡數(shù)據(jù),但要將整數(shù)量化到 8 位(或更少)常常需要學習量化參數(shù)并對模型進行再訓練。許多 int8/32 量化方案可以像原始的浮點模型達到同樣的準確率,但是它們也可能在處理任務時發(fā)生過擬合現(xiàn)象,從而無法在 ImageNet 驗證集以外的任務上保證其準確率。
但是對于今天的計算機運算來說,除了整數(shù)、定點或浮點運算外,還有許多其他的選擇。其中一些方法可以追溯到 20 世紀 50 年代:
非線性尾數(shù)映射
二進制隨機數(shù)
熵編碼
Facebook 使用這一思路創(chuàng)造出了一種浮點運算,其性能超過 int8/32。該方法的實現(xiàn)與目前硬件中的浮點運算及其變體(如非規(guī)格化的清零行為或字大小/字段位寬度變化,如 bfloat16 或 minifloat)有很大的區(qū)別。與 int8/32 量化不同的是,該實現(xiàn)仍然是一種通用的浮點運算,可以直接對其運算結(jié)果進行解釋。
實現(xiàn)更高效浮點運算的關鍵
為了開發(fā)一種高效浮點運算的新方法,F(xiàn)acebook 研究人員認真分析了硬件浮點數(shù)低效的各種原因:
字(word)大小過大:有很大一部分算力被用于移動數(shù)據(jù):從外部的 DRAM 到內(nèi)部的 SRAM,從 SRAM 到寄存器,或從寄存器到寄存器(觸發(fā)器)。浮點的字大小越大,消耗的算力就越多。
通用的定點數(shù)機制:尾數(shù)是定點數(shù),定點數(shù)的加法器、乘法器和除法器是算術運算所必需的。浮點類型的精度(尾數(shù)長度)越高,這些組件就越大。硬件乘法器和除法器通常比硬件加法器更消耗資源(芯片面積、功耗和延遲)。
通用的浮點數(shù)機制:該機制處理基數(shù)點的「浮點」,因此是浮點表示法的一部分。例如,用于重新規(guī)格化的前導零(LZ)計數(shù)器、用于尾數(shù)對齊的移位器和舍入邏輯。浮點精度也對該機制所使用的硬件資源有很大的影響。
IEEE 754 的專有機制:這為 IEEE 754 標準中實現(xiàn)的逐漸下溢提供了非規(guī)格化的支持,并提供了額外的移位器、LZ 計數(shù)器和尾數(shù)重新規(guī)格化所需要的其他修改。非規(guī)格化的處理增加了大多數(shù)浮點操作的復雜性和計算開銷。
減小字大小
縮小字(word)的大小可以顯著地提升算力的利用率。我們可以嘗試將 32 位數(shù)據(jù)壓縮為 8 位或 16 位。典型的浮點數(shù)固定大小字段編碼迫使我們做出困難的選擇,是減少動態(tài)范圍(指數(shù))還是減小精度(尾數(shù)),而我們需要的是二者的折中。
我們可以用不同的方式來處理這種權(quán)衡。浮點數(shù)本身就是(無限精度)實數(shù)的量化形式。適用于見過的數(shù)據(jù)分布的量化器在數(shù)據(jù)復制的過程中誤差會較小。對于在通用計算機上遇到的數(shù)據(jù)分布,我們通常沒有太多的先驗知識。然而,神經(jīng)網(wǎng)絡的分布在實際中是接近高斯分布的,有時還會受到批歸一化等過程的控制。標準浮點數(shù)盡可能保證尾數(shù)在 10^-5 的精度與在 10^5 的精度相當,但大多數(shù)神經(jīng)網(wǎng)絡在一個相對較小的范圍內(nèi)(如 -10.0 到 10.00)執(zhí)行計算。這個范圍內(nèi)的小數(shù)字(例如 0.0001)會被頻繁使用,而大數(shù)字的使用頻率較低。理想情況下,我們可以改變量化器,在需要的地方提供更高的精度,并保持一定的小數(shù)字動態(tài)范圍。
縮減(tapered)浮點數(shù)可以幫助實現(xiàn)這些目標并減小字的大小。Gustafson 提出的 Posit 方法是一種效果很好的縮減形式。Posit 使用無前綴編碼將指數(shù)編碼為可變位數(shù),其余部分為尾數(shù)。它在+/-1.0 左右將精度最大化,而在 0 或+/-∞ 處的精度則較低。它的壓縮和擴展都是有損的,以損失某些地方的精度為代價來保證在其他地方的動態(tài)范圍。因此,與 IEEE 風格的浮點數(shù)相比,它可以提供更高的精度(在某些地方)和更大的動態(tài)范圍。當我們不知道待處理數(shù)據(jù)的數(shù)據(jù)分布時,posit 可以擴展到其他無前綴編碼中(比如霍夫曼編碼)。
定點數(shù)機制
我們可以設法避免在尾數(shù)上進行的乘法和除法運算。尾數(shù)可以被看作是小數(shù)部分的映射 f(x),它將取值范圍在 [0, 1) 間的定點數(shù) x 映射到 [1, 2) 中。(這種方法在 Lindstrom 等人 2018 年的論文《Universal Coding of the Reals: Alternatives to IEEE Floating Point》中有詳細的介紹。)在典型的規(guī)格化浮點運算中,f(x) 是仿射函數(shù) 1+x(我們稱之為線性域數(shù))。
當 f(x) = 2^x 時,我們可以使用對數(shù)數(shù)字系統(tǒng)(LNS)將乘法和除法變成加法和減法。不過,添加 LNS 需要大量的硬件查找表來計算兩個對數(shù)域數(shù)的和或差。這是采用 LNS 的一個主要問題,因為這些表可能比硬件乘法器更難以處理。注意,典型的浮點數(shù)已經(jīng)是對數(shù)(指數(shù))和線性(尾數(shù))表示的組合,但是 LNS 表示完全是基于對數(shù)的。
浮點數(shù)機制
在計算機線性代數(shù)中,有效的操作是「乘加」:計算值「c」和 a 與 b 乘積「a x b」的和,得到「c + a x b」。通常情況下,對于 ResNet-50 等模型,單個累加器中可能會對數(shù)千個這樣的乘積求和;在部署過程中運行一個模型時涉及數(shù)百萬獨立累加操作,而訓練模型時則需要進行數(shù)以億計的累加操作。
浮點融合乘加(FMA)是一種常見的乘加方法,它能夠減小誤差,但它比標準的浮點加法器或乘法器復雜得多。一種稱為 Kulisch 累加的技術可以避免 FMA 的復雜操作。類似的操作在第一臺可編程數(shù)字計算機 Konrad Zuse Z3 上被采用過。Gustafson 也在他最近的浮點研究中提出了 Kulisch 累加的標準用法(https://www.crcpress.com/The-End-of-Error-Unum-Computing/Gustafson/p/book/9781482239867)。其思想不是在浮點運算中進行累加,而是在定點運算中維護一個運行時的和(running sum),這個和需要足夠大以避免下溢或溢出。與浮點加法不同的是,Kulisch 累加可以精確地表示任意數(shù)量的浮點值的和。不論順序如何,求和方法都是滿足結(jié)合率并可復現(xiàn)的。在完成所有求和工作之后,我們通過尾數(shù)對齊和舍入將其轉(zhuǎn)換回浮點數(shù)。
下圖顯示了一個累加步驟的示例。Kulisch 累加器當前包含值 35.5,我們將其與 0.84375 相加,表示為線性域浮點值。這個被求和的浮點值可能以前來自于標量值的乘積,或者只是我們希望累加的單個值。在浮點指數(shù)的基礎上,通過對齊尾數(shù)的基數(shù)點,將浮點數(shù)轉(zhuǎn)換為定點數(shù)。該轉(zhuǎn)換使用了一個調(diào)整因子,它是累加器最多尾數(shù)位(在下面的例子中是 6)的有效指數(shù)。然后將對齊后的尾數(shù)和累加器與進位相加。(為簡單起見,此處省略了 Kulisch 累加器可能支持下溢和溢出所需的額外精度位)。在高于 32 位的浮點數(shù)中,Kulisch 累加的代價很高,因為累加器、移位器和加法器的大小可能大于 500 位,但是對于較小的浮點類型來說,它是非常實用的。
Kulisch 累加不能直接用于對數(shù)域求和。但是,正如 Kulisch 累加以不同于參數(shù)(浮點數(shù))的形式(定點數(shù))執(zhí)行求和運算一樣,這里也可以采用類似的方法,因此我們不需要一個巨大的 LNS 和/差查找表。我們可以在線性域中對 log 值取近似,在線性域中做 Kulisch 累加,然后在所有求和工作都完成時將其轉(zhuǎn)換回 log 域。這種方法對于通用線性代數(shù)非常有效,因為向量內(nèi)積需要在累加器中多次重復求和。
IEEE 754 的專有機制
有助于減小字大小的 posit 編碼也避免了這個問題,因為 posit 的尾數(shù)總是規(guī)格化的。緩慢的下溢立刻防止了精度下降,而不是逐漸緩解精度下降,這在 IEEE 754 非規(guī)格化表示中是通過尾數(shù)部分中前導一的位置解決的。Posit 逐漸減小到更小的數(shù)字上,導致在指數(shù)上使用尾數(shù)部分的位,從而擴展了動態(tài)范圍并降低了精度。Posit 的縮減(taper)技術在功能上類似于非規(guī)格化的逐漸下溢,但是沒有重新規(guī)格化尾數(shù)的開銷。Posit 緩慢溢出也以類似的方式支持縮減。
融合這些方法
為了獲得性能的提升,研究人員考慮將這四種技術結(jié)合起來。對數(shù)域表示避免了硬件乘法器,我們將 posit 用于對數(shù)。為了與 int8/32 抗衡,研究人員考慮使用一種稱為 (8, 1, alpha, beta, gamma) 對數(shù)的 8-bit 格式,其中 (8,1) 是 posit 參數(shù)。這種編碼在最大和最小正值之間提供了超過 1600 萬:1 的比率,同時在 1.0 左右保留了 4 位(對數(shù)域)精度,所有這些都是用 8 位表示的(只有 256 個可能的值)。alpha、beta 和 gamma 值可以控制對數(shù)到線性以及線性到對數(shù)的轉(zhuǎn)換準確率。
如上所述,我們在線性域中執(zhí)行對數(shù)域的求和。這個結(jié)果是非常近似的,但與 FMA 不同的是,對于序列和,這里沒有 Kulisch 累加的線性域誤差。我們稱這種技術為 ELMA,或精確的對數(shù)線性乘加。對數(shù)域乘法是精確的,所有的線性域求和過程也都是精確的,但是對數(shù)到線性的轉(zhuǎn)換是近似的,返回的線性到對數(shù)的轉(zhuǎn)換也是近似的。這種折中在實踐中是可以接受的。
硬件查找表用于轉(zhuǎn)換,但它們要比 LNS 加法所需表小得多。使用更大的 alpha、beta 和 gamma 參數(shù)會得到更精確的結(jié)果,但也會消耗更多的芯片面積和功耗。與浮點型 FMA 相比,ELMA 乘加電路及其核心更加簡單。它使用三個加法器、一個查找表和一個移位器就完成了大部分工作:
直接替代方法
與 int8/32 不同,F(xiàn)acebook 研究人員針對神經(jīng)網(wǎng)絡的 8 位對數(shù)格式不需要學習量化參數(shù)、激活采樣或?qū)υ季W(wǎng)絡進行再訓練。只需要獲取網(wǎng)絡(如 ResNet-50)的 32 位浮點參數(shù),然后使用「取與該參數(shù)最近的偶數(shù)」的規(guī)則對其進行轉(zhuǎn)換。使用 posit 編碼可以在如此小的類型中保證所需的動態(tài)范圍和精度。
使用 ELMA 的 (8, 1, 5, 5, 7) 對數(shù)與原始的 ResNet-50 的運算方法相同,在 ImageNet 驗證集上獲得了 75.23% 的 top-1 準確率和 92.66% 的 top-5 準確率,分別比原始網(wǎng)絡的準確率降低了 0.9% 和 0.2%。這些結(jié)果與許多現(xiàn)有的 int8/32 量化方法類似。在 int8/32 量化中使用的調(diào)優(yōu)訓練和模型調(diào)整可以進一步提高該方法的性能,但是這里基線的結(jié)果是在對軟件進行最少修改的情況下實現(xiàn)的。所有的數(shù)學仍然在通用浮點運算中執(zhí)行,使用壓縮編碼作為量化器。ELMA 設計也可以被用于非線性代數(shù)任務(如多項式計算)。
硬件效率
研究人員使用一種商用 28 納米 ASIC 工藝技術將 (8, 1, 5, 5, 7) 對數(shù)的 ELMA 以 int8/32 乘加 0.96 倍的功耗作用于獨立的處理單元(PE)。在一個完整的 32×32 矩陣乘法的脈動陣列中,使用對數(shù) ELMA 處理單元方案的功耗是使用 int8/32 處理單元版本的 0.865 倍。該方案之所以能夠省電主要是因為取消了硬件乘法器。
擴展到 16 位后,即使沒有非規(guī)格化的支持(這在很大程度上降低了 IEEE 754 的效率),這種方法使用的功耗是 IEEE 754 半精度 FMA 的 0.59 倍,而使用的芯片面積是后者的 0.68 倍,同時還降低了延遲。得益于這些 16 位浮點數(shù)上的性能提升,我們可以在相同的時間內(nèi)支持更復雜的人工智能模型的訓練。然而,與 32 位的 IEEE 754 單精度 FMA 相比,ELMA 并沒有更加有效,這是由于 Kulisch 累加器過于龐大(增加了加法器/移位器尺寸和觸發(fā)器功率),而且禁止使用從對數(shù)到線性的查找表。
未來的工作
實現(xiàn)人工智能技術的極大發(fā)展需要計算效率的顯著提高,而這只有通過新方法才能實現(xiàn),而不僅僅是建立在舊方法的基礎上。例如,軟件仿真工作常常很慢,無法有效地在前沿的人工智能模型上測試新的運算方法。不幸的是,在 FPGA/ASIC 硬件上進行實驗比在軟件上還要困難得多,這使得這些潛在的提升空間在很大程度上沒有得到充分的開發(fā)。然而,如果開發(fā)出利用這些技術的新硬件,它將有利于廣泛的人工智能研究和應用。
Facebook 計劃研究硬件上的 16 位 ELMA 的設計,并將其在人工智能模型訓練和其他任務上的性能表現(xiàn)與 IEEE 754 半精度浮點數(shù)和 bfloat16 進行對比。這些新想法和數(shù)值近似方法并不總是適用的,但是人工智能提供了一個獨特的機會來探索它們的邊界,并幫助推翻人們關于硬件可能完成的任務的舊有看法。