FP8 W8A8#

vLLM 支持使用 Nvidia H100 和 AMD MI300x 等 GPU 上的硬件加速进行 FP8(8 位浮点)权重和激活量化。目前,仅官方支持 Hopper 和 Ada Lovelace GPU 用于 W8A8。Ampere GPU 支持使用 Marlin 内核进行 W8A16(仅权重 FP8)量化。使用 FP8 量化模型可以将模型内存需求减少 2 倍,并将吞吐量提高高达 1.6 倍,同时对准确性的影响最小。

请访问 HF 集合中的 vLLM 可直接使用的流行 LLM 量化 FP8 检查点

硬件中通常支持的 FP8 类型有两种不同的表示形式,每种在不同的场景中都有用:

  • E4M3: 包含 1 个符号位、4 个指数位和 3 个尾数位。它可以存储高达 +/-448 和 nan 的值。

  • E5M2: 包含 1 个符号位、5 个指数位和 2 个尾数位。它可以存储高达 +/-57344、+/- infnan 的值。增加动态范围的代价是存储值的精度降低。

备注

FP8 计算在计算能力 > 8.9(Ada Lovelace、Hopper)的 NVIDIA GPU 上受支持。FP8 模型将在计算能力 > 8.0(Ampere)上作为仅权重 W8A16 运行,利用 FP8 Marlin。

在线动态量化的快速入门#

可以使用 vLLM 将原始精度 BF16/FP16 模型动态量化为 FP8,无需任何校准数据。你可以在命令行中指定 --quantization="fp8" 或在 LLM 构造函数中设置 quantization="fp8" 来启用此功能。

在此模式下,所有线性模块(最终的``lm_head``除外)的权重都被量化为 FP8_E4M3 精度,并使用每个张量的比例。激活在每次前向传递期间计算其最小值和最大值,以提供用于高精度的动态每个张量比例。因此,此模式下的延迟改进有限。

from vllm import LLM
model = LLM("facebook/opt-125m", quantization="fp8")
# INFO 06-10 17:55:42 model_runner.py:157] Loading model weights took 0.1550 GB
result = model.generate("Hello, my name is")

警告

目前,我们在量化为 8 位之前以原始精度加载模型,因此你需要足够的内存来加载整个模型。

安装#

要使用 vLLM 生成性能优异的 FP8 量化模型,你需要安装 llm-compressor 库:

$ pip install llmcompressor==0.1.0

量化过程#

量化过程涉及三个主要步骤:

  1. 加载模型

  2. 应用量化

  3. 在 vLLM 中评估精度

1. 加载模型#

使用 SparseAutoModelForCausalLM``(它包装了 ``AutoModelForCausalLM)来保存和加载量化模型:

from llmcompressor.transformers import SparseAutoModelForCausalLM
from transformers import AutoTokenizer

MODEL_ID = "meta-llama/Meta-Llama-3-8B-Instruct"

model = SparseAutoModelForCausalLM.from_pretrained(
  MODEL_ID, device_map="auto", torch_dtype="auto")
tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)

2. 应用量化#

对于 FP8 量化,我们可以使用简单的 RTN 量化来恢复精度。我们建议使用 FP8_DYNAMIC 方案针对所有 Linear 层,该方案使用:

  • 权重上的静态、每个通道量化

  • 激活上的动态、每个标记量化

由于简单的 RTN 不需要数据进行权重量化,并且激活是动态量化的,因此我们不需要任何校准数据来进行此量化流程。

from llmcompressor.transformers import oneshot
from llmcompressor.modifiers.quantization import QuantizationModifier

# Configure the simple PTQ quantization
recipe = QuantizationModifier(
  targets="Linear", scheme="FP8_DYNAMIC", ignore=["lm_head"])

# Apply the quantization algorithm.
oneshot(model=model, recipe=recipe)

# Save the model.
SAVE_DIR = MODEL_ID.split("/")[1] + "-FP8-Dynamic"
model.save_pretrained(SAVE_DIR)
tokenizer.save_pretrained(SAVE_DIR)

3. 评估精度#

安装 vllmlm-evaluation-harness

$ pip install vllm lm_eval==0.4.3

vllm 中加载并运行模型:

from vllm import LLM
model = LLM("./Meta-Llama-3-8B-Instruct-FP8-Dynamic")
model.generate("Hello my name is")

使用 lm_eval 评估精度(例如,在 gsm8k 的 250 个样本上):

备注

量化模型可能对 bos 标记的存在敏感。lm_eval 默认情况下不会添加 bos 标记,因此请确保在运行评估时包含 add_bos_token=True 参数。

$ MODEL=$PWD/Meta-Llama-3-8B-Instruct-FP8-Dynamic
$ lm_eval \
  --model vllm \
  --model_args pretrained=$MODEL,add_bos_token=True \
  --tasks gsm8k  --num_fewshot 5 --batch_size auto --limit 250

以下是结果分数的示例:

|Tasks|Version|     Filter     |n-shot|  Metric   |   |Value|   |Stderr|
|-----|------:|----------------|-----:|-----------|---|----:|---|-----:|
|gsm8k|      3|flexible-extract|     5|exact_match|↑  |0.768|±  |0.0268|
|     |       |strict-match    |     5|exact_match|↑  |0.768|±  |0.0268|

故障排除和支持#

如果你遇到任何问题或有功能请求,请在 vllm-project/llm-compressor GitHub 存储库中打开一个问题。

已弃用流程#

备注

以下信息保留用于参考和搜索目的。下面描述的量化方法已被弃用,取而代之的是上面描述的``llmcompressor``方法。

对于静态每张量离线量化到 FP8,请安装 AutoFP8 库

git clone https://github.com/neuralmagic/AutoFP8.git
pip install -e AutoFP8

此包引入了 AutoFP8ForCausalLMBaseQuantizeConfig 对象,用于管理模型的压缩方式。

使用静态激活缩放因子的离线量化#

你可以使用 AutoFP8 和校准数据,通过启用 activation_scheme="static" 参数来生成权重和激活的每张量静态缩放因子。

from datasets import load_dataset
from transformers import AutoTokenizer
from auto_fp8 import AutoFP8ForCausalLM, BaseQuantizeConfig

pretrained_model_dir = "meta-llama/Meta-Llama-3-8B-Instruct"
quantized_model_dir = "Meta-Llama-3-8B-Instruct-FP8"

tokenizer = AutoTokenizer.from_pretrained(pretrained_model_dir, use_fast=True)
tokenizer.pad_token = tokenizer.eos_token

# Load and tokenize 512 dataset samples for calibration of activation scales
ds = load_dataset("mgoin/ultrachat_2k", split="train_sft").select(range(512))
examples = [tokenizer.apply_chat_template(batch["messages"], tokenize=False) for batch in ds]
examples = tokenizer(examples, padding=True, truncation=True, return_tensors="pt").to("cuda")

# Define quantization config with static activation scales
quantize_config = BaseQuantizeConfig(quant_method="fp8", activation_scheme="static")

# Load the model, quantize, and save checkpoint
model = AutoFP8ForCausalLM.from_pretrained(pretrained_model_dir, quantize_config)
model.quantize(examples)
model.save_quantized(quantized_model_dir)

你的模型检查点,包含量化后的权重和激活,应该位于 Meta-Llama-3-8B-Instruct-FP8/。最后,你可以在 vLLM 中直接加载量化后的模型检查点。

from vllm import LLM
model = LLM(model="Meta-Llama-3-8B-Instruct-FP8/")
# INFO 06-10 21:15:41 model_runner.py:159] Loading model weights took 8.4596 GB
result = model.generate("Hello, my name is")