通过实际示例探索Bits-and-Bytes、AWQ、GPTQ、EXL2 和 GGUF 量化技术

📖阅读时长:19分钟

🕙发布时间:2025-02-19

近日热文:全网最全的神经网络数学原理(代码和公式)直观解释
欢迎关注知乎和公众号的专栏内容
LLM架构专栏
知乎LLM专栏
知乎【柏企
公众号【柏企科技说】【柏企阅文

在模型优化的领域中,量化技术发挥着关键作用,尤其是在资源受限的环境下。本文将深入探讨Bits-and-Bytes、GPTQ、GGUF、EXL2和AWQ等量化方法,并通过实际示例展示如何运用它们来提升模型性能。

1. Bits-and-Bytes量化

Bits-and-Bytes是一个功能多样的模型量化库,主要聚焦于4位和8位格式。与GPTQ等方法不同,它在推理过程中进行量化时,无需校准数据集。该库支持的8位量化,对于在资源有限的硬件上运行大型模型非常实用。而在4位量化方面,它引入了FP4和NF4等特定格式,针对微调和推理任务都进行了优化。不过,与GPTQ或GGUF等更专业的量化方法相比,其推理速度可能会稍慢一些。

实例

1. 安装所需的库

在这部分,我们要安装使用Hugging Face工具和bitsandbytes库进行模型量化与运行所需的软件包。这些命令能确保所有依赖项都是最新的。

pip install -q -U bitsandbytes
pip install -q -U git+https://github.com/huggingface/transformers.git
pip install -q -U git+https://github.com/huggingface/peft.git
pip install -q -U git+https://github.com/huggingface/accelerate.git
2. 设置量化配置

这里,我们使用BitsAndBytesConfig为模型配置4位量化。该设置过程简单直接,重点在于通过以4位模式加载模型来减少内存使用量。

from transformers import BitsAndBytesConfig, AutoModelForCausalLM, AutoTokenizer
quantization_config = BitsAndBytesConfig(
    load_in_4bit = True 
)
3. 加载预训练模型和分词器

在此步骤中,我们在应用量化设置的同时,加载预训练模型和分词器。模型会根据GPU的可用性,自动分配到GPU或CPU上运行。

pretrained_model = "Qwen/Qwen2-1.5B-Instruct"
quantized_model = "4bit_quantized-qwen2_1.5B"
device = "cuda" if torch.cuda.is_available() else "cpu"
model = AutoModelForCausalLM.from_pretrained(pretrained_model, quantization_config=quantization_config)
tokenizer = AutoTokenizer.from_pretrained(pretrained_model)
4. 准备输入并生成响应

最后,我们创建一个类似聊天的输入内容,对其进行标记化处理,然后使用模型生成响应。生成的输出会被解码并打印出来,展示模型对给定提示的回复内容。

prompt = tokenizer.apply_chat_template(
    [{"role": "system", "content": "You are a helpful assistent"},
     {"role": "user", "content": "What is Quantization ?"}],
    tokenize=False,
    add_generation_prompt=True
)
inputs = tokenizer(prompt, return_tensors="pt", add_special_tokens=False).to(device)
outputs = model.generate(**inputs, max_new_tokens=24)
response = tokenizer.decode(outputs[0], skip_special_tokens=False)
print(response)

2. GPTQ量化

GPTQ(Gradient Post-Training Quantization)是一种应用广泛的量化方法,支持8位、4位、3位和2位量化。它的核心目标是在保持模型准确性的同时,最大程度地降低量化误差。GPTQ采用逆Hessian方法逐层对模型进行量化,以此确定重要权重的优先级。该方法主要用于在GPU上以较低精度运行大型模型,并且不会显著影响模型的性能表现。在实际应用中,GPTQ因其高效性和高精度而备受青睐。

实例

1. 安装AutoGPTQ库

我们使用--no-build-isolation标志来安装auto - gptq库,这个标志有助于避免在安装过程中出现依赖项隔离问题。

pip install auto-gptq --no-build-isolation
2. 设置分词器

在这里,我们利用预训练模型目录来初始化分词器。

from transformers import AutoTokenizer
from auto_gptq import AutoGPTQForCausalLM, BaseQuantizeConfig
import logging
pretrained_model_dir = "Qwen/Qwen2-1.5B-Instruct"
tokenizer = AutoTokenizer.from_pretrained(pretrained_model_dir, use_fast=True)

use_fast=True选项会启用快速分词器,该分词器针对速度进行了优化,通常在大多数任务中都推荐使用。

3. 配置和量化模型

我们使用BaseQuantizeConfig来配置4位量化模型。

  • 位(Bits):设置为4,代表进行4位量化。
  • 组大小(Group Size):设为128,这是保持模型质量的常见推荐值。
  • desc_act:设置为False可以加快推理速度,但可能会对困惑度产生轻微影响。
quantize_config = BaseQuantizeConfig(
    bits=4,
    group_size=128,
    desc_act=False
)
model = AutoGPTQForCausalLM.from_pretrained(pretrained_model_dir, quantize_config)
example_1 = tokenizer("GPTQ (Gradient Post-Training Quantization) is a widely used 4-bit quantization method focused on minimizing quantization error while preserving model accuracy.")
example_2 = tokenizer("GPTQ quantizes the model layer-by-layer using an inverse-Hessian approach to prioritize important weights.")
examples = [example_1, example_2]
model.quantize(examples)

在设置好配置后,会使用带有“input_ids”和“attention_mask”键的示例数据集对模型进行量化。

4. 保存量化模型

接下来,我们将量化后的模型和分词器保存到指定目录。

quantized_model_dir = "Qwen2-1.5B-GPTQ"
model.save_quantized(quantized_model_dir)
tokenizer.save_pretrained(quantized_model_dir)
model.save_quantized(quantized_model_dir, use_safetensors=True)

模型会以标准格式保存,同时还会以safetensors格式保存,以便实现安全高效的加载。

5. 加载并运行量化模型

在这里,我们将量化模型加载到第一个GPU(cuda:0)上。从预训练模型目录重新加载分词器,并创建聊天提示。提示内容会被标记化并移动到GPU上,然后传递给模型进行生成操作。

model = AutoGPTQForCausalLM.from_quantized(quantized_model_dir, device="cuda:0")
tokenizer = AutoTokenizer.from_pretrained(pretrained_model_dir)
prompt = tokenizer.apply_chat_template(
    conversation=[{"role": "system", "content": "You are a helpful assistent"},
                  {"role": "user", "content": "What is Quantization ?"}],
    tokenize=False,
    add_generation_prompt=True
)
inputs = tokenizer(prompt, return_tensors="pt")
inputs.to("cuda:0")  # loads tensors to the first GPU
outputs = model.generate(**inputs, max_new_tokens=32)
response = tokenizer.decode(outputs[0], skip_special_tokens=True)
print(response)

输出结果会被解码并打印出来,展示模型的响应内容。

3. GGUF量化

GGUF专为需要在CPU和GPU资源之间平衡计算负载的场景而设计。当VRAM(显存)有限时,这种方法尤为有用。GGUF可以将特定层卸载到CPU上,使其适用于具有混合硬件功能的设备设置。它与LLaMA模型配合得很好,并支持卸载层等高级功能,对于那些GPU内存不足的用户来说,使用GGUF能提高效率。

实例

1. 克隆和构建Llama.cpp

我们克隆Llama.cpp存储库,并为CUDA加速进行设置。在获取最新更新后,使用LLAMA_CUBLAS=1编译项目,以增强GPU支持。

!git clone https://github.com/ggerganov/llama.cpp
!cd llama.cpp && git pull && make clean && LLAMA_CUBLAS=1 make
!pip install -r llama.cpp/requirements.txt
!(cd llama.cpp && make)

最后,安装Python依赖项并构建项目,为模型量化做准备。

2. 下载预训练模型

在这部分,我们定义模型ID,并使用Git LFS从Hugging Face下载模型。同时,从ID中提取模型名称,供后续步骤使用。

model_id = "Qwen/Qwen2-1.5B-Instruct"
model_name = model_id.split('/')[-1]
git lfs install
git clone https://huggingface.co/{model_id}

这一步准备了模型转换和量化所需的文件。

3. 将模型转换为FP16

我们使用Llama.cpp转换脚本,将下载的模型转换为FP16格式。这一步非常关键,因为在进一步量化为GGUF格式之前,模型需要先转换为FP16格式。

fp16 = f"{model_name}/{model_name.lower()}.fp16.bin"
!python llama.cpp/convert_hf_to_gguf.py {model_name} --outtype f16 --outfile {fp16}
4. 运行量化

在这个模块中,我们使用Llama.cpp的量化工具对模型进行量化。指定一种量化方法,如q4_k_m,该方法在内存效率和准确性之间取得了较好的平衡。

method = "q4_k_m"
qtype = f"{model_name}/{model_name.lower()}.{method.upper()}.gguf"
!./llama.cpp/llama-quantize {fp16} {qtype} {method}

其他推荐的方法包括q5_k_mq6_kq8_0,其中q8_0是8位量化,与原始模型权重相比几乎无损。

生成的GGUF文件已准备好用于推理。

5. 测试量化模型

最后,我们使用带有样本提示的量化模型进行测试。模型的输出通过Llama.cpp的命令行界面(CLI)生成并评估。

!./llama.cpp/llama-cli -m {qtype} -n 128 --repeat_penalty 1.0 --color -i -r "User:" -f /content/llama.cpp/prompts/chat-with-bob.txt

这个测试展示了量化模型在精度降低的情况下,保持性能的能力,帮助我们检查其实际响应质量。

4. EXL2量化

EXL2是一种经过优化的量化方法,旨在提高推理速度和计算效率。虽然它不如GPTQ等方法常见,但EXL2专注于通过优化权重量化和激活函数来减少推理过程中的延迟。对于低延迟响应至关重要的部署场景,如实时应用程序,EXL2特别有用。

实例

1. 克隆和安装ExLlamaV2

我们首先克隆ExLlamaV2存储库,并安装其依赖项。这个软件包提供了专门针对速度和内存效率优化的模型量化和推理工具。

!git clone https://github.com/turboderp/exllamav2
!(cd exllamav2 && pip install -r requirements.txt && pip install .)
2. 下载预训练模型

接下来,定义模型ID,并使用Git LFS从Hugging Face下载模型。同时提取模型名称,供后续步骤使用。

model_id = "Qwen/Qwen2-1.5B-Instruct"
model_name = model_id.split('/')[-1]
git lfs install
git clone https://huggingface.co/{model_id}
3. 以4位精度运行量化器

在此步骤中,我们运行比特率为4.0的ExLlamaV2量化脚本。指定模型文件作为输入,输出保存在临时目录中。这个过程将4位量化应用于模型权重,从而在减少资源使用的情况下实现高效推理。

!mkdir temp
!python exllamav2/convert.py \
    -i {model_name} \
    -o temp/ \
    -cf {model_name}-exl2/{quant_bpw}bpw/ \
    -b {quant_bpw}
4. 测试量化模型

最后,我们使用ExLlamaV2推理脚本测试量化模型。

!python exllamav2/test_inference.py -m {model_name}-exl2/{quant_bpw}bpw -p "What is quantization ?"

将示例提示(“What is quantization?”)传递给模型,以评估其性能,并验证量化后的输出质量。

5. AWQ量化

AWQ(Activation Weight Quantization)是另一种训练后量化方法,与GPTQ类似,但针对非GPU设置(如笔记本电脑或Mac)进行了优化,以获得更好的性能。在使用激活重新排序时,AWQ特别有用,即使量化数据与推理数据集不同,它也能提高准确性。在这种场景下,与GPTQ相比,AWQ往往速度更快、效果更好,因此成为各种硬件环境下的热门选择。

实例

1. 安装AutoAWQ库

首先安装autoawq库,该库专为使用AWQ方法量化模型而设计。这个软件包对于执行权重量化和优化模型推理至关重要。

pip install autoawq
2. 加载预训练模型和分词器

接下来,使用AutoAWQForCausalLM加载预训练模型,并提供减少CPU内存使用量的选项。

from awq import AutoAWQForCausalLM
from transformers import AutoTokenizer
pretrained_model_dir = "Qwen/Qwen2-1.5B-Instruct"
model = AutoAWQForCausalLM.from_pretrained(
    pretrained_model_dir, **{"low_cpu_mem_usage": True, "use_cache": False}
)
tokenizer = AutoTokenizer.from_pretrained(pretrained_model_dir, trust_remote_code=True)

加载分词器时,trust_remote_code=True参数允许从模型的存储库加载自定义配置和脚本。

3. 量化模型

在这里,我们使用以下设置定义量化配置:

  • zero_point:启用零点量化。
  • q_group_size:设置为128,可在速度和准确性之间取得更好的平衡。
  • w_bit:配置为4位量化。
  • version:指定量化策略(如“GEMM”)。
quant_config = { "zero_point": True, "q_group_size": 128, "w_bit": 4, "version": "GEMM" }
model.quantize(tokenizer, quant_config=quant_config)

这些设置用于量化模型,使其在保持模型质量的同时,适应高效推理。

4. 保存量化模型

在此步骤中,量化模型和分词器被保存到指定目录。这样便于在未来的会话中轻松重新加载和部署量化模型。

quantized_model_dir = "Qwen2_AWQ"
model.save_quantized(quantized_model_dir)
tokenizer.save_pretrained(quantized_model_dir)
5. 加载和测试量化模型

最后,我们将量化模型加载到第一个GPU(cuda:0)上,并使用分词器设置类似聊天的提示。输入内容被标记化后移动到GPU上,然后传递给模型生成响应。

model = AutoAWQForCausalLM.from_quantized(quantized_model_dir, device="cuda:0")
tokenizer = AutoTokenizer.from_pretrained(pretrained_model_dir)
prompt = tokenizer.apply_chat_template(
    [{"role": "system", "content": "You are a helpful assistent"},
     {"role": "user", "content": "What is Quantization ?"}],
    tokenize=False,
    add_generation_prompt=True
)
inputs = tokenizer(prompt, return_tensors="pt")
inputs.to("cuda:0")  # loads tensors to the first GPU
outputs = model.generate(**inputs, max_new_tokens=32)
response = tokenizer.decode(outputs[0], skip_special_tokens=True)
print(response)

输出结果会被解码并打印出来,让我们能够观察量化模型在实际场景中的表现。

## 推荐阅读
1. DeepSeek-R1的顿悟时刻是如何出现的? 背后的数学原理
2. 微调 DeepSeek LLM:使用监督微调(SFT)与 Hugging Face 数据
3. 使用 DeepSeek-R1 等推理模型将 RAG 转换为 RAT
4. DeepSeek R1:了解GRPO和多阶段训练
5. 深度探索:DeepSeek-R1 如何从零开始训练
6. DeepSeek 发布 Janus Pro 7B 多模态模型,免费又强大!

本文由mdnice多平台发布


柏企科技圈
15 声望5 粉丝