当前位置: 首页 > news >正文

华为Asend NPU 大模型W8A8量化调优

目前华为显卡上支持的量化方案比较少,只能选取它自己的量化框架msmodelslim进行量化。

1 安装msmodelslim

下载一个vllm-ascend的docker

然后下载msmodelslim的gitee 项目 https://gitee.com/ascend/msit.git

然后开始安装,需要什么pip,就自己离线拷贝进去安装。

我们这里使用的是arrch64的cpu。

easydict==1.13
einops
pydantic>=2.0.3

安装好了以后。开始量化校准。

"""
1、导入相关依赖
"""
import os
import json
import torch
import torch_npu # 如果需要使用npu进行量化
from transformers import AutoTokenizer, AutoModelForCausalLM
from msmodelslim.pytorch.llm_ptq.anti_outlier import AntiOutlierConfig, AntiOutlier
from msmodelslim.pytorch.llm_ptq.llm_ptq_tools import Calibrator, QuantConfig
from precision_tool.precision_tool import PrecisionTest # precision_tool用于伪量化测精度SEQ_LEN_OUT = 100
device_id = 4
batch_size = 5# 如果使用npu进行量化需开启二进制编译,避免在线编译算子
torch.npu.set_compile_mode(jit_compile=False)
option = {}
option["NPU_FUZZY_COMPILE_BLACKLIST"] = "ReduceProd"
torch.npu.set_option(option)"""
2、导入相关模型
"""
fp16_path = '/data/chatglm2-6b' # 原始浮点模型路径tokenizer = AutoTokenizer.from_pretrained(pretrained_model_name_or_path=fp16_path,local_files_only=True
)model = AutoModelForCausalLM.from_pretrained(pretrained_model_name_or_path=fp16_path,local_files_only=True,device_map="auto",torch_dtype="auto"
).eval()"""
数据集测原始模型浮点精度(此示例中选择的是boolq)
"""
precision_test = PrecisionTest(model, tokenizer, "boolq", batch_size, "npu")
precision_test.test()"""
3、获取校准数据
"""
# 一般数据都在cpu上,用npu进行量化的时候都需要指定数据到npu设备上
def build_prompt(title, text, passage):prompt = f"{title} -- {passage}\nQuestion:{text}?\nAnswer:"return promptdef get_calib_dataset(tokenizer, calib_list, device=f"npu:{device_id}"):calib_dataset = []for calib_data in calib_list:title = calib_data["title"]text = calib_data["question"]passage = calib_data["passage"]queries = build_prompt(title, text, passage)inputs = tokenizer(queries, return_tensors='pt')calib_dataset.append([inputs.data['input_ids'].to(device), inputs.data['attention_mask'].to(device)])     return calib_datasetentry = "/path/to/calib_dataset" # 此示例中校准数据选取"precision_tool/dataset/boolq/dev.jsonl"
calib_set = []
i = 0
with open(entry, encoding="utf-8") as file:for line in file:data =json.loads(line) # 将字符串转换为字典while i < 50: # 获取50条校准数据calib_set.append(data)i += 1dataset_calib = get_calib_dataset(tokenizer, calib_set)"""
4、离群值抑制AntiOutlier(W8A8)
"""
anti_config = AntiOutlierConfig(anti_method="m2", dev_type="npu", dev_id=device_id)
anti_outlier = AntiOutlier(model, calib_data=dataset_calib, cfg=anti_config)
anti_outlier.process()"""
5、回退层设置
"""
"""
因为一些量化后的网络层对精度影响太大了,所以需要让这些网络层使用浮点权重进行计算, disable_names中为需要进行回退的网络层。
"""
disable_names = []"""
6、执行PTQ量化校准 + 存储量化参数用于部署
"""
quant_config = QuantConfig(a_bit=8,w_bit=8,disable_names=disable_names,dev_type='npu',dev_id=device_id,act_method=3,pr=1.0,w_sym=True,mm_tensor=False
)calibrator = Calibrator(model, quant_config, calib_data=dataset_calib, disable_level='L0')  # disable_level: 自动回退n个linear
calibrator.run()  # 执行PTQ量化校准
calibrator.save('/save/path', save_type=["safe_tensor", "numpy"]) # "safe_tensor"对应safetensors格式权重,"numpy"对应npy格式权重"""
数据集测伪量化模型精度(此示例中选择的是boolq)
"""
precision_test = PrecisionTest(model, tokenizer, "boolq", batch_size, "npu")
precision_test.test()"""
7、伪量化验证一轮推理(可选)
"""
print("testing quantized weights...")
test_prompt = "Common sense questions and answers\n\nQuestion: How to learn a new language\nFactual answer:"
test_input = tokenizer(test_prompt, return_tensors="pt")
print("model is inferring...")
model = model.to(f"npu:{device_id}")
model.eval()
generate_ids = model.generate(test_input.input_ids.to(f"npu:{device_id}"), attention_mask=test_input.attention_mask.to(f"npu:{device_id}"), max_new_tokens=SEQ_LEN_OUT
)res = tokenizer.batch_decode(generate_ids, skip_special_tokens=True, clean_up_tokenization_spaces=False
)
for idx, item in enumerate(res):print(item)

在调用Calibrator.run()方法后,构建Calibrator时传入的model会被替换为伪量化模型,可以直接调用进行前向推理,用来测试对话效果。
如果伪量化结果不理想,可以参考以下方法进行调优:

主要有下面四个方法。

1.离群值抑制(AntiOutlier)

可优化参数——anti_method

m1:SmoothQuant算法
m2:SmoothQuant升级版
m3:AWQ算法(适用于W8A16/W4A16)
m4:SmoothQuant优化算法
m5:CBQ算法
m6:Flex smooth量化算法

w8a8适用m1、m2、m4、m5、m6 建议从m1尝试到m6,因为不同模型对不同离群抑制算法表现不一样,当前m2已适配qwen-vl和llava-v1.5-7b多模态模型

anti_config = AntiOutlierConfig(anti_method="m2",dev_type="npu",dev_id=device_id
)

2 量化参数选择

可优化参数——disable_names、disable_level、act_method
【增加回退层(建议最后进行调整),可以按照一定经验,通过disable_names手动设置回退层,或使用disable_level自动回退功能按照一定的标准自动回退对精度影响比较大的Linear层】

disable_names: 手动指定回退层(根据理论经验和日志信息) disable_level='L0': 自动回退

act_method:激活值量化方法
act_method默认值为1,该参数可选1、2、3
1代表min-max量化方式;
2代表histogram量化方式;
3.代表min-max和histogram混合的量化的方式。
LLM大模型场景下建议使用3

quant_config = QuantConfig(a_bit=8,w_bit=8,disable_names=disable_names,dev_type='npu',dev_id=device_id,act_method=3,pr=1.0,w_sym=True,mm_tensor=False
)calibrator = Calibrator(model, quant_config, calib_data=dataset_calib, disable_level='L0'
)  

3 校准集调整

可以使用官方数据集,也可以使用自己的数据集,针对自己的场景进行专门的量化调优。

数据集格式:

然后读取数据:

def get_calib_dataset(tokenizer, calib_list, device=f"npu:{device_id}"):calib_dataset = []for calib_data in calib_list:title = calib_data["title"]text = calib_data["question"] passage = calib_data["passage"]queries = build_prompt(title, text, passage)inputs = tokenizer(queries, return_tensors='pt')calib_dataset.append([inputs.data['input_ids'].to(device), inputs.data['attention_mask'].to(device)])       return calib_dataset

4 量化回退

大模型需要量化的原因:模型量化可以降低模型大小,减少计算量,降低内存占用,提升推理速度。

大模型量化线性层的原因:大模型中的线性层层数多、权重数量庞大且存在矩阵相乘(计算量大),通过量化线性层的权重和激活值,可以达到降低模型大小,减少计算量,降低内存占用,提升推理速度。

量化回退的原因:某些线性层对于量化比较敏感,量化后会带来一定的精度损失,这些层是不太适合量化的,应该使用浮点数进行计算,这个过程称之为回退,可以通过设置disable_names控制哪些线性层应该被回退。

怎么判定敏感:终端的打印日志中会显示每一层算子激活量化输入的range_parm数值,range_parm数值越大越敏感。
终端打印日志示例:

时间戳 - msmodelslim-logger - INFO - use histogram observer:transformer.encoder.layers.27.mlp.dense_h_to_4h.quant_input, range_parm:41.21875

此示例中的 range_parm:41.21875 数值就很大(和日志中其他层的range_parm相比),说明该层敏感,需要回退。

量化回退的方法:分为手动回退和自动回退两个方法(可叠加使用),建议先手动回退,如果不清楚该回退哪些模型层或者手动回退精度不好的话,再自动回退。

注:量化回退会造成一定的性能损失。

手动回退——disable_names

disable_names=[]: []手动回退层名称,如果不添加则不回退

按以下顺序进行回退:
1、回退down_proj层(精度敏感):mlp的采样层,(如果没有标识出down_proj就看out_features, 数值小的就是下采样层)。
2、回退o_proj层(通常精度敏感):是self_attention中调的最后一个线性层,(model中打出来的只是初始化时的顺序,要去模型代码里看实际调用顺序) 。
3、根据理论经验或终端打印日志中的range_parm数值大小找出量化敏感层进行回退。

如下示例为手动回退chatglm2-6b的所有down_proj层:

disable_names=['transformer.encoder.layers.0.mlp.dense_4h_to_h','transformer.encoder.layers.1.mlp.dense_4h_to_h','transformer.encoder.layers.2.mlp.dense_4h_to_h','transformer.encoder.layers.3.mlp.dense_4h_to_h','transformer.encoder.layers.4.mlp.dense_4h_to_h','transformer.encoder.layers.5.mlp.dense_4h_to_h','transformer.encoder.layers.6.mlp.dense_4h_to_h','transformer.encoder.layers.7.mlp.dense_4h_to_h','transformer.encoder.layers.8.mlp.dense_4h_to_h','transformer.encoder.layers.9.mlp.dense_4h_to_h','transformer.encoder.layers.10.mlp.dense_4h_to_h','transformer.encoder.layers.11.mlp.dense_4h_to_h','transformer.encoder.layers.12.mlp.dense_4h_to_h','transformer.encoder.layers.13.mlp.dense_4h_to_h','transformer.encoder.layers.14.mlp.dense_4h_to_h','transformer.encoder.layers.15.mlp.dense_4h_to_h','transformer.encoder.layers.16.mlp.dense_4h_to_h','transformer.encoder.layers.17.mlp.dense_4h_to_h','transformer.encoder.layers.18.mlp.dense_4h_to_h','transformer.encoder.layers.19.mlp.dense_4h_to_h','transformer.encoder.layers.20.mlp.dense_4h_to_h','transformer.encoder.layers.21.mlp.dense_4h_to_h','transformer.encoder.layers.22.mlp.dense_4h_to_h','transformer.encoder.layers.23.mlp.dense_4h_to_h','transformer.encoder.layers.24.mlp.dense_4h_to_h','transformer.encoder.layers.25.mlp.dense_4h_to_h','transformer.encoder.layers.26.mlp.dense_4h_to_h','transformer.encoder.layers.27.mlp.dense_4h_to_h',
]

自动回退——disable_level

自动回退会根据range_parm参数由大到小排序回退对精度影响比较大的Linear层。 设置disable_level='Lx',x为自动回退的linear层数量,会在终端显示回退的层名称,diable_level='L0'即为不进行回退,x设置的数量超过模型层数就是全部回退,并且也不报错。

5 KV Cache int8量化

可在QuantConfig后调用kv_quant函数来开启KV Cache int8量化。

quant_config = QuantConfig(a_bit=8,w_bit=8,disable_names=disable_names,dev_type='npu',dev_id=device_id
).kv_quant()

长序列场景下KV Cache占用显存空间较大,通过KV Cache量化可以节约显存占用,增加并发数。
调用kv_quant函数会自动将QuantConfig中use_kvcache_quant设置为True。
use_kvcache_quant=True启用KV Cache量化,支持与W8A8、W8A16和稀疏量化同时使用。

以下是量化chatglm-6b,每个操作的精度损失情况,可以作为参考。

步骤参数更改描述精度
原浮点模型精度0.794
添加QuantConfig量化参数disable_names = [] ,act_method = 3, disable_level = "L0", dataset_calib 数据量为2条0.519
添加离群值抑制anti_method = "m2"0.497
增加boolq校准数据从2条增加到50条0.505
增加量化回退(手动回退)手动回退所有layer中的mlp.down_proj0.793
增加量化回退(自动回退)disable_names = [],设置 disable_level = "L28"0.791
增加量化回退(手动回退+自动回退)disable_names手动回退10层,disable_level = "L28"0.795

模型量化后,可基于MindIE、vLLM等进行部署推理。

http://www.dtcms.com/a/487608.html

相关文章:

  • C#拆箱/装箱(性能优化)
  • 深圳市做网站建设wordpress 获取子分类
  • 网站推广排名平台做网站常州
  • 企业配电柜里的“防火卫士”——ATE800无线测温传感器,让设备更安全!
  • 如何使用云手机进行游戏挂机?
  • 网站自适应手机代码百度网盘资源搜索引擎搜索
  • 做网站的手机软件河北住房和城乡建设厅网站卡
  • 设计模式(解释器模式(Interpreter Pattern)结构|原理|优缺点|场景|示例
  • 我的家乡网站设计模板中国网站备案信息查询
  • 站酷设计网站官网入口文字设计企业为什么需要手机网站
  • `ztask` 轻量级合作式任务调度器
  • Segment Anything(SAM)
  • string 1 easy
  • 全球著名科技网站手机自助建站系统
  • LRU Cache 最近最少使用
  • h5游戏免费下载:跳一跳
  • 用asp做网站深圳市点击未来科技网站建设
  • EtherCAT转EtherNet/IP工业模块:数据网关实现电子制造业协议转换
  • 傻瓜式建网站泰兴市建设局网站
  • 制作一个网站做网站做哪个
  • SkipList跳表
  • BEVFUSION解读(八)
  • 网站的icp备案怎么在百度做网站
  • SAP MM 自制=>外协加工
  • Spring Boot临时解决循环依赖注入问题
  • 数字身份安全在重点行业的应用与机遇:现状复盘、需求洞察与趋势展望
  • 网站三元素怎么做网站流量建设
  • wordpress单本小说站wordpress如何做页面模板下载
  • seo在网站建设中的作用网站开发怎么使用维语
  • 个人创业:如何找到适合自己且值得投入的小项目?