实战Transformers模型量化Facebook OPT

news2024/9/23 21:21:39

基于上篇文章的理论知识,本文主要讲述了实战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。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1971819.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ARCH和GARCH模型

个人学习笔记,课程为数学建模清风付费课程 目录 一、为什么引入ARCH模型? 二、 ARCH模型 2.1概念 2.2适用情形 2.3条件异方差 2.4ARCH(1)模型和ARCH(q)模型 三、GARCH(p,q)模型 3.1ARCH(q)效应和GARCH(p,q)效应 3.2GARCH效应检验 3.2.1检验GA…

Variational Mode Decomposition (VMD) 详解与应用

Variational Mode Decomposition (VMD) 的详细介绍 VMD 是一种信号分解方法,旨在将复杂信号分解为若干个具有不同频率成分的模态。它的基本思想是通过变分优化的方式,得到一组模态信号,这些模态信号在频域上彼此分离。 1. 问题定义 假设我…

【C++】类和对象两个必看题

这两个题只有一句代码的差别。 看题目之前我先说一下怎么看汇编指令。 第一题&#xff1a;下面程序运行结果是&#xff1f; A.编译报错 B.运行崩溃 C.正常运行 #include <iostream> using namespace std; class A { public:void Print(){cout << "A::Pri…

正点原子imx6ull-mini-Linux驱动之异步通知实验(13)

在前面使用阻塞或者非阻塞的方式来读取驱动中按键值都是应用程序主动读取的&#xff0c;对于非 阻塞方式来说还需要应用程序通过 poll 函数不断的轮询。最好的方式就是驱动程序能主动向应 用程序发出通知&#xff0c;报告自己可以访问&#xff0c;然后应用程序在从驱动程序中读…

docker部署kkfileview文件在线预览服务

kkfileview文件在线预览服务部署使用 免费开源&#xff0c;功能强大&#xff0c;几乎支持日常见到的所有文件类型在线预览 目前支持的文件类型如下 支持 doc, docx, xls, xlsx, xlsm, ppt, pptx, csv, tsv, dotm, xlt, xltm, dot, dotx,xlam, xla 等 Office 办公文档支持 wp…

day12 多线程

目录 1.概念相关 1.1什么是线程 1.2什么是多线程 2.创建线程 2.1方式一&#xff1a;继承Thread类 2.1.1实现步骤 2.1.2优缺点 2.1.3注意事项 2.2方式二&#xff1a;实现Runnable接口 2.2.1实现步骤 2.2.2优缺点 2.2.3匿名内部类写法 2.3方式三&#xff1a;实现cal…

鸿蒙系统开发【网络-上传和下载(ArkTS)】基本功能

网络-上传和下载&#xff08;ArkTS&#xff09; 介绍 本示例使用ohos.request接口创建上传和下载任务&#xff0c;实现上传、下载功能&#xff0c;hfs作为服务器&#xff0c;实现了文件的上传和下载和任务的查询功能。 效果预览 使用说明 1.本示例功能需要先配置服务器环境…

BootStrap前端面试常见问题

在前端面试中&#xff0c;关于Bootstrap的问题通常围绕其基本概念、使用方式、特性以及实际应用等方面展开。以下是一些常见的问题及其详细解答&#xff1a; 1. Bootstrap是哪家公司研发的&#xff1f; 回答&#xff1a;Bootstrap是由Twitter的Mark Otto和Jacob Thornton合作…

go语言day21 goland使用gin框架、gorm框架操作mysql数据库redis数据库 使用宝塔创建redis数据库

GORM 指南 | GORM - The fantastic ORM library for Golang, aims to be developer friendly. gorm package - github.com/jinzhu/gorm - Go Packages go语言day20实现投票功能项目包-CSDN博客 gin框架标准项目结构&#xff1a; models&#xff1a;存放对应实体类和gorm包增删…

Godot的节点与场景

要深入的理解节点与场景&#xff0c;我们需要跳出这两个概念来看他。说的再直白一些godot本质就是一个场景编辑器&#xff01; 场景的概念应该在我们平时看电影看电视时会经常提到&#xff0c;比如某一个打斗的场景&#xff0c;这个场景可能会被设在某一个街道&#xff0c;那么…

RIP综合练习

要求&#xff1a; 1.合理使用IP地址划分网络&#xff0c;各自创建循环接口 2.R1创建环回172.16.1.1/24 172.16.2.1/24 172.16.3.1/24 3.要求R3使用R2访问R1环回 4.减少路由条目数量&#xff0c;R1,R2之间增加路由传递安全性 5.R5创建一个环回模拟运营商&#xff0c;不能…

Flink的DateStream API中的ProcessWindowFunction和AllWindowFunction两种用于窗口处理的函数接口的区别

目录 ProcessWindowFunction AllWindowFunction 具体区别 ProcessWindowFunction 示例 AllWindowFunction 示例 获取时间不同&#xff0c;一个数据产生的时间一个是数据处理的时间 ProcessWindowFunction AllWindowFunction 具体示例 ProcessWindowFunction 示例 Al…

CRMEB 电商系统安装及分析

CRMEB系统采用前后端分离技术&#xff0c;基于TP6Vue2.5Uniapp框架开发&#xff1b;支持微信小程序、公众号、H5、APP、PC端适配&#xff0c;数据同步&#xff01;是一套单商户新零售社交电商系统。 目录 安装 安装环境 安装过程 开始安装 安装检测 数据库配置 高级设置…

基于Cloudflare搭建私有Docker镜像源

周四原本不是发文的日子&#xff0c;主要因为两个原因&#xff1a; 第一个原因是总有人留言说 Docker 用不了&#xff0c;第二个原因是看了下上个月的阅读量&#xff0c;和之前比实在有点惨淡&#xff0c;除了文章总被人搬运外&#xff0c;我估计可能跟第一个原因多少还是有点…

计算机基础(Windows 10+Office 2016)教程 —— 第4章 计算机网络与Internet(上)

第4章 计算机网络与Internet 4.1 计算机网络概述4.1.1 计算机网络的定义4.1.2 计算机网络的发展4.1.3 计算机网络的功能4.1.4 计算机网络体系结构和TCP/IP 参考模型 4.2 计算机网络的组成和分类4.2.1 计算机网络的组成4.2.2 计算机网络的分类 4.3 网络传输介质和通信设备4.3.1 …

【Unity】3D功能开发入门系列(二)

Unity3D功能开发入门系列&#xff08;二&#xff09; 一、资源&#xff08;一&#xff09;资源文件&#xff08;二&#xff09;场景文件&#xff08;三&#xff09;资源包&#xff08;四&#xff09;Unity 资源商店&#xff08;五&#xff09;项目资源的导入 二、父子关系&…

【C语言篇】数据在内存中的存储(超详细)

文章目录 数据在内存中的存储二进制和进制转换基本概念进制转换十进制转二进制二进制转八进制和十六进制 整数在内存中的存储反码原码补码大小端字节序和字节序判断什么是大小端&#xff1f;为什么有大小端 浮点数在内存中的存储题目提出浮点数存的过程浮点数取的过程 题目解析…

Java语言程序设计——篇十一(2)

&#x1f33f;&#x1f33f;&#x1f33f;跟随博主脚步&#xff0c;从这里开始→博主主页&#x1f33f;&#x1f33f;&#x1f33f; 欢迎大家&#xff1a;这里是我的学习笔记、总结知识的地方&#xff0c;喜欢的话请三连&#xff0c;有问题可以私信&#x1f333;&#x1f333;&…

算法导论 总结索引 | 第五部分 第二十一章:用于不相交集合的数据结构

一些应用涉及 将n个不同的元素分成一组不相交的集合。寻找包含给定元素的唯一集合 和 合并两个集合 1、不相交集合的操作 1、一个不相交集合 数据结构 维持了 一个不相交动态集的集合 S {S_1, S_2,…, S_n}。用一个代表 来标识每个集合&#xff0c;它是这个集合的某个成员。…

IoTDB 入门教程 企业篇④——安全控制 | 白名单、审计日志、登录日志和操作日志

文章目录 一、前文二、白名单2.1 配置文件iotdb-common.properties2.2 配置文件white.list2.3 注意事项 三、审计日志3.1 Cli操作日志3.2 RESTful操作日志3.3 MQTT操作日志3.4 Java操作日志3.5 C#操作日志3.6 Python操作日志 四、参考 一、前文 IoTDB入门教程——导读 IoTDB企业…