4.5 模型持久化与部署 模型以 JSON/UBJSON 存储可跨语言跨版本加载,pickle 只适合同环境的快速暂存;上线形态在"离线批量、在线服务、端侧嵌入"之间按延迟与吞吐取舍。 本节实测三种格式的体积与兼容性,走通保存加载预测一致性检查,并给出部署形态的决策要点。 流水线最后一站。本节两个知识点:持久化格式的选择、三种上线形态的适用边界。 一、三种格式实测 三种格式的定位:JSON 可读可 diff、能被 JVM/其他语言的 XGBoost 前端直接加载,是交付与归档格式;UBJSON 同样跨语言且体积小加载快,是生产推荐格式;pickle 连同 Python 对象状态整体序列化,版本一换就可能加载失败,只用于同一环境内的临时暂存。
模型以 JSON/UBJSON 存储可跨语言跨版本加载,pickle 只适合同环境的快速暂存;上线形态在"离线批量、在线服务、端侧嵌入"之间按延迟与吞吐取舍。 本节实测三种格式的体积与兼容性,走通保存加载预测一致性检查,并给出部署形态的决策要点。
流水线最后一站。本节两个知识点:持久化格式的选择、三种上线形态的适用边界。
import os import pickle import xgboost as xgb from sklearn.metrics import roc_auc_score # 承接上节的 clf(sklearn 接口模型),取出原生 booster booster = clf.get_booster() booster.save_model('churn_model.json') # JSON:人类可读、跨语言 booster.save_model('churn_model.ubj') # UBJSON:二进制、更小更快 with open('churn_model.pkl', 'wb') as f: # pickle:依赖 Python 环境 pickle.dump(clf, f) for fn in ('churn_model.json', 'churn_model.ubj', 'churn_model.pkl'): print(f"{fn:20s} {os.path.getsize(fn)/1024:.1f} KB") # 运行输出: # churn_model.json 118.6 KB # churn_model.ubj 84.2 KB # churn_model.pkl 131.4 KB # 跨格式加载与一致性检查 loaded = xgb.Booster() loaded.load_model('churn_model.ubj') p1 = booster.predict(dtest) p2 = loaded.predict(dtest) print("JSON/UBJSON 加载后预测一致:", (p1 == p2).all()) # 运行输出: JSON/UBJSON 加载后预测一致: True
三种格式的定位:JSON 可读可 diff、能被 JVM/其他语言的 XGBoost 前端直接加载,是交付与归档格式;UBJSON 同样跨语言且体积小加载快,是生产推荐格式;pickle 连同 Python 对象状态整体序列化,版本一换就可能加载失败,只用于同一环境内的临时暂存。注意 save_model 保存的是 booster 本身,不包含特征预处理逻辑——编码、填充、阈值都住在训练脚本里,上线时必须与模型一起版本化,这是事故高发区。
# 预测一致性、阈值、版本 三件套 import numpy as np # 1. 一致性:同一批数据新旧模型输出必须逐位一致(无随机成分时) assert np.allclose(p1, p2), "加载后预测漂移" # 2. 业务阈值随模型走:上节定的 0.31 阈值要写进部署配置 THRESHOLD = 0.31 alerts = (p2 > THRESHOLD).sum() print(f"加载模型按 0.31 阈值报警数: {alerts} / {len(p2)}") # 运行输出: 加载模型按 0.31 阈值报警数: 611 / 2000 # 3. 记录训练指纹:特征列顺序 + 版本号,加载时校验 assert list(X_tr_enc.columns) == list(X_te_enc.columns) print("特征顺序校验通过, 模型版本:", getattr(clf, 'xgb_version', '2.x')) # 运行输出: 特征顺序校验通过, 模型版本: 2.x
离线批量是流失预测这类业务的默认形态:每晚全量客户打分,名单交给运营。工程要点是特征快照管理——预测用的特征必须是"预测时点可得"的版本,与第 4.1 节的防泄漏纪律一脉相承。在线服务把 booster 包进推理接口,真正难点不在模型而在特征:线上实时拼特征要与训练时的构造逻辑严格一致,常见的落地办法是把特征逻辑做成训练线上共用的库。端侧嵌入是 JSON 格式的用武之地——XGBoost 的模型文件可以被编译到移动端运行,树模型的推理只是几十次比较,端侧毫秒级完成。
⚠️ 常见坑:只上传模型文件、不带预处理与阈值。三周后特征列顺序变了、编码字典变了、阈值还是旧的,线上分数无声漂移。模型上线交付的最小单元是"模型文件 + 预处理代码 + 阈值配置 + 特征清单"四件套,缺一不可。
实战流水线全线贯通。第 5 章处理让流水线翻车的难题:不平衡、特征工程、解释性、超大规模与横向对比。
补一句版本管理的经验:模型文件名里带上数据快照日期与参数指纹(例如 churn_ubj_0823_d4_lr01),比统一叫 model_final 好得多——"final"这个后缀在第三次迭代后就会变成谎言,而带指纹的文件名让任何一次回滚都有据可查。配套动作是每次存档时顺手记录一份元信息(训练集行数、正例比例、验证分数、阈值),四行日志换来半年后回看时的清醒。