在这里插入图片描述

一、背景介绍

ModeSlim 是什么?

ModeSlim 是昇腾提供的模型量化压缩工具。

ModeSlim 能做什么?

它可以对深度学习模型进行轻量化处理,核心目标是在保证模型性能(如精度)基本不受显著影响的前提下,减小模型体积、降低计算复杂度,从而提升模型的部署效率和运行速度,尤其适用于资源受限的场景。

官方仓库地址:GitCode - 全球开发者的开源社区,开源代码托管平台

二、依赖环境

硬件要求 Atlas 800I A2/ Atlas 800T A2、Atlas 300I Duo 推理卡
OS版本 openEuler 22.03 LTS
Python版本 python3.10/python3.11
CANN版本 8.2.RC2

基础配套镜像:昇腾镜像仓库详情

三、具体步骤

开启二进制编译(可选)

如果使用的是 npu 进行量化,可以选择开启二进制编译,从而避免在线编译算子

torch.npu.set_compile_mode(jit_compile=False)
option = {}
option["NPU_FUZZY_COMPILE_BLACKLIST"] = "ReduceProd"
torch.npu.set_option(option)

模型加载

将模型加载到 npu 上:

model_path = '/data/Qwen2.5-72B-Instruct/'

model = AutoModelForCausalLM.from_pretrained(
        pretrained_model_name_or_path=model_path,
        torch_dtype=torch.bfloat16,
        trust_remote_code=True,
        device_map="auto",
        max_memory={0:"0GiB",1:"0GiB",2:"0GiB",3:"0GiB",4:"25GiB",5:"25GiB",6:"25GiB",7:"25GiB"}
    ).eval()

获取校准数据

校准数据建议选取业务数据中,场景比较普适的子数据集。 例如对于ceval场景,选择teacher_qualification.jsonl。 对于中英文混合场景需要均衡输入中英文数据,对于代码生成类模型需要输入代码生成任务。 输入数量建议为10条-50条。

def get_calib_dataset(tokenizer, calib_list, device=model.device):
    calib_dataset = []
    for calib_data in calib_list:
        inputs = tokenizer(calib_data, return_tensors='pt')
        calib_dataset.append([
            inputs.data['input_ids'].to(device),
            inputs.data['attention_mask'].to(device)
        ])
    return calib_dataset

# boolq数据集
entry = "/dataset/boolq_lite/dev3.jsonl"
with open(entry, 'r') as file:
    calib_set = json.load(file)
dataset_calib = get_calib_dataset(tokenizer, calib_set)

离群值抑制AntiOutlier设置

对于部分模型,单独的W8A8量化精度表现效果可能较差,可能需要在调用量化之前调用AntiOutlier模块进行异常值抑制,通过抑制量化过程中的异常值,使能后续更好的量化。

  • m1:SmoothQuant算法
  • m2:SmoothQuant升级版
  • m3:AWQ算法(适用于W8A16/W4A16)
  • m4:SmoothQuant优化算法
  • m5:CBQ算法
  • m6:Flex smooth量化算法
anti_config = AntiOutlierConfig(anti_method="m3", dev_type="npu", dev_id=model.device.index)
anti_outlier = AntiOutlier(model, calib_data=dataset_calib, cfg=anti_config)
anti_outlier.process()

配置量化参数

quant_config = QuantConfig(
    a_bit=8,
    w_bit=8,
    disable_names=disable_names,
    dev_type='npu',
    dev_id=model.device.index,
    act_method=1,
    pr=1.0,
    w_sym=True,
    mm_tensor=False
).fa_quant(fa_amp=0)
  • disatble_names:回退层
  • arc_method:激活值量化方法
    • 1 代表 min-max 量化方式
    • 2 代表 histogram 量化方式
    • 3 代表 min-max 和 histogram 的混合量化方式

执行并保存

alibrator = Calibrator(model, quant_config, calib_data=dataset_calib, disable_level='L0')
calibrator.run()
calibrator.save('/data/qwen2.5-72-w8a8', save_type=["safe_tensor"])

四、qwen2.5-72B w8a8 fa3量化代码样例

import json
import torch
import torch_npu
from transformers import AutoTokenizer, AutoModelForCausalLM
from modelslim.pytorch.llm_ptq.anti_outlier import AntiOutlierConfig, AntiOutlier
from modelslim.pytorch.llm_ptq.llm_ptq_tools import Calibrator, QuantConfig
import jsonlines
SEQ_LEN_OUT = 100
batch_size = 1

# 如果使用npu进行量化需开启二进制编译,避免在线编译算子
torch.npu.set_compile_mode(jit_compile=False)
option = {}
option["NPU_FUZZY_COMPILE_BLACKLIST"] = "ReduceProd"
torch.npu.set_option(option)

"""
原始模型加载
"""
model_path = '/data/Qwen2.5-72B-Instruct/'
model = AutoModelForCausalLM.from_pretrained(
    pretrained_model_name_or_path=model_path,
    torch_dtype=torch.bfloat16,
    trust_remote_code=True,
    device_map="auto",
    max_memory={0:"0GiB",1:"0GiB",2:"25GiB",3:"25GiB",4:"25GiB",5:"25GiB",6:"25GiB",7:"25GiB"}
).eval()
tokenizer = AutoTokenizer.from_pretrained(
    pretrained_model_name_or_path=model_path,
    trust_remote_code=True,
    device_map="auto",
)
tokenizer.pad_token = tokenizer.eos_token

"""
获取校准数据
"""
def get_calib_dataset(tokenizer, calib_list, device=model.device):
    calib_dataset = []
    for calib_data in calib_list:
        inputs = tokenizer(calib_data, return_tensors='pt')
        calib_dataset.append([
            inputs.data['input_ids'].to(device),
            inputs.data['attention_mask'].to(device)
        ])
    return calib_dataset

entry = "/dataset/boolq_lite/dev3.jsonl"
with open(entry, 'r') as file:
    calib_set = json.load(file)
dataset_calib = get_calib_dataset(tokenizer, calib_set)

"""
回退层设置
"""
disable_names = []
num_layers = 80
disable_idx_lst = list(range(num_layers))
for layer_index in disable_idx_lst:
    down_proj_name = "model.layers.{}.mlp.down_proj".format(layer_index)
    disable_names.append(down_proj_name)

"""
AntiOutlier:本模型无需设置离群抑制值精度即可达标
"""

"""
配置量化参数
"""
quant_config = QuantConfig(
    a_bit=8,
    w_bit=8,
    disable_names=disable_names,
    dev_type='npu',
    dev_id=model.device.index,
    act_method=1,
    pr=1.0,
    w_sym=True,
    mm_tensor=False
).fa_quant(fa_amp=0)

calibrator = Calibrator(model, quant_config, calib_data=dataset_calib, disable_level='L0') #disable_level设置为L0精度即可达标
calibrator.run()
calibrator.save('/data/qwen25-72-w8a8', save_type=["safe_tensor"])

五、常见问题

报错卡异常模型无法加载

max_memory={0:“0GiB”,1:“0GiB”,2:“25GiB”,3:“25GiB”,4:“25GiB”,5:“25GiB”,6:“25GiB”,7:“25GiB”}

800I A2,32G qwen2.5-72B量化最少使用六卡,使用四卡时报错如下图

注明:昇腾PAE案例库对本文写作亦有帮助。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐