☰
GLM-130B 量化实战指南:INT4/INT8 权重量化原理、配置与低资源推理
2026/9/27 21:31:51 网站建设 项目流程
  • 大模型
  • NLP
  • 基础模型
  • 模型评测
  • 模型量化

【免费下载链接】GLM-130B

GLM-130B: An Open Bilingual Pre-Trained Model (ICLR 2023)

项目地址:https://gitcode.com/gh_mirrors/gl/GLM-130B
点击查看免费下载

导读

本文以 docs/quantization.md 为核心,完整讲解 GLM-130B(130B 参数开源双语预训练模型)的量化方案:如何在几乎无损的前提下把模型权重压缩到 INT8 甚至 INT4,从而把推理硬件门槛从 8 × A100(40G) 降到 4 × RTX 3090(24G) 的单一服务器。读者将掌握量化原理(W8A16 权重量化、向量级对称量化)、checkpoint 张量并行维度转换、INT4/INT8 配置文件切换、量化 checkpoint 生成与加载,以及量化层的底层 CUDA 实现与性能基准。


一、为什么 GLM-130B 需要量化

GLM-130B 拥有 130B 参数,全精度 FP16 推理通常需要 8 × A100(40G) 级别的服务器。为降低硬件门槛,官方于 2022.08.24 发布了量化版本:保持激活精度为 FP16,仅将模型权重量化到最低 INT4,性能几乎无损失,从而将硬件需求降低到单台 4 × RTX 3090(24G) 服务器(见 README.md 的 News 与 Getting Started 章节)。

仓库为不同精度提供了独立的模型配置(见 configs 目录):

硬件GPU 显存量化权重卸载
8 × A10040 GB无无
8 × V10032 GB无有(BMInf)
8 × V10032 GBINT8无
8 × RTX 309024 GBINT8无
4 × RTX 309024 GBINT4无
8 × RTX 2080 Ti11 GBINT4无

二、量化方案设计:W8A16(只量化权重,激活保持 FP16)

2.1 激活异常值(Outliers)带来的困境

典型的量化方法会同时把模型权重和激活量化为 INT8,从而使用高效的 INT8 矩阵乘内核。但 GLM-130B 的激活值中存在异常值(outlier),使得降低激活精度变得困难——如上图所示,激活张量中存在少量数值极大的特征维度。

值得注意的是,Meta AI(LLM.int8(),见 arXiv:2208.07339)同期也发现大型 Transformer(>6.8B)存在这种 "emergent outliers" 现象,与 GLM-130B 的观测一致。他们的深入分析表明,异常值仅约占全部特征维度的 0.1%,因此可以对矩阵乘做分解:对包含异常值的少数维度用高精度乘法,其余维度用低精度乘法。

2.2 GLU 结构放大了异常值问题

GLM-130B 的情况更特殊:由于使用了GLU(门控线性单元)作为 FFN 变体,激活异常值有时最多可占特征维度的30%,这使得"混合精度分解"的矩阵乘效率远低于单个 FP16 矩阵乘。

经过反复试验,官方最终决策是:

  • 激活精度保留 FP16,只对模型权重进行量化(即 W8A16/W4A16 方案);
  • 量化后的权重在运行时动态转换回 FP16参与计算,引入少量计算开销,但大幅降低存储权重的显存需求。

2.3 量化的对象与方式

  • 量化对象:所有线性层(占模型参数的大部分);除输入/输出 embedding、LayerNorm 和 bias 之外的模型权重。
  • 量化方式:向量级(vector-wise)对称量化,即按权重矩阵的每一行(每个输出通道)计算一个量化 scale。
  • INT4 存储压缩:INT4 精度下,两个 INT4 权重被打包进一个 INT8 权重以节省显存,最终INT4 模型权重仅需约 70GB GPU 显存。

三、快速上手:三步完成量化推理

3.1 环境要求

  • SwissArmyTransformer >= 0.2.11(量化功能必需);
  • Python 3.9+ / CUDA 11+ / PyTorch 1.10+ / DeepSpeed 0.6+,并安装带 CUDA 与 C++ 扩展的 Apex,依赖见 requirements.txt。

3.2 设置 CHECKPOINT_PATH 与 CPU 内存要求

把CHECKPOINT_PATH设置为你本地的 checkpoint 文件夹(对应configs/model_glm_130b_{int4/int8}.sh)。加载流程是:

模型首先在 CPU 内存中从 FP16 checkpoint 初始化,然后被动态量化并转移到 GPU 内存。

因此请确保你有足够的 CPU 内存(> 260GB)来存放 FP16 模型权重。

3.3 张量并行维度转换(关键步骤)

仓库官方分发的 checkpoint 是8 路张量并行(8-way tensor parallel),即 8 张 GPU 共同存储一个完整模型。若你需要在更少的 GPU 上推理(例如 4 × RTX 3090 跑 INT4),必须先把 checkpoint 转换为 4 路张量并行,并同步修改配置文件中的MP_SIZE:

python tools/convert_tp.py \ --input-folder <SRC_CKPT_PATH> \ --output-folder <DST_CKPT_PATH> \ --target-tp 4

tools/convert_tp.py除转换并行度外,还支持在转换时直接产出量化权重(见下文 3.5 与第五节)。

3.4 切换配置文件并运行脚本

将脚本(如 scripts/generate.sh)中的模型配置从configs/model_glm_130b.sh换成对应的量化配置,然后照常运行:

bash scripts/generate.sh --input-source interactive

generate.sh通过source "${main_dir}/configs/model_glm_130b.sh"引入模型配置,并把MODEL_ARGS传给 generate.py,再以torchrun --nproc_per_node $MP_SIZE启动。所以更换配置文件的本质是改变MODEL_ARGS中的--quantization-bit-width、--from-quantized-checkpoint与MP_SIZE。

3.5 量化 checkpoint 的生成与加载

  • 默认行为:加载全精度(FP16)checkpoint,运行时动态量化。
  • 生成量化权重:运行转换脚本并指定量化位宽,即可产出量化后的模型权重:
python tools/convert_tp.py \ --input-folder <SRC_CKPT_PATH> \ --output-folder <DST_CKPT_PATH> \ --target-tp <TARGET_TP> \ --quantization-bit-width 4 # 或 8
  • 从量化 checkpoint 加载:在模型配置文件中添加--from-quantized-checkpoint,同时必须保留--quantization-bit-width <4 或 8>以告知解压逻辑。

四、INT4 / INT8 配置文件深度解析

三个配置文件的差异集中在MP_SIZE与量化参数上:

配置项FP16(model_glm_130b.sh)INT8(model_glm_130b_int8.sh)INT4(model_glm_130b_int4.sh)
MP_SIZE(张量并行度)884
--quantization-bit-width无84
--from-quantized-checkpoint无可选(加载量化权重时添加)可选(加载量化权重时添加)

三者共享的模型结构参数(来自configs/model_glm_130b_int4.sh):

MODEL_TYPE="glm-130b" CHECKPOINT_PATH="<your checkpoint path>" MP_SIZE=4 MODEL_ARGS="--model-parallel-size ${MP_SIZE} \ --num-layers 70 \ --hidden-size 12288 \ --inner-hidden-size 32768 \ --vocab-size 150528 \ --num-attention-heads 96 \ --max-sequence-length 2048 \ --tokenizer-type icetk-glm-130B \ --layernorm-order post \ --quantization-bit-width 4 \ --load ${CHECKPOINT_PATH} \ --skip-init \ --fp16"

参数要点:

  • --model-parallel-size ${MP_SIZE}:张量并行度,必须与 checkpoint 的实际切分方式一致(用convert_tp.py转换后同步修改);
  • --quantization-bit-width:取值4 或 8,定义量化位宽;
  • --load ${CHECKPOINT_PATH}:指向 checkpoint 目录;--skip-init跳过随机初始化,--fp16使用半精度计算;
  • --from-quantized-checkpoint:加载量化权重时必须添加(见 initialize.py)。

scripts/generate.sh、scripts/evaluate.sh、scripts/benchmark.sh均通过 source 对应配置文件获取MODEL_ARGS,因此只需修改配置文件即可全局切换精度模式。


五、源码级实现原理

5.1 初始化与量化时机(initialize.py)

initialize.py 的initialize_model_and_tokenizer是量化的核心调度点,按张量并行 rank 逐个初始化:

  1. model = GLM130B(args).half()创建模型;
  2. 若args.from_quantized_checkpoint:先断言quantization_bit_width已设置,然后调用quantize(model, ...)在加载 checkpoint 之前将模型结构替换为量化层(initialize.py);
  3. load_checkpoint(model, args)加载(量化)权重;
  4. 若设置了--quantization-bit-width但不是从量化 checkpoint 加载,则在加载后调用quantize(model, ...)动态量化(initialize.py);
  5. 最后把模型转移到 GPU。

量化参数由add_quantization_args注册(initialize.py):--quantization-bit-width(默认None)与--from-quantized-checkpoint。

5.2 层替换(quantization/init.py)

quantize(model, weight_bit_width)遍历model.transformer.layers的每一层,把四个权重占比最大的线性层替换为量化版本(quantization/init.py):

原层替换为类型
attention.query_key_valueQuantizedColumnParallelLinear列并行
attention.denseQuantizedRowParallelLinear行并行
mlp.dense_h_to_4hQuantizedColumnParallelLinear列并行
mlp.dense_4h_to_hQuantizedRowParallelLinear行并行

这与 tools/convert_tp.py 中QUANTIZED_LAYERS列表完全一致——四个权重张量即"被量化的线性层"。

5.3 量化存储与对称 scale(quantization/layers.py)

QuantizedColumnParallelLinear/QuantizedRowParallelLinear(quantization/layers.py)的实现要点:

  • 权重以torch.int8存储,张量形状变为shape[1] * weight_bit_width // 8(INT4 时宽度减半,实现两个 INT4 打包进一个 INT8,对应文档中"70GB 显存"的结论);

  • 向量级对称量化:按行计算 scale:

    self.weight_scale = (weight.abs().max(dim=-1).values / ((2 ** (weight_bit_width - 1)) - 1)).half() self.weight = torch.round(weight / self.weight_scale[:, None]).to(torch.int8)

    即每行以最大绝对值除以位宽上限(INT4 为 7,INT8 为 127)得到缩放因子,再将权重四舍五入到整数区间;

  • INT4 时调用compress_int4_weight(self.weight)压缩打包;

  • weight与weight_scale都注册为requires_grad=False的Parameter;

  • 前向计算通过W8A16Linear.apply(...)完成(quantization/layers.py),并保持 SAT 的张量并行通信语义(copy_to_model_parallel_region、gather_from_model_parallel_region、reduce_from_model_parallel_region等)。

5.4 运行时解压与矩阵乘(quantization/functional.py)

W8A16Linear(quantization/functional.py)的前向过程体现了"动态转换回 FP16"的设计:

  1. 把输入 reshape 为 2D;
  2. weight = extract_weight_to_half(quant_w, scale_w, weight_bit_width)在 GPU 上把量化权重解压回 FP16;
  3. output = inp.mm(weight.t())直接调用 FP16 矩阵乘(PyTorch 自带的高效内核)。

类还实现了backward,因此在有反向需求时(如继续微调实验)也能正常计算梯度。

5.5 CUDA 内核(cuda/quantization.cu 与 kernels/init.py)

解压与压缩的底层实现是手写 CUDA 内核(cuda/quantization.cu):

  • INT4 压缩int4WeightCompressionDevice:output[i] = (input[i * 2] << 4) | (input[i * 2 + 1] & 0b00001111),把连续两个 INT4 值拼进一个 INT8(cuda/quantization.cu);
  • INT4 解压int4WeightExtractionDevice:high = original >> 4、low = original << 4; low >>= 4,拆出高 4 位与低 4 位并乘以该行的 scale(cuda/quantization.cu);
  • INT8 解压int8WeightExtractionDevice:output[i] = T(weight[i]) * scale_list[blockIdx.x](cuda/quantization.cu);
  • 对外分别暴露int4WeightExtractionHalf/Float、int8WeightExtractionHalf/Float与int4WeightCompression全局内核。

kernels/init.py 通过ctypes加载预编译的 kernels/quantization.fatbin,封装出两个可直接调用的函数:

  • compress_int4_weight(weight):调用int4WeightCompression,把(n, m)的 INT8 权重压缩为(n, m/2);
  • extract_weight_to_half(weight, scale_list, source_bit_width):按位宽选择int4/int8WeightExtractionHalf内核,解压为(n, m * 8 // bit_width)的 FP16 张量。

预编译的 fatbin 通过 cuda/Makefile 用nvcc -fatbin生成,覆盖sm_61/sm_62/sm_70/sm_72/sm_75/sm_80/sm_86多代 GPU 架构(分别对应 RTX 2080 Ti、V100、A100、RTX 3090 等)。


六、评估结果:量化几乎无损

官方在 docs/quantization.md 中给出了 FP16 与量化版本在 5 个基准上的对比:

精度MMLU(Accuracy↑)LAMBADA(Accuracy↑)WikiText-2(PPL↓)WikiText-103(PPL↓)PTB(PPL↓)
FP1644.75180.20610.90110.75918.964
INT844.70980.20610.90410.76318.994
INT444.80179.46811.16711.04619.535

可见 INT8 与 FP16 几乎完全一致;INT4 在 LAMBADA 与 PPL 上有极小波动,MMLU 甚至略高(44.801 vs 44.751)。这些结果可用仓库的 scripts/evaluate.sh 在对应任务 YAML(如 tasks/mmlu/mmlu.yaml、tasks/lambada/lambada.yaml)上复现。


七、空间与速度基准

7.1 SAT 推理基准

以下结果是使用 SAT(SwissArmyTransformer)测试的端到端生成耗时:

硬件GPU 显存精度51210242048
8 × A10040 GBFP1645.21 s89.00 s179.22 s
8 × V10032 GBINT8106.35 s216.50 s449.17 s
4 × RTX 309024 GBINT4138.66 s292.69 s649.64 s
8 × RTX 2080 Ti11 GBINT4117.39 s240.96 s528.66 s

(表格列头 "512/1024/2048" 对应生成序列长度;耗时单位为秒。)

7.2 FasterTransformer 加速基准

使用 NVIDIA FasterTransformer 可提速2 倍以上,详细用法见 Inference with FasterTransformer。Encode / Decode 耗时(毫秒 / 秒):

硬件GPU 显存精度128 Encode / Decode512 Encode / Decode1024 Encode / Decode2048 Encode / Decode
8 × A10040 GBINT4145 ms / 4.29 s183 ms / 17.7 s313 ms / 37.8 s495 ms / 86.0 s
4 × A10080 GBINT4174 ms / 6.62 s272 ms / 27.1 s439 ms / 56.2 s810 ms / 123 s
8 × V10032 GBINT4309 ms / 6.97 s666 ms / 28.1 s1208 ms / 58.4 s2304 ms / 125 s
4 × V10032 GBINT4448 ms / 11.4 s843 ms / 45.87 s1488 ms / 93.5 s2803 ms / 196 s
8 × RTX 309024 GBINT4283 ms / 5.07 s915 ms / 20.5 s1793 ms / 42.7 s3477 ms / 90.3 s
4 × RTX 309024 GBINT4374 ms / 8.16 s1300 ms / 32.3 sOOM / 66.5 sOOM / 150 s
8 × RTX 2080 Ti11 GBINT4392 ms / 6.77 s1044 ms / 27.29 sOOM / 56.02 sOOM / OOM

从表可以看出,在 4 × RTX 3090(24GB)这类入门级配置上,INT4 + FasterTransformer 即可支撑 512~1024 token 级别的解码任务(OOM 出现在更长序列)。


八、注意事项与最佳实践

  1. CPU 内存是硬约束:无论 INT4 还是 INT8,启动时都要先在 CPU 上加载完整 FP16 checkpoint(>260GB),请使用足够内存的机器并优先把 checkpoint 放在 SSD 或内存盘上以缩短加载时间(参考 README.md)。
  2. 并行度必须匹配:官方 checkpoint 为 8 路张量并行;改用 4 卡必须先用convert_tp.py --target-tp 4转换,并把配置中的MP_SIZE改为 4(对应 configs/model_glm_130b_int4.sh)。
  3. --quantization-bit-width与--from-quantized-checkpoint配套使用:加载量化权重时两者缺一不可,否则要么加载失败、要么在运行时再次执行不必要的动态量化。
  4. 量化范围:只有线性层权重(attention.dense、attention.query_key_value、mlp.dense_h_to_4h、mlp.dense_4h_to_h)参与量化,embedding、LayerNorm、bias 保持 FP16;INT4 模式下的显存节省主要来自权重压缩打包。
  5. 追求更高吞吐:若延迟敏感,建议直接使用 FasterTransformer 推理路径(docs/inference-with-fastertransformer.md),其 INT4 权重可复用本仓库的转换产物。

相关文档

  • docs/quantization.md:量化方案的原始说明与全部基准数据
  • docs/inference-with-fastertransformer.md:FasterTransformer 2 倍以上加速推理
  • docs/low-resource-inference.md:结合 BMInf 权重卸载的更小显存推理
  • docs/evaluate-your-own-tasks.md:自定义评测任务
  • configs/model_glm_130b_int4.sh / configs/model_glm_130b_int8.sh:INT4/INT8 配置文件
  • tools/convert_tp.py:张量并行转换与量化权重生成脚本
  • quantization/layers.py 与 quantization/functional.py:量化层实现
  • cuda/quantization.cu 与 kernels/quantization.fatbin:压缩/解压 CUDA 内核

通过本文的配置与源码解析,你可以独立完成 GLM-130B 在 INT8/INT4 精度下的 checkpoint 转换、配置切换与推理部署,在近乎无损的模型质量下把显存开销降低数倍。

  • 大模型
  • NLP
  • 基础模型
  • 模型评测
  • 模型量化

【免费下载链接】GLM-130B

GLM-130B: An Open Bilingual Pre-Trained Model (ICLR 2023)

项目地址:https://gitcode.com/gh_mirrors/gl/GLM-130B
点击查看免费下载

相关推荐

上一篇:MiroTalk P2P中的实时协作功能:白板、文件共享与屏幕共享
下一篇:OpenAI 里程碑式开源:gpt-oss 双模型落地,16GB 显存即可本地部署

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询