如何利用量化在低資源情況下執行70B的LLaMA2模型?

許恆修 | Heng-Shiou Sheu
13 min readJul 30, 2023

從超大型語言模型的硬體需求,到量化技術的革新應用。本文將帶你解密如何在內存限制的設備上順利運行參數量高達70B的LLaMA2模型。

TL;DR

大型語言模型(LLM)雖然效能超強,但參數量動輒就是好幾百甚至上千億,對於計算設備和記憶體的需求,大到一般的公司扛不住。量化(Quantization)則是常見的壓縮手法,透過降低模型權重的精度(比如從32bit降到8bit),換取更快的推理速度和更小的內存需求,雖然這樣會犧牲掉一部分的模型效能。

圖片取自 Lexica

大到裝不下的語言模型

眾所皆知,大型語言模型(Large Language Model; LLM)是超級大的。它們有很多參數,在常見的硬體設備上進行推論、訓練資料,對於使用者來說都是一個極大的挑戰。

通常,這些參數由 Float32 資料格式表示。因此像 GPT-2 這樣具有 1.5B 參數的模型將需要

4 bytes * 1,500,000,000 = 6GB RAM 。

領先的開源模型,如LLaMA2,Falcon 和Guanaco,目前有65B參數,需要大約260GB RAM。這是大量的RAM,甚至沒有計算存儲輸入和輸出資料所需的內容。

圖片取自:https://huggingface.co/blog/hf-bitsandbytes-integration

由於這些龐大的模型需要這麼多 GPU 才玩得起,因此我們需要找到可以降低這些要求的方法,同時保持模型的性能。你可能聽說過量化、蒸餾等能夠在常見的 GPU 上跑起模型的方法

機器學習中常見的資料格式

模型大小主要由參數量以及浮點數資料格式決定,通常是 Float32(FP32)、Float16(FP16)、BFloat16(BF16) 其中一種。有時候在機器學習文章中會使用精度(precision)來描述。

浮點數表達中包含 n 個 bit,每個 bit 都屬於一個特定的類別,負責表示數位的一個組成部分(sign 、range和Precision)。這些表示以下內容。

圖片取自:https://developer.nvidia.com/blog/getting-immediate-speedups-with-a100-tf32/

單精度 Float32 (Single precision; FP32)

float32 (FP32) 代表標準化的 IEEE 32 位浮點表示形式。使用此數據類型,可以表示各種浮點數。在 FP32 中,8 bit 保留用於 Range,23 bits 保留用於 Precision,1 bit 用於表達 sign。除此之外,大多數硬體都支援FP32操作和指令。

半精度 Float16 (Half precision, FP16)

在 float16 (FP16) 資料類型中,5 位保留給 Range,10 位保留給 Precision。這使得FP16數位的可表示範圍遠低於FP32。FP32 可以表達 2^(8+23),在 FP16 中僅能表達 2^(8+10)。這使 FP16 資料格式面臨和溢出(stackoverflow)的風險。

BLoat16 (BF16)

為此,Google Brain 創建 BF16 來避免 FP 16 問題,在BF16中,為 Range 保留8bits(與FP32相同),為 Precision 保留7bits。這意味著在BF16中,我們可以保留與FP32相同的表達範圍。但是相對於 FP16 來說,我們損失了 3 bits 在 Precision 上。

量化:將模型縮小的方式

模型量化主要是將浮點數轉換成整數,減少空間的同時,也敬可能減少計算上精度損失的方法。

準確來說,模型量化是一種壓縮類神經網路參數的方式,他將原本用浮點數表達的數據換成用整數表達。在模型推論過程中,再將正數反向量化成為福點數,得到結果。

圖片取自:https://huggingface.co/blog/hf-bitsandbytes-integration

量化基本上是通過從一種數據類型「捨入」到另一種數據類型來完成的。例如,如果一種數據類型的範圍為 0~9,另一種數據類型的範圍為 0~4,則第一種數據類型中的 “4” 將在第二種數據類型中捨入為“2”。

但是,如果我們在第一種數據類型中有值“3”,它位於第二種數據類型的 1 到 2 之間,那麼我們通常會四捨五入為“2”。這表明第一種數據類型的值“4”和“3”在第二種數據類型中具有相同的值“2”。這突出表明量化是一個嘈雜的過程,可能導致信息丟失,一種有損壓縮。

而在語言模型中常見的量化技術有 8-bit 量化以及 4-bit 量化,這個你可以在 bitsandbytes 這個套件中參數經常看見。

圖片擷取自 BitsAndBytes 使用範例

情境題,老闆要你架設 LLama2 70B 模型!

今天想要在電腦上跑最新最潮的 LLama2 70b 模型的話,我們需要準備多少的 VRAM 呢?

首先,來計算保留最佳狀況,採用單精度(FP32)需要 ```4 bytes * 70,000,000,000 = 280GB RAM```,哎呀,再來使用 BFloat16 好了,也需要 140 GB。這要依然太多,至少 2 張 A100–80GB GPUs 才跑得動。

這時候想過在網路上看過教學文,可以使用量化的方式,我們先採用 8-bits 量化這時候僅需 70GB,一張 A100–80GB 就可以。如果我們更近一步採用 4 bits 量化的話,僅需 35 GB 即可,這時候兩張 RTX 3090 24GB 就可以了。

總結一下,快速計算記憶體需求量算法,直接除上 2 的倍數即可,端看今天採用哪種方式。

表格:記憶體需求量算法

常見的量化手段

QLoRA

QLoRa 結合了量化以及 LoRA 微調參數兩種方法於一身。QLoRA 一種高效的微調方法,可減少記憶體使用量,足以在單個 48GB GPU 上微調 65B 參數模型,同時保留完整的 16 位微調任務性能。主要有三個貢獻

A. 4 NormalFloat NF4

B. Double quantization,通過量化量化常量來減少平均記憶體佔用

C. paged optimizers

採用 BitsAndBytes 套件庫使用時的範例程式碼

##訓練
trainer = transformers.Trainer(
model=model,
train_dataset=data["train"],
args=transformers.TrainingArguments(
per_device_train_batch_size=1,
gradient_accumulation_steps=4,
warmup_steps=2,
max_steps=10,
learning_rate=2e-4,
fp16=True,
logging_steps=1,
output_dir="outputs",
optim="paged_adamw_8bit"
),
data_collator=transformers.DataCollatorForLanguageModeling(tokenizer, mlm=False),
)
model.config.use_cache = False # silence the warnings. Please re-enable for inference!
trainer.train()
##推論
from transformers import BitsAndBytesConfig

nf4_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_use_double_quant=True,
bnb_4bit_compute_dtype=torch.bfloat16
)

model_nf4 = AutoModelForCausalLM.from_pretrained(model_id, quantization_config=nf4_config)

outputs = model_nf4.generate(**inputs, max_new_tokens=20)
print(tokenizer.decode(outputs[0], skip_special_tokens=True))

GPTQ

GPTQ: Accurate Post-Training Quantization for Generative Pre-trained Transformers 一篇研究論文,概述了在 LLM 已經以全 float32 精度進行訓練後量化它們的細節,以及所涉及的權衡。他們的工作是作為一個開源庫實現的,該庫已被AutoGPTQ改編為與 Huggingface Transformers一起使用。

## 訓練
from transformers import AutoTokenizer, TextGenerationPipeline
from auto_gptq import AutoGPTQForCausalLM, BaseQuantizeConfig

pretrained_model_dir = "facebook/opt-125m"
quantized_model_dir = "opt-125m-4bit"

quantize_config = BaseQuantizeConfig(
bits=4, # 將模型量化為 4-bit 數值型態
group_size=128, # 一般建議把這個參數值設定為 128
desc_act=False, # 設為 False 可以顯著提升推論速度,但 perplexity 可能會稍微變差

)

# 載入未量化的模型,預設狀況下,模型總是會被載入到 CPU 內存中
model = AutoGPTQForCausalLM.from_pretrained(pretrained_model_dir, quantize_config)

#量化模型, 範例的資料型態應該為 List[Dict],其中字典的鍵只能有input_ids 和 attention_mask
model.quantize(examples)

# 使用 safetensors 保存量化好的模型
model.save_quantized(quantized_model_dir, use_safetensors=True)
##推論
tokenizer = AutoTokenizer.from_pretrained(pretrained_model_dir, use_fast=True)

# 從 Hugging Face Hub 下載量化好的模型並載入到能被辨識到的第一塊顯示卡中

model = AutoGPTQForCausalLM.from_quantized(repo_id, device="cuda:0", use_safetensors=True, use_triton=False)

# 使用 model.generate 執行推論
print(tokenizer.decode(model.generate(**tokenizer("auto_gptq is", return_tensors="pt").to(model.device))[0]))

# 使用 TextGenerationPipeline
pipeline = TextGenerationPipeline(model=model, tokenizer=tokenizer)
print(pipeline("auto-gptq is")[0]["generated_text"])

GGML

GGML是另一種專注於CPU優化的量化實現,特別是對於Apple M1和M2晶元。它依賴於相同的原則,但是不同的基礎實現。作為一般經驗法則,如果您使用的是 NVIDIA 硬體並且您的整個型號適合 VRAM,GPTQ 會更快。如果您使用的是Apple或Intel硬體,GGML可能會更快。

# 範例程式碼
# Run the GPT-J 6B model (requires 12GB disk space and 16GB CPU RAM)
../examples/gpt-j/download-ggml-model.sh 6B
./bin/gpt-j -m models/gpt-j-6B/ggml-model.bin -p "This is an example"

文章小結

  • 大型語言模型(LLM)具有強大的功能,但其參數量也非常龐大,這使得在常見的硬體設備上進行推理和訓練變得非常困難。
  • 量化是一種壓縮模型的技術,通過降低模型權重的精度來減少模型的大小和計算需求。
  • 常見的量化技術包括8位量化和4位量化。
  • 量化可以使LLM在常見的硬體設備上運行,這使得LLM更易於部署和使用。

總體而言,量化是一種有效的技術,可以使LLM更易於部署和使用。

參考文件

  1. [AutoGPTQ](https://github.com/PanQiWei/AutoGPTQ)
  2. [GGML](https://github.com/ggerganov/ggml)
  3. [PostgresML 與 GGML](https://postgresml.org/blog/announcing-gptq-and-ggml-quantized-llm-support-for-huggingface-transformers)
  4. [](https://moocaholic.medium.com/fp64-fp32-fp16-bfloat16-tf32-and-other-members-of-the-zoo-a1ca7897d407)
  5. [Tim_Detters](https://twitter.com/Tim_Dettmers/status/1605209177919750147)
  6. [](https://huggingface.co/blog/4bit-transformers-bitsandbytes)
  7. [Google introduce BF16](https://cloud.google.com/blog/products/ai-machine-learning/bfloat16-the-secret-to-high-performance-on-cloud-tpus)

--

--

許恆修 | Heng-Shiou Sheu

AI研究員 @喬泰科技,軟體工程師@微光國際,業界講師 @FCU 創能學院,Co-Founder @圖靈文本。專注將科技應用於改善生活中,持續性分享軟體架構設計、前沿人工智慧研究、公司治理等觀念。整合科技、人文思維於一體。聯絡 📪 hengshiousheu@gmail.com