3. 模型导出与序列化

模型训练完成后,必须将其从内存中的对象转换为可持久化存储、可跨环境传输、可被高性能推理引擎加载的格式。本章围绕四种主流序列化方案展开:Python pickle/joblib、ONNX、TensorFlow SavedModel 与 PyTorch TorchScript,并对比其适用场景与优势。

3.1 Python pickle / joblib:快速原型与轻量部署

对于基于 scikit-learn 构建的信用评分模型(逻辑回归、XGBoost、LightGBM 等),pickle 与 joblib 是最直接的序列化方式。

特性 pickle joblib
适用对象 任意 Python 对象 大型 NumPy 数组、估算器
压缩支持 需手动包装 内置 compress 参数
序列化速度 中等 对大数组更快
跨版本兼容 弱(Python 版本敏感) 同 pickle 限制
推荐场景 小型模型、临时存储 生产级 scikit-learn 模型
⚠️ 安全警告: 切勿从不可信来源加载 pickle/joblib 文件,反序列化时会执行任意代码。生产环境建议对模型文件做签名校验。
# 使用 joblib 保存与加载 scikit-learn 模型
from sklearn.ensemble import GradientBoostingClassifier
import joblib

model = GradientBoostingClassifier(n_estimators=100)
model.fit(X_train, y_train)

# 保存(带压缩)
joblib.dump(model, 'credit_score_model.pkl', compress=3)

# 加载
loaded_model = joblib.load('credit_score_model.pkl')
predictions = loaded_model.predict(X_test)

3.2 ONNX 格式:跨框架互操作与推理优化

ONNX(Open Neural Network Exchange)定义了一套统一的算子集与计算图表示,使模型可以在不同框架(PyTorch → ONNX → TensorRT / ONNX Runtime)之间迁移。

核心优势: ONNX Runtime 提供图优化、算子融合、量化推理,在 CPU/GPU 上均可获得显著加速,尤其适合信用评分场景下的高吞吐批量评分。
# 将 PyTorch 模型导出为 ONNX
import torch
import torch.onnx

class CreditScoreNet(torch.nn.Module):
    def __init__(self):
        super().__init__()
        self.fc = torch.nn.Linear(20, 1)

    def forward(self, x):
        return torch.sigmoid(self.fc(x))

model = CreditScoreNet()
model.eval()

dummy_input = torch.randn(1, 20)
torch.onnx.export(
    model,
    dummy_input,
    "credit_score.onnx",
    input_names=['features'],
    output_names=['score'],
    dynamic_axes={'features': {0: 'batch_size'}, 'score': {0: 'batch_size'}}
)
ONNX 跨框架转换与推理流程 PyTorch 训练 TensorFlow 训练 scikit-learn 训练 ONNX 模型 credit_score.onnx 计算图 + 权重 ONNX Runtime TensorRT OpenVINO

3.3 TensorFlow SavedModel:完整服务封装

SavedModel 是 TensorFlow 官方推荐的导出格式,包含计算图(GraphDef)、权重(Checkpoint)与签名(SignatureDef),可直接被 TensorFlow Serving 加载。

# 导出 TensorFlow SavedModel
import tensorflow as tf

model = tf.keras.Sequential([
    tf.keras.layers.Dense(64, activation='relu', input_shape=(20,)),
    tf.keras.layers.Dense(1, activation='sigmoid')
])
model.compile(optimizer='adam', loss='binary_crossentropy')
model.fit(X_train, y_train, epochs=10)

# 导出
model.save('credit_score_savedmodel', save_format='tf')

# 使用 tf.saved_model.save 更细粒度控制
@tf.function(input_signature=[tf.TensorSpec(shape=[None, 20], dtype=tf.float32)])
def predict_fn(x):
    return model(x)

tf.saved_model.save(model, 'credit_score_savedmodel_v2', signatures=predict_fn)
版本兼容: SavedModel 的序列化格式与 TensorFlow 主版本强绑定。使用 TF2.x 导出的模型无法被 TF1.x 加载。建议在 Docker 容器中固定 TensorFlow Serving 版本。

3.4 PyTorch TorchScript:生产级图模式推理

TorchScript 将 PyTorch 动态图转换为静态计算图,支持序列化、优化与无 Python 依赖的 C++ 运行时加载。

导出方式 方法 适用场景
Tracing torch.jit.trace 模型不含控制流(if/for 依赖数据)
Scripting torch.jit.script 模型包含动态控制流
# TorchScript 导出(Tracing 方式)
import torch

class ScoringModel(torch.nn.Module):
    def __init__(self):
        super().__init__()
        self.linear = torch.nn.Linear(20, 1)

    def forward(self, x):
        return torch.sigmoid(self.linear(x))

model = ScoringModel()
model.eval()

# Tracing
dummy = torch.randn(1, 20)
traced_model = torch.jit.trace(model, dummy)
traced_model.save('credit_score_traced.pt')

# Scripting(支持条件分支)
@torch.jit.script
def scored_fn(x):
    score = torch.sigmoid(torch.mm(x, torch.randn(20, 1)))
    if score > 0.5:
        return score, torch.tensor(1)
    else:
        return score, torch.tensor(0)

torch.jit.save(scored_fn, 'credit_score_scripted.pt')
四种序列化格式适用场景对比 pickle / joblib scikit-learn 模型 快速原型 / 单体服务 ONNX 跨框架互操作 高性能推理引擎 SavedModel TensorFlow Serving 完整服务封装 TorchScript PyTorch 生产部署 C++ 无 Python 运行时 选择建议 原型阶段用 joblib → 需要跨框架或加速时转 ONNX → TF 生态用 SavedModel → PyTorch 生产用 TorchScript

3.5 序列化格式选型总结

信用评分模型部署推荐路径:
1. 开发阶段使用 joblib 快速迭代。
2. 需要跨平台或 GPU 加速时,将模型转换为 ONNX 格式,配合 ONNX Runtime 部署。
3. 若已有 TensorFlow/PyTorch 基础设施,分别使用 SavedModel 或 TorchScript 获得最佳生态集成。

无论选择哪种格式,都应在导出后执行 一致性验证:加载序列化模型,对同一批样本计算输出,确保与原模型输出的差异在浮点误差范围内(通常 < 1e-5)。