🤗量化入門,💗🧑‍🍳烹製

社群文章 釋出於2023年8月25日

Image by jenestephaniuk on Unsplash

量化是一組技術,用於降低深度學習模型的精度,使模型更小,訓練更快。如果你不理解這句話,別擔心,在這篇部落格文章的最後你會明白。在這篇部落格文章中,我們將介紹...

  1. 什麼是精度,為什麼我們需要量化,以及一個簡單的量化示例;
  2. GPTQ 量化;
  3. 4/8 位(bitsandbytes)量化。

衝呀!

精度

精度可以定義為表示一個數字所使用的有效數字或位數。它是衡量一個數字可以被**精確**表示的程度,或者在表示中可以保留多少細節(在我們的例子中,是二進位制表示)。

在這篇部落格文章中,我不會詳細介紹用於精度的二進位制表示如何工作,但你可以檢視這篇直觀的部落格文章來了解它的工作原理。

我們根據數字本身的不同,以不同的資料型別表示數字。每種資料型別都有其可以表示的數字範圍。常見的資料型別包括:

資料型別 範圍 精度
FP32(單精度) 約 ±1.4013 x 10^-45 到 ±3.4028 x 10^38 7 位小數
FP16(半精度) 約 ±5.96 x 10^-8 到 ±6.55 x 10^4 3-4 位小數
FP8(自定義 8 位浮點) 動態 動態
Int8(8 位整數) -128 到 127(有符號)或 0 到 255(無符號) 無小數

一個數字需要表示得越精確,它所佔用的記憶體就越多。在深度學習中,我們使用浮點表示(FP32/16/8...)來表示權重。雖然 FP32 表示能提供更高的精度和準確性,但模型大小會變得更大,並且訓練或推理(取決於量化型別)期間的計算會變慢。因此,需要降低精度,這也被稱為量化。它是一種有失真壓縮形式,我們壓縮的資訊越多,效能損失就越大。

一種非常簡單的量化技術是將較大範圍的量化型別縮放/投影到較小的尺度,例如(FP32 到 int8)。這看起來如下圖所示 👇

image/png

對於給定資料類型範圍 [-α, α],我們可以使用以下公式投影給定值 ss

s=(2b1)1/α=127/αs = (2^{b-1})-1/α = 127/α

然而,這種方法有不同的缺點,例如在訓練和推理過程中引入開銷,降低效能,並且對資料中的分佈變化敏感。儘管它非常簡單,但在不同的混合精度訓練方法中被大量使用。

主要有兩種量化方法 👇

  • 訓練後量化:這些方法側重於在模型訓練後降低精度。由於它更容易理解,我們將在本部落格文章中主要介紹這種方法,儘管它的效能不如量化感知訓練。
  • 量化感知訓練:這種方法允許量化模型,然後對模型進行微調,以減少量化引起的效能下降,或者量化可以在訓練期間進行。

最先進的方法正試圖克服上述問題。我們現在將討論它們以及如何透過 🤗 生態系統中的工具(transformers、TGI、optimum 和 PEFT)使用它們。

GPTQ 量化

GPTQ 是一種訓練後量化方法,透過校準資料集使模型更小。GPTQ 的核心思想非常簡單:它透過找到權重的壓縮版本來量化每個權重,以使均方誤差最小,如下圖所示 👇

給定一個層 ll 及其權重矩陣 WlW_{l} 和層輸入 XlX_{l},找到量化權重 W^l\hat{W}_{l}

(W^l=argminWl^WlXW^lX22)({\hat{W}_{l}}^{*} = argmin_{\hat{W_{l}}} ||W_{l}X-\hat{W}_{l}X||^{2}_{2})

在 GPTQ 中,我們一次性進行後量化,這既能節省記憶體又能加快推理速度(與我們稍後將介紹的 4/8 位量化不同)。AutoGPTQ 是一個支援 GPTQ 量化的庫。它已整合到 🤗 生態系統中的各種庫中,用於量化模型、使用/服務已量化模型或進一步微調模型。讓我們看看如何做到這些。

首先,安裝 AutoGPTQ

pip install auto-gptq # for cuda versions other than 11.7, refer to installation guide in above link
pip install transformers optimum peft
  • 你可以在 Hugging Face Hub 上執行給定的 GPTQ 模型,如下所示(在此處查詢它們:這裡)👇
from transformers import AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained("TheBloke/Llama-2-7b-Chat-GPTQ", torch_dtype=torch.float16, device_map="auto")

你可以像下面這樣量化任何 transformer 模型 👇

from transformers import AutoModelForCausalLM, AutoTokenizer, GPTQConfig

model_id = "facebook/opt-125m"
tokenizer = AutoTokenizer.from_pretrained(model_id)
quantization_config = GPTQConfig(bits=4, dataset = "c4", tokenizer=tokenizer)

model = AutoModelForCausalLM.from_pretrained(model_id, device_map="auto", quantization_config=quantization_config)
  • 你可以使用 PEFT 在這個gist中進一步微調給定的 GPTQ 模型。
  • 你可以使用 text-generation-inference 量化和提供已經用 GPTQ 方法量化的模型。它在底層不使用 AutoGPTQ 庫。按照此處的說明安裝 TGI 後,你可以像下面這樣執行你在 hub 上找到的 GPTQ 模型 👇
docker run --gpus all --shm-size 1g -p 8080:80 -v $volume:/data ghcr.io/huggingface/text-generation-inference:latest --model-id $model --quantize gptq

要僅使用校準資料集執行量化,只需執行

text-generation-server quantize tiiuae/falcon-40b /data/falcon-40b-gptq

您可以透過執行 text-generation-server quantize --help 瞭解更多量化選項。

使用 bitsandbytes 進行 4/8 位量化

bitsandbytes 是一個用於對模型進行 8 位和 4 位量化的庫。它可以在訓練期間用於混合精度訓練,也可以在推理前使用,以使模型更小。

8 位量化使數十億引數規模的模型能夠適應更小的硬體,而不會降低效能。8 位量化工作原理如下 👇

  1. 從輸入隱藏狀態中按列提取較大的值(離群值)。
  2. 對 FP16 中的離群值和 int8 中的非離群值進行矩陣乘法。
  3. 將非離群值結果放大以將值拉回到 FP16,並將其新增到 FP16 中的離群值結果中。

所以本質上,我們執行矩陣乘法以節省精度,然後將非離群值結果拉回 FP16,而不會在非離群值的初始值和縮放回的值之間產生很大的差異。您可以在下面看到一個示例 👇

您可以像下面這樣安裝 bitsandbytes 👇

pip install bitsandbytes

要在 transformers 中以 8 位載入模型,只需執行 👇

from transformers import AutoModelForCausalLM, AutoTokenizer
import torch

model_8bit = AutoModelForCausalLM.from_pretrained(name, device_map="auto", load_in_8bit=True)
tokenizer = AutoTokenizer.from_pretrained(name)
encoded_input = tokenizer(text, return_tensors='pt')
output_sequences = model.generate(input_ids=encoded_input['input_ids'].cuda())
print(tokenizer.decode(output_sequences[0], skip_special_tokens=True))

bitsandbytes 8 位量化的一個缺點是推理速度比 GPTQ 慢。

4 位浮點(FP4)和 4 位 NormalFloat(NF4)是兩種與 QLoRA 技術(一種引數高效微調技術)一起使用的資料型別。這些資料型別也可以用於在不使用 QLoRA 的情況下減小預訓練模型的大小。TGI 基本上在推理前使用這些資料型別進行訓練後量化。

與 8 位載入類似,您可以在 4 位中載入 transformers 模型,如下所示 👇

from transformers import AutoModelForCausalLM

model = AutoModelForCausalLM.from_pretrained("facebook/opt-350m", load_in_4bit=True, device_map="auto")

在 TGI 中,您可以透過將 --quantize 與以下值一起傳遞來使用 bitsandbytes 量化技術,以實現不同的量化方法

  • 用於 8 位量化的 bitsandbytes
  • 用於 4 位 NormalFloat 的 bitsandbytes-nf4
  • 用於 4 位的 bitsandbytes-fp4,如下所示 👇
docker run --gpus all --shm-size 1g -p 8080:80 -v $volume:/data ghcr.io/huggingface/text-generation-inference:latest --model-id $model --quantize bitsandbytes

有用資源

您可以透過以下連結瞭解更多上述概念。

社群

註冊登入 以評論

© . This site is unofficial and not affiliated with Hugging Face, Inc.