欢迎光临
我们一直在努力

第19篇-模型格式转换全链路-从PyTorch到生产部署

【AIaaS 全栈架构师】第 19 篇:模型格式转换全链路——从 PyTorch 到生产部署格式

本系列定位:面向全栈架构师的 AIaaS 系统化教程。本篇为模块三"模型推理与部署优化"的第六篇,梳理模型格式转换的完整链路。技术栈以 Go 为主,Python/C++ 为辅。


本篇你将学到

  • 理解为什么 PyTorch checkpoint 不能直接用于生产部署,以及四大主流生产格式的定位
  • 掌握 Safetensors 格式的设计动机:如何防御 pickle 反序列化攻击
  • 理解 ONNX 作为跨框架中间表示的角色,以及它的能力边界
  • 掌握 GGUF 格式如何把模型权重、Tokenizer、量化元信息打包成单文件
  • 理解 TensorRT Engine 的编译时优化与 GPU 架构绑定特性
  • 建立格式选型决策框架与转换工具链的完整认知

学完本篇,你将能根据部署目标(vLLM、llama.cpp、TensorRT-LLM、ONNX Runtime)选择正确的目标格式,并规划从训练 checkpoint 到生产部署的完整转换链路。


一、为什么需要模型格式转换

1.1 训练格式与部署格式的鸿沟

训练阶段,几乎所有大模型都基于 PyTorch。训练结束后,你会得到一个 .pt / .pth / .bin 文件——本质都是 PyTorch 的 pickle 序列化,存储的是一个 state_dict(参数名到张量的字典)。

但生产部署时,这个格式几乎无人直接使用。原因如下:

问题说明
安全风险 pickle 反序列化可执行任意 Python 代码,加载不可信 .pth 等于远程代码执行
依赖重 加载 .pth 必须有完整 PyTorch + 模型定义代码,运行时体积大
加载慢 pickle 反序列化慢,大模型启动耗时数分钟
无量化信息 原始 checkpoint 只有 FP32/FP16/BF16,没有 INT4/INT8 量化元数据
无 Tokenizer 仅存权重,分词器、特殊 Token、对话模板需另外保存
跨框架难 TensorFlow/JAX/C++ 推理引擎读不了 pickle

因此从训练到生产,必须经过一次(或多次)格式转换。

1.2 四大生产部署格式全景

目前业界主流的生产部署格式有四种,分别对应不同的推理生态:

#mermaid-svg-09tsCWmeT5Vcr8Kg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-09tsCWmeT5Vcr8Kg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-09tsCWmeT5Vcr8Kg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-09tsCWmeT5Vcr8Kg .error-icon{fill:#552222;}#mermaid-svg-09tsCWmeT5Vcr8Kg .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-09tsCWmeT5Vcr8Kg .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-09tsCWmeT5Vcr8Kg .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-09tsCWmeT5Vcr8Kg .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-09tsCWmeT5Vcr8Kg .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-09tsCWmeT5Vcr8Kg .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-09tsCWmeT5Vcr8Kg .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-09tsCWmeT5Vcr8Kg .marker{fill:#333333;stroke:#333333;}#mermaid-svg-09tsCWmeT5Vcr8Kg .marker.cross{stroke:#333333;}#mermaid-svg-09tsCWmeT5Vcr8Kg svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-09tsCWmeT5Vcr8Kg p{margin:0;}#mermaid-svg-09tsCWmeT5Vcr8Kg .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-09tsCWmeT5Vcr8Kg .cluster-label text{fill:#333;}#mermaid-svg-09tsCWmeT5Vcr8Kg .cluster-label span{color:#333;}#mermaid-svg-09tsCWmeT5Vcr8Kg .cluster-label span p{background-color:transparent;}#mermaid-svg-09tsCWmeT5Vcr8Kg .label text,#mermaid-svg-09tsCWmeT5Vcr8Kg span{fill:#333;color:#333;}#mermaid-svg-09tsCWmeT5Vcr8Kg .node rect,#mermaid-svg-09tsCWmeT5Vcr8Kg .node circle,#mermaid-svg-09tsCWmeT5Vcr8Kg .node ellipse,#mermaid-svg-09tsCWmeT5Vcr8Kg .node polygon,#mermaid-svg-09tsCWmeT5Vcr8Kg .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-09tsCWmeT5Vcr8Kg .rough-node .label text,#mermaid-svg-09tsCWmeT5Vcr8Kg .node .label text,#mermaid-svg-09tsCWmeT5Vcr8Kg .image-shape .label,#mermaid-svg-09tsCWmeT5Vcr8Kg .icon-shape .label{text-anchor:middle;}#mermaid-svg-09tsCWmeT5Vcr8Kg .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-09tsCWmeT5Vcr8Kg .rough-node .label,#mermaid-svg-09tsCWmeT5Vcr8Kg .node .label,#mermaid-svg-09tsCWmeT5Vcr8Kg .image-shape .label,#mermaid-svg-09tsCWmeT5Vcr8Kg .icon-shape .label{text-align:center;}#mermaid-svg-09tsCWmeT5Vcr8Kg .node.clickable{cursor:pointer;}#mermaid-svg-09tsCWmeT5Vcr8Kg .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-09tsCWmeT5Vcr8Kg .arrowheadPath{fill:#333333;}#mermaid-svg-09tsCWmeT5Vcr8Kg .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-09tsCWmeT5Vcr8Kg .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-09tsCWmeT5Vcr8Kg .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-09tsCWmeT5Vcr8Kg .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-09tsCWmeT5Vcr8Kg .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-09tsCWmeT5Vcr8Kg .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-09tsCWmeT5Vcr8Kg .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-09tsCWmeT5Vcr8Kg .cluster text{fill:#333;}#mermaid-svg-09tsCWmeT5Vcr8Kg .cluster span{color:#333;}#mermaid-svg-09tsCWmeT5Vcr8Kg div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-09tsCWmeT5Vcr8Kg .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-09tsCWmeT5Vcr8Kg rect.text{fill:none;stroke-width:0;}#mermaid-svg-09tsCWmeT5Vcr8Kg .icon-shape,#mermaid-svg-09tsCWmeT5Vcr8Kg .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-09tsCWmeT5Vcr8Kg .icon-shape p,#mermaid-svg-09tsCWmeT5Vcr8Kg .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-09tsCWmeT5Vcr8Kg .icon-shape .label rect,#mermaid-svg-09tsCWmeT5Vcr8Kg .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-09tsCWmeT5Vcr8Kg .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-09tsCWmeT5Vcr8Kg .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-09tsCWmeT5Vcr8Kg :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

转换

转换

转换

转换

被加载

被加载

被加载

被加载

PyTorch 训练checkpoint .pt/.pth

Safetensors(.safetensors)

ONNX(.onnx)

GGUF(.gguf)

TensorRT Engine(.engine/.plan)

vLLM / TGI / Transformers

ONNX Runtime / Triton

llama.cpp / Ollama / LM Studio

TensorRT-LLM / Triton

格式主推方主要生态文件后缀
Safetensors HuggingFace HF Transformers / vLLM / TGI .safetensors
ONNX Microsoft + 社区 ONNX Runtime / Triton / OpenVINO .onnx
GGUF llama.cpp 社区 llama.cpp / Ollama / LM Studio .gguf
TensorRT Engine NVIDIA TensorRT-LLM / Triton .engine / .plan

下面逐个深入。


二、Safetensors:HuggingFace 的安全格式

2.1 设计动机:防御 pickle 攻击

PyTorch 默认用 pickle 序列化模型。Pickle 的本质是一个图灵完备的指令流——反序列化时可以执行任意 Python 代码。这意味着:

# 这是一个"恶意"的 .pth 文件
import torch
import os

class MaliciousModel:
def __reduce__(self):
return (os.system, ("rm -rf /",))

# 保存后,任何人 torch.load() 都会执行 rm -rf /
torch.save(MaliciousModel(), "evil.pth")

历史上已发生过多起通过 HuggingFace Hub 分发恶意模型的安全事件。Safetensors 就是为解决这个问题而设计的。

2.2 文件结构

Safetensors 是一个极简的二进制格式,文件结构如下:

[Header 长度(u64, 小端)] [Header JSON] [张量数据…]

Header 是一段 JSON,描述每个张量的:

  • 名称(如 transformer.h.0.attn.weight)
  • 数据类型(F32 / F16 / BF16 / I8 / I4 …)
  • 形状(如 [4096, 4096])
  • 在文件中的字节偏移量([start, end])

关键安全特性:

  • Header 是纯 JSON,没有可执行代码
  • 张量数据是纯二进制,按偏移量直接 mmap 读取
  • 反序列化过程不调用任何 Python 对象方法
  • 加载不可信 Safetensors 文件最多读到脏数据,不会执行代码
  • 2.3 加载速度优势

    由于 Safetensors 是 mmap 友好的零拷贝格式,加载速度比 pickle 快得多:

    格式Llama-7B 加载耗时内存占用
    PyTorch .bin(pickle) ~25s 峰值 28GB(反序列化副本)
    Safetensors ~3s 峰值 14GB(mmap 零拷贝)

    mmap 的另一个好处:多进程共享同一份权重。在 vLLM/TGI 等多 worker 推理场景下,多个进程可以映射同一个 Safetensors 文件,物理内存只占一份。

    2.4 使用方式

    保存模型为 Safetensors:

    from transformers import AutoModelForCausalLM, AutoTokenizer

    model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-3-8B")
    model.save_pretrained("./llama-8b-safetensors", safe_serialization=True)
    # 默认就是 safe_serialization=True,会生成 model.safetensors

    加载 Safetensors:

    # Transformers 自动识别
    model = AutoModelForCausalLM.from_pretrained("./llama-8b-safetensors")

    # 也可以用 safetensors 库直接读张量
    from safetensors.torch import load_file
    tensors = load_file("./model.safetensors")
    # tensors 是 dict[str, torch.Tensor]

    2.5 Safetensors 的局限

    Safetensors 不是万能的:

    • 只存张量,不存计算图:必须配合模型代码才能用。脱离了 Transformers 库,Safetensors 文件本身不能推理
    • 不支持量化元信息:只能存原始张量,INT4/INT8 量化的元数据(scale/zero-point)需另存
    • 无 Tokenizer:分词器仍需另行保存(HF 用 tokenizer.json)

    因此 Safetensors 适合作为 HF 生态内的中间格式,而非端到端部署格式。


    三、ONNX:跨框架的中间表示

    3.1 设计目标:框架无关的标准算子集

    ONNX(Open Neural Network Exchange)由微软和脸书(现 Meta)在 2017 年联合推出,目标是定义一套跨框架的标准算子集和图格式。

    核心思想:无论你用 PyTorch、TensorFlow、JAX 还是 PaddlePaddle 训练,都能导出成 ONNX;无论你用 ONNX Runtime、TensorRT、OpenVINO 还是 CoreML 部署,都能加载 ONNX。

    #mermaid-svg-RkzlWVISKHU2mEHY{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-RkzlWVISKHU2mEHY .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-RkzlWVISKHU2mEHY .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-RkzlWVISKHU2mEHY .error-icon{fill:#552222;}#mermaid-svg-RkzlWVISKHU2mEHY .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-RkzlWVISKHU2mEHY .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-RkzlWVISKHU2mEHY .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-RkzlWVISKHU2mEHY .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-RkzlWVISKHU2mEHY .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-RkzlWVISKHU2mEHY .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-RkzlWVISKHU2mEHY .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-RkzlWVISKHU2mEHY .marker{fill:#333333;stroke:#333333;}#mermaid-svg-RkzlWVISKHU2mEHY .marker.cross{stroke:#333333;}#mermaid-svg-RkzlWVISKHU2mEHY svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-RkzlWVISKHU2mEHY p{margin:0;}#mermaid-svg-RkzlWVISKHU2mEHY .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-RkzlWVISKHU2mEHY .cluster-label text{fill:#333;}#mermaid-svg-RkzlWVISKHU2mEHY .cluster-label span{color:#333;}#mermaid-svg-RkzlWVISKHU2mEHY .cluster-label span p{background-color:transparent;}#mermaid-svg-RkzlWVISKHU2mEHY .label text,#mermaid-svg-RkzlWVISKHU2mEHY span{fill:#333;color:#333;}#mermaid-svg-RkzlWVISKHU2mEHY .node rect,#mermaid-svg-RkzlWVISKHU2mEHY .node circle,#mermaid-svg-RkzlWVISKHU2mEHY .node ellipse,#mermaid-svg-RkzlWVISKHU2mEHY .node polygon,#mermaid-svg-RkzlWVISKHU2mEHY .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-RkzlWVISKHU2mEHY .rough-node .label text,#mermaid-svg-RkzlWVISKHU2mEHY .node .label text,#mermaid-svg-RkzlWVISKHU2mEHY .image-shape .label,#mermaid-svg-RkzlWVISKHU2mEHY .icon-shape .label{text-anchor:middle;}#mermaid-svg-RkzlWVISKHU2mEHY .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-RkzlWVISKHU2mEHY .rough-node .label,#mermaid-svg-RkzlWVISKHU2mEHY .node .label,#mermaid-svg-RkzlWVISKHU2mEHY .image-shape .label,#mermaid-svg-RkzlWVISKHU2mEHY .icon-shape .label{text-align:center;}#mermaid-svg-RkzlWVISKHU2mEHY .node.clickable{cursor:pointer;}#mermaid-svg-RkzlWVISKHU2mEHY .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-RkzlWVISKHU2mEHY .arrowheadPath{fill:#333333;}#mermaid-svg-RkzlWVISKHU2mEHY .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-RkzlWVISKHU2mEHY .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-RkzlWVISKHU2mEHY .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-RkzlWVISKHU2mEHY .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-RkzlWVISKHU2mEHY .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-RkzlWVISKHU2mEHY .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-RkzlWVISKHU2mEHY .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-RkzlWVISKHU2mEHY .cluster text{fill:#333;}#mermaid-svg-RkzlWVISKHU2mEHY .cluster span{color:#333;}#mermaid-svg-RkzlWVISKHU2mEHY div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-RkzlWVISKHU2mEHY .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-RkzlWVISKHU2mEHY rect.text{fill:none;stroke-width:0;}#mermaid-svg-RkzlWVISKHU2mEHY .icon-shape,#mermaid-svg-RkzlWVISKHU2mEHY .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-RkzlWVISKHU2mEHY .icon-shape p,#mermaid-svg-RkzlWVISKHU2mEHY .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-RkzlWVISKHU2mEHY .icon-shape .label rect,#mermaid-svg-RkzlWVISKHU2mEHY .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-RkzlWVISKHU2mEHY .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-RkzlWVISKHU2mEHY .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-RkzlWVISKHU2mEHY :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    torch.onnx.export

    tf2onnx

    flax.to_onnx

    paddle2onnx

    加载

    加载

    加载

    加载

    PyTorch

    ONNX 文件(.onnx)

    TensorFlow

    JAX/Flax

    PaddlePaddle

    ONNX Runtime

    TensorRT

    OpenVINO

    CoreML

    3.2 ONNX 文件结构

    ONNX 是基于 Protocol Buffers 的二进制格式,主要组成:

    • Graph:计算图,由节点(Node)和边(Tensor)组成
    • Node:一个算子调用,如 Conv / MatMul / Softmax
    • Initializer:常量张量(即模型权重)
    • Operator Set(opset):算子集版本,不同 opset 支持不同算子

    可视化 ONNX 文件最常用的工具是 Netron,能直观展示整个计算图。

    3.3 导出流程

    import torch
    from transformers import AutoModelForCausalLM

    model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-3-8B")
    model.eval()

    dummy_input = torch.randint(0, 32000, (1, 32))

    torch.onnx.export(
    model,
    dummy_input,
    "llama-8b.onnx",
    input_names=["input_ids"],
    output_names=["logits"],
    dynamic_axes={"input_ids": {0: "batch", 1: "sequence"}},
    opset_version=16,
    )

    dynamic_axes 让某个维度可变(如 batch、sequence),运行时可以传不同形状的输入。

    3.4 ONNX 量化

    ONNX Runtime 提供了量化工具,能将 ONNX 模型动态/静态量化:

    from onnxruntime.quantization import quantize_dynamic, QuantType

    quantize_dynamic(
    model_input="llama-8b.onnx",
    model_output="llama-8b-int8.onnx",
    weight_type=QuantType.QInt8,
    )

    ONNX 量化的优势是跨硬件通用:同一份 INT8 ONNX 可以跑在 CPU、GPU、NPU 上。

    3.5 ONNX 在大模型场景的局限

    ONNX 在 CNN 时代(ResNet/YOLO)非常成功,但大语言模型时代它的角色大幅萎缩:

    问题说明
    大模型导出困难 几百层 Transformer 导出 ONNX 经常失败或不完整
    动态形状支持弱 LLM 的 KV Cache 是动态增长,ONNX 表达吃力
    推理性能不如专用引擎 ONNX Runtime 跑 LLM 的吞吐远不及 vLLM/TensorRT-LLM
    不支持 Continuous Batching ONNX Runtime 没有原生的请求调度
    文件巨大 完整 LLM 的 ONNX 文件数十 GB,加载极慢

    结论:ONNX 适合中小型模型(如 BERT、ResNet、Whisper encoder)的跨平台部署,不推荐用于大语言模型推理。LLM 推理应优先选择 Safetensors + vLLM、GGUF + llama.cpp、TensorRT Engine + TensorRT-LLM。


    四、GGUF:llama.cpp 的原生格式

    4.1 设计哲学:单文件自包含

    GGUF(GPT-Generated Unified Format)由 llama.cpp 作者 Georgi Gerganov 设计,目标是一个文件搞定一切:

    • 模型权重(含量化)
    • Tokenizer 配置
    • 模型超参数(层数、注意力头数、上下文长度等)
    • Chat 模板(用于对话格式化)
    • 量化元数据(每层的 scale 和 zero-point)

    对比 Safetensors 需要一整套文件(config.json + model.safetensors + tokenizer.json + …),GGUF 把所有东西塞进一个文件,方便分发和管理。

    4.2 GGUF 的演化谱系

    #mermaid-svg-HsAHSwOevkFUsnqZ{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-HsAHSwOevkFUsnqZ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-HsAHSwOevkFUsnqZ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-HsAHSwOevkFUsnqZ .error-icon{fill:#552222;}#mermaid-svg-HsAHSwOevkFUsnqZ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-HsAHSwOevkFUsnqZ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-HsAHSwOevkFUsnqZ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-HsAHSwOevkFUsnqZ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-HsAHSwOevkFUsnqZ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-HsAHSwOevkFUsnqZ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-HsAHSwOevkFUsnqZ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-HsAHSwOevkFUsnqZ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-HsAHSwOevkFUsnqZ .marker.cross{stroke:#333333;}#mermaid-svg-HsAHSwOevkFUsnqZ svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-HsAHSwOevkFUsnqZ p{margin:0;}#mermaid-svg-HsAHSwOevkFUsnqZ .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-HsAHSwOevkFUsnqZ .cluster-label text{fill:#333;}#mermaid-svg-HsAHSwOevkFUsnqZ .cluster-label span{color:#333;}#mermaid-svg-HsAHSwOevkFUsnqZ .cluster-label span p{background-color:transparent;}#mermaid-svg-HsAHSwOevkFUsnqZ .label text,#mermaid-svg-HsAHSwOevkFUsnqZ span{fill:#333;color:#333;}#mermaid-svg-HsAHSwOevkFUsnqZ .node rect,#mermaid-svg-HsAHSwOevkFUsnqZ .node circle,#mermaid-svg-HsAHSwOevkFUsnqZ .node ellipse,#mermaid-svg-HsAHSwOevkFUsnqZ .node polygon,#mermaid-svg-HsAHSwOevkFUsnqZ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-HsAHSwOevkFUsnqZ .rough-node .label text,#mermaid-svg-HsAHSwOevkFUsnqZ .node .label text,#mermaid-svg-HsAHSwOevkFUsnqZ .image-shape .label,#mermaid-svg-HsAHSwOevkFUsnqZ .icon-shape .label{text-anchor:middle;}#mermaid-svg-HsAHSwOevkFUsnqZ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-HsAHSwOevkFUsnqZ .rough-node .label,#mermaid-svg-HsAHSwOevkFUsnqZ .node .label,#mermaid-svg-HsAHSwOevkFUsnqZ .image-shape .label,#mermaid-svg-HsAHSwOevkFUsnqZ .icon-shape .label{text-align:center;}#mermaid-svg-HsAHSwOevkFUsnqZ .node.clickable{cursor:pointer;}#mermaid-svg-HsAHSwOevkFUsnqZ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-HsAHSwOevkFUsnqZ .arrowheadPath{fill:#333333;}#mermaid-svg-HsAHSwOevkFUsnqZ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-HsAHSwOevkFUsnqZ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-HsAHSwOevkFUsnqZ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-HsAHSwOevkFUsnqZ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-HsAHSwOevkFUsnqZ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-HsAHSwOevkFUsnqZ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-HsAHSwOevkFUsnqZ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-HsAHSwOevkFUsnqZ .cluster text{fill:#333;}#mermaid-svg-HsAHSwOevkFUsnqZ .cluster span{color:#333;}#mermaid-svg-HsAHSwOevkFUsnqZ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-HsAHSwOevkFUsnqZ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-HsAHSwOevkFUsnqZ rect.text{fill:none;stroke-width:0;}#mermaid-svg-HsAHSwOevkFUsnqZ .icon-shape,#mermaid-svg-HsAHSwOevkFUsnqZ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-HsAHSwOevkFUsnqZ .icon-shape p,#mermaid-svg-HsAHSwOevkFUsnqZ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-HsAHSwOevkFUsnqZ .icon-shape .label rect,#mermaid-svg-HsAHSwOevkFUsnqZ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-HsAHSwOevkFUsnqZ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-HsAHSwOevkFUsnqZ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-HsAHSwOevkFUsnqZ :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    重构

    扩展

    已被淘汰,新模型不再使用

    GGML(2023初)

    GGUF v1(2023年中)

    GGUF v2/v3(2023末至今)

    废弃

    老格式 GGML 已被废弃,新模型只发布 GGUF。GGUF 的关键改进是可扩展的 key-value 元数据结构——添加新字段不破坏旧版本兼容性。

    4.3 量化方案

    GGUF 内置了一套丰富的量化方案,称为 k-quants(第 17 篇详细讨论过)。常用方案:

    量化名比特/参数大小(7B 模型)质量损失推荐场景
    Q8_0 8 bit 7.0 GB 极小 质量优先
    Q6_K 6 bit 5.5 GB 很小 平衡
    Q5_K_M 5 bit 4.8 GB 推荐
    Q4_K_M 4 bit 4.1 GB 中等 最常用
    Q4_0 4 bit 3.8 GB 较大 极致压缩
    Q3_K_M 3 bit 3.3 GB 明显 显存极紧
    Q2_K 2 bit 2.7 GB 较大 极限场景

    _K_M 后缀(Medium)是混合精度变体:注意力层用高精度,MLP 用低精度,整体质量比纯 Q4_0 更好。

    4.4 转换工具链

    从 HuggingFace 模型转 GGUF 的标准流程:

    # 1. 克隆 llama.cpp
    git clone https://github.com/ggerganov/llama.cpp
    cd llama.cpp

    # 2. 安装 Python 依赖
    pip install -r requirements.txt

    # 3. 转换(FP16 中间格式)
    python convert_hf_to_gguf.py \\
    /path/to/hf-model \\
    –outfile model-fp16.gguf \\
    –outtype f16

    # 4. 量化(k-quants)
    ./llama-quantize model-fp16.gguf model-q4_k_m.gguf Q4_K_M

    # 5. 验证
    ./llama-cli -m model-q4_k_m.gguf -p "你好" -n 32

    关键点:

    • convert_hf_to_gguf.py 支持 Llama / Qwen / Mistral / Yi / DeepSeek 等主流架构
    • 量化前必须先转成 FP16 GGUF 中间格式
    • 不同量化级别用同一个 FP16 中间文件生成,便于对比

    4.5 GGUF 的运行生态

    GGUF 已成为端侧 LLM 的事实标准:

    运行时平台特点
    llama.cpp 全平台 原生实现,C++ 编写,支持 CPU/GPU 混合
    Ollama macOS/Linux/Windows 基于 llama.cpp,自动管理模型,类似 Docker 体验
    LM Studio macOS/Windows 桌面 GUI,从 Hub 下载 GGUF 即用
    GPT4All 全平台 桌面应用,内置模型库
    llamafile 全平台 单可执行文件(GGUF + 运行时打包)

    4.6 GGUF 的 CPU/GPU 混合推理

    GGUF 的杀手锏是层卸载(Layer Offload):模型太大 GPU 放不下时,可以把一部分层放 GPU、其余放 CPU,逐步推理。

    # ngl = number of GPU layers
    ./llama-cli -m model-q4_k_m.gguf -p "你好" -n 32 -ngl 20

    比如 70B Q4 模型(35GB),如果 GPU 只有 16GB 显存,可以把前 20 层放 GPU、剩余 40 层放 CPU 内存。速度虽不如全 GPU,但能跑起来——这是其他格式做不到的。


    五、TensorRT Engine:NVIDIA 的极致优化格式

    5.1 设计目标:极致推理性能

    TensorRT 是 NVIDIA 推出的深度学习推理优化器,其输出是 Engine 文件(也叫 Plan 文件)。Engine 是经过深度优化的二进制,包含:

    • 算子融合(Kernel Fusion):多个小算子合并成一个大算子,减少 kernel 启动开销
    • 精度校准(Precision Calibration):自动选择 FP32/FP16/INT8
    • Kernel 自动调优:针对当前 GPU 选择最快的 kernel 实现
    • 显存规划:预分配所有中间张量内存,运行时零分配

    5.2 Engine 的关键特性:硬件绑定

    TensorRT Engine 是编译时绑定 GPU 架构的。这意味着:

    维度是否绑定
    GPU 架构(如 Ampere/Hopper) 绑定
    具体型号(如 A100 vs A10) 不绑定(同架构通用)
    CUDA 版本 绑定
    TensorRT 版本 绑定
    Batch Size 部分绑定(需指定 optimization profile)

    实践影响:

    • 在 A100 上编译的 Engine,不能直接拿到 H100 上跑
    • 升级 TensorRT 版本后,旧 Engine 可能失效,需重新编译
    • 这与 Safetensors/GGUF 的"一份文件到处跑"形成鲜明对比

    5.3 编译流程

    #mermaid-svg-lL13Bxf1ABff084V{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-lL13Bxf1ABff084V .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-lL13Bxf1ABff084V .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-lL13Bxf1ABff084V .error-icon{fill:#552222;}#mermaid-svg-lL13Bxf1ABff084V .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-lL13Bxf1ABff084V .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-lL13Bxf1ABff084V .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-lL13Bxf1ABff084V .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-lL13Bxf1ABff084V .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-lL13Bxf1ABff084V .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-lL13Bxf1ABff084V .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-lL13Bxf1ABff084V .marker{fill:#333333;stroke:#333333;}#mermaid-svg-lL13Bxf1ABff084V .marker.cross{stroke:#333333;}#mermaid-svg-lL13Bxf1ABff084V svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-lL13Bxf1ABff084V p{margin:0;}#mermaid-svg-lL13Bxf1ABff084V .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-lL13Bxf1ABff084V .cluster-label text{fill:#333;}#mermaid-svg-lL13Bxf1ABff084V .cluster-label span{color:#333;}#mermaid-svg-lL13Bxf1ABff084V .cluster-label span p{background-color:transparent;}#mermaid-svg-lL13Bxf1ABff084V .label text,#mermaid-svg-lL13Bxf1ABff084V span{fill:#333;color:#333;}#mermaid-svg-lL13Bxf1ABff084V .node rect,#mermaid-svg-lL13Bxf1ABff084V .node circle,#mermaid-svg-lL13Bxf1ABff084V .node ellipse,#mermaid-svg-lL13Bxf1ABff084V .node polygon,#mermaid-svg-lL13Bxf1ABff084V .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-lL13Bxf1ABff084V .rough-node .label text,#mermaid-svg-lL13Bxf1ABff084V .node .label text,#mermaid-svg-lL13Bxf1ABff084V .image-shape .label,#mermaid-svg-lL13Bxf1ABff084V .icon-shape .label{text-anchor:middle;}#mermaid-svg-lL13Bxf1ABff084V .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-lL13Bxf1ABff084V .rough-node .label,#mermaid-svg-lL13Bxf1ABff084V .node .label,#mermaid-svg-lL13Bxf1ABff084V .image-shape .label,#mermaid-svg-lL13Bxf1ABff084V .icon-shape .label{text-align:center;}#mermaid-svg-lL13Bxf1ABff084V .node.clickable{cursor:pointer;}#mermaid-svg-lL13Bxf1ABff084V .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-lL13Bxf1ABff084V .arrowheadPath{fill:#333333;}#mermaid-svg-lL13Bxf1ABff084V .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-lL13Bxf1ABff084V .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-lL13Bxf1ABff084V .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-lL13Bxf1ABff084V .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-lL13Bxf1ABff084V .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-lL13Bxf1ABff084V .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-lL13Bxf1ABff084V .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-lL13Bxf1ABff084V .cluster text{fill:#333;}#mermaid-svg-lL13Bxf1ABff084V .cluster span{color:#333;}#mermaid-svg-lL13Bxf1ABff084V div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-lL13Bxf1ABff084V .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-lL13Bxf1ABff084V rect.text{fill:none;stroke-width:0;}#mermaid-svg-lL13Bxf1ABff084V .icon-shape,#mermaid-svg-lL13Bxf1ABff084V .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-lL13Bxf1ABff084V .icon-shape p,#mermaid-svg-lL13Bxf1ABff084V .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-lL13Bxf1ABff084V .icon-shape .label rect,#mermaid-svg-lL13Bxf1ABff084V .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-lL13Bxf1ABff084V .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-lL13Bxf1ABff084V .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-lL13Bxf1ABff084V :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    转换

    trtexec 编译

    加载

    PyTorch/.pth或 ONNX

    ONNX 中间格式(.onnx)

    TensorRT Engine(.engine)

    TensorRT Runtime推理

    使用 trtexec 命令行工具编译:

    # 从 ONNX 编译 Engine
    trtexec \\
    –onnx=model.onnx \\
    –saveEngine=model.engine \\
    –fp16 \\
    –minShapes=input_ids:1×32 \\
    –optShapes=input_ids:8×512 \\
    –maxShapes=input_ids:32×2048 \\
    –verbose

    关键参数:

    • –fp16 / –int8:选择精度
    • –minShapes / –optShapes / –maxShapes:定义动态形状范围(optimization profile),编译器据此选择最优 kernel
    • –workspace:编译期最大 workspace 显存

    5.4 TensorRT-LLM:针对 LLM 的专用方案

    通用 TensorRT 编译 LLM 非常复杂(要手动实现 KV Cache、Attention 等算子)。NVIDIA 推出了 TensorRT-LLM,专门为 LLM 推理优化:

    • 内置 FlashAttention、PagedAttention 的 TensorRT 实现
    • 自动处理 KV Cache 管理
    • 支持 Continuous Batching、投机解码
    • 提供 Python API 简化编译

    import tensorrt_llm
    from tensorrt_llm.models import LLaMAForCausalLM

    # 编译 Llama 为 TensorRT Engine
    builder = tensorrt_llm.Builder()
    model = LLaMAForCausalLM.from_hugging_face("meta-llama/Llama-3-8B")
    engine = builder.build(
    model,
    precision="fp16",
    max_batch_size=32,
    max_seq_len=4096,
    )
    engine.save("llama-8b.engine")

    TensorRT-LLM 在 NVIDIA GPU 上的吞吐量通常是 vLLM 的 1.2-1.5 倍(同硬件),是追求极致性能时的首选。

    5.5 Engine 的局限

    局限说明
    硬件绑定 跨架构迁移需重新编译,编译耗时数十分钟到数小时
    版本绑定 TensorRT 升级后旧 Engine 可能不兼容
    闭源 TensorRT 本身闭源,调试困难
    仅 NVIDIA 不能在 AMD/Intel GPU 或 CPU 上运行
    不可读 Engine 是纯二进制,无法反推模型结构

    六、四大格式横向对比

    维度SafetensorsONNXGGUFTensorRT Engine
    设计目标 安全的权重存储 跨框架中间表示 端侧单文件部署 极致 NVIDIA GPU 性能
    是否含计算图 否(仅权重) 是(完整计算图) 否(权重+超参) 是(已编译)
    是否含 Tokenizer
    是否含量化元数据 部分 是(k-quants)
    文件大小(7B FP16) ~14 GB ~14 GB+图开销 ~14 GB / ~4 GB(Q4) ~14 GB+优化数据
    加载速度 快(mmap) 快(已编译)
    推理性能 取决于引擎 中等 中等(CPU 优秀) 极致(NVIDIA)
    跨硬件 取决于引擎 优秀 优秀(CPU/GPU 混合) 仅 NVIDIA GPU
    安全性 高(无代码执行) 中等
    可读性 中(Header JSON 可读) 高(Netron 可视化) 无(纯二进制)
    生态绑定 HuggingFace 跨平台 llama.cpp NVIDIA
    适合模型类型 大模型 中小模型 大模型 大模型(NVIDIA)

    七、格式选型决策树

    #mermaid-svg-f94hUfNLMBXH4cFh{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-f94hUfNLMBXH4cFh .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-f94hUfNLMBXH4cFh .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-f94hUfNLMBXH4cFh .error-icon{fill:#552222;}#mermaid-svg-f94hUfNLMBXH4cFh .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-f94hUfNLMBXH4cFh .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-f94hUfNLMBXH4cFh .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-f94hUfNLMBXH4cFh .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-f94hUfNLMBXH4cFh .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-f94hUfNLMBXH4cFh .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-f94hUfNLMBXH4cFh .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-f94hUfNLMBXH4cFh .marker{fill:#333333;stroke:#333333;}#mermaid-svg-f94hUfNLMBXH4cFh .marker.cross{stroke:#333333;}#mermaid-svg-f94hUfNLMBXH4cFh svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-f94hUfNLMBXH4cFh p{margin:0;}#mermaid-svg-f94hUfNLMBXH4cFh .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-f94hUfNLMBXH4cFh .cluster-label text{fill:#333;}#mermaid-svg-f94hUfNLMBXH4cFh .cluster-label span{color:#333;}#mermaid-svg-f94hUfNLMBXH4cFh .cluster-label span p{background-color:transparent;}#mermaid-svg-f94hUfNLMBXH4cFh .label text,#mermaid-svg-f94hUfNLMBXH4cFh span{fill:#333;color:#333;}#mermaid-svg-f94hUfNLMBXH4cFh .node rect,#mermaid-svg-f94hUfNLMBXH4cFh .node circle,#mermaid-svg-f94hUfNLMBXH4cFh .node ellipse,#mermaid-svg-f94hUfNLMBXH4cFh .node polygon,#mermaid-svg-f94hUfNLMBXH4cFh .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-f94hUfNLMBXH4cFh .rough-node .label text,#mermaid-svg-f94hUfNLMBXH4cFh .node .label text,#mermaid-svg-f94hUfNLMBXH4cFh .image-shape .label,#mermaid-svg-f94hUfNLMBXH4cFh .icon-shape .label{text-anchor:middle;}#mermaid-svg-f94hUfNLMBXH4cFh .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-f94hUfNLMBXH4cFh .rough-node .label,#mermaid-svg-f94hUfNLMBXH4cFh .node .label,#mermaid-svg-f94hUfNLMBXH4cFh .image-shape .label,#mermaid-svg-f94hUfNLMBXH4cFh .icon-shape .label{text-align:center;}#mermaid-svg-f94hUfNLMBXH4cFh .node.clickable{cursor:pointer;}#mermaid-svg-f94hUfNLMBXH4cFh .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-f94hUfNLMBXH4cFh .arrowheadPath{fill:#333333;}#mermaid-svg-f94hUfNLMBXH4cFh .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-f94hUfNLMBXH4cFh .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-f94hUfNLMBXH4cFh .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-f94hUfNLMBXH4cFh .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-f94hUfNLMBXH4cFh .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-f94hUfNLMBXH4cFh .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-f94hUfNLMBXH4cFh .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-f94hUfNLMBXH4cFh .cluster text{fill:#333;}#mermaid-svg-f94hUfNLMBXH4cFh .cluster span{color:#333;}#mermaid-svg-f94hUfNLMBXH4cFh div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-f94hUfNLMBXH4cFh .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-f94hUfNLMBXH4cFh rect.text{fill:none;stroke-width:0;}#mermaid-svg-f94hUfNLMBXH4cFh .icon-shape,#mermaid-svg-f94hUfNLMBXH4cFh .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-f94hUfNLMBXH4cFh .icon-shape p,#mermaid-svg-f94hUfNLMBXH4cFh .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-f94hUfNLMBXH4cFh .icon-shape .label rect,#mermaid-svg-f94hUfNLMBXH4cFh .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-f94hUfNLMBXH4cFh .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-f94hUfNLMBXH4cFh .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-f94hUfNLMBXH4cFh :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    NVIDIA 服务器追求极致性能

    NVIDIA 服务器通用方案

    CPU 或消费级 GPU端侧部署

    跨硬件/嵌入式中小模型

    有训练好的 PyTorch 模型需要部署

    部署目标?

    TensorRT Engine用 TensorRT-LLM 编译

    Safetensors用 vLLM/TGI 加载

    GGUF用 llama.cpp/Ollama

    ONNX用 ONNX Runtime

    注意:硬件绑定换 GPU 架构需重编译

    主流方案HF 模型默认 Safetensors

    端侧事实标准单文件分发

    不推荐用于大语言模型

    7.1 典型场景对照

    场景 A:云端 LLM 服务(A100/H100 集群)

    • 目标格式:Safetensors(基础) + 可选 TensorRT Engine(极致)
    • 工具链:HF Transformers 训练 → save_pretrained(safe_serialization=True) → vLLM 加载
    • 极致优化:用 TensorRT-LLM 编译 Engine,吞吐再提 20-50%

    场景 B:私有化部署(消费级 GPU 或纯 CPU)

    • 目标格式:GGUF(Q4_K_M 或 Q5_K_M)
    • 工具链:HF 模型 → convert_hf_to_gguf.py → llama-quantize → Ollama 分发
    • 优势:单文件、跨平台、CPU/GPU 混合

    场景 C:移动端/嵌入式(手机、边缘设备)

    • 目标格式:ONNX 或专用格式(CoreML/TFLite)
    • 工具链:PyTorch → torch.onnx.export → ONNX Runtime Mobile
    • 局限:仅适合小模型(< 1B 参数)

    场景 D:多框架/多硬件通用

    • 目标格式:ONNX
    • 工具链:任意框架 → ONNX → 多种运行时
    • 局限:LLM 场景不推荐

    八、完整转换链路实战

    8.1 从 HF 模型到 vLLM(Safetensors 链路)

    最简单的链路,HF Hub 上大多数模型已是 Safetensors 格式:

    # 直接用 vLLM 启动
    python -m vllm.entrypoints.openai.api_server \\
    –model meta-llama/Llama-3-8B-Instruct \\
    –tensor-parallel-size 1

    # vLLM 自动从 HF Hub 下载并加载 Safetensors

    如果你的模型是自训练的,需先保存为 Safetensors:

    model.save_pretrained("./my-model", safe_serialization=True)
    # 生成: config.json, model.safetensors, tokenizer.json

    8.2 从 HF 模型到 llama.cpp(GGUF 链路)

    # 1. 下载 HF 模型
    huggingface-cli download meta-llama/Llama-3-8B-Instruct \\
    –local-dir ./llama-3-8b

    # 2. 转 FP16 GGUF
    cd llama.cpp
    python convert_hf_to_gguf.py ../llama-3-8b \\
    –outfile ../llama-3-8b-fp16.gguf \\
    –outtype f16

    # 3. 量化
    ./llama-quantize ../llama-3-8b-fp16.gguf ../llama-3-8b-q4_k_m.gguf Q4_K_M

    # 4. 运行
    ./llama-cli -m ../llama-3-8b-q4_k_m.gguf -p "你好" -ngl 99

    # 5. 或用 Ollama 导入
    cat > Modelfile <<EOF
    FROM ./llama-3-8b-q4_k_m.gguf
    EOF

    ollama create my-llama -f Modelfile
    ollama run my-llama

    8.3 从 HF 模型到 TensorRT-LLM(Engine 链路)

    最复杂的链路:

    # 1. 克隆 TensorRT-LLM
    git clone https://github.com/NVIDIA/TensorRT-LLM.git
    cd TensorRT-LLM

    # 2. 用提供的脚本转换
    python examples/llama/convert_checkpoint.py \\
    –model_dir ./llama-3-8b-hf \\
    –output_dir ./llama-3-8b-trt-checkpoint \\
    –dtype float16

    # 3. 编译 Engine
    python examples/llama/build.py \\
    –checkpoint_dir ./llama-3-8b-trt-checkpoint \\
    –output_dir ./llama-3-8b-engine \\
    –use_gpt_attention_plugin float16 \\
    –use_gemm_plugin float16 \\
    –max_batch_size 32 \\
    –max_input_len 2048 \\
    –max_output_len 512

    # 4. 运行
    python examples/llama/run.py \\
    –engine_dir ./llama-3-8b-engine \\
    –tokenizer_dir ./llama-3-8b-hf

    8.4 链路对比

    链路转换难度转换耗时(7B 模型)部署难度推理性能
    Safetensors → vLLM 极简 0(HF 已是此格式) 极简 优秀
    HF → GGUF → llama.cpp 简单 ~10 分钟 简单 中等(CPU 优秀)
    HF → ONNX 中等 ~30 分钟 中等 中等
    HF → TensorRT Engine 复杂 ~1-2 小时 复杂 极致

    九、格式转换的常见坑

    9.1 Tokenizer 不一致

    坑:转换格式后,Tokenizer 配置丢失或不一致,导致输出乱码或质量下降。

    表现:

    • GGUF 转换后,特殊 Token(如 <|im_start|>)未被识别
    • Safetensors 跨库加载时,BOS/EOS Token 配置不一致
    • TensorRT-LLM 编译时未指定正确 tokenizer

    对策:

    • GGUF 转换用最新的 convert_hf_to_gguf.py,它会自动从 tokenizer_config.json 读取特殊 Token
    • 部署后用固定 prompt 测试,确认 BOS/EOS 行为正确
    • TensorRT-LLM 需显式指定 –tokenizer_dir

    9.2 量化精度回退

    坑:跨格式转换时量化精度意外回退到 FP16。

    表现:

    • GGUF Q4 模型转 ONNX 后变成 FP16(丢失量化)
    • ONNX INT8 模型转 TensorRT 后精度异常

    对策:

    • 转换前后用 llama-cli 或推理脚本对比 perplexity,差异应 < 1%
    • 不同格式之间不要直接互转量化模型,应回到 FP16 中间格式重新量化

    9.3 TensorRT Engine 跨机器失效

    坑:在开发机编译的 Engine,部署到生产机报错。

    表现:

    [TensorRT] INTERNAL ERROR: Assertion failed: … engine expects SM 8.6, but device is SM 8.0

    对策:

    • Engine 必须在目标硬件上编译
    • CI/CD 流水线用 Docker 镜像固定 TensorRT 版本,编译时挂载目标 GPU
    • 或者:分发 ONNX/Safetensors,在目标机器上现场编译 Engine

    9.4 大模型分片问题

    坑:Safetensors 大模型通常分片存储(model-00001-of-00005.safetensors),转换工具可能不识别分片。

    对策:

    • 用 HF Transformers 的 from_pretrained 自动合并分片
    • GGUF 转换脚本已支持分片输入
    • TensorRT-LLM 的 convert_checkpoint.py 也支持

    9.5 BF16 兼容性

    坑:BF16(Brain Float 16)模型在只支持 FP16 的硬件/格式上报错。

    表现:

    • BF16 模型转 GGUF Q4 后精度异常
    • BF16 ONNX 在旧版 ONNX Runtime 报错

    对策:

    • 转换前先 torch.float16 转一下(精度损失极小)
    • GGUF 转换脚本用 –outtype f16 显式指定 FP16

    十、模型仓库的组织规范

    生产环境中,同一模型可能需要多种格式并存。推荐的目录结构:

    models/my-llama-8b/
    ├── hf/ # HuggingFace 格式(源)
    │ ├── config.json
    │ ├── model.safetensors
    │ ├── tokenizer.json
    │ └── …
    ├── gguf/
    │ ├── my-llama-8b-q5_k_m.gguf # 平衡版
    │ └── my-llama-8b-q4_k_m.gguf # 压缩版
    ├── trt/
    │ ├── my-llama-8b-a100.engine # A100 专用
    │ └── my-llama-8b-h100.engine # H100 专用
    ├── onnx/
    │ └── my-llama-8b-int8.onnx # ONNX(如需要)
    ├── README.md # 模型说明
    └── checksums.sha256 # 校验和

    规范要点:

  • HF 格式是 source of truth:所有其他格式都从 HF 转换
  • 量化级别用文件名标注:如 q4_k_m、int8、fp16
  • Engine 标注硬件:不同 GPU 架构的 Engine 必须分文件
  • 保存校验和:每个文件生成 SHA256,便于完整性校验
  • 保留转换脚本:用 convert.sh 记录完整转换流程,便于复现

  • 十一、自动化转换流水线

    在 AIaaS 平台中,模型格式转换应自动化。典型的 CI 流水线:

    #mermaid-svg-1MVjSby7C6Ogrk7z{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-1MVjSby7C6Ogrk7z .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-1MVjSby7C6Ogrk7z .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-1MVjSby7C6Ogrk7z .error-icon{fill:#552222;}#mermaid-svg-1MVjSby7C6Ogrk7z .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-1MVjSby7C6Ogrk7z .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-1MVjSby7C6Ogrk7z .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-1MVjSby7C6Ogrk7z .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-1MVjSby7C6Ogrk7z .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-1MVjSby7C6Ogrk7z .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-1MVjSby7C6Ogrk7z .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-1MVjSby7C6Ogrk7z .marker{fill:#333333;stroke:#333333;}#mermaid-svg-1MVjSby7C6Ogrk7z .marker.cross{stroke:#333333;}#mermaid-svg-1MVjSby7C6Ogrk7z svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-1MVjSby7C6Ogrk7z p{margin:0;}#mermaid-svg-1MVjSby7C6Ogrk7z .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-1MVjSby7C6Ogrk7z .cluster-label text{fill:#333;}#mermaid-svg-1MVjSby7C6Ogrk7z .cluster-label span{color:#333;}#mermaid-svg-1MVjSby7C6Ogrk7z .cluster-label span p{background-color:transparent;}#mermaid-svg-1MVjSby7C6Ogrk7z .label text,#mermaid-svg-1MVjSby7C6Ogrk7z span{fill:#333;color:#333;}#mermaid-svg-1MVjSby7C6Ogrk7z .node rect,#mermaid-svg-1MVjSby7C6Ogrk7z .node circle,#mermaid-svg-1MVjSby7C6Ogrk7z .node ellipse,#mermaid-svg-1MVjSby7C6Ogrk7z .node polygon,#mermaid-svg-1MVjSby7C6Ogrk7z .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-1MVjSby7C6Ogrk7z .rough-node .label text,#mermaid-svg-1MVjSby7C6Ogrk7z .node .label text,#mermaid-svg-1MVjSby7C6Ogrk7z .image-shape .label,#mermaid-svg-1MVjSby7C6Ogrk7z .icon-shape .label{text-anchor:middle;}#mermaid-svg-1MVjSby7C6Ogrk7z .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-1MVjSby7C6Ogrk7z .rough-node .label,#mermaid-svg-1MVjSby7C6Ogrk7z .node .label,#mermaid-svg-1MVjSby7C6Ogrk7z .image-shape .label,#mermaid-svg-1MVjSby7C6Ogrk7z .icon-shape .label{text-align:center;}#mermaid-svg-1MVjSby7C6Ogrk7z .node.clickable{cursor:pointer;}#mermaid-svg-1MVjSby7C6Ogrk7z .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-1MVjSby7C6Ogrk7z .arrowheadPath{fill:#333333;}#mermaid-svg-1MVjSby7C6Ogrk7z .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-1MVjSby7C6Ogrk7z .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-1MVjSby7C6Ogrk7z .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-1MVjSby7C6Ogrk7z .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-1MVjSby7C6Ogrk7z .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-1MVjSby7C6Ogrk7z .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-1MVjSby7C6Ogrk7z .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-1MVjSby7C6Ogrk7z .cluster text{fill:#333;}#mermaid-svg-1MVjSby7C6Ogrk7z .cluster span{color:#333;}#mermaid-svg-1MVjSby7C6Ogrk7z div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-1MVjSby7C6Ogrk7z .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-1MVjSby7C6Ogrk7z rect.text{fill:none;stroke-width:0;}#mermaid-svg-1MVjSby7C6Ogrk7z .icon-shape,#mermaid-svg-1MVjSby7C6Ogrk7z .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-1MVjSby7C6Ogrk7z .icon-shape p,#mermaid-svg-1MVjSby7C6Ogrk7z .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-1MVjSby7C6Ogrk7z .icon-shape .label rect,#mermaid-svg-1MVjSby7C6Ogrk7z .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-1MVjSby7C6Ogrk7z .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-1MVjSby7C6Ogrk7z .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-1MVjSby7C6Ogrk7z :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    训练完成推送 HF 格式

    触发转换流水线

    Job 1: Safetensors校验 + 上传仓库

    Job 2: GGUF多量化级别

    Job 3: TRT Engine多 GPU 架构

    模型仓库

    通知部署系统新版本可用

    关键设计:

    • HF 格式上传后自动触发所有下游转换 Job
    • 各 Job 并行执行,互不阻塞
    • 每个 Job 输出标准化的 manifest(量化级别、硬件、性能基准)
    • 失败的 Job 不阻塞其他 Job,但触发告警

    十二、格式演进趋势

    12.1 Safetensors 的统治地位加强

    随着 vLLM、TGI 等主流推理引擎的普及,Safetensors 已成为云端 LLM 推理的事实标准。HuggingFace Hub 上新发布的大模型几乎全部默认 Safetensors。

    12.2 GGUF 在端侧继续扩张

    GGUF 是端侧部署(Ollama、LM Studio、桌面应用)的唯一选择。随着消费级 GPU 显存增大(RTX 5090 32GB),Q4 量化的 70B 模型也能在桌面跑起来,GGUF 生态持续繁荣。

    12.3 ONNX 在 LLM 领域收缩

    ONNX 在中小模型(CV、语音、中小文本模型)仍有一席之地,但 LLM 领域基本退出主流。Microsoft 自家的 ONNX Runtime 也在转向支持 GGUF 作为 LLM 后端。

    12.4 TensorRT Engine 锁定高端

    TensorRT-LLM 在 NVIDIA 高端 GPU 集群(A100/H100/B200)上是性能王者,但其硬件绑定和闭源特性限制了普及。AMD 的 ROCm 生态、Intel 的 GPU 生态在追赶,但短期内 NVIDIA 优势明显。

    12.5 新兴格式:Mamba/SSM 专用格式

    随着 Mamba、RWKV 等非 Transformer 架构兴起,传统格式(基于 Transformer 假设设计的)面临挑战。未来可能出现针对 SSM(State Space Model)优化的新格式。


    本篇小结

    知识点核心内容
    格式转换必要性 PyTorch pickle 不安全、依赖重、加载慢,生产必须转换
    Safetensors HuggingFace 安全格式,零拷贝 mmap 加载,防 pickle 攻击,是云端 LLM 主流
    ONNX 跨框架中间表示,Protocol Buffers 格式,适合中小模型跨平台部署,LLM 场景不推荐
    GGUF llama.cpp 原生格式,单文件自包含(权重+Tokenizer+量化),端侧事实标准
    GGUF k-quants 丰富的量化方案(Q4_K_M 最常用),CPU/GPU 混合推理(层卸载)
    TensorRT Engine NVIDIA 编译时优化产物,极致性能但硬件绑定,需用 TensorRT-LLM 编译 LLM
    选型决策 云端 NVIDIA→Safetensors 或 TRT Engine;端侧→GGUF;跨硬件中小模型→ONNX
    转换链路 HF 是 source of truth,所有格式从 HF 转换,不要跨格式互转量化模型
    工程规范 模型仓库按格式分子目录,Engine 标注硬件,保存校验和和转换脚本
    自动化 转换流水线化,HF 上传触发并行 Job,输出标准化 manifest

    下篇预告

    第 20 篇:推理部署实战——用 Go 构建 vLLM 推理服务客户端

    模块三讨论了推理引擎、KV Cache、Continuous Batching、量化、投机解码、模型格式转换等核心优化技术,但都是站在引擎内部视角。下一篇我们切换到外部调用方视角,用 Go 语言构建一个生产级的 vLLM 推理客户端——调用 OpenAI 兼容 API、处理流式 SSE 响应、gRPC 推理、健康检查、连接池管理,所有代码完整可运行,把前面学到的理论落地到工程。


    如果本篇内容对你有帮助,欢迎点赞收藏!有任何疑问,欢迎在评论区交流。

    赞(0)
    未经允许不得转载:171主机测评 » 第19篇-模型格式转换全链路-从PyTorch到生产部署
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址