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

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)

0. 概述

上一节 对安装和使用有个基本介绍。根据这个 issue 的描述,后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作,其中包含了大量可以学习的地方。本文主要看看它导出模型的部分,导出模型分为 convert_checkpoint.py (quantize.py) 和 trtllm-build 两个过程。

有些较新的模型不支持这个流程了,比如 DeepSeek-R1 等,需使用 pytorch backend 那套。

1. convert_checkpoint.py

首先确定待转换模型的类型,然后在 examples/models 下面找到对应使用的脚本。本文使用 Qwen2.5-0.5B-Instruct,对应脚本文件是 examples/models/core/qwen/convert_checkpoint.py。

前文 提到,在 convert_checkpoint.py 这个过程主要是确定权重的拆分和计算方式,以及实际采用的量化方式,所以参数主要也是分为这两部分。

1.1 权重的拆分和计算

按照不同的切分方式,将模型权重以某种方式将其加载后放置到不同卡上,使得较大模型也能在多张较小显存的卡上运行。在实际运行时,某张卡仅负责部分权重的加载和运行,然后在需要整体数据时归约各卡的计算结果。

1.1.1 tp_size

将权重按照设置的 tp_size 值切分并加载到不同卡上,每张卡上保存全部激活值。当需要全局信息如计算自注意力的时候,首先将各卡结果归约。在实际设置时,tp_size 必须能整除 num_attention_heads 和 num_kv_heads 等这种维度划分的纬度值。

1.1.2 pp_size

将模型按照层切分到不同卡上,注意 tp_size*pp_size 的值不超过总卡数。

1.1.3 cp_size

暂时跳过,tp_size pp_size 和 cp_size 可以任意组合设置。

1.1.4 moe_tp_size

请添加图片描述
moe 和集成学习类似,通过多个模型来解决同一个问题,并且将它们的结果整合。如上图,论文 使用稀疏的 moe 块替换稠密的 FFN 层,图中每一个子 FFN 模块称为一个专家,整体还包含一个门控模块。在实际运行时,输入首先过一个门控网络,门控模块输出 softmax 的概率结果来确定输出应该路由到哪些专家并参与运算,同时通过 --moe_top_k 参数来控制参数运算的专家数。

--moe_tp_size 对 moe 模块使用 tp,默认值等于 tp_size 的值。

1.1.5 moe_ep_size

对于 moe 模块,将不同的专家放到不同的卡上,可以和 moe_tp_size 组合使用,默认值是 1,该值必须能够整除专家数。

1.1.6 示例

如设置 tp_size=4 pp_size=2:

python examples/models/core/qwen/convert_checkpoint.py \--model_dir Qwen2.5-0.5B-Instruct \--tp_size 4 \--pp_size 2 \--output_dir Qwen2.5-0.5B-Instruct-pp2-tp4 

1.2 量化

量化将权重或激活值从浮点类型转换为另一数值类型,一方面是最快降低模型推理显存占用的方案,另一方面在某些场景下也快于原浮点精度推理。比如,fp16 的 70b 模型需要大约 140G 的显存来存放权重。而如果将其权重量化为 int4 类型,则仅需要约 35G。对于量化,需要处理的是数值范围改变后带来的模型精度降低,从而可能导致模型产生不合理输出的情况。对于 TensorRT-LLM,量化主要针对权重、激活值和 kv cache 这三部分。

1.2.1 weight_only_quantization

权重量化,配合 --weight_only_precision 为 int8 int4 或者 int4_gptq 设置不同的权重量化方法。

int8 和 int4 是基础的量化方法,没有校准。在量化时,一般采用 per_channel 的方式。int4_gptq 是一种更细粒度的量化方法,将通道按照如默认的 128 划分 group,划分部分共用一个缩放系数,可通过 --group_size 设置 group 大小。

1.2.2 smoothquant

既量化权重也量化激活值,论文。大体思想是:由于权重量化相对于激活值量化,更能保证模型的精度(可以参考原论文的相关实验),因此引入一个平滑因子来将量化难度从激活转移到权重上。对于矩阵乘法:
Y = X ⋅ W Y=X\cdot W Y=XW

可变换为:
Y = ( X ⋅ d i a g ( s ) − 1 ) ⋅ ( d i a g ( s ) ⋅ W ) Y=\left(X\cdot{\rm diag(s)}^{-1}\right)\cdot \left({\rm diag(s)}\cdot W\right) Y=(Xdiag(s)1)(diag(s)W)

其中,激活值右乘对角矩阵相当于对矩阵按列缩放,权重值左乘对角矩阵相当于对矩阵按行缩放(大学线代知识)。为实现量化难度从激活值转移到权重上,论文将上述变换的参数定义为:
s j = m a x ( ∣ X j ∣ ) α / m a x ( ∣ W j ∣ ) 1 − α {\rm s}_j={\rm max}\left(|X_j|\right)^{\alpha}/{\rm max}\left(|W_j|\right)^{1-\alpha} sj=max(Xj)α/max(Wj)1α

其中 α \alpha α 是定义的超参数,范围是 0 到 1(推荐从 0.5 开始尝试),且论文有取值的消融实验。这样,我们可以先通过数据集离线计算 s {\rm s} s 的值,然后在推理时将该值作用到激活值和权重。在指定 --smoothquant 或 -sq 后会启用默认数据集 ccdv/cnn_dailymail,或使用 --calib_dataset 指定的数据集。

默认情况下,–smoothquant 会采用 per-tensor 的模式,即每个矩阵共用一个缩放系数。TensorRT-LLM 提供了 --per-token 和 --per-channel 的任意组合来分别确定激活值和权重的缩放方式。

1.2.3 int8_kv_cache

使用 int8 类型来存放 KV Cache 值,通过 --int8_kv_cache 指定。

1.2.4 示例

使用 int8 weight only 的量化:

python examples/models/core/qwen/convert_checkpoint.py \--model_dir Qwen2.5-0.5B-Instruct \--use_weight_only \--weight_only_precision int8 \--output_dir Qwen2.5-0.5B-Instruct-int8

2. quantize.py

更多量化方法在 quantize.py 中指定,其中也有 tp_size 等选项。在 quantize.py 中提供了 --qformat 选项指定量化方式,包括:

量化方式说明
nvfp4Blackwell 架构,如 B 卡上的数据格式,没有设备没试过
fp8Hopper 架构,如 H 卡上的数据格式
int8_sqint8 smoothquant
int4_awq和 gptq 类似,awq 保留部分权重的原始数据类型
w4a8_awq和上一个参数一样,配合 --awq_block_size 设置 block 大小
int8_woint8 weight only 量化
int4_woint4 weight only 量化
full_prec不量化

--kv_cache_dtype 可以设置 int8 或 fp8 来指定 kv cache 的数据类型。此外,为了实现混合精度,如 MLP 量化为 int4,其余部分为 int8。可通过 json 文件(命名为 quant_cfg.json)为模型不同部分设置不同精度:

{"quant_algo": "MIXED_PRECISION","kv_cache_quant_algo": "FP8","quantized_layers": {"transformer.layers.0.attention.qkv": {"quant_algo": "FP8"},"transformer.layers.0.attention.dense": {"quant_algo": "FP8"},"transformer.layers.0.mlp.fc": {"quant_algo": "W4A16_AWQ","group_size": 128,"has_zero_point": false,"pre_quant_scale": true},"transformer.layers.0.mlp.proj": {"quant_algo": "W8A8_SQ_PER_CHANNEL"},..."transformer.layers.31.mlp.proj": {"quant_algo": "FP8"}}
}

3. trtllm-build

trtllm-build 输入是上面 convert_checkpoint.py 的输出目录,这里只列出常见的选项,没用过的暂时不列举了。

3.1 基本选项

3.1.1 长度相关

max_batch_size max_input_len max_seq_len 和 max_num_tokens 这几个配合使用,参考 说明。总的来说,由于 TensorRT 的静态特性,将 max_batch_size max_input_len 和 max_seq_len 设置得足够大以满足场景需求,然后控制 max_num_tokens 的值。如果 max_num_tokens 值太大,在 build 阶段的 warmup 等过程会提前暴露出如 oom 等错误。

3.1.2 max_beam_width

beam search 的返回结果数量,用于需产生多样化输出的场景。

3.1.3 kv_cache_type

kv cache 的存储和调度方式,默认为 paged kv cache。

3.2 logits 处理

如果需要收集 prefill 阶段(–gather_context_logits)和 decode (–gather_generation_logits) 阶段的 logits,或者都需要(–gather_all_token_logits),则需开启对应选项。

3.3 lora 相关

没用过,暂时跳过。

3.4 speculative decoding

没用过,暂时跳过。

3.5 plugin 相关

当 --remove_input_padding 开启时,不同输入组成一个一维向量,连同各输入长度送入模型。否则,对于不同输入,较短的输入会被填充到最大长度,这会带来额外的空间和计算浪费。

选项 --tokens_per_block 用在 paged kv cache 中,用于设置每个 block 的大小,默认为 32。

选项 --use_paged_context_fmha 可开启 kv cache 复用,以及 context chunking 功能(将长上下文分段 prefill)。

其他一些默认开启的设置,没有怎么设置用过。

4. run.py

导出模型后,可使用 run.py 快速验证和运行,如 tp_size*pp_size 等于 4:

mpirun -n 4 run.py --max_output_len 128 --input_text "What is AI?"

5. 总结

本文主要记录了原 tensorrt backend 的模型导出部分,后续可能用得也不多了,做个备份,还有其他内容可以想起来的时候补充。

相关文章:

  • 二叉树进阶:经典算法题详解
  • 6月10日day50打卡
  • 可视化图解算法50:最小的K个数
  • SpringBoot集成Tess4j :低成本解锁OCR 图片识别能力
  • 鹰盾视频的AI行为检测是怎样的风控?
  • [极客时间]LangChain 实战课 ----- 01|LangChain系统安装和快速入门(2)
  • 第四章 软件需求工程
  • 论文略读: CUT YOUR LOSSES IN LARGE-VOCABULARY LANGUAGE MODELS
  • 如何通过DNS解析实现负载均衡?有哪些优势?
  • 期权卖方是谁?
  • Linux动态库与静态库详解:从入门到精通
  • mysql-innoDB存储引擎事务的原理
  • 智能合约安全专题(一):什么是重入攻击?——从 DAO 事件谈起
  • Ribbon负载均衡实战指南:7种策略选择与生产避坑
  • 《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》
  • 广告系统中后链路数据为什么要使用流批一体技术?流批一体技术是什么?
  • [特殊字符] 智能合约中的数据是如何在区块链中保持一致的?
  • Redis高可用与扩展性:构建稳定高效的缓存系统
  • Qt Widget类解析与代码注释
  • 图像直方图分析:全面掌握OpenCV与Matplotlib绘制技巧
  • 企业网站seo服务/windows优化大师在哪里
  • 呼和浩特 网站建设/网络营销优化
  • 深圳大型网站建设/培训学校招生方案范文
  • 宝鸡做网站/个人网页制作成品
  • 网站建设销售专业术语/推广业务平台
  • 做网站怎么赚钱滑县电/如何发布一个网站