3、模型转换基础:理解ONNX、TorchScript、FasterTransformer等模型格式,以及转换为TensorRT-LLM的流程
3.1 为什么需要关注模型格式
在进入TensorRT-LLM编译之前,首先要回答一个关键问题:我们手里拿到的模型文件,到底是以什么格式存在的?不同训练框架产出的模型格式,决定了后续编译管线的入口。PyTorch训练出的模型通常是.pt或.pth(包含权重与网络结构),HuggingFace生态则统一使用safetensors + config.json的目录结构。而TensorRT-LLM本身并不直接消费这些原始格式,它需要的是经过特定转换后的中间表示。理解这一点,是避免“拿到模型却无从下手”的第一步。
3.2 三种主流模型格式的定位与差异
在TensorRT-LLM的生态中,你会频繁接触到ONNX、TorchScript和FasterTransformer(现已并入TensorRT-LLM)三种格式。它们各自服务于不同的转换阶段,不能混为一谈。
| 格式 | 本质 | 在TensorRT-LLM中的角色 | 典型来源 |
|---|---|---|---|
| ONNX | 跨框架的静态计算图 | 作为中间桥梁,将PyTorch模型导出为通用图,再转换为TensorRT-LLM的权重格式 | torch.onnx.export() |
| TorchScript | PyTorch的序列化图表示 | 较少直接用于TensorRT-LLM,更多用于PyTorch自身推理优化;在转换流程中可作为备选导出路径 | torch.jit.trace/script |
| FasterTransformer | 早期高性能推理的权重/引擎格式 | 其权重格式与TensorRT-LLM兼容,部分旧模型可直接复用其转换脚本 | FasterTransformer仓库的utils脚本 |
需要特别强调的是:ONNX不是TensorRT-LLM的最终引擎格式。ONNX在这里扮演的是“通用交换格式”的角色。TensorRT-LLM真正需要的是权重文件(通常是.safetensors或.bin)加模型配置,然后通过其内部的trtllm-build命令直接构建引擎。因此,ONNX导出往往只是转换管线中的一个中间步骤,而非终点。
3.3 从PyTorch到TensorRT-LLM的标准转换流程
下面以最常见的HuggingFace模型为例,梳理一条完整的转换路径。整个流程分为四个阶段,每个阶段都有明确的输入输出。
# 阶段1:导出ONNX(可选但推荐用于验证)
import torch
from transformers import AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b-hf")
dummy_input = torch.randint(0, 32000, (1, 64))
torch.onnx.export(
model, dummy_input, "llama2-7b.onnx",
opset_version=17,
input_names=["input_ids"],
output_names=["logits"]
)
# 阶段2:使用官方转换脚本生成TensorRT-LLM权重
python convert_checkpoint.py \
--model_dir ./llama2-7b-hf \
--output_dir ./tllm_checkpoint \
--dtype float16
# 阶段3:构建TensorRT引擎
trtllm-build \
--checkpoint_dir ./tllm_checkpoint \
--output_dir ./llama2-7b-engine \
--gemm_plugin float16
# 阶段4:加载引擎进行推理
from tensorrt_llm.runtime import ModelRunner
runner = ModelRunner.from_dir(engine_dir="./llama2-7b-engine")
上述流程中,阶段2的convert_checkpoint.py是核心。它读取HuggingFace的config.json和safetensors权重,将其重新组织为TensorRT-LLM自定义的checkpoint格式。这个格式包含了模型结构参数(层数、头数、维度等)以及经过重排的权重张量。值得注意的是,ONNX导出在官方推荐流程中并非必需——TensorRT-LLM的转换脚本直接解析HuggingFace格式,跳过了ONNX这一步。ONNX更多用于调试、可视化或对接其他推理后端。
convert_checkpoint.py即可,无需手动导出ONNX。只有当模型结构较新、官方脚本尚未支持时,才考虑通过ONNX作为中间表示进行自定义转换。
3.4 案例:Llama-2-7B的完整转换复盘
我们以Llama-2-7B为例,走一遍真实转换过程,并记录关键输出。
# 1. 准备HuggingFace模型(已下载至本地)
ls ./llama2-7b-hf/
# config.json generation_config.json pytorch_model.bin tokenizer.json tokenizer_config.json
# 2. 执行转换(关键日志)
python convert_checkpoint.py --model_dir ./llama2-7b-hf --output_dir ./tllm_checkpoint --dtype float16
# [INFO] Loading model from ./llama2-7b-hf
# [INFO] Model config: LlamaConfig(vocab_size=32000, hidden_size=4096, num_hidden_layers=32, num_attention_heads=32)
# [INFO] Converting 32 decoder layers...
# [INFO] Saving checkpoint to ./tllm_checkpoint
# [INFO] Done. Total 128 files written.
# 3. 构建引擎
trtllm-build --checkpoint_dir ./tllm_checkpoint --output_dir ./llama2-7b-engine --gemm_plugin float16
# [INFO] Engine built in 45.3 seconds.
# [INFO] Engine size: 13.4 GB (FP16)
这个案例揭示了几个关键点:
- 转换时间远小于构建时间:checkpoint转换只是权重重排,而引擎构建涉及算子选择、内核调优和显存规划。
- 权重文件数量众多:128个文件对应每一层的QKV投影、输出投影、MLP等独立张量,TensorRT-LLM按层分文件存储,便于并行加载。
- FP16引擎体积约为原始FP32权重的1/2:因为权重本身转为FP16存储,且引擎中包含了kernel代码和调度元数据。
3.5 常见误区与排障复盘
在模型转换环节,初学者最容易踩入以下几个坑。我们逐一复盘并给出对策。
dtype参数的影响。转换时指定的--dtype float16决定了权重存储精度。如果模型有某些层对精度敏感(如LayerNorm的beta/gamma),可能需要使用float32保留这些层,否则推理精度会下降。建议转换前检查模型配置中的torch_dtype字段。
convert_checkpoint.py和trtllm-build混为一谈。实际上,前者只是把HuggingFace权重“翻译”成TensorRT-LLM的checkpoint格式,不涉及任何GPU优化;后者才真正生成针对特定GPU的优化引擎。如果换了GPU型号,只需要重新执行trtllm-build,无需重新转换权重。
另一个常见问题是版本不匹配。TensorRT-LLM对模型结构的支持是硬编码的,如果你的模型是Llama-3.2而本地TensorRT-LLM版本只支持到Llama-3.1,转换脚本会直接报错或生成错误权重。此时需要:
- 检查
tensorrt_llm/models/目录下是否有对应模型定义文件; - 若无,考虑升级TensorRT-LLM版本,或使用
--model_type参数指定相近的模型结构; - 最稳妥的方案是查阅官方文档的“Supported Models”列表,确认模型版本在支持范围内。
3.6 转换流程中的关键检查清单
为了确保转换过程顺利,建议在动手前逐项核对以下清单:
- 模型版本确认:在TensorRT-LLM官方文档的Supported Models列表中确认你的模型架构和版本受支持。
- 权重精度规划:明确目标精度(FP16/BF16/FP8),并检查模型是否有特殊层需要保留FP32。
- 分词器完整性:转换脚本通常不处理tokenizer,但推理时需要。确保
tokenizer.json或tokenizer.model与模型权重放在同一目录。 - 磁盘空间:转换后的checkpoint体积约为原始权重的1~1.5倍(取决于dtype),引擎文件另占空间。预留至少2倍模型大小的磁盘。
- GPU显存预检:构建引擎时会将checkpoint加载到显存,建议显存大于模型FP16体积的1.5倍。
完成上述检查后,转换流程通常可以一次通过。如果遇到报错,优先查看convert_checkpoint.py输出的日志尾部——绝大多数错误会明确提示是“模型结构不支持”还是“权重文件缺失”,据此对症下药即可。