微信扫码
与创始人交个朋友
我要投稿
hi~
上一篇,跟着雄哥做了int8量化!
今天,我们继续用GPTQ来做4位量化!后面,跟着雄哥再用GGML、EXL2技术量化大模型!
也得因为量化技术发展,大模型的部署成本,有望降低!
雄哥在公园,整理了几个热门量化工具的代码,全免费资源,在colab/阿里云上,全部跑通,整个内容是这样的!
day3:手把手量化大模型!有什么方法?什么是量化?【点击学习】
day4:手把手GPTQ量化大模型!有什么区别?优势?【本篇】
day5:手把手GGML量化大模型!与llama.cpp异曲同工?
day6:手把手使用ExLlamaV2量化!精炼后的GPTQ?
如果你跟着雄哥之前的教程,抢到了阿里云的免费算力,可以用医疗组伙伴共享的方法,改为国内源下载并量化模型!非常棒!
import os
# 设置环境变量HF_ENDPOINT
os.environ['HF_ENDPOINT'] = 'https://hf-mirror.com'
人的专注力只有10分钟,那!话不多说!
① 量化技术的困难背景!
② 什么是GPTQ量化?背后算法是?
③ 动起手来,跑一个实例!边跑边聊细节!
第一部分:量化技术的困难背景!
说到量化,不得不说一直以来“修剪”的技术,稍后你可以去看一下!
https://arxiv.org/abs/2208.11580
埃利亚斯·弗兰塔尔、西达克·帕尔·辛格、丹·阿里斯塔
我们考虑了深度神经网络 (DNN) 在具有挑战性的单次/训练后环境中的模型压缩问题,在这种环境中,我们得到了一个精确的训练模型,并且必须仅基于少量校准输入数据进行压缩,而无需任何重新训练。鉴于新兴的软件和硬件支持通过修剪和/或加速量化来执行压缩的模型,这个问题已经变得流行,并且已经为这两种压缩方法独立提出了性能良好的解决方案。在本文中,我们引入了一种新的压缩框架,该框架在统一的设置中涵盖了权重修剪和量化,既省时又省空间,并大大提高了现有训练后方法的实际性能。在技术层面上,我们的方法基于经典最佳脑外科医生 (OBS) 框架的精确和有效实现 [LeCun, Denker, and Solla, 1990] 扩展到也涵盖了现代 DNN 规模的权重量化。从实践的角度来看,我们的实验结果表明,它可以显著提高现有训练后方法的压缩精度权衡,并且能够在训练后环境中实现修剪和量化的准确复合应用。
方法灵感来自修剪技术,从经过充分训练的密集神经网络(Optimal Brain Surgeon)中去除权重!
使用近似技术,为要删除的最佳单个权重w_q和最佳更新提供明确的公式,以调整剩余的非量化权重 F 集以弥补删除:
定义一个与该优化过程相关的变量:
使用 OBQ,我们可以先简单量化权重,有损失!
然后,调整所有剩余的非量化权重,来补偿精度损失!
然后,我们选择下一个权重进行量化,依此类推!
发现没?
这种方法的一个潜在问题是:当存在异常值权重时,有超高量化误差!
通常,这些异常值将最后量化,此时几乎没有剩余的非量化权重可以调整以补偿大误差。
当一些权重被中间更新推到网格之外时,这种影响可能会恶化。应用了一个简单的启发式方法来防止这种情况:异常值一出现就被量化。
这个过程的计算量可能很大!
为了解决这个问题,OBQ 方法使用了一个技巧,可以避免每次简化权重时重做整个计算。量化权重后,它通过删除与该权重关联的行和列(使用高斯消元法)来调整计算中使用的矩阵(Hessian):
公众号的文稿格式很差,我让最新千问2.5来生成!
该方法,采用矢量化来一次处理权重矩阵的多行!效率很高,但权重矩阵增加后,OBQ 的计算时间也直接起飞!
OBQ,不适合现在千亿参数的超大型模型上!
第二部分:什么是GPTQ?底层算法?
GPTQ 算法由 Frantar 等人 (2023) 引入,灵感来自 OBQ 方法,重写!把他扩展到超大参数语言模型上!论文在这,之后可以自己去看!
https://arxiv.org/abs/2210.17323
他是这样做的!
步骤 1:任意顺序的洞察
OBQ 方法按照特定顺序选择权重(模型中的参数)进行量化,顺序取决于哪些权重会增加最少的额外误差!
然而,GPTQ 发现对于大型模型而言,以任何固定的顺序量化权重都能表现出色!
因为尽管某些权重单独来看可能会引入更多误差,但在量化过程后期,当剩余可增加误差的权重不多时,这些权重才会被量化。因此,顺序的重要性并不像我们原先想象的那么大。
基于这一洞察,GPTQ 旨在对矩阵的所有行按照相同的顺序量化所有权重。这样做能够加快处理速度,因为某些计算只需为每一列执行一次,而不是为每个权重单独执行一次!
步骤 2:惰性批次更新
此方案不会很快,因为它要求用极少的计算来更新一个巨大的矩阵中的每个条目。这类操作无法充分利用GPU的全部计算能力,并且会受到内存限制(内存吞吐量瓶颈)的影响而减速。
为解决问题,GPTQ 引入了“惰性批次”更新的概念!给定列的最终舍入决策仅受该列上执行的更新影响,而不受后续列的影响。
因此,GPTQ 可以一次对一批列(比如128列)应用算法,仅更新这些列以及矩阵中的相应块。在处理完一个块后,算法再对整个矩阵执行全局更新。
这种方法提高效率,减少了内存访问频率,通过批量处理列来更有效地利用GPU的并行计算能力,减少全局更新次数来减轻内存带宽瓶颈!
步骤 3:Cholesky 重述
当算法扩展到超大模型时,数值不精确性,成为问题!具体来说,重复应用某个特定操作可能会累积数值误差!
为了解决这个问题,GPTQ 使用 Cholesky 分解,这是一种数值稳定的方法,用于解决某些数学问题。使用 Cholesky 方法预先计算矩阵中所需的部分信息。结合对矩阵对角元素轻微的“阻尼”(添加一个小常数),帮助算法避免数值问题。
完整的算法是这样的:
1. **Cholesky 分解开始**:GPTQ 算法首先对 Hessian 逆矩阵(一个帮助决定如何调整权重的矩阵)进行 Cholesky 分解。
2. **循环处理**:然后,它以循环的方式运行,每次处理一批列。
3. **按批次处理列**:对于批次中的每一列,它量化权重,计算误差,并相应地更新块中的权重。
4. **基于块错误更新**:处理完批次后,根据该块的误差更新所有剩余的权重。
**GPTQ 算法测试**:
GPTQ 算法在多种语言生成任务上进行了测试。与其他量化方法比较,如将所有权重四舍五入到最近的量化值(RTN)。GPTQ 与 BLOOM(1760亿参数)和 OPT(1750亿参数)模型系列一起使用,并且模型使用单个 NVIDIA A100 GPU 进行量化。GPTQ 在保持模型性能的同时显著降低内存花销的!
第三部分:跑起来!边跑边聊细节!
所有的代码,雄哥都上传到会员盘了!仅意友圈成员专享!目前420+付费成员!
获取知识星球优惠,或遇到问题需解答!或加群?末尾找技术助手小胖!
如果你还未加入,在这里备注申请!
一样!你打开雄哥上传的代码,无论在本地、阿里云、colab均可!
推荐colab,免费,无需理会环境!
GPTQ技术很火!可以在Hugging Face找到许多示例!
如果你用纯CPU,GGML是最适合的,下篇雄哥就更新!
上传好之后,开始跑!
定义模型!
只要你有足够资源,你可以改任何模型,你只需要把下方的model_id后的模型名称改为hf上的模型路径!
import random
from auto_gptq import AutoGPTQForCausalLM, BaseQuantizeConfig
from datasets import load_dataset
import torch
from transformers import AutoTokenizer
model_id = "gpt2"
out_dir = model_id + "-GPTQ"
把上方的路径换进去!例如你要量化llama3!
model_id = "meta-llama/Meta-Llama-3-8B"
他会自动去hf下载模型!
加载模型和分词器!
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)
分词器是使用库中的经典类加载的。另一方面,我们需要传递一个特定的配置来加载模型
此配置,我们指定要量化的位数和组大小(惰性批处理的大小)!
注意,此组大小是可选的:我们还可以对整个权重矩阵使用一组参数。在实践中,这些组通常以非常低的成本(尤其是 )提高量化的质量。该值在这里帮助 Cholesky 重新制定,不要更改!
加载数据!
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')
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. **数据加载**:首先,它设置了`n_samples = 1024`,指定了要处理的数据样本数量。然后使用`load_dataset`函数从AllenAI的C4数据集中加载数据。具体加载的是英文数据部分("en/c4-train.00001-of-01024.json.gz"),并限制加载的数据范围为前`n_samples * 5`个样本作为训练数据。
2. **文本预处理**:加载的数据通过一个名为`tokenizer`的函数进行预处理,该函数将文本数据转换成模型可以理解的token(词或子词)形式。这里,所有文本样本通过`\n\n`连接起来作为一个长字符串传递给tokenizer,并要求返回的张量格式为'pt'(PyTorch张量)。
3. **生成示例**:之后,代码进入一个循环,目的是从tokenized的数据中创建用于模型输入的示例。对于每个样本(总共`n_samples`个):
- 随机选择一个起始点`i`,确保在选取的序列长度(`tokenizer.model_max_length`)不会超出tokenized数据的最大边界。
- 计算结束点`j`,等于`i`加上模型允许的最大长度。
- 从`tokenized_data.input_ids`中提取从`i`到`j`的序列,作为模型的`input_ids`。
- 创建一个与`input_ids`形状相同的全1张量`attention_mask`,用于指示模型哪些token应当被关注(在Transformer模型中用于处理序列中的padding部分)。
- 将`input_ids`和`attention_mask`作为字典添加到`examples_ids`列表中,形成最终的训练示例。
开始量化!
%%time
model.quantize(
examples_ids,
batch_size=1,
use_triton=True,
)
model.save_quantized(out_dir, use_safetensors=True)
tokenizer.save_pretrained(out_dir)
搞好了,你可以下载到本地!
在本文中,雄哥介绍了 GPTQ 算法,这是一种最先进的量化技术,用于在消费级硬件上运行 LLM。
我们展示它如何解决逐层压缩问题,该技术基于改进的 OBS 技术,具有任意顺序洞察、延迟批处理更新和 Cholesky 重新表述。这种新颖的方法大大降低了内存和计算要求,使 LLM 可供更广泛的受众使用。
此外,我们在免费的 T4 GPU 上量化了我们自己的 LLM 模型,并运行它来生成文本。您可以在 Hugging Face Hub 上推送您自己的 GPTQ 4 位量化模型版本。正如介绍中提到的,GPTQ 并不是唯一的 4 位量化算法:GGML 和 NF4 都不错!
下一篇雄哥会详细聊!
每天时间!真的!不够用!能做的事,对于AI来说,太有限!
技术发展飞快,如何从小!短频快的节奏中!快速上线!
快速收钱!
这是雄哥搞AI产品,最佳状态!
我们在年后,给不少公司做了技术团队的技能集训,让你的团队瞬间拥有开发技能,感兴趣可以联系雄哥或工作人员!
期待与你展开愉快的技术交流和合作!
进群、知识星球优惠,联系雄哥技术助手-小胖!
53AI,企业落地应用大模型首选服务商
产品:大模型应用平台+智能体定制开发+落地咨询服务
承诺:先做场景POC验证,看到效果再签署服务协议。零风险落地应用大模型,已交付160+中大型企业
2024-03-30
2024-04-26
2024-05-10
2024-04-12
2024-05-28
2024-05-14
2024-04-25
2024-07-18
2024-04-26
2024-05-06
2024-12-22
2024-12-21
2024-12-21
2024-12-21
2024-12-21
2024-12-20
2024-12-20
2024-12-19