偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

大模型 LLM.int8() 量化技術(shù)原理與代碼實(shí)現(xiàn)

人工智能
本文將深入探討量化的基本原理,介紹LLM.int8()大模型量化方法,并通過(guò)具體的代碼實(shí)戰(zhàn)來(lái)展示如何實(shí)現(xiàn)模型的量化,以便在各種設(shè)備上高效運(yùn)行這些模型。

大語(yǔ)言模型LLM因其龐大的參數(shù)規(guī)模,往往難以在消費(fèi)級(jí)硬件上直接運(yùn)行。這些模型的參數(shù)量可能達(dá)到數(shù)十億級(jí)別(主要是權(quán)重),這些參數(shù)不僅存儲(chǔ)成本高,推理階段的計(jì)算量也很大。通常需要顯存較大的GPU來(lái)加速推理過(guò)程。

因此,越來(lái)越多的研究開始關(guān)注如何縮小模型,比如改進(jìn)訓(xùn)練方法或引入適配器模塊。其中一項(xiàng)關(guān)鍵技術(shù)便是量化(quantization)。

本文將深入探討量化的基本原理,介紹LLM.int8()大模型量化方法,并通過(guò)具體的代碼實(shí)戰(zhàn)來(lái)展示如何實(shí)現(xiàn)模型的量化,以便在各種設(shè)備上高效運(yùn)行這些模型。

基礎(chǔ)知識(shí)

1.數(shù)值表示

模型推理過(guò)程中,激活值是輸入和權(quán)重之積,因此權(quán)重?cái)?shù)量越多,激活值也會(huì)越大。

因此,我們需要盡可能高效表示數(shù)十億個(gè)值,從而盡可能減少存儲(chǔ)參數(shù)所需的空間。

大語(yǔ)言模型中參數(shù)數(shù)值,通常被表示為浮點(diǎn)數(shù)。浮點(diǎn)數(shù)(floating-point numbers,簡(jiǎn)稱 floats)是一種用于表示帶有小數(shù)點(diǎn)的正數(shù)或負(fù)數(shù)的數(shù)據(jù)類型。

在計(jì)算機(jī)科學(xué)中,浮點(diǎn)數(shù)通常遵循IEEE-754標(biāo)準(zhǔn)進(jìn)行存儲(chǔ)。這一標(biāo)準(zhǔn)定義了浮點(diǎn)數(shù)的結(jié)構(gòu),包括符號(hào)位、指數(shù)位和尾數(shù)位三個(gè)組成部分。其中,

  • 符號(hào)位(Sign Bit):決定了浮點(diǎn)數(shù)的正負(fù)。
  • 指數(shù)位(Exponent Bits):表示浮點(diǎn)數(shù)的指數(shù)部分。
  • 尾數(shù)位(Fraction Bits):表示小數(shù)點(diǎn)后的數(shù)值部分。

三部分結(jié)合起來(lái),即可根據(jù)一組bit值計(jì)算出所表示的數(shù)值。使用的位數(shù)越多,表示的數(shù)值值通常越精確。

  • 半精度浮點(diǎn)數(shù)(Half-Precision Floats, FP16):使用16位來(lái)表示一個(gè)浮點(diǎn)數(shù),其中包括1位符號(hào)位、5位指數(shù)位和10位尾數(shù)位。

  • 單精度浮點(diǎn)數(shù)(Single-Precision Floats, FP32):使用32位來(lái)表示一個(gè)浮點(diǎn)數(shù),其中包括1位符號(hào)位、8位指數(shù)位和23位尾數(shù)位。

2.動(dòng)態(tài)范圍與精度

動(dòng)態(tài)范圍(Dynamic Range):指的是可表示的最大值與最小值之間的范圍。可用的位數(shù)越多,動(dòng)態(tài)范圍也就越廣。

精度(Precision):指兩個(gè)相鄰可表示值之間的差距??捎玫奈粩?shù)越多,精度也就越高。

對(duì)于給定的浮點(diǎn)數(shù)表示形式,我們可以計(jì)算出存儲(chǔ)特定數(shù)值所需的內(nèi)存大小。例如,對(duì)于32位浮點(diǎn)數(shù)(FP32),每個(gè)數(shù)值占用4字節(jié)(8位/字節(jié)),而對(duì)于16位浮點(diǎn)數(shù)(FP16),每個(gè)數(shù)值占用2字節(jié)。

假設(shè)模型有N個(gè)參數(shù),每個(gè)參數(shù)使用B位表示,則模型的內(nèi)存需求(以字節(jié)為單位)可以用以下公式計(jì)算:

在實(shí)際應(yīng)用中,除了模型本身的參數(shù)外,推理過(guò)程中的內(nèi)存/顯存需求還受到其他因素的影響,例如:

  • 上下文大?。簩?duì)于序列模型而言,處理的序列長(zhǎng)度會(huì)影響內(nèi)存需求。
  • 模型架構(gòu):不同的模型架構(gòu)可能會(huì)有不同的內(nèi)存使用模式。

對(duì)于一個(gè)包含700億參數(shù)的模型,如果使用32位浮點(diǎn)數(shù)表示,所需的內(nèi)存為:

如果改為使用16位浮點(diǎn)數(shù)表示,所需的內(nèi)存將減少一半:

由此可見,將模型參數(shù)的表示位數(shù)最小化,即量化(不僅是推理,還有訓(xùn)練過(guò)程)能夠顯著減少內(nèi)存需求,但這也意味著精度的降低,可能會(huì)對(duì)模型的準(zhǔn)確性產(chǎn)生負(fù)面影響。

「因此,量化技術(shù)的目標(biāo)是在保持模型準(zhǔn)確性的同時(shí)盡可能減少表示數(shù)值所需的位數(shù)?!?/p>

二、什么是模型量化?

所謂模型量化,其實(shí)就是將模型參數(shù)的精度從較高位寬(如FP16、FP32、BF16,一般是浮點(diǎn)運(yùn)算)轉(zhuǎn)換為較低位寬(如Int8、Int4,一般是整數(shù)運(yùn)算),從而降低模型存儲(chǔ)大小及顯存占用、提升推理性能。

三、量化分類

模型量化可從以下幾方面分類:

(1) 根據(jù)量化時(shí)機(jī)

  • 訓(xùn)練時(shí)量化(Quantization-Aware Training, QAT),需要模型重新訓(xùn)練。
  • 訓(xùn)練后量化(Post Training Quantization,PTQ),可以量化預(yù)訓(xùn)練好的模型。不需要重新訓(xùn)練。

(2) 根據(jù)映射函數(shù)是否為線性

  • 線性量化
  • 非線性量化

(3) 根據(jù)量化的粒度(共享量化參數(shù)的范圍)

  • Tensor粒度(per-tensor):整個(gè)矩陣一起量化。
  • Token粒度(per-token)和Channel粒度(per-channel):每行/每列單獨(dú)量化,X的每一行代表一個(gè)Token,W的每一列代表一個(gè)Channel。
  • Group粒度(per-group):兩者的折衷,多行/多列分為一組,每組分別量化。

(4) 根據(jù)量化范圍

  • 只量化權(quán)重(Weight Only):只量化模型權(quán)重,推理時(shí)是INT乘FLOAT。
  • 權(quán)重與激活同時(shí)量化(Weight and Activation):這里的激活實(shí)際是就是每一層的輸入,對(duì)于矩陣乘法Y = WX,同時(shí)量化W和X,推理時(shí)是INT乘INT。

目前Weight and Activation可以做到Int8(或者叫W8A8,Weight 8bit Activition 8bit)與FP16水平相當(dāng),而Weight Only方向INT4(W4A16)已經(jīng)可以做到與FP16相差無(wú)幾,INT3(W3A16)也很接近了。實(shí)際上,這兩個(gè)方向并不是互斥的,我們完全可以同時(shí)應(yīng)用兩種方式,只是工程比較復(fù)雜,暫時(shí)還沒(méi)有成熟的框架。

?

(5) 根據(jù)存儲(chǔ)一個(gè)權(quán)重元素所需的位數(shù)

  • 8bit量化
  • 4bit量化
  • 2bit量化
  • 1bit量化

四、量化方案

1.LLM.int8()

(1) LLM.int8()量化算法

INT8量化的基本思想是將浮點(diǎn)數(shù)通過(guò)縮放因子scale映射到范圍在[-128, 127]內(nèi)的8位整數(shù)表示。

量化公式如下:

其中:

  • Xq表示量化后的整數(shù)。
  • Xf表示量化前的浮點(diǎn)數(shù)。
  • scale表示縮放因子。
  • Round 表示四舍五入為整數(shù)。
  • Clip表示將結(jié)果截?cái)嗟絒-128, 127]范圍內(nèi)。

縮放因子scale的計(jì)算公式:

其中,表示浮點(diǎn)數(shù)最大絕對(duì)值。

反量化的過(guò)程為:

如下圖所示為通過(guò)該方式實(shí)現(xiàn)量化-反量化的示例。假設(shè)使用absmax quantization技術(shù)對(duì)向量[1.2, -0.5, -4.3, 1.2, -3.1, 0.8, 2.4, 5.4]進(jìn)行量化。首先找到絕對(duì)值最大值5.4。Int8的取值范圍是[-127, 127],所以量化因子為127/5.4=23.5。因此向量會(huì)被量化成[28, -12, -101, 28, -73, 19, 56, 127]。

為了還原原始值,可以使用全精度的int8數(shù)值除以量化因子23.5。但是它們?cè)诹炕^(guò)程中是四舍五入取整過(guò)的,會(huì)損失一些精度。

為了不區(qū)分int8格式的正負(fù)符號(hào),我們需要減去最小值,然后再使用最大值作為量化因子。具體實(shí)現(xiàn)如下:

對(duì)于給定的向量或矩陣,首先找到最小值,并減去最小值:

找到X'的絕對(duì)最大值,使用絕對(duì)最大值作為量化因子:

這類似于zero-point量化,但不同之處在于,zero-point量化會(huì)確保全精度數(shù)值0仍然轉(zhuǎn)換為整數(shù)0,從而在數(shù)值0處保證不會(huì)有量化損失。

LLM.int8()算法的具體步驟:

  • 從矩陣隱藏層中,以列為單位,抽取值大于確定閾值的異常值(outliers)。
  • 分別通過(guò)FP16精度對(duì)outliers的部分做矩陣乘法,通過(guò)量化int8精度對(duì)其他的做矩陣乘法。
  • 將量化的部分恢復(fù)成FP16,然后將兩部分合在一起。

「為什么要單獨(dú)抽出異常值(outliers)?」

在大規(guī)模模型中,數(shù)值超出全局閾值范圍的被稱為outliers。8位精度的數(shù)據(jù)是壓縮的,因此量化一個(gè)含有幾個(gè)大數(shù)值的向量會(huì)導(dǎo)致大量錯(cuò)誤的結(jié)果。例如,如果一個(gè)向量中有幾個(gè)數(shù)值遠(yuǎn)大于其他數(shù)值,那么量化這些數(shù)值會(huì)導(dǎo)致其他數(shù)值被壓縮到零,從而產(chǎn)生較大的誤差。

Transformer 架構(gòu)的模型會(huì)將所有的內(nèi)置特征連接組合在一起。因此,這些量化錯(cuò)誤會(huì)在多層網(wǎng)絡(luò)的傳播中逐步混合在一起,導(dǎo)致整體性能的下降。

為了解決這些問(wèn)題,混合精度量化技術(shù)應(yīng)運(yùn)而生。這種技術(shù)將大數(shù)值的特征拆分出來(lái),進(jìn)行更有效的量化和混合精度計(jì)算。

(2) LLM.int8()量化實(shí)現(xiàn)

如下是在Transformers庫(kù)中集成nuances庫(kù),利用bitsandbytes庫(kù)提供的8位量化功能,將模型轉(zhuǎn)換為int8精度。

第一步:導(dǎo)入庫(kù)

import torch
import torch.nn as nn
import bitsandbytes as bnb
from bnb.nn import Linear8bitLt

在自己的數(shù)據(jù)集和任務(wù)上訓(xùn)練模型了,最后保存模型定義自己的模型。可以從任何精度(FP16,BF16,FP32)轉(zhuǎn)換至int8。但模型的輸入需要是FP16精度。所以下面為FP16精度的模型。

fp16_model = nn.Sequential(
    nn.Linear(64, 64),
    nn.Linear(64, 64)
)

第三步:在自己的數(shù)據(jù)集和任務(wù)上訓(xùn)練模型,最后保存模型

# 訓(xùn)練模型
[... train the model ...]

# 保存模型
torch.save(fp16_model.state_dict(), "model.pt")

第四步:定義一個(gè)int8精度的模型。

int8_model = nn.Sequential(
    Linear8bitLt(64, 64, has_fp16_weights=False),
    Linear8bitLt(64, 64, has_fp16_weights=False)
)

這里加入has_fp16_weights的參數(shù)是很重要的。因?yàn)樗J(rèn)會(huì)被設(shè)置為True,這意味著它會(huì)被作為Int8/FP16混合精度訓(xùn)練。然而,我們關(guān)心的是use has_fp16_weights=False時(shí)的計(jì)算內(nèi)存占用。

第五步:加載模型并量化至int8精度。

int8_model.load_state_dict(torch.load("model.pt"))
int8_model = int8_model.to(0)  # 量化

int8_model = int8_model.to(0) 將模型存入顯卡,會(huì)執(zhí)行量化。

如果在其之前打印int8_model[0]的權(quán)重,可得到FP16的精度值。

print("Before quantization:")
print(int8_model[0].weight)


Parameter containing:
tensor([[ 0.0031, -0.0438, 0.0494, ..., -0.0046, -0.0410, 0.0436],
        [-0.1013, 0.0394, 0.0787, ..., 0.0986, 0.0595, 0.0162],
        [-0.0859, -0.1227, -0.1209, ..., 0.1158, 0.0186, -0.0530],
        ...,
        [ 0.0804, 0.0725, 0.0638, ..., -0.0487, -0.0524, -0.1076],
        [-0.0200, -0.0406, 0.0663, ..., 0.0123, 0.0551, -0.0121],
        [-0.0041, 0.0865, -0.0013, ..., -0.0427, -0.0764, 0.1189]],
 dtype=torch.float16)

如果在其之后打印int8_model[0]的權(quán)重,可得到INT8的精度值。

print("After quantization:")
print(int8_model[0].weight)
Parameter containing:
tensor([[ 3, -47, 54, ..., -5, -44, 47],
        [-104, 40, 81, ..., 101, 61, 17],
        [ -89, -127, -125, ..., 120, 19, -55],
        ...,
        [ 82, 74, 65, ..., -49, -53, -109],
        [ -21, -42, 68, ..., 13, 57, -12],
        [ -4, 88, -1, ..., -43, -78, 121]],
 device='cuda:0', dtype=torch.int8, requires_grad=True)

由此可見,權(quán)重值被壓縮了,分布在[-127,127]之間。

如需恢復(fù)FP16精度,則:

print("Restored FP16 precision:")
print((int8_model[0].weight.CB * int8_model[0].weight.SCB) / 127)

然后得到:

tensor([[ 0.0028, -0.0459, 0.0522, ..., -0.0049, -0.0428, 0.0462],
        [-0.0960, 0.0391, 0.0782, ..., 0.0994, 0.0593, 0.0167],
        [-0.0822, -0.1240, -0.1207, ..., 0.1181, 0.0185, -0.0541],
        ..., 
        [ 0.0757, 0.0723, 0.0628, ..., -0.0482, -0.0516, -0.1072],
        [-0.0194, -0.0410, 0.0657, ..., 0.0128, 0.0554, -0.0118], 
        [-0.0037, 0.0859, -0.0010, ..., -0.0423, -0.0759, 0.1190]],
 device='cuda:0')

這和原始的FP16精度權(quán)重非常接近。

第六步:在同一個(gè)顯卡上用FP16精度計(jì)算模型。

input_ = torch.randn(64, dtype=torch.float16)
hidden_states = int8_model(input_.to(torch.device('cuda', 0)))

第七步:集成到Transformer庫(kù)。

使用accelerate庫(kù)初始化模型。當(dāng)處理大型模型時(shí),accelerate庫(kù)提供了很多便利,特別是在內(nèi)存管理和模型初始化方面。init_empty_weights方法可以幫助任何模型在初始化時(shí)不占用任何內(nèi)存。

import torch.nn as nn
from accelerate import init_empty_weights
with init_empty_weights():
    model = nn.Sequential([nn.Linear(100000, 100000) for _ in range(1000)]) # This will take ~0 RAM!

修改.from_pretrained。當(dāng)調(diào)用函數(shù).from_pretrained時(shí),會(huì)內(nèi)置將所有參數(shù)調(diào)用torch.nn.Parameter,這不符合功能模塊Linear8bitLt。因此,將Actor生成的

module._parameters[name] = nn.Parameter(module._parameters[name].to(torch.device("meta")))

修改為:

param_cls = type(module._parameters[name])
kwargs = module._parameters[name].__dict__
module._parameters[name] = param_cls(module._parameters[name].to(torch.device("meta")), **kwargs)

替換 nn.Linear 層為 Linear8bitLt 層

def replace_8bit_linear(model, threshold=6.0, module_to_not_convert="lm_head"):
    for name, module in model.named_children():
        if len(list(module.children())) > 0:
            replace_8bit_linear(module, threshold, module_to_not_convert)

        if isinstance(module, nn.Linear) and name != module_to_not_convert:
            with init_empty_weights():
                model._modules[name] = bnb.nn.Linear8bitLt(
                    module.in_features,
                    module.out_features,
                    module.bias is not None,
                    # 參數(shù)has_fp16_weights需要被設(shè)置為False,從而直接加載模型權(quán)重為int8精度。
                    has_fp16_weights=False,
                    threshold=threshold
                )
    return model
model = replace_8bit_linear(model, threshold=6.0)
責(zé)任編輯:趙寧寧 來(lái)源: 小喵學(xué)AI
相關(guān)推薦

2024-08-19 02:35:00

模型量化深度學(xué)習(xí)

2024-09-13 16:47:06

模型量化AI

2024-04-07 14:28:48

邊緣計(jì)算LLM人工智能

2025-03-27 02:50:00

2023-10-06 20:30:33

大模型LLMtoken

2025-03-04 01:00:00

LLM架構(gòu)數(shù)據(jù)訓(xùn)練

2024-06-18 14:01:17

2024-07-31 14:08:00

2024-09-02 12:30:30

2025-10-15 01:15:00

模型壓縮剪枝蒸餾

2024-04-02 07:25:19

大語(yǔ)言模型青少年編程NLG

2024-07-09 11:01:24

2015-09-25 09:56:37

負(fù)載均衡

2024-10-22 09:17:07

2025-08-25 07:00:00

大語(yǔ)言模型LLM人工智能

2017-05-16 15:33:42

Python網(wǎng)絡(luò)爬蟲核心技術(shù)框架

2024-07-31 08:14:17

2024-04-25 14:40:47

2025-05-29 08:30:00

LLM大語(yǔ)言模型AI

2023-11-06 08:38:50

LLM語(yǔ)言模型ChatGPT
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)