自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

萬字技術干貨!LLM工程師必讀量化指南,可視化圖解揭秘大模型如何壓縮

人工智能 新聞
面對LLM逐漸膨脹的參數規(guī)模,沒有H100的開發(fā)者和研究人員們想出了很多彌補方法,「量化」技術就是其中的一種。這篇可視化指南用各種圖解,將「量化」的基本概念和分支方法進行了全方位總結。

大語言模型(LLM)通常過于龐大,無法在消費級硬件上運行。這些模型的參數可能超過數十億,通常需要顯存較大的GPU來加速推理過程。

因此,越來越多的研究開始關注如何縮小模型,比如改進訓練方法或使用適配器。該領域的一項主要技術被稱為量化(quantization)。

ML工程師Maarten Grootendorst撰寫了一篇博客文章,在語言建模背景下專門介紹了量化技術,并通過可視化的方法逐一探索相關概念,以幫助我們建立對該技術的直觀理解。

圖片

在這篇博文中,Maarten將探討各種方法、使用案例以及量化背后的原理。

文章目錄以及涵蓋內容如下圖所示,主要介紹了訓練后量化(PTQ)以及量化感知訓練(QAT)兩種方法,建議有AI基礎的讀者直接跳轉至對稱量化部分:

圖片

第一部分:LLM的「問題」

「大語言模型」就是大在模型參數量上,規(guī)模通常達到數十億的級別(其中主要是權重)。

這些參數不僅存儲成本相當高,推理階段的計算量也很大。

在推理過程中,激活值是輸入和權重的乘積,因此權重數量越多,激活值也會越大。

圖片

因此,我們希望盡可能高效地表示數十億個值,從而盡可能減少存儲參數所需的空間。

讓我們從頭開始,探索數值是如何表示的,然后再進行優(yōu)化。

如何表示數值

數值存儲的形式通常是浮點數(floting point number,或簡稱為floats):一個帶有小數點的正數或負數。

這些值由每一位(bit)上的二進制數字表示。

IEEE-754標準描述了每一位上的數字如何表示具體數值,具體來說共有三種映射:符號、指數或小數(尾數)。

圖片

這三個部分可以結合起來,根據一組bit值計算出所表示的數值:

圖片

使用的位數越多,表示的數值值通常越精確,比如FP32形式就能比FP16精確到小數點后更多位數:

圖片

內存限制

可用的位數越多,不僅數值越精確,可表示的數值范圍也越廣。

圖片

給定位數和表示形式,可表示的數值區(qū)間稱為動態(tài)范圍(dynamic range),而兩個相鄰值之間的距離稱為精度(precision)。

圖片

這種表達形式的一個巧妙特性在于,我們可以計算出設備需要多少內存來存儲某個給定值。

由于內存中的每個字節(jié)含有8位,我們可以為大多數形式的浮點數創(chuàng)建一個基本公式——

圖片

在實際應用中,還有更多因素會影響推理過程中所需的顯存/內存大小,例如上下文大小和模型架構

現在假設我們有一個包含700億參數的模型。大多數模型本身使用32位浮點數(通常稱為全精度)表示,這需要280GB的內存來加載模型。

圖片

但如果能將所有參數用16位浮點數表示,所需的內存大小就可以直接減少一倍。

因此,將模型參數的表示位數最小化(不僅是推理,還有訓練過程)是非常有吸引力的。

然而,這種方法不是沒有代價的。隨著表示位數減少導致精度降低,模型的準確性通常也會下降。

我們希望在保持準確性的同時減少表示數值的位數……此時,量化技術就派上用場了。

第二部分:量化入門

現在我們知道,量化的目的是將模型參數的精度從較高位寬(如32位浮點數)降低到較低位寬(如8位整數)。

圖片

在減少表示原始參數的位數時,通常也會伴隨一些精度(粒度,granularity)的損失。

為了讓這種效果更直觀,我們可以用照片顏色作為類比。比如,選擇任意圖像(左圖),但只用8種顏色表示(右圖):

圖片

注意看,放大的曲奇餅干看起來比原來更有「顆粒感」。

與之相似,量化的主要目標是減少表示原始參數所需的比特數(顏色),同時盡可能保留原始參數的精度。

常見數據類型

首先,讓我們看看常見的數據類型以及使用它們替代32位(稱為全精度或FP32)表示的影響。

FP16

首先是一個從32位到16位(稱為半精度或FP16)浮點數的例子:

圖片

FP16可取的數值范圍比FP32小得多。

BF16

為了獲得與原始FP32相似的數值范圍,引入了bfloat 16作為一種「截斷的FP32」類型:

圖片

BF16使用的位數與FP16相同,但增加了指數位,因此能取到更廣泛的數值范圍,常用于深度學習領域。

INT8

進一步減少位數時,就更接近整數而非浮點數的表示方法。比如,從FP32到只具有8位的INT8,只有原始位數的1/4:

圖片

每次減少位數時,都會進行映射,將初始的FP32表示「壓縮」到較少的位數中。

但在實際操作中,我們不需要將整個FP32范圍[-3.4e38, 3.4e38]全部映射到INT8中。我們只需找到一種方法,將實際模型參數的數據范圍映射到INT8中。

常見的壓縮/映射方法可以有對稱量化和非對稱量化兩種,都屬于線性映射。

接下來將要探討的就是從FP32到INT8的量化方法。

對稱量化

在對稱量化中,原始浮點值的范圍被映射到量化空間中以零為中心的對稱范圍,量化前后的范圍都以零為中點。

這意味著,原來浮點空間中的零,映射到量化空間后也恰好是零。

圖片

一種對稱量化的典型例子是最大絕對值(absmax)量化。

給定一個數值列表,我們取其中最高的絕對值(α)作為執(zhí)行線性映射的范圍。

圖片

[-127, 127]表示受限范圍(restricted range),未受限范圍是[-128, 127],取決于量化方法

由于這是一個以零為中心的線性映射,公式很簡單。

首先用以下公式計算比例因子(s):

- b是我們要量化到的字節(jié)數(8)

- α是最高的絕對值

然后,我們使用s來量化輸入x:

圖片

如上圖所示,最大絕對值α為10.8,將FP32映射到INT8時,即有如下公式:

圖片

如果要恢復原始的FP32值,也可以使用先前計算的比例因子(s)來進行反量化。

圖片

先量化,再反量化以恢復原始值,全過程如下所示:

圖片

可以看到某些值,如3.08和3.02,在量化為INT8時都是36。因此進行反量化恢復到FP32時,它們失去了一些精度并且不再可區(qū)分。

這種原始值和反量化值之間的差異被稱為量化誤差。通常,量化結果的位數越少,誤差越大。

圖片

非對稱量化

與對稱量化不同,非對稱量化不是以零為中心的對稱。相反,它將浮點范圍內的最小值(β)和最大值(α)分別映射到量化范圍的最小值和最大值。

這里我們探討的方法被稱為零點量化(zero-point quantization)。

圖片

注意0的位置是如何移動的。這就是為什么它被稱為非對稱量化。在范圍[-7.59, 10.8]中,最大值和最小值到0的距離不同。

由于零點位置的偏移,我們必須計算INT8范圍內的零點才能執(zhí)行線性映射。與之前一樣,我們還必須計算比例因子(s),但使用INT8范圍的差值[-128, 127]。

圖片

由于需要在INT8范圍內計算零點(z)以移動權重,這有點復雜。

像之前一樣,讓我們填入公式:

圖片

為了將量化后的值從INT8反量化回FP32,我們需要使用先前計算的比例因子(s)和零點(z)。

除此之外,反量化很簡單:

圖片

當我們將對稱和非對稱量化并排放置時,可以快速看出兩種方法之間的區(qū)別:

圖片

在上圖中,我們能看到對稱量化的零中心特性與非對稱量化的偏移。

范圍映射和剪裁(Clipping)

在之前的例子中,我們探討了如何將給定向量中的值范圍映射到低位表示。雖然這樣可以映射整個向量值的范圍,但有一個主要缺點,即異常值(outlier)。

想象一下,你有一個包含以下值的向量:

圖片

一個值比其他所有值都大得多,可以被認為是異常值。如果我們映射整個向量的范圍,所有小值將被映射到相同的低位表示,并失去它們的區(qū)分度:

圖片

這是之前使用的absmax方法。如果不進行剪裁,非對稱量化也會發(fā)生同樣的情況

相反,我們可以選擇剪裁某些值。剪裁是指設置原始值的不同動態(tài)范圍,使所有異常值都被設為相同的值。

在下面的例子中,我們手動將動態(tài)范圍設置為[-5, 5],所有超出該范圍的值將被映射到-127或127,無論它們的實際值是多少:

圖片

這種方法的主要優(yōu)點是非異常值的量化誤差顯著減少。然而會導致異常值的量化誤差增加。

校準(Calibration)

上面的例子中,我們隨機將動態(tài)范圍設置為[-5, 5],但其實應該通過「校準」過程做出決定,找到一個合適的范圍,包含盡可能多的值,同時最小化量化誤差。

校準步驟的具體執(zhí)行對于不同類型的參數是不一樣的。

權重(和偏置)

我們可以將大語言模型(LLM)的權重和偏置(weights & biases)視為靜態(tài)值,因為它們在運行模型之前是已知的。例如,Llama 3的約20GB文件大部分由其權重和偏置組成。

由于偏置變量的數量(數百萬)顯著少于權重(數十億),因此偏置通常保持較高精度(如INT16),而量化的主要工作集中在權重上。

對于已知的靜態(tài)權重,選擇范圍的校準技術包括:

- 手動選擇輸入范圍的百分位數

- 優(yōu)化原始權重和量化權重之間的均方誤差(MSE)

- 最小化原始值和量化值之間的熵(KL散度)

圖片

例如,選擇一個百分位數,會導致類似于我們之前看到的剪裁行為。

激活值

在整個大語言模型中不斷更新的輸入通常被稱為激活值(activations)。

圖片

之所以被稱為激活值,因為它們通常會經過一些激活函數,如sigmoid或relu

與權重不同,激活值在推理過程中隨輸入數據而變化,因此難以準確量化。

由于這些值在每個隱藏層之后都會更新,因此在推理階段,只有輸入數據通過模型后才能得知它們的具體數值。

圖片

總體來說,有兩種方法用于校準權重和激活值,應用于模型的不同階段:

- 訓練后量化(Post-Training Quantization,PTQ)

- 顧名思義,即訓練后進行的量化

- 量化感知訓練(Quantization Aware Training,QAT)

- 訓練/微調期間的量化

第三部分:訓練后量化(PTQ)

訓練后量化(PTQ)是最流行的量化技術之一。它是在模型訓練完成后,對模型的參數(包括權重和激活值)進行量化。

權重的量化可以采用對稱量化或非對稱量化的方法。

然而,激活值的量化需要經過推理階段來獲取其潛在分布,因為我們事先并不知道它們的范圍。

激活值的量化有兩種形式:

- 動態(tài)量化(dynamic quantization)

- 靜態(tài)量化(static quantization)

動態(tài)量化

數據通過隱藏層后,其激活值會被收集,比較出每一層的最大值(α)和最小值(β):

圖片

然后利用這些激活值的分布來計算量化輸出所需的零點(zeropoint,z)和比例因子(scale factor,s)值:

圖片

每次數據通過新的網絡層時,這個過程都會重復。因此,每一層都有其獨立的z和s值,從而使用不同的量化方案。

靜態(tài)量化

與動態(tài)量化不同,靜態(tài)量化并不是在推理過程中計算零點(zeropoint,z)和比例因子(scale factor,s),而是在推理之前計算這些值。

為了找到這些值,我們會使用一個校準數據集,并將其輸入模型以收集這些潛在的激活值分布。

圖片

收集到這些分布之后,就可以計算出在推理過程中進行量化所需的s和z值。

在實際推理時,不會重新計算s和z值,而是在所有激活中全局使用它們來對其進行量化。

總體來說,動態(tài)量化為每個隱藏層計算s和z值,往往更準確。然而,這可能會增加計算時間,因為這些值需要在每次推理時計算。

相反,靜態(tài)量化雖然不如動態(tài)量化準確,但速度更快,因為它已經預先知道用于量化的s和z值。

4-bit量化領域

低于8-bit的量化一直是一個挑戰(zhàn),因為每減少一位,量化誤差就會增加。幸運的是,有幾種巧妙的方法可以將位數減少到6、4,甚至2-bit(盡管通常不建議將位數降到低于4-bit)。

我們將探討在HuggingFace上常見的兩種方法:

- GPTQ(全模型在GPU上運行)

- GGUF(可能將層卸載到CPU上)

GPTQ

GPTQ可以說是實際應用中最著名的4-bit量化方法之一。

它使用非對稱量化,并逐層進行處理,每層獨立處理后再繼續(xù)處理下一層:

圖片

在這個逐層量化過程中,它首先將層的權重轉換為逆Hessian矩陣。逆Hessian矩陣是模型損失函數的二階導數,表示模型輸出對每個權重變化的敏感性。

簡單來說,它本質上展示了每個層中權重的重要性(逆重要性)。

Hessian矩陣中較小值的權重更為重要,因為這些權重的微小變化可能導致模型性能的顯著變化。

圖片

在逆Hessian矩陣中,較低的值表示更「重要」的權重

接下來,我們量化并反量化權重矩陣的第一行:

圖片

這一過程使我們能夠計算量化誤差(q),我們可以使用之前計算的逆Hessian值(h_1)來加權這個量化誤差。

本質上,我們是在基于權重的重要性創(chuàng)建加權量化誤差:

圖片

接下來,我們將這個加權量化誤差重新分配到該行的其他權重上。這有助于保持網絡的整體功能和輸出。

例如,如果對第二個權重(即x_2=0.3)進行此操作,我們會將量化誤差(q)乘以第二個權重的逆Hessian(h_2)加上去:

圖片

接下來,繼續(xù)對給定行中的第三個權重進行相同的操作:

圖片

重復這個重新分配加權量化誤差q的過程,直到所有值都被量化。

這個方法所以有效,是因為權重通常是相互關聯的。因此,當一個權重有量化誤差時,相關的權重會通過逆Hessian進行相應的更新。

GGUF

雖然GPTQ是一種很好的在GPU上運行整個大語言模型(LLM)的量化方法,但如果沒有相應的硬件條件,也可以通過GGUF將LLM的任意層卸載到CPU上。

相當于同時用CPU和GPU運行模型,以彌補顯存(VRAM)不足的情況。

量化方法GGUF經常更新,而且依賴于具體的量化位數,但基本原理如下。

首先,給定層的權重被分成「超級塊」,每個「超級塊」包含一組「子塊」。從這些「子塊」中,我們計算出比例因子(s)和α值:

圖片

為了量化給定的「子塊」,可以使用之前提到的absmax量化,將給定的權重乘以比例因子(s_sub):

圖片

比例因子s_sub是使用「子塊」中的信息計算的,但用「超級塊」中的信息s_super進行量化:

圖片

總而言之,這種以塊為單位的量化使用「超級塊」的比例因子(s_super)來量化「子塊」的比例因子(s_sub)。

每個比例因子的量化級別可能不同,「超級塊」的比例因子通常比「子塊」有更高的精度。

為了說明這一點,讓我們探討幾個量化級別(2-bit、4-bit和6-bit):

圖片

根據量化類型,還需要一個額外的最小值(m)來調整零點,這些與比例因子(s)一樣被量化

第四部分:量化感知訓練(QAT)

第三部分講述了如何在訓練后對模型進行量化。這種方法的缺點在于,沒有考慮到實際的訓練過程。

這就是量化感知訓練(QAT)派上用場的地方。與訓練后量化(PTQ)不同,QAT的目標是在訓練中學習量化過程。

圖片

QAT往往比PTQ更準確,因為在訓練過程中已經考慮了量化。其工作原理如下:

在訓練過程中,引入了所謂的「假」量化。比如先將權重量化為INT4,然后再反量化回FP32:

圖片

這一過程讓模型在訓練階段進行損失計算和權重更新時,就已經考慮到了量化誤差。

如下圖所示,QAT嘗試探索「寬」極小值情況下的損失值,以減少量化誤差,因為「窄」極小值往往會導致更大的量化誤差。

圖片

假設在反向傳播過程中沒有考慮量化,梯度下降過程就會選擇損失值最小的權重。然而,如果它處于「窄」極小值中,那將引入更大的量化誤差。

相反,如果我們考慮量化,將在「寬」極小值中選擇一個不同的更新權重,其量化誤差要小得多。

圖片

因此,盡管PTQ方法在高精度(例如FP32)有較低的損失值,但QAT在低精度(例如INT4)下損失值也很低,這是我們所追求的。

1-bit時代:BitNet

之前我們看到,將量化精度降低到4-bit已經相當小了,但如果我們進一步降低呢?

這就是BitNet的用武之地,它將模型的權重表示為單個比特,即-1或1,通過將量化過程直接注入到Transformer架構中來實現這一點。

Transformer架構是大多數LLM的基礎,由涉及線性層的計算組成:

圖片

這些線性層通常以更高的精度表示,如FP16,而且是大多數權重所在的位置。

BitNet用BitLinear層替換了這些線性層:

圖片

BitLinear層的工作原理與普通線性層相同,用權重乘以激活值來計算輸出。

但不同的是,BitLinear層僅用1位表示模型的權重,使用INT8表示激活值:

圖片

BitLinear層像量化感知訓練(QAT)一樣,在訓練期間執(zhí)行一種「假」量化,以分析權重和激活值的量化效果:

圖片

讓我們一步步地了解BitLinear。

權重量化

在訓練過程中,權重以INT8存儲,然后使用一種稱為符號函數(signum function)的基本策略將其量化為1位。

本質上,它將權重的分布移動至以0為中心,然后將所有小于0的值分配為-1,將所有大于0的值分配為1:

圖片

此外,它還跟蹤一個值β(平均絕對值),我們將在之后的反量化過程中使用。

激活值量化

為了量化激活值,BitLinear使最大絕對值方法(absmax)將激活值從FP16轉換為INT8,因為它們需要以較高的精度進行矩陣乘法(×)。

圖片

此外,它還跟蹤一個值α(最大絕對值),我們將在之后的反量化過程中使用。

反量化

我們跟蹤了α(激活值的最大絕對值)和β(權重的平均絕對值),這些值將幫助我們將激活值反量化回FP16。

輸出激活值使用{α, γ}重新縮放,以將其反量化到原始精度:

圖片

這個過程相對簡單,并且允許模型僅用兩個值表示,即-1或1。

通過這種方法,作者觀察到,隨著模型規(guī)模的增長,1位訓練和FP16訓練之間的性能差距越來越小。

然而,這僅適用于較大的模型(>30B參數),較小模型之間的差距仍然很大。

所有LLM都是1.58位

為了改善之前提到的擴展性問題,BitNet 1.58b被引入。

在這種新方法中,模型的每個權重不僅可以是-1或1,還可以取0,使每個變量成為三元值(ternary)。

有趣的是,僅僅是添加0這個簡單的操作,就大大改進了BitNet,加速了計算過程。

0的力量

為什么添加0是一個重大改進呢?

這與矩陣乘法有關!

首先,讓我們探討一下矩陣乘法的基本工作原理。

當計算輸出時,我們將權重矩陣與輸入向量相乘。下面是權重矩陣的第一層的第一行乘法的可視化:

圖片

這種乘法涉及兩個動作,將單個權重與輸入相乘,然后將它們全部相加。

相比之下,BitNet 1.58b設法避免了乘法的動作,因為三值權重本質上告訴你以下內容:

- 1:我想加上這個值

- 0:我不想要這個值

- -1:我想減去這個值

因此,如果你的權重被量化到1.58 bit,你只需要執(zhí)行加法:

圖片

這不僅可以顯著加快計算速度,還允許特征過濾。

將給定的權重設置為0就相當于忽略了這個輸入,而不是像1-bit那樣,表示加上或減去輸入值。

量化

為了執(zhí)行權重量化,BitNet 1.58b使用平均絕對值量化(absmean),這是我們之前見過的最大絕對值量化(absmax)的變體。

它只是壓縮權重的分布并使用絕對均值(α)來量化值。然后將它們四舍五入為-1、0或1:

圖片

與BitNet相比,激活值量化是相同的,除了一個方面:不是將激活值縮放到范圍[0, 2??1],而是使用最大絕對值方法縮放到[-2??1, 2??1]。

總結一下,1.58-bit量化主要涉及兩個技巧:

- 添加0以創(chuàng)建三值表示[-1, 0, 1]

- 權重的絕對均值量化

BitNet論文中有這樣的結論:「13B BitNet b1.58在延遲、內存使用和能耗方面比3B FP16 LLM更高效?!?/span>

圖片

論文地址:https://arxiv.org/abs/2402.17764

由于只有1.58個計算效率高的bit,我們得到了輕量級模型。

責任編輯:張燕妮 來源: 新智元
相關推薦

2024-01-15 08:17:00

模型技術

2025-01-07 13:22:58

2024-07-19 08:34:18

2010-09-13 17:38:47

Google的系統工程

2023-03-30 08:28:57

explain關鍵字MySQL

2024-09-11 15:59:31

LLM.int8()大模型量化

2020-10-26 15:33:13

可視化數據項目

2023-12-04 13:38:55

模型3D可視化

2022-09-28 09:12:16

HBase分布式數據庫數據庫

2018-06-15 15:50:34

技術

2020-09-21 10:50:24

Java多線程代碼

2015-08-13 13:48:50

數據中心

2024-02-01 08:34:30

大模型推理框架NVIDIA

2016-05-16 14:18:00

2022-06-06 21:46:32

Kubernetes網絡

2018-01-02 09:17:57

2020-11-17 08:08:34

分庫分表

2022-07-04 15:56:55

智能方案

2022-02-15 18:45:35

Linux進程調度器

2025-04-23 08:31:26

Java并發(fā)框架
點贊
收藏

51CTO技術棧公眾號