PAYATHON 2026

如何用 SHAP 解释极度不平衡入侵检测数据上的 CNN+BiLSTM 模型?

架构老王

建议先用 GradientExplainer 做小规模验证,再根据兼容性决定是否采用 DeepExplainer。原始数据的类别不平衡不会直接让 SHAP 值失效,但会影响模型学到的规律、背景数据的代表性和全局特征重要性的统计结果。背景数据应根据解释目标选择,不必与重采样后的训练分布一致。

如何选择解释器?

GradientExplainer 使用 expected gradients,适用于可微模型;DeepExplainer 使用基于 DeepLIFT 的归因规则近似 SHAP 值。两者都需要背景数据。GradientExplainer 文档、DeepExplainer 文档

对于 CNN+BiLSTM+Multi-Head Self-Attention,建议先尝试 GradientExplainer。这项建议基于计算方式,并不保证它一定更准确或兼容。DeepExplainer 对计算图中的算子有特定处理规则,能否使用需要结合 BiLSTM、Attention 的实现以及 TensorFlow、Keras、SHAP 的版本检查。DeepExplainer 的 TensorFlow 实现

可以先用少量背景样本解释一条记录,确认以下事项:

  • 目标输出对输入的梯度可以正常计算。
  • 推理时关闭 Dropout,BatchNormalization 使用推理行为。
  • 归因值没有 NaN 或无穷大,也没有无法解释的全零结果。
  • 归因值之和与目标输出和背景输出均值之差基本吻合。

如果 DeepExplainer 报算子或梯度错误,应先检查兼容性,不要仅关闭加和检查后就把结果当作有效解释。

类别不平衡会怎样影响解释?

SHAP 解释的是已经训练好的模型。正常流量只有 0.18%,即使用 SMOTE 扩充了样本数量,也没有增加同等数量的独立真实观测。模型仍可能遗漏某些正常流量模式,或学到合成样本带来的特征。解释器能呈现这些模型行为,但不能证明预测正确。

背景数据会改变解释的参照点。对于选定的模型输出,近似加和关系可以写成:

$$ f(x) \approx \mathbb{E}_{b\sim B}[f(b)] + \sum_j \phi_j(x;B) $$

其中,B 是背景分布。更换背景后,基准输出和各项归因都可能变化。这通常意味着参照问题发生了变化,并不代表某一组结果必然错误。expected gradients 的归因在相应条件下收敛到输出与背景期望输出之差。expected gradients 说明

如果还要统计全局重要性,直接在原始比例的样本上计算 mean(abs(SHAP)),结果主要反映攻击流量。建议同时按真实类别分别统计,并单独查看误报、漏报样本。

背景应该使用哪种分布?

解释目标建议的背景解释含义
解释相对于目标运行环境的预测变化能代表目标环境的真实流量为什么该样本的输出偏离目标环境的平均输出
在两类同等重要的参照下比较从真实样本中构建的平衡背景相对于人为设定的平衡参照,哪些输入推动预测
分析某条流量为何具有攻击特征真实正常流量背景哪些输入使攻击输出偏离正常流量的参考水平

原始数据比例只有在能够代表目标运行环境时,才适合作为部署解释的依据。不能仅因为数据集中攻击占 99.82%,就假定实际 IoT 网络也具有相同比例。

采用原始比例时,背景样本过少可能遗漏正常流量。例如,随机抽取 100 条记录时,正常流量的期望数量仅为 100 × 0.0018 = 0.18。少量背景样本因此难以代表正常类别。

可以增加背景规模,并使用不同的背景抽样重复解释。若为了覆盖正常流量而提高其抽样比例,应明确将结果标为平衡背景或其他指定比例背景;未经权重处理,不能把它称为原始分布背景。

解释真实流量时,优先从未重采样的真实数据中选择背景。训练使用了 SMOTE,并不意味着解释也必须使用 SMOTE 合成样本。

如何实现单个预测的解释?

下面的示例假设模型只有一个输入,形状为 (N, T, F),输出为 (N, 1) 的攻击概率。X_train_original_seq 表示未重采样、但已按训练要求完成预处理和序列构建的训练数据;X_test_seq 表示独立测试数据。变量名仅用于示例,需要替换为实际数据。

示例使用真实训练数据的随机子集作为背景。如果解释目标是相对于正常流量,应改用真实正常流量子集。

import numpy as np
import tensorflow as tf
import shap

X_pool = np.asarray(X_train_original_seq, dtype=np.float32)
X_explain = np.asarray(X_test_seq[:1], dtype=np.float32)

rng = np.random.default_rng(42)
n_background = min(200, len(X_pool))
indices = rng.choice(len(X_pool), size=n_background, replace=False)
background = X_pool[indices]

# model 是已经训练好的模型,输出形状为 (N, 1)。
inputs = tf.keras.Input(shape=X_pool.shape[1:])
outputs = model(inputs, training=False)
explain_model = tf.keras.Model(inputs, outputs)

explainer = shap.GradientExplainer(explain_model, background)
values = explainer.shap_values(
    X_explain,
    nsamples=400,
    rseed=42,
)

# 兼容单输入、单输出场景中的常见返回形式。
if isinstance(values, list):
    if len(values) != 1:
        raise ValueError("Expected one explanation array")
    values = values[0]

phi = np.asarray(values)
if phi.shape == X_explain.shape + (1,):
    phi = phi[..., 0]
if phi.shape != X_explain.shape:
    raise ValueError(f"Unexpected SHAP shape: {phi.shape}")

baseline = explain_model(background, training=False).numpy().mean()
prediction = explain_model(X_explain, training=False).numpy()[:, 0]
attribution_sum = phi.reshape(len(X_explain), -1).sum(axis=1)
residual = prediction - baseline - attribution_sum

print("prediction:", prediction)
print("baseline:", baseline)
print("additivity residual:", residual)

# 沿时间轴求和,得到每个特征对该预测的净贡献。
feature_contribution = phi.sum(axis=1)

200 和 400 是示例设置,不是可靠性阈值。SHAP 的返回结构可能随输出数量和版本变化,应以实际形状为准。官方 API 文档说明了相关返回形式。返回值说明

若模型输出为两个或多个 softmax 类别,先明确需要解释哪个输出,再构造仅保留该输出的模型。不要默认索引 1 一定对应攻击。若解释的是 sigmoid 概率,正归因表示提高该概率,负归因表示降低该概率。

代码中的残差只用于检查数值一致性。expected gradients 使用采样估计,残差不一定严格为零。应改变背景抽样和 nsamples,观察残差及主要特征贡献是否稳定;加和吻合也不能单独证明解释可信。

原采样代码有哪些需要确认的地方?

原代码调用了 SMOTE,但展示的导入语句中没有导入它。若其他位置也没有导入,需要补充:

from imblearn.over_sampling import SMOTE

SMOTETomek 在这段代码中没有使用,因此这个流程没有实际执行 Tomek links 清理。

另外,RandomUnderSampler 默认使用 sampling_strategy='auto'。在所述二分类场景下,它会先把多数类攻击流量降到少数类正常流量的数量;随后默认配置的 SMOTE 通常已没有需要补齐的类别。应检查每一步后的类别计数,确认流程是否实现了预期的混合采样,还是仅做了大量欠采样。RandomUnderSampler 参数说明

重采样应只在训练数据内进行。验证集和测试集应保留用于评估目标场景的真实分布;交叉验证时也应在每个训练折内完成重采样,避免数据泄漏。imbalanced-learn 数据泄漏说明

对于序列输入,还要确认 SMOTE 的样本单位。如果把窗口展平后插值,再恢复为序列,应检查生成样本是否仍符合流量和时间约束。输入包含类别编码、离散字段或强相关特征时,插值路径也可能经过不合理的输入组合。SHAP 结果适合作为模型行为分析依据,不能直接视为网络攻击的因果证据。

备注:内容仅供参考。