<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          FP8 量化:原理、實(shí)現(xiàn)與誤差分析

          共 11948字,需瀏覽 24分鐘

           ·

          2022-11-01 15:34

          一、前言
          FP8 是 FP16 的衍生產(chǎn)物,它包含兩種編碼格式 E4M3 與 E5M2。對(duì)于 E4M3 而言,其包含 4 比特指數(shù)、3 比特底數(shù)、以及 1 比特符號(hào)位。
          E5M2 同理包含 5 比特指數(shù)位、3 比特底數(shù)、1 比特符號(hào)。在本文中,我們稱指數(shù)部分為 exponent,底數(shù)部分為 mantissa
          下圖展示了 FP32, FP16, FP8 的格式對(duì)比:

          圖1. FP 數(shù)據(jù)格式對(duì)比
          使用 FP8 數(shù)據(jù)格式,能夠有效地以在推理時(shí)提升效率,同時(shí)也可以使用 FP8 數(shù)據(jù)格式直接進(jìn)行訓(xùn)練,從而到達(dá) 16bit 訓(xùn)練的精度。在后續(xù)的內(nèi)容中 Nvidia 的開發(fā)者在常見模型中使用 FP8 數(shù)據(jù)格式進(jìn)行實(shí)驗(yàn),其實(shí)驗(yàn)結(jié)果可以媲美 FP16 的精度。

          二、FP8 數(shù)據(jù)格式
          在本節(jié)中,我們將向你介紹FP8的表示方法,以及使用FP8表示神經(jīng)網(wǎng)絡(luò)數(shù)據(jù)時(shí)的細(xì)節(jié)問題。

          2.1 浮點(diǎn)數(shù)表示法:

          • 在計(jì)算機(jī)中我們使用符號(hào)位、指數(shù)、底數(shù)三部分表示一個(gè)浮點(diǎn)數(shù)。符號(hào)位只占用1bit,用來表達(dá)數(shù)的正負(fù),0-表示整數(shù),1-表示負(fù)數(shù)。這也意味著在浮點(diǎn)數(shù)中0有兩種表達(dá)方式:

          二進(jìn)制的 (0 0000 000) 表示 FP8 中的正數(shù) 0
          二進(jìn)制的 (1 0000 000) 表示 FP8 中的負(fù)數(shù) 0
          • 接下來我們討論浮點(diǎn)表示中的指數(shù)部分:

          除符號(hào)位外浮點(diǎn)數(shù)具有一個(gè)指數(shù)部分,這也是其區(qū)別于定點(diǎn)數(shù)的地方。在 FP8 E4M3 格式中,我們具有4個(gè)比特用于表示指數(shù)。在(0 1000 000) 中,指數(shù)部分的 1000 為十進(jìn)制的 8,其對(duì)應(yīng)的十進(jìn)制數(shù)為:2^(8 - 7) * (1) = 2
          在浮點(diǎn)表示法當(dāng)中,指數(shù)部分總是會(huì)減去一個(gè)偏移量,對(duì)于FP8 E4M3 而言,這個(gè)偏移量為-7,這使得指數(shù)的表示范圍為[-7, 8]。對(duì)于 FP8 E5M2 而言,指數(shù)偏移量為 -15,指數(shù)表示范圍為[-15, 16]。
          特別地,我們規(guī)定當(dāng)指數(shù)部分全為1時(shí)的浮點(diǎn)值為無窮大,這一規(guī)定也適用于 FP16 與 FP32,是IEEE754標(biāo)準(zhǔn)的一部分。
          二進(jìn)制的 (0 11111 10) 在 FP8 E5M2 格式中表示 正無窮大
          二進(jìn)制的 (1 11111 00) 在 FP8 E5M2 格式中表示 負(fù)無窮大
          FP8 E4M3 不遵循 IEEE754 標(biāo)準(zhǔn),其在指數(shù)全為1時(shí)仍然可以表示有效數(shù)字,當(dāng)且僅當(dāng)指數(shù)與底數(shù)部分全為1時(shí),其表示無窮大。
          二進(jìn)制的 (0 1111 110) 在 FP8 E4M3 格式中表示 2^(15-7) * (1+1/2 + 1/4) = 448
          二進(jìn)制的 (1 1111 100) 在 FP8 E4M3 格式中表示 -2^(15-7) * (1+1/2) = 384
          二進(jìn)制的 (1 1111 111) 在 FP8 E4M3 格式中表示 負(fù)無窮大
          • 最后我們討論浮點(diǎn)數(shù)中的底數(shù)部分:

          圖2. 浮點(diǎn)數(shù)底數(shù)表示法
          在浮點(diǎn)數(shù)中,底數(shù)從高位到低位,分別表示2的負(fù)k次冪;對(duì)于E4M3格式,我們使用3個(gè)比特表示底數(shù),其分別對(duì)應(yīng)2的負(fù)1, 2, 3次冪(見上圖2)。對(duì)于E5M2格式,我們使用2個(gè)比特表示底數(shù),分別對(duì)應(yīng)2的負(fù)1, 2冪。浮點(diǎn)數(shù)的底數(shù)值轉(zhuǎn)換成十進(jìn)制時(shí),我們需要將所有底數(shù)位的數(shù)字相加,再額外加1。上圖2中,左邊的底數(shù)部分為: 1 + 1/2 + 1/8 = 1.625,右側(cè)的底數(shù)部分為 1+0.25 = 1.25。
          非規(guī)格化浮點(diǎn)數(shù):
          當(dāng)一個(gè)浮點(diǎn)數(shù)的指數(shù)部分全為0時(shí),其是一個(gè)非規(guī)格化浮點(diǎn)數(shù),此時(shí)其底數(shù)部分不再額外加1。
          (0 0000 000) 表示 2^(0-7) * 0,而非 2^(0-7) * 1
          (0 0000 001) 表示 2^(0-7) * 1/8

          2.2 數(shù)的浮點(diǎn)量化

          由于指數(shù)部分的存在,浮點(diǎn)量化與INT量化表現(xiàn)出了不一樣的性質(zhì),浮點(diǎn)量化的步長(zhǎng)是"可變"的。從圖像上來看,浮點(diǎn)量化器的量化步長(zhǎng)隨著指數(shù)部分的變大而變大。在本文中,我們以紅色表示FP8 E4M3的量化情況,藍(lán)色表示FP8 E5M2的量化情況,而綠色表示INT8的量化情況:

          圖3 浮點(diǎn)量化表示與整數(shù)量化表示
          FP8 E4M3的表示范圍為[-448, 448],INT8的表示范圍為[-128, 127];在圖3中的實(shí)驗(yàn)中,我們進(jìn)行INT8量化時(shí)額外地添加了縮放因子scale = 4.0,從而保證在[0, 500]范圍上三種方案都能夠比較良好地完成表示。

          圖4 浮點(diǎn)量化誤差隨數(shù)值變化而增大
          圖上的例子說明,INT的量化步長(zhǎng)是均勻的,總是以一定的步長(zhǎng)完成量化,這是一種均勻的量化。而浮點(diǎn)的量化則是非均勻的,隨著數(shù)值增大,其步長(zhǎng)也在逐漸變大。且E5M2的步長(zhǎng)變化較E4M3而言更加明顯。從另一個(gè)角度出發(fā),量化的誤差總是與步長(zhǎng)正相關(guān)的,因此FP8浮點(diǎn)量化相比于INT8而言,對(duì)于小數(shù)來說會(huì)更加精確,但對(duì)于大數(shù)則更不精確。

          2.3 FP32 到 FP8 的數(shù)據(jù)格式轉(zhuǎn)換

          FP8 E4M3 的表示范圍只有[-448, 448],對(duì)于一些應(yīng)用來說,這是無法完成表示的。因此我們也額外地在轉(zhuǎn)換過程中引入縮放因子 scale。FP32 向 FP8 的轉(zhuǎn)換過程可以表示為先除以尺度因子得到中間結(jié)果 Unscaled FP32,再由中間結(jié)果完成 FP32 到 FP8 的格式轉(zhuǎn)換。
          1. Unscaled FP32 = FP32 / scale

          2. FP8 = Convert(Unscaled FP32)

          下面我們討論Convert函數(shù)的執(zhí)行過程,我們將討論三種情況:
          1. 當(dāng) Unscaled FP32 數(shù)據(jù)已經(jīng)超出 FP8 的表示范圍,即 Unscaled FP32 的幅值大于 448,那么直接進(jìn)行截?cái)啵藭r(shí)為浮點(diǎn)上溢出。

          2. 當(dāng) Unscaled FP32 數(shù)據(jù)范圍在 FP8 的表示范圍內(nèi),且幅值大于 FP8 能夠表達(dá)的最小值,此時(shí)需要移去多余的底數(shù)位,并對(duì)底數(shù)進(jìn)行四舍五入。

          3. 當(dāng) Unscaled FP32 數(shù)據(jù)小于 FP8 能夠表達(dá)的最小值,此時(shí)浮點(diǎn)下溢出,只需判斷能否四舍五入為 (0 0000 001),若不能則直接為0。

          以程序?qū)崿F(xiàn),代碼如下:
          union FPConvertHelper {
              float value;
              uint32_t data;
          };

          template<typename Dtype, typename Stype, typename Otype>
          __device__ __inline__
          float QuantizeScalarFloating(
              const Dtype value, const Stype scale, const Otype offset,
              const int exponent, const int mantissa,
              const float clip_min, const float clip_max, 
              const Rounding rounding){
              /**
               * PPQ Quantization Function implementation.
               * This function convert an float value to low-precision float
               */
              FPConvertHelper helper; FPConvertHelper rounding_helper;
              helper.value = static_cast<float>(value) / scale;
              // Following code will Split float32 into sign, exp, mantissa
              /* IEEE 754 Standard: 1 bit sign, 8 bit exponent, 23 bit mantissa */

              /* In binary 10000000 00000000 00000000 00000000 = 0x80000000 in Hex */
              /* In binary 01111111 10000000 00000000 00000000 = 0x7F800000 in Hex */
              /* In binary 00000000 01111111 11111111 11111111 = 0x007FFFFF in Hex */

              /* Tool: https://www.h-schmidt.net/FloatConverter/IEEE754.html */

              uint32_t fp32_sign    = helper.data & 0x80000000;
              int32_t fp32_exp      = helper.data & 0x7F800000;
              int32_t fp32_mantissa = helper.data & 0x007FFFFF;
              int32_t exponent_min  = -(1 << (exponent - 1)) + mantissa;
              int32_t exponent_max  = (1 << (exponent - 1));

              // Float Overflow.
              if (value > clip_max) return clip_max;
              if (value < clip_min) return clip_min;

              // Following code will process Float underflow
              /* Float underflow means fp32_exp is smaller than exponent_min          */
              /* Where exponent_min is the minimum exponent value of quantized float. */
              /* For FP8 E4M3, the minimum exponent value should be -9.               */
           if (((fp32_exp >> 23) - 127) < exponent_min){
                  if (((fp32_exp >> 23) - 127) == (exponent_min - 1)){
                      // there is a chance to round
                      rounding_helper.data = (fp32_mantissa & 0x007FFFFF) + 0x3F800000;
                      if (_round2int(rounding_helper.value - 1, rounding)) {
                          helper.data = fp32_sign + ((exponent_min + 127) << 23) + (1 << (23 - mantissa));
                          return helper.value;
                      }
                  }
                  return 0.0f;
           }
              if ((fp32_exp >> 23) - 127 > exponent_max){
                  if (fp32_sign) return clip_min;
                  else return clip_max;
              }

              /* high precision mantissa convert to low precision mantissa requires rounding                         */
              /* Here we apply a tricky method to round mantissa:                                                    */
              /* We create another floatwhich sign = 0, exponent = 127, mantissa = fp32_mantissa << (23 - mantissa) */
              /* Then we directly round this float to int, result here is what we want, you can prove it by yourself */
              rounding_helper.data = ((fp32_mantissa << (mantissa)) & 0x007FFFFF) + 0x3F800000;
              uint32_t round_bit = _round2int(rounding_helper.value - 1, rounding);

              // process mantissa
              fp32_mantissa = ((fp32_mantissa >> (23 - mantissa)) + round_bit) << (23 - mantissa);
              helper.data = fp32_sign + fp32_mantissa + fp32_exp;

              return CLIP<float>(helper.value + offset, clip_min, clip_max);
          }

          三、浮點(diǎn)量化誤差分析
          FP8 具有更大的表示范圍,但在一定范圍內(nèi),其表示精度相較 INT8 更差。為了闡明這一問題,我們從正太分布中隨機(jī)抽樣 1000 萬個(gè)數(shù)字,分別使用 FP8 E4M3, FP8 E5M2, INT8 完成量化。
          在三者的量化中,我們都應(yīng)用縮放因子來調(diào)整量化效果。
          通過不斷調(diào)整縮放因子的大小,我們可以得到量化的誤差隨縮放因子的變化情況,這反映了一些有意義的問題:

          圖5 量化誤差隨縮放因子的變化情況
          我們認(rèn)為在選取了合適的縮放因子時(shí),INT8的量化精度高于FP8,兩者之間的誤差幾乎相差一個(gè)數(shù)量級(jí)。這是INT8量化的優(yōu)勢(shì),它更加精確。FP8將提供更好的寬容性,在scale的選取上不需要花費(fèi)太多力氣,F(xiàn)P8的量化對(duì)scale的選擇不敏感。也就是說FP8的場(chǎng)景下,你幾乎可以不做 calibration 就完成網(wǎng)絡(luò)的量化。
          在之前的視頻中我們已經(jīng)闡述過這樣的觀點(diǎn):量化誤差是一個(gè)關(guān)于量化步長(zhǎng)的二次函數(shù),隨著scale的增大其誤差將很快發(fā)散。FP8的量化同樣遵循這個(gè)原理,但其表示范圍太過寬泛,它的誤差曲線是一個(gè)開口非常大的二次函數(shù),從圖上看它幾乎是平的。只有當(dāng)scale選取非常不合理時(shí),F(xiàn)P8的誤差才會(huì)呈現(xiàn)二次曲線的性質(zhì)。

          圖6 量化誤差隨縮放因子的變化情況
          在圖6中,我們進(jìn)一步擴(kuò)大scale的選取范圍,可以看到對(duì)于正太分布而言,scale=2 時(shí) FP8 E4M3 仍然有較高的量化精度,而此時(shí)int8的量化早已完全失效。同時(shí)FP8量化誤差曲線呈現(xiàn)明顯的周期性,讀者可以自行探索這一現(xiàn)象發(fā)生的原因。
          在這里,我們不想進(jìn)一步分析FP8的量化誤差公式,這些公式非常難算且沒有太多意義。在后續(xù)更新的視頻內(nèi)容中我們可能會(huì)對(duì)這一部分內(nèi)容有更深入的討論。我們只給出一個(gè)有參考意義的結(jié)果。下表反映了對(duì)于正太總體而言,以最優(yōu)的scale完成量化,F(xiàn)P8與INT8的量化誤差期望。其中量化誤差的衡量方式為量化噪聲的能量除以信號(hào)自身的能量,可以看到INT8的誤差期望是要遠(yuǎn)小于FP8的。
          FP8 E4M3FP8 E5M2INT8
          0.06%0.2%0.008%

          四、實(shí)驗(yàn)部分
          在這里我們給出兩部分實(shí)驗(yàn)結(jié)果,第一部分來自于 Nvidia 的論文,在論文中研究者使用了訓(xùn)練中量化的技術(shù),從而訓(xùn)練出了一批適合于FP8的網(wǎng)絡(luò)模型,并與直接使用FP16完成訓(xùn)練的模型進(jìn)行了精度對(duì)比,實(shí)驗(yàn)結(jié)果如下:

          圖7 Nvidia QAT 實(shí)驗(yàn)結(jié)果
          浮點(diǎn)量化的訓(xùn)練過程是簡(jiǎn)單的,由于浮點(diǎn)量化對(duì)scale并不敏感,我們可以在訓(xùn)練時(shí)直接省去對(duì)scale的討論,將所有縮放因子設(shè)置為1.0,只需保證網(wǎng)絡(luò)中的激活與權(quán)重在訓(xùn)練過程中不會(huì)超出FP8的表示范圍,也即[-448, 448]。相比FP32,樂觀地講我們只需要在網(wǎng)絡(luò)中加入一些額外的clip算子就可以完成FP8的QAT訓(xùn)練。一個(gè)額外的細(xì)節(jié)是:在訓(xùn)練時(shí),如果我們發(fā)現(xiàn)網(wǎng)絡(luò)中的數(shù)值或梯度出現(xiàn)了inf,我們可以降低網(wǎng)絡(luò)的學(xué)習(xí)速率來保證穩(wěn)定。
          第二部分的實(shí)驗(yàn)結(jié)果來自我們的量化工具
          在這部分實(shí)驗(yàn)中我們不加訓(xùn)練地直接量化分類網(wǎng)絡(luò),設(shè)置所有縮放因子為1.0,同時(shí)以前文提及的數(shù)據(jù)轉(zhuǎn)換函數(shù)執(zhí)行FP8的量化模擬,實(shí)驗(yàn)結(jié)果如下:

          INT8FP8
          Inceptionv369.468.2
          mnasnet63.922.3
          mnasnet72.871.3
          squeezenet57.857.1
          shufflenet68.866.0
          resnet1869.669.4
          mobilenetv270.967.2
          mobilenetv373.370.3
          efficientnet-b052.874.9

          圖表1 訓(xùn)練后量化實(shí)驗(yàn)結(jié)果
          在兩部分的實(shí)驗(yàn)中,我們均只量化卷積和矩陣乘的輸入和權(quán)重,網(wǎng)絡(luò)中的其他值保持為FP32精度,Bias也保持為FP32精度。

          五、結(jié)論
          • FP8的量化并不精確

          • FP8的量化具有良好的寬容度,我們期待他在QAT中取得更好的表現(xiàn)

          • FP8良好的寬容度可以量化一些奇怪的網(wǎng)絡(luò),例如Effcientnet。

          總的來看,F(xiàn)P8 更加適合訓(xùn)練,這是一項(xiàng)很大的優(yōu)點(diǎn),其良好的寬容度讓我們可以期待 FP8 QAT 有著更好的穩(wěn)定性,用戶也可以借 FP8 省去非常麻煩的 Calibration 過程。FP8 的量化是不精確的,另一方面 FP8 的運(yùn)算器設(shè)計(jì)依然會(huì)比 INT8 的更加復(fù)雜,它依然不適合端側(cè)芯片的部署,更加適合于 GPU。
          ▎參考:
          · https://github.com/openppl-public/ppq/tree/master/ppq
          · https://github.com/openppl-public/ppq/pull/274
          · https://www.graphcore.ai/posts/graphcore-and-amd-propose-8-bit-fp-ai-standard-with-qualcomm-support
          · 本文部分內(nèi)容翻譯自:https://arxiv.org/pdf/2209.05433.pdf
          ?? 歡迎 star 

          GitHub: https://github.com/openppl-public
          官網(wǎng):https://openppl.ai
          QQ 群:627853444



          推薦閱讀

          深入理解生成模型VAE

          DropBlock的原理和實(shí)現(xiàn)

          SOTA模型Swin Transformer是如何煉成的!

          有碼有顏!你要的生成模型VQ-VAE來了!

          集成YYDS!讓你的模型更快更準(zhǔn)!

          輔助模塊加速收斂,精度大幅提升!移動(dòng)端實(shí)時(shí)的NanoDet-Plus來了!

          SimMIM:一種更簡(jiǎn)單的MIM方法

          SSD的torchvision版本實(shí)現(xiàn)詳解


          機(jī)器學(xué)習(xí)算法工程師


                                              一個(gè)用心的公眾號(hào)


          瀏覽 627
          1點(diǎn)贊
          1評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          全部評(píng)論
          QS5894650b997c2401e2023-09-21 09:25
          不得不說,翻譯完比原文看上去順眼多了
          點(diǎn)贊回復(fù)
          推薦
          1點(diǎn)贊
          1評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产黄片免费 | 夜色帮福利福利 | 波多野吉衣网站 | 天天干夜夜骑 | 日a在线 日本aⅴ 日本草比 |