首页 > 其他分享 >LLM大模型:推理优化-模型int8量化

LLM大模型:推理优化-模型int8量化

时间:2024-08-03 21:18:40浏览次数:7  
标签:一层 模型 矩阵 整数 int8 LLM 量化 浮点数

    前面介绍的推理优化方法都有缺陷:

  • knowledge distillation:需要样本数据训练student,同时要大量算力更新student参数
  • vLLM:通过page attention,减少显存浪费,充分利用碎片化的显存,并未减少算力

  以上两种推理优化的方式都有缺陷,为了弥补上述缺陷,需要新的推理优化方式!

  transformer架构中,不论是embedding,还是FFN,核心都是矩阵乘法,所以这里选个layer看看weight的分布,如下:

         

   很明显的(-1,1)之间的正太分布,而且全是浮点数,除了0就没整数了,这就是weight的现状!面对大量的浮点数,怎么提速计算速度,并且减少显存占用了?既然存的都是浮点数,自然要想办法对浮点数进行优化了!

  • 浮点数存储:fp32需要4byte、fp16需要2byte

  • 浮点数计算:对阶、尾数运算、规格化、舍入处理、溢出判断

  浮点数存储和计算怎么看都觉得”费事“!既然浮点数这么难缠,能不能用整数替代浮点数了?还有,如果不能用整体替代浮点数做运算,也找不到其他合适的数了,现在只能硬着头皮想办法换算成整数了!

  • 整数存储:空间明显比浮点数少,普通整数只需要8bit
  • 整数计算:整数计算直接XOR异或,根本不需要像浮点数那样经历5个阶段,速度快很多

  又该怎么把浮点数映射转换成整数了?浮点数和整数完全是两种不同的数啊!先回顾一下:机器学习很重要的一个步骤就是矩阵乘法,为啥要用矩阵乘法了?用几何解释就是把向量通过矩阵乘法映射到新的空间,这个空间就是矩阵的列向量组成的!在新空间可以根据业务需求进一步做各种操作,最常见的就是分类和回归了!按照这个思路,就需要把浮点数映射到整数这边来计算了!使用整数的初衷是节约显存,所以整数的bit不能过多,否则就没意义了,不如直接使用fp16;所以整数最多只能用8bit,简称int8;int8还要表示正负数,所以整个范围就在-2^7~2^7之间,也就是-127~127之间!最核心的一步就是想办法把浮点数映射到这个范围内了,这类似的功能是不是很熟悉了?以前做传统机器学习,对于输入的特征数据,为了防止过拟合,提升泛化能力,大部分模型都要求做normalization,把输入的每个特征都压缩在某个特定的范围内(一般是-1到1之间),和这里的浮点数转到整数特定范围的应用场景刚好一样啊!

  1、量化方式

   (1)对称量化:找到一组float数据中最大的数,除以127,得到缩放比例scale,然后每个数都除以scale后四舍五入取整(这里是反量化后误差的根因),就得到整数的隐射了;反量化还原就乘以scale即可,举例如下:

        

    用对称量化做矩阵乘法:输入x和权重w都做量化相乘,如下:可以直观感受到原始结果和量化结果之间的误差

        

  (2)对称量化的精度不高,还有提升的需求。使用同样的scale思路,映射到0~255之间了?如下:反量化后误差明显比对称量化小

        

   非对称量化矩阵乘法:量化结果相比对称量化,确实精确一些

        

   2、量化的方式有了,那什么时候量化了?量化本质就是把浮点数映射成整数后做计算,所以只要涉及到浮点数运算的地方都可以量化后再计算,完成后通过反量化还原即可!从量化的环节看,分以下两种方式:

  (1)训练后动态量化:

  • 将训练好的模型权重量化为int8,并保存量化参数,
  • 在模型推理时,对每一层输入的fp32激活值,动态进行进行量化为int8:
  • 在每一层对量化后的int8权重和int8激活值进行计算。
  • 在每一层输出时将结果反量化为fp32。
  • 将fp32激活值传入到下一层。

  流程示意如下:

      

   这种方式有明显缺陷:

  • 每一次推理每一层都要对输入统计量化参数,比较耗时;
  • 每一层计算完都转化为fp32,存入显存,占用显存带宽

 (2)训练后静态量化:针对训练后动态量化的缺陷,改进的思路如下:

  • 每一次推理每一层都要对输入统计量化参数,比较耗时:用有代表性的输入数据跑一遍整个网络,通过统计得到每层大概得量化参数
  • 每一层计算完都转化为fp32,存入显存,占用显存带宽:这一层的输出是下一层的输入,下一层还是要量化,不如在这层直接量化好再传给下一层,计算量是一样的,但是传输的数据量少了很多,节约带宽

    具体操作方法:

  • 将训练好的模型权重量化为int8,并保存量化参数。
  • 校准(calibration): 选一些样本模拟推理,求出每层激活函数各自的scale、zero_point,后续每次推理时输入数据x都用这次得到的scale、zero_point,不用每次都重复计算scale、zero_point了,减少计算量
  • 在每一层对量化后的int8权重和int8激活值进行十算。
  • 在每一层输出时将结果反量化为fp32,同时根据校准产生的激活值量化参数,把激活值量化为int8,把量化参数放入量化后的激活值中;这里先反量化后再次量化,不是多此一举么?
    • 神经网络或者说深度学习有多层,每层处理的语义是不同的,所以每层都要单独量化,不能直接用上一层的量化传递给下一层
    • 每层的量化范围不同,直接把上层int8的结果输出给下一层,可能导致数值范围不匹配
    • 所以每层输出先反量化,让层与层之间统一量纲(以浮点数为准),然后再次量化后传入下一层
  • 将int8的激活值和它的量化参数传入到下一层。

  流程示意如下:

      

   3、huggingface的transformer库中也有可以直接使用量化框架:LLM.int8() 混合精度量化;在不同参数量的模型上,使用不同的量化位数,其准确率如下(原论文:https://arxiv.org/pdf/2208.07339):

       

   参数超过6.7B时,LLM.int8()的准确率和原模型惊人地保持一致,并未降低,这个量化方法到底是怎么做的了?中国人有句古话:林子大了什么样的鸟都有!这话同样适用于LLM:一旦模型参数量达到数十亿级别,参数中就会出现一些离群点,也就是值比较大的维度;这些维度的值较大,应该是模型学到的比较重要的特征维度,俗称Emergent feathers。先看一个例子:原始特征有些权重比较大,经过量化后再反量化时,会让其他部分维度清零,信息严重丢失!如果强行忽略这些维度值较大的特征,其他维度倒是保持不变了,但重要的特征信息也没了,会严重影响下游的任务准确性

  

   现在面临的情况是:值较大的维度去也不是,不去也不是,怎么办?既然放在一起量化和反量化不行,要不然分而治之?把较小值的维度和较大值的维度分开处理试一试?比如下面的矩阵:

       

   左边是weight,明显有outlier feature(原论文设置的阈值>=6),右边是input;按照以前的放在一起、胡子眉毛一把抓的量化思路,权重小的部分维度量化后可能就没了。新的处理方法如下:

  • 从输入的隐含状态中,按列提取异常值 (即大于某个阈值的值)。
  • 对 FP16 离群值矩阵和 Int8 非离群值矩阵分别作矩阵乘法。
  • 反量化非离群值的矩阵乘结果并其与离群值矩阵乘结果相加,获得最终的 FP16 结果。

   上述的weight中,第2列和第4列权重明显大,把这两列单独踢出来;input对应的2、4两行也单独踢出来,组成新矩阵,分别相乘,如下:

      

   weight小的权重才量化,weight大的权重直接浮点数相乘就行了!我个人认为weight大的不用量化:

  • weight大的特征肯定是少数,看看文章开头那张weight分布图呗!
  • weight小的数量多,量化效果明显

   注意:LLM.int8()虽然精度没降低,但因为要把矩阵拆开,分别计算,所以过程比较复杂,推理的效率和原模型比甚至是降低的!

       

  使用的方式也简单,transformer包里面已经集成好了:事先安装好BitsAndBytesConfig就行:

 quantization_config = BitsAndBytesConfig(load_in_8bit=True)
    model = AutoModelForCausalLM.from_pretrained(
        base_model,
        device_map=device,
        trust_remote_code=True,
        quantization_config=quantization_config,
        # torch_dtype=torch.float16
    )

 

   tips:经常做各种LLM的尝试,需要依赖各种第三方包。为了避免包或版本冲突,还是用虚拟环境吧,然后就是一路上各种缺包,各种补齐!

       

 

参考:

1、https://www.bilibili.com/video/BV1EE42157Ms/?spm_id_from=333.337.search-card.all.click&vd_source=241a5bcb1c13e6828e519dd1f78f35b2  大模型部署推理优化

2、https://www.bilibili.com/video/BV1FH4y1c73W/?spm_id_from=333.788.recommend_more_video.4&vd_source=241a5bcb1c13e6828e519dd1f78f35b2  bitsandbytes、GPTQ、GGUF、AWQ

   https://github.com/chunhuizhang/llm_inference_serving/blob/main/tutorials/quantization/qlora_gptq_gguf_awq.ipynb

   https://github.com/chunhuizhang/llm_inference_serving/blob/main/tutorials/quantization/basics.ipynb

3、https://www.cnblogs.com/yilang/p/11277201.html 浮点数计算

4、https://huggingface.co/blog/zh/hf-bitsandbytes-integration  大规模 Transformer 模型 8 比特矩阵乘简介 - 基于 Hugging Face Transformers、Accelerate 以及 bitsandbytes

标签:一层,模型,矩阵,整数,int8,LLM,量化,浮点数
From: https://www.cnblogs.com/theseventhson/p/18339205

相关文章

  • 大模型网信办备案全网最详细说明(附附件)
    本文共分为以下几个章节一、大模型算法备案的强制性二、生成式人工智能(大语言模型)安全评估要点三、大模型备案必备材料+重点说明四、算法备案填报流程五、大模型备案时间成本对比六、备案建议附录、过程性材料一、大模型算法备案的强制性1、强制要求备案(1)《办法》......
  • 灰狼优化算法(GWO)与长短期记忆网络(LSTM)结合的预测模型(GWO-LSTM)及其Python和MATLAB实现
    ####一、背景在现代数据科学和人工智能领域,预测模型的准确性和效率是研究者和工程师不断追求的目标,尤其是在时间序列预测、金融市场分析、气象预测等领域。长短期记忆(LSTM)网络是一种解决传统递归神经网络(RNN)在长序列学习中存在的梯度消失和爆炸问题的有效模型。LSTM能够保持......
  • 灰狼优化算法(GWO)与门控循环单元(GRU)结合的预测模型(GWO-GRU)及其Python和MATLAB实现
    ####一、背景深度学习已成为解决复杂时序数据预测问题的重要工具。在众多神经网络架构中,门控循环单元(GatedRecurrentUnit,GRU)凭借其在捕捉时间序列数据中的长程依赖性和相对较低的计算复杂度而受到广泛关注。此外,优化算法在深度学习模型的训练中扮演着至关重要的角色。灰......
  • LLM场景下常用浮点数介绍
    在计算机中,浮点数的表示基于IEEE754标准,这是最广泛使用的浮点数表示标准。对于一个具体的数值,如10.2345434,它会被分解为符号位、指数位和尾数位。这里以最常见的float32(单精度浮点数)为例来解释这个过程:符号位如果数值是正的,符号位为0;如果数值是负的,符号位为1。对于10.23454......
  • YOLOv8模型:从YAML文件到模型定义(代码逐行解析)
    鱼弦:公众号【红尘灯塔】,CSDN博客专家、内容合伙人、新星导师、全栈领域优质创作者、51CTO(Top红人+专家博主)、github开源爱好者(go-zero源码二次开发、游戏后端架构https://github.com/Peakchen)YOLOv8模型:从YAML文件到模型定义(代码逐行解析)简介YOLOv8是目前最先进的目......
  • LLM场景下常用浮点数介绍
    在计算机中,浮点数的表示基于IEEE754标准,这是最广泛使用的浮点数表示标准。对于一个具体的数值,如10.2345434,它会被分解为符号位、指数位和尾数位。这里以最常见的float32(单精度浮点数)为例来解释这个过程:符号位如果数值是正的,符号位为0;如果数值是负的,符号位为1。对于10.23454......
  • 大语言模型(LLM)工作的3个步骤,一文带你搞清楚!
    生成式AI中常说的token是什么?嵌入(Embeddings)是什么意思?为什么现在的AI具有生成能力?AI是怎么和你进行对话的?为什么都说提示词很重要?为什么同一段提示词,同一个AI模型/工具,多问几次可能得到截然不同的结果?要回答以上这些问题,你需要了解大语言模型(LLM)是如何工作的。知其然,也要......
  • LLM场景下常用浮点数介绍
    在计算机中,浮点数的表示基于IEEE754标准,这是最广泛使用的浮点数表示标准。对于一个具体的数值,如10.2345434,它会被分解为符号位、指数位和尾数位。这里以最常见的float32(单精度浮点数)为例来解释这个过程:符号位如果数值是正的,符号位为0;如果数值是负的,符号位为1。对于10.23454......
  • LLM场景下常用浮点数介绍
    在计算机中,浮点数的表示基于IEEE754标准,这是最广泛使用的浮点数表示标准。对于一个具体的数值,如10.2345434,它会被分解为符号位、指数位和尾数位。这里以最常见的float32(单精度浮点数)为例来解释这个过程:符号位如果数值是正的,符号位为0;如果数值是负的,符号位为1。对于10.23454......
  • LLM场景下常用浮点数介绍
    在计算机中,浮点数的表示基于IEEE754标准,这是最广泛使用的浮点数表示标准。对于一个具体的数值,如10.2345434,它会被分解为符号位、指数位和尾数位。这里以最常见的float32(单精度浮点数)为例来解释这个过程:符号位如果数值是正的,符号位为0;如果数值是负的,符号位为1。对于10.23454......