量化KV快取¶
FP8 KV快取¶
將KV快取量化為FP8可減少其記憶體佔用。這增加了可儲存在快取中的token數量,從而提高了吞吐量。
FP8 格式¶
OCP (開放計算專案) 指定了兩種常見的8位浮點資料格式
- E5M2 (5位指數和2位尾數)
- E4M3FN (4位指數和3位尾數,通常縮寫為E4M3)
E4M3格式比E5M2提供更高的精度。然而,由於其動態範圍較小(±240.0),E4M3通常需要與每個量化張量一起使用更高精度(FP32)的縮放因子。
當前限制¶
目前,僅支援逐張量(標量)縮放因子。正在開發中以支援更細粒度(例如,逐通道)的縮放因子。
效能影響¶
當前的FP8 KV快取實現主要透過允許約兩倍的KV快取分配空間來提高吞吐量。這使得可以:
- 處理單個請求的更長上下文長度,或
- 處理更多併發請求批次
然而,目前沒有延遲改進,因為該實現尚未包含融合的反量化和注意力操作。未來的版本將支援帶硬體加速的量化注意力,這應該會提供額外的效能優勢。儘管最新的晶片產品(例如AMD MI300、NVIDIA Hopper或更高版本)支援FP8與其他格式(fp32、fp16、bf16)之間的本地硬體轉換,但此優勢尚未完全實現。
研究表明,FP8 E4M3量化通常只會對推理精度造成極小的降級,使其成為吞吐量最佳化的實用選擇。
使用示例¶
以下是如何啟用FP8量化的示例
程式碼
# To calculate kv cache scales on the fly enable the calculate_kv_scales
# parameter
from vllm import LLM, SamplingParams
sampling_params = SamplingParams(temperature=0.7, top_p=0.8)
llm = LLM(model="meta-llama/Llama-2-7b-chat-hf",
kv_cache_dtype="fp8",
calculate_kv_scales=True)
prompt = "London is the capital of"
out = llm.generate(prompt, sampling_params)[0].outputs[0].text
print(out)
kv_cache_dtype
引數指定 KV 快取儲存的資料型別: - "auto"
:使用模型的預設“未量化”資料型別 - "fp8"
或 "fp8_e4m3"
:在 CUDA 11.8+ 和 ROCm (AMD GPU) 上支援 - "fp8_e5m2"
:在 CUDA 11.8+ 上支援
校準標度以獲得更高精度¶
為了在使用FP8 KV快取時獲得最佳模型質量,我們建議使用針對代表性推理資料調整的校準標度。LLM Compressor 是完成此過程的推薦工具。
安裝¶
首先,安裝所需的依賴項
使用示例¶
以下是一個使用 meta-llama/Llama-3.1-8B-Instruct
的完整示例(大多數模型可以使用相同的模式)
程式碼
from datasets import load_dataset
from transformers import AutoModelForCausalLM, AutoTokenizer
from llmcompressor.transformers import oneshot
# Select model and load it
MODEL_ID = "meta-llama/Llama-3.1-8B-Instruct"
model = AutoModelForCausalLM.from_pretrained(MODEL_ID, device_map="auto", torch_dtype="auto")
tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
# Select calibration dataset
DATASET_ID = "HuggingFaceH4/ultrachat_200k"
DATASET_SPLIT = "train_sft"
# Configure calibration parameters
NUM_CALIBRATION_SAMPLES = 512 # 512 samples is a good starting point
MAX_SEQUENCE_LENGTH = 2048
# Load and preprocess dataset
ds = load_dataset(DATASET_ID, split=DATASET_SPLIT)
ds = ds.shuffle(seed=42).select(range(NUM_CALIBRATION_SAMPLES))
def process_and_tokenize(example):
text = tokenizer.apply_chat_template(example["messages"], tokenize=False)
return tokenizer(
text,
padding=False,
max_length=MAX_SEQUENCE_LENGTH,
truncation=True,
add_special_tokens=False,
)
ds = ds.map(process_and_tokenize, remove_columns=ds.column_names)
# Configure quantization settings
recipe = """
quant_stage:
quant_modifiers:
QuantizationModifier:
kv_cache_scheme:
num_bits: 8
type: float
strategy: tensor
dynamic: false
symmetric: true
"""
# Apply quantization
oneshot(
model=model,
dataset=ds,
recipe=recipe,
max_seq_length=MAX_SEQUENCE_LENGTH,
num_calibration_samples=NUM_CALIBRATION_SAMPLES,
)
# Save quantized model: Llama-3.1-8B-Instruct-FP8-KV
SAVE_DIR = MODEL_ID.split("/")[1] + "-FP8-KV"
model.save_pretrained(SAVE_DIR, save_compressed=True)
tokenizer.save_pretrained(SAVE_DIR)
上述指令碼將在您當前目錄下建立一個資料夾,其中包含您已量化的模型(例如,Llama-3.1-8B-Instruct-FP8-KV
)和校準後的標度。
執行模型時,您必須指定 kv_cache_dtype="fp8"
才能啟用 KV 快取量化並使用這些標度。