趋近智
让我们将成员身份推断攻击的理论付诸实践。正如本章前面所讨论的,目标是确定一个特定数据点是否属于目标模型的训练集,通常通过观察模型处理该数据点时的行为来判断。直观的理解是,模型对于训练中已经见过的数据,可能会与对未见过的数据有不同的响应,例如更高的置信度或特定的输出模式。
我们将关注一种常见且行之有效的方法:使用影子模型。这种方法涉及训练辅助模型(“影子模型”),使其模仿目标模型的行为。然后我们训练一个“攻击模型”,用来区分这些影子模型在其各自的训练(成员)数据和测试(非成员)数据上产生的输出。最后,这个攻击模型被用来对实际目标模型的输出进行分类。
设想一个攻击者可以查询一个已训练的目标模型,ftarget。攻击者还拥有一些数据,其分布与目标模型的私有训练数据Dtarget_train相似。攻击者不知道Dtarget_train,但想确定对于给定样本x,它是否在Dtarget_train中。
基于影子模型的成员身份推断攻击的主要步骤是:
让我们通过伪代码片段来说明这一点,假设你拥有define_model()函数(返回模型架构,例如Keras/PyTorch模型)和train_model(model, train_data, epochs)函数(训练模型)。我们还假设数据已适当准备(例如,使用TensorFlow Datasets或PyTorch DataLoaders)。
# 假设 attacker_data 是攻击者可用的数据集
# 假设 num_shadow_models 是所需影子模型的数量
# 假设 target_model_architecture 已知或已近似
shadow_model_outputs = []
shadow_model_labels = []
for i in range(num_shadow_models):
print(f"正在训练影子模型 {i+1}/{num_shadow_models}...")
# 为此影子模型分割攻击者的数据
shadow_train_data, shadow_test_data = split_data(attacker_data, ratio=0.5) # 使用不重叠的分区
# 定义并训练影子模型
shadow_model = define_model(architecture=target_model_architecture)
train_model(shadow_model, shadow_train_data, epochs=50) # 示例训练轮次
# 获取其自身训练数据(成员)的预测
member_predictions = shadow_model.predict(shadow_train_data.x) # 获取输出向量
member_labels = np.ones(len(member_predictions))
# 获取其自身测试数据(非成员)的预测
non_member_predictions = shadow_model.predict(shadow_test_data.x) # 获取输出向量
non_member_labels = np.zeros(len(non_member_predictions))
# 存储结果以供攻击模型训练
shadow_model_outputs.append(np.concatenate((member_predictions, non_member_predictions)))
shadow_model_labels.append(np.concatenate((member_labels, non_member_labels)))
# 组合所有影子模型的结果
attack_train_X = np.concatenate(shadow_model_outputs)
attack_train_y = np.concatenate(shadow_model_labels)
print(f"已生成攻击训练数据: {attack_train_X.shape}, {attack_train_y.shape}")
这个循环模拟了为目标模型创建代理的过程。每个影子模型在其自身数据上学习模式,其在已见过数据与未见过数据上的表现为攻击模型提供了信号。
使用影子模型的成员身份推断攻击流程图。攻击者在自己的数据上训练影子模型,以生成用于攻击模型的训练数据。然后,该攻击模型根据目标模型针对特定查询数据点的输出来预测成员身份。
我们可以使用scikit-learn中的简单分类器,如逻辑回归或小型多层感知机(MLP)作为攻击模型。
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, classification_report
from sklearn.preprocessing import StandardScaler
# 可选:特征(模型输出)标准化
scaler = StandardScaler()
attack_train_X_scaled = scaler.fit_transform(attack_train_X)
# 分割攻击数据以进行评估
X_train_att, X_test_att, y_train_att, y_test_att = train_test_split(
attack_train_X_scaled, attack_train_y, test_size=0.3, stratify=attack_train_y, random_state=42
)
# 训练攻击模型
attack_model = LogisticRegression(solver='liblinear', random_state=42)
# 或者使用一个小型 MLP:
# attack_model = MLPClassifier(hidden_layer_sizes=(64,), max_iter=300, random_state=42)
attack_model.fit(X_train_att, y_train_att)
# 在保留的攻击数据分割上进行评估
y_pred_att = attack_model.predict(X_test_att)
print("攻击模型表现(在影子模型数据上):")
print(f"准确率: {accuracy_score(y_test_att, y_pred_att):.4f}")
print(classification_report(y_test_att, y_pred_att))
这项评估告诉我们攻击模型从影子模型的输出中区分成员与非成员的熟练程度。
现在,来到重要一步:在目标模型的输出上使用已训练的attack_model。为了正确评估攻击对目标的成功,我们需要一些数据点相对于Dtarget_train的成员身份的真实信息。这通常在我们可以控制目标模型训练的研究设置中是可行的,但在真实的黑盒场景中则不然。
假设我们拥有target_model,并且可以为了评估目的而访问其原始训练集target_train_data和测试集target_test_data。
# 获取已知成员(来自其训练集)的目标模型输出
target_member_outputs = target_model.predict(target_train_data.x)
# 获取已知非成员(来自其测试集)的目标模型输出
target_non_member_outputs = target_model.predict(target_test_data.x)
# 组合这些输出,形成针对目标的攻击模型的测试集
attack_test_target_X = np.concatenate((target_member_outputs, target_non_member_outputs))
attack_test_target_y = np.concatenate([np.ones(len(target_member_outputs)), np.zeros(len(target_non_member_outputs))])
# 使用在影子模型输出上拟合的相同标准化器进行标准化
attack_test_target_X_scaled = scaler.transform(attack_test_target_X) # 使用 transform,而非 fit_transform
# 使用攻击模型预测成员身份
final_predictions = attack_model.predict(attack_test_target_X_scaled)
final_probabilities = attack_model.predict_proba(attack_test_target_X_scaled)[:, 1] # 是成员的概率
# 评估攻击对目标模型的成功率
print("\n成员身份推断攻击表现(在目标模型数据上):")
print(f"准确率: {accuracy_score(attack_test_target_y, final_predictions):.4f}")
print(classification_report(attack_test_target_y, final_predictions))
# 你也可以使用 final_probabilities 和 attack_test_target_y 计算 AUC
# from sklearn.metrics import roc_auc_score
# print(f"AUC: {roc_auc_score(attack_test_target_y, final_probabilities):.4f}")
这里的主要衡量指标是attack_model在目标模型数据上的最终准确率(或AUC)。
“成员”类别的高精度表示当攻击预测为“成员”时,其很可能是正确的。高召回率表示攻击识别出了大部分真实成员。
示例评估结果显示攻击表现明显优于随机猜测,这表明目标模型可能存在成员身份信息泄露。
这种实际操作的视角表明,成员身份推断并非仅仅是理论上的担忧。在获得适当访问权限和数据的情况下,攻击者可以构建模型来探查机器学习系统的训练历史,从而引发重要的隐私问题。弄清楚如何实施这些攻击是评估模型脆弱性并设计有效防御的第一步。
这部分内容有帮助吗?
© 2026 ApX Machine Learning用心打造