大模型NLP基础模型模型评测模型量化【免费下载链接】GLM-130BGLM-130B: An Open Bilingual Pre-Trained Model (ICLR 2023)项目地址https://gitcode.com/gh_mirrors/gl/GLM-130B点击查看免费下载导读本文以 docs/quantization.md 为核心完整讲解 GLM-130B130B 参数开源双语预训练模型的量化方案如何在几乎无损的前提下把模型权重压缩到 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无有BMInf8 × V10032 GBINT8无8 × RTX 309024 GBINT8无4 × RTX 309024 GBINT4无8 × RTX 2080 Ti11 GBINT4无二、量化方案设计W8A16只量化权重激活保持 FP162.1 激活异常值Outliers带来的困境典型的量化方法会同时把模型权重和激活量化为 INT8从而使用高效的 INT8 矩阵乘内核。但 GLM-130B 的激活值中存在异常值outlier使得降低激活精度变得困难——如上图所示激活张量中存在少量数值极大的特征维度。值得注意的是Meta AILLM.int8()见 arXiv:2208.07339同期也发现大型 Transformer6.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_SIZEpython tools/convert_tp.py \ --input-folder SRC_CKPT_PATH \ --output-folder DST_CKPT_PATH \ --target-tp 4tools/convert_tp.py除转换并行度外还支持在转换时直接产出量化权重见下文 3.5 与第五节。3.4 切换配置文件并运行脚本将脚本如 scripts/generate.sh中的模型配置从configs/model_glm_130b.sh换成对应的量化配置然后照常运行bash scripts/generate.sh --input-source interactivegenerate.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 的生成与加载默认行为加载全精度FP16checkpoint运行时动态量化。生成量化权重运行转换脚本并指定量化位宽即可产出量化后的模型权重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与量化参数上配置项FP16model_glm_130b.shINT8model_glm_130b_int8.shINT4model_glm_130b_int4.shMP_SIZE张量并行度884--quantization-bit-width无84--from-quantized-checkpoint无可选加载量化权重时添加可选加载量化权重时添加三者共享的模型结构参数来自configs/model_glm_130b_int4.shMODEL_TYPEglm-130b CHECKPOINT_PATHyour checkpoint path MP_SIZE4 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.pyinitialize.py 的initialize_model_and_tokenizer是量化的核心调度点按张量并行 rank 逐个初始化model GLM130B(args).half()创建模型若args.from_quantized_checkpoint先断言quantization_bit_width已设置然后调用quantize(model, ...)在加载 checkpoint 之前将模型结构替换为量化层initialize.pyload_checkpoint(model, args)加载量化权重若设置了--quantization-bit-width但不是从量化 checkpoint 加载则在加载后调用quantize(model, ...)动态量化initialize.py最后把模型转移到 GPU。量化参数由add_quantization_args注册initialize.py--quantization-bit-width默认None与--from-quantized-checkpoint。5.2 层替换quantization/init.pyquantize(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 量化存储与对称 scalequantization/layers.pyQuantizedColumnParallelLinear/QuantizedRowParallelLinearquantization/layers.py的实现要点权重以torch.int8存储张量形状变为shape[1] * weight_bit_width // 8INT4 时宽度减半实现两个 INT4 打包进一个 INT8对应文档中70GB 显存的结论向量级对称量化按行计算 scaleself.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 为 7INT8 为 127得到缩放因子再将权重四舍五入到整数区间INT4 时调用compress_int4_weight(self.weight)压缩打包weight与weight_scale都注册为requires_gradFalse的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.pyW8A16Linearquantization/functional.py的前向过程体现了动态转换回 FP16的设计把输入 reshape 为 2Dweight extract_weight_to_half(quant_w, scale_w, weight_bit_width)在 GPU 上把量化权重解压回 FP16output inp.mm(weight.t())直接调用 FP16 矩阵乘PyTorch 自带的高效内核。类还实现了backward因此在有反向需求时如继续微调实验也能正常计算梯度。5.5 CUDA 内核cuda/quantization.cu 与 kernels/init.py解压与压缩的底层实现是手写 CUDA 内核cuda/quantization.cuINT4 压缩int4WeightCompressionDeviceoutput[i] (input[i * 2] 4) | (input[i * 2 1] 0b00001111)把连续两个 INT4 值拼进一个 INT8cuda/quantization.cuINT4 解压int4WeightExtractionDevicehigh original 4、low original 4; low 4拆出高 4 位与低 4 位并乘以该行的 scalecuda/quantization.cuINT8 解压int8WeightExtractionDeviceoutput[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 个基准上的对比精度MMLUAccuracy↑LAMBADAAccuracy↑WikiText-2PPL↓WikiText-103PPL↓PTBPPL↓FP1644.75180.20610.90110.75918.964INT844.70980.20610.90410.76318.994INT444.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 推理基准以下结果是使用 SATSwissArmyTransformer测试的端到端生成耗时硬件GPU 显存精度512102420488 × A10040 GBFP1645.21 s89.00 s179.22 s8 × V10032 GBINT8106.35 s216.50 s449.17 s4 × RTX 309024 GBINT4138.66 s292.69 s649.64 s8 × 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 / Decode8 × A10040 GBINT4145 ms / 4.29 s183 ms / 17.7 s313 ms / 37.8 s495 ms / 86.0 s4 × A10080 GBINT4174 ms / 6.62 s272 ms / 27.1 s439 ms / 56.2 s810 ms / 123 s8 × V10032 GBINT4309 ms / 6.97 s666 ms / 28.1 s1208 ms / 58.4 s2304 ms / 125 s4 × V10032 GBINT4448 ms / 11.4 s843 ms / 45.87 s1488 ms / 93.5 s2803 ms / 196 s8 × RTX 309024 GBINT4283 ms / 5.07 s915 ms / 20.5 s1793 ms / 42.7 s3477 ms / 90.3 s4 × RTX 309024 GBINT4374 ms / 8.16 s1300 ms / 32.3 sOOM / 66.5 sOOM / 150 s8 × RTX 2080 Ti11 GBINT4392 ms / 6.77 s1044 ms / 27.29 sOOM / 56.02 sOOM / OOM从表可以看出在 4 × RTX 309024GB这类入门级配置上INT4 FasterTransformer 即可支撑 512~1024 token 级别的解码任务OOM 出现在更长序列。八、注意事项与最佳实践CPU 内存是硬约束无论 INT4 还是 INT8启动时都要先在 CPU 上加载完整 FP16 checkpoint260GB请使用足够内存的机器并优先把 checkpoint 放在 SSD 或内存盘上以缩短加载时间参考 README.md。并行度必须匹配官方 checkpoint 为 8 路张量并行改用 4 卡必须先用convert_tp.py --target-tp 4转换并把配置中的MP_SIZE改为 4对应 configs/model_glm_130b_int4.sh。--quantization-bit-width与--from-quantized-checkpoint配套使用加载量化权重时两者缺一不可否则要么加载失败、要么在运行时再次执行不必要的动态量化。量化范围只有线性层权重attention.dense、attention.query_key_value、mlp.dense_h_to_4h、mlp.dense_4h_to_h参与量化embedding、LayerNorm、bias 保持 FP16INT4 模式下的显存节省主要来自权重压缩打包。追求更高吞吐若延迟敏感建议直接使用 FasterTransformer 推理路径docs/inference-with-fastertransformer.md其 INT4 权重可复用本仓库的转换产物。相关文档docs/quantization.md量化方案的原始说明与全部基准数据docs/inference-with-fastertransformer.mdFasterTransformer 2 倍以上加速推理docs/low-resource-inference.md结合 BMInf 权重卸载的更小显存推理docs/evaluate-your-own-tasks.md自定义评测任务configs/model_glm_130b_int4.sh / configs/model_glm_130b_int8.shINT4/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-130BGLM-130B: An Open Bilingual Pre-Trained Model (ICLR 2023)项目地址https://gitcode.com/gh_mirrors/gl/GLM-130B点击查看免费下载相关推荐vLLM INT8 W4A8 量化实战指南用 LLM Compressor 实现 INT4 权重 INT8 激活的模型压缩与高效推理vLLM INT8 W4A8 量化实战指南用 LLM Compressor 实现 INT4 权重 INT8 激活的模型压缩与高效推理 vLLM 支持将模型人工智能大模型模型推理服务推理引擎本地部署bitsandbytes 量化格式全指南INT8、NF4、FP4 与双重量化的原理、配置与实战bitsandbytes 量化格式全指南INT8、NF4、FP4 与双重量化的原理、配置与实战 本篇技术指南以 bitsandbytes 的量化格式为核心系AI 技能人工智能大模型深度学习基于 Transformers 的 XVERSE-7B-Chat 推理与 INT4/INT8 量化实战指南基于 Transformers 的 XVERSE 7B Chat 推理与 INT4/INT8 量化实战指南 XVERSE 7B Chat 是深圳元象科技开源的大模型人工智能教程本地部署微调上一篇MiroTalk P2P中的实时协作功能白板、文件共享与屏幕共享下一篇OpenAI 里程碑式开源gpt-oss 双模型落地16GB 显存即可本地部署创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考