实战Transformers模型量化Facebook OPT

基于上篇文章的理论知识,本文主要讲述了实战Transformers模型量化:介绍Facebook OPT模型的量化过程和相关技术。

Transformers 模型量化技术:GPTQ

Frantar等人发表了论文 GPTQ:Accurate Post-Training Quantization for Generative Pre-trained Transformers。作者详细介绍了一种训练后量化算法,适用于所有通用的预训练 Transformer模型,同时只有微小的性能下降。GPTQ算法需要通过对量化模型进行推理来校准模型的量化权重。其呈现的效果可以表达成Hugging Face + AutoGPTQ。

使用 GPTQ 量化模型

为了使用 auto-gptq 库量化一个模型,需要向量化器传递一个数据集。通常有两种方式构造数据集:

  • 量化器支持的默认数据集(包括[‘wikitext2’,‘c4’,‘c4-new’,‘ptb’,‘ptb-new’])
  • 一个字符串列表(这些字符串将被用作数据集)
    先安装好项目所依赖的包,如requirements。
torch>=2.1.2==2.3.0.dev20240116+cu121
transformers==4.37.2
ffmpeg==1.4
ffmpeg-python==0.2.0
timm==0.9.12
datasets==2.16.1
evaluate==0.4.1
scikit-learn==1.3.2
pandas==2.1.1
peft==0.7.1
accelerate==0.26.1
autoawq==0.2.2
optimum==1.17.0
auto-gptq==0.6.0
bitsandbytes>0.39.0==0.41.3.post2
jiwer==3.0.3
soundfile>=0.12.1==0.12.1
librosa==0.10.1
gradio==4.13.0
trl

然后进行加载requirements.txt内所有依赖包。

pip install -r requirements.txt

运行出来的界面如下图所示:
安装依赖包运行界面图

使用 GPTQ 算法支持的默认数据集来量化

对此,现使用"wikitext2"数据集将模型量化为4位精度,且支持的精度有[2, 4, 6, 8]。

from transformers import AutoModelForCausalLM, AutoTokenizer, GPTQConfig
import torch

model_id = "facebook/opt-2.7b"

quantization_config = GPTQConfig(
     bits=4, # 量化精度
     group_size=128,
     dataset="c4",
     desc_act=False,
)

运行界面图

tokenizer =AutoTokenizer.from_pretrained(model_id)
quant_model = AutoModelForCausalLM.from_pretrained(model_id, quantization_config=quantization_config, device_map='auto') 

运行参数界面
关于device_map参数,大家可以浏览huggingface的官方原文解释。
地址:https://huggingface.co/docs/transformers/v4.36.1/en/quantization
huggingface界面
上图为huggingface官方解释界面。

实测GPU显存占用:量化模型(峰值超过7GB)

运行图
由于电脑配置较低导致没有运行出来,笔者暂截取Github上的示例图。

检查量化模型正确性

通过检查线性层的属性来确保模型已正确量化,它们应该包含qweight和qzeros属性,这些属性应该是torch.int32数据类型。更简单地说,GPTQ简单的方法能够检查量化模型是否正确,是否有错误等,但该方法无法衡量模型的参数值被量化得非常好。即能够运行出来的模型到底有没有达到比较好的指标是无法被检查出来的。

quant_model.model.decoder.layers[0].self_attn.q_proj.__dict__

运行界面图
运行的界面图

使用GPU加载模型并生成文本

tokenizer = AutoTokenizer.from_pretrained(model_name_or_path)

text = "Merry Christmas! I'm glad to"
inputs = tokenizer(text, return_tensors="pt").to(0)

out = quant_model.generate(**inputs, max_new_tokens=64)
print(tokenizer.decode(out[0], skip_special_tokens=True))

运行界面图

使用自定义数据集量化模型

下面演示通过传递自定义数据集来量化一个模型。通过字符串列表来自定义一个数据集,建议样本数不少于128(样本数太少会影响模型性能)

from transformers import AutoModelForCausalLM, GPTQConfig, AutoTokenizer

model_name_or_path = "facebook/opt-2.7b"
custom_dataset = ["auto-gptq is an easy-to-use model quantization library with user-friendly apis, based on GPTQ algorithm."]

custom_quantization_config = GPTQConfig(
    bits=4,
    group_size=128,
    desc_act=False,
    dataset=custom_dataset
)

custom_quant_model = AutoModelForCausalLM.from_pretrained(model_name_or_path,
                                                          quantization_config=custom_quantization_config,
                                                          torch_dtype=torch.float16,
                                                          device_map="auto")

运行界面图

相比使用默认数据集,未经精心准备的自定义数据集会明显降低模型性能。

text = "Merry Christmas! I'm glad to"
inputs = tokenizer(text, return_tensors="pt").to(0)

out = custom_quant_model.generate(**inputs, max_new_tokens=64)
print(tokenizer.decode(out[0], skip_special_tokens=True))

示例图

Transformers 模型量化技术:AWQ

在AWQ:Activation-aware Weight Quantization for LLM Compression and Acceleration论文中,作者介绍了一种激活感知权重量化算法,可以用于压缩任何基于 Transformer 的语言模型,同时只有微小的性能下降。AWQ可以看成transformers + quantization综合表达的效果。

量化前模型测试文本生成任务

from transformers import pipeline

model_path = "facebook/opt-125m"

# 使用 GPU 加载原始的 OPT-125m 模型
generator = pipeline('text-generation',
                     model=model_path,
                     device=0,
                     do_sample=True,
                     num_return_sequences=3)

运行界面图

实测GPU显存占用:加载OPT-125m模型后

界面图

示例对比

generator("The woman worked as a")

运行结果
示例1 运行结果

generator("The man worked as a")

运行结果
示例2 运行结果

使用 AutoAWQ 量化模型

下面我们以 facebook opt-125m 模型为例,使用 AutoAWQ 库实现的 AWQ 算法实现模型量化。

from awq import AutoAWQForCausalLM
from transformers import AutoTokenizer


quant_path = "models/opt-125m-awq"
quant_config = {"zero_point": True, "q_group_size": 128, "w_bit": 4, "version": "GEMM"}

# 加载模型
model = AutoAWQForCausalLM.from_pretrained(model_path, device_map="cuda")
tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)

图

# 量化模型
model.quantize(tokenizer, quant_config=quant_config)

实测GPU显存使用:量化模型时峰值达到将近 4GB。

quant_config

界面

Transformers兼容性配置

from transformers import AwqConfig, AutoConfig

# 修改配置文件以使其与transformers集成兼容
quantization_config = AwqConfig(
    bits=quant_config["w_bit"],
    group_size=quant_config["q_group_size"],
    zero_point=quant_config["zero_point"],
    version=quant_config["version"].lower(),
).to_dict()

# 预训练的transformers模型存储在model属性中,需要传递一个字典
model.model.config.quantization_config = quantization_config
# 保存模型权重

model.save_quantized(quant_path)
tokenizer.save_pretrained(quant_path)  # 保存分词器

界面图

Transformers 量化技术 BitsAndBytes

BitsAndBytes
bitsandbytes是将模型量化为8位和4位的最简单选择。

  • 8位量化将fp16中的异常值与int8中的非异常值相乘,将非异常值转换回fp16,然后将它们相加以返回fp16中的权重。这减少了异常值对模型性能产生的降级效果。
  • 4位量化进一步压缩了模型,并且通常与QLoRA一起用于微调量化LLM(低精度语言模型)。

异常值: 是指大于某个阈值的隐藏状态值,这些值是以fp16进行计算的。虽然这些值通常服从正态分布([-3.5, 3.5]),但对于大型模型来说,该分布可能会有很大差异([-60, 6]或[6, 60])。8位量化适用于约为5左右的数值,但超过此范围后将导致显著性能损失。一个好的默认阈值是6,但对于不稳定的模型(小型模型或微调)可能需要更低的阈值。

在 Transformers 中使用参数量化

使用 Transformers 库的 model.from_pretrained()方法中的load_in_8bit或load_in_4bit参数,便可以对模型进行量化。只要模型支持使用Accelerate加载并包含torch.nn.Linear层,这几乎适用于任何模态的任何模型。

from transformers import AutoModelForCausalLM
model_id = "facebook/opt-2.7b"
model_4bit = AutoModelForCausalLM.from_pretrained(model_id,
                                                  device_map="auto",
                                                  load_in_4bit=True)
model_4bit

示例图

# 获取当前模型占用的 GPU显存(差值为预留给 PyTorch 的显存)
memory_footprint_bytes = model_4bit.get_memory_footprint()
memory_footprint_mib = memory_footprint_bytes / (1024 ** 2)  # 转换为 MiB

print(f"{memory_footprint_mib:.2f}MiB")

运行结果为:1457.52MiB,
而在显存中占用的初始结果为1774MiB。

from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained(model_id
                                         )
text = "Merry Christmas! I'm glad to"
inputs = tokenizer(text, return_tensors="pt").to(0)

out = model_4bit.generate(**inputs, max_new_tokens=64)
print(tokenizer.decode(out[0], skip_special_tokens=True))

运行界面图

使用 NF4 精度加载模型


from transformers import BitsAndBytesConfig

nf4_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",
)

model_nf4 = AutoModelForCausalLM.from_pretrained(model_id, quantization_config=nf4_config)
# 获取当前模型占用的 GPU显存(差值为预留给 PyTorch 的显存)
memory_footprint_bytes = model_nf4.get_memory_footprint()
memory_footprint_mib = memory_footprint_bytes / (1024 ** 2)  # 转换为 MiB

print(f"{memory_footprint_mib:.2f}MiB")

运行结果为:1457.52MiB
而在显存中占用的初始结果为3414MiB。

使用双量化加载模型

double_quant_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_use_double_quant=True,
)

model_double_quant = AutoModelForCausalLM.from_pretrained(model_id, quantization_config=double_quant_config)
# 获取当前模型占用的 GPU显存(差值为预留给 PyTorch 的显存)
memory_footprint_bytes = model_double_quant.get_memory_footprint()
memory_footprint_mib = memory_footprint_bytes / (1024 ** 2)  # 转换为 MiB

print(f"{memory_footprint_mib:.2f}MiB")

运行结果为:1457.52MiB,
而在显存中占用的初始结果为:4910MiB

使用 QLoRA 所有量化技术加载模型

import torch

qlora_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_use_double_quant=True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_compute_dtype=torch.bfloat16
)

model_qlora = AutoModelForCausalLM.from_pretrained(model_id, quantization_config=qlora_config)
# 获取当前模型占用的 GPU显存(差值为预留给 PyTorch 的显存)
memory_footprint_bytes = model_qlora.get_memory_footprint()
memory_footprint_mib = memory_footprint_bytes / (1024 ** 2)  # 转换为 MiB

print(f"{memory_footprint_mib:.2f}MiB")

运行结果为:1457.52MiB。

在Hugging Face Transformers库中,使用AWD-QAModel(即Abridged Wasserstein Distance Quantization Model)通常涉及到将预训练的大型语言模型进行量化,以便于部署到资源有限的设备上,如手机或嵌入式系统。AWD量化是通过Quantization-Aware Training (QAT) 过程实现的,它允许模型在训练过程中就考虑到量化的影响。 以下是使用Hugging Face Transformers进行AWD量化模型的基本步骤: 1. **安装依赖**: 首先,你需要安装`transformers`库及其相关的量化工具包,例如`transformers quantization`。可以使用pip安装: ``` pip install transformers[quantization] ``` 2. **加载模型**: 导入需要的模块并加载预训练的模型,比如BERT、GPT-2等: ```python from transformers import AutoTokenizer, AutoModelForSequenceClassification, is_apex_available, AWDQConfig model_name = "bert-base-uncased" tokenizer = AutoTokenizer.from_pretrained(model_name) model = AutoModelForSequenceClassification.from_pretrained(model_name) ``` 3. **量化配置**: 创建一个AWD量化配置对象: ```python config = AWDQConfig(model=model) ``` 4. **准备数据**: 将数据转换成模型接受的格式,并分割成小批次,这对于量化过程很重要。 5. **量化训练**: 使用`Trainer` API进行量化训练,这会自动在训练过程中应用量化技巧: ```python trainer = Trainer( model=model, args=..., data_collator=..., train_dataset=..., eval_dataset=..., # 可选 tokenizer=tokenizer, config=config, compute_metrics=..., ) trainer.train() ``` 6. **保存量化模型**: 训练完成后,你可以保存量化后的模型: ```python trainer.save_model("path/to/save/awd_quantized_model") ``` 7. **部署**: 现在可以将这个量化模型用于推理任务,相比未量化模型,它的内存占用更小,速度更快。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Whitney_mao

您的认可和鼓励是持续分享的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值