3、TensorRT-LLM基础:模型加载、推理流程、引擎构建与序列化

3.1 核心原理:从PyTorch权重到TensorRT引擎的映射逻辑

TensorRT-LLM的本质,是将HuggingFace等生态中的PyTorch模型,通过逐层翻译的方式转换为TensorRT引擎可执行的图结构。这一过程并非简单的格式转换,而是涉及算子映射、权重重排与图优化三个层面的深度重构。PyTorch模型中的nn.Linear、nn.LayerNorm、nn.Embedding等模块,会被映射为TensorRT-LLM中对应的Linear、LayerNorm、Lookup等层;而注意力机制中的QKV投影、RotaryEmbedding、Cache管理等操作,则会被融合为TensorRT-LLM自定义的Attention算子。

权重重排是另一个关键差异点。PyTorch权重通常以[out_features, in_features]布局存储,而TensorRT-LLM为了发挥Tensor Core的矩阵乘算力,往往需要将权重预置为[K, N]且按16字节对齐的格式。例如,对于LLaMA-7B的gate_proj与up_proj,在PyTorch中它们是两个独立的Linear层,但在TensorRT-LLM中,为了减少kernel启动开销,通常会将两者拼接为一个[2 * intermediate_size, hidden_size]的大权重矩阵,由单个GEMM完成计算后再按块切分。

核心理解:TensorRT-LLM的模型定义文件(如model.py)并不是“另一个实现”,而是PyTorch模型的TensorRT-LLM方言翻译。同一个LLaMA结构,在PyTorch中调用model.forward(),在TensorRT-LLM中则通过LLaMAForCausalLM类的forward()构建出TensorRT网络定义。因此,阅读模型定义源码是理解映射关系的最佳入口。

PyTorch 模型 nn.Linear (gate_proj) nn.Linear (up_proj) nn.Linear (down_proj) nn.LayerNorm nn.Embedding 权重: [out, in] 布局 TensorRT-LLM 翻译层 权重拼接 [2*inter, hid] GEMM 融合 + SwiGLU 激活 LayerNorm 融合 residual 权重转置 + 16B 对齐 TensorRT 引擎 Gemm_1 (融合QKV) Gemm_2 (gate+up) Gemm_3 (down) LayerNorm + Residual Lookup + Mask 权重: [K, N] 16B 对齐 映射核心:算子翻译 + 权重重排 + 图融合(如 SwiGLU 的两次 GEMM 合并为一次)

3.2 方法流程:引擎构建与序列化的完整链路

TensorRT-LLM的引擎构建遵循“权重准备 → 网络定义 → 引擎编译 → 序列化”四步流程。首先,通过from_pretrained加载HuggingFace格式的模型权重,并调用save_checkpoint将权重转换为TensorRT-LLM的checkpoint格式。这一步骤会完成权重重排与格式统一,例如将FP32权重转换为FP16或INT8的量化格式。

随后,在build阶段,TensorRT-LLM读取checkpoint,通过模型定义文件(如LLaMAForCausalLM)构建TensorRT网络。此时可以指定并行方式(张量并行、流水线并行)、量化策略(FP8、INT4-AWQ等)、最大序列长度、批处理大小等编译选项。引擎编译完成后,通过engine_buffer = engine.serialize()得到二进制引擎文件,该文件可直接落盘保存,供后续推理加载。

# 典型构建流程(LLaMA-7B 示例)
from tensorrt_llm.models import LLaMAForCausalLM

# 1. 加载HF权重并转换为TRT-LLM checkpoint
llama = LLaMAForCausalLM.from_pretrained(
    "meta-llama/Llama-2-7b-hf",
    dtype="float16",
    tensor_parallel_size=2,   # 张量并行度
    quant_config={"quant_algo": "FP8"}
)
llama.save_checkpoint("./llama7b_trtllm_ckpt")

# 2. 构建引擎
from tensorrt_llm.builder import build_engine
engine = build_engine(
    model_dir="./llama7b_trtllm_ckpt",
    max_batch_size=8,
    max_seq_len=4096,
    use_fused_mlp=True,
    use_gpt_attention_plugin="float16"
)

# 3. 序列化保存
with open("llama7b_fp8.engine", "wb") as f:
    f.write(engine.serialize())
构建阶段关键操作产物常见耗时
权重转换HF → TRT-LLM checkpoint,含量化checkpoint目录1-3分钟
网络定义逐层翻译为TensorRT网络内存中的INetwork秒级
引擎编译算子选择、内存规划、kernel调优ICudaEngine5-30分钟
序列化引擎二进制序列化.engine文件秒级

3.3 推理流程:从引擎加载到Token生成的内部机制

推理阶段,TensorRT-LLM采用运行时(Runtime)与会话(Session)两层抽象。首先通过EngineBuffer从文件加载引擎,然后创建GenerationSession。每次推理请求,需要准备输入张量:input_ids(形状[batch, seq_len])、position_ids、attention_mask等。会话内部维护KV Cache,用于缓存历史token的Key和Value,避免重复计算。

生成过程采用自回归循环:每次前向传播只生成下一个token,然后将新token追加到输入序列,更新KV Cache,再继续下一次前向。TensorRT-LLM通过max_new_tokens控制生成长度,通过end_id(如</s>)判断终止。整个循环在GPU上以同步批处理方式执行,多个请求可以共享同一个引擎实例,通过in_flight_batching实现动态批处理。

# 推理调用示例
from tensorrt_llm.runtime import GenerationSession

session = GenerationSession(engine_buffer)
input_ids = tokenizer(["今天天气不错"], return_tensors="pt").input_ids.cuda()

output = session.generate(
    input_ids,
    max_new_tokens=128,
    temperature=0.7,
    top_k=50,
    top_p=0.9,
    end_id=tokenizer.eos_token_id
)
generated_text = tokenizer.decode(output[0])
关键性能点:KV Cache的显存管理是推理性能的核心。TensorRT-LLM允许通过kv_cache_config设置max_tokens(缓存容量),超出后采用LRU淘汰策略。对于长序列生成,KV Cache可能占据数十GB显存,需根据batch × seq_len × layers × hidden_size × 2估算。

3.4 案例实战:构建并部署一个GPT-2风格引擎

下面通过一个最小化案例,演示从HuggingFace的GPT2模型构建TensorRT-LLM引擎并执行推理的完整流程。该案例使用gpt2(124M参数)作为演示对象,可在单张消费级GPU上运行。

# 步骤1:安装与导入
pip install tensorrt-llm transformers

# 步骤2:权重转换
from tensorrt_llm.models import GPT2LMHeadModel
model = GPT2LMHeadModel.from_pretrained("gpt2", dtype="float16")
model.save_checkpoint("./gpt2_ckpt")

# 步骤3:构建引擎(使用默认配置)
from tensorrt_llm.builder import build_engine
engine = build_engine(
    model_dir="./gpt2_ckpt",
    max_batch_size=4,
    max_seq_len=1024,
    use_gpt_attention_plugin="float16"
)
with open("gpt2.engine", "wb") as f:
    f.write(engine.serialize())

# 步骤4:加载并推理
from tensorrt_llm.runtime import GenerationSession
from transformers import GPT2Tokenizer

tokenizer = GPT2Tokenizer.from_pretrained("gpt2")
session = GenerationSession(engine_buffer=open("gpt2.engine","rb").read())

prompt = "The future of AI is"
input_ids = tokenizer(prompt, return_tensors="pt").input_ids.cuda()
output = session.generate(input_ids, max_new_tokens=50, temperature=0.8)
print(tokenizer.decode(output[0]))

运行上述代码,预期输出类似"The future of AI is bright and full of possibilities..."。若构建过程中出现OutOfMemory,可降低max_batch_size或max_seq_len。若推理结果乱码,检查dtype是否与GPU支持一致(如float16需要GPU支持FP16计算)。

3.5 常见误区与复盘

  • 误区1:认为引擎文件与GPU型号无关。TensorRT引擎与GPU架构强绑定(如sm_80对应A100,sm_89对应RTX 4090)。在A100上构建的引擎无法在V100上运行,必须重新构建。
  • 误区2:忽略KV Cache显存估算。KV Cache大小与batch × seq_len × num_layers × hidden_size × 2 bytes成正比。例如LLaMA-7B(32层,hidden=4096)在batch=1、seq=2048时,KV Cache约1×2048×32×4096×2 = 512MB,多batch时线性增长。
  • 误区3:混淆max_seq_len与max_new_tokens。max_seq_len是引擎支持的最大总序列长度(输入+输出),而max_new_tokens是单次生成的最大新token数。若输入长度为100,max_new_tokens=2000,但max_seq_len=1024,则生成到924个token时就会报错。
  • 误区4:直接修改checkpoint中的权重文件。checkpoint目录中的权重是经过重排的二进制格式,不可直接编辑。如需修改权重,应回到HuggingFace格式修改后重新转换。
排障提示:当构建引擎报错Unsupported op时,通常意味着模型中有TensorRT-LLM尚未支持的算子。此时可尝试:① 升级TensorRT-LLM版本;② 使用--plugins启用自定义插件;③ 检查模型是否包含特殊结构(如MoE、Mamba等),需使用对应的模型定义文件。