4. 概率输出与分数:模型输出与阈值的关系

在可解释 AI 的阈值调整流程中,理解模型输出的原始数值形态是第一步。模型不会直接输出“是/否”的最终决策,而是输出一个连续分数或概率,再由阈值将其映射为离散类别。本节将详细拆解 logits、softmax 概率、sigmoid 分数这三种常见输出形式,以及它们与阈值之间的核心关系。

4.1 三种输出形态的定义与对比

不同模型架构和任务类型会输出不同形态的原始分数。下表从数值范围、含义和阈值适用性三个维度进行对比:

输出形态 数值范围 核心含义 阈值调整方式
Logits (-∞, +∞) 模型最后一层线性变换的原始输出,未经过任何概率归一化 直接对 logits 设定截断值;或先转换为概率再调阈值
Softmax 概率 [0, 1],且所有类别概率之和 = 1 多分类任务中,将 logits 向量归一化为概率分布 对每个类别的概率设定独立阈值(通常默认 0.5)
Sigmoid 分数 (0, 1) 二分类或多标签任务中,将单个 logit 压缩到 (0,1) 区间 对每个输出节点设定独立阈值(通常默认 0.5)
关键区分: Softmax 强制所有类别概率总和为 1,适合互斥分类(如手写数字识别);Sigmoid 对每个类别独立计算,适合多标签分类(如一张图片同时包含“猫”和“狗”)。

4.2 从 Logits 到概率的转换流程

下图展示了从模型原始 logits 到最终决策标签的完整数据流,以及阈值在其中的作用位置:

模型输出与阈值决策流程 模型输入 Logits Softmax / Sigmoid 概率转换 概率/分数 阈值比较 最终决策标签 流程说明 模型先输出未归一化的 Logits,经 Softmax/Sigmoid 转换为概率,再与阈值比较得到最终决策。 阈值调整的核心操作发生在“概率/分数”与“阈值比较”之间。

4.3 如何获取原始分数

在实际开发中,获取模型原始分数(而非仅最终标签)是进行阈值分析和可解释性分析的前提。以下是三种主流框架的获取方式:

4.3.1 Scikit-learn 模型

使用 predict_proba() 或 decision_function() 方法:

from sklearn.ensemble import RandomForestClassifier

model = RandomForestClassifier()
model.fit(X_train, y_train)

# 获取 softmax 概率(二分类返回两列:负类概率、正类概率)
probs = model.predict_proba(X_test)   # shape: (n_samples, n_classes)

# 获取决策函数值(相当于 logits)
scores = model.decision_function(X_test)  # shape: (n_samples,)

4.3.2 PyTorch 模型

在推理时关闭梯度计算,手动提取 logits 并应用 softmax:

import torch
import torch.nn.functional as F

model.eval()
with torch.no_grad():
    logits = model(X_tensor)           # 原始 logits,shape: (batch, n_classes)
    probs = F.softmax(logits, dim=1)   # 转换为概率
    # 对于二分类,也可使用 torch.sigmoid(logits)

4.3.3 TensorFlow / Keras 模型

通过设置模型输出层为线性激活(或直接访问 logits 层):

import tensorflow as tf

# 方式一:构建时保留 logits 输出
model = tf.keras.Sequential([
    tf.keras.layers.Dense(64, activation='relu'),
    tf.keras.layers.Dense(1, activation=None)  # 输出 logits
])

# 方式二:从已有模型中提取 logits 层输出
logits_model = tf.keras.Model(inputs=model.input,
                              outputs=model.layers[-1].output)
logits = logits_model.predict(X_test)

# 手动应用 sigmoid 得到概率
probs = tf.sigmoid(logits).numpy()
实践建议: 在模型部署或可解释性分析时,始终保留输出原始 logits 或概率的接口,而不是只输出最终标签。这样可以在不重新训练模型的情况下,灵活调整阈值并观察不同阈值下的性能变化。

4.4 阈值与概率分数的映射关系

阈值本质上是一个截断点:当模型输出的概率(或分数)大于等于阈值时,预测为正类;否则为负类。下图展示了不同阈值对二分类决策边界的影响:

阈值与概率分数的映射关系 模型输出概率 P (0 ~ 1) 0 1 0.5 阈值 = 0.3 (更宽松) 阈值 = 0.5 (默认) 阈值 = 0.7 (更严格) 正类区域(阈值0.3) 正类区域(阈值0.5) 正类区域(阈值0.7) 阈值越低,更多样本被归为正类(召回率↑,精确率↓);阈值越高,正类判定越严格(精确率↑,召回率↓)。

4.5 获取原始分数的注意事项

  • 数值稳定性: 直接从 logits 计算 softmax 时,建议先减去最大值(logits - max(logits)),防止指数运算溢出。
  • 多分类 vs 多标签: 多分类使用 softmax,阈值通常对所有类别统一调整;多标签使用 sigmoid,每个标签可独立设置阈值。
  • 校准问题: 某些模型(如未校准的 SVM、提升树)输出的概率可能不是真实概率,需通过 Platt 缩放或 Isotonic 回归进行校准后再调阈值。
  • 保存原始分数: 在模型评估和监控阶段,建议将原始概率/分数与预测标签一并保存到日志或数据库,便于后续回溯分析。
常见误区: 不要直接使用 model.predict() 返回的标签进行阈值分析,因为该标签已经使用了默认阈值(通常为 0.5)。必须使用 predict_proba() 或等效接口获取原始概率,才能进行灵活的阈值调整实验。