提高LoRA模型的推理速度:合并与GPTQ量化

背景

在某领域任务中,使用自有数据集通过 LoRA 方式训练了一个 LoRA adapter 模型。在推理阶段,常规做法是读入一个量化模型,并使用 PeftModel.from_pretrained() 读取 16 位的 adapter 以挂载该 adapter。不过,这种方法的推理速度较慢

为了兼顾推理速度与质量,需要对模型和 adapter 进行 16 位合并以及 GPTQ 量化,本文以Qwen 2.5-vl为例,实现一个合并与量化过程。 适用场景:推理机显存有限,且希望保证推理速度和推理质量均衡。

以Qwen 2.5 VL为例,我们采用transformer读取以及合并模型,ms-swift进行GPTQ量化,vllm进行推理。

安装依赖

# 克隆 ms-swift 项目仓库到本地
git clone https://github.com/modelscope/ms-swift.git
# 进入 ms-swift 目录
cd ms-swift
# 安装 ms-swift 及其相关的语言模型(llm)依赖,-e 选项允许对安装的包进行可编辑安装,方便开发过程中的修改和调试
pip install -e.[llm] -q
pip install --upgrade transformers -q
pip install -U auto_gptq optimum -q
pip install -U bitsandbytes -q
pip install -U peft -q
pip install trl -q
pip install qwen_vl_utils -q
pip install vllm -q

训练

本文不再赘述,可参考https://colab.research.google.com/github/unslothai/notebooks/blob/main/nb/Qwen2_VL_(7B)-Vision.ipynbhttps://colab.research.google.com/github/unslothai/notebooks/blob/main/nb/Qwen2_VL_(7B)-Vision.ipynb等。训练后需要保留adapter模型,也可以在训练后直接使用save_pretrained_merged保存合并后模型,跳过加载与合并步骤。

注意训练时不要量化base model(QLoRA)。原因在于:

  • 训练阶段用QLoRA,推理阶段也要用QLoRA。但QLoRA因为base model和adapter精度不同,合并会报错,不能用本文方法后续量化。如果希望合并后高效部署,请用LoRA重新训练;

  • 训练阶段用LoRA,推理阶段也要用LoRA,本文适用LoRA的情况。

⚠️ 把LoRA adapter挂载到量化后的base model上,或QLoRA的权重加载到16bit精度的base model上,会导致困惑度(ppl,越低越好)增高。https://medium.com/@bnjmn_marie/lora-load-and-merge-your-adapters-with-care-3204119f0426

加载与合并

在已有adapter文件的基础上,需要加载模型并合并。这一步可以将模型地址CKPT_PATH改成自己的基座模型地址,lora_path是LoRA adapter的保存地址。

from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training, PeftModel
from transformers import (
AutoModelForCausalLM,
AutoTokenizer,
Qwen2_5_VLForConditionalGeneration,
AutoProcessor,
)
import torch
compute_dtype = getattr(torch, "float16")

lora_path = 'YOUR PATH'
CKPT_PATH='Qwen/Qwen2.5-VL-7B-Instruct'
tokenizer = AutoProcessor.from_pretrained(CKPT_PATH, 
                                         trust_remote_code=True, 
                                         use_fast=True)
# use cuda device
model = Qwen2_5_VLForConditionalGeneration.from_pretrained(CKPT_PATH, # 3B or 7B
                                             device_map="auto",
                                             trust_remote_code=True,
                                            torch_dtype=compute_dtype,
                                            ).eval()
# merge as fp16 model and output
lora_model = PeftModel.from_pretrained(
    model,
    lora_path,
    torch_dtype=torch.float16,
)
lora_model = lora_model.merge_and_unload()
lora_model.save_pretrained("qwen_2.5_vl_r1_2")
tokenizer.save_pretrained("qwen_2.5_vl_r1_2")

量化

预量化需要一个数据集用于校准,可准备一个微调训练中用到的数据集(如果是强化微调,请预先用训练后模型生成一些QA)。json数据集中每条数据格式如下:

{"messages": [{"role": "user", "content": "什么是SFT?"}, {"role": "assistant":"content":""}]}

采用ms-swift进行量化。为了防止爆显存,量化数据集所选数量quant_n_samples不需要很大,且截断长度max_length不需要设置很大.

# 参考https://blog.youkuaiyun.com/xiaobing259/article/details/147527746
OMP_NUM_THREADS=4
swift export \
    --model 'YOUR ROOT/qwen_2.5_vl_r1_2' \
    --dataset 'quantize_dataset.json#100'\
              'AI-ModelScope/alpaca-gpt4-data-zh#30' \
              'AI-ModelScope/alpaca-gpt4-data-en#30' \
    --quant_n_samples 160 \
    --quant_batch_size 1 \
    --max_length 512 \
    --quant_method gptq \
    --quant_bits 4 \
    --output_dir 'Qwen2.5-VL-Instruct-GPTQ-Int4'

量化Qwen 2.5 VL 7B Instruct+LoRA(r=32),采用以上配置刚好可以在双卡Tesla T4上运行。

推理

采用GPTQ量化的模型,推荐用vllm进行推理,若采用transformers架构,实测推理速度很慢。 ⚠️ 需要在推理机上也安装上述依赖

from vllm import LLM, SamplingParams
from transformers import AutoProcessor, TextStreamer
import torch

CKPT_PATH='YOUR PATH/Qwen2.5-VL-Instruct-GPTQ-Int4'
tokenizer = AutoProcessor.from_pretrained(CKPT_PATH, trust_remote_code=True)
model = LLM(
    model=CKPT_PATH,
    dtype="float16",  # 同 compute_dtype
    quantization="gptq",  
    gpu_memory_utilization=0.9,
    trust_remote_code=True,
)
messages.append({'role': 'user', 'content':"YOUR CONTENT"})
input_text = tokenizer.apply_chat_template(messages,tokenize=False,add_generation_prompt = True)
sampling_params = SamplingParams(temperature=0.6, top_p=0.95, top_k=20, max_tokens=4096)
output_st = model.generate(
    [input_text],
    sampling_params = sampling_params,
)[0].outputs[0].text
print(output_st)

量化后速度比较

模型设定

推理框架

推理速度 tokens/s

显存占用

推理质量(目标任务上)

Qwen 2.5 VL 7B Instruct

vllm

-

oom

-

Qwen 2.5 VL 7B Instruct

transformers

12.1

Qwen 2.5 VL 7B Instruct+LoRA

vllm

-

oom

-

Qwen 2.5 VL 7B Instruct+LoRA

transformers

8.3

Qwen 2.5 VL 7B Instruct Merged GPTQ INT4

vllm

40.6

Qwen 2.5 VL 7B Instruct Merged GPTQ INT4

transformers

2(不推荐)

除了gptq,awq等ms-swift支持的量化方案也可以尝试,需要安装不同的依赖,模型和transformers库支持即可。

<think>好的,我现在需要帮助用户解决他们关于量化模型的问题。用户之前已经使用Hugging Face的Transformers库微调了模型,并且已经将微调后的模型基座模型合并。现在他们想知道如何进行量化,并请求具体的代码示例。 首先,我需要回顾一下量化的基本概念,确保自己理解正确。量化是将模型参数的精度降低,比如从FP32降到INT8或4-bit,以减少模型大小和提升推理速度。用户已经合并模型,所以可能需要的是训练后量化(PTQ)或者使用现有的工具进行量化,而不需要重新训练。 接下来,用户的模型是用Hugging Face的Transformers库微调的,因此我需要考虑适用于该库的量化工具。常见的工具包括bitsandbytes、GPTQ、AWQ等。其中,bitsandbytes支持4-bit和8-bit量化,并且Transformers库集成较好,适合快速实现。GPTQ则需要更复杂的步骤,可能需要使用AutoGPTQ库,但通常能提供更好的性能。用户可能需要具体的代码示例,因此选择bitsandbytes可能更直接,尤其是因为他们可能希望快速应用量化而无需太多配置。 然后,我需要考虑用户可能的场景。他们可能希望将模型部署到资源受限的环境中,比如移动设备或低显存的GPU上。因此,重点应放在如何应用量化,减少模型大小和内存占用,同时保持合理的推理速度。用户可能需要知道不同的量化方法之间的权衡,比如4-bit和8-bit在速度和精度上的差异。 用户的具体问题还提到已经合并模型,这意味着他们可能已经将LoRA等适配器合并到基座模型中。这时候,直接对整个模型进行量化是可行的。需要检查是否有合并后的模型保存为标准的Transformers格式,这样可以直接加载并进行量化。 接下来,我需要提供具体的代码示例。使用bitsandbytes的4-bit量化可以通过在from_pretrained方法中设置load_in_4bit=True来实现。同时,可能需要调整其他参数,如bnb_4bit_compute_dtype和量化类型。此外,需要提醒用户安装必要的库,如bitsandbytes和accelerate。 另外,如果用户希望更高效的推理,可以考虑使用GPTQ量化。这里需要介绍使用AutoGPTQ库的步骤,包括加载模型、进行量化,并保存量化后的模型。需要注意的是,GPTQ量化需要校准数据集,用户可能需要准备一些数据样本来进行校准,这对他们来说可能是一个额外的步骤,但能带来更好的效果。 还需要提到的是,量化模型的评估非常重要。用户需要检查量化后的模型在任务上的性能是否下降太多,必要时可能需要调整量化参数或选择不同的层进行量化。此外,硬件兼容性也是一个问题,比如某些GPU可能不支持4-bit运算,需要确认用户的部署环境。 最后,用户可能需要一些注意事项,比如量化后的模型不能继续训练,只能用于推理,以及不同量化方法对资源的需求。同时,提供参考链接和安装命令可以帮助用户快速开始。 总结起来,我需要分步骤介绍两种主要的量化方法:bitsandbytes的4/8-bit量化GPTQ量化,分别给出代码示例,并说明它们的优缺点和适用场景。同时,强调安装步骤和评估的重要性,确保用户能够顺利实施量化并验证结果。</think>好的!如果你已经用Huggingface Transformers微调并合并模型量化可以通过 **`bitsandbytes`**(4/8-bit量化)或 **`AutoGPTQ`**(GPTQ量化)等工具实现。以下是具体方法和代码示例: --- ### **1. 量化工具选择** | **工具** | **优点** | **适用场景** | |------------------|---------------------------------------------|--------------------------------| | **bitsandbytes** | 快速集成,支持4/8-bit量化,无需校准数据 | 快速部署,轻量级推理 | | **AutoGPTQ** | 更高精度,支持GPTQ算法,显存占用更低 | 对精度要求高或需要极致压缩的场景 | | **AWQ** | 保留模型激活敏感权重,平衡速度和精度 | 需要高性能推理的场景 | --- ### **2. 方法一:使用`bitsandbytes`(4/8-bit量化)** 这是Huggingface官方推荐的轻量化方法,适合快速部署。支持 **LLM.int8()** 和 **4-bit** 量化。 #### **步骤 1:安装依赖** ```bash pip install bitsandbytes accelerate # 必须安装 ``` #### **步骤 2:加载模型时直接量化** ```python from transformers import AutoModelForCausalLM, AutoTokenizer model_name = "你的合并模型路径" tokenizer = AutoTokenizer.from_pretrained(model_name) # 4-bit量化(推荐) model = AutoModelForCausalLM.from_pretrained( model_name, device_map="auto", # 自动分配设备(GPU/CPU) load_in_4bit=True, # 启用4-bit量化 bnb_4bit_compute_dtype="float16", # 计算时用FP16加速 bnb_4bit_quant_type="nf4", # 量化类型:nf4或fp4 trust_remote_code=True # 如果模型有自定义代码 ) # 8-bit量化(兼容性更好) # model = AutoModelForCausalLM.from_pretrained( # model_name, # load_in_8bit=True, # device_map="auto" # ) ``` #### **步骤 3:推理测试** ```python input_text = "中国的首都是哪里?" inputs = tokenizer(input_text, return_tensors="pt").to("cuda") outputs = model.generate(**inputs, max_new_tokens=50) print(tokenizer.decode(outputs[0], skip_special_tokens=True)) ``` --- ### **3. 方法二:使用`AutoGPTQ`(GPTQ量化)** GPTQ是一种更精细的量化方法,需少量校准数据,但压缩率和精度更高。 #### **步骤 1:安装依赖** ```bash pip install auto-gptq optimum # 安装AutoGPTQ和优化库 ``` #### **步骤 2量化模型(需要校准数据)** ```python from auto_gptq import AutoGPTQForCausalLM, BaseQuantizeConfig # 定义量化配置 quantize_config = BaseQuantizeConfig( bits=4, # 4-bit量化 group_size=128, # 量化分组大小(平衡精度) desc_act=False, # 是否按顺序激活(Llama设为False) ) # 加载原始模型量化 model = AutoGPTQForCausalLM.from_pretrained( "你的合并模型路径", quantize_config, trust_remote_code=True ) # 准备校准数据(示例:从训练集随机采样128条) from datasets import load_dataset calib_data = load_dataset("your_dataset")["train"].shuffle().select(range(128)) calib_data = [tokenizer(text["text"], return_tensors="pt") for text in calib_data] # 执行量化 model.quantize(calib_data, use_triton=True) # use_triton加速(需GPU) # 保存量化模型 model.save_quantized("量化模型保存路径") tokenizer.save_pretrained("量化模型保存路径") ``` #### **步骤 3:加载量化模型推理** ```python from transformers import AutoTokenizer from auto_gptq import AutoGPTQForCausalLM model = AutoGPTQForCausalLM.from_quantized( "量化模型保存路径", device="cuda:0", use_triton=True, # 启用Triton推理加速 trust_remote_code=True ) tokenizer = AutoTokenizer.from_pretrained("量化模型保存路径") # 测试生成 input_text = "如何做西红柿炒鸡蛋?" inputs = tokenizer(input_text, return_tensors="pt").to("cuda") outputs = model.generate(**inputs, max_new_tokens=100) print(tokenizer.decode(outputs[0], skip_special_tokens=True)) ``` --- ### **4. 方法对比选择** | **指标** | **bitsandbytes** | **AutoGPTQ** | |-----------------|------------------|-------------------| | **量化速度** | 快(无需校准) | 慢(需校准数据) | | **显存占用** | 较高 | 更低 | | **推理速度** | 中等 | 更快 | | **精度损失** | 略高(4-bit) | 更低 | | **易用性** | 简单 | 需准备校准数据 | - **推荐场景**: - 快速测试 → 用`bitsandbytes`的4-bit量化- 生产部署 → 用`AutoGPTQ`或`AWQ`。 --- ### **5. 注意事项** 1. **硬件支持**:确保GPU支持INT4/INT8运算(如NVIDIA Turing架构及以上)。 2. **量化后训练**:量化模型不能继续训练(需先反量化)。 3. **校准数据**:GPTQ需要任务相关的校准数据(通常从训练集采样100~512条)。 4. **精度验证**:量化后务必用测试集检查任务指标(如准确率、生成质量)。 如果需要更具体的配置(比如自定义量化参数),可以告诉我你的模型类型(如Llama、ChatGLM)和任务场景! 🚀
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值