3. 模型训练与导出:基于 XGBoost 的异常交易分类模型

本章将使用 Python 训练一个基于 XGBoost 的异常交易二分类模型,并将其导出为 ONNX 格式。ONNX(Open Neural Network Exchange)是一种开放的模型表示标准,能够使模型在不同框架和推理引擎之间无缝迁移,是实时风控系统部署的关键步骤。

前置条件:确保已安装 xgboost、onnx、sklearn、pandas、numpy 以及 skl2onnx 库。建议使用 Python 3.8+ 环境。

3.1 数据准备与特征工程

我们模拟一个包含正常交易与异常交易的金融数据集。特征包括交易金额、交易时间、用户历史行为统计等。以下为数据加载与预处理的核心步骤:

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler

# 加载示例数据(实际场景中替换为真实数据源)
df = pd.read_csv('transaction_data.csv')

# 特征列与标签列
feature_cols = ['amount', 'hour_of_day', 'day_of_week', 'user_avg_amount',
                'user_txn_count_1h', 'merchant_risk_score', 'distance_from_home']
target_col = 'is_fraud'

X = df[feature_cols]
y = df[target_col]

# 处理缺失值
X.fillna(X.median(), inplace=True)

# 划分训练集与测试集
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)

# 标准化(XGBoost 对尺度不敏感,但 ONNX 推理时建议保持一致性)
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)
注意:标准化器(StandardScaler)需要在训练集上拟合,并保存其参数(均值、方差)。在 ONNX 导出时,需要将标准化步骤与模型合并,或作为预处理节点单独部署。

3.2 XGBoost 模型训练

XGBoost 在异常检测任务中表现优异,尤其适合处理不平衡数据集。我们使用 scale_pos_weight 参数来缓解正负样本不平衡问题。

import xgboost as xgb

# 计算正负样本比例
neg_count = (y_train == 0).sum()
pos_count = (y_train == 1).sum()
scale_pos_weight = neg_count / pos_count

# 定义 XGBoost 分类器
model = xgb.XGBClassifier(
    n_estimators=200,
    max_depth=6,
    learning_rate=0.1,
    subsample=0.8,
    colsample_bytree=0.8,
    scale_pos_weight=scale_pos_weight,
    eval_metric='auc',
    use_label_encoder=False,
    random_state=42
)

# 训练模型
model.fit(
    X_train_scaled, y_train,
    eval_set=[(X_test_scaled, y_test)],
    verbose=False
)

# 评估模型
from sklearn.metrics import classification_report, roc_auc_score
y_pred = model.predict(X_test_scaled)
y_proba = model.predict_proba(X_test_scaled)[:, 1]

print("AUC-ROC:", roc_auc_score(y_test, y_proba))
print(classification_report(y_test, y_pred))
参数 值 说明
n_estimators 200 树的数量,控制模型复杂度
max_depth 6 树的最大深度,防止过拟合
scale_pos_weight neg/pos 正负样本权重平衡
eval_metric auc 使用 AUC 作为早停评估指标

3.3 模型导出为 ONNX 格式

使用 skl2onnx 库将训练好的 XGBoost 模型转换为 ONNX 格式。关键步骤包括:定义输入特征的类型与形状,以及将标准化器与模型组合成一个完整的推理管道。

from skl2onnx import convert_sklearn
from skl2onnx.common.data_types import FloatTensorType
import onnx

# 定义 ONNX 输入类型(特征数量为 7)
initial_type = [('float_input', FloatTensorType([None, X_train_scaled.shape[1]]))]

# 将标准化器与 XGBoost 模型组合成管道
from sklearn.pipeline import Pipeline
pipeline = Pipeline([
    ('scaler', scaler),
    ('xgb', model)
])

# 转换管道为 ONNX
onnx_model = convert_sklearn(
    pipeline,
    initial_types=initial_type,
    target_opset=12  # 推荐使用 opset 12 或更高
)

# 保存 ONNX 模型
onnx_path = 'fraud_detection_xgb.onnx'
onnx.save_model(onnx_model, onnx_path)
print(f"ONNX 模型已保存至: {onnx_path}")
关键点:将 StandardScaler 与 XGBClassifier 封装在 Pipeline 中一起导出,可以确保推理时输入数据自动完成标准化,无需在部署端额外编写预处理代码。

3.4 ONNX 模型验证

导出后,必须使用 ONNX Runtime 对模型进行推理验证,确保输出结果与原始 XGBoost 模型一致。

import onnxruntime as ort
import numpy as np

# 创建 ONNX Runtime 会话
session = ort.InferenceSession(onnx_path)
input_name = session.get_inputs()[0].name

# 取测试集前 5 条样本进行验证
sample = X_test_scaled[:5].astype(np.float32)

# ONNX 推理
onnx_output = session.run(None, {input_name: sample})[0]
onnx_proba = 1 / (1 + np.exp(-onnx_output[:, 1]))  # 转换为概率

# 原始模型推理
original_proba = model.predict_proba(sample)[:, 1]

# 对比结果
print("ONNX 概率:", onnx_proba)
print("原始概率:", original_proba)
print("最大差异:", np.max(np.abs(onnx_proba - original_proba)))
XGBoost 模型训练与 ONNX 导出流程 数据准备与特征工程 训练/测试集划分 StandardScaler 拟合 XGBoost 模型训练 Pipeline 封装 skl2onnx 导出 ONNX Runtime 推理验证 特征工程 模型训练 导出与验证

3.5 模型导出参数对比

不同的 ONNX opset 版本对算子支持程度不同。下表列出了常用 opset 版本与 XGBoost 的兼容性:

ONNX opset XGBoost 兼容性 推荐场景
11 基本支持 旧版推理引擎兼容
12 完全支持 通用部署(推荐)
13+ 完全支持 需要新算子时使用
最佳实践:建议使用 target_opset=12,它在兼容性与新特性之间取得了良好平衡。如果部署环境较老,可降级至 opset 11。

3.6 导出后的文件结构

ONNX 模型文件是一个独立的二进制文件,通常包含完整的计算图与权重。以下为导出后的典型文件清单:

  • fraud_detection_xgb.onnx — 主模型文件,可直接被 ONNX Runtime 加载。
  • scaler_params.pkl (可选)— 如果未将标准化器封装进 Pipeline,则需要单独保存标准化参数。
  • feature_columns.json (可选)— 记录特征顺序与名称,用于部署端输入校验。
重要:ONNX 模型文件不包含特征名称信息。部署时,必须确保输入张量的顺序与训练时完全一致。建议在导出时记录特征列表,并在推理服务启动时进行校验。
ONNX 模型文件内部结构 fraud_detection_xgb.onnx 计算图 (GraphProto) 模型参数 (Initializer) 输入/输出元数据 (ValueInfoProto) 包含标准化 + XGBoost 完整推理逻辑

3.7 常见问题与排查

  1. ONNX 导出报错 "Unsupported operator":通常是因为 XGBoost 版本与 skl2onnx 版本不匹配。建议升级 skl2onnx 至最新版,或降级 XGBoost 至 1.6.x 系列。
  2. 推理结果与原始模型不一致:检查 Pipeline 中是否遗漏了预处理步骤(如缺失值填充、独热编码)。ONNX 模型仅包含导出时 Pipeline 内的操作。
  3. ONNX Runtime 加载失败:确认 ONNX 文件路径正确,且 opset 版本被当前 Runtime 支持。可使用 onnx.checker.check_model() 进行完整性校验。