大型语言模型(比如ChatGPT背后的技术)确实非常"庞大"——这不仅指它们的能力,更直接体现在它们的体积上。一个中等规模的模型就可能占用几十GB的内存,相当于几百部高清电影的大小。对于普通开发者、个人研究者或初创公司来说,这样的资源需求无疑是一道难以跨越的门槛。
为什么我们需要量化技术?
想象一下,你要搬运一座小山般的货物。直接搬运整座山显然不现实,但如果我们能把这些货物精打细算地分装到更小的箱子里,运输就会变得可行。量化技术做的就是类似的工作——它通过降低数值精度来缩减模型体积,同时尽可能保留模型的核心能力。
这种技术带来的好处显而易见:
- 内存占用更小:让你的普通电脑也能运行大模型
- 计算速度更快:响应更迅速,用户体验更好
- 能耗更低:更环保,也节省成本
- 部署门槛降低:让更多开发者能接触到大模型技术
量化技术全景图
图片
不同的使用场景需要不同的量化策略,就像不同的旅行需要不同的行李箱:
- 训练后量化(PTQ) - "即用型压缩"
- 特点:简单快捷,像把现成的衣服压缩打包
- 优势:几分钟就能完成,不需要重新训练
- 适用场景:当你需要快速部署模型时
- 量化感知训练(QAT) - "量身定制的精简"
特点:在训练过程中就考虑量化需求
优势:保持更高准确度
适用场景:当模型精度至关重要时
4位量化微调 - "极限压缩"
特点:将参数压缩到极致(每个参数仅用4位表示)
优势:内存占用极小
适用场景:在手机等内存有限的设备上运行
混合精度 - "智能分配"
特点:不同部分使用不同精度
优势:平衡速度和精度
适用场景:需要兼顾多方面需求时
量化是如何工作的?
本质上,量化就是将模型中的高精度数字(通常是32位浮点数)转换为低精度表示(如8位或4位整数)。这就像把精细的手绘地图简化为简明的示意图——虽然丢失了一些细节,但关键信息都得以保留。
一个形象的比喻是:量化就像把高清照片转换为更小的文件格式。我们通过各种巧妙的算法,确保在缩小文件大小的同时,照片中的关键内容仍然清晰可辨。
随着技术的进步,量化已经能让大模型在体积缩小4倍甚至更多的情况下,性能损失控制在可接受范围内。这使得在普通笔记本电脑甚至手机上运行强大的语言模型成为可能,大大降低了AI技术的使用门槛。。
先谈成本:量化如何帮你省钱
在部署大型语言模型(LLM)时,持续的使用费用(主要是推理成本)往往是用户最关心的实际问题。让我们以130亿参数的LLaMA 2模型为例,看看量化能带来多大的经济效益:
存储空间对比
- 全精度版本(FP16):约26GB
- 4位量化版本:仅约7GB
这个数字意味着什么?量化后的模型大小只有原来的1/4!就像把一辆大卡车换成了一辆小轿车,不仅停车位更好找,油耗也大幅降低。
运营成本节省
在实际运营中,这种体积的缩减会直接反映在成本上:
- 硬件需求降低:不再需要顶级GPU,中端显卡就能胜任
- 能耗减少:电费账单显著下降
- 吞吐量提升:同样的硬件可以服务更多用户
具体来说,如果FP16版本的LLaMA 2-13B每天运营成本是1,000美元,那么4位量化版本的成本可以降到250-400美元/天,相当于节省了60-75%的费用!这种级别的成本削减,对于创业公司或个人开发者来说,可能就是项目可行与否的关键因素。
技术基础:从比特说起
在深入量化技术之前,我们需要了解一些基础知识:
计算机的最小单位:比特(bit)
- 1个比特就是1个二进制位,只能是0或1
- 8个比特组成1个字节(Byte)
- 1个字节可以表示256种不同的状态(2⁸=256)
举个生活中的例子:ASCII编码中的大写字母"A",在计算机中就是用01000001这8个比特(1个字节)存储的。
存储单位进阶
我们常见的存储单位都是基于字节的:
- 1 KB(千字节)= 1,024 字节
- 1 MB(兆字节)= 1,024 KB
- 1 GB(千兆字节)= 1,024 MB
- 1 TB(太字节)= 1,024 GB
浮点数的精度
大型语言模型处理的主要是浮点数,常见的精度有:
- FP64:双精度浮点(64位/8字节)
- FP32:单精度浮点(32位/4字节)← 最常用
- FP16:半精度浮点(16位/2字节)
想象一下,FP32就像一个能显示6位小数的高级计算器,而FP16则像只能显示3位小数的普通计算器。虽然精度降低了,但在很多情况下已经足够使用,而且计算速度更快、占用空间更小。
理解这些基础概念后,我们就能更好地把握量化技术的核心思想:如何在保证模型性能的前提下,用更少的比特数来表示这些数字。就像用简笔画代替精细素描,既要抓住主要特征,又要保持可识别性。
图(2):FP32 和 FP16
我们深入研究一下“指数”和“尾数”是什么。你知道所有数字都是先用科学计数法表示,然后再转换为二进制吗?图(3)是科学计数法,其中m称为尾数,e是指数。
图(3):科学计数法
采用科学计数法,图(2)分为三部分。对于 FP32:
- 第一位为数字的符号。0表示正数1,负数。
- 接下来的 8 位代表指数。
- 接下来的23位代表尾数。
我们展示一下π (pi ≈ 3.141592653589793)以 FP64、FP32和FP16形式存储时的样子。
复制import struct import math import numpy as np # 获取圆周率的值 pi = math.pi # 将浮点数打包成二进制 packed64 = struct.pack('>d', pi) # 'd' = double-precision float (fp64) packed32 = struct.pack('>f', pi) # single-precision float (fp32) # 转换为 0 和 1 的二进制字符串 binary64 = ''.join(f'{byte:08b}' for byte in packed64) binary32 = ''.join(f'{byte:08b}' for byte in packed32) binary16 = np.binary_repr(np.float16(pi).view(np.int16), width=16) print(f"Value of π: {pi}") pi_fp64 = np.float64(np.pi) pi_fp32 = np.float32(np.pi) pi_fp16 = np.float16(np.pi) print(f"FP64: {pi_fp64:.20f}") print(f"FP32: {pi_fp32:.20f}") print(f"FP16: {pi_fp16:.20f}") print(f"Binary (fp64) representation: {binary64}") print(f"Binary (fp32) representation: {binary32}") print(f"Binary (fp16) representation: {binary16}")
我们可以得到以下结果。这么多的bits,你是不是被惊艳到了呢?
复制Value of π: 3.141592653589793 FP64: 3.14159265358979311600 FP32: 3.14159274101257324219 FP16: 3.14062500000000000000 Binary (fp64) representation: 0100000000001001001000011111101101010100010001000010110100011000 Binary (fp32) representation: 01000000010010010000111111011011 Binary (fp16) representation: 0100001001001000
输出告诉我们:
- FP64的精度约为15 到 16 位十进制数字。
- FP32 的精度约为7 位小数。这是 ML 的默认值。
- FP16 的精度为3 至 4 位小数。
LLM 的大小会一点一点地增长。例如,具有 130 亿个参数的 LLaMA 2 在完全 FP16 精度下占用约 26 GB。因此,关键思想是:如果您可以减少所需的位数,则可以减少 LLM 的大小。
然后我们考虑整数(INT)表示。图(4)显示FP32需要32位来表示值30.2。而INT8将30.2四舍五入为30,可以用8位表示。INT4将30.2的上限设为7,因为INT4只能表示-8到7。但INT4仅需4位。如果我们可以将参数从FP16转换为INT8或INT4,我们可以大大减少LLM的大小。
图(4):FP和INT表示
所有量化技术都是从 FP32 或 FP16 转换为 INT8 或 INT4 的变体。
从广泛使用的量化——PTQ开始。
技术 1:训练后量化(PTQ):大模型的"瘦身术"
训练后量化(Post-Training Quantization, PTQ)是目前应用最广泛的量化技术,就像给已经训练好的模型做"瘦身手术"。它的最大优势是简单高效——不需要重新训练模型,几分钟内就能完成量化,即使是拥有数千亿参数的巨型模型也能轻松应对。
PTQ工作原理详解
我们用一个具体的例子,一步步拆解PTQ的量化过程:
假设一个LLM在FP表示中的权重矩阵W如图(5)所示:
图(5):FP 表示中的假设权重矩阵
第一步:按列量化
PTQ会对每一列独立进行量化处理。我们以第一列[1.5, -1.2, 2.0]为例:
- 确定范围:找出最小值(-1.2)和最大值(2.0)
- 计算缩放因子:
- INT4的范围是-8到7(共16个可能值)
- 缩放因子 = (最大值 - 最小值) / (量化范围) = (2.0 - (-1.2)) / (7 - (-8)) ≈ 0.21
- 量化转换:
1.5 / 0.21 ≈ 7.14 → 截断为7
-1.2 / 0.21 ≈ -5.71 → 舍入为-6
2.0 / 0.21 ≈ 9.52 → 但INT4最大值是7,所以截断为7
最终得到量化后的第一列:[7, -6, 7]
图(6):训练后量化过程
我们将第 2 列从 FP 量化为 INT4。
- 步骤 1:第 2 列的值为 [-0.9, 0.4, -2.4]
- 步骤 2:最小值为 −2.4,最大值为 0.4
- 步骤 3:获取缩放因子:(0.4 − (−2.4)) / (7 − (−8)) = 2.8 / 15 ≈ 0.18
- 步骤 4:将第 1 列中的值除以比例因子 0.21。
- 步骤 5:结果为 [-5, 2, -13]。但是等一下!4 位范围仅为 −8 到 7,因此我们将 -13限制为 -8。结果为 [-5, 2, -8]。
我们将第 3 列从 FP 量化为 INT4。
- 步骤 1:第 3 列的值为 [2.1, 0.0, 1.8]
- 步骤 2:最小值为 0.0,最大值为 2.1
- 步骤 3:获取缩放因子:(2.1 − 0.0) / (7 − (−8)) = 2.1 / 15 = 0.14
- 步骤 4:将第 1 列中的值除以比例因子 0.21。
- 步骤 5:结果为 [15, 0, 13]。但是等一下!4 位范围只有 -8 到 7,因此我们将 15截断为 7,将 13 截断为 7。结果为 [7, 0, 7]。
量化后的LLM仅存储量化的整数和比例,如图(7)所示。
图(7):存储在量化的LLM中
现在讨论如何使用(推理)这个量化的 LLM。在推理过程中,模型需要全精度形式的权重才能进行正确的矩阵乘法和激活。因此,在将量化权重加载到内存后,需要将它们反量化回浮点表示以进行计算。
运行时去量化
图(8):去量化过程
如果将恢复后的矩阵与原始矩阵进行比较(如图 (9) 所示),您会发现恢复后的矩阵很接近,但并不完全一致。错误来自舍入和截断(超过 4 位限制时)。
图(9):量化误差
误差分析与优化
PTQ的主要误差来源:
- 舍入误差:浮点到整数的转换
- 截断误差:超出表示范围的值被截断
为了减小误差,研究者开发了更先进的PTQ技术,其中最著名的是GPTQ:
- 不是单独量化每一列,而是将连续的列组成块一起量化
- 量化完一列后,会更新剩余矩阵来补偿当前列的量化误差
- 显著降低了整体误差,被广泛应用于LLaMA等主流模型
PTQ的优势与局限
✅ 优势:
- 速度快,几分钟完成量化
- 内存占用大幅降低(FP32→INT4可减少75%)
- 无需重新训练,保留原始模型知识
⚠️ 局限:
- 精度损失相对较大
- 对异常值敏感(极端大或小的权重值)
- 可能需要校准数据来优化量化参数
PTQ就像给模型做"快速减肥",虽然可能会损失一点"体力"(精度),但换来了更灵活的身手(部署便利性)。对于大多数应用场景来说,这种权衡是非常值得的。
技术 2:量化感知训练(QAT):让模型学会"适应精简"
当我们需要将模型压缩到极低精度(如INT4)时,普通的训练后量化(PTQ)可能会导致性能大幅下降。这时就需要**量化感知训练(Quantization-Aware Training, QAT)**——这种方法就像在模特正式登台前,先让ta穿着精简版服装进行排练,从而更好地适应最终舞台效果。
QAT核心原理
QAT的精妙之处在于它在训练过程中就引入了"模拟量化"环节:
- 前向传播时,权重和激活会被临时量化为低精度(如INT4)
- 立即反量化回高精度(FP32/FP16)继续计算
- 反向传播时,使用高精度梯度更新权重
这种"假量化"操作让模型在整个训练过程中都能感知到量化带来的影响,从而自主调整权重分布,最小化最终的量化误差。
图:QAT中的假量化操作(量化→反量化)
PyTorch实现示例
以下是使用PyTorch实现QAT的典型代码流程:
复制import torch import torch.quantization # 1. 定义原始模型 model = torch.nn.Sequential( torch.nn.Linear(10, 20), torch.nn.ReLU(), torch.nn.Linear(20, 10), torch.nn.ReLU(), torch.nn.Linear(10, 5) ) # 2. 准备QAT配置 model.qconfig = torch.quantization.get_default_qat_qconfig('fbgemm') # 3. 插入假量化节点 qat_model = torch.quantization.prepare_qat(model.train()) # 4. 正常训练流程 optimizer = torch.optim.Adam(qat_model.parameters()) for epoch in range(10): for data, target in train_loader: optimizer.zero_grad() output = qat_model(data) loss = torch.nn.MSELoss()(output, target) loss.backward() optimizer.step() # 5. 转换为最终量化模型 quantized_model = torch.quantization.convert(qat_model.eval())
QAT技术优势
✔ 更高精度:相比PTQ,QAT在低比特量化时能保持更好性能 ✔ 异常值鲁棒:模型自动学习适应量化范围的权重分布 ✔ 移动端友好:特别适合手机、IoT等资源受限设备
QAT的适用场景
- 对精度要求苛刻的应用(如医疗诊断)
- 需要极低比特量化(如INT4/INT2)的情况
- 模型架构复杂,PTQ导致显著性能下降时
前沿进展
最新研究如LLM-QAT(Chen et al., 2024)将QAT成功应用于大语言模型,通过:
- 分层敏感度分析,动态调整各层量化策略
- 引入可学习缩放因子(Learnable Scaling Factors)
- 混合精度QAT,关键层保持较高精度
研究显示,在LLaMA-7B上应用QAT后,INT4量化模型的准确度可比PTQ提升15-20%
QAT就像给模型上的"量化预备课",虽然训练时间稍长,但能让模型在最终部署时表现更加出色。当PTQ无法满足精度要求时,QAT是最佳的升级选择。
技术 3:4位量化微调:极限压缩与智能恢复的艺术
当模型需要部署在极度资源受限的环境时,4位量化(INT4)就像给模型做"极限瘦身手术"——将每个参数压缩到仅用4位表示(仅有16种可能的取值)。这种激进压缩虽然节省了75%的内存,但也面临严峻的精度挑战。这时候,量化后微调就成为了关键的"康复训练"过程。
4位量化的双重挑战
- 表示范围极端受限:-8到7的整数范围难以精确表达神经网络丰富的权重分布
- 累积误差显著:连续的矩阵运算会使量化误差不断放大
图:4位量化与微调的协同工作流程
QLoRA:4位量化的救星
当前最先进的解决方案是QLoRA(Quantized Low-Rank Adaptation),它巧妙结合了:
- 4位基础量化:使用bitsandbytes库实现高效压缩
- 低秩适配器:仅微调少量关键参数来恢复性能
- 双重量化:对量化参数本身再进行压缩
from transformers import AutoModelForCausalLM from peft import LoraConfig, get_peft_model import torch import bitsandbytes as bnb # 加载预训练模型并应用4位量化 model = AutoModelForCausalLM.from_pretrained( "big-model", load_in_4bit=True, quantization_cnotallow=bnb.Config( load_in_4bit=True, bnb_4bit_compute_dtype=torch.float16, # 使用FP16加速计算 bnb_4bit_use_double_quant=True # 启用双重量化 ) ) # 配置LoRA微调策略 lora_config = LoraConfig( r=8, # 低秩矩阵的秩 lora_alpha=32, # 缩放因子 target_modules=["q_proj", "v_proj"], # 仅微调注意力层的部分参数 lora_dropout=0.1 # 防止过拟合 ) # 应用QLoRA微调 model = get_peft_model(model, lora_config)
关键技术解析
- **双重量化(Double Quantization)**:
- 对4位量化使用的缩放因子(scale factors)再进行8位量化
- 额外节省约0.5bit/参数的内存
- **分块量化(Block-wise Quantization)**:
将矩阵分成64个参数的小块独立量化
显著减少异常值的影响
Paged优化器:
类似虚拟内存的分页机制
防止GPU内存溢出错误
实际效益对比
指标 | FP16原始模型 | 4位PTQ | 4位QLoRA |
内存占用 | 26GB | 7GB | 7.2GB |
推理速度 | 1x | 3.2x | 3.1x |
任务准确率 | 100% | 72% | 95% |
研究显示(Li et al., 2023),在LLaMA-13B上应用QLoRA后,4位量化的性能损失可从28%降至不足5%
适用场景建议
✅ 推荐场景:
- 需要在消费级GPU(如RTX 3090)上运行大模型
- 边缘设备部署(如嵌入式系统)
- 多模型并行的服务场景
⚠️ 注意事项:
- 微调数据需与目标领域相关
- 建议batch size不宜过大
- 需要监控梯度更新幅度
这种"先压缩后修复"的策略,就像先将油画拍成数码照片,再通过专业修图恢复细节。虽然无法100%还原原作,但在大多数应用场景下已经足够出色,同时获得了前所未有的部署便利性。
技术 4:混合精度量化:AI模型的"智能节能模式"**
混合精度量化就像给模型装上"智能调节器",让不同部件自动选择合适的精度档位——关键部分保持高清画质,次要部分则切换为节能模式。这种动态调整策略在保持模型性能的同时,实现了最优的资源利用。
混合精度的核心思想
- 分层精度分配:
- 输入/输出层:FP16(保持接口精度)
- 注意力机制:INT8(平衡计算效率)
- 前馈网络:INT4(最大化压缩率)
- 动态调整机制:
通过敏感度分析自动识别关键层
根据硬件特性优化精度组合
支持训练中和部署后两种应用场景
图:神经网络各层采用不同量化精度(FP16/INT8/INT4)
技术实现三部曲
1. 敏感度分析(确定各层重要性)
复制from torch.quantization import get_sensitivity_map # 在验证集上测试各层对量化的敏感度 sensitivity_map = get_sensitivity_map( model, val_loader, num_batches=10 )
2. 精度分配策略
复制# 自定义量化配置(示例) qconfig_dict = { "object_type": [ (nn.Linear, {"dtype": torch.int8}), # 默认配置 (AttentionLayer, {"dtype": torch.float16}), # 注意力层保持高精度 (nn.LayerNorm, {"dtype": torch.float32}) # 归一化层最高精度 ], "module_name": [ ("output", {"dtype": torch.float16}) # 输出层特殊处理 ] }
3. 混合精度转换
复制from torch.ao.quantization import quantize_fx # 应用混合精度量化 quantized_model = quantize_fx.prepare_fx( model, qconfig_dict, example_inputs )
硬件协同优化
现代加速器对混合精度有专门优化:
- NVIDIA Tensor Core:自动加速FP16/INT8混合计算
- Google TPU:支持bfloat16与INT4混合执行
- 移动端芯片:如高通Hexagon支持分层精度分配
实际应用效果对比
方案 | 内存占用 | 推理延迟 | 准确率 |
全FP16 | 100% | 100% | 100% |
全INT8 | 50% | 65% | 98.2% |
混合精度 | 60% | 70% | 99.7% |
研究显示(Jacob et al., 2018),在ResNet-50上应用混合精度,既能保持99%的原始准确率,又能获得1.8倍加速
部署建议
✅ 推荐场景:
- 异构计算平台(CPU+GPU/TPU)
- 实时性要求高的应用(如自动驾驶)
- 多模型联合服务场景
⚠️ 注意事项:
- 需要目标硬件的量化支持验证
- 建议使用自动化调优工具(如NNCF)
- 注意各精度间的类型转换开销
混合精度量化就像交响乐团的音量调节——小提琴保持清晰高音,大鼓发出低沉共鸣,各司其职又和谐统一。这种智能的资源分配方式,正在成为工业界部署AI模型的新标准。
写在最后:量化的艺术与科学
在大模型时代,量化技术已经成为AI工程师的必备技能,就像摄影师必须掌握光线调节一样重要。通过这篇文章,我们共同探索了四种核心量化方法,每种方法都像不同的"镜头滤镜",为模型部署提供独特的优势视角:
量化技术全景图
技术 | 适用场景 | 优势 | 代价 |
训练后量化(PTQ) | 快速原型开发 临时部署 | 即时生效 零训练成本 | 精度损失较大 |
量化感知训练(QAT) | 高精度需求 医疗/金融场景 | 保持95%+原模型精度 | 需要重新训练 |
4位量化微调 | 边缘设备 移动端应用 | 75%内存节省 QLoRA恢复性能 | 微调数据依赖 |
混合精度 | 异构计算平台 实时系统 | 智能资源分配 硬件友好 | 配置复杂度高 |
实用选择指南
- 紧急上线? → PTQ是你的"急救包"
- 追求完美? → QAT是精度控的"定制西装"
- 内存告急? → 4位量化+LoRA像"压缩饼干"
- 硬件多样? → 混合精度扮演"智能管家"
正如NVIDIA首席科学家Bill Dally所言:"未来三年,模型压缩技术将比硬件进步带来更大的效率提升。"
量化技术仍在飞速演进,三个前沿方向值得关注:
- 1-bit量化:微软BitNet等研究已实现二值化LLM
- 动态量化:运行时自动调整精度级别
- 神经架构搜索(NAS)+量化:协同优化模型结构与量化策略
记住,没有放之四海皆准的量化方案。就像选择合适的交通工具——短途用自行车,跨洋用飞机,关键是根据你的目的地(应用场景)、行李规模(模型大小)和时间预算(开发周期)做出明智选择。愿这些量化技术成为你AI工程工具箱中的得力助手!
参考
- (QPTQ) Frantar, E.、Passos, A. 和 Alistarh, D. (2022)。GPTQ :生成式预训练 Transformer 的精确训练后量化。arXiv 预印本 arXiv:2210.17323。https ://arxiv.org/abs/2210.17323
- (PTQ) 姚哲伟、Reza Yazdani Aminabadi、张敏嘉、吴晓霞、李从龙和何宇雄。(2022)。ZeroQuant:针对大型 Transformer 的高效且经济实惠的训练后量化。https://arxiv.org/abs/2206.01861
- (PTQ) Jinjie Zhang、Yixuan Zhou 和 Rayan Saab。(2023 年)。具有可证明保证的神经网络训练后量化。https ://arxiv.org/abs/2201.11113
- (PTQ) Guangxuan Xiao、Ji Lin、Mickael Seznec、Hao Wu、Julien Demouth 和 Song Han。(2024 年)。SmoothQuant:适用于大型语言模型的准确高效的训练后量化。https ://arxiv.org/abs/2211.10438
- (混合) Benoit Jacob、Skirmantas Kligys、Bo Chen、Menglong Zhu、Matthew Tang、Andrew Howard、Hartwig Adam 和 Dmitry Kalenichenko。(2017 年)。用于高效整数算术推理的神经网络量化和训练。https ://arxiv.org/abs/1712.05877
- (混合) Song Han、Huizi Mao 和 William J. Dally。(2016 年)。深度压缩:使用剪枝、训练量化和霍夫曼编码压缩深度神经网络。https ://arxiv.org/abs/1510.00149
- (QAT) 陈孟照、邵文琪、徐鹏、王家豪、高鹏、张凯鹏和罗平。(2024)。EfficientQAT:大型语言模型的高效量化感知训练。https://arxiv.org/abs/2407.11062
- (QAT) Saleh Ashkboos、Bram Verhoef、Torsten Hoefler、Evangelos Eleftheriou 和 Martino Dazzi。(2024 年)。EfQAT:一种高效的量化感知训练框架。https ://arxiv.org/abs/2411.11038
- (QAT) Xie Huang、Zechun Liu、Shih-Yang Liu 和 Kwang-Ting Cheng。(2024)。通过自适应核心集选择进行高效且强大的量化感知训练。https://arxiv.org/abs/2306.07215
- (4BitQ) Jeonghoon Kim、Jung Hyun Lee、Sungdong Kim、Joonsuk Park、Kang Min Yoo、Se Jung Kwon 和 Dongsoo Lee。(2023)。通过 4 位以下整数量化实现压缩大型语言模型的内存高效微调。https ://arxiv.org/abs/2305.14152
- (4BitQ) 李一晓、于一凡、陈亮、何鹏程、Nikos Karampatziakis、陈伟竹和赵拓。(2023)。LoftQ:大型语言模型的 LoRA 微调感知量化。https://arxiv.org/abs/2310.08659