模型的量化(Quantization)

文章目录

  • 一、浮点数格式:FP64, FP32, FP16, BFLOAT16, TF32之间的相互区别
    • 1、关于浮点数
    • 2、常见的浮点数格式
  • 二、量化(Quantization)
    • 1、基本概念
    • 2、量化的实现
      • 8bit量化
      • 4bit量化
  • 三、QLora
  • 四、大语言模型量化方法对比:GPTQ、GGUF、AWQ
    • 1、GPTQ: Post-Training Quantization for GPT Models
    • 2、GPT-Generated Unified Format
    • 3、AWQ: Activation-aware Weight Quantization


一、浮点数格式:FP64, FP32, FP16, BFLOAT16, TF32之间的相互区别

1、关于浮点数

浮点数是一种用二进制表示的实数,它由三个部分组成:sign(符号位)、exponent(指数位)和fraction(小数位)。不同的浮点数格式有不同的位数分配给这三个部分,从而影响了它们能表示的数值范围和精度。
在这里插入图片描述

2、常见的浮点数格式

浮点数格式表示位数signexponentfraction数值范围适用范围
FP64(双精度浮点数)64位1位11位52位大约在2.23e-308到1.80e308,精度大约是15到17位有效数字常用于科学计算中对精度要求较高的场合,但在深度学习中不常用,因为它占用的内存和计算资源较多
FP32(单精度浮点数)32位1位8位23位大约是1.18e-38到3.40e38,精度大约是6到9位有效数字深度学习中长期使用的标准格式,因为它能平衡数值范围和精度,同时也有较好的硬件支持
FP16(半精度浮点数)16位1位5位10位大约是6.10e-5到6.55e4,精度大约是3到4位有效数字深度学习中越来越流行的格式,因为它能节省内存和计算资源,同时也有张量核心(Tensor Core)等专门的硬件加速器。但是数值范围和精度较低,可能导致数值溢出或下溢的问题。
BFLOAT16(Brain Floating Point 16)16位1位8位7位数值范围和FP32相同,但精度只有2位有效数字由Google提出的一种针对深度学习优化的格式,能保持和FP32相同的数值范围,从而避免数值溢出或下溢的问题,同时也能节省内存和计算资源,提高训练速度。但是精度较低,可能导致数值不稳定或精度损失的问题。
TF32(TensorFloat 32)32位1位8位10位剩余的13位被忽略。它的数值范围和FP32相同,但精度只有3到4位有效数字NVIDIA在Ampere架构中推出的一种专为深度学习设计的格式,它的优点是能保持和FP32相同的数值范围,同时也能利用张量核心(Tensor Core)等专门的硬件加速器,提高训练速度。它的缺点是精度较低,可能导致数值不稳定或精度损失的问题。

二、量化(Quantization)

1、基本概念

量化是机器学习中一种优化技术,旨在减少模型的内存占用、计算开销,并加速推理过程。其核心思想是将模型中的浮点数参数(通常是32位浮点数)转化为低精度的数值表示(如8位、16位整数等),也就是说,使用更少的bit来存储原本以浮点数存储的tensor,以及使用更少的bit来完成原本以浮点数完成的计算。因此可以减少模型的存储和计算成本,同时尽量保持模型的性能。

  • 权重量化(Weight Quantization):将模型的权重(weights)从32位浮点数转换为较低精度(如8位整数)。这种方法通常会减少存储和计算负担。
  • 激活量化(Activation Quantization):将模型中的激活值(中间计算结果)量化为低精度表示,进一步减少计算资源。
  • 混合量化(Mixed Precision Quantization):不同的层或参数使用不同的量化精度,某些关键层使用较高精度,其他层使用较低精度,以平衡性能和效率。

2、量化的实现

我们可以直接使用Bitsandbytes库进行量化操作:

8bit量化

from transformers import  BitsAndBytesConfig
quantization_config = BitsAndBytesConfig(
    load_in_8bit=True,  # 启用 8-bit 量化 [−128,127]
    llm_int8_threshold=6.0,  # 设置低精度计算的阈值:当某个权重的绝对值超过这个阈值时,认为它对模型性能的影响较大,将其保留为高精度类型。
    llm_int8_skip_modules=None  # 指定跳过量化的模块(可选)
)

model = Qwen2VLForConditionalGeneration.from_pretrained(
    "/path/to/qwen_2B_instruct", torch_dtype=torch.bfloat16, device_map="cuda", quantization_config=quantization_config,
)

4bit量化

quantization_config = BitsAndBytesConfig(
    load_in_4bit=True,  # 启用 4-bit 量化 [-8, 7]
    bnb_4bit_compute_dtype="float16",  # 计算时的精度:量化主要针对模型的权重存储,而实际计算仍然需要浮点数来保持精度。
    bnb_4bit_use_double_quant=True,  # 双重量化:4-bit 权重的值被先量化为 int8,然后再进一步压缩到 4-bit。
    bnb_4bit_quant_type="nf4"  # 量化类型(如 `nf4` 或标准量化) NF4 使用对数分布或其他非均匀分布来更精确地表示权重值。
)

三、QLora

在量化的模型上插入 LoRA 层,微调这些低秩参数。量化后的权重在反向传播时被临时去量化(恢复为高精度),以确保梯度计算的精度。 显存占用极低,支持超大模型。

from transformers import AutoModelForCausalLM, BitsAndBytesConfig
from peft import LoraConfig, get_peft_model

bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_compute_dtype="float16",
    bnb_4bit_quant_type="nf4",
)

model_name = "huggingface/llama-7b"
model = AutoModelForCausalLM.from_pretrained(model_name, quantization_config=bnb_config)

lora_config = LoraConfig(
    r=4,
    lora_alpha=16,
    target_modules=["q_proj", "v_proj"],
    lora_dropout=0.1,
)

model = get_peft_model(model, lora_config)

四、大语言模型量化方法对比:GPTQ、GGUF、AWQ

  • GPTQ 通过梯度优化对量化误差进行最小化,适用于后训练阶段的精细量化,精度较高。
  • GGUF 采用全局统一的量化策略,具有简单高效的优点,适用于资源受限的部署场景,但可能导致某些模型层的精度损失。
  • AWQ 关注激活值的量化,通过分析激活值的分布对量化策略进行自适应调整,精度更高但计算复杂度较大。

1、GPTQ: Post-Training Quantization for GPT Models

GPTQ (Gradient-based Post-training Quantization)是一种基于梯度的后训练量化方法,主要目的是在减少浮点计算时尽量保持模型的性能。这种方法对大语言模型的量化尤其有效,适用于 8-bit 或更低的量化需求。

  • 后训练量化:模型已经训练完毕,不需要重新训练,只需在训练后对权重进行量化。
  • 梯度校正:在进行量化的过程中,GPTQ 通过优化目标函数,对量化误差进行最小化。它通过梯度优化调整量化时的权重误差,使得量化后模型的表现与未量化模型尽可能接近。
  • 误差补偿:由于量化不可避免地引入误差,GPTQ 采用了误差反馈机制,将量化过程中产生的误差传播到后续的层进行补偿,从而减少累积误差对模型输出结果的影响。
# # 环境安装
# pip install transformers accelerate
# pip install git+https://github.com/qwopqwop200/GPTQ-for-LLaMa.git

import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from gptq import GPTQ

model_name = "huggingface/llama"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(model_name, torch_dtype=torch.float16)

# 初始化 GPTQ
quantizer = GPTQ(model)
W_BITS = 8 # 设置量化位数(比如8-bit量化)

# 量化模型
quantizer.quantize(w_bits=W_BITS, layer_types=["self_attn", "mlp"])
quantized_model = quantizer.finish()

# 测试模型推理(生成文本)
input_text = "What is the capital of France?"
inputs = tokenizer(input_text, return_tensors="pt")
outputs = quantized_model.generate(**inputs, max_new_tokens=20)
decoded_output = tokenizer.decode(outputs[0], skip_special_tokens=True)
print(decoded_output)

2、GPT-Generated Unified Format

GPTQ是最常用的压缩方法,因为它针对GPU使用进行了优化。但是如果你的GPU无法处理如此大的模型,那么从GPTQ开始切换到以cpu为中心的方法(如GGUF)是绝对值得的。GGUF(以前称为GGML)允许用户使用CPU来运行LLM,但也可以将其某些层加载到GPU以提高速度。

GGUF (Generalized Global Uniform Quantization Framework)是一种通用的全局统一量化框架,专门设计用于处理大规模神经网络。

  • 全局量化:将整个模型中的所有参数统一映射到固定的范围,比如使用 8-bit 或 4-bit 表示所有的浮点数。它假设模型的所有层或某一类参数具有相似的分布,从而可以使用相同的量化范围。
  • 均匀量化:所有的数值都被线性地映射到一个均匀的范围。这种方式计算效率高,尤其适合硬件加速器。
  • 权重重定标:由于采用统一量化策略,GGUF 通常会引入一个缩放因子,用来在推理阶段重定标量化后的数值,以避免数值溢出或精度过低的问题。
import torch
from transformers import GPT2Tokenizer, GPT2LMHeadModel
from torch.quantization import QuantStub, DeQuantStub, quantize_dynamic

model_name = "gpt2"
tokenizer = GPT2Tokenizer.from_pretrained(model_name)
model = GPT2LMHeadModel.from_pretrained(model_name)

# 打印原始模型的大小
print(f"Original model size: {model.num_parameters()} parameters")

# 模型准备:将全局所有层量化(使用动态量化)
quantized_model = quantize_dynamic(
    model,  # 要量化的模型
    {torch.nn.Linear},  # 量化哪些层(这里是线性层)
    dtype=torch.qint8  # 量化数据类型,这里使用 8-bit 量化
)

# 打印量化后的模型大小
print(f"Quantized model size: {sum(p.numel() for p in quantized_model.parameters())} parameters")

# 测试量化后的模型生成文本
input_text = "Once upon a time"
inputs = tokenizer(input_text, return_tensors="pt")
outputs = quantized_model.generate(**inputs, max_new_tokens=50)
generated_text = tokenizer.decode(outputs[0], skip_special_tokens=True)
print("Generated text:", generated_text)

3、AWQ: Activation-aware Weight Quantization

AWQ(激活感知权重量化)是一种类似于GPTQ的量化方法。AWQ和GPTQ作为方法有几个不同之处,但最重要的是AWQ假设并非所有权重对LLM的性能都同等重要,也就是说在量化过程中会跳过一小部分权重,这有助于减轻量化损失。

AWQ主要关注激活值,在量化过程中考虑了激活值分布对模型性能的影响。这种方法通过分析激活值的分布特性,在量化过程中对激活值进行适应性处理,从而提高量化后模型的准确性。

  • 激活值感知:在对权重进行量化的同时,AWQ 也会对每一层的激活值分布进行分析。在某些层,激活值可能呈现出不均匀或长尾分布,导致量化过程中精度下降。AWQ 对这些激活值分布进行感知并自适应调整量化策略。
  • 非均匀量化:在量化激活值时,AWQ 并不采用线性均匀量化,而是针对不同的激活值范围选择不同的量化尺度。这样可以更好地捕捉激活值的细节,减少量化误差。
  • 动态缩放:通过动态调整每层的量化缩放因子,使得量化后的激活值分布尽量保持和原始模型一致。
import torch
from transformers import GPT2Tokenizer, GPT2LMHeadModel
from torch.quantization import QuantStub, DeQuantStub, prepare_qat, convert

# 加载 GPT-2 模型和分词器
model_name = "gpt2"
tokenizer = GPT2Tokenizer.from_pretrained(model_name)
model = GPT2LMHeadModel.from_pretrained(model_name)

# 定义量化模块
class QuantizedGPT2(torch.nn.Module):
    def __init__(self, model):
        super(QuantizedGPT2, self).__init__()
        self.quant = QuantStub()  # 用于激活值的量化
        self.model = model
        self.dequant = DeQuantStub()  # 用于激活值的反量化
    
    def forward(self, input_ids):
        # 对输入的激活值进行量化
        quantized_inputs = self.quant(input_ids)
        outputs = self.model(input_ids=quantized_inputs)
        # 对输出进行反量化
        return self.dequant(outputs.logits)

# 将模型包装在量化模块中
quantized_model = QuantizedGPT2(model)

# 量化感知训练准备(QAT)
quantized_model.qconfig = torch.quantization.get_default_qat_qconfig('fbgemm')

# 准备 QAT
quantized_model = prepare_qat(quantized_model, inplace=True)

# 模拟训练(可以加载现有权重并继续训练)
input_text = "What is the capital of France?"
inputs = tokenizer(input_text, return_tensors="pt")['input_ids']
quantized_model.train()

for _ in range(10):  # 模拟训练步骤
    outputs = quantized_model(inputs)
    loss = torch.nn.functional.cross_entropy(outputs.view(-1, outputs.size(-1)), inputs.view(-1))
    loss.backward()

# 完成量化
quantized_model.eval()
quantized_model = convert(quantized_model)

# 测试量化后的模型
with torch.no_grad():
    outputs = quantized_model(inputs)
generated_text = tokenizer.decode(outputs[0].argmax(dim=-1), skip_special_tokens=True)
print("Generated text:", generated_text)

参考:
https://www.cnblogs.com/lemonzhang/p/17843336.html
bupt-yiwo/VLLM
Pytorch模型量化
大语言模型量化方法对比:GPTQ、GGUF、AWQ
【LLM】8:大语言模型的量化(GPTQ、GGUF、AWQ原理)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

10. zynq应用开发--camke编译

使用SDK工具 如果只做 Linux 应用开发,只需要一个 sdk.sh 文件即可,可以脱离 Petalinux 和 Vitis,也可以编译其三方的应用,可以说一劳永逸。 配置根文件系统 petalinux-config -c rootfs 编译SDK petalinux-build --sdk Linux主…

CSS学习记录20

CSS 3D 转换 通过CSS transform 属性,您可以使用以下3D转换方法: rotateX()rotateY()rotateZ() rotateX() 方法 rotateX() 方法使元素绕其X轴旋转给定角度: #myDiv {transform: rotateX(150deg); } rotateY() 方法 rotateY() 方法使元…

开发微信小程序的过程与心得

起因 作为家长,我近期参与了学校的护学岗工作。在这个过程中,我发现需要使用水印相机来记录护学活动,但市面上大多数水印相机应用都要求开通会员才能使用完整功能。作为一名程序员,我决定利用自己的技术背景,开发一个…

【论文笔记】Visual Alignment Pre-training for Sign Language Translation

🍎个人主页:小嗷犬的个人主页 🍊个人网站:小嗷犬的技术小站 🥭个人信条:为天地立心,为生民立命,为往圣继绝学,为万世开太平。 基本信息 标题: Visual Alignment Pre-tra…

数据可视化echarts学习笔记

目录,介绍 知识储备 一端操作,多端联动的效果(开启了多个网页,操作一端,多个网页的效果会跟着改变) cmd命令控制面板返回上一级或上上级 在当前目录打开文件: cd 文件名 在Windows命令提示符&am…

踏踏实实练SQLday1-1连续登录

踏踏实实练SQLday1 1连续登录1.1查询连续登录3天以上的用户第一步去重第二步-开窗rownumber,用date减一下,对结果进行分组 -- over()开窗函数知识图谱第三步 1.2查询连续登录最大天数用户1.3某个用户连续登录天数注意先where一下这个用户的数据过滤出来.…

Vue开发环境搭建上篇:安装NVM和NPM(cpnm、pnpm)

文章目录 引言I 安装NVM1.1 Windows系统安装NVM,实现Node.js多版本管理1.2 配置下载镜像1.3 NVM常用操作命令II NPM永久使用淘宝源安装 cnpm安装pnpm【推荐】see also: vscode常用插件引言 淘宝镜像:http://npm.taobao.org 和 http://registry.npm.taobao.org 已在 2022.06.3…

数据仓库工具箱—读书笔记02(Kimball维度建模技术概述03、维度表技术基础)

Kimball维度建模技术概述 记录一下读《数据仓库工具箱》时的思考,摘录一些书中关于维度建模比较重要的思想与大家分享🤣🤣🤣 第二章前言部分作者提到:技术的介绍应该通过涵盖各种行业的熟悉的用例展开(赞同…

Postman接口测试02|执行接口测试、全局变量和环境变量、接口关联、动态参数、断言

目录 五、Postman 1、安装 2、postman的界面介绍 六、Postman执行接口测试 1、请求页签 3、响应页签 七、Postman的环境变量和全局变量 1、创建环境变量和全局变量可以解决的问题 2、postman中的操作 八、接口关联 1、第一种方式:Json提取器 2、第二种方…

Oracle 日常巡检

1. 检查服务器状态 1.1. CPU使用情况 1.1.1. top top 命令是 Linux 和 Unix 系统中用于显示实时系统状态的工具,特别是对于监控 CPU 和内存的使用非常有用。 在命令行中输入 top,top 会显示一个实时更新的界面,其中包含系统的关键指标&am…

计算机组成原理的学习笔记(8)-- 指令系统·其一 指令的组成以及数据寻址方式

学习笔记 前言 ​ 本文主要是对于b站尚硅谷的计算机组成原理的学习笔记,仅用于学习交流。 1. 指令 1.1 组成 操作码(Opcode):指指令中执行特定操作的部分。地址码:指令中用于指定操作数位置的部分。 1.2 扩展操作…

JavaScript 标准内置对象——Array

1、构造函数 2、静态方法 // 从可迭代或类数组对象创建一个新的浅拷贝的数组实例 // arrayLike 想要转换成数组的类数组或可迭代对象 Array.from(arrayLike, mapFn, thisArg) Array.fromAsync(arrayLike, mapFn, thisArg) // 异步Array.isArray(value) // 判断传递的值是否是一…

IndexOf Apache Web For Liunx索引服务器部署及应用

Apache HTTP Server 是一款广泛使用的开源网页服务器软件,它支持多种协议,包括 HTTP、HTTPS、FTP 等 IndexOf 功能通常指的是在一个目录中自动生成一个索引页面的能力,这个页面会列出该目录下所有的文件和子目录。比如网上经常看到的下图展现的效果,那么接下来我们就讲一下…

【PSINS】EKF、UKF、CKF三个滤波下的组合导航(松组合)对比

该 MATLAB 代码实现了扩展卡尔曼滤波(EKF)、无迹卡尔曼滤波(UKF)和无迹卡尔曼滤波的变体(CKF)的对比,主要用于导航与定位领域,通过处理惯性测量单元(IMU)和GP…

PPT画图——如何设置导致图片为600dpi

winr,输入regedit打开注册表 按路径找,HKEY_CURRENT_USER\Software\Microsoft\Office\XX.0\PowerPoint\Options(xx为版本号,16.0 or 15.0或则其他)。名称命名:ExportBitmapResolution 保存即可,…

Linux复习4——shell与文本处理

认识vim编辑器 #基本语法格式: vim 文件名 •如果文件存在,进入编辑状态对其进行编辑 •如果文件不存在,创建文件并进入编辑状态 例: [rootlocalhosttest]# vim practice.txt #Vim 编辑器三种模式: 命令模式&a…

Gmsh有限元网格剖分(Python)---点、直线、平面的移动

Gmsh有限元网格剖分(Python)—点、直线、平面的移动和旋转 最近在学习有限元的网格剖分算法,主要还是要参考老外的开源Gmsh库进行,写一些博客记录下学习过程,方便以后回忆嘞。 Gmsh的官方英文文档可以参考:gmsh.pdf 但咋就说&a…

【Linux】基础I/O -> 如何谈文件与文件系统?

文件的基础理解 空文件也要在磁盘上占据空间。文件 文件内容文件属性。文件操作 对内容的操作 对属性的操作或者是对内容和属性的操作。标定一个文件,必须使用:文件路径 文件名(具有唯一性)。如果没有指明对应的文件路径&…

python+reportlab创建PDF文件

目录 字体导入 画布写入 创建画布对象 写入文本内容 写入图片内容 新增页 画线 表格 保存 模板写入 创建模板对象 段落及样式 表格及样式 画框 图片 页眉页脚 添加图形 构建pdf文件 reportlab库支持创建包含文本、图像、图形和表格的复杂PDF文档。 安装&…

软件项目需求分析的实践探索(1)

一、项目启动与规划 组建团队 包括项目经理、系统分析师、业务分析师以及可能涉及的最终用户代表和领域专家等。例如,开发一个医疗管理软件,就需要有医疗行业的专家参与,确保对医疗业务流程有深入理解。明确各成员的职责,如系统分…