SplitRec:在隐语拆分学习中使用 FeatureInferenceAttack#

在联邦学习中,攻击者可以通过监听训练模型过程中传输的数值和梯度信息,攻击对方模型或数据,在一定程度上推理出有用信息,造成信息泄露。

本文考虑两方拆分学习中的特征推理攻击,将介绍《Feature Inference Attacks on Model Predictions in Vertical Federated Learning》中的 GRN 攻击方法在隐语中的使用。

Feature Inference Attack with Generative Regression Network#

特征推理攻击中,有标签的一方作为攻击方,推测对方的特征。在联邦模型训练之后,GRN 攻击方法通过一个生成回归网络(Generator Model)预测对方特征,并通过不断缩小预测特征在联邦模型的输出值和真实联邦模型输出值的差距,训练 Genertor Model,因而可以预测对方特征,如下图所示。

fia0

其中 Generator Model 具体训练步骤如下:

  1. 将攻击方特征(蓝色)和随机生成的数据(橙色)输入到 Generator Model 中,输出值作为预测的对方特征

  2. 将攻击方特征和预测的对方特征输入已经训完的联邦模型中,计算 logit 输出

  3. 利用步骤 2 中输出的 logit 与真实 logit(攻击方特征和对方真实特征输入联邦模型计算的 logit)计算损失

  4. 对得到的损失进行反向传播,更新 Generator Model 参数

算法伪代码如下:

fia1

loss 函数定义如下:

fia2

隐语中的攻击方法实现#

在隐语中攻击方法的实现是通过 callback 机制来完成。攻击算法基类 CallBack 位于 secretflow/ml/nn/sl/backend/torch/callback.py,我们在联邦模型训练的以下几个节点提供 hook,不同攻击方法可以通过将攻击算法实现在对应节点的 hook, 使攻击逻辑注入到联邦模型的训练过程中。

  • on_train_begin

  • on_train_end

  • on_epoch_begin

  • on_epoch_end

  • on_batch_begin

  • on_batch_end

用户如果需要实现自定义的攻击方法,需要

  1. 定义 CustomAttacker 继承基类 Callback,将攻击逻辑实现到对应的 hook 函数中

  2. 定义 attacker_builder 函数将构建 attacker 写到其中

  3. 与普通 Split Learning 模型训练一样定义 sl_model, 并在调用 sl_model.fit() 时,将 callback_dict {party -> attacker_builder} 传入 callbacks 参数即可

其中步骤 1 可以参考隐语中已有的 FeatureInferenceAttacker/LabelInferenceAttacker,步骤 2 和 3 可参考下面 FeatureInferenceAttacker 的使用方式。

Feature Inferece Attack 的隐语封装#

我们在隐语中提供了多种攻击方法的封装。对于论文中的攻击方法,我们提供了 FeatureInferenceAttacker 封装,具体使用可以参考以下代码。

首先和一般 Split Learning 模型训练一样,我们将进行数据处理,并定义一个 SLModel。

然后定义调用 FeatureInferenceAttacker 的 attacker_builder,并在 SLModel fit 时将 attacker_builder 传入进行训练和攻击。

环境设置#

[1]:
import secretflow as sf

# Check the version of your SecretFlow
print('The version of SecretFlow: {}'.format(sf.__version__))

# In case you have a running secretflow runtime already.
sf.shutdown()
sf.init(['alice', 'bob'], address="local")
alice, bob = sf.PYU('alice'), sf.PYU('bob')
device_y = alice
The version of SecretFlow: 1.1.0.dev20230926
2023-09-26 19:49:40,269 INFO worker.py:1538 -- Started a local Ray instance.

数据集介绍#

这里我们使用 UCI Sensorless Drive Diagnosis 数据集,该数据集有 48 维特征 11 分类。

这里我们对数据进行纵向切分,攻击方持有 28 维特征和 label,被攻击方持有 20 维特征。

数据集官网

这里可以下载论文代码数据集: drive_cleaned.csv

或直接使用我们提供的 demo 数据 drive_cleaned_demo.csv

准备数据#

[2]:
import numpy as np
from secretflow.data.ndarray import FedNdarray, PartitionWay
from secretflow.utils.simulation.datasets import _DATASETS, get_dataset


def prepare_data():
    data_path = get_dataset(_DATASETS['drive_cleaned'])
    full_data_table = np.genfromtxt(data_path, delimiter=',')
    samples = full_data_table[:, :-1].astype(np.float32)
    labels = full_data_table[:, -1].astype(np.int64)

    # permuate columns
    batch, columns = samples.shape
    permu_cols = np.random.permutation(columns)
    samples = samples[:, permu_cols]

    # normalize feature
    fea_min = samples.min(axis=0)
    fea_max = samples.max(axis=0)
    samples = (samples - fea_min) / (fea_max - fea_min)
    mean_attr = samples.mean(axis=0)

    # split train, test, pred
    random_selection = np.random.rand(samples.shape[0]) <= 0.6
    train_sample = samples[random_selection]
    train_label = labels[random_selection]
    sample_left = samples[~random_selection]
    label_left = labels[~random_selection]

    random_selection = np.random.rand(sample_left.shape[0]) <= 0.5
    test_sample = sample_left[random_selection]
    test_label = label_left[random_selection]
    pred_sample = sample_left[~random_selection]
    pred_label = label_left[~random_selection]

    return (
        train_sample,
        train_label,
        test_sample,
        test_label,
        pred_sample,
        pred_label,
        mean_attr,
    )


(
    train_fea,
    train_label,
    test_fea,
    test_label,
    pred_fea,
    pred_label,
    mean_attr,
) = prepare_data()

bob_mean = mean_attr[28:]

fed_data = FedNdarray(
    partitions={
        alice: alice(lambda x: x[:, :28])(train_fea),
        bob: bob(lambda x: x[:, 28:])(train_fea),
    },
    partition_way=PartitionWay.VERTICAL,
)
test_fed_data = FedNdarray(
    partitions={
        alice: alice(lambda x: x[:, :28])(test_fea),
        bob: bob(lambda x: x[:, 28:])(test_fea),
    },
    partition_way=PartitionWay.VERTICAL,
)
test_data_label = device_y(lambda x: x)(test_label)

label = device_y(lambda x: x)(train_label)

定义 SL 模型结构#

[3]:
import torch
import torch.nn as nn
from secretflow.ml.nn.utils import BaseModule


class SLBaseNet(BaseModule):
    def __init__(self):
        super(SLBaseNet, self).__init__()
        self.linear = nn.Linear(10, 10)

    def forward(self, x):
        y = x
        return y

    def output_num(self):
        return 1


class SLFuseModel(BaseModule):
    def __init__(self, input_dim=48, output_dim=11):
        super(SLFuseModel, self).__init__()
        torch.manual_seed(1234)
        self.dense = nn.Sequential(
            nn.Linear(input_dim, 600),
            nn.ReLU(),
            nn.Linear(600, 300),
            nn.ReLU(),
            nn.Linear(300, 100),
            nn.ReLU(),
            nn.Linear(100, output_dim),
        )

    def forward(self, x):
        x = torch.cat(x, dim=1)
        return self.dense(x)

定义 SL Model#

[4]:
import torch.optim as optim
from torchmetrics import Accuracy, Precision
from secretflow.ml.nn.fl.utils import metric_wrapper, optim_wrapper
from secretflow.ml.nn import SLModel
from secretflow.ml.nn.utils import TorchModel


loss_fn = nn.CrossEntropyLoss
optim_fn = optim_wrapper(torch.optim.Adam)
base_model = TorchModel(
    model_fn=SLBaseNet,
    loss_fn=loss_fn,
    optim_fn=optim_fn,
    metrics=[
        metric_wrapper(Accuracy, task="multiclass", num_classes=11, average='micro'),
        metric_wrapper(Precision, task="multiclass", num_classes=11, average='micro'),
    ],
)

fuse_model = TorchModel(
    model_fn=SLFuseModel,
    loss_fn=loss_fn,
    optim_fn=optim_fn,
    metrics=[
        metric_wrapper(Accuracy, task="multiclass", num_classes=11, average='micro'),
        metric_wrapper(Precision, task="multiclass", num_classes=11, average='micro'),
    ],
)

base_model_dict = {
    alice: base_model,
    bob: base_model,
}

sl_model = SLModel(
    base_model_dict=base_model_dict,
    device_y=device_y,
    model_fuse=fuse_model,
    dp_strategy_dict=None,
    compressor=None,
    simulation=True,
    random_seed=1234,
    backend='torch',
    strategy='split_nn',
)
INFO:root:Create proxy actor <class 'secretflow.ml.nn.sl.backend.torch.strategy.split_nn.PYUSLTorchModel'> with party alice.
INFO:root:Create proxy actor <class 'secretflow.ml.nn.sl.backend.torch.strategy.split_nn.PYUSLTorchModel'> with party bob.

定义 attacker_builder#

定义 FeatureInferenceAttacker 中的 Generator Model#

[5]:
class Generator(nn.Module):
    def __init__(self, latent_dim=48, target_dim=20):
        super().__init__()
        self.net = nn.Sequential(
            nn.Linear(latent_dim, 600),
            nn.LayerNorm(600),
            nn.ReLU(),
            nn.Linear(600, 200),
            nn.LayerNorm(200),
            nn.ReLU(),
            nn.Linear(200, 100),
            nn.LayerNorm(100),
            nn.ReLU(),
            nn.Linear(100, target_dim),
            nn.Sigmoid(),
        )

    def forward(self, x):
        return self.net(x)

定义 FeatureInferenceAttacker 中的 data_builder#

[6]:
from torch.utils.data import Dataset, DataLoader, TensorDataset


def data_builder(data, label, batch_size):
    def prepare_data():
        alice_data = data[:, :28]
        bob_data = data[:, 28:]

        alice_dataset = TensorDataset(torch.tensor(alice_data))
        alice_dataloader = DataLoader(
            dataset=alice_dataset,
            shuffle=False,
            batch_size=batch_size,
        )

        bob_dataset = TensorDataset(torch.tensor(bob_data))
        bob_dataloader = DataLoader(
            dataset=bob_dataset,
            shuffle=False,
            batch_size=batch_size,
        )

        dataloader_dict = {'alice': alice_dataloader, 'bob': bob_dataloader}
        return dataloader_dict, dataloader_dict

    return prepare_data

定义 attacker_builder#

这里 attacker_builder 是一个字典,其元素是参与方和对应的 attacker_builder_function,通常只需要填充攻击方和对应的 attacker_builder_function。

由于本文中的特征攻击算法需要对方 base 模型参数,这里我们通过被攻击方在训练结束时将 base 模型保存到磁盘,攻击方从磁盘对应路径加载模型得到对应 base 模型来实现,因而这里双方都有对应的 attacker_builder。

[7]:
from secretflow.ml.nn.sl.attacks.fia_torch import (
    FeatureInferenceAttack,
    # SaveModelCallback,
)


def create_attacker_builder(
    model_save_path, bob_mean, pred_data, pred_label, batch_size, save_model_path
):
    def attacker_builder():
        victim_model_dict = {
            'bob': [SLBaseNet, model_save_path],
        }
        optim_fn = optim_wrapper(optim.Adam, lr=0.0001)
        generator_model = TorchModel(
            model_fn=Generator,
            loss_fn=None,
            optim_fn=optim_fn,
            metrics=None,
        )

        data_buil = data_builder(pred_data, pred_label, batch_size)

        attacker = FeatureInferenceAttack(
            victim_model_dict=victim_model_dict,
            base_model_list=['alice', 'bob'],
            attack_party='alice',
            generator_model_wrapper=generator_model,
            data_builder=data_buil,
            victim_fea_dim=20,
            attacker_fea_dim=28,
            enable_mean=True,
            enable_var=True,
            victim_mean_feature=bob_mean,
            save_model_path=save_model_path,
        )
        return attacker

    return attacker_builder


# in Algorithm 2 line 9, attacker will inference v_hat so attacker should get the whole federated model(which maybe unrealistic)
# victim bob will call this callback_builder to save base model first, then attacker alice loads this victim's model from the same path
# def create_victim_callback_builder(model_save_path):
#     def builder():
#         cb = SaveModelCallback(model_save_path)
#         return cb

#     return builder


batch_size = 64
import os
import shutil

fia_path = './model_saved'
if os.path.exists(fia_path):
    shutil.rmtree(fia_path)
os.mkdir(fia_path)
model_save_path = fia_path + '/sl_model_victim'
generator_save_path = fia_path + '/generator'

# callback_dict = {
#     alice: create_attacker_builder(
#         model_save_path,
#         bob_mean,
#         pred_fea,
#         pred_label,
#         batch_size,
#         generator_save_path,
#     ),
#     bob: create_victim_callback_builder(model_save_path),
# }

开始训练和攻击#

[8]:
sl_model.fit(
    fed_data,
    label,
    validation_data=(test_fed_data, test_data_label),
    epochs=1,
    batch_size=batch_size,
    shuffle=False,
    random_seed=1234,
    dataset_builder=None,
    # callbacks=callback_dict, # 暂时注释掉,callback完成后恢复 @caibei
)
INFO:root:SL Train Params: {'x': FedNdarray(partitions={PYURuntime(alice): <secretflow.device.device.pyu.PYUObject object at 0x7f937485e4c0>, PYURuntime(bob): <secretflow.device.device.pyu.PYUObject object at 0x7f9374883730>}, partition_way=<PartitionWay.VERTICAL: 'vertical'>), 'y': <secretflow.device.device.pyu.PYUObject object at 0x7f937485ebe0>, 'batch_size': 64, 'epochs': 1, 'verbose': 1, 'callbacks': {PYURuntime(alice): <function create_attacker_builder.<locals>.attacker_builder at 0x7f9297b8bee0>, PYURuntime(bob): <function create_victim_callback_builder.<locals>.builder at 0x7f9374d0fdc0>}, 'validation_data': (FedNdarray(partitions={PYURuntime(alice): <secretflow.device.device.pyu.PYUObject object at 0x7f9374883dc0>, PYURuntime(bob): <secretflow.device.device.pyu.PYUObject object at 0x7f93748835b0>}, partition_way=<PartitionWay.VERTICAL: 'vertical'>), <secretflow.device.device.pyu.PYUObject object at 0x7f9374594190>), 'shuffle': False, 'sample_weight': None, 'validation_freq': 1, 'dp_spent_step_freq': None, 'dataset_builder': None, 'audit_log_params': {}, 'random_seed': 1234, 'audit_log_dir': None, 'self': <secretflow.ml.nn.sl.sl_model.SLModel object at 0x7f9297bcc400>}
(pid=1843185) 2023-09-26 19:49:48.399383: W tensorflow/compiler/xla/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libcudart.so.11.0'; dlerror: libcudart.so.11.0: cannot open shared object file: No such file or directory; LD_LIBRARY_PATH: /opt/rh/gcc-toolset-11/root/usr/lib64:/opt/rh/gcc-toolset-11/root/usr/lib:/opt/rh/gcc-toolset-11/root/usr/lib64/dyninst:/opt/rh/gcc-toolset-11/root/usr/lib/dyninst
(pid=1843449) 2023-09-26 19:49:48.657976: W tensorflow/compiler/xla/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libcudart.so.11.0'; dlerror: libcudart.so.11.0: cannot open shared object file: No such file or directory; LD_LIBRARY_PATH: /opt/rh/gcc-toolset-11/root/usr/lib64:/opt/rh/gcc-toolset-11/root/usr/lib:/opt/rh/gcc-toolset-11/root/usr/lib64/dyninst:/opt/rh/gcc-toolset-11/root/usr/lib/dyninst
(pid=1843185) 2023-09-26 19:49:49.258363: W tensorflow/compiler/xla/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libnvinfer.so.7'; dlerror: libnvinfer.so.7: cannot open shared object file: No such file or directory; LD_LIBRARY_PATH: /opt/rh/gcc-toolset-11/root/usr/lib64:/opt/rh/gcc-toolset-11/root/usr/lib:/opt/rh/gcc-toolset-11/root/usr/lib64/dyninst:/opt/rh/gcc-toolset-11/root/usr/lib/dyninst
(pid=1843185) 2023-09-26 19:49:49.258463: W tensorflow/compiler/xla/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libnvinfer_plugin.so.7'; dlerror: libnvinfer_plugin.so.7: cannot open shared object file: No such file or directory; LD_LIBRARY_PATH: /opt/rh/gcc-toolset-11/root/usr/lib64:/opt/rh/gcc-toolset-11/root/usr/lib:/opt/rh/gcc-toolset-11/root/usr/lib64/dyninst:/opt/rh/gcc-toolset-11/root/usr/lib/dyninst
(pid=1843185) 2023-09-26 19:49:49.258475: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Cannot dlopen some TensorRT libraries. If you would like to use Nvidia GPU with TensorRT, please make sure the missing libraries mentioned above are installed properly.
(pid=1843449) 2023-09-26 19:49:49.494645: W tensorflow/compiler/xla/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libnvinfer.so.7'; dlerror: libnvinfer.so.7: cannot open shared object file: No such file or directory; LD_LIBRARY_PATH: /opt/rh/gcc-toolset-11/root/usr/lib64:/opt/rh/gcc-toolset-11/root/usr/lib:/opt/rh/gcc-toolset-11/root/usr/lib64/dyninst:/opt/rh/gcc-toolset-11/root/usr/lib/dyninst
(pid=1843449) 2023-09-26 19:49:49.494731: W tensorflow/compiler/xla/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libnvinfer_plugin.so.7'; dlerror: libnvinfer_plugin.so.7: cannot open shared object file: No such file or directory; LD_LIBRARY_PATH: /opt/rh/gcc-toolset-11/root/usr/lib64:/opt/rh/gcc-toolset-11/root/usr/lib:/opt/rh/gcc-toolset-11/root/usr/lib64/dyninst:/opt/rh/gcc-toolset-11/root/usr/lib/dyninst
(pid=1843449) 2023-09-26 19:49:49.494741: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Cannot dlopen some TensorRT libraries. If you would like to use Nvidia GPU with TensorRT, please make sure the missing libraries mentioned above are installed properly.
  0%|          | 0/5 [00:00<?, ?it/s](PYUSLTorchModel pid=1843185) /home/ssd2/zhaocaibei/miniconda3/envs/jupyter/lib/python3.8/site-packages/secretflow/ml/nn/sl/attack/torch/feature_inference_attack.py:112: UserWarning: The given NumPy array is not writable, and PyTorch does not support non-writable tensors. This means writing to this tensor will result in undefined behavior. You may want to copy the array to protect its data or make it writable before converting it to a tensor. This type of warning will be suppressed for the rest of this program. (Triggered internally at ../torch/csrc/utils/tensor_numpy.cpp:206.)
(PYUSLTorchModel pid=1843185)   self.victim_mean_feature = torch.from_numpy(victim_mean_feature)
(_run pid=1835170) 2023-09-26 19:49:52.135553: W tensorflow/compiler/xla/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libcudart.so.11.0'; dlerror: libcudart.so.11.0: cannot open shared object file: No such file or directory; LD_LIBRARY_PATH: /opt/rh/gcc-toolset-11/root/usr/lib64:/opt/rh/gcc-toolset-11/root/usr/lib:/opt/rh/gcc-toolset-11/root/usr/lib64/dyninst:/opt/rh/gcc-toolset-11/root/usr/lib/dyninst
(_run pid=1835170) 2023-09-26 19:49:52.965082: W tensorflow/compiler/xla/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libnvinfer.so.7'; dlerror: libnvinfer.so.7: cannot open shared object file: No such file or directory; LD_LIBRARY_PATH: /opt/rh/gcc-toolset-11/root/usr/lib64:/opt/rh/gcc-toolset-11/root/usr/lib:/opt/rh/gcc-toolset-11/root/usr/lib64/dyninst:/opt/rh/gcc-toolset-11/root/usr/lib/dyninst
(_run pid=1835170) 2023-09-26 19:49:52.965192: W tensorflow/compiler/xla/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libnvinfer_plugin.so.7'; dlerror: libnvinfer_plugin.so.7: cannot open shared object file: No such file or directory; LD_LIBRARY_PATH: /opt/rh/gcc-toolset-11/root/usr/lib64:/opt/rh/gcc-toolset-11/root/usr/lib:/opt/rh/gcc-toolset-11/root/usr/lib64/dyninst:/opt/rh/gcc-toolset-11/root/usr/lib/dyninst
(_run pid=1835170) 2023-09-26 19:49:52.965203: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Cannot dlopen some TensorRT libraries. If you would like to use Nvidia GPU with TensorRT, please make sure the missing libraries mentioned above are installed properly.
100%|██████████| 5/5 [00:03<00:00,  1.50it/s, epoch: 1/1 -  train_loss:1.714323878288269  train_MulticlassAccuracy:0.7785466909408569  train_MulticlassPrecision:0.7785466909408569  val_val_loss:1.5049391984939575  val_MulticlassAccuracy:1.0  val_MulticlassPrecision:1.0 ]
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 0, loss is 1.1522607803344727
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 1, loss is 0.8157393336296082
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 2, loss is 0.6134978532791138
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 3, loss is 0.48556119203567505
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 4, loss is 0.4039228558540344
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 5, loss is 0.3467817008495331
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 6, loss is 0.30952346324920654
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 7, loss is 0.2818766236305237
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 8, loss is 0.25987595319747925
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 9, loss is 0.24386532604694366
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 10, loss is 0.22900035977363586
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 11, loss is 0.2106342762708664
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 12, loss is 0.20029443502426147
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 13, loss is 0.19823205471038818
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 14, loss is 0.18952125310897827
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 15, loss is 0.1832481324672699
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 16, loss is 0.1828383505344391
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 17, loss is 0.17258648574352264
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 18, loss is 0.17232480645179749
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 19, loss is 0.1667376607656479
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 20, loss is 0.15784838795661926
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 21, loss is 0.15870268642902374
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 22, loss is 0.15539318323135376
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 23, loss is 0.1502450406551361
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 24, loss is 0.15154865384101868
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 25, loss is 0.1471061408519745
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 26, loss is 0.1450311243534088
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 27, loss is 0.14683523774147034
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 28, loss is 0.14344236254692078
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 29, loss is 0.13282963633537292
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 30, loss is 0.13793230056762695
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 31, loss is 0.13422174751758575
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 32, loss is 0.1318027377128601
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 33, loss is 0.12955468893051147
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 34, loss is 0.12937012314796448
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 35, loss is 0.1284986287355423
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 36, loss is 0.1253005415201187
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 37, loss is 0.13130077719688416
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 38, loss is 0.1258171647787094
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 39, loss is 0.12141703069210052
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 40, loss is 0.11995712667703629
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 41, loss is 0.1222689226269722
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 42, loss is 0.12318340688943863
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 43, loss is 0.12048806250095367
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 44, loss is 0.11977540701627731
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 45, loss is 0.11720554530620575
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 46, loss is 0.11837649345397949
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 47, loss is 0.11739760637283325
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 48, loss is 0.11748425662517548
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 49, loss is 0.11602818965911865
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 50, loss is 0.11085663735866547
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 51, loss is 0.11347486078739166
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 52, loss is 0.11071737110614777
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 53, loss is 0.1132960245013237
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 54, loss is 0.11038753390312195
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 55, loss is 0.10890733450651169
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 56, loss is 0.10951762646436691
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 57, loss is 0.10976753383874893
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 58, loss is 0.11292025446891785
(PYUSLTorchModel pid=1843185) INFO:root:In epoch 59, loss is 0.1031401976943016
(PYUSLTorchModel pid=1843185) INFO:root:Mean generator loss: 0.04493473656475544
(PYUSLTorchModel pid=1843185) INFO:root:Mean random guess loss: 0.17182568460702896
(PYUSLTorchModel pid=1843185) INFO:root:Mean generator loss Per Feature: [0.00954273 0.02475509 0.03384783 0.02044668 0.03715948 0.00336939
(PYUSLTorchModel pid=1843185)  0.03370478 0.03777658 0.07355641 0.02407766 0.25157754 0.01827634
(PYUSLTorchModel pid=1843185)  0.02219832 0.0097403  0.00756813 0.01786439 0.02057017 0.0055741
(PYUSLTorchModel pid=1843185)  0.00618307 0.24090575]
(PYUSLTorchModel pid=1843185) INFO:root:Mean random guess loss Per Feature: [0.14084914 0.15443441 0.15860398 0.15230184 0.19461861 0.12846064
(PYUSLTorchModel pid=1843185)  0.18179844 0.16156382 0.21596114 0.20383138 0.33147337 0.13473797
(PYUSLTorchModel pid=1843185)  0.13449802 0.10377935 0.11541938 0.16272019 0.14198899 0.14747391
(PYUSLTorchModel pid=1843185)  0.12969266 0.34230641]
[8]:
{'train_loss': [array(1.7143239, dtype=float32)],
 'train_MulticlassAccuracy': [tensor(0.7785)],
 'train_MulticlassPrecision': [tensor(0.7785)],
 'val_val_loss': [array(1.5049392, dtype=float32)],
 'val_MulticlassAccuracy': [tensor(1.)],
 'val_MulticlassPrecision': [tensor(1.)]}

总结#

本文通过 UCI Sensorless Drive Diagnosis 数据集上的特征攻击任务来演示了如何通过隐语来使用 FeatureInferenceAttack。

您可以:

  1. 下载并拆分数据集,准备训练、攻击使用的数据

  2. 定义拆分模型结构及 SL Model

  3. 定义 attacker_builder,在其中定义攻击需要的 data_builder 和 FeatureInfereceAttacker

  4. 调用 SL Model 进行训练攻击

您可以在自己的数据集上进行尝试,如有任何问题,可以在 github 进行训练即可。