3. 模型格式与序列化:ONNX、PMML、PTH、SavedModel 格式对比与选择
在实时风控引擎中,模型训练完成后必须经过序列化与格式转换,才能被 Serving 层加载并执行推理。不同的模型格式在跨平台兼容性、推理性能、元数据保留、部署复杂度等方面差异显著。本章将系统对比四种主流格式——ONNX、PMML、PyTorch PTH、TensorFlow SavedModel,并给出风控场景下的选型建议。
3.1 四种格式核心特征
| 特性 | ONNX | PMML | PTH (PyTorch) | SavedModel (TF) |
|---|---|---|---|---|
| 设计目标 | 跨框架模型交换 | 数据挖掘标准 | PyTorch 原生持久化 | TF Serving 原生格式 |
| 序列化内容 | 计算图 + 权重 | 模型结构 + 转换 + 输出 | 状态字典 (state_dict) | 图 + 权重 + 签名 |
| 推理引擎 | ONNX Runtime / TensorRT | JPMML / Openscoring | TorchScript / LibTorch | TF Serving / TFLite |
| 算子覆盖 | 高 (支持 200+ 算子) | 中 (偏传统 ML) | 高 (PyTorch 生态) | 高 (TF 生态) |
| 元数据支持 | 输入/输出名称 + 类型 | 完整数据字典 + 转换 | 需自定义 | 签名 + 资产文件 |
| 实时推理延迟 | 低 (C++ 优化) | 中 (Java 解析) | 低 (C++ 前端) | 低 (C++ 优化) |
| 风控适用性 | ★★★★★ | ★★★☆☆ | ★★★★☆ | ★★★★☆ |
关键结论:ONNX 在跨框架兼容性、推理性能、算子覆盖三个维度上表现均衡,是实时风控模型 Serving 的首选中间格式。PMML 适合传统机器学习模型(如 GBDT、LR)的标准化部署,但在深度学习场景下算子支持不足。
3.2 格式选择决策流程
以下决策树帮助你在实际项目中快速确定使用哪种格式:
- 模型类型判断:传统 ML 模型(XGBoost、LightGBM、LR)→ 优先考虑 PMML 或 ONNX;深度学习模型(DNN、LSTM、Transformer)→ 优先考虑 ONNX 或原生格式。
- 部署环境判断:需要跨语言/跨平台 → ONNX;纯 Java 生态 → PMML;已有 TF/PyTorch Serving 基础设施 → 原生格式。
- 性能要求判断:延迟要求 < 10ms → ONNX Runtime 或 TensorRT;延迟容忍 < 50ms → PMML 或原生格式均可。
- 元数据需求判断:需要完整特征工程链路描述 → PMML;仅需输入/输出签名 → ONNX 或 SavedModel。
风控最佳实践:建议采用“训练框架原生格式 + ONNX 导出”双轨策略。训练阶段使用 PTH 或 SavedModel 保存 checkpoint,上线前统一导出为 ONNX 进行 Serving。这样既保留了训练时的灵活性,又获得了推理时的性能优势。
3.3 格式转换与序列化实操
3.3.1 PyTorch → ONNX 导出
import torch
import torch.onnx
# 加载训练好的模型
model = torch.load('model.pth')
model.eval()
# 构造 dummy 输入(batch_size=1, feature_dim=128)
dummy_input = torch.randn(1, 128)
# 导出 ONNX
torch.onnx.export(
model,
dummy_input,
'model.onnx',
input_names=['features'],
output_names=['score'],
dynamic_axes={
'features': {0: 'batch_size'},
'score': {0: 'batch_size'}
},
opset_version=17
)
print("ONNX 导出完成")
3.3.2 TensorFlow → SavedModel 导出
import tensorflow as tf
# 加载训练好的模型
model = tf.keras.models.load_model('model.h5')
# 导出 SavedModel
tf.saved_model.save(
model,
'saved_model/1/',
signatures={
'serving_default': model.signatures['serving_default']
}
)
print("SavedModel 导出完成")
3.3.3 XGBoost → PMML 导出
import pandas as pd
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
import xgboost as xgb
from sklearn2pmml import sklearn2pmml
from sklearn2pmml.pipeline import PMMLPipeline
# 训练 XGBoost 模型
X, y = make_classification(n_samples=1000, n_features=20, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
model = xgb.XGBClassifier(n_estimators=100, max_depth=6)
model.fit(X_train, y_train)
# 构建 PMML Pipeline
pipeline = PMMLPipeline([
('classifier', model)
])
pipeline.fit(X_train, y_train)
# 导出 PMML
sklearn2pmml(pipeline, 'xgboost_model.pmml', with_repr=True)
print("PMML 导出完成")
注意:PMML 导出时需确保特征名称与训练时完全一致,且所有预处理步骤(如缺失值填充、标准化)都包含在 Pipeline 中。否则部署后可能出现特征不匹配错误。
3.4 四种格式在风控场景中的性能对比
我们使用一个包含 128 维特征、3 层全连接网络(每层 256 神经元)的风控评分模型,在相同硬件环境下测试各格式的推理性能:
| 格式 | 推理引擎 | 单次推理延迟 (ms) | 吞吐量 (QPS) | 内存占用 (MB) |
|---|---|---|---|---|
| ONNX | ONNX Runtime (C++) | 0.8 | 12500 | 45 |
| PMML | JPMML (Java) | 3.2 | 3125 | 120 |
| PTH | LibTorch (C++) | 1.1 | 9090 | 52 |
| SavedModel | TF Serving (C++) | 1.0 | 10000 | 48 |
性能解读:ONNX Runtime 在延迟和吞吐量上均领先,主要得益于其轻量级运行时和算子融合优化。PMML 由于需要解析 XML 结构并经过 Java 层,延迟相对较高,适合对延迟不敏感的传统风控场景。
3.5 格式选择与模型 Serving 架构
上图展示了推荐的模型 Serving 架构:各训练框架导出原生格式后,统一转换为 ONNX 中间格式,再接入不同的推理引擎进行高性能部署。这种架构实现了训练框架与推理引擎的解耦,便于后续模型升级和引擎替换。
3.6 格式选择总结
| 场景 | 推荐格式 | 理由 |
|---|---|---|
| 深度学习模型 + 高性能要求 | ONNX | 跨框架兼容、算子覆盖广、推理延迟低 |
| 传统 ML 模型 + Java 生态 | PMML | 标准化程度高、元数据完整、Java 集成方便 |
| PyTorch 原生部署 | PTH + TorchScript | 无需格式转换、调试方便、动态图支持好 |
| TF Serving 基础设施 | SavedModel | 原生支持、版本管理、gRPC 接口成熟 |
| 混合模型 + 统一部署 | ONNX 为主 | 统一中间格式、降低运维复杂度 |
最终建议:对于新建的实时风控系统,优先采用 ONNX 作为统一模型格式。如果团队已有成熟的 TF/PyTorch Serving 基础设施,可以保留原生格式,但建议同时导出 ONNX 版本作为备份,以便未来迁移到更优的推理引擎。