「模型量化技術」可視化指南:A Visual Guide to Quantization 原創 精華
編者按:隨著大語言模型(LLMs)規模的不斷擴大,如何在有限的計算資源下高效部署這些模型成為了一個迫切需要解決的問題。模型量化作為一種有效的模型壓縮技術,在保持模型性能的同時大大降低了計算和存儲開銷,因此廣受關注。但對于許多人來說,模型量化的具體原理和實現方法仍然是一個“黑盒”。
我們今天為大家帶來的這篇文章,通過可視化圖示詳細解析各種模型量化技術的原理和實現方法,為各位讀者提供一個全面且直觀的模型量化技術指南。
本文旨在幫助各位讀者涉獵以下技能領域:
- 理解模型量化技術的基本原理和作用
- 掌握多種模型量化方法及其優缺點
- 學會如何選擇合適的量化方法,并根據實際場景進行調整
我們分享這篇全面且深入的技術解析,期望各位讀者不僅能夠理解模型量化的基本原理,還能洞察該領域的最新發展趨勢。隨著模型量化技術的不斷進步,我們有理由相信,未來將會出現更加高效、更輕量級的大語言模型,為 AI 技術的更廣泛應用鋪平道路。
作者 ?? | Maarten Grootendorst
編譯 ?? | 岳揚
目錄??
01 第 1 部分:LLMs 存在的“問題”
1.1 參數數值(value)的表示方法
1.2 內存限制問題
02 第 2 部分:模型量化技術簡介
2.1 常用的數據類型
2.1.1 FP16
2.1.2 BF16
2.1.3 INT8
2.2 對稱量化 Symmetric Quantization
2.3 非對稱量化 asymmetric quantization
2.4 取值范圍的映射與裁剪
2.5 校準過程 Calibration
2.5.1 權重(和偏置項) Weights (and Biases)
2.5.2 激活值
03 第 3 部分:Post-Training Quantization
3.1 動態量化(Dynamic Quantization)
3.2 靜態量化(Static Quantization)
3.3 探索 4-bit 量化的極限
3.3.1 GPTQ
3.3.2 GGUF
04 第 4 部分:Quantization Aware Training
4.1 1-bit LLM 的時代:BitNet
4.2 權重的量化 Weight Quantization
4.3 激活值的量化 Activation Quantization
4.4 反量化過程 Dequantization
4.5 所有 LLMs 實際上均為 1.58-bit
4.5.1 The Power of 0
4.5.2 Quantization 量化過程
05 Conclusion
Resources
文中鏈接??
顧名思義,大語言模型(Large Language Models,LLMs)的特點就是龐大,以至于普通的消費級硬件都難以承載。這些模型的參數量級可達數十億,而且在進行推理時,往往需要依賴擁有大量顯存(VRAM)的 GPU 來加快推理速度。
鑒于此,越來越多的研究者將目光投向如何通過優化訓練方法、使用適配器(adapters)等技術來縮小模型體積。在這一領域,模型量化(quantization)技術成為了一個重要的研究方向。
本篇文章將帶領大家深入了解語言模型領域的量化技術,并逐一探討相關概念,幫助大家建立起對這一領域的直觀認識。我們將一起探索不同的量化方法、實際應用場景,以及模型量化技術的基本原理。
本文將提供許多圖表(visualizations)來幫助各位讀者更好地理解和掌握模型量化技術這一概念,希望大家能夠直觀、深入地理解模型量化技術。
01 第 1 部分:LLMs 存在的“問題”
大語言模型之所以被稱為“大”,是因為其參數數量十分之龐大。目前,這類模型的參數數量通常能夠達到數十億之巨(主要是指權重參數(weights)),這樣的數據量其存儲成本無疑是一筆巨大的開銷。
在模型的推理過程中,激活值(譯者注:activations,神經網絡中某個層對輸入數據應用激活函數后產生的輸出值。)是通過輸入數據(input)與模型權重(weights)相乘等一系列步驟來生成的,這些激活值的數據量也可能非常龐大。
因此,我們的目標是找到一種盡可能高效的方式來表達數十億個參數,以減少存儲每個參數所需的空間。
在開始對這些參數進行優化之前,我們從最基本的部分入手,先探討一下參數數值(value)在計算機中最初是如何表示的。
1.1 參數數值(value)的表示方法
在計算機科學中,特定的數值(value)通常都以浮點數的形式來表示,即帶有正負號和小數點的數字。
這些數值是由 “bits” 組成的,也就是由二進制數字表示。根據 IEEE-754 標準[1],這些 “bits” 可以用來表示三個不同的部分,從而構成一個完整的數值(value):符號位、指數部分以及小數部分(也稱為尾數)。
這三個部分結合起來,就能根據一組特定的 “bit” 值來計算出一個具體的數值(value):
一般來說,用來表示數值(value)的 “bit” 越多,得到的數值(value)精確度就越高:
1.2 內存限制問題
可用的 “bits” 數量越多,所能表示的數值范圍就越大。
一個特定的數值表示法能夠表示的所有數值的區間被稱為動態范圍(dynamic range) ,而相鄰兩個數值之間的間隔則被稱為精度(precision) 。
使用這些 “bits” 的一個有趣功能是,我們可以計算出存儲一個特定數值(value)所需的設備內存量。由于一個字節(byte)占 8 位(bits),我們可以為大多數浮點表示形式(floating point representation)制定一個基本的計算公式。
Note:在實際應用中,模型推理階段所需的顯存(VRAM)量還受到諸多因素的影響,比如模型處理上下文的大小和模型架構設計。
假設我們有一個擁有 700 億參數的模型。通常情況下,這些模型默認使用 32 位浮點數(常稱為全精度)進行表示,僅加載模型就需要 280GB 內存。
因此,盡可能地減少用于表示模型參數的 “bits” 數量(包括模型訓練過程中也是如此)是非常有必要的。但是,有一點必須注意,精度的降低往往會導致模型準確性下降。
我們的目標是減少用于表示模型參數的 “bits” 數量,同時又不損害模型的準確性…… 這就是模型量化技術的作用所在!
02 第 2 部分:模型量化技術簡介
模型量化的核心在于將模型參數的精度從較高的位寬(bit-widths)(例如 32 位浮點數)降低到較低的位寬(bit-widths)(例如 8 位整數)。
在減少參數的 “bits” 數量時,通常會出現一定的精度損失(即丟失一些數值細節)。
為了更直觀地說明這種影響,我們可以嘗試將任意一張圖片僅用 8 種顏色來表示:
該圖像基于 Slava Sidorov 的原作[2]進行了修改
觀察放大區域,我們可以發現它比原始圖片看起來更加“粗糙”,因為使用的顏色種類減少了。
模型量化的主要目的就是減少表示原始參數所需的 “bits” 數量(在上述案例中即為顏色種類),同時盡可能保留原始參數的精度。
2.1 常用的數據類型
首先,我們來看看一些常見的數據類型,以及它們與 32-bit(全精度(full-precision)或 FP32 )表示法相比的影響。
2.1.1 FP16
以從 32-bit 轉換到 16-bit(半精度或 FP16 )的浮點數為例:
可以看到,FP16 的數值范圍比 FP32 要窄得多。
2.1.2 BF16
為了保持與原始 FP32 相似的數值范圍,引入了 bfloat 16 這一數據類型,它類似于“截斷版的FP32”:
BF16 雖然使用的 “bits” 數量與 FP16 相同,但能表示的數值范圍更廣,因此在深度學習領域內得到了廣泛應用。
2.1.3 INT8
當我們需要再進一步減少 “bits” 的數量時,就到了整數表示法施展身手的領域,而不再是浮點數表示法。例如,從 FP32 轉換為僅有 8 bits 的 INT8,其占用的 bits 數量僅僅是原來的四分之一:
有些硬件優化了整數運算,因此在這些硬件上整數運算可能會更高效。然而,并不是所有硬件都進行了這樣的優化。不過,一般來說,使用較少的 “bits” 數量,計算速度通常會更快一些。
每減少一個 bits ,就需要進行一次映射(mapping)操作,將原本的 FP32 表示形式“壓縮”到更少的 “bits” 數量。
在實際應用中,我們并不需要將 FP32 所表示的全部數值范圍 [-3.4e38, 3.4e38] 都映射到 INT8。我們只需找到一種方法,將數據(即模型參數)范圍映射到 INT8 即可。
常用的壓縮(squeezing)和映射(mapping)方法包括對稱量化(symmetric quantization)和非對稱量化(asymmetric quantization),它們都是線性映射(linear mapping)的不同形式。
接下來,我們將探討一下這些將 FP32 量化為 INT8 的方法。
2.2 對稱量化 Symmetric Quantization
在對稱量化過程中,原本浮點數的值域會被映射到量化空間(quantized space)中一個以零為中心的對稱區間。從前面的例子可以看出,量化前后的值域都是圍繞零點對稱的。
這就意味著,在浮點數中表示零的值,在量化空間中仍然是正好為零。
對稱量化(symmetric quantization)有一種經典方法是絕對最大值(absmax,absolute maximum)量化。
具體操作時,我們會從一組數值中找出最大的絕對值(α),以此作為線性映射的范圍(譯者注:從 -α 到 +α)。
Note:值域 [-127, 127] 代表的是受限制??的范圍,而 8-bit 整數可以表示的完整范圍是[-128, 127],選擇哪種范圍取決于所采用的量化方法。
由于這是一種以零為中心的線性映射(linear mapping),所以計算公式相對簡單。
我們首先根據以下公式計算比例因子(s):
- b 是我們想要量化到的字節數(譯者注:原文為“Byte”,此處保留原義,譯為字節數,譯者認為可能為 bits 數量)(這里是 8 ),
- α 是最大絕對值,
接著,我們用這個比例因子 s 來量化輸入值 x:
將這些數值代入公式后,我們將得到以下結果:
為了恢復原始的 FP32 值,我們可以使用之前計算出的比例因子(s)來對量化后的數值進行反量化(dequantize)。
先量化后再反量化以恢復原始值的過程如下所示:
我們可以觀察到,某些值(如 3.08 和 3.02 )在量化到 INT8 后,都被分配了相同的值 36。當這些值反量化(dequantize)回 FP32 時,會丟失一些精度,變得無法再區分。
這種現象通常被稱為量化誤差(quantization error) ,我們可以通過比較原始值(original values)和反量化值(dequantized values)之間的差值來計算這個誤差。
一般來說,“bits” 的數量越少,量化誤差往往越大。
2.3 非對稱量化 asymmetric quantization
與對稱量化(symmetric around)不同,非對稱量化并不是以零為中心對稱的。 它將浮點數范圍中的最小值(β)和最大值(α)映射到量化范圍(quantized range)的最小值和最大值。
我們在此要探討的方法稱為零點量化。
各位注意到 0 的位置是如何移動的嗎?這正是它被稱為“非對稱量化”的原因。在區間 [-7.59, 10.8] 中,最小值和最大值與零點之間的距離是不相等的。
由于零點位置的偏移,我們需要計算 INT8 范圍的零點來進行線性映射(linear mapping)。與之前一樣,我們還需要計算一個比例因子(s),但這次要使用 INT8 范圍( [-128, 127] )的兩個端點之間的差值。
請注意,由于需要計算 INT8 取值范圍中的零點(z)來調整權重,這個過程稍微復雜一些。
和之前一樣填入公式:
要將從 INT8 量化后的數值反量化回 FP32 ,需要使用之前計算的比例因子(s)和零點(z)。
除此之外,反量化過程則相對比較直接:
當我們將對稱量化和非對稱量化放在一起對比時,我們可以迅速看出這兩種方法之間的差異:
Note:請注意對稱量化(symmetric quantization)以零點為中心的特性,以及非對稱量化(asymmetric quantization)存在的零點偏移。
2.4 取值范圍的映射與剪裁
在前文所舉的例子中,我們研究了如何將向量中的數值映射到更低的位表示形式(lower-bit representation)中。雖然這樣使得向量的全范圍都能被映射,但有一個明顯的缺點,那就是有離群值(outlier)時不太好處理。
假設有一個向量,其值如下:
請注意,如果其中一個數值(value)遠大于其他所有數值,該數值就可以被視作離群值(outlier)。 如果我們要映射這個向量的全部數值,那么所有較小的數值都將映射到相同的較低位表示,并因此失去它們的獨特特性:
這就是我們之前使用的 absmax 方法。請注意,如果我們不進行剪裁(clipping),非對稱量化也會出現這樣的問題。
另一種選擇是裁剪(clip)掉某些數值。裁剪(Clipping)操作會為原始值設定一個不同的動態范圍,這樣所有離群值都會被映射到相同的值。
在下文給出的案例中,如果我們手動將動態范圍設置為 [-5, 5] ,所有超出這個范圍的數值無論其原始值是多少,都將被映射為 -127 或 127 :
這種方法的主要優點是,顯著減少了非離群值的量化誤差。然而,離群值的量化誤差卻增加了。
2.5 校準過程 Calibration
在前文的示例中,我展示了一種簡單方法 —— 即任意選擇一個取值范圍 [-5, 5]。這個過程被稱為校準(calibration),其目的是找到一個能夠包含盡可能多數值(values)的范圍,同時盡量減少量化誤差(quantization error)。
對于不同類型的參數,執行校準步驟的方法并不相同。
2.5.1 權重(和偏置項) Weights (and Biases)
在 LLMs 中,我們可以將權重(weights)和偏置項(Biases)視為預先確定的靜態值,因為這些值在運行模型之前就已經確定了。例如,Llama 3 的約 20 GB 文件[3]中大部分都是其權重和偏置項。
由于偏置項的數量(以百萬計)遠少于權重(以數十億計),偏置項通常被保留在更高的精度(如 INT16 ),而量化的主要工作則集中在權重的處理上。
因為權重是靜態且已知的,所以對其的量化技術可以有:
- 手動選擇輸入范圍的百分位數
- 優化原始權重和量化權重之間的均方誤差(MSE)
- 最小化原始值和量化值之間的熵(KL 散度)
例如,第一種方法(手動選擇輸入范圍的百分位數)會導致出現與前文我們看到的相似的裁剪(clipping)行為。
2.5.2 激活值
在 LLMs 中, 那些在整個推理過程中持續更新的輸入(input)通常被稱為“激活值”(activations)。
請注意,這些值之所以被稱為激活值,是因為它們經常需要經過某些激活函數處理,比如 sigmoid 或 relu。
與權重不同,激活值會隨著每次輸入數據的改變而變化,因此很難對其進行精確量化。
由于這些值在每個隱藏層之后都會更新,因此我們只能在輸入數據通過模型時才能預測它們在推理過程中的具體數值。
一般來說,校準權重和激活值的量化方法主要有兩種:
- Post-Training Quantization(PTQ)— 訓練完成后進行量化
- Quantization Aware Training(QAT)— 訓練/微調過程中同時進行量化
03 第 3 部分:Post-Training Quantization
在眾多量化技術中,post-training quantization(PTQ)是最為流行的一種。這種方法是在訓練完模型之后對模型的參數(包括權重和激活值)進行量化。
對于權重值的量化可以采用對稱量化(symmetric quantization) 或非對稱量化(asymmetric quantization) 兩種方式。
至于激活值,由于我們不知道其范圍,因此需要通過模型的推理來獲取它們的 potential distribution(譯者注:指的是在不同的輸入數據和模型參數下,激活值可能出現的一系列數值。了解這個分布有助于我們選擇一個能夠包含大部分激活值范圍的量化級別,從而減少量化誤差。),然后再進行量化。
激活值的量化主要有兩種形式:
- 動態量化(Dynamic Quantization)
- 靜態量化(Static Quantization)
3.1 動態量化(Dynamic Quantization)
當數據通過隱藏層時,其激活值會被收集起來:
隨后,利用這些激活值的分布(distribution of activations)來計算量化輸出值所需的零點(z)和比例因子(s)值:
每次數據通過一個新模型層時,都要重復上述過程。因此,每個模型層都有其獨特的 z 值和 s 值,因此也有不同的量化方案。
3.2 靜態量化(Static Quantization)
與動態量化不同,靜態量化在模型推理過程中不實時計算零點(z)和比例因子(s),而是在模型訓練或校準過程中提前計算。
為了找到這些值,會使用一個校準數據集,并讓模型處理這些數據,以便收集可能的激活值分布(potential distributions)。
收集到這些數值后,我們就可以計算出必要的 s 值和 z 值,以便在推理過程中進行量化。
在實際推理過程中,s 值和 z 值不需要重新計算,而是被應用于所有激活值,實現全局量化。
通常情況下,動態量化技術可能會稍微更精確一些,因為它為每個隱藏層計算一次 s 值和 z 值。不過,由于需要計算這些值,因此可能會增加計算時間。
相比之下,靜態量化雖然準確度稍低,但由于事先已知用于量化的 s 值和 z 值,因此在推理時更為高效。
3.3 探索 4-bit 量化的極限
將量化位數降至 8-bit 以下是一項艱巨的任務,因為每減少一個 bit,量化誤差(quantization error)就會增加。 幸運的是,有幾種巧妙的方法可以將量化位數進一步降低到 6-bit、4-bit,甚至 2-bit (不過不建議低于 4-bit )。
接下來將探討兩種在 HuggingFace** 上常用的方法:
- GPTQ — 全模型在 GPU 上運行。
- GGUF — 將一部分模型層從 GPU 轉移到 CPU 上執行。
3.3.1 GPTQ
GPTQ 無疑是實際應用中最著名的 4-bits 量化方法之一。1
它采用非對稱量化(asymmetric quantization),并逐層處理,每一層都經過獨立處理,然后再繼續處理下一層:
在這個逐層量化的過程中,首先將模型層的權重轉換為 Hessian 矩陣(譯者注:Hessian 矩陣是二階偏導數矩陣,用于描述函數在其輸入變量上的局部曲率。對于多變量函數,Hessian 矩陣可以幫助我們了解函數在某一點上的凹凸性,以及函數值對輸入變量的變化有多敏感。)的逆矩陣。它是模型損失函數的二階導數,它告訴我們模型輸出對每個權重變化的敏感程度。
簡單來說,該過程展示了模型層中每個權重的重要性(或者說是權重的影響程度)。
與 Hessian 矩陣中較小值相關的權重更為重要,因為這些權重的微小變化可能會對模型的性能產生重大影響。
在 Hessian 矩陣的逆矩陣中,數值越低,權重越 “重要”。
接下來,我們對權重矩陣的第一行權重進行量化,再進行反量化:
通過這一過程,我們可以計算出量化誤差 (q),我們可以用之前計算的 Hessian 矩陣的逆矩陣(h_1)來調整這個誤差。
換句話說,我們是在根據權重的重要性來構建加權量化誤差(weighted-quantization error):
接著,我們將這個加權的量化誤差重新分配到該行的其他權重上。這樣做可以保持神經網絡的整體功能(overall function)和輸出(output)不變。
例如,如果要對第二個權重(如果它是 0.3(x_2))進行此操作,我們就會將量化誤差(q)乘以第二個權重的 Hessian 矩陣的逆矩陣(h_2)加上去。
我們可以對第一行中的第三個權重進行同樣的處理:
重復這個重新分配加權量化誤差的過程,直到所有值都被量化。
這種方法之所以行之有效,是因為權重之間通常是相互關聯的。因此,當一個權重出現量化誤差(quantization error)時,與之相關的權重也會相應地更新(通過 Hessian 矩陣的逆矩陣)。
NOTE:本文作者[4]采用了幾種技巧來加快計算速度并提高性能,例如在 Hessian 矩陣中添加阻尼因子(dampening factor)、“懶惰批處理(lazy batching)”,以及使用 Cholesky 方法預先計算信息(precomputing information)。我強烈建議各位讀者觀看這個視頻[5]。
TIP:如果你想要一種可以優化性能和提高推理速度的量化方法,可以查看 EXL2[6] 這個項目。
3.3.2 GGUF
雖然 GPTQ 是一種在 GPU 上運行完整 LLMs 的最佳模型量化方法,但我們可能很多時候沒有這種條件。于是我們可以使用 GGUF 將 LLM 的某些模型層放到到 CPU 上進行處理。2
這樣,當 VRAM 不足時,就可以同時使用 CPU 和 GPU。
量化方法 GGUF 仍不斷在更新,并且其性能可能會根據量化位數的不同而有所變化。其基本原理如下:
首先,給定模型層的權重被分割成包含一組“子”塊的“超級”塊(“super” blocks)。
我們從這些 blocks 中提取比例因子(s)和 α(α):
為了量化給定的“子”塊(“sub” block),我們可以使用之前介紹的 absmax 量化方法。這種方法會將給定權重乘以比例因子(s):
比例因子是通過“子”塊的信息計算出來的,但量化時使用的是“超級”塊的信息,后者有自己的比例因子:
這種基于塊(blocks)的量化方法使用“超級”塊的比例因子(s_super)來量化“子”塊的比例因子(s_sub)。
每個比例因子的量化級別可能會有所不同,“超級”塊的比例因子通常比“子”塊的比例因子有更高的精度。
為了更直觀地理解,觀看下圖進一步了解這幾個量化級別相關信息( 2-bit、4-bit 和 6-bit ):
NOTE:在某些量化方法中,為了保持量化后的模型性能,可能需要一個額外的最小值來調整零點,以確保模型能夠正確處理極端值。這個最小值和比例因子一樣,都是量化過程中的關鍵參數,它們需要被正確地量化,以確保量化后的模型能夠保持原有的性能。
各位讀者可以查看這個 PR[7] ,了解所有量化級別的詳細信息。此外,還可以查看這個 PR[8],獲取更多關于使用重要性矩陣(importance matrices)進行量化的信息。
04 第 4 部分:Quantization Aware Training
在第 3 部分中,我們了解到如何在訓練完成后對模型進行量化。這種方法的不足之處在于,量化過程并未考慮到實際的訓練過程。
于是 Quantization Aware Training(QAT)就有了用武之地。與訓練后使用 post-training quantization(PTQ)技術對模型進行量化不同,QAT 的目標是在訓練過程中學習量化過程。
QAT 通常比 PTQ 更準確,因為在訓練過程中已經考慮了量化。其工作原理如下:
在訓練過程中,引入所謂的“偽”量化。比如先將權重量化到例如 INT4 等形式,然后將它們反量化回 FP32 :
這一過程使得模型在訓練階段進行損失值計算和權重更新時能夠考慮到量化誤差。
QAT 嘗試探索損失函數中的“寬”最小值區域,以盡可能減少量化誤差,因為“窄”最小值區域往往會導致更大的量化誤差。
例如,假設我們在反向傳播過程(backward pass)中沒有考慮量化誤差。我們將根據梯度下降法(gradient descent)選擇損失值(loss)最小的權重。但是,如果它位于“窄”最小值區域,可能會引入更大的量化誤差。
相反,如果我們考慮到量化誤差,我們將選擇在“寬”最小值區域中的不同權重進行更新,量化誤差會小得多。
因此,雖然 PTQ 在高精度(例如,FP32)下具有較小的損失值,但 QAT 在低精度(例如, INT4 )下的損失值較小,這正是我們追求的目標。
4.1 1-bit LLM 的時代:BitNet
正如前文所述,將量化位數降低到 4-bit 已經非常小了,但如果我們還要進一步降低呢?
這就是 BitNet[9] 的用武之地了,它使用 1-bit 表示模型的權重,每個權重都使用 -1 或 1 表示。3
它通過直接將量化過程整合到 Transformer 架構中來實現這一點。
Transformer 架構是大多數 LLMs 的基礎,它依賴于線性層來處理序列數據,并在模型中執行關鍵的計算操作:
這些線性層(linear layers)通常使用更高的精度,如 FP16,它們也是大部分權重所在的地方。
BitNet 將這些線性層替換為他們稱之為 BitLinear 的模型層:
BitLinear 層的工作原理與普通線性層相同,根據權重(weights)和激活值(activation)的乘積計算輸出值(output)。
BitLinear 層使用 1-bit 來表示模型的權重,并使用 INT8 來表示激活值:
類似于 Quantization-Aware Training(QAT)技術,BitLinear 層在訓練過程中執行一種 “偽” 量化,以便用來分析權重和激活值的量化效果:
NOTE:在論文中使用的是 γ 而不是 α ,但由于在本文中所舉的例子一直使用 α ,所以我使用 α 。此外,請注意此處的 β 與前文在零點量化(zero-point quantization)中使用的 β 不同,它是基于平均絕對值(average absolute value)計算得出的。
讓我們一步一步來學習 BitLinear 。
4.2 權重的量化 Weight Quantization
在訓練過程中,權重以 INT8 的形式存儲,然后使用一種稱為 signum 函數的基本策略,將其量化到 1-bit。
這種方法的核心在于,它將權重分布(distribution of weights)重新調整到以 0 為中心,然后將所有小于 0 的值(左側)設置為 -1 ,將所有大于 0 的值(右側)設置為 1 :
此外,它還會跟蹤記錄一個值 β(平均絕對值(average absolute value)),我們稍后會用到它來進行反量化(dequantization)。
4.3 激活值的量化 Activation Quantization
為了量化激活值,BitLinear 利用 absmax 量化方法將 FP16 格式的激活值轉換為 INT8 格式,因為矩陣乘法 (×) 需要更高精度的激活值。
同時,它還會跟蹤記錄 α(最高絕對值),我們將在后續的反量化過程中使用該值。
4.4 反量化過程 Dequantization
我們跟蹤記錄了 α(激活值的最高絕對值)和 β(權重的平均絕對值),因為這些值將在后續的反量化過程中幫助我們把激活值從 INT8 格式恢復到 FP16 格式。
輸出激活值(output activations)通過 {α, γ} 進行縮放,然后進行反量化將其恢復到原始精度:
就是這樣!這個過程相對簡單,只需用兩個值(-1 或 1)來表示模型。
根據這一流程,作者發現隨著模型規模的擴大,1-bit 形式和 FP16 形式訓練的模型之間的性能差異逐漸縮小。
不過,這只適用于較大型的模型(參數超過 300 億(30 B)),而對于較小型的模型,這個性能差距仍然很大。
4.5 所有 LLMs 實際上均為 1.58-bit
BitNet 1.58b[10] 就是為了解決之前提到的擴展性問題而提出的。4
在這種新方法中,模型的每一個權重不僅可以是 -1 或 1 ,還可以取 0 ,從而成為了一個三元模型。有趣的是,僅僅添加了 0 這一可取值就極大地提升了 BitNet 的性能,并使得計算速度大大提升。
4.5.1 The Power of 0
那么,為什么就添加了一個可取值 0 就能帶來如此大的提升呢?
這與矩陣乘法的原理緊密相關!
首先,讓我們了解一下矩陣乘法的一般工作原理。在計算輸出值時,我們將權重矩陣(weight matrix)與輸入向量(input vector)相乘。下圖展示了權重矩陣第一層與輸入向量相乘的過程:
請注意,這一過程包含兩個步驟:首先將每個權重與輸入值相乘,然后將所有乘積相加。
與此不同,BitNet 1.58b 則省略了乘法這一步驟,因為三元權重(ternary weights)實際上傳達了這樣的信息:
- 1: 我想要加上這個值
- 0: 我不需要加上這個值
- -1: 我想要減去這個值
因此,當權重量化到 1.58 bit 時,只需要執行加法運算:
這樣不僅可以大大加快了計算速度,還可以進行特征過濾(feature filtering)。
將某個權重設置為 0 后,我們就可以選擇忽略它,而不是像 1-bit 表示法那樣要么加上要么減去權重。
4.5.2 Quantization 量化過程
在 BitNet 1.58b 中,進行權重量化(weight quantization)時采用了 absmean 量化方法,這是之前看到的 absmax 量化方法的一種改進形式。
這種方法通過壓縮權重的分布,并利用權重的絕對平均值(α)來進行數值(value)的量化。之后,這些數值會被歸整到 -1、0 或 1 :
相較于 BitNet,激活值的量化過程基本相同,但還是有一點不同。激活值不再被縮放到 [0, 2??1] 區間,而是通過 absmax 量化方法被調整到了 [-2??1, 2??1] 區間。
就是這樣!1.58-bit 量化主要需要兩種技巧:
- 通過添加可取值 0 構建三元數值表示法 [-1, 0, 1]
- 對權重實施 absmean 量化方法。
“13B BitNet b1.58 在響應延遲、內存占用和能耗方面,相較于 3B FP16 LLM 更高效。”
由于僅需 1.58 個 bits ,計算效率高,我們得以構建出更為輕量的模型!
05 Conclusion
我們的量化之旅到此告一段落!但愿本文能幫助你更深入地認識到量化技術、GPTQ、GGUF 以及 BitNet 的巨大潛力。未來模型的體積又將能夠縮小到何種程度?真是令人期待啊!
如果要查看更多與 LLMs 相關的可視化內容,并希望支持我們,不妨留意一下我和 Jay Alammar 正在編寫的新書。該書即將發行!
你可以在 O’Reilly 網站[11]上免費試讀此書,或者直接在亞馬遜[12]上預訂。我們還會將所有相關代碼同步更新到 Github[13] 上。
Resources
Hopefully, this was an accessible introduction to quantization! If you want to go deeper, I would suggest the following resources:
- A HuggingFace blog about the LLM.int8()[14] quantization method: you can find the paper here[15]. (譯者注:LLM.int8() 量化方法)
- Another great HuggingFace blog about quantization for embeddings[16].(譯者注:嵌入向量的量化問題)
- A blog about Transformer Math 101[17], describing the basic math related to computation and memory usage for transformers.(譯者注:介紹了與 Transformer 的計算和內存使用相關的基本概念)
- This[18] and this are two nice resources to calculate the (V)RAM you need for a given model.(譯者注:計算特定模型所需(V)RAM 的數量)
- If you want to know more about QLoRA5, a quantization technique for fine-tuning, it is covered extensively in my upcoming book: Hands-On Large Language Models[19].(譯者注:QLoRA 技術的學習資料)
- A truly amazing YouTube video[20] about GPTQ explained incredibly intuitively.(譯者注:GPTQ 技術的學習資料)
腳注:
- Frantar, Elias, et al. "Gptq: Accurate post-training quantization for generative pre-trained transformers." arXiv preprint arXiv:2210.17323 (2022).
- You can find more about GGUF on their GGML repository here[21].
- Wang, Hongyu, et al. "Bitnet: Scaling 1-bit transformers for large language models." arXiv preprint arXiv:2310.11453 (2023).
- Ma, Shuming, et al. "The era of 1-bit llms: All large language models are in 1.58 bits." arXiv preprint arXiv:2402.17764 (2024).
- Dettmers, Tim, et al. "Qlora: Efficient finetuning of quantized llms." Advances in Neural Information Processing Systems 36 (2024).
Thanks for reading!
Hope you have enjoyed and learned new things from this blog!
Maarten Grootendorst
Data Scientist | Psychologist | Writer | Open Source Developer (BERTopic, PolyFuzz, KeyBERT) | At the intersection of Artificial Intelligence and Psychology
END
??文中鏈接??
[1]??https://en.wikipedia.org/wiki/IEEE_754??
[3]??https://huggingface.co/meta-llama/Meta-Llama-3-8B/tree/main??
[4]??https://arxiv.org/pdf/2210.17323??
[5]??https://www.youtube.com/watch?v=mii-xFaPCrA??
[6]??https://github.com/turboderp/exllamav2??
[7]??https://github.com/ggerganov/llama.cpp/pull/1684??
[8]??https://github.com/ggerganov/llama.cpp/pull/4861??
[9]??https://arxiv.org/pdf/2310.11453??
[10]??https://arxiv.org/pdf/2402.17764??
[11]??https://www.oreilly.com/library/view/hands-on-large-language/9781098150952/??
[12]??https://www.amazon.com/Hands-Large-Language-Models-Understanding/dp/1098150961??
[13]??https://github.com/HandsOnLLM/Hands-On-Large-Language-Models??
[14]??https://huggingface.co/blog/hf-bitsandbytes-integration??
[15]??https://arxiv.org/pdf/2208.07339??
[16]??https://huggingface.co/blog/embedding-quantization??
[17]??https://blog.eleuther.ai/transformer-math/??
[18]??https://huggingface.co/spaces/NyxKrage/LLM-Model-VRAM-Calculator??
[19]??https://www.amazon.com/Hands-Large-Language-Models-Understanding/dp/1098150961??
[20]??https://www.youtube.com/watch?v=mii-xFaPCrA??
[21]??https://github.com/ggerganov/ggml/blob/master/docs/gguf.md??
本文經原作者授權,由 Baihai IDP 編譯。如需轉載譯文,請聯系獲取授權。
原文鏈接:
??https://newsletter.maartengrootendorst.com/p/a-visual-guide-to-quantization??
