1. 环境准备从零开始的昇腾量化工作站大家好我是昇腾实战派。最近在项目里折腾GLM4.5和GLM4.6的昇腾部署特别是w8a8量化这块踩了不少坑也积累了一些实战经验。今天这篇指南就是想把我从源码适配到最终权重导出的完整流程手把手地分享给你。如果你也正头疼如何在昇腾910B上高效运行这些大模型希望这篇“保姆级”教程能帮你省下几天甚至几周的摸索时间。咱们的目标很明确把智谱开源的GLM4.5/4.6浮点模型通过权重量化w8a8技术转换成能在昇腾NPU上高效推理的格式。整个过程涉及环境搭建、源码修改、量化脚本编写和权重后处理我会尽量把每一步的原理和操作细节都讲清楚确保你能跟着做出来。先说说硬件和软件的基础环境这是所有工作的起点环境不对后面全是白费功夫。1.1 获取模型与确认版本配套首先你得有模型。智谱的GLM-4.5和GLM-4.6模型权重在ModelScope上可以直接下载。我建议你直接使用modelscope库的snapshot_download功能这比手动下载再解压要方便可靠得多。打开你的终端创建一个专门的工作目录然后执行下面的命令来获取模型。这里以GLM-4.5为例GLM-4.6的操作完全一样只是模型名称不同。# 安装modelscope库如果还没装的话 pip install modelscope # 在工作目录下下载GLM-4.5模型 from modelscope import snapshot_download model_dir snapshot_download(ZhipuAI/GLM-4.5, cache_dir./model_weights) print(f模型已下载至: {model_dir})下载完成后你会得到一个包含config.json,model.safetensors等文件的文件夹。记下这个路径我们后面会反复用到它作为--model_path。接下来是版本配套这是最容易出问题的地方。根据我的实测以下组合是经过验证可以稳定工作的硬件昇腾910B AI处理器我是在8卡服务器上操作的单卡流程也类似。CANN版本8.2.RC1。这是核心版本不匹配会导致后续工具链无法正常工作。msmodelslim版本我们需要使用一个特定的提交版本其哈希值为803a9b266。这是华为提供的模型量化与压缩工具套件我们后续的适配和量化都基于它。Python库重点注意transformers库的版本。经过测试4.54.0版本与当前工具链兼容性最好版本过高或过低都可能引发意想不到的错误。1.2 配置Docker容器环境为了环境纯净和可复现强烈建议在Docker容器中进行所有操作。华为官方提供了预集成CANN的镜像。我们需要使用包含CANN 8.2.RC1的镜像。你可以从指定的镜像仓库拉取例如quay.io上的v0.10.2rc1A2版本。拉取并运行容器的命令如下docker run -it -d --nethost --shm-size1g \ --privileged \ --name glm4_5_quant \ --device/dev/davinci_manager \ --device/dev/hisi_hdc \ --device/dev/devmm_svm \ -v /usr/local/Ascend/driver:/usr/local/Ascend/driver:ro \ -v /usr/local/sbin:/usr/local/sbin:ro \ -v /home:/home \ quay.io/your-repo/ascend-toolkit:8.2.RC1-a2 \ bash运行后使用docker exec -it glm4_5_quant bash进入容器。进入后第一件事就是确认CANN版本是否正确安装cat /usr/local/Ascend/ascend-toolkit/latest/compiler/version.info。看到版本号是8.2.RC1就可以进行下一步了。1.3 安装必要的Python依赖在容器内我们需要安装一系列Python第三方库。这里我列出了一个经过验证的依赖列表直接复制粘贴运行即可。注意protobuf的版本有些新版本可能不兼容。pip3 install attrs cython numpy1.19.2,1.24.0 decorator sympy cffi pyyaml pathlib2 psutil protobuf3.20.0 scipy requests absl-py接着安装指定版本的transformerspip install transformers4.54.01.4 获取并安装msmodelslim这是我们的核心工具。我们需要从Gitee上克隆代码并切换到我们需要的那个特定提交。git clone https://gitee.com/ascend/msit.git cd msit git checkout 803a9b266 cd msmodelslim bash install.shinstall.sh脚本会自动完成msmodelslim包的编译和安装。安装成功后你可以尝试在Python中import msmodelslim如果没有报错说明工具包就绪了。至此一个为GLM4模型量化准备好的基础环境就搭建完成了。环境搭建就像盖房子的地基虽然繁琐但一步都不能错。接下来我们就要进入最核心的部分——修改源码来适配我们的模型。2. 源码适配让工具认识GLM4模型现在环境准备好了模型也下载了但直接跑量化肯定会失败。因为msmodelslim这个量化工具最初并没有内置对GLM4.5/4.6 MoE模型的支持。我们需要“教”它认识这个新模型。这个过程类似于为工具添加一个新的“驱动程序”。别担心我们不需要从零开始写可以借鉴工具里已经实现的其他模型比如Qwen3的代码结构。2.1 创建模型适配器文件首先我们需要在msmodelslim的代码目录里创建一个新的适配器模块。关键路径是msit/msmodelslim/msmodelslim/pytorch/llm_ptq/model/。在这个目录下我们新建一个名为glm4moe的文件夹。cd msit/msmodelslim/msmodelslim/pytorch/llm_ptq/model/ mkdir glm4moe cd glm4moe然后在这个文件夹里创建两个文件__init__.py和glm4moe.py。__init__.py文件很简单它的作用就是把这个文件夹变成一个Python包并暴露我们主要的适配器类。# __init__.py 文件内容 # -*- coding: utf-8 -*- # Copyright (c) 2025-2025 Huawei Technologies Co., Ltd. # Licensed under the Apache License, Version 2.0 (the License); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an AS IS BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. __all__ [Glm4moeAdapter] from .glm4moe import Glm4moeAdapter接下来是重头戏glm4moe.py。这个文件定义了Glm4moeAdapter类它告诉量化工具GLM4模型的结构是什么样的比如哪些是注意力层哪些是前馈网络层以及如何进行特定的量化参数调整。我直接把调试好的代码贴出来并加上关键注释。# glm4moe.py 文件内容 # Copyright Huawei Technologies Co., Ltd. 2025-2025. All rights reserved. from typing import List, Any, Dict, Optional, Type, TYPE_CHECKING import torch import torch.nn as nn from transformers import PreTrainedModel from msmodelslim.pytorch.llm_ptq.model.base import ModelAdapter, ModelAdapterRegistry if TYPE_CHECKING: from msmodelslim.pytorch.llm_ptq.anti_outlier.config import AntiOutlierConfig ModelAdapterRegistry.register(glm4_moe) ModelAdapterRegistry.register(glm4moe) class Glm4moeAdapter(ModelAdapter): def __init__(self, model: PreTrainedModel): super().__init__(model) # 判断是否是MoE模型GLM4.5/4.6都是MoE架构 self.is_moe moe in self.model.config.model_type # 初始化注意力头数这对后续的M4量化方法很重要 self.num_attention_heads, self.num_key_value_heads self._init_num_attention_heads() def get_norm_linear_subgraph(self, cfg: AntiOutlierConfig, dummy_input: Optional[torch.Tensor] None, norm_class: Optional[List[Type[nn.Module]]] None): 这个方法定义了模型中Norm层和Linear层的连接关系是量化工具进行层间融合和优化的依据。 norm_linear {} layer_num self.model.config.num_hidden_layers # 校验一下层数防止配置错误 if layer_num 1 or layer_num 999: raise ValueError(fThe number of hidden layers({layer_num}) is invalid. It must be between 1 and 999.) for layer in range(layer_num): # 定义每一层中输入LayerNorm到Q/K/V投影层的映射 input_layernorm model.layers. str(layer) .input_layernorm q_proj model.layers. str(layer) .self_attn.q_proj k_proj model.layers. str(layer) .self_attn.k_proj v_proj model.layers. str(layer) .self_attn.v_proj o_proj model.layers. str(layer) .self_attn.o_proj norm_linear[v_proj] [o_proj] norm_linear[input_layernorm] [q_proj, k_proj, v_proj] # 如果不是MoE模型这里我们是但代码保持通用性定义后注意力LayerNorm到门控/上投影层的映射 if not self.is_moe: post_layernorm model.layers. str(layer) .post_attention_layernorm gate_proj model.layers. str(layer) .mlp.gate_proj up_proj model.layers. str(layer) .mlp.up_proj down_proj model.layers. str(layer) .mlp.down_proj norm_linear[up_proj] [down_proj] norm_linear[post_layernorm] [gate_proj, up_proj] return norm_linear def modify_smooth_args(self, cfg: AntiOutlierConfig, norm_name: str, linear_names: str, args: List[Any], kwargs: Dict[str, Any]): 这个方法用于在应用M4反异常值量化方法时调整特定层的参数。 # 针对该模型进行m4量化时需要对特定层开启偏移 if cfg.anti_method m4: is_shift False if norm in norm_name: is_shift True kwargs[is_shift] is_shift kwargs[alpha] cfg.alpha # 针对GLM4模型需要传递正确的注意力头数参数 if cfg.anti_method m4 and num_attention_heads in kwargs: kwargs[num_attention_heads] [self.num_attention_heads, self.num_key_value_heads] return args, kwargs def _init_num_attention_heads(self): 从模型配置中安全地提取注意力头数和键值头数。 num_attention_heads None num_key_value_heads None attention_heads_keys [num_attention_heads, n_head, num_heads] key_value_heads_keys [num_key_value_heads] for key in attention_heads_keys: if hasattr(self.model.config, key): num_attention_heads getattr(self.model.config, key) for key in key_value_heads_keys: if hasattr(self.model.config, key): num_key_value_heads getattr(self.model.config, key) if not num_attention_heads: raise ValueError( fthe config of model must have num_attention_heads, n_head or num_heads, \ please check or modify the config file ) return num_attention_heads, num_key_value_heads2.2 注册适配器并重装工具创建好适配器文件后我们需要告诉msmodelslim工具这个新适配器的存在。修改上一级目录的__init__.py文件路径msit/msmodelslim/msmodelslim/pytorch/llm_ptq/model/__init__.py把我们新建的Glm4moeAdapter加进去。# 修改后的 __init__.py 文件内容 __all__ [ModelAdapter, ModelAdapterRegistry] from .base import ModelAdapter, ModelAdapterRegistry from .deepseek_v2 import DeepseekV2Adapter from .hunyuan import HunyuanLargeAdapter, HunyuanVideoAdapter from .qwen3 import Qwen3Adapter from .flux import FluxAdapter # 添加下面这行导入 from .glm4moe import Glm4moeAdapter最后为了让修改生效我们需要重新安装msmodelslim。回到msmodelslim的根目录再次运行安装脚本。cd /path/to/msit/msmodelslim bash install.sh这一步完成后量化工具就已经“认识”GLM4 MoE模型了。你可以写个简单的测试脚本尝试导入这个适配器看看是否报错。源码适配是打通流程的关键一步很多量化失败的问题都源于适配器写得不正确。接下来我们就可以着手编写量化脚本了。3. 量化脚本编写与执行适配器搞定后量化本身反而像是个“标准流程”了。不过针对GLM4.5/4.6这种MoE大模型我们需要制定一个特别的量化策略并处理一个常见的“坑”。3.1 量化策略制定GLM4.5/4.6是混合专家模型它的前馈网络层MLP是MoE结构。对于MoE层我们采用动态量化。这是因为MoE层的激活值分布动态范围可能较大静态量化容易丢失信息。而对于模型的其他部分如注意力层、归一化层等我们采用更高效、推理速度更快的静态量化。同时为了最大限度保证精度我们通常会将模型最开始的几层例如第0、1、2层的down_proj和o_proj层回退到浮点精度即不量化因为模型底层对输入特征的提取非常关键量化带来的误差可能会被高层放大。3.2 编写量化执行脚本我们需要在msmodelslim的示例目录下创建一个新的Python脚本。我参考了Qwen3-MOE的示例创建了glm4_moe_w8a8.py。这个脚本内容较长但逻辑清晰加载模型 - 准备校准数据 - 配置量化参数 - 执行量化 - 保存结果。我把核心部分和关键参数解释一下。首先脚本开头需要设置好路径和导入必要的模块。注意因为昇腾NPU的环境我们需要导入torch_npu并进行初始化。# glm4_moe_w8a8.py 头部 import os import sys import argparse import functools import json from unittest.mock import patch import torch import torch_npu from torch_npu.contrib import transfer_to_npu # 添加msmodelslim路径到系统路径 current_directory os.path.dirname(os.path.abspath(__file__)) parent_directory os.path.abspath(os.path.join(current_directory, .., ..)) sys.path.append(parent_directory) from example.common.security.path import get_valid_read_path, get_write_directory from example.common.security.type import check_number from example.common.utils import SafeGenerator, cmd_bool from msmodelslim.tools.copy_config_files import copy_config_files, modify_config_json from msmodelslim.pytorch.llm_ptq.anti_outlier import AntiOutlierConfig, AntiOutlier from msmodelslim.pytorch.llm_ptq.llm_ptq_tools import Calibrator, QuantConfig from msmodelslim.tools.logger import set_logger_level然后定义参数解析和主函数。主函数里我们依次完成加载模型和分词器这里使用了SafeGenerator来安全加载并指定了device_map将大部分层放在CPU上只把嵌入层和输出层放在NPU上这是为了节省显存因为量化过程本身是在CPU上进行的。准备校准数据集量化需要一小部分数据比如50-100条文本来统计激活值的分布。你需要准备两个json文件anti_prompt_50.json用于反异常值处理和calib_prompt_50.json用于标准校准。文件内容就是字符串列表例如[请介绍人工智能, 今天的天气怎么样, ...]。配置反异常值使用AntiOutlier处理激活值中的极端值这对提升w8a8量化精度至关重要这里选择了m4方法。配置量化参数创建QuantConfig对象设置权重和激活都是8比特w8a8指定需要回退不量化的层disable_names并设置MoE层使用动态量化mix_cfg。执行校准与保存运行Calibrator完成量化最后将量化后的权重和配置文件保存到指定目录。脚本中一个关键函数是custom_hook它会在保存配置时被调用确保生成的config.json里有一个quantize: w8a8_dynamic的字段这是昇腾推理引擎识别量化模型的标志之一。3.3 修复Transformers源码的一个坑直接运行上面的量化脚本你很可能会遇到一个错误提示缺少e_score_correction_bias这个参数。这是因为GLM4 MoE模型的transformers实现中Glm4MoeTopkRouter类在初始化时缺少了这个参数的定义但在加载某些权重时又会去寻找它。解决方法很简单找到你环境中transformers库的安装位置修改对应的模型文件。首先用pip show transformers找到库路径然后编辑modeling_glm4_moe.py文件。# 查找transformers安装路径 pip show transformers | grep Location # 假设路径是 /usr/local/lib/python3.8/site-packages # 找到并编辑文件 vim /usr/local/lib/python3.8/site-packages/transformers/models/glm4_moe/modeling_glm4_moe.py在文件中搜索class Glm4MoeTopkRouter在其__init__方法里添加下面这一行代码# 在 __init__ 方法内添加通常是在定义其他参数的地方 self.e_score_correction_bias nn.Parameter(torch.zeros((self.n_routed_experts), dtypetorch.float32))这个参数是一个偏置项即使权重里没有我们也需要把它定义为一个可初始化的空参数让模型能够顺利加载。3.4 执行量化命令修复完transformers的代码后就可以运行量化脚本了。确保你的校准数据文件anti_prompt_50.json和calib_prompt_50.json放在脚本同级目录或指定路径。cd /path/to/msit/msmodelslim/example/Qwen3-MOE/ python glm4_moe_w8a8.py \ --model_path /home/your_path/GLM-4.5 \ --save_path /home/your_path/glm4.5_w8a8_dynamic/ \ --trust_remote_code True \ --batch_size 4--model_path: 指向你下载的原始浮点模型目录。--save_path: 量化后权重的输出目录。--trust_remote_code: GLM4模型需要这个参数来加载自定义代码。--batch_size: 根据你的NPU显存调整如果遇到OOM内存不足可以减小这个值。这个过程会比较耗时取决于模型大小和你的硬件。对于GLM4.5-360B这样的模型在8卡910B上可能也需要数小时。耐心等待如果一切顺利你会在save_path目录下看到生成的safetensors权重文件和几个配置文件。4. 量化后处理与权重合并量化脚本跑完生成了权重文件但工作还没结束。为了让生成的量化权重能被昇腾的推理框架如MindIE正确识别和加载我们还需要进行一些后处理操作。这一步常常被忽略但却是模型能成功跑起来的关键。4.1 合并量化配置到config.json量化工具会生成一个独立的quant_model_description_w8a8_dynamic.json文件里面包含了每一层的量化参数如scale和zero_point。但是很多推理引擎期望这些信息是直接嵌入在模型的config.json文件里的。因此我们需要写一个小脚本把这两个文件合并。我写了一个configmerge.py脚本它的逻辑很直接读取config.json和量化描述文件将量化描述的全部内容作为一个子字段比如quantization_config合并到config.json中并保存回去。注意脚本里的INPUT_DIR和OUTPUT_FILE路径需要替换成你自己的。#!/usr/bin/env python3 # configmerge.py import os import json import sys def merge_configs(input_dir, output_file): config_path os.path.join(input_dir, config.json) quant_desc_path os.path.join(input_dir, quant_model_description_w8a8_dynamic.json) if not os.path.exists(config_path): print(f错误: 配置文件不存在: {config_path}) return False if not os.path.exists(quant_desc_path): print(f错误: 量化描述文件不存在: {quant_desc_path}) return False try: with open(config_path, r, encodingutf-8) as f: config_data json.load(f) with open(quant_desc_path, r, encodingutf-8) as f: quant_desc_data json.load(f) # 将量化配置合并到config.json中 if quantization_config not in config_data: config_data[quantization_config] {} config_data[quantization_config].update(quant_desc_data) # 添加一个模型级别的量化类型标识方便推理时判断 if moe_quantize not in config_data: config_data[moe_quantize] w8a8_dynamic with open(output_file, w, encodingutf-8) as f: json.dump(config_data, f, indent4, ensure_asciiFalse) print(f成功: 配置已合并并保存到 {output_file}) return True except Exception as e: print(f错误: 处理配置文件时发生异常: {str(e)}) return False if __name__ __main__: # 请修改为你的实际路径 MODEL_DIR /home/your_path/glm4.5_w8a8_dynamic OUTPUT_CONFIG /home/your_path/glm4.5_w8a8_dynamic/config.json success merge_configs(MODEL_DIR, OUTPUT_CONFIG) sys.exit(0 if success else 1)运行这个脚本python configmerge.py。完成后检查新的config.json文件应该能看到一个庞大的quantization_config字段里面包含了所有层的量化信息。4.2 拷贝模板文件原始的GLM模型目录里通常包含一个chat_template.jinja文件这是定义对话模板的。推理时可能会用到。我们需要把它也拷贝到量化后的模型目录中保持模型的完整性。cp /path/to/original/GLM-4.5/chat_template.jinja /home/your_path/glm4.5_w8a8_dynamic/4.3 可选合并MTP浮点权重这是一个高级优化选项。对于GLM4.5-360B这样的超大模型其参数可能被分成多个文件并且可能包含一些未参与量化的“专家”权重在MoE中。在某些部署场景下为了兼容性或特定优化我们需要将原始的浮点权重MTP格式也合并到量化后的目录中但以不同的文件名前缀区分。msmodelslim的示例中提供了add_safetensors.py脚本通常在example/DeepSeek/目录下我们可以参考它。核心思想是遍历原始权重目录将safetensors文件复制到目标目录并加上mtp_float_之类的前缀同时更新config.json中的quantization_config指明哪些层对应的是浮点权重。# 示例代码片段展示思路 from add_safetensors import add_safetensors # 将原始路径下的safetensors文件以‘mtp_float_’为前缀复制到目标目录并更新配置 add_safetensors( org_paths/home/your_path/GLM-4.5, target_dir/home/your_path/glm4.5_w8a8_with_float_mtp, safetensors_prefixmtp_float, max_file_size_gb5, prefixmodel.layers.92. # 例如只处理特定层的权重 )这一步不是必须的取决于你后续的推理引擎要求。完成以上所有步骤后你就得到了一个完整的、经过w8a8量化的GLM4.5/4.6模型文件夹里面包含了量化权重、合并了量化信息的配置文件以及对话模板。你可以将这个文件夹直接用于昇腾平台上的推理部署了。整个过程虽然步骤不少但每一步都有其明确的目的跟着走下来你对模型量化和昇腾工具链的理解一定会深刻很多。如果在实际操作中遇到问题多检查路径和版本大部分错误都能从中找到答案。