模型的量化(Quantization)

发布时间:2026/10/1 9:34:30
模型的量化(Quantization)
文章目录一、混合精度的原理一浮点数精度背景二常见的浮点数格式三混合精度的原理与使用流程四损失缩放Loss Scaling二、如何解决训练使用float16导致溢出的问题一float16 溢出问题的原因二解决溢出问题的方法1、使用混合精度训练2、损失缩放3、使用 bfloat16 代替 float164、改进数值稳定性5、调整超参数三、量化Quantization一基本概念二量化的实现1、8bit量化2、4bit量化四、QLora五、大语言模型量化方法对比GPTQ、GGUF、AWQ一GPTQ: Post-Training Quantization for GPT Models二GPT-Generated Unified Format三AWQ: Activation-aware Weight Quantization一、混合精度的原理混合精度Mixed Precision训练是一种通过结合不同数值精度如FP32和FP16进行深度学习模型训练的方法旨在提高计算效率并减少内存占用同时在保持模型精度的前提下优化训练性能。核心思想模型中的某些操作对数值精度要求较高而另一些操作可以使用较低精度完成从而在性能与精度之间找到平衡。一浮点数精度背景浮点数是一种用二进制表示的实数它由三个部分组成sign符号位、exponent指数位和fraction小数位。不同的浮点数格式有不同的位数分配给这三个部分从而影响了它们能表示的数值范围和精度。二常见的浮点数格式浮点数格式表示位数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等专门的硬件加速器。但是数值范围和精度较低可能导致数值溢出或下溢的问题。BFLOAT16Brain Floating Point 1616位1位8位7位数值范围和FP32相同但精度只有2位有效数字由Google提出的一种针对深度学习优化的格式能保持和FP32相同的数值范围从而避免数值溢出或下溢的问题同时也能节省内存和计算资源提高训练速度。但是精度较低可能导致数值不稳定或精度损失的问题。TF32TensorFloat 3232位1位8位10位剩余的13位被忽略。它的数值范围和FP32相同但精度只有3到4位有效数字NVIDIA在Ampere架构中推出的一种专为深度学习设计的格式它的优点是能保持和FP32相同的数值范围同时也能利用张量核心Tensor Core等专门的硬件加速器提高训练速度。它的缺点是精度较低可能导致数值不稳定或精度损失的问题。训练的时候用float16、bfloat16还是float32为什么float32 具有较高的精度通常用于模型训练的初始阶段或者极度敏感的参数如某些权重矩阵的更新尤其适合在小模型或者高精度模型调优阶段float16的数值范围和精度较低常用于需要降低显存使用和提高计算速度的场景尤其是大型模型的中间层或加速训练阶段bfloat16具有float32的数值范围和float16的存储优势但精度比float32低适合在深度学习训练中替代float32尤其是需要平衡计算效率和数值稳定性的情况下如Google TPU环境下的大模型训练。三混合精度的原理与使用流程混合精度训练的核心流程是根据不同操作的需求在前向传播、反向传播和权重更新中分别使用FP16和FP32来最大化训练效率具体步骤如下初始化模型的神经网络权重参数最初以FP32形式存储权重转换将神经网络的权重参数从FP32 转换为 FP16用于后续的计算前向传播与反向传播在前向和反向传播计算中使用FP16完成主要的矩阵运算和激活函数计算以减少内存占用并加速计算。反向传播过程中梯度也使用FP16进行计算梯度转换将FP16 的梯度转换回 FP32确保在梯度更新过程中使用更高精度的计算避免精度丢失梯度更新FP32的梯度与学习率相乘保证精度较小的数值不会因浮点数的限制而丢失权重更新使用更新后的FP32梯度更新网络的FP32权重。四损失缩放Loss Scaling问题在混合精度训练中由于FP16的数值表示范围较小特别是在反向传播过程中较小的梯度值可能会因为精度不足而变为零。为了解决这个问题引入了损失缩放技术将损失值按某个系数进行放大确保反向传播时梯度值足够大避免FP16下的数值下溢反向传播过程计算放大后的梯度计算完成后在更新参数前将梯度缩小相应倍数以保证数值正确性。二、如何解决训练使用float16导致溢出的问题一float16 溢出问题的原因由于float16 的指数位和尾数位较少其能表示的数值范围大大缩小*。这在训练深度学习模型时尤其是在反向传播过程中可能会导致梯度的溢出或下溢。二解决溢出问题的方法1、使用混合精度训练参数和激活值使用float16降低内存占用加快计算速度累加和关键计算使用float32提高数值稳定性防止溢出。2、损失缩放静态损失缩放使用固定的缩放因子动态损失缩放根据训练过程动态调整缩放因子3、使用 bfloat16 代替 float16bfloat16具有与float32相同的指数位数但是尾数位减少。因此其数值范围与 float32 相同但精度较低。更大的数值范围减少溢出和下溢的可能性计算效率接近 float16 的计算性能。4、改进数值稳定性选择数值稳定的激活函数 如使用 Leaky ReLU 或 ELU 代替 ReLU避免梯度为零正则化技巧 如批量归一化Batch Normalization稳定梯度分布梯度裁剪 在反向传播时限制梯度的最大范数防止梯度爆炸。5、调整超参数学习率调整 降低学习率可以减少梯度值的大小防止溢出批量大小的选择 适当减小批量大小降低每次更新的梯度值权值初始化 使用合适的初始化方法如 He 初始化防止前期训练中的数值异常。三、量化Quantization一基本概念量化是机器学习中一种优化技术旨在减少模型的内存占用、计算开销并加速推理过程。其核心思想是将模型中的浮点数参数通常是32位浮点数转化为低精度的数值表示如8位、16位整数等也就是说使用更少的bit来存储原本以浮点数存储的tensor以及使用更少的bit来完成原本以浮点数完成的计算。因此可以减少模型的存储和计算成本同时尽量保持模型的性能。权重量化Weight Quantization将模型的权重weights从32位浮点数转换为较低精度如8位整数。这种方法通常会减少存储和计算负担。激活量化Activation Quantization将模型中的激活值中间计算结果量化为低精度表示进一步减少计算资源。混合量化Mixed Precision Quantization不同的层或参数使用不同的量化精度某些关键层使用较高精度其他层使用较低精度以平衡性能和效率。二量化的实现我们可以直接使用Bitsandbytes库进行量化操作1、8bit量化fromtransformersimportBitsAndBytesConfig quantization_configBitsAndBytesConfig(load_in_8bitTrue,# 启用 8-bit 量化 [−128,127]llm_int8_threshold6.0,# 设置低精度计算的阈值当某个权重的绝对值超过这个阈值时认为它对模型性能的影响较大将其保留为高精度类型。llm_int8_skip_modulesNone# 指定跳过量化的模块可选)modelQwen2VLForConditionalGeneration.from_pretrained(/path/to/qwen_2B_instruct,torch_dtypetorch.bfloat16,device_mapcuda,quantization_configquantization_config,)2、4bit量化quantization_configBitsAndBytesConfig(load_in_4bitTrue,# 启用 4-bit 量化 [-8, 7]bnb_4bit_compute_dtypefloat16,# 计算时的精度:量化主要针对模型的权重存储而实际计算仍然需要浮点数来保持精度。bnb_4bit_use_double_quantTrue,# 双重量化:4-bit 权重的值被先量化为 int8然后再进一步压缩到 4-bit。bnb_4bit_quant_typenf4# 量化类型如 nf4 或标准量化 NF4 使用对数分布或其他非均匀分布来更精确地表示权重值。)四、QLora在量化的模型上插入 LoRA 层微调这些低秩参数。量化后的权重在反向传播时被临时去量化恢复为高精度以确保梯度计算的精度。 显存占用极低支持超大模型。fromtransformersimportAutoModelForCausalLM,BitsAndBytesConfigfrompeftimportLoraConfig,get_peft_model bnb_configBitsAndBytesConfig(load_in_4bitTrue,bnb_4bit_compute_dtypefloat16,bnb_4bit_quant_typenf4,)model_namehuggingface/llama-7bmodelAutoModelForCausalLM.from_pretrained(model_name,quantization_configbnb_config)lora_configLoraConfig(r4,lora_alpha16,target_modules[q_proj,v_proj],lora_dropout0.1,)modelget_peft_model(model,lora_config)五、大语言模型量化方法对比GPTQ、GGUF、AWQGPTQ 通过梯度优化对量化误差进行最小化适用于后训练阶段的精细量化精度较高。GGUF 采用全局统一的量化策略具有简单高效的优点适用于资源受限的部署场景但可能导致某些模型层的精度损失。AWQ 关注激活值的量化通过分析激活值的分布对量化策略进行自适应调整精度更高但计算复杂度较大。一GPTQ: Post-Training Quantization for GPT ModelsGPTQ (Gradient-based Post-training Quantization)是一种基于梯度的后训练量化方法主要目的是在减少浮点计算时尽量保持模型的性能。这种方法对大语言模型的量化尤其有效适用于 8-bit 或更低的量化需求。后训练量化模型已经训练完毕不需要重新训练只需在训练后对权重进行量化。梯度校正在进行量化的过程中GPTQ 通过优化目标函数对量化误差进行最小化。它通过梯度优化调整量化时的权重误差使得量化后模型的表现与未量化模型尽可能接近。误差补偿由于量化不可避免地引入误差GPTQ 采用了误差反馈机制将量化过程中产生的误差传播到后续的层进行补偿从而减少累积误差对模型输出结果的影响。# # 环境安装# pip install transformers accelerate# pip install githttps://github.com/qwopqwop200/GPTQ-for-LLaMa.gitimporttorchfromtransformersimportAutoModelForCausalLM,AutoTokenizerfromgptqimportGPTQ model_namehuggingface/llamatokenizerAutoTokenizer.from_pretrained(model_name)modelAutoModelForCausalLM.from_pretrained(model_name,torch_dtypetorch.float16)# 初始化 GPTQquantizerGPTQ(model)W_BITS8# 设置量化位数比如8-bit量化# 量化模型quantizer.quantize(w_bitsW_BITS,layer_types[self_attn,mlp])quantized_modelquantizer.finish()# 测试模型推理生成文本input_textWhat is the capital of France?inputstokenizer(input_text,return_tensorspt)outputsquantized_model.generate(**inputs,max_new_tokens20)decoded_outputtokenizer.decode(outputs[0],skip_special_tokensTrue)print(decoded_output)二GPT-Generated Unified FormatGPTQ是最常用的压缩方法因为它针对GPU使用进行了优化。但是如果你的GPU无法处理如此大的模型那么从GPTQ开始切换到以cpu为中心的方法(如GGUF)是绝对值得的。GGUF(以前称为GGML)允许用户使用CPU来运行LLM但也可以将其某些层加载到GPU以提高速度。GGUF (Generalized Global Uniform Quantization Framework)是一种通用的全局统一量化框架专门设计用于处理大规模神经网络。全局量化将整个模型中的所有参数统一映射到固定的范围比如使用 8-bit 或 4-bit 表示所有的浮点数。它假设模型的所有层或某一类参数具有相似的分布从而可以使用相同的量化范围。均匀量化所有的数值都被线性地映射到一个均匀的范围。这种方式计算效率高尤其适合硬件加速器。权重重定标由于采用统一量化策略GGUF 通常会引入一个缩放因子用来在推理阶段重定标量化后的数值以避免数值溢出或精度过低的问题。importtorchfromtransformersimportGPT2Tokenizer,GPT2LMHeadModelfromtorch.quantizationimportQuantStub,DeQuantStub,quantize_dynamic model_namegpt2tokenizerGPT2Tokenizer.from_pretrained(model_name)modelGPT2LMHeadModel.from_pretrained(model_name)# 打印原始模型的大小print(fOriginal model size:{model.num_parameters()}parameters)# 模型准备将全局所有层量化使用动态量化quantized_modelquantize_dynamic(model,# 要量化的模型{torch.nn.Linear},# 量化哪些层这里是线性层dtypetorch.qint8# 量化数据类型这里使用 8-bit 量化)# 打印量化后的模型大小print(fQuantized model size:{sum(p.numel()forpinquantized_model.parameters())}parameters)# 测试量化后的模型生成文本input_textOnce upon a timeinputstokenizer(input_text,return_tensorspt)outputsquantized_model.generate(**inputs,max_new_tokens50)generated_texttokenizer.decode(outputs[0],skip_special_tokensTrue)print(Generated text:,generated_text)三AWQ: Activation-aware Weight QuantizationAWQ(激活感知权重量化)是一种类似于GPTQ的量化方法。AWQ和GPTQ作为方法有几个不同之处但最重要的是AWQ假设并非所有权重对LLM的性能都同等重要也就是说在量化过程中会跳过一小部分权重这有助于减轻量化损失。AWQ主要关注激活值在量化过程中考虑了激活值分布对模型性能的影响。这种方法通过分析激活值的分布特性在量化过程中对激活值进行适应性处理从而提高量化后模型的准确性。激活值感知在对权重进行量化的同时AWQ 也会对每一层的激活值分布进行分析。在某些层激活值可能呈现出不均匀或长尾分布导致量化过程中精度下降。AWQ 对这些激活值分布进行感知并自适应调整量化策略。非均匀量化在量化激活值时AWQ 并不采用线性均匀量化而是针对不同的激活值范围选择不同的量化尺度。这样可以更好地捕捉激活值的细节减少量化误差。动态缩放通过动态调整每层的量化缩放因子使得量化后的激活值分布尽量保持和原始模型一致。importtorchfromtransformersimportGPT2Tokenizer,GPT2LMHeadModelfromtorch.quantizationimportQuantStub,DeQuantStub,prepare_qat,convert# 加载 GPT-2 模型和分词器model_namegpt2tokenizerGPT2Tokenizer.from_pretrained(model_name)modelGPT2LMHeadModel.from_pretrained(model_name)# 定义量化模块classQuantizedGPT2(torch.nn.Module):def__init__(self,model):super(QuantizedGPT2,self).__init__()self.quantQuantStub()# 用于激活值的量化self.modelmodel self.dequantDeQuantStub()# 用于激活值的反量化defforward(self,input_ids):# 对输入的激活值进行量化quantized_inputsself.quant(input_ids)outputsself.model(input_idsquantized_inputs)# 对输出进行反量化returnself.dequant(outputs.logits)# 将模型包装在量化模块中quantized_modelQuantizedGPT2(model)# 量化感知训练准备QATquantized_model.qconfigtorch.quantization.get_default_qat_qconfig(fbgemm)# 准备 QATquantized_modelprepare_qat(quantized_model,inplaceTrue)# 模拟训练可以加载现有权重并继续训练input_textWhat is the capital of France?inputstokenizer(input_text,return_tensorspt)[input_ids]quantized_model.train()for_inrange(10):# 模拟训练步骤outputsquantized_model(inputs)losstorch.nn.functional.cross_entropy(outputs.view(-1,outputs.size(-1)),inputs.view(-1))loss.backward()# 完成量化quantized_model.eval()quantized_modelconvert(quantized_model)# 测试量化后的模型withtorch.no_grad():outputsquantized_model(inputs)generated_texttokenizer.decode(outputs[0].argmax(dim-1),skip_special_tokensTrue)print(Generated text:,generated_text)参考https://www.cnblogs.com/lemonzhang/p/17843336.htmlbupt-yiwo/VLLMPytorch模型量化大语言模型量化方法对比GPTQ、GGUF、AWQ【LLM】8大语言模型的量化GPTQ、GGUF、AWQ原理