vLLM 推理 AWQ 量化后的模型
vLLM 推理 AWQ 量化后的模型
flyfish
量化方法:指将高精度参数(如 fp32)压缩到低精度格式(如 int4)的技术手段(如均匀量化、AWQ、GPTQ 等)。
量化精度(格式):指模型权重 / 激活值被压缩后的存储位数(如 int4、int8、fp8 等),是量化的 “结果格式”。比如 int4 表示用 4 位整数存储参数,int8 表示用 8 位整数存储。
微调
swift sft \--model Qwen/Qwen2.5-1.5B-Instruct-AWQ \--train_type lora \--dataset 'AI-ModelScope/alpaca-gpt4-data-zh#500' \'AI-ModelScope/alpaca-gpt4-data-en#500' \'swift/self-cognition#500' \--torch_dtype bfloat16 \--num_train_epochs 1 \--per_device_train_batch_size 1 \--per_device_eval_batch_size 1 \--learning_rate 1e-4 \--lora_rank 8 \--lora_alpha 32 \--target_modules all-linear \--gradient_accumulation_steps 16 \--eval_steps 50 \--save_steps 50 \--save_total_limit 2 \--logging_steps 5 \--max_length 2048 \--output_dir output \--system 'You are a helpful assistant.' \--warmup_ratio 0.05 \--dataloader_num_workers 4 \--dataset_num_proc 4 \--model_name '二分' 'erfen' \--model_author '飞鱼' 'flyfish'
微调后的推理
# 导入必要的库
# vllm.LLM:用于高效加载和运行大语言模型的核心类
# SamplingParams:用于配置文本生成时的采样参数(如最大长度、温度等)
# LoRARequest:vllm中用于配置LoRA微调权重加载的类
# AutoTokenizer:用于加载模型对应的分词器,处理文本与token的转换
from vllm import LLM, SamplingParams
from vllm.lora.request import LoRARequest
from transformers import AutoTokenizerdef main():# 定义模型路径# 基础模型路径:指向预训练的基础模型(这里使用Qwen2.5-3B-Instruct)base_model_path = "/media/user/models/Qwen/Qwen2.5-1.5B-Instruct-AWQ/"# LoRA路径:指向微调后生成的LoRA权重文件(包含模型参数增量)lora_path = "/home/user/output/checkpoint-94" # 输入提示文本:用户希望模型回答的问题prompt_text = "你是谁?"# 配置文本生成参数sampling_params = SamplingParams(max_tokens=300, # 生成文本的最大token数量(防止输出过长)temperature=0.5, # 温度参数:控制生成的随机性(0-1,值越低越确定)top_p=0.9, # 核采样参数:只从概率和为0.9的token中采样,平衡多样性和相关性repetition_penalty=1.05 # 重复惩罚:略大于1可减少重复生成的内容)# 初始化分词器# 从基础模型路径加载对应的分词器,确保与模型兼容# trust_remote_code=True:允许加载模型仓库中可能包含的自定义代码(部分模型需要)tokenizer = AutoTokenizer.from_pretrained(base_model_path,trust_remote_code=True)# 初始化LLM模型(启用LoRA功能)llm = LLM(model=base_model_path, # 基础模型路径trust_remote_code=True, # 允许加载远程自定义代码tensor_parallel_size=1, # 张量并行数量:1表示单卡运行(多卡可增加该值)gpu_memory_utilization=0.7, # GPU内存利用率:0.7表示使用70%的GPU内存(避免内存溢出)enable_lora=True, # 启用LoRA功能:允许加载LoRA微调权重max_loras=1, # 最大同时加载的LoRA数量:这里只加载1个max_lora_rank=8, # LoRA的最大秩:需与训练时的rank参数一致(确保权重兼容)quantization="awq")# 构建符合模型要求的对话格式# 多数对话模型需要特定格式(如system/user/assistant角色区分)messages = [{"role": "system", "content": "你是一个经过微调的助手,请根据指令回答。"}, # 系统提示:定义模型行为{"role": "user", "content": prompt_text} # 用户输入:实际问题]# 将对话列表转换为模型可理解的文本格式# add_generation_prompt=True:在结尾添加模型生成的起始标记(如"<|assistant|>")prompt = tokenizer.apply_chat_template(messages,tokenize=False, # 不直接转换为token,保留文本格式add_generation_prompt=True)# 定义LoRA请求配置:指定要加载的LoRA权重lora_request = LoRARequest(lora_name="custom_lora", # LoRA的名称(自定义标识,用于内部管理)lora_path=lora_path, # LoRA权重的实际路径lora_int_id=1 # LoRA的整数ID(用于多LoRA场景下的区分,单LoRA可设为1))# 使用模型生成回答(应用LoRA权重)# 传入处理后的prompt、生成参数和LoRA配置outputs = llm.generate(prompt, sampling_params=sampling_params,lora_request=lora_request # 加载并应用指定的LoRA微调权重)# 打印生成结果print("===== 输入 =====")print(prompt_text) # 输出用户原始输入print("\n===== 加载LoRA后的模型回答 =====")# 提取生成的文本(outputs是批量结果列表,这里取第一个结果的第一个输出)print(outputs[0].outputs[0].text.strip())# 当脚本直接运行时,执行main函数
if __name__ == "__main__":main()
AWQ(Activation-aware Weight Quantization)
AWQ,即Activation-aware Weight Quantization(激活感知权重量化),是一种针对大型语言模型(Large Language Models,简称LLM)设计的后训练量化(Post-Training Quantization,PTQ)技术。它旨在通过将模型权重量化到低位整数(如INT3或INT4),显著减少模型的内存占用和计算需求,同时尽量保持模型的性能和准确性。AWQ由MIT Han Lab开发,主要解决LLM在边缘设备(如移动GPU或桌面GPU)上部署时的内存和带宽限制问题。它是一种硬件友好的方法,只量化权重(weight-only quantization),激活值(activations)保持在FP16精度,从而在内存受限的场景中加速令牌生成。 AWQ的核心洞察是:LLM中的权重并非同等重要,只有少量(0.1%-1%)的“显著权重”(salient weights)对模型输出影响巨大,通过保护这些权重,可以最小化量化误差。
AWQ考虑了模型激活值的分布(activations,即输入到权重的中间值)来优化权重量化过程。具体来说,AWQ通过分析激活值的统计特性(如分布和重要性),选择性地保护那些对模型输出影响较大的权重(salient weights),从而最小化量化引入的误差。这使得AWQ在低位宽量化下表现出色,特别是4-bit。
量化格式
量化格式 | 位宽 (Bits) | 描述 | 优势 | 缺点 | 典型应用与示例 |
---|---|---|---|---|---|
FP32 (Single Precision Floating Point) | 32 | 全精度浮点表示,包括1位符号、8位指数、23位尾数。标准训练和推理的默认格式。 | 高精度,数值范围广(约1e-38到1e+38),支持精确计算。 | 计算和内存开销大(每个参数需4字节),不适合移动设备或大规模部署。 | 模型预训练和全参数微调。在量化前作为基准。 |
FP16 (Half Precision Floating Point) | 16 | 半精度浮点,包括1位符号、5位指数、10位尾数。相比FP32减少一半内存。 | 内存节省50%,推理速度更快,支持混合精度训练(AMP)。在GPU上高效(如NVIDIA Tensor Cores)。 | 动态范围小(指数位少,导致溢出风险),可能精度损失(尤其是梯度计算)。 | 训练加速(如PyTorch AMP)和推理(如Llama模型的FP16版本)。常用于不需极高精度的任务。 |
BF16 (Brain Floating Point 16) | 16 | Google Brain开发的浮点格式,1位符号、8位指数、7位尾数。指数位与FP32相同,尾数减少。 | 动态范围广(与FP32相当,避免溢出),适合训练(梯度稳定)。内存节省50%。 | 尾数位少,导致精度稍低(约FP32的1/128精度)。在某些硬件上不如FP16优化。 | LLM训练(如Transformer模型),尤其在TPU或A100 GPU上。常用于QAT以保持训练稳定性。 |
INT8 (8-bit Integer) | 8 | 8位整数表示,通常有符号(-128到127)或无符号(0到255)。常用于权重和激活量化。 | 内存节省75%(相对于FP32),整数运算快(GPU/CPU优化)。精度损失小(<1%)。 | 范围有限,需缩放因子处理溢出。动态量化可能增加计算开销。 | PTQ和QAT中的权重量化(如MobileNet、ResNet的部署)。在边缘设备如手机AI中常见。 |
UINT8 (Unsigned 8-bit Integer) | 8 | 无符号8位整数(0到255)。类似于INT8,但无负值。 | 与INT8类似,适合非负权重或激活。计算高效。 | 无法表示负值,需额外处理符号。范围更窄。 | 激活量化(如TensorFlow Lite),或特定模型层(如ReLU后激活)。 |
INT4 (4-bit Integer) | 4 | 4位整数,通常有符号(-8到7)或无符号(0到15)。激进量化,常需分组或激活感知。 | 内存节省87.5%(相对于FP32),推理极快。适合大模型部署。 | 精度损失大(2-5%),易引入误差。需先进方法如AWQ优化。 | AWQ或GPTQ中的权重量化 |
UINT4 (Unsigned 4-bit Integer) | 4 | 无符号4位整数(0到15)。 | 与INT4类似,但无负值支持。极致压缩。 | 范围极窄,无法处理负权重。需符号位额外编码。 | 特定量化方案中,如非负权重的自定义模型。较少见于通用LLM。 |
INT3 (3-bit Integer) | 3 | 3位整数,通常有符号(-4到3)或无符号(0到7)。极低位宽,需要高级优化。 | 内存节省约90%,超高效部署。 | 精度损失显著(>5%),需AWQ或GPTQ保护显著权重。泛化差。 | 实验性量化(如AWQ的INT3-g128),用于研究或极致边缘设备(如IoT)。 |
INT2 (2-bit Integer) | 2 | 2位整数,通常有符号(-2到1)或无符号(0到3)。最低位宽,实验性质。 | 最大压缩(>90%节省),潜在速度提升。 | 精度大幅下降(>10%),几乎不可用于复杂任务。除非结合混合精度。 | 研究中结合GPTQ/AWQ(如OPT-6.7B的INT2实验),不推荐生产使用。 |
NF4 (Normal Float 4) | 4 (有效) | 基于正态分布的4位浮点量化,类似INT4但优化分布。 | 更好地捕捉权重分布,精度高于标准INT4。内存节省相同。 | 需自定义内核支持,实现复杂。 | BitsAndBytes库中的LLM量化(如QLoRA的nf4选项)。适合微调。 |
FP8 (8-bit Floating Point) | 8 | 8位浮点,包括变体如E4M3(1符号、4指数、3尾数)或E5M2(1符号、5指数、2尾数)。 | 平衡浮点精度和整数效率。动态范围好。 | 硬件支持有限(如4090、H100 GPU)。精度介于INT8和FP16间。 | Transformer引擎中的训练/推理(如NVIDIA的混合精度)。未来趋势。 |
MX (Microscaling Formats) | 变体 (e.g., 8/9-bit) | Intel/AMD提出的共享指数缩放格式,支持FP/INT混合。 | 高效分组量化,减少缩放开销。 | 需特定硬件(如Intel AMX)。兼容性差。 | 高效矩阵乘法(如GEMM操作)中的实验量化。 |
位宽与压缩关系:位宽越低,内存节省越大(相对于FP32:FP16节省50%,INT8节省75%,INT4节省87.5%)。但精度风险增加,需要如AWQ(Activation-aware Weight Quantization)或GPTQ等方法优化。
有符号 vs. 无符号:有符号(如INT)支持负值,适合权重;无符号(如UINT)用于激活(如ReLU后)。
分组量化(Group-wise):低位格式如INT4常分组(e.g., 每128权重共享缩放因子),减少误差。
混合使用:实际中常混合,如权重INT4 + 激活FP16(W4A16),平衡效率与精度。