4. 模型量化基础

在金融模型部署中,模型压缩的第一道常用工序就是量化。它把原本以 FP32 存储和计算的权重、激活值,映射到 INT8、INT4 甚至二值等低位宽表示,从而显著降低显存占用、提升推理吞吐,并让模型更容易在 CPU、边缘设备或低延迟交易环境中落地。但量化不是简单“砍精度”,而是一套关于数值映射、误差控制和精度评估的系统工程。

一、量化原理:从连续浮点到离散整数

量化的本质是建立一个可逆的仿射映射。设真实浮点值为 x,量化后的整数为 q,则最常见的形式为:

q = round(x / scale + zero_point)
x_hat = (q - zero_point) * scale

其中 scale 是缩放因子,zero_point 是零点偏移。推理时,矩阵乘法可以在整数域完成,再通过 scale 还原到浮点域。金融场景中,收益率预测、信用评分、风控特征等对数值分布非常敏感,因此 scale 的选取直接决定量化误差。

核心洞察:量化误差主要来自两部分——截断误差(超出表示范围的值被裁剪)和舍入误差(连续值映射到离散格点)。金融数据常存在长尾分布,截断误差往往比舍入误差更危险。

二、对称量化与非对称量化

根据零点是否为零,量化可分为对称量化和非对称量化。对称量化强制 zero_point = 0,映射区间关于原点对称,适合权重这类近似零均值分布的数据;非对称量化允许零点偏移,能更灵活地覆盖非对称分布,适合激活值、ReLU 输出等。

对比维度对称量化非对称量化
零点固定为 0可学习/统计得到
映射区间[-max, max][min, max]
适用对象权重、零均值激活非负激活、偏态分布
计算复杂度较低略高
金融场景因子权重、嵌入向量成交量、波动率特征

实际部署中,权重常用对称量化,激活常用非对称量化,形成混合策略。例如在 PyTorch 中可这样观察量化参数:

import torch
from torch.quantization import observer

x = torch.randn(4, 8)
obs = observer.MinMaxObserver(dtype=torch.quint8)
obs(x)
scale, zero_point = obs.calculate_qparams()
print(scale, zero_point)

三、训练后量化与量化感知训练

按量化发生的时间,可分为训练后量化(PTQ)和量化感知训练(QAT)。PTQ 在模型训练完成后直接统计校准集上的激活分布,计算 scale 和 zero_point,流程简单、成本低,适合快速验证。QAT 则在训练阶段插入伪量化节点,让模型在反向传播中“感知”量化误差,从而微调权重,通常能获得更高精度。

PTQ 与 QAT 流程对比 训练后量化 PTQ FP32 模型训练完成 校准集统计 min/max 计算 scale / zero_point 直接生成 INT8 模型 量化感知训练 QAT FP32 模型 + 伪量化节点 前向模拟量化误差 反向微调权重 导出高精度 INT8 模型 精度不足时

在金融风控模型中,若直接对 LSTM 或 Transformer 做 PTQ,AUC 可能下降 1~3 个百分点;而加入 QAT 后,通常能把损失控制在 0.5 个百分点以内。代价是训练成本增加,因此需要根据业务容忍度选择。

实践建议:先用 PTQ 做快速基线,若精度不达标再上 QAT。校准集应覆盖真实业务分布,尤其是极端行情、违约样本等长尾数据,否则 scale 会被“平均化”,导致关键样本失真。

四、金融模型量化精度评估指标

量化后不能只看模型大小和速度,必须建立多维评估体系。金融模型常用指标包括:

  • 任务指标:分类用 AUC、KS、F1;回归用 MAE、RMSE、IC、RankIC。
  • 排序一致性:Top-K 命中率、NDCG,评估量化前后排序能力是否漂移。
  • 校准误差:ECE、Brier Score,衡量预测概率是否仍然可靠。
  • 数值稳定性:最大绝对误差、相对误差、输出分布 KL 散度。
  • 业务指标:回测收益、最大回撤、换手率、拒真率。

常见误区:只对比整体 AUC,忽略尾部样本。金融风控中,违约样本往往只占 1%~5%,量化误差可能集中在这部分,导致整体指标看似正常,但坏账率显著上升。建议分层评估:按分数段、按样本权重、按时间窗口分别统计。

一个可复用的评估脚本骨架如下:

def evaluate_quant(model_fp32, model_int8, loader):
    metrics = {}
    for name, model in [("fp32", model_fp32), ("int8", model_int8)]:
        preds, labels = [], []
        for x, y in loader:
            preds.append(model(x))
            labels.append(y)
        metrics[name] = {
            "auc": roc_auc_score(labels, preds),
            "ks": ks_statistic(labels, preds),
            "ece": expected_calibration_error(labels, preds),
        }
    return metrics

复盘时,建议把量化前后指标做成对照表,并重点关注精度下降是否集中在高价值样本。如果 INT8 模型在整体 AUC 上只降 0.3%,但在高分段样本上降了 5%,那就需要重新设计量化策略,例如对关键层保留 FP16,或对激活采用更细粒度的 per-channel 量化。

量化是金融模型压缩与部署的起点,理解对称与非对称的取舍、PTQ 与 QAT 的适用边界,并建立面向业务的精度评估体系,才能在速度、体积与风险之间找到平衡点。