LLM大模型4位量化实战【GPTQ】

news2025/1/18 8:34:20

权重量化方面的最新进展使我们能够在消费类硬件上运行大量大型语言模型,例如 RTX 3090 GPU 上的 LLaMA-30B 模型。 这要归功于性能下降最小的新型 4 位量化技术,例如 GPTQ、GGML 和 NF4。

在上一篇文章中,我们介绍了简单的 8 位量化技术和出色的 LLM.int8()。 在本文中,我们将探索流行的 GPTQ 算法,以了解其工作原理并使用 AutoGPTQ 库实现它。

你可以在 Google Colab 和 GitHub 上找到代码。

在线工具推荐: Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 可编程3D场景编辑器 

1、最优大脑量化

让我们首先介绍我们要解决的问题。 对于网络中的每一层 ℓ,我们希望找到原始权重 Wₗ 的量化版本 Ŵₗ。 这称为分层压缩问题。 更具体地说,为了最大限度地减少性能下降,我们希望这些新权重的输出 (ŴᵨXᵨ) 尽可能接近原始权重 (WᵨXᵨ)。 换句话说,我们想要找到:

人们提出了不同的方法来解决这个问题,但我们对这里的最优大脑量化器(OBQ:Optimal Brain Quantizer)框架感兴趣。

该方法的灵感来自于一种修剪(pruning)技术,该技术可以仔细地从经过充分训练的密集神经网络(最佳脑外科医生)中去除权重。 它使用近似技术,并为要删除的最佳单个权重 w和最佳更新 δ提供显式公式,以调整剩余非量化权重 F 的集合以弥补删除:

其中 quant(w) 是量化给出的权重舍入,H 是 Hessian 矩阵。

使用 OBQ,我们可以首先量化最简单的权重,然后调整所有剩余的非量化权重以补偿这种精度损失。 然后我们选择下一个要量化的权重,依此类推。

这种方法的一个潜在问题是当存在异常权重时,这可能会导致高量化误差。 通常,当剩下很少的非量化权重可以调整以补偿大误差时,这些离群值将最后被量化。 当一些权重因中间更新而被进一步推到网格之外时,这种效果可能会恶化。 应用一个简单的启发式方法来防止这种情况:异常值一出现就被量化。

这个过程的计算量可能很大,尤其是对于KKM而言。 为了解决这个问题,OBQ 方法使用了一种技巧,可以避免每次简化权重时都重新进行整个计算。 量化权重后,它通过删除与该权重关联的行和列(使用高斯消除)来调整计算中使用的矩阵(Hessian):

该方法还采用矢量化来一次处理多行权重矩阵。 尽管其效率很高,但 OBQ 的计算时间随着权重矩阵大小的增加而显着增加。 这种立方增长使得在具有数十亿参数的大型模型上使用 OBQ 变得困难。

2、GPTQ 算法

由 Frantar 等人提出,GPTQ 算法从 OBQ 方法中汲取灵感,但进行了重大改进,以将其扩展到(非常)大型语言模型。

第 1 步:任意排序洞察

OBQ 方法按一定的顺序选择权重(模型中的参数)进行量化,所确定的权重将增加最少的附加误差。 然而,GPTQ 观察到,对于大型模型,以任何固定顺序量化权重都可以获得同样的效果。 这是因为,即使某些权重可能会单独引入更多误差,但它们会在过程中稍后进行量化,因为此时几乎没有其他权重可能会增加误差。 所以顺序并不像我们想象的那么重要。

基于这一见解,GPTQ 旨在以相同的顺序量化矩阵所有行的所有权重。 这使得过程更快,因为某些计算只需为每列执行一次,而不是为每个权重执行一次。

第 2 步:惰性批量更新

该方案不会很快,因为它需要更新一个巨大的矩阵,并且每个条目的计算量很少。 此类操作无法充分利用 GPU 的计算能力,并且会因内存限制(内存吞吐量瓶颈)而减慢速度。

为了解决这个问题,GPTQ 引入了“惰性批量”更新。 事实证明,给定列的最终舍入决策仅受对该列执行的更新的影响,而不受后续列上执行的更新的影响。 因此,GPTQ 可以一次将该算法应用于一批列(例如 128 列),仅更新这些列和矩阵的相应块。 完全处理一个块后,算法对整个矩阵执行全局更新。

步骤 3:Cholesky 重构

然而,还有一个问题需要解决。 当算法扩展到非常大的模型时,数值不准确可能会成为一个问题。 具体来说,重复应用某个运算可能会累积数值误差。

为了解决这个问题,GPTQ 使用 Cholesky 分解,这是一种用于解决某些数学问题的数值稳定方法。 它涉及使用 Cholesky 方法从矩阵中预先计算一些所需的信息。 这种方法与轻微的“阻尼”(向矩阵的对角元素添加一个小常数)相结合,有助于算法避免数值问题。

完整的算法可以概括为以下几个步骤:

  • GPTQ 算法从 Hessian 逆矩阵(帮助决定如何调整权重的矩阵)的 Cholesky 分解开始
  • 然后它循环运行,一次处理一批列。
  • 对于批次中的每一列,它都会量化权重,计算误差,并相应地更新块中的权重。
  • 处理完该批次后,它会根据块的错误更新所有剩余的权重。

GPTQ 算法在各种语言生成任务上进行了测试。 它与其他量化方法进行了比较,例如将所有权重四舍五入到最接近的量化值(RTN)。 GPTQ 与 BLOOM(176B 参数)和 OPT(175B 参数)模型系列一起使用,并使用单个 NVIDIA A100 GPU 对模型进行量化。

3、使用 AutoGPTQ 量化 LLM

GPTQ 在创建可在 GPU 上高效运行的 4 位精度模型方面非常流行。 你可以在 Hugging Face Hub 上找到许多示例,尤其是来自 TheBloke 的示例。 如果你正在寻找一种对 CPU 更友好的方法,GGML 目前是你的最佳选择。 最后,带有 bitsandbytes 的 Transformer 库允许你在使用 load_in_4bit=true 参数加载模型时对其进行量化,这需要下载完整模型并将其存储在 RAM 中。

让我们使用 AutoGPTQ 库实现 GPTQ 算法并量化 GPT-2 模型。 这需要 GPU,但 Google Colab 上的免费 T4 就可以了。 我们首先加载库并定义我们想要量化的模型(在本例中为 GPT-2)。

!BUILD_CUDA_EXT=0 pip install -q auto-gptq transformers
import random

from auto_gptq import AutoGPTQForCausalLM, BaseQuantizeConfig
from datasets import load_dataset
import torch
from transformers import AutoTokenizer


# Define base model and output directory
model_id = "gpt2"
out_dir = model_id + "-GPTQ"

我们现在要加载模型和分词器。 分词器是使用 Transformers 库中的经典 AutoTokenizer 类加载的。 另一方面,我们需要传递特定的配置(BaseQuantizeConfig)来加载模型。

在此配置中,我们可以指定要量化的位数(此处,bits=4)和组大小(惰性批次的大小)。 请注意,该组大小是可选的:我们还可以对整个权重矩阵使用一组参数。 在实践中,这些组通常以非常低的成本提高量化质量(特别是在 group_size=1024 的情况下)。 此处的 hum_percent 值用于帮助 Cholesky 重新公式化,不应更改。

最后,desc_act(也称为行为顺序)是一个棘手的参数。 它允许你根据减少的激活来处理行,这意味着首先处理最重要或最有影响力的行(由采样的输入和输出确定)。 该方法旨在将大部分量化误差(在量化过程中不可避免地引入)置于不太重要的权重上。 这种方法通过确保以更高的精度处理最重要的权重,提高了量化过程的整体准确性。 然而,当与组大小一起使用时,由于需要频繁重新加载量化参数,desc_act 可能会导致性能下降。 因此,我们不会在这里使用它(但是将来可能会修复它)。

# Load quantize config, model and tokenizer
quantize_config = BaseQuantizeConfig(
    bits=4,
    group_size=128,
    damp_percent=0.01,
    desc_act=False,
)
model = AutoGPTQForCausalLM.from_pretrained(model_id, quantize_config)
tokenizer = AutoTokenizer.from_pretrained(model_id)

量化过程很大程度上依赖于样本来评估和提高量化质量。 它们提供了一种比较原始模型和新量化模型产生的输出的方法。 提供的样本数量越多,进行更准确和有效比较的潜力就越大,从而提高量化质量。

在本文中,我们利用 C4(Colossal Clean Crawled Corpus)数据集来生成样本。 C4 数据集是从 Common Crawl 项目收集的大规模、多语言的网络文本集合。 这个庞大的数据集经过专门清理和准备,用于训练大规模语言模型,使其成为此类任务的重要资源。 维基文本数据集是另一个流行的选择。

在下面的代码块中,我们从 C4 数据集中加载 1024 个样本,对它们进行标记并格式化。

# Load data and tokenize examples
n_samples = 1024
data = load_dataset("allenai/c4", data_files="en/c4-train.00001-of-01024.json.gz", split=f"train[:{n_samples*5}]")
tokenized_data = tokenizer("\n\n".join(data['text']), return_tensors='pt')

# Format tokenized examples
examples_ids = []
for _ in range(n_samples):
    i = random.randint(0, tokenized_data.input_ids.shape[1] - tokenizer.model_max_length - 1)
    j = i + tokenizer.model_max_length
    input_ids = tokenized_data.input_ids[:, i:j]
    attention_mask = torch.ones_like(input_ids)
    examples_ids.append({'input_ids': input_ids, 'attention_mask': attention_mask})

现在数据集已准备就绪,我们可以开始批大小为 1 的量化过程。我们还可以选择使用 OpenAI Triton(CUDA 的替代方案)与 GPU 进行通信。 完成此操作后,我们将分词器和模型保存为安全张量格式。

# Quantize with GPTQ
model.quantize(
    examples_ids,
    batch_size=1,
    use_triton=True,
)

# Save model and tokenizer
model.save_quantized(out_dir, use_safetensors=True)
tokenizer.save_pretrained(out_dir)

像往常一样,然后可以使用 AutoGPTQForCausalLM 和 AutoTokenizer 类从输出目录加载模型和标记生成器。

device = "cuda:0" if torch.cuda.is_available() else "cpu"

# Reload model and tokenizer
model = AutoGPTQForCausalLM.from_quantized(
    out_dir,
    device=device,
    use_triton=True,
    use_safetensors=True,
)
tokenizer = AutoTokenizer.from_pretrained(out_dir)

让我们检查一下模型是否正常工作。 AutoGPTQ 模型(大部分)作为普通transformer模型工作,这使得它与推理管道兼容,如以下示例所示:

from transformers import pipeline

generator = pipeline('text-generation', model=model, tokenizer=tokenizer)
result = generator("I have a dream", do_sample=True, max_length=50)[0]['generated_text']
print(result)
I have a dream," she told CNN last week. "I have this dream of helping my mother find her own. But, to tell that for the first time, now that I'm seeing my mother now, just knowing how wonderful it is that

我们成功地从量化的 GPT-2 模型中获得了令人信服的完成结果。 更深入的评估需要测量量化模型与原始模型的复杂度。 但是,我们将其排除在本文的讨论范围之外。

4、结束语

在本文中,我们介绍了 GPTQ 算法,这是一种在消费级硬件上运行 LLM 的最先进的量化技术。 我们展示了它如何基于具有任意顺序洞察、惰性批量更新和 Cholesky 重构的改进 OBS 技术来解决分层压缩问题。 这种新颖的方法显着降低了内存和计算需求,使LLM可供更广泛的受众使用。

此外,我们在免费的 T4 GPU 上量化了我们自己的 LLM 模型,并运行它来生成文本。 你可以在 Hugging Face Hub 上推送自己的 GPTQ 4 位量化模型版本。 正如简介中提到的,GPTQ 并不是唯一的 4 位量化算法:GGML 和 NF4 都是优秀的替代方案,但范围略有不同。 我鼓励你更多地了解它们并尝试一下!


原文链接:GPTQ 4位量化实战 - BimAnt

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

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

相关文章

2020年06月 Scratch(二级)真题解析#中国电子学会#全国青少年软件编程等级考试

Scratch等级考试(1~4级)全部真题・点这里 一、单选题(共25题,每题2分,共50分) 第1题 如下图所示脚本运行的结果是()? A:画一条直线 B:画一个三角形 C:画一个圆形 D:画一条虚线 答案:D 第2题 运行如下图所示脚本,下面选项中说法错误的是? A:“笔的颜色”…

计算机网络秋招面试题

自己在秋招过程中遇到的计算机网络的面试题 OSI七层网络模型 DNS:应用层协议 根据域名查IP地址 DNS查询⽅式有哪些? 递归解析 局部DNS服务器⾃⼰负责向其他DNS服务器进⾏查询,⼀般是先向该域名的根域服务器查询,再由根域名服…

C++之map容器

C之map容器 map构造和赋值 #include<iostream> #include<string> using namespace std; #include<map>void printMap(map<int,int>&m) {for (map<int,int>::iterator it m.begin();it ! m.end();it){//cout <<"key is: "&l…

macbook ntfs能读不能复制 c盘ntfs拒绝访问怎么解决

如果你是一位Mac用户&#xff0c;你可能会遇到这样的问题&#xff1a;你的Mac能够读取NTFS格式的移动硬盘或U盘&#xff0c;但是不能往里面复制或者修改文件。或者&#xff0c;你的Windows电脑出现了C盘NTFS拒绝访问的错误&#xff0c;导致你无法正常使用系统。这些问题都是由于…

Spring 设计模式-简洁版

Java 中包括以下设计模式&#xff1a; 其中Spring 用到的设计模式 1.简单工厂-BeanFactory 2.工厂方法FactoryBean 3.单例模式Bean实例 4.适配器模式SpringMVC中的HandlerAdatper 5.装饰器模式BeanWrapper 6.代理模式_AOP底层 7.观察者模式-spring的事件监听 8.策略横式exclud…

Unity在Windows选项下没有Auto Streaming

Unity在Windows选项下没有Auto Streaming Unity Auto Streaming插件按网上说的不太好使最终解决方案 Unity Auto Streaming插件 我用的版本是个人版免费版&#xff0c;版本号是&#xff1a;2021.2.5f1c1&#xff0c;我的里边Windows下看不到Auto Streaming选项,就像下边这张图…

Clickhouse初认识

技术主题-clickhouse 一什么是clickHouse 1&#xff09;本质上就是一款数据库管理系统&#xff0c;能提供海量数据的存储和检索 2&#xff09;基于列存储&#xff0c;数据是按照列进行存储的&#xff08;数据格式一样&#xff0c;方便进行压缩&#xff09; 3&#xff09;具备…

数据结构-插入排序+希尔排序+选择排序

目录 1.插入排序 插入排序的时间复杂度&#xff1a; 2.希尔排序 希尔排序的时间复杂度&#xff1a; 3.选择排序 选择排序的时间复杂度&#xff1a; 所谓排序&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某些关键字的大小&#xff0c;递增或递减的排列起来的…

Gem5模拟器学习之旅——翻译自官网

文章目录 安装并使用gem5 模拟器支持的操作系统和环境依赖在 Ubuntu 22.04 启动(gem5 > v21.1)Docker获取代码用 SCons 构建用法首次构建 gem5gem5 二进制类型调试opt快速 常见错误错误的 gcc 版本Python 位于非默认位置未安装 M4 宏处理器Protobuf 3.12.3 问题 安装并使用g…

Pandas中loc和iloc函数(提取某几列或者行的数据)

loc函数&#xff1a;通过行索引&#xff08;列名、行名&#xff09; 中的具体值来取行数据&#xff08;如取"Index"为"A"的行&#xff09; iloc函数&#xff1a;通过行号&#xff08;数字&#xff09;来取行数据&#xff08;如取第二行的数据&#xff09;…

JAVA刷题之字符串的一些个人思路

感谢您的阅读&#xff01; ꒰˃͈꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱ ʕ̯•͡˔•̯᷅ʔ大家好&#xff0c;我是xiaoxie.希望你看完之后,有不足之处请多多谅解&#xff0c;让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客 本文由xiaoxieʕ̯…

【Spring总结】基于配置的方式来写Spring

本篇文章是对这两天所学的内容做一个总结&#xff0c;涵盖我这两天写的所有笔记&#xff1a; 【Spring】 Spring中的IoC&#xff08;控制反转&#xff09;【Spring】Spring中的DI&#xff08;依赖注入&#xff09;Dependence Import【Spring】bean的基础配置【Spring】bean的实…

计算机msvcr120.dll丢失的解决方法,分享多种亲测可靠的方法

在使用计算机的过程中&#xff0c;我们有时可能会遇到一些技术问题&#xff0c;其中之一就是提示丢失msvcr120.dll文件。当计算机提示丢失msvcr120.dll文件时&#xff0c;可能是由于某些程序无法找到这个文件&#xff0c;从而导致程序无法正常运行。那么我们需要如何解决修复好…

一文读懂:testcafe框架和页面元素交互

一、互动要求 使用 TestCafe 与元素进行交互操作&#xff0c;元素需满足以下条件&#xff1a;☟ 元素在 body 页面窗口或 iframe 窗口的元素内。如果某个元素在视口之外&#xff0c;则 TestCafe 通过滚动可以滚动到元素可见。 元素是可见的&#xff0c;具有以下属性&#…

Leetcode—剑指OfferII LCR 022.环形链表II【中等】

2023每日刷题&#xff08;三十三&#xff09; Leetcode—LCR 022.环形链表II 算法思想 参考k神的博客 实现代码 /*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/ struct ListNode *detectCycle(struct List…

2.3 调用智谱 API

调用智谱 API 1 申请调用权限2 调用智谱 AI API3 使用 LangChain 调用智谱 AI参考&#xff1a; 智谱 AI 是由清华大学计算机系技术成果转化而来的公司&#xff0c;致力于打造新一代认知智能通用模型。公司合作研发了双语千亿级超大规模预训练模型 GLM-130B&#xff0c;并构建了…

Python------列表 集合 字典 推导式(本文以 集合为主)

推导式&#xff1a; 推导式comprehensions&#xff08;又称解析式&#xff09;&#xff0c;是Python的一种独有特性。推导式是可以从一个数据序列 构建 另一个 新的数据序列&#xff08;一个有规律的列表或控制一个有规律列表&#xff09;的结构体。 共有三种推导&#xff…

HUAWEI华为笔记本MateBook X 2021款i5集显(EULD-WFH9,WXX9)原装出厂Windows11系统工厂模式包

下载链接&#xff1a;https://pan.baidu.com/s/1gQ_O203SSm83Nc-zDk1iNA?pwd4exz 提取码&#xff1a;4exz 系统带F10一键智能还原功能隐藏恢复分区、所有驱动、Office办公软件、华为电脑管家等预装程序 所需要工具&#xff1a;32G或以上的U盘 文件格式&#xff1a;zip …

TensorRt推理加速框架Python API服务器部署教程以及运行Helloworld程序

一、确认cuda工具包和n卡相关驱动是否安装 在终端中输入以下命令&#xff1a; nvcc -V如果出现以下提示&#xff0c;则已经成功安装 在终端中输入以下命令&#xff1a; nvidia-smi如果出现即为成功&#xff0c;我在这里就不去介绍怎么下载cuda和驱动怎么下载了&#xff0c;…

【Linux系统化学习】进程的父子关系 | fork 进程

个人主页点击直达&#xff1a;小白不是程序媛 Linux专栏&#xff1a;Linux系统化学习 目录 前言&#xff1a; 父子进程 父子进程的引入 查看父子进程 查询进程的动态目录 更改进程的工作目录 fork创建进程 fork的引入 fork的使用 fork的原理 fork如何实现的&#…