diff --git a/examples/privacy/gradient_inversion_attack/LICENSE.md b/examples/privacy/gradient_inversion_attack/LICENSE.md new file mode 100644 index 0000000000000000000000000000000000000000..c4b49ed8f4ac20f8349dae9fcbc54d72875b2fbc --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/LICENSE.md @@ -0,0 +1,13 @@ +Copyright 2024 Huawei Technologies Co., Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/examples/privacy/gradient_inversion_attack/README.md b/examples/privacy/gradient_inversion_attack/README.md new file mode 100644 index 0000000000000000000000000000000000000000..3c874c21bccd569dd884f52acb17e9d011381480 --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/README.md @@ -0,0 +1,67 @@ +# 梯度逆向攻击(Gradient Inversion Attack) + +使用 MindSpore 框架实现梯度逆向攻击(威胁模型可见参考文献[1]). + +我们提供了3种梯度逆向攻击算法(InvGrad, SeeThrough, StepWise,算法细节见参考文献[2][3][4])、3种数据类型以及2种模型组合的攻击实例。 + +同时,使用者可以参考我们提供的攻击测试实例,并基于我们提供的函数,快速扩展出更多的测试案例。 + +除此之外,我们还提供了差分隐私、梯度裁剪等防御方法防御梯度泄露攻击的功能。 + + +## 配置 +### 依赖 +环境配置请参考 `minimal_environment.yml`。 + +### 硬件 +我们建议使用GPU来运行这些代码。 + + +## 使用 +请在使用前准备好数据集。 + +### 数据集 +你可以使用公用的机器学习数据集,如: *CIFAR-100*, *Tiny-ImageNet*. 请在使用前传入正确的数据路径 `--data_path`. + +或者你也可以使用自制的图像数据(224x224 px),请将其放置于文件夹 */custom_data/1_img/* 中。 + + +### 运行攻击 +我们提供了用户友好的运行方式。 +如果你想要运行攻击(with default configuration),只需要在终端运行: +``` +python main.py +``` +或者你可以传入更多的参数: `--out_put`, `--data_path`, `--dataset`, `--model`, `--alg_name`, `--defense`, `--num_data_points`, `--max_iterations`, +`--step_size`, `--TV_scale`, `--TV_start`, `--BN_scale`, `--BN_start` and `--callback`. + +| argument | description | +|-----------------|--------------------------------------------------------------------------| +| out_put | str: 输出路径 | +| data_path | str: 数据集的路径 | +| dataset | str: 'TinyImageNet', 'CIFAR100', 'WebImage' | +| model | str: 'resnet18', 'resnet34' | +| alg_name | str: 'InvGrad', 'SeeThrough', 'StepWise' | +| defense | str: 'None', 'Vicinal Augment', 'Differential Privacy', 'Gradient Prune' | +| num_data_points | int: 同时重构的数据量 | +| max_iterations | int: 攻击最大迭代次数 | +| step_size | float: 攻击时的优化步长 | +| TV_scale | float: Total Variation 正则项权重 | +| TV_start | int: Total Variation 开始时的步数 | +| BN_scale | float: Batch Normalization 正则项权重 | +| TV_start | int: Batch Normalization 开始时的步数 | +| callback | int: 每经过该步数输出一次攻击结果 | + + +## 开源协议 +请参见文件: `LICENSE.md`. + +## 参考文献 +[1] Zhu, Ligeng, Zhijian Liu, and Song Han. "Deep leakage from gradients." in NeurIPS, 2019. + +[2] Geiping, Jonas, et al. "Inverting gradients-how easy is it to break privacy in federated learning?." in NeurIPS, 2020. + +[3] Yin, Hongxu, et al. "See through gradients: Image batch recovery via gradinversion." in CVPR, 2021. + +[4] Ye, Zipeng, et al. "High-Fidelity Gradient Inversion in Distributed Learning." in AAAI, 2024. + diff --git a/examples/privacy/gradient_inversion_attack/breaching/__init__.py b/examples/privacy/gradient_inversion_attack/breaching/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..7e93105c328f7b11b17d7f8ddf24d9b824c71802 --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/breaching/__init__.py @@ -0,0 +1,35 @@ +from breaching import attacks +from breaching import cases +# from breaching import utils + +__all__ = ["attacks", "cases"] + + +import hydra + +"""Construct interfaces to cfg folders for use in packaged installations:""" + + +def get_config(overrides=[]): + """Return default hydra config.""" + with hydra.initialize(config_path="config", version_base="1.1"): + cfg = hydra.compose(config_name="cfg", overrides=overrides) + print(f"Investigating use case {cfg.case.name} with server type {cfg.case.server.name}.") + return cfg + + +def get_attack_config(attack="invertinggradients", overrides=[]): + """Return default hydra config for a given attack.""" + with hydra.initialize(config_path="config/attack", version_base="1.1"): + cfg = hydra.compose(config_name=attack, overrides=overrides) + print(f"Loading attack configuration {cfg.attack_type}-{cfg.type}.") + return cfg + + +def get_case_config(case="1_single_image_small", overrides=[]): + """Return default hydra config for a given attack.""" + with hydra.initialize(config_path="config/case", version_base="1.1"): + cfg = hydra.compose(config_name=case, overrides=overrides) + print(f"Investigating use case {cfg.name} with server type {cfg.server.name}.") + return cfg + diff --git a/examples/privacy/gradient_inversion_attack/breaching/attacks/__init__.py b/examples/privacy/gradient_inversion_attack/breaching/attacks/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..419af36f13b48c3e8e708df0efec1c34efd61f4d --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/breaching/attacks/__init__.py @@ -0,0 +1,13 @@ +from .optimization_based_attack import OptimizationBasedAttacker + + +def prepare_attack(model, loss, cfg_attack): + if cfg_attack.attack_type == "optimization": + attacker = OptimizationBasedAttacker(model, loss, cfg_attack) + else: + raise ValueError(f"Invalid type of attack {cfg_attack.attack_type} given.") + + return attacker + + +__all__ = ["prepare_attack"] diff --git a/examples/privacy/gradient_inversion_attack/breaching/attacks/auxiliaries/__init__.py b/examples/privacy/gradient_inversion_attack/breaching/attacks/auxiliaries/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/examples/privacy/gradient_inversion_attack/breaching/attacks/auxiliaries/common.py b/examples/privacy/gradient_inversion_attack/breaching/attacks/auxiliaries/common.py new file mode 100644 index 0000000000000000000000000000000000000000..a0ac8b6e553f08ee2668163802aeb37e7efa33a5 --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/breaching/attacks/auxiliaries/common.py @@ -0,0 +1,44 @@ +from mindspore import nn +import mindspore as ms + +class StepLR: + def __init__(self, step_size, max_iter, gamma=0.33): + self.max_it = max_iter + self.mile1, self.mile2, self.mile3 = max_iter//2.667, max_iter//1.6, max_iter//1.142 + self.lr0 = step_size + self.lr1 = self.lr0 * gamma + self.lr2 = self.lr1 * gamma + self.lr3 = self.lr2 * gamma + + def __call__(self, cur_step): + if cur_step < self.mile1: + return self.lr0 + elif cur_step < self.mile2: + return self.lr1 + elif cur_step < self.mile3: + return self.lr2 + else: + return self.lr3 + + +def optimizer_lookup(params, optim_name, step_size, scheduler=None, max_iterations=10_000): + if optim_name.lower() == "adam": + optimizer = nn.Adam([params], learning_rate=step_size) + elif optim_name.lower() == "sgd": + optimizer = nn.SGD([params], learning_rate=step_size, momentum=0.0) + else: + raise ValueError(f"Invalid optimizer {optim_name} given.") + + if scheduler == "step-lr": + scheduler = StepLR(step_size, max_iterations) + elif scheduler == "cosine-decay": + scheduler = nn.CosineDecayLR(0.0, step_size, max_iterations) + elif scheduler == "linear": + scheduler = nn.PolynomialDecayLR(step_size, 0.0, max_iterations, power=1.0) + return optimizer, scheduler + + +if __name__ == "__main__": + sc = nn.CosineDecayLR(0.0, 0.1, 10) + for i in range(10): + print(sc(ms.Tensor(i))) diff --git a/examples/privacy/gradient_inversion_attack/breaching/attacks/auxiliaries/deepinversion.py b/examples/privacy/gradient_inversion_attack/breaching/attacks/auxiliaries/deepinversion.py new file mode 100644 index 0000000000000000000000000000000000000000..763d925ac6ca4dc40f442006a6c972d64b27c5bc --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/breaching/attacks/auxiliaries/deepinversion.py @@ -0,0 +1,22 @@ +import mindspore as ms + + +class DeepInversionFeatureHook: + + def __init__(self, module): + self.hook = module.register_forward_hook(self.hook_fn) + self.module = module + + def hook_fn(self, ids, input, output): + nch = input[0].shape[1] + mean = input[0].mean([0, 2, 3]) + var = ms.ops.transpose(input[0], (1, 0, 2, 3)).reshape([nch, -1]).var(1) + + r_feature = ms.ops.norm(self.module.moving_variance.value() - var, 2) + ms.ops.norm(self.module.moving_mean.value() - mean, 2) + + self.r_feature = r_feature + + def close(self): + self.hook.remove() + + diff --git a/examples/privacy/gradient_inversion_attack/breaching/attacks/auxiliaries/objectives.py b/examples/privacy/gradient_inversion_attack/breaching/attacks/auxiliaries/objectives.py new file mode 100644 index 0000000000000000000000000000000000000000..ac9b9f527c6b6960417ed7ec912ca63ee0b3e6c3 --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/breaching/attacks/auxiliaries/objectives.py @@ -0,0 +1,142 @@ +import mindspore as ms +from mindspore import nn +from mindspore import ops + + +class GradientLoss(nn.Cell): + + def __init__(self): + super().__init__() + + def initialize(self, cfg_impl, model): + self.model = model + self.cfg_impl = cfg_impl + + def construct(self, gradient_data, candidate, labels): + gradient, task_loss = self._grad_fn_single_step(candidate, labels) + objective = self.gradient_based_loss(gradient, gradient_data) + return objective + + def gradient_based_loss(self, gradient_rec, gradient_data): + raise NotImplementedError() + + def __repr__(self): + raise NotImplementedError() + + def _grad_fn_single_step(self, candidate, labels): + def _single_forward(candidate, labels): + predict = self.model(candidate) + task_loss = self._loss_fn(predict, labels) + tmp_loss = nn.CrossEntropyLoss()(predict, labels) + return task_loss + grad_fn1 = ops.value_and_grad(_single_forward, None, weights=self.model.trainable_params()) + task_loss, gradient = grad_fn1(candidate, labels) + return gradient, task_loss + + def _loss_fn(self, logits, labels): + logs = ops.log(ops.softmax(logits)) + loss = self._nll_loss(logs, labels) + return loss + + def _nll_loss(self, logs, labels): + loss = [-logs[i, int(j)] for i, j in enumerate(labels)] + loss = ops.stack(loss).mean() + return loss + + + +class Euclidean(GradientLoss): + + def __init__(self, scale=1.0, start=0, min_start=0, broken_tail=0, peroid_Add10=1000, add10=10, **kwargs): + super().__init__() + self.scale = scale + self.start = start + self.min_start = min_start + self.broken_tail = broken_tail + self.peroid_Add10 = peroid_Add10 + self.add10 = add10 + self.iter = 0 + + def gradient_based_loss(self, gradient_rec, gradient_data): + len_layer = len(gradient_data) + final = len_layer + if (self.iter + 1) % self.peroid_Add10 == 0: + self.start = self.start - self.add10 if (self.start - self.add10) > self.min_start else self.min_start + self.iter += 1 + objective = 0 + for count, (rec, data) in enumerate(zip(gradient_rec, gradient_data)): + if self.start <= count + 1 <= final: + objective += (rec - data).pow(2).sum() + return 0.5 * objective * self.scale + + @staticmethod + def _euclidean(gradient_rec, gradient_data): + objective = 0 + for rec, data in zip(gradient_rec, gradient_data): + objective += (rec - data).pow(2).sum() + return 0.5 * objective + + +class CosineSimilarity(GradientLoss): + + def __init__(self, scale=1.0, task_regularization=0.0, **kwargs): + super().__init__() + self.scale = scale + self.task_regularization = task_regularization + + def gradient_based_loss(self, gradient_rec, gradient_data): + return self._cosine_sim(gradient_rec, gradient_data) * self.scale + + @staticmethod + def _cosine_sim(gradient_rec, gradient_data): + scalar_product = ms.Tensor(0.0) + rec_norm = ms.Tensor(0.0) + data_norm = ms.Tensor(0.0) + + for rec, data in zip(gradient_rec, gradient_data): + scalar_product += (rec * data).sum() + rec_norm += rec.pow(2).sum() + data_norm += data.pow(2).sum() + + objective = 1.0 - scalar_product / (rec_norm.sqrt() * data_norm.sqrt()) + return objective + + +class DynaLayerRandPickedCosineSimilarity(GradientLoss): + + def __init__(self, scale=1.0, start=0, min_start=0, broken_tail=0, peroid_Add10=1000, add10=10, **kwargs): + super().__init__() + self.scale = scale + self.start = start + self.min_start = min_start + self.broken_tail = broken_tail + self.peroid_Add10 = peroid_Add10 + self.add10 = add10 + self.iter = 0 + + def gradient_based_loss(self, gradient_rec, gradient_data): + len_layer = len(gradient_data) + final = len_layer - self.broken_tail + scalar_product, rec_norm, data_norm = 0.0, 0.0, 0.0 + if (self.iter+1) % self.peroid_Add10 == 0: + self.start = self.start-self.add10 if (self.start-self.add10) > self.min_start else self.min_start + self.iter += 1 + for count, (rec, data) in enumerate(zip(gradient_rec, gradient_data)): + if self.start <= count+1 <= final: + mask = ms.ops.rand_like(data) > 0.0 + weight = 1.0 + scalar_product += (rec * data * mask).sum()*weight + rec_norm += (rec * mask).pow(2).sum()*weight + data_norm += (data * mask).pow(2).sum()*weight + + objective = 1 - scalar_product / rec_norm.sqrt() / data_norm.sqrt() + + return objective * self.scale + + + +objective_lookup = { + "euclidean": Euclidean, + "cosine-similarity": CosineSimilarity, + "dyna-layer-rand-cosine-similarity":DynaLayerRandPickedCosineSimilarity, +} diff --git a/examples/privacy/gradient_inversion_attack/breaching/attacks/auxiliaries/regularizers.py b/examples/privacy/gradient_inversion_attack/breaching/attacks/auxiliaries/regularizers.py new file mode 100644 index 0000000000000000000000000000000000000000..1198784841898573920b27bb2463dd4f584e3f10 --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/breaching/attacks/auxiliaries/regularizers.py @@ -0,0 +1,89 @@ +import mindspore as ms +from mindspore import nn +from .deepinversion import DeepInversionFeatureHook + + +class TotalVariation(nn.Cell): + + def __init__(self, scale=0.1, inner_exp=1, outer_exp=1, tv_start=0, double_opponents=False, eps=1e-8): + + super().__init__() + self.scale = scale + self.inner_exp = float(inner_exp) + self.outer_exp = float(outer_exp) + self.start = tv_start + self.eps = eps + self.double_opponents = double_opponents + + grad_weight = ms.Tensor([[0, 0, 0], [0, -1, 1], [0, 0, 0]]).unsqueeze(0).unsqueeze(1) + grad_weight = ms.ops.concat((ms.ops.transpose(grad_weight, (0,1,3,2)), grad_weight), 0) + self.groups = 6 if self.double_opponents else 3 + self.weight = ms.ops.concat([grad_weight] * self.groups, 0) + self.conv = nn.Conv2d(3,6, kernel_size=3, stride=1, pad_mode='pad', padding=1, dilation=1, group=self.groups) + self.conv.trainable_params()[0].set_data(self.weight) + + def initialize(self, models, *args, **kwargs): + pass + + def construct(self, tensor, iter=0, *args, **kwargs): + if iter < self.start: + return 100 + + diffs = self.conv(tensor) + + squares = (diffs.abs() + self.eps).pow(self.inner_exp) + squared_sums = (squares[:, 0::2] + squares[:, 1::2]).pow(self.outer_exp) + return squared_sums.mean() * self.scale + + +class NormRegularization(nn.Cell): + + def __init__(self, scale=0.1, pnorm=2.0, norm_start=0): + super().__init__() + self.scale = scale + self.pnorm = pnorm + self.start = norm_start + + def initialize(self, models, *args, **kwargs): + pass + + def construct(self, tensor, iter=0, *args, **kwargs): + if iter < self.start: + return 100 + return 1 / self.pnorm * tensor.pow(self.pnorm).mean() * self.scale + + +class DeepInversion(nn.Cell): + + def __init__(self, scale=0.1, first_bn_multiplier=10, second_bn_multiplier=10, deep_inv_start=0, deep_inv_stop=3000): + super().__init__() + self.scale = scale + self.first_bn_multiplier = first_bn_multiplier + self.second_bn_multiplier = second_bn_multiplier + self.start = deep_inv_start + self.stop = deep_inv_stop + + def initialize(self, models, *args, **kwargs): + self.losses = [] + model = models[0] + for _, module in model._children_scope_recursive(): + if isinstance(module, nn.BatchNorm2d): + self.losses.append(DeepInversionFeatureHook(module)) + + def construct(self, tensor, iter=0, *args, **kwargs): + if iter < self.start: + return 100 + if iter > self.stop: + return 0 + else: + rescale = [self.first_bn_multiplier, self.second_bn_multiplier] + [1.0 for _ in range(len(self.losses) - 2)] + feature_reg = 0 + feature_reg += sum([mod.r_feature * rescale[idx] for (idx, mod) in enumerate(self.losses)]) + return self.scale * feature_reg + + +regularizer_lookup = dict( + total_variation=TotalVariation, + norm=NormRegularization, + deep_inversion=DeepInversion, +) diff --git a/examples/privacy/gradient_inversion_attack/breaching/attacks/base_attack.py b/examples/privacy/gradient_inversion_attack/breaching/attacks/base_attack.py new file mode 100644 index 0000000000000000000000000000000000000000..c38589afdc4bff567a1792774149293fd4db5a21 --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/breaching/attacks/base_attack.py @@ -0,0 +1,136 @@ +import copy +import mindspore as ms +from .auxiliaries.common import optimizer_lookup +from mindspore import ops + + +class _BaseAttacker: + + def __init__(self, model, loss_fn, cfg_attack): + self.cfg = cfg_attack + self.model_template = copy.copy(model) + self.loss_fn = copy.copy(loss_fn) + + def reconstruct(self, server_payload, shared_data): + raise NotImplementedError() + + return reconstructed_data + + def __repr__(self): + raise NotImplementedError() + + def prepare_attack(self, server_payload, shared_data): + + shared_data = shared_data.copy() + server_payload = server_payload.copy() + + metadata = server_payload[0]["metadata"] + self.data_shape = list(metadata.shape) + if hasattr(metadata, "mean"): + self.dm = ms.Tensor(list(metadata.mean))[None, :, None, None] + self.ds = ms.Tensor(list(metadata.std))[None, :, None, None] + else: + self.dm, self.ds = ms.Tensor(0), ms.Tensor(1) + + rec_models = self._construct_models_from_payload_and_buffers(server_payload, shared_data) + shared_data = self._cast_shared_data(shared_data) + self._rec_models = rec_models + + if shared_data[0]["metadata"]["labels"] is None: + labels = self._recover_label_information(shared_data, server_payload, rec_models) + else: + labels = copy.copy(shared_data[0]["metadata"]["labels"]) + labels = labels.astype(ms.int32) + return rec_models, labels + + def _construct_models_from_payload_and_buffers(self, server_payload, shared_data): + models = [] + for idx, payload in enumerate(server_payload): + + new_model = copy.copy(self.model_template) + + # Load parameters + parameters = payload["parameters"] + if shared_data[idx]["buffers"] is not None: + buffers = shared_data[idx]["buffers"] + new_model.set_train(False) + elif payload["buffers"] is not None: + buffers = payload["buffers"] + new_model.set_train(False) + else: + new_model.set_train(True) + buffers = [] + + with ms._no_grad(): + for param, server_state in zip(new_model.trainable_params(), parameters): + param.set_data(server_state.value()) + for buffer, server_state in zip(new_model.untrainable_params(), buffers): + buffer.set_data(server_state.value()) + models.append(new_model) + return models + + def _cast_shared_data(self, shared_data): + for data in shared_data: + data["gradients"] = [g for g in data["gradients"]] + if data["buffers"] is not None: + data["buffers"] = [b for b in data["buffers"]] + return shared_data + + def _initialize_data(self, data_shape): + init_type = self.cfg.init + if init_type == "randn": + candidate = ops.randn(data_shape) + elif init_type == "randn-trunc": + candidate = (ops.randn(data_shape) * 0.1).clamp(-0.1, 0.1) + elif init_type == "rand": + candidate = (ops.rand(data_shape) * 2) - 1.0 + elif init_type == "zeros": + candidate = ops.zeros(data_shape) + else: + raise ValueError(f"Unknown initialization scheme {init_type} given.") + + candidate.requires_grad = True + return candidate + + def _init_optimizer(self, candidate): + optimizer, scheduler = optimizer_lookup( + candidate, + self.cfg.optim.optimizer, + self.cfg.optim.step_size, + scheduler=self.cfg.optim.step_size_decay, + max_iterations=self.cfg.optim.max_iterations, + ) + return optimizer, scheduler + + def _recover_label_information(self, user_data, server_payload, rec_models): + num_data_points = user_data[0]["metadata"]["num_data_points"] + num_classes = user_data[0]["gradients"][-1].shape[0] + + if self.cfg.label_strategy is None: + return None + elif self.cfg.label_strategy == "iDLG": + label_list = [] + for query_id, shared_data in enumerate(user_data): + last_weight_min = ms.ops.argmin(ops.sum(shared_data["gradients"][-2], dim=-1), axis=-1) + label_list += [last_weight_min.detach()] + labels = ops.stack(label_list) + elif self.cfg.label_strategy == "yin": + total_min_vals = ms.Tensor(0) + for query_id, shared_data in enumerate(user_data): + total_min_vals += shared_data["gradients"][-2].min(axis=-1) + labels = total_min_vals.argsort()[:num_data_points] + print(labels.shape) + # elif self.cfg.label_strategy == "ye_res34": + # n_pop, iters = 20, 200 + # labels = get_labels(user_data[0], num_data_points, n_pop, iters) + else: + raise ValueError(f"Invalid label recovery strategy {self.cfg.label_strategy} given.") + + if len(labels) < num_data_points: + labels = ms.ops.concat( + [labels, ms.ops.randint(0, num_classes, (num_data_points-len(labels)))] + ) + + labels = (labels.sort()[0]).astype(ms.int32) + print(f"Recovered labels {labels}.") + return labels diff --git a/examples/privacy/gradient_inversion_attack/breaching/attacks/optimization_based_attack.py b/examples/privacy/gradient_inversion_attack/breaching/attacks/optimization_based_attack.py new file mode 100644 index 0000000000000000000000000000000000000000..7a7512d91f2e44f80c268868ad32eb6c2ca90889 --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/breaching/attacks/optimization_based_attack.py @@ -0,0 +1,148 @@ +import math +import time +import os +from .base_attack import _BaseAttacker +from .auxiliaries.regularizers import regularizer_lookup +from .auxiliaries.objectives import objective_lookup +import mindspore as ms +from mindspore import ops +from PIL import Image + +class OptimizationBasedAttacker(_BaseAttacker): + + def __init__(self, model, loss_fn, cfg_attack): + super().__init__(model, loss_fn, cfg_attack) + objective_fn = objective_lookup.get(self.cfg.objective.type) + if objective_fn is None: + raise ValueError(f"Unknown objective type {self.cfg.objective.type} given.") + else: + self.objective = objective_fn(**self.cfg.objective) + self.regularizers = [] + try: + for key in self.cfg.regularization.keys(): + if self.cfg.regularization[key].scale > 0: + self.regularizers += [regularizer_lookup[key](**self.cfg.regularization[key])] + except AttributeError: + pass + + def reconstruct(self, server_payload, shared_data, initial_data=None, custom=None): + + rec_models, labels = self.prepare_attack(server_payload, shared_data) + candidate_solutions = self._run_trial(rec_models, shared_data, labels, custom) + reconstructed_data = dict(data=candidate_solutions, labels=labels) + + return reconstructed_data + + def _run_trial(self, rec_model, shared_data, labels, custom=None): + + open(self.txt_path, 'w') + self.gt_img = Image.open(self.cfg.save_dir + 'A_0.png') + for regularizer in self.regularizers: + regularizer.initialize(rec_model, shared_data, labels) + self.objective.initialize(self.cfg.impl, rec_model[0]) + candidate_all = [] + minimal_list = [] + + for seed in range(1): + candidate_tmp = self._initialize_data([shared_data[0]["metadata"]["num_data_points"], *self.data_shape]) + candidate_tmp = ms.Parameter(candidate_tmp) + candidate_all.append(candidate_tmp) + minimal_list.append(ms.Tensor(float("inf"))) + best_candidate = ops.randn_like(candidate_tmp) + + optimizer, scheduler = [], [] + for seed in range(1): + opt_tmp, sched_tmp = self._init_optimizer(candidate_all[seed]) + opt_tmp.update_parameters_name('data') + optimizer.append(opt_tmp) + scheduler.append(sched_tmp) + current_wallclock = time.time() + self.save_flag = 0 + + try: + for iteration in range(self.cfg.optim.max_iterations): + + for seed in range(1): + candidate = candidate_all[seed] + optim = optimizer[seed] + grad_fn = ms.value_and_grad(self._forward_total_loss, None, optim.parameters) + objective_value = self._get_obj_and_step(candidate, shared_data[0]["gradients"], labels, iteration, grad_fn, optim, scheduler[seed]) + + with ms._no_grad(): + if self.cfg.optim.boxed: + max_p = (1 - self.dm) / self.ds + min_p = -self.dm / self.ds + candidate.set_data(ops.clamp(candidate, min_p, max_p)) + if "peroid_Add10" in self.cfg.objective.keys(): + if objective_value < minimal_list[seed] or (iteration+1) % self.cfg.objective.peroid_Add10 == 0: + minimal_list[seed] = objective_value.item() + best_candidate = ms.Tensor(candidate) + elif objective_value < minimal_list[seed]: + minimal_list[seed] = objective_value.item() + best_candidate = ms.Tensor(candidate) + + if iteration + 1 == self.cfg.optim.max_iterations or iteration % self.cfg.optim.callback == 0: + timestamp = time.time() + obj_value = math.modf(float(objective_value))[0] + math.modf(float(objective_value))[1] % 10 + print(f"{self.save_flag}|| It: {iteration + 1} | Rec. loss: {obj_value:2.4f} | T: {timestamp - current_wallclock:4.2f}s\n") + with open(self.txt_path, 'a') as f: + f.write( + f"{self.save_flag}|| It: {iteration + 1} | Rec. loss: {obj_value:2.4f} | T: {timestamp - current_wallclock:4.2f}s\n" + ) + current_wallclock = timestamp + # self.gt_img.save(self.cfg.save_dir + f'A_{self.save_flag}.png') + if custom is not None: + if "save_dir" not in self.cfg.keys(): + raise AttributeError('saving path is not given!!!!!!!!') + else: + if not os.path.exists(self.cfg.save_dir): + os.mkdir(self.cfg.save_dir) + save_path = self.cfg.save_dir + f'recon_{iteration + 1}.png' + custom.save_recover(best_candidate, save_pth=save_path) + self.save_flag += 1 + + if not ms.ops.isfinite(objective_value): + print(f"Recovery loss is non-finite in iteration {iteration}, seed {seed}. Cancelling reconstruction!") + break + + except KeyboardInterrupt: + print(f"Recovery interrupted manually in seed {seed}, iteration {iteration}!") + pass + + return best_candidate + + def _get_obj_and_step(self, candidate, shared_grads, labels, iteration, grad_fn, optim, sched): + total_objective, grad = grad_fn(candidate, shared_grads, labels, iteration) + lr = sched(ms.Tensor(iteration)) + optim.learning_rate.set_data(lr) + grad = grad[0] + with ms._no_grad(): + if self.cfg.optim.langevin_noise > 0: + step_size = lr + noise_map = ops.randn_like(candidate.value()) + grad += self.cfg.optim.langevin_noise * step_size * noise_map + if self.cfg.optim.grad_clip is not None: + grad_norm = candidate.value().norm() + if grad_norm > self.cfg.optim.grad_clip: + grad *= self.cfg.optim.grad_clip / (grad_norm + 1e-8) + if self.cfg.optim.signed is not None: + if self.cfg.optim.signed == "soft": + scaling_factor = ( + 1 - iteration / self.cfg.optim.max_iterations + ) + grad = ops.tanh(grad*scaling_factor)/scaling_factor + elif self.cfg.optim.signed == "hard": + grad = ops.sign(grad) + else: + pass + grad = tuple([grad]) + optim(grad) + return total_objective + + def _forward_total_loss(self, candidate, shared_grads, labels, iteration): + objective_tmp = self.objective(shared_grads, candidate, labels) + total_objective = 0 + total_objective += objective_tmp + for regularizer in self.regularizers: + total_objective += regularizer(candidate, iter=iteration) + return total_objective diff --git a/examples/privacy/gradient_inversion_attack/breaching/cases/__init__.py b/examples/privacy/gradient_inversion_attack/breaching/cases/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..3731723a29e669c09ad757d8ff8d198619699dd1 --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/breaching/cases/__init__.py @@ -0,0 +1,15 @@ +from .servers import construct_server +from .users import construct_user +from .models import construct_model +from .data import construct_dataloader + +__all__ = ["construct_server", "construct_user", "construct_model", "construct_case", "construct_dataloader"] + + +def construct_case(cfg_case): + model, loss_fn = construct_model(cfg_case.model, cfg_case.data, pretrained=cfg_case.server.pretrained) + # Server: + server = construct_server(model, loss_fn, cfg_case) + # User: + user = construct_user(model, loss_fn, cfg_case) + return user, server, model, loss_fn diff --git a/examples/privacy/gradient_inversion_attack/breaching/cases/data/__init__.py b/examples/privacy/gradient_inversion_attack/breaching/cases/data/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..2b497fe23e42d0841fdbe572ad7e1b555b18e6b6 --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/breaching/cases/data/__init__.py @@ -0,0 +1,3 @@ +from .data_preparation import construct_dataloader + +__all__ = ["construct_dataloader"] diff --git a/examples/privacy/gradient_inversion_attack/breaching/cases/data/data_preparation.py b/examples/privacy/gradient_inversion_attack/breaching/cases/data/data_preparation.py new file mode 100644 index 0000000000000000000000000000000000000000..6503e3342e408fe6e6c9996cd6ca6990d13ff2e4 --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/breaching/cases/data/data_preparation.py @@ -0,0 +1,38 @@ +from .data_utils import TinyImageNetDatasetPre, Cifar100DatasetPre +import warnings +from mindspore.dataset import GeneratorDataset + +warnings.filterwarnings("ignore", "(Possibly )?corrupt EXIF data", UserWarning) + + +class EmptyLoader: + def __init__(self): + self.name = None + + +def construct_dataloader(cfg_data): + if cfg_data.name == "TinyImageNet": + loader = TinyImageNetDatasetPre(cfg_data=cfg_data) + dataloader = GeneratorDataset(source=loader, shuffle=True, column_names=["data", "label"]) + elif cfg_data.name == "CIFAR100": + loader = Cifar100DatasetPre(cfg_data=cfg_data) + dataloader = GeneratorDataset(source=loader, shuffle=True, column_names=["data", "label"]) + else: + dataloader = EmptyLoader() + dataloader.name = cfg_data.name + return dataloader + + +if __name__ == "__main__": + class cfg_data_tmp: + path = '../../../../../data' + mean = [0.4789886474609375, 0.4457630515098572, 0.3944724500179291] + std = [0.27698642015457153, 0.2690644860267639, 0.2820819020271301] + + cfg_data = cfg_data_tmp + + loader = Cifar100DatasetPre(cfg_data) + dataset = GeneratorDataset(source=loader, shuffle=True, column_names=["data", "label"]).batch(batch_size=4) + data, label = next(dataset.create_tuple_iterator()) + print(type(data)) + print(label.dtype) diff --git a/examples/privacy/gradient_inversion_attack/breaching/cases/data/data_utils.py b/examples/privacy/gradient_inversion_attack/breaching/cases/data/data_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..cf0979577f6ca42cac85b484d8cfb27af17c14f5 --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/breaching/cases/data/data_utils.py @@ -0,0 +1,116 @@ +from PIL import Image +import os +import glob +from mindspore.dataset import transforms, vision +import pickle +import mindspore as ms +import numpy as np + + +def unpickle(file): + with open(file, 'rb') as fo: + dict = pickle.load(fo, encoding='bytes') + return dict + + +class Cifar100DatasetPre: + folder = "cifar-100-python" + def __init__(self, cfg_data, split="train"): + self.root = cfg_data.path + self.split = split + self.path = os.path.join(self.root, self.folder, self.split) + self._read_all_data_labels() + mean = list(cfg_data.mean) + std = list(cfg_data.std) + self.trans = transforms.Compose( + [ + vision.Rescale(1.0 / 255.0, 0), + vision.Normalize(mean=mean, std=std), + vision.HWC2CHW() + ] + ) + + def __len__(self): + """Return length via image paths.""" + return len(self.labels) + + def __getitem__(self, index): + img = self.data[index] + img = self.trans(img) + label = ms.Tensor(self.labels[index], dtype=ms.int32) + if self.split == "test": + return img, None + else: + return img, label + + def _read_all_data_labels(self): + data_dict = unpickle(self.path) + self.data = np.transpose(data_dict[b'data'].reshape(-1, 3, 32, 32), axes=(0,2,3,1)) + self.labels = data_dict[b'fine_labels'] + + +class TinyImageNetDatasetPre: + + EXTENSION = "JPEG" + NUM_IMAGES_PER_CLASS = 500 + CLASS_LIST_FILE = "wnids.txt" + VAL_ANNOTATION_FILE = "val_annotations.txt" + CLASSES = "words.txt" + folder = "tiny-imagenet-200" + + def __init__(self, cfg_data, split="train"): + self.root = cfg_data.path + self.split = split + self.split_dir = os.path.join(self.root, self.folder, self.split) + self.image_paths = sorted( + glob.iglob(os.path.join(self.split_dir, "**", "*.%s" % self.EXTENSION), recursive=True) + ) + self.labels = {} + self._parse_labels() + mean = list(cfg_data.mean) + std = list(cfg_data.std) + self.trans = transforms.Compose( + [ + vision.Rescale(1.0 / 255.0, 0), + vision.Normalize(mean=mean, std=std), + vision.HWC2CHW() + ] + ) + + def __len__(self): + """Return length via image paths.""" + return len(self.image_paths) + + def __getitem__(self, index): + img = Image.open(self.image_paths[index]) + img = img.convert("RGB") + img = self.trans(img)[0] + target = ms.Tensor(self.targets[index], dtype=ms.int32) + if self.split == "test": + return img, None + else: + return img, target + + def _parse_labels(self): + with open(os.path.join(self.root, self.folder, self.CLASS_LIST_FILE), "r") as fp: + self.label_texts = sorted([text.strip() for text in fp.readlines()]) + self.label_text_to_number = {text: i for i, text in enumerate(self.label_texts)} + + if self.split == "train": + for label_text, i in self.label_text_to_number.items(): + for cnt in range(self.NUM_IMAGES_PER_CLASS): + self.labels["%s_%d.%s" % (label_text, cnt, self.EXTENSION)] = i + elif self.split == "val": + with open(os.path.join(self.split_dir, self.VAL_ANNOTATION_FILE), "r") as fp: + for line in fp.readlines(): + terms = line.split("\t") + file_name, label_text = terms[0], terms[1] + self.labels[file_name] = self.label_text_to_number[label_text] + # Build class names + label_text_to_word = dict() + with open(os.path.join(self.root, self.folder, self.CLASSES), "r") as file: + for line in file: + label_text, word = line.split("\t") + label_text_to_word[label_text] = word.split(",")[0].rstrip("\n") + self.classes = [label_text_to_word[label] for label in self.label_texts] + self.targets = [self.labels[os.path.basename(file_path)] for file_path in self.image_paths] diff --git a/examples/privacy/gradient_inversion_attack/breaching/cases/models/__init__.py b/examples/privacy/gradient_inversion_attack/breaching/cases/models/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..40908ed10a971d8fe4a94ab742dfa6c37f8f5d45 --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/breaching/cases/models/__init__.py @@ -0,0 +1,3 @@ +from .model_preparation import construct_model + +__all__ = ["construct_model"] \ No newline at end of file diff --git a/examples/privacy/gradient_inversion_attack/breaching/cases/models/cus_ResNet.py b/examples/privacy/gradient_inversion_attack/breaching/cases/models/cus_ResNet.py new file mode 100644 index 0000000000000000000000000000000000000000..d15cf649bde2ea8c1596ce3c309e60f952e201fe --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/breaching/cases/models/cus_ResNet.py @@ -0,0 +1,91 @@ +"""resnet in pytorch + + + +[1] Kaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sun. + + Deep Residual Learning for Image Recognition + https://arxiv.org/abs/1512.03385v1 +""" + +import torch +import torch.nn as nn + +class BasicBlock(nn.Module): + expansion = 1 + + def __init__(self, in_channels, out_channels, stride=1): + super().__init__() + + #residual function + self.residual_function = nn.Sequential( + nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride, padding=1, bias=False), + nn.BatchNorm2d(out_channels), + nn.ReLU(inplace=True), + nn.Conv2d(out_channels, out_channels * BasicBlock.expansion, kernel_size=3, padding=1, bias=False), + nn.BatchNorm2d(out_channels * BasicBlock.expansion) + ) + + self.shortcut = nn.Sequential() + + if stride != 1 or in_channels != BasicBlock.expansion * out_channels: + self.shortcut = nn.Sequential( + nn.Conv2d(in_channels, out_channels * BasicBlock.expansion, kernel_size=1, stride=stride, bias=False), + nn.BatchNorm2d(out_channels * BasicBlock.expansion) + ) + + def forward(self, x): + return nn.ReLU(inplace=True)(self.residual_function(x) + self.shortcut(x)) + + +class ResNet(nn.Module): + + def __init__(self, block, num_block, num_classes=100): + super().__init__() + + self.in_channels = 64 + + self.conv1 = nn.Sequential( + nn.Conv2d(3, 64, kernel_size=3, padding=1, bias=False), + nn.BatchNorm2d(64), + nn.ReLU(inplace=True)) + self.conv2_x = self._make_layer(block, 64, num_block[0], 1) + self.conv3_x = self._make_layer(block, 128, num_block[1], 2) + self.conv4_x = self._make_layer(block, 256, num_block[2], 2) + self.conv5_x = self._make_layer(block, 512, num_block[3], 2) + self.avg_pool = nn.AdaptiveAvgPool2d((1, 1)) + self.fc = nn.Linear(512 * block.expansion, num_classes) + + def _make_layer(self, block, out_channels, num_blocks, stride): + strides = [stride] + [1] * (num_blocks - 1) + layers = [] + for stride in strides: + layers.append(block(self.in_channels, out_channels, stride)) + self.in_channels = out_channels * block.expansion + + return nn.Sequential(*layers) + + def forward(self, x): + output = self.conv1(x) + output = self.conv2_x(output) + output = self.conv3_x(output) + output = self.conv4_x(output) + output = self.conv5_x(output) + output = self.avg_pool(output) + output = output.view(output.size(0), -1) + output = self.fc(output) + + return output + + +def resnet18(num_classes=100): + """ return a ResNet 18 object + """ + return ResNet(BasicBlock, [2, 2, 2, 2], num_classes) + + +def resnet34(num_classes=100): + """ return a ResNet 34 object + """ + return ResNet(BasicBlock, [3, 4, 6, 3], num_classes) + diff --git a/examples/privacy/gradient_inversion_attack/breaching/cases/models/model_preparation.py b/examples/privacy/gradient_inversion_attack/breaching/cases/models/model_preparation.py new file mode 100644 index 0000000000000000000000000000000000000000..f1182fb2a7a8b9f26ae50ae21a6f74fa63282ad4 --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/breaching/cases/models/model_preparation.py @@ -0,0 +1,71 @@ +import os + +import mindspore +from mindspore import nn +try: + from .ms_ResNet2 import resnet18, resnet34 +except: + from ms_ResNet2 import resnet18, resnet34 + + +def construct_model(cfg_model, cfg_data, pretrained=True, **kwargs): + if cfg_data.modality == "vision": + model = _construct_vision_model(cfg_model, cfg_data, pretrained, **kwargs) + else: + raise ValueError(f"Invalid data modality {cfg_data.modality}") + model.name = cfg_model + + if "classification" in cfg_data.task: + loss_fn = nn.CrossEntropyLoss() + else: + raise ValueError(f"No loss function registered for task {cfg_data.task}.") + return model, loss_fn + + +class VisionContainer(nn.Cell): + def __init__(self, model): + super().__init__() + self.model = model + + def construct(self, inputs, **kwargs): + tmp = self.model(inputs) + return tmp + + +def _construct_vision_model(cfg_model, cfg_data, pretrained=False, **kwargs): + classes = cfg_data.classes + dir = os.path.dirname(__file__).split('mindspore')[0] + 'mindspore_impl/cache_models/' + if cfg_model.lower() == 'resnet18': + if not pretrained: + model = resnet18(class_num=classes) + else: + model = resnet18(1001) + param_dict = mindspore.load_checkpoint(dir+'resnet18_ms.ckpt') + mindspore.load_param_into_net(model, param_dict, strict_load=False) + elif cfg_model.lower() == 'resnet34': + if not pretrained: + model = resnet34(class_num=classes) + else: + model = resnet34(1001) + param_dict = mindspore.load_checkpoint(dir+'resnet34_ms.ckpt') + mindspore.load_param_into_net(model, param_dict, strict_load=False) + else: + raise ValueError(f'not support {cfg_model} with {cfg_data.name}') + + model.end_point = nn.Dense(model.end_point.in_channels, classes, bias_init="zeros") + + return VisionContainer(model) + +if __name__ =='__main__': + model = resnet18(1001) + dir = os.path.dirname(__file__).split('mindspore')[0] + 'mindspore_impl/cache_models/' + param_dict = mindspore.load_checkpoint(dir + 'resnet18_ms.ckpt') + mindspore.load_param_into_net(model, param_dict, strict_load=False) + param = model.trainable_params() + kk = [i for i in param] + model3 = resnet18(1001) + for _, module in model._children_scope_recursive(): + if isinstance(module, nn.BatchNorm2d): + print(type(module.moving_mean.value())) + print(mindspore.ops.norm(module.moving_variance.value() - module.moving_mean, 2)) + break diff --git a/examples/privacy/gradient_inversion_attack/breaching/cases/models/ms_ResNet.py b/examples/privacy/gradient_inversion_attack/breaching/cases/models/ms_ResNet.py new file mode 100644 index 0000000000000000000000000000000000000000..43fa2226a6f4bd34a2b165deb68e341d7560365e --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/breaching/cases/models/ms_ResNet.py @@ -0,0 +1,623 @@ +# Copyright 2020-2021 Huawei Technologies Co., Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================ +"""ResNet.""" +import math +import numpy as np +from scipy.stats import truncnorm +import mindspore.nn as nn +import mindspore.ops as ops +import mindspore.common.dtype as mstype +from mindspore.common.tensor import Tensor +# from src.model_utils.config import config + + +def conv_variance_scaling_initializer(in_channel, out_channel, kernel_size): + fan_in = in_channel * kernel_size * kernel_size + scale = 1.0 + scale /= max(1., fan_in) + stddev = (scale ** 0.5) / .87962566103423978 + # if config.net_name == "resnet152": + # stddev = (scale ** 0.5) + mu, sigma = 0, stddev + weight = truncnorm(-2, 2, loc=mu, scale=sigma).rvs(out_channel * in_channel * kernel_size * kernel_size) + weight = np.reshape(weight, (out_channel, in_channel, kernel_size, kernel_size)) + return Tensor(weight, dtype=mstype.float32) + + +def _weight_variable(shape, factor=0.01): + init_value = np.random.randn(*shape).astype(np.float32) * factor + return Tensor(init_value) + + +def calculate_gain(nonlinearity, param=None): + """calculate_gain""" + linear_fns = ['linear', 'conv1d', 'conv2d', 'conv3d', 'conv_transpose1d', 'conv_transpose2d', 'conv_transpose3d'] + res = 0 + if nonlinearity in linear_fns or nonlinearity == 'sigmoid': + res = 1 + elif nonlinearity == 'tanh': + res = 5.0 / 3 + elif nonlinearity == 'relu': + res = math.sqrt(2.0) + elif nonlinearity == 'leaky_relu': + if param is None: + neg_slope = 0.01 + elif not isinstance(param, bool) and isinstance(param, int) or isinstance(param, float): + neg_slope = param + else: + raise ValueError("neg_slope {} not a valid number".format(param)) + res = math.sqrt(2.0 / (1 + neg_slope ** 2)) + else: + raise ValueError("Unsupported nonlinearity {}".format(nonlinearity)) + return res + + +def _calculate_fan_in_and_fan_out(tensor): + """_calculate_fan_in_and_fan_out""" + dimensions = len(tensor) + if dimensions < 2: + raise ValueError("Fan in and fan out can not be computed for tensor with fewer than 2 dimensions") + if dimensions == 2: # Linear + fan_in = tensor[1] + fan_out = tensor[0] + else: + num_input_fmaps = tensor[1] + num_output_fmaps = tensor[0] + receptive_field_size = 1 + if dimensions > 2: + receptive_field_size = tensor[2] * tensor[3] + fan_in = num_input_fmaps * receptive_field_size + fan_out = num_output_fmaps * receptive_field_size + return fan_in, fan_out + + +def _calculate_correct_fan(tensor, mode): + mode = mode.lower() + valid_modes = ['fan_in', 'fan_out'] + if mode not in valid_modes: + raise ValueError("Unsupported mode {}, please use one of {}".format(mode, valid_modes)) + fan_in, fan_out = _calculate_fan_in_and_fan_out(tensor) + return fan_in if mode == 'fan_in' else fan_out + + +def kaiming_normal(inputs_shape, a=0, mode='fan_in', nonlinearity='leaky_relu'): + fan = _calculate_correct_fan(inputs_shape, mode) + gain = calculate_gain(nonlinearity, a) + std = gain / math.sqrt(fan) + return np.random.normal(0, std, size=inputs_shape).astype(np.float32) + + +def kaiming_uniform(inputs_shape, a=0., mode='fan_in', nonlinearity='leaky_relu'): + fan = _calculate_correct_fan(inputs_shape, mode) + gain = calculate_gain(nonlinearity, a) + std = gain / math.sqrt(fan) + bound = math.sqrt(3.0) * std # Calculate uniform bounds from standard deviation + return np.random.uniform(-bound, bound, size=inputs_shape).astype(np.float32) + + +def _conv3x3(in_channel, out_channel, stride=1, use_se=False, res_base=False): + if use_se: + weight = conv_variance_scaling_initializer(in_channel, out_channel, kernel_size=3) + else: + weight_shape = (out_channel, in_channel, 3, 3) + weight = Tensor(kaiming_normal(weight_shape, mode="fan_out", nonlinearity='relu')) + # if config.net_name == "resnet152": + # weight = _weight_variable(weight_shape) + if res_base: + return nn.Conv2d(in_channel, out_channel, kernel_size=3, stride=stride, + padding=1, pad_mode='pad', weight_init="xavier_uniform") + return nn.Conv2d(in_channel, out_channel, kernel_size=3, stride=stride, + padding=0, pad_mode='same', weight_init=weight) + + +def _conv1x1(in_channel, out_channel, stride=1, use_se=False, res_base=False): + if use_se: + weight = conv_variance_scaling_initializer(in_channel, out_channel, kernel_size=1) + else: + weight_shape = (out_channel, in_channel, 1, 1) + weight = Tensor(kaiming_normal(weight_shape, mode="fan_out", nonlinearity='relu')) + # if config.net_name == "resnet152": + # weight = _weight_variable(weight_shape) + if res_base: + return nn.Conv2d(in_channel, out_channel, kernel_size=1, stride=stride, + padding=0, pad_mode='pad', weight_init="xavier_uniform") + return nn.Conv2d(in_channel, out_channel, kernel_size=1, stride=stride, + padding=0, pad_mode='same', weight_init=weight) + + +def _conv7x7(in_channel, out_channel, stride=1, use_se=False, res_base=False): + if use_se: + weight = conv_variance_scaling_initializer(in_channel, out_channel, kernel_size=7) + else: + weight_shape = (out_channel, in_channel, 7, 7) + weight = Tensor(kaiming_normal(weight_shape, mode="fan_out", nonlinearity='relu')) + # if config.net_name == "resnet152": + # weight = _weight_variable(weight_shape) + if res_base: + return nn.Conv2d(in_channel, out_channel, + kernel_size=7, stride=stride, padding=3, pad_mode='pad', weight_init="xavier_uniform") + return nn.Conv2d(in_channel, out_channel, + kernel_size=7, stride=stride, padding=0, pad_mode='same', weight_init=weight) + + +def _bn(channel, res_base=False): + if res_base: + return nn.BatchNorm2d(channel, eps=1e-5, momentum=0.0) + return nn.BatchNorm2d(channel, eps=1e-5, momentum=0.0) + + +def _bn_last(channel): + return nn.BatchNorm2d(channel, eps=1e-5, momentum=0.0) + + +def _fc(in_channel, out_channel, use_se=False): + if use_se: + weight = np.random.normal(loc=0, scale=0.01, size=out_channel * in_channel) + weight = Tensor(np.reshape(weight, (out_channel, in_channel)), dtype=mstype.float32) + else: + weight_shape = (out_channel, in_channel) + weight = Tensor(kaiming_uniform(weight_shape, a=math.sqrt(5))) + # if config.net_name == "resnet152": + # weight = _weight_variable(weight_shape) + return nn.Dense(in_channel, out_channel, has_bias=True, weight_init=weight, bias_init=0) + + +class ResidualBlock(nn.Cell): + """ + ResNet V1 residual block definition. + + Args: + in_channel (int): Input channel. + out_channel (int): Output channel. + stride (int): Stride size for the first convolutional layer. Default: 1. + use_se (bool): Enable SE-ResNet50 net. Default: False. + se_block(bool): Use se block in SE-ResNet50 net. Default: False. + + Returns: + Tensor, output tensor. + + Examples: + >>> ResidualBlock(3, 256, stride=2) + """ + expansion = 4 + + def __init__(self, + in_channel, + out_channel, + stride=1, + use_se=False, se_block=False): + super(ResidualBlock, self).__init__() + self.stride = stride + self.use_se = use_se + self.se_block = se_block + channel = out_channel // self.expansion + self.conv1 = _conv1x1(in_channel, channel, stride=1, use_se=self.use_se) + self.bn1 = _bn(channel) + if self.use_se and self.stride != 1: + self.e2 = nn.SequentialCell([_conv3x3(channel, channel, stride=1, use_se=True), _bn(channel), + nn.ReLU(), nn.MaxPool2d(kernel_size=2, stride=2, pad_mode='same')]) + else: + self.conv2 = _conv3x3(channel, channel, stride=stride, use_se=self.use_se) + self.bn2 = _bn(channel) + + self.conv3 = _conv1x1(channel, out_channel, stride=1, use_se=self.use_se) + self.bn3 = _bn(out_channel) + # if config.optimizer == "Thor" or config.net_name == "resnet152": + # self.bn3 = _bn_last(out_channel) + if self.se_block: + self.se_global_pool = ops.ReduceMean(keep_dims=False) + self.se_dense_0 = _fc(out_channel, int(out_channel / 4), use_se=self.use_se) + self.se_dense_1 = _fc(int(out_channel / 4), out_channel, use_se=self.use_se) + self.se_sigmoid = nn.Sigmoid() + self.se_mul = ops.Mul() + self.relu = nn.ReLU() + + self.down_sample = False + + if stride != 1 or in_channel != out_channel: + self.down_sample = True + self.down_sample_layer = None + + if self.down_sample: + if self.use_se: + if stride == 1: + self.down_sample_layer = nn.SequentialCell([_conv1x1(in_channel, out_channel, + stride, use_se=self.use_se), _bn(out_channel)]) + else: + self.down_sample_layer = nn.SequentialCell([nn.MaxPool2d(kernel_size=2, stride=2, pad_mode='same'), + _conv1x1(in_channel, out_channel, 1, + use_se=self.use_se), _bn(out_channel)]) + else: + self.down_sample_layer = nn.SequentialCell([_conv1x1(in_channel, out_channel, stride, + use_se=self.use_se), _bn(out_channel)]) + + def construct(self, x): + identity = x + + out = self.conv1(x) + out = self.bn1(out) + out = self.relu(out) + if self.use_se and self.stride != 1: + out = self.e2(out) + else: + out = self.conv2(out) + out = self.bn2(out) + out = self.relu(out) + out = self.conv3(out) + out = self.bn3(out) + if self.se_block: + out_se = out + out = self.se_global_pool(out, (2, 3)) + out = self.se_dense_0(out) + out = self.relu(out) + out = self.se_dense_1(out) + out = self.se_sigmoid(out) + out = ops.reshape(out, ops.shape(out) + (1, 1)) + out = self.se_mul(out, out_se) + + if self.down_sample: + identity = self.down_sample_layer(identity) + + out = out + identity + out = self.relu(out) + + return out + + +class ResidualBlockBase(nn.Cell): + """ + ResNet V1 residual block definition. + + Args: + in_channel (int): Input channel. + out_channel (int): Output channel. + stride (int): Stride size for the first convolutional layer. Default: 1. + use_se (bool): Enable SE-ResNet50 net. Default: False. + se_block(bool): Use se block in SE-ResNet50 net. Default: False. + res_base (bool): Enable parameter setting of resnet18. Default: True. + + Returns: + Tensor, output tensor. + + Examples: + >>> ResidualBlockBase(3, 256, stride=2) + """ + + def __init__(self, + in_channel, + out_channel, + stride=1, + use_se=False, + se_block=False, + res_base=True): + super(ResidualBlockBase, self).__init__() + self.res_base = res_base + self.conv1 = _conv3x3(in_channel, out_channel, stride=stride, res_base=self.res_base) + self.bn1d = _bn(out_channel) + self.conv2 = _conv3x3(out_channel, out_channel, stride=1, res_base=self.res_base) + self.bn2d = _bn(out_channel) + self.relu = nn.ReLU() + + self.down_sample = False + if stride != 1 or in_channel != out_channel: + self.down_sample = True + + self.down_sample_layer = None + if self.down_sample: + self.down_sample_layer = nn.SequentialCell([_conv1x1(in_channel, out_channel, stride, + use_se=use_se, res_base=self.res_base), + _bn(out_channel, res_base)]) + + def construct(self, x): + identity = x + + out = self.conv1(x) + out = self.bn1d(out) + out = self.relu(out) + + out = self.conv2(out) + out = self.bn2d(out) + + if self.down_sample: + identity = self.down_sample_layer(identity) + + out = out + identity + out = self.relu(out) + + return out + + +class ResNet(nn.Cell): + """ + ResNet architecture. + + Args: + block (Cell): Block for network. + layer_nums (list): Numbers of block in different layers. + in_channels (list): Input channel in each layer. + out_channels (list): Output channel in each layer. + strides (list): Stride size in each layer. + num_classes (int): The number of classes that the training images are belonging to. + use_se (bool): Enable SE-ResNet50 net. Default: False. + se_block(bool): Use se block in SE-ResNet50 net in layer 3 and layer 4. Default: False. + res_base (bool): Enable parameter setting of resnet18. Default: False. + + Returns: + Tensor, output tensor. + + Examples: + >>> ResNet(ResidualBlock, + >>> [3, 4, 6, 3], + >>> [64, 256, 512, 1024], + >>> [256, 512, 1024, 2048], + >>> [1, 2, 2, 2], + >>> 10) + """ + + def __init__(self, + block, + layer_nums, + in_channels, + out_channels, + strides, + num_classes, + use_se=False, + res_base=False): + super(ResNet, self).__init__() + + if not len(layer_nums) == len(in_channels) == len(out_channels) == 4: + raise ValueError("the length of layer_num, in_channels, out_channels list must be 4!") + self.use_se = use_se + self.res_base = res_base + self.se_block = False + if self.use_se: + self.se_block = True + + if self.use_se: + self.conv1_0 = _conv3x3(3, 32, stride=2, use_se=self.use_se) + self.bn1_0 = _bn(32) + self.conv1_1 = _conv3x3(32, 32, stride=1, use_se=self.use_se) + self.bn1_1 = _bn(32) + self.conv1_2 = _conv3x3(32, 64, stride=1, use_se=self.use_se) + else: + self.conv1 = _conv7x7(3, 64, stride=2, res_base=self.res_base) + self.bn1 = _bn(64, self.res_base) + self.relu = ops.ReLU() + + if self.res_base: + self.pad = nn.Pad(paddings=((0, 0), (0, 0), (1, 1), (1, 1))) + self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, pad_mode="valid") + # self.maxpool = nn.AdaptiveAvgPool2d() + else: + self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, pad_mode="same") + + self.layer1 = self._make_layer(block, + layer_nums[0], + in_channel=in_channels[0], + out_channel=out_channels[0], + stride=strides[0], + use_se=self.use_se) + self.layer2 = self._make_layer(block, + layer_nums[1], + in_channel=in_channels[1], + out_channel=out_channels[1], + stride=strides[1], + use_se=self.use_se) + self.layer3 = self._make_layer(block, + layer_nums[2], + in_channel=in_channels[2], + out_channel=out_channels[2], + stride=strides[2], + use_se=self.use_se, + se_block=self.se_block) + self.layer4 = self._make_layer(block, + layer_nums[3], + in_channel=in_channels[3], + out_channel=out_channels[3], + stride=strides[3], + use_se=self.use_se, + se_block=self.se_block) + + self.mean = ops.ReduceMean(keep_dims=True) + self.flatten = nn.Flatten() + self.end_point = _fc(out_channels[3], num_classes, use_se=self.use_se) + + def _make_layer(self, block, layer_num, in_channel, out_channel, stride, use_se=False, se_block=False): + """ + Make stage network of ResNet. + + Args: + block (Cell): Resnet block. + layer_num (int): Layer number. + in_channel (int): Input channel. + out_channel (int): Output channel. + stride (int): Stride size for the first convolutional layer. + se_block(bool): Use se block in SE-ResNet50 net. Default: False. + Returns: + SequentialCell, the output layer. + + Examples: + >>> _make_layer(ResidualBlock, 3, 128, 256, 2) + """ + layers = [] + + resnet_block = block(in_channel, out_channel, stride=stride, use_se=use_se) + layers.append(resnet_block) + if se_block: + for _ in range(1, layer_num - 1): + resnet_block = block(out_channel, out_channel, stride=1, use_se=use_se) + layers.append(resnet_block) + resnet_block = block(out_channel, out_channel, stride=1, use_se=use_se, se_block=se_block) + layers.append(resnet_block) + else: + for _ in range(1, layer_num): + resnet_block = block(out_channel, out_channel, stride=1, use_se=use_se) + layers.append(resnet_block) + return nn.SequentialCell(layers) + + def construct(self, x): + if self.use_se: + x = self.conv1_0(x) + x = self.bn1_0(x) + x = self.relu(x) + x = self.conv1_1(x) + x = self.bn1_1(x) + x = self.relu(x) + x = self.conv1_2(x) + else: + x = self.conv1(x) + x = self.bn1(x) + x = self.relu(x) + if self.res_base: + x = self.pad(x) + c1 = self.maxpool(x) + + c2 = self.layer1(c1) + c3 = self.layer2(c2) + c4 = self.layer3(c3) + c5 = self.layer4(c4) + + out = self.mean(c5, (2, 3)) + out = self.flatten(out) + out = self.end_point(out) + + return out + + +def resnet18(class_num=10): + """ + Get ResNet18 neural network. + + Args: + class_num (int): Class number. + + Returns: + Cell, cell instance of ResNet18 neural network. + + Examples: + >>> net = resnet18(10) + """ + return ResNet(ResidualBlockBase, + [2, 2, 2, 2], + [64, 64, 128, 256], + [64, 128, 256, 512], + [1, 2, 2, 2], + class_num, + res_base=True) + +def resnet34(class_num=10): + """ + Get ResNet34 neural network. + + Args: + class_num (int): Class number. + + Returns: + Cell, cell instance of ResNet34 neural network. + + Examples: + >>> net = resnet18(10) + """ + return ResNet(ResidualBlockBase, + [3, 4, 6, 3], + [64, 64, 128, 256], + [64, 128, 256, 512], + [1, 2, 2, 2], + class_num, + res_base=True) + +def resnet50(class_num=10): + """ + Get ResNet50 neural network. + + Args: + class_num (int): Class number. + + Returns: + Cell, cell instance of ResNet50 neural network. + + Examples: + >>> net = resnet50(10) + """ + return ResNet(ResidualBlock, + [3, 4, 6, 3], + [64, 256, 512, 1024], + [256, 512, 1024, 2048], + [1, 2, 2, 2], + class_num) + + +def se_resnet50(class_num=1001): + """ + Get SE-ResNet50 neural network. + + Args: + class_num (int): Class number. + + Returns: + Cell, cell instance of SE-ResNet50 neural network. + + Examples: + >>> net = se-resnet50(1001) + """ + return ResNet(ResidualBlock, + [3, 4, 6, 3], + [64, 256, 512, 1024], + [256, 512, 1024, 2048], + [1, 2, 2, 2], + class_num, + use_se=True) + + +def resnet101(class_num=1001): + """ + Get ResNet101 neural network. + + Args: + class_num (int): Class number. + + Returns: + Cell, cell instance of ResNet101 neural network. + + Examples: + >>> net = resnet101(1001) + """ + return ResNet(ResidualBlock, + [3, 4, 23, 3], + [64, 256, 512, 1024], + [256, 512, 1024, 2048], + [1, 2, 2, 2], + class_num) + + +def resnet152(class_num=1001): + """ + Get ResNet152 neural network. + + Args: + class_num (int): Class number. + + Returns: + Cell, cell instance of ResNet152 neural network. + + Examples: + # >>> net = resnet152(1001) + """ + return ResNet(ResidualBlock, + [3, 8, 36, 3], + [64, 256, 512, 1024], + [256, 512, 1024, 2048], + [1, 2, 2, 2], + class_num) diff --git a/examples/privacy/gradient_inversion_attack/breaching/cases/models/ms_ResNet2.py b/examples/privacy/gradient_inversion_attack/breaching/cases/models/ms_ResNet2.py new file mode 100644 index 0000000000000000000000000000000000000000..877be69e9dfba35672b184f6c042052301230028 --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/breaching/cases/models/ms_ResNet2.py @@ -0,0 +1,91 @@ +import mindspore as ms +from mindspore import nn + + +class BasicBlock(nn.Cell): + expansion = 1 + + def __init__(self, in_channels, out_channels, stride=1): + super().__init__() + + self.residual_function = nn.SequentialCell( + nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride, padding=1, pad_mode='pad', weight_init="xavier_uniform"), + nn.BatchNorm2d(out_channels, eps=1e-5, momentum=0.0), + nn.LeakyReLU(), + nn.Conv2d(out_channels, out_channels * BasicBlock.expansion, kernel_size=3, padding=1, pad_mode='pad', weight_init="xavier_uniform"), + nn.BatchNorm2d(out_channels * BasicBlock.expansion, eps=1e-5, momentum=0.0) + ) + + self.shortcut = nn.SequentialCell() + + if stride != 1 or in_channels != BasicBlock.expansion * out_channels: + self.shortcut = nn.SequentialCell( + nn.Conv2d(in_channels, out_channels * BasicBlock.expansion, kernel_size=1, stride=stride, weight_init="xavier_uniform"), + nn.BatchNorm2d(out_channels * BasicBlock.expansion, eps=1e-5, momentum=0.0) + ) + + def construct(self, x): + return nn.LeakyReLU()(self.residual_function(x) + self.shortcut(x)) + + +class ResNet(nn.Cell): + + def __init__(self, block, num_block, num_classes=100): + super().__init__() + + self.in_channels = 64 + + self.conv1 = nn.SequentialCell( + nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, pad_mode='pad', weight_init="xavier_uniform"), + nn.BatchNorm2d(64, eps=1e-5, momentum=0.0), + nn.LeakyReLU(), + nn.MaxPool2d(kernel_size=3, stride=2, pad_mode='same')) + self.layer1 = self._make_layer(block, 64, num_block[0], 1) + self.layer2 = self._make_layer(block, 128, num_block[1], 2) + self.layer3 = self._make_layer(block, 256, num_block[2], 2) + self.layer4 = self._make_layer(block, 512, num_block[3], 2) + # self.avg_pool = ms.ops.operations.AdaptiveAvgPool2D((1,1)) + self.end_point = nn.Dense(512 * block.expansion, num_classes) + + def _make_layer(self, block, out_channels, num_blocks, stride): + strides = [stride] + [1] * (num_blocks - 1) + layers = [] + for stride in strides: + layers.append(block(self.in_channels, out_channels, stride)) + self.in_channels = out_channels * block.expansion + + return nn.SequentialCell(*layers) + + def avg_pool(self, x): + return x.mean(axis=(2,3), keep_dims=True) + + def construct(self, x): + output = self.conv1(x) + output = self.layer1(output) + output = self.layer2(output) + output = self.layer3(output) + output = self.layer4(output) + output = self.avg_pool(output) + output = output.view(output.shape[0], -1) + output = self.end_point(output) + + return output + + +def resnet18(class_num=100): + """ return a ResNet 18 object + """ + return ResNet(BasicBlock, [2, 2, 2, 2], class_num) + + +def resnet34(class_num=100): + """ return a ResNet 34 object + """ + return ResNet(BasicBlock, [3, 4, 6, 3], class_num) + + +if __name__ == "__main__": + model = resnet18(100) + data = ms.ops.randn(2,3,224,224) + pred = model(data) + print(pred) diff --git a/examples/privacy/gradient_inversion_attack/breaching/cases/servers.py b/examples/privacy/gradient_inversion_attack/breaching/cases/servers.py new file mode 100644 index 0000000000000000000000000000000000000000..cfb055aadd340a4da0a4bda597162e6e2fc94829 --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/breaching/cases/servers.py @@ -0,0 +1,45 @@ +import logging + +log = logging.getLogger(__name__) + + +def construct_server(model, loss_fn, cfg_case): + """Interface function.""" + dataloader = None + server = HonestServer(model, loss_fn, cfg_case, external_dataloader=dataloader) + return server + + +class HonestServer: + + THREAT = "Honest-but-curious" + + def __init__( + self, model, loss, cfg_case, external_dataloader=None + ): + self.model = model + self.model.set_train(False) + self.loss = loss + self.num_queries = cfg_case.server.num_queries + self.cfg_data = cfg_case.data + self.cfg_server = cfg_case.server + self.external_dataloader = external_dataloader + self.secrets = dict() + + def reset_model(self): + pass + + def distribute_payload(self, query_id=0): + honest_model_parameters = [p for p in self.model.trainable_params()] + if self.cfg_server.provide_public_buffers: + honest_model_buffers = [b for b in self.model.untrainable_params()] + else: + honest_model_buffers = None + return dict(parameters=honest_model_parameters, buffers=honest_model_buffers, metadata=self.cfg_data) + + def vet_model(self): + return self.model + + def queries(self): + return range(self.num_queries) + diff --git a/examples/privacy/gradient_inversion_attack/breaching/cases/users.py b/examples/privacy/gradient_inversion_attack/breaching/cases/users.py new file mode 100644 index 0000000000000000000000000000000000000000..60f2a458b1c5a8d7b5aadb098bcad2306fe46d32 --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/breaching/cases/users.py @@ -0,0 +1,138 @@ +"""Implement user code.""" +import copy +import mindspore as ms +from mindspore import nn +from .data import construct_dataloader +import numpy as np + + +def construct_user(model, loss_fn, cfg_case): + """Interface function.""" + if cfg_case.user.user_type == "local_gradient": + dataloader = construct_dataloader(cfg_case.data) + user = UserSingleStep(model, loss_fn, dataloader, idx=cfg_case.user.user_idx, cfg_user=cfg_case.user) + else: + raise ValueError(f'no user type: {cfg_case.user.user_type}') + return user + + +class UserSingleStep(nn.Cell): + + def __init__(self, model, loss, dataloader, idx, cfg_user): + """Initialize from cfg_user dict which contains atleast all keys in the matching .yaml :>""" + super().__init__() + self.num_data_points = cfg_user.num_data_points + + self.provide_labels = cfg_user.provide_labels + self.provide_num_data_points = cfg_user.provide_num_data_points + self.provide_buffers = cfg_user.provide_buffers + + self.user_idx = idx + + self.model = copy.copy(model) #copy.deepcopy(model) + self.model.set_train(False) + + self.defense_repr = [] + + self.dataloader = dataloader + self.loss = loss + + self.counted_queries = 0 + + def compute_local_updates(self, server_payload, custom_data=None, secure_input=False, apply_noise=False, apply_prune=False): + self.counted_queries += 1 + if custom_data is None: + data = self._load_data() + else: + data = custom_data + self.data_key = "inputs" + data["labels"] = data["labels"].astype(ms.int32) + parameters = server_payload["parameters"] + buffers = server_payload["buffers"] + # t_par = [p for p in self.model.trainable_params()] + # t_buf = [p for p in self.model.untrainable_params()] + + with ms._no_grad(): + for param, server_state in zip(self.model.trainable_params(), parameters): + param.set_data(server_state.value()) + if buffers is not None: + for buffer, server_state in zip(self.model.untrainable_params(), buffers): + buffer.set_data(server_state.value()) + self.model.set_train(False) + else: + self.model.set_train(True) + + def _compute_batch_gradient(data, secure_input=False): + if secure_input: + print('---------------using secure input---------------') + def forward_fn(data, label): + inputs = data + labels = label + n_data = inputs.shape[0] + lam = 0.8 + mix_result = -lam * inputs + idx = np.arange(1, n_data+1).tolist() + idx[-1] = 0 + tmp = inputs[idx] + mix_result = mix_result + (1-lam) * tmp + aug_data = ms.ops.concat([inputs, mix_result], 0) + aug_label = ms.ops.concat([labels, labels], 0) + outputs = self.model(aug_data) + loss = self.loss(outputs, aug_label) + return loss + else: + def forward_fn(data, label): + outputs = self.model(data) + loss = self.loss(outputs, label) + return loss + grad_fn = ms.value_and_grad(forward_fn, None, weights=self.model.trainable_params()) + loss, grads = grad_fn(data["inputs"], data["labels"]) + return grads + + shared_grads = list(_compute_batch_gradient(data, secure_input=secure_input)) + if apply_noise: + print('---------apply noise-----------') + self._apply_additive_noise(shared_grads) + if apply_prune: + print('---------apply pruning-----------') + self._apply_pruning(shared_grads) + + shared_buffers = None + + metadata = dict( + num_data_points=self.num_data_points if self.provide_num_data_points else None, + labels=data["labels"].sort()[0] if self.provide_labels else None, + local_hyperparams=None, + ) + shared_data = dict( + gradients=shared_grads, buffers=shared_buffers if self.provide_buffers else None, metadata=metadata + ) + true_user_data = dict(data=data[self.data_key], labels=data["labels"], buffers=shared_buffers) + + return shared_data, true_user_data + + def _apply_additive_noise(self, grads): + # this is a simple noise strategy, using [max_absolute_value * 0.3] as noise scale + loc = ms.Tensor([0.0]) + for i in range(len(grads)-2): + grad = grads[i] + scale = ms.ops.max(ms.ops.abs(grad))[0] * 0.3 + grads[i] += ms.ops.laplace(grad.shape, mean=loc, lambda_param=scale) + + def _apply_pruning(self, grads): + # this is a simple pruning strategy, 90% small gradients are pruned + prun_rate = 0.9 + for i in range(len(grads)): + grad = grads[i] + n = int(prun_rate*grad.numel()) + tmp_grad = ms.ops.abs(grad) + sort_data = ms.ops.sort(tmp_grad.flatten())[0] + cut = sort_data[n-1] + mask = tmp_grad > cut + grads[i] *= mask + + def _load_data(self): + self.dataloader = self.dataloader.batch(self.num_data_points).create_tuple_iterator() + inputs, labels = next(self.dataloader) + self.data_key = "inputs" + return dict(inputs=inputs, labels=labels) diff --git a/examples/privacy/gradient_inversion_attack/breaching/config/__init__.py b/examples/privacy/gradient_inversion_attack/breaching/config/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/examples/privacy/gradient_inversion_attack/breaching/config/attack/__init__.py b/examples/privacy/gradient_inversion_attack/breaching/config/attack/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/examples/privacy/gradient_inversion_attack/breaching/config/attack/_default_optimization_attack.yaml b/examples/privacy/gradient_inversion_attack/breaching/config/attack/_default_optimization_attack.yaml new file mode 100644 index 0000000000000000000000000000000000000000..20158e8a5fe1d130fabc40bc105f9df5eb094a5b --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/breaching/config/attack/_default_optimization_attack.yaml @@ -0,0 +1,44 @@ +type: default + +attack_type: optimization # analytic, equation solver +label_strategy: yin +# 'bias-corrected' Only in effect if the user does not provide labels +# Label strategy options are 'iDLG', 'analytic', 'yin', 'wainakh-simple', 'wainakh-whitebox', 'random', 'exhaustive' +text_strategy: run-embedding # options: run-embedding +token_recovery: from-labels + +objective: + type: euclidean + scale: 1.0 + task_regularization: 0.0 + +restarts: + num_trials: 1 + scoring: euclidean + +init: randn +normalize_gradients: False + +optim: + optimizer: Adam + signed: + step_size: 1.0 + boxed: False + max_iterations: 400 + step_size_decay: + langevin_noise: 0.0 + warmup: 0 + grad_clip: + + callback: 100 # Print objective value every callback many iterations + +augmentations: + +differentiable_augmentations: False + +regularization: + +impl: + dtype: float + mixed_precision: False + JIT: # bembel with care diff --git a/examples/privacy/gradient_inversion_attack/breaching/config/attack/deepleakage.yaml b/examples/privacy/gradient_inversion_attack/breaching/config/attack/deepleakage.yaml new file mode 100644 index 0000000000000000000000000000000000000000..4cd0b3272df2fc2183c27ab44d0bb8a80b8eb399 --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/breaching/config/attack/deepleakage.yaml @@ -0,0 +1,19 @@ +# Deep Leakage from Gradients +defaults: + - _default_optimization_attack + - _self_ +type: deep-leakage +attack_type: joint-optimization +label_strategy: None + +token_recovery: from-embedding + +optim: + optimizer: adam #L-BFGS + step_size: 1.0 + boxed: True # False + max_iterations: 5000 + + callback: 1000 # Print objective value every callback many iterations + +save_dir: "/custom_data/DGL_res34/" diff --git a/examples/privacy/gradient_inversion_attack/breaching/config/attack/invertinggradients.yaml b/examples/privacy/gradient_inversion_attack/breaching/config/attack/invertinggradients.yaml new file mode 100644 index 0000000000000000000000000000000000000000..f9e2bd7386f4f170ddbb724429620519a5de6f03 --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/breaching/config/attack/invertinggradients.yaml @@ -0,0 +1,38 @@ +defaults: + - _default_optimization_attack + - _self_ +type: invertinggradients +label_strategy: yin + +objective: + type: cosine-similarity + scale: 1 # 1.0 # need to have a much smaller scale like 0.0001 for euclidean objectives + +restarts: + num_trials: 1 + scoring: cosine-similarity + +optim: + optimizer: adam + signed: "hard" + step_size: 0.1 # 0.1 + boxed: True + max_iterations: 10000 # 24_000 + step_size_decay: cosine-decay + + langevin_noise: 0 #og: 0.01 # the original paper has 0.2 but the value does feel relatively large in my experiments + warmup: 50 + pixel_decay: 0 + + callback: 1000 # Print objective value every callback many iterations + +regularization: + total_variation: + scale: 0.01 + inner_exp: 1 + outer_exp: 1 + tv_start: 0 + +save_dir: "/custom_data/InvGrad_res34/" + + diff --git a/examples/privacy/gradient_inversion_attack/breaching/config/attack/our_res18_pretrained.yaml b/examples/privacy/gradient_inversion_attack/breaching/config/attack/our_res18_pretrained.yaml new file mode 100644 index 0000000000000000000000000000000000000000..1ef5d02d1b8d5e6367ba37dbd5838ccdf5c7086c --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/breaching/config/attack/our_res18_pretrained.yaml @@ -0,0 +1,54 @@ +defaults: + - _default_optimization_attack + - _self_ +type: HF_GradInv +label_strategy: yin #wainakh-simple + +objective: + type: dyna-layer-rand-cosine-similarity + scale: 1 # 1e-4 + start: 40 + min_start: 20 # 20 for 224x224 # 5 for 64x64 + broken_tail: 0 + peroid_Add10: 500 + +restarts: + num_trials: 1 + scoring: cosine-similarity + +init: randn +optim: + optimizer: adam + signed: "hard" #"soft" #False + mul_scale: 2 + step_size: 0.1 + boxed: True + max_iterations: 7000 + step_size_decay: step-lr + langevin_noise: 0 + warmup: 0 + pixel_decay: 0.0 + + callback: 500 + +regularization: + total_variation: + scale: 2e-3 #5e-3 for 224x224 #5e-2 for 64x64 no share statistics + inner_exp: 1 + outer_exp: 1 + tv_start: 1000 + norm: + scale: 1e-8 + pnorm: 2 + norm_start: 30000 + deep_inversion: + scale: 1e-4 #1e-4 for 224x224 #5e-3 for 64x64 no share statistics + first_bn_multiplier: 1.3 #1 + second_bn_multiplier: 3 # 1 + deep_inv_start: 1500 + deep_inv_stop: 30000 + +save_dir: "./custom_data/recon_fig9/resnet18p_32_sec/" +#sat_ratio: 1.3 + +augmentations: diff --git a/examples/privacy/gradient_inversion_attack/breaching/config/attack/our_res34_pretrained.yaml b/examples/privacy/gradient_inversion_attack/breaching/config/attack/our_res34_pretrained.yaml new file mode 100644 index 0000000000000000000000000000000000000000..b3885b92f6f6219da8df9c064cb7c577aa759c2a --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/breaching/config/attack/our_res34_pretrained.yaml @@ -0,0 +1,54 @@ +defaults: + - _default_optimization_attack + - _self_ +type: HF_GradInv +label_strategy: yin #wainakh-simple + +objective: + type: dyna-layer-rand-cosine-similarity # euclidean + scale: 1 # 1e-4 + start: 60 + min_start: 30 # 20 for 224x224 # 5 for 64x64 + broken_tail: 0 + peroid_Add10: 500 + +restarts: + num_trials: 1 + scoring: cosine-similarity # euclidean + +init: randn +optim: + optimizer: adam + signed: "hard" #False + mul_scale: 2 + step_size: 0.1 # 0.2 for 5 # og: 0.1 + boxed: True + max_iterations: 7000 + step_size_decay: step-lr # cosine-decay + langevin_noise: 0 #og: 0.01 # the original paper has 0.2 + warmup: 0 + pixel_decay: 0.0 + + callback: 500 + +regularization: + total_variation: + scale: 2e-3 #5e-3 for 224x224 #1e-2 for 64x64 no share statistics + inner_exp: 1 + outer_exp: 1 + tv_start: 2000 + norm: + scale: 1e-8 # 1e-6 + pnorm: 2 + norm_start: 30000 + deep_inversion: + scale: 1e-4 #1e-4 for 224x224 #3e-3 for 64x64 no share statistics + first_bn_multiplier: 1.3 #1 + second_bn_multiplier: 3 # 5 + deep_inv_start: 3000 + deep_inv_stop: 30000 + +save_dir: "./custom_data/recons/" +#sat_ratio: 1.2 + +augmentations: \ No newline at end of file diff --git a/examples/privacy/gradient_inversion_attack/breaching/config/attack/seethrough_res18.yaml b/examples/privacy/gradient_inversion_attack/breaching/config/attack/seethrough_res18.yaml new file mode 100644 index 0000000000000000000000000000000000000000..4d9aaf9987510a6c86ccf9c144e72bd96209f201 --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/breaching/config/attack/seethrough_res18.yaml @@ -0,0 +1,54 @@ +defaults: + - _default_optimization_attack + - _self_ +type: HF_GradInv +label_strategy: yin #wainakh-simple + +objective: + type: dyna-layer-rand-cosine-similarity + scale: 1 # 1e-4 + start: 20 + min_start: 20 # 20 for 224x224 # 5 for 64x64 + broken_tail: 0 + peroid_Add10: 500 + +restarts: + num_trials: 1 + scoring: cosine-similarity + +init: randn +optim: + optimizer: adam + signed: "hard" #"soft" #False + mul_scale: 2 + step_size: 0.1 + boxed: True + max_iterations: 7000 + step_size_decay: step-lr + langevin_noise: 0 + warmup: 0 + pixel_decay: 0.0 + + callback: 500 + +regularization: + total_variation: + scale: 2e-3 #5e-3 for 224x224 #5e-2 for 64x64 no share statistics + inner_exp: 1 + outer_exp: 1 + tv_start: 0 + norm: + scale: 1e-8 + pnorm: 2 + norm_start: 30000 + deep_inversion: + scale: 1e-4 #1e-4 for 224x224 #5e-3 for 64x64 no share statistics + first_bn_multiplier: 1.3 #1 + second_bn_multiplier: 3 # 1 + deep_inv_start: 0 + deep_inv_stop: 30000 + +save_dir: "./custom_data/recon_fig9/resnet18p_32_sec/" +#sat_ratio: 1.3 + +augmentations: diff --git a/examples/privacy/gradient_inversion_attack/breaching/config/attack/seethrough_res34.yaml b/examples/privacy/gradient_inversion_attack/breaching/config/attack/seethrough_res34.yaml new file mode 100644 index 0000000000000000000000000000000000000000..eba77d113c914423fdb2d64225bc0cc6eb55bdac --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/breaching/config/attack/seethrough_res34.yaml @@ -0,0 +1,54 @@ +defaults: + - _default_optimization_attack + - _self_ +type: HF_GradInv +label_strategy: yin #wainakh-simple + +objective: + type: dyna-layer-rand-cosine-similarity # euclidean + scale: 1 # 1e-4 + start: 30 + min_start: 30 # 20 for 224x224 # 5 for 64x64 + broken_tail: 0 + peroid_Add10: 500 + +restarts: + num_trials: 1 + scoring: cosine-similarity # euclidean + +init: randn +optim: + optimizer: adam + signed: "hard" #False + mul_scale: 2 + step_size: 0.1 # 0.2 for 5 # og: 0.1 + boxed: True + max_iterations: 7000 + step_size_decay: step-lr # cosine-decay + langevin_noise: 0 #og: 0.01 # the original paper has 0.2 + warmup: 0 + pixel_decay: 0.0 + + callback: 500 + +regularization: + total_variation: + scale: 2e-3 #5e-3 for 224x224 #1e-2 for 64x64 no share statistics + inner_exp: 1 + outer_exp: 1 + tv_start: 0 + norm: + scale: 1e-8 # 1e-6 + pnorm: 2 + norm_start: 30000 + deep_inversion: + scale: 1e-4 #1e-4 for 224x224 #3e-3 for 64x64 no share statistics + first_bn_multiplier: 1.3 #1 + second_bn_multiplier: 3 # 5 + deep_inv_start: 0 + deep_inv_stop: 30000 + +save_dir: "./custom_data/recons/" +#sat_ratio: 1.2 + +augmentations: \ No newline at end of file diff --git a/examples/privacy/gradient_inversion_attack/breaching/config/case/11_small_batch_cifar.yaml b/examples/privacy/gradient_inversion_attack/breaching/config/case/11_small_batch_cifar.yaml new file mode 100644 index 0000000000000000000000000000000000000000..189abe9ef556b7aa89c50c71ea0c1118a62cdb40 --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/breaching/config/case/11_small_batch_cifar.yaml @@ -0,0 +1,16 @@ +name: small_batch_cifar + +defaults: + - data: CIFAR100 + - impl: default + - server: honest-but-curious + - user: local_gradient + - _self_ +model: ConvNet + +user: + provide_labels: False + num_data_points: 4 + +# Server and user: +num_queries: 1 diff --git a/examples/privacy/gradient_inversion_attack/breaching/config/case/12_custom_imagenet.yaml b/examples/privacy/gradient_inversion_attack/breaching/config/case/12_custom_imagenet.yaml new file mode 100644 index 0000000000000000000000000000000000000000..d40c352962d0aeda6ccfc29be646c779b8f736b9 --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/breaching/config/case/12_custom_imagenet.yaml @@ -0,0 +1,17 @@ +name: custom_imagenet + +defaults: + - data: ImageNet + - impl: default + - server: honest-but-curious + - user: local_gradient + - _self_ +model: ResNet18 +no_dropout: True + +user: + provide_labels: False + num_data_points: 4 + +# Server and user: +num_queries: 1 diff --git a/examples/privacy/gradient_inversion_attack/breaching/config/case/13_custom_tinyimagenet.yaml b/examples/privacy/gradient_inversion_attack/breaching/config/case/13_custom_tinyimagenet.yaml new file mode 100644 index 0000000000000000000000000000000000000000..b5fd78b683ff1e9d7f849341146aa10de53c9b1a --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/breaching/config/case/13_custom_tinyimagenet.yaml @@ -0,0 +1,17 @@ +name: custom_imagenet + +defaults: + - data: TinyImageNet + - impl: default + - server: honest-but-curious + - user: local_gradient + - _self_ +model: ResNet18 +no_dropout: True + +user: + provide_labels: False + num_data_points: 4 # 4 + +# Server and user: +num_queries: 1 diff --git a/examples/privacy/gradient_inversion_attack/breaching/config/case/__init__.py b/examples/privacy/gradient_inversion_attack/breaching/config/case/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/examples/privacy/gradient_inversion_attack/breaching/config/case/data/CIFAR100.yaml b/examples/privacy/gradient_inversion_attack/breaching/config/case/data/CIFAR100.yaml new file mode 100644 index 0000000000000000000000000000000000000000..2928bd8ad04b711c377904128638d21b90143162 --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/breaching/config/case/data/CIFAR100.yaml @@ -0,0 +1,42 @@ +name: CIFAR100 +modality: vision +task: classification + +path: "./implementations/training_theft/data" +size: 50_000 +classes: 100 +shape: + - 3 + - 32 + - 32 + +normalize: True +mean: + - 0.5071598291397095 + - 0.4866936206817627 + - 0.44120192527770996 +std: + - 0.2673342823982239 + - 0.2564384639263153 + - 0.2761504650115967 + +augmentations_train: + RandomCrop: + - 32 + - 4 + RandomHorizontalFlip: 0.5 +augmentations_val: + +# Federated Learning specifics: +default_clients: 100 +partition: balanced # used for synthetic splits. Current options for synthetic split: balanced / unique-class +examples_from_split: validation + +# Data-specific implementation constants: +batch_size: 128 +caching: False +defaults: + - db: none # Database Setup # use the cmd-line to activate the LMDB module with data.db=LMDB + +mix: 0 +smooth: 0 \ No newline at end of file diff --git a/examples/privacy/gradient_inversion_attack/breaching/config/case/data/ImageNet.yaml b/examples/privacy/gradient_inversion_attack/breaching/config/case/data/ImageNet.yaml new file mode 100644 index 0000000000000000000000000000000000000000..64ee8c274b4462e248ac402576eb4e56848340b8 --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/breaching/config/case/data/ImageNet.yaml @@ -0,0 +1,43 @@ +name: ImageNet +modality: vision +task: classification + +path: "./implementations/training_theft/data" +size: 1_281_167 +classes: 1000 +shape: + - 3 + - 224 + - 224 + +# Preprocessing: +normalize: True +mean: + - 0.485 + - 0.456 + - 0.406 +std: + - 0.229 + - 0.224 + - 0.225 +# Data Augmentations: +augmentations_train: + RandomResizedCrop: 224 + RandomHorizontalFlip: 0.5 +augmentations_val: + Resize: 256 + CenterCrop: 224 + +# Federated Learning specifics: +default_clients: 50 +partition: balanced # used for synthetic splits. Current options for synthetic split: balanced / unique-class +examples_from_split: validation + +# Data-specific implementation constants: +batch_size: 128 +caching: False +defaults: + - db: none # Database Setup # use the cmd-line to activate the LMDB module with data.db=LMDB + +smooth: 0 +mix: 0 \ No newline at end of file diff --git a/examples/privacy/gradient_inversion_attack/breaching/config/case/data/TinyImageNet.yaml b/examples/privacy/gradient_inversion_attack/breaching/config/case/data/TinyImageNet.yaml new file mode 100644 index 0000000000000000000000000000000000000000..b5ac314801bbd7e02796ec7b477580487c173731 --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/breaching/config/case/data/TinyImageNet.yaml @@ -0,0 +1,44 @@ +name: TinyImageNet +modality: vision +task: classification + +path: "./implementations/training_theft/data" +size: 100_000 +classes: 200 +shape: + - 3 + - 64 + - 64 + +# Preprocessing +normalize: True +mean: + - 0.4789886474609375 + - 0.4457630515098572 + - 0.3944724500179291 +std: + - 0.27698642015457153 + - 0.2690644860267639 + - 0.2820819020271301 +# Data Augmentations +augmentations_train: +# RandomCrop: +# - 64 +# - 8 +# RandomHorizontalFlip: 0.5 +#augmentations_val: +# CenterCrop: 64 + +# Federated Learning specifics: +default_clients: 200 +partition: balanced # used for synthetic splits. Current options for synthetic split: balanced / unique-class +examples_from_split: train + +# Data-specific implementation constants: +batch_size: 128 +caching: False +defaults: + - db: none # Database Setup # use the cmd-line to activate the LMDB module with data.db=LMDB + +mix: 0 +smooth: 0 \ No newline at end of file diff --git a/examples/privacy/gradient_inversion_attack/breaching/config/case/data/db/LMDB.yaml b/examples/privacy/gradient_inversion_attack/breaching/config/case/data/db/LMDB.yaml new file mode 100644 index 0000000000000000000000000000000000000000..40c3068f8ef3ef84c9c75fa8f3da81b2e9b11fcc --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/breaching/config/case/data/db/LMDB.yaml @@ -0,0 +1,16 @@ +name: LMDB +path: "~/data/lmdb" + +# writing: +rebuild_existing_database: False +normalize: False +write_frequency: 5000 # how often to flush during database creation +shuffle_while_writing: False + +# reading: +max_readers: 128 +readahead: True # this should be beneficial for long sequential reads +meminit: True +max_spare_txns: 128 + +access: get # cursor or get diff --git a/examples/privacy/gradient_inversion_attack/breaching/config/case/data/db/none.yaml b/examples/privacy/gradient_inversion_attack/breaching/config/case/data/db/none.yaml new file mode 100644 index 0000000000000000000000000000000000000000..a818778e5fede63bcd660e6c3a7c01cd720c2052 --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/breaching/config/case/data/db/none.yaml @@ -0,0 +1 @@ +name: diff --git a/examples/privacy/gradient_inversion_attack/breaching/config/case/impl/default.yaml b/examples/privacy/gradient_inversion_attack/breaching/config/case/impl/default.yaml new file mode 100644 index 0000000000000000000000000000000000000000..d530ad2526315572b59bf0bec97e842b0a16874a --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/breaching/config/case/impl/default.yaml @@ -0,0 +1,31 @@ +# Dataloader implementation choices: +# Turn these off for better reproducibility of experiments +shuffle: True +sample_with_replacement: False +fix_generator: False +generator_seed: 101 #101 + +# PyTorch configuration +dtype: float # this has to be float when mixed_precision is True +non_blocking: True +sharing_strategy: file_descriptor +enable_gpu_acc: False # use this flag to disable GPU usage + +benchmark: True # CUDNN benchmarking +deterministic: False # This option will disable non-deterministic ops + +pin_memory: True +threads: 0 # maximal number of cpu dataloader workers used per GPU +persistent_workers: False + +mixed_precision: False +grad_scaling: True # this is a no-op if mixed-precision is off +JIT: # script currently break autocast mixed precision and trace breaks training + +validate_every_nth_step: 10 + +checkpoint: + name: + save_every_nth_step: 10 + +enable_huggingface_offline_mode: True # Only set this to true after caching everything diff --git a/examples/privacy/gradient_inversion_attack/breaching/config/case/server/honest-but-curious.yaml b/examples/privacy/gradient_inversion_attack/breaching/config/case/server/honest-but-curious.yaml new file mode 100644 index 0000000000000000000000000000000000000000..dba61170a7e8bb726dd33241902ead24b54e1943 --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/breaching/config/case/server/honest-but-curious.yaml @@ -0,0 +1,7 @@ +name: honest_but_curious +pretrained: True +model_state: default +provide_public_buffers: True #True # Send public buffers to users (this is batch norm specific) + +has_external_data: False +num_queries: 1 diff --git a/examples/privacy/gradient_inversion_attack/breaching/config/case/user/local_gradient.yaml b/examples/privacy/gradient_inversion_attack/breaching/config/case/user/local_gradient.yaml new file mode 100644 index 0000000000000000000000000000000000000000..155acc461783034fe2bb585bc0e003114fc019d5 --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/breaching/config/case/user/local_gradient.yaml @@ -0,0 +1,17 @@ +user_type: local_gradient +user_idx: 1 # Evaluate training data from the user with this index. If no index is given, then the user is chosen at random. +num_data_points: 1 # If users have more data, the remaining data is truncated. + +provide_buffers: False # False +provide_labels: False +provide_num_data_points: True + +# Local differential privacy: +local_diff_privacy: + gradient_noise: 0.0 #0.0 + input_noise: 0.0 + distribution: laplacian + per_example_clipping: 0.0 +# Specific to this user type: + +# This user can also be used to simulate a larger silo over which the gradient is aggregated. diff --git a/examples/privacy/gradient_inversion_attack/breaching/config/case/user/local_updates.yaml b/examples/privacy/gradient_inversion_attack/breaching/config/case/user/local_updates.yaml new file mode 100644 index 0000000000000000000000000000000000000000..30d6f0163340966d0813f4573b55eeb2001a823d --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/breaching/config/case/user/local_updates.yaml @@ -0,0 +1,20 @@ +user_type: local_update +user_idx: 0 # Evaluate training data from the user with this index. If no index is given, then the user is chosen at random. +num_data_points: 4 # If users have more data, the remaining data is truncated. + +provide_buffers: False +provide_labels: False +provide_num_data_points: True + +# Local differential privacy: +local_diff_privacy: + gradient_noise: 0.0 + input_noise: 0.0 + distribution: laplacian + per_example_clipping: 0.0 + +# Specific to this user type: +num_local_updates: 4 +num_data_per_local_update_step: 1 # Every step is taken on a different sample +local_learning_rate: 0.001 +provide_local_hyperparams: True # Provide local_learning_rate, num_data_per_local_update_step, num_local_updates to server diff --git a/examples/privacy/gradient_inversion_attack/breaching/config/cfg.yaml b/examples/privacy/gradient_inversion_attack/breaching/config/cfg.yaml new file mode 100644 index 0000000000000000000000000000000000000000..8aca27fbf69f3f78ce905dd4dc3a1031133e5a04 --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/breaching/config/cfg.yaml @@ -0,0 +1,29 @@ +# @package _global_ +# Configuration defaults +# Settings are separated into case, attack analysis +defaults: + - case: 12_custom_imagenet + - attack: invertinggradients + - _self_ + - override hydra/job_logging: custom + +base_dir: outputs +hydra: + sweep: + dir: ${base_dir}/${name}/${now:%Y-%m-%d}/${now:%H-%M-%S} + run: + dir: ${base_dir}/${name}/${now:%Y-%m-%d}/${now:%H-%M-%S} +# To change output folder location: +# Set hydra.output_subdir=something +# searchpath: +# - pkg:// + +seed: # Optional: Set initial seed +name: default # A name for this run [will be used for the summary table and outputs folder] + +# debug implementation by running every loop just once: +dryrun: False + +# When benchmarking: +num_trials: 100 +save_reconstruction: True diff --git a/examples/privacy/gradient_inversion_attack/breaching/config/hydra/__init__.py b/examples/privacy/gradient_inversion_attack/breaching/config/hydra/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/examples/privacy/gradient_inversion_attack/breaching/config/hydra/job_logging/custom.yaml b/examples/privacy/gradient_inversion_attack/breaching/config/hydra/job_logging/custom.yaml new file mode 100644 index 0000000000000000000000000000000000000000..e10076ce871208b87ef1cb778ea37d92c81e961d --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/breaching/config/hydra/job_logging/custom.yaml @@ -0,0 +1,20 @@ +# python logging configuration for tasks +version: 1 +formatters: + simple: + format: "[%(asctime)s] %(message)s" +handlers: + console: + class: logging.StreamHandler + formatter: simple + stream: ext://sys.stdout + file: + class: logging.FileHandler + formatter: simple + # relative to the job log directory + filename: ${name}_${hydra.job.name}.log +root: + level: INFO + handlers: [console, file] + +disable_existing_loggers: false diff --git a/examples/privacy/gradient_inversion_attack/custom_data/1_img/11-11.jpg b/examples/privacy/gradient_inversion_attack/custom_data/1_img/11-11.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4b98014bc4385702472f99fff471254aa082f9eb Binary files /dev/null and b/examples/privacy/gradient_inversion_attack/custom_data/1_img/11-11.jpg differ diff --git a/examples/privacy/gradient_inversion_attack/custom_data/1_img/13-13.jpg b/examples/privacy/gradient_inversion_attack/custom_data/1_img/13-13.jpg new file mode 100644 index 0000000000000000000000000000000000000000..503b40e558bf6f2db207dd7e1e5a282b6638b2ca Binary files /dev/null and b/examples/privacy/gradient_inversion_attack/custom_data/1_img/13-13.jpg differ diff --git a/examples/privacy/gradient_inversion_attack/custom_data/1_img/18-18.jpg b/examples/privacy/gradient_inversion_attack/custom_data/1_img/18-18.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cbc983f81680366eacb17bab0babd603b3e13111 Binary files /dev/null and b/examples/privacy/gradient_inversion_attack/custom_data/1_img/18-18.jpg differ diff --git a/examples/privacy/gradient_inversion_attack/custom_data/1_img/20-20.jpg b/examples/privacy/gradient_inversion_attack/custom_data/1_img/20-20.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6cb555de5d593cb7f81cc9111dcdc6f0af247d34 Binary files /dev/null and b/examples/privacy/gradient_inversion_attack/custom_data/1_img/20-20.jpg differ diff --git a/examples/privacy/gradient_inversion_attack/custom_data/1_img/22-22.jpg b/examples/privacy/gradient_inversion_attack/custom_data/1_img/22-22.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3625a751e3a2163673886c51b8b556aa0c579f60 Binary files /dev/null and b/examples/privacy/gradient_inversion_attack/custom_data/1_img/22-22.jpg differ diff --git a/examples/privacy/gradient_inversion_attack/custom_data/1_img/29-29.jpg b/examples/privacy/gradient_inversion_attack/custom_data/1_img/29-29.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5bba8a4693e00dd1e62e101893b266c8a055f2fe Binary files /dev/null and b/examples/privacy/gradient_inversion_attack/custom_data/1_img/29-29.jpg differ diff --git a/examples/privacy/gradient_inversion_attack/custom_data/1_img/32-32.jpg b/examples/privacy/gradient_inversion_attack/custom_data/1_img/32-32.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4f3d89ef5d7390054e1aedf7e97980d94e0b8156 Binary files /dev/null and b/examples/privacy/gradient_inversion_attack/custom_data/1_img/32-32.jpg differ diff --git a/examples/privacy/gradient_inversion_attack/custom_data/1_img/39-39.jpg b/examples/privacy/gradient_inversion_attack/custom_data/1_img/39-39.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e465f269c7447d171d831b827070f4bce0d5e682 Binary files /dev/null and b/examples/privacy/gradient_inversion_attack/custom_data/1_img/39-39.jpg differ diff --git a/examples/privacy/gradient_inversion_attack/custom_data/1_img/45-45.jpg b/examples/privacy/gradient_inversion_attack/custom_data/1_img/45-45.jpg new file mode 100644 index 0000000000000000000000000000000000000000..99d1e171df49db908cc1832854efed1b8172b502 Binary files /dev/null and b/examples/privacy/gradient_inversion_attack/custom_data/1_img/45-45.jpg differ diff --git a/examples/privacy/gradient_inversion_attack/custom_data/1_img/47-47.jpg b/examples/privacy/gradient_inversion_attack/custom_data/1_img/47-47.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0151d48de9a9f2ed5f9aa1b6f94ca187eaf63352 Binary files /dev/null and b/examples/privacy/gradient_inversion_attack/custom_data/1_img/47-47.jpg differ diff --git a/examples/privacy/gradient_inversion_attack/custom_data/1_img/55-55.jpg b/examples/privacy/gradient_inversion_attack/custom_data/1_img/55-55.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3c9ca9c29149bfea62132cb8c4784be22c223f80 Binary files /dev/null and b/examples/privacy/gradient_inversion_attack/custom_data/1_img/55-55.jpg differ diff --git a/examples/privacy/gradient_inversion_attack/custom_data/1_img/57-57.jpg b/examples/privacy/gradient_inversion_attack/custom_data/1_img/57-57.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2a07799ec145e4e458188deda79f676c03027c4d Binary files /dev/null and b/examples/privacy/gradient_inversion_attack/custom_data/1_img/57-57.jpg differ diff --git a/examples/privacy/gradient_inversion_attack/custom_data/1_img/64-64.jpg b/examples/privacy/gradient_inversion_attack/custom_data/1_img/64-64.jpg new file mode 100644 index 0000000000000000000000000000000000000000..18c45e81fd446dffaa163ee272deb5949d186707 Binary files /dev/null and b/examples/privacy/gradient_inversion_attack/custom_data/1_img/64-64.jpg differ diff --git a/examples/privacy/gradient_inversion_attack/custom_data/1_img/66-66.jpg b/examples/privacy/gradient_inversion_attack/custom_data/1_img/66-66.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6609a129d4d3d14faab4060415e982c703a322d6 Binary files /dev/null and b/examples/privacy/gradient_inversion_attack/custom_data/1_img/66-66.jpg differ diff --git a/examples/privacy/gradient_inversion_attack/custom_data/1_img/76-76.jpg b/examples/privacy/gradient_inversion_attack/custom_data/1_img/76-76.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b25c37cb010ad75decadced62a21cbee4df4d75b Binary files /dev/null and b/examples/privacy/gradient_inversion_attack/custom_data/1_img/76-76.jpg differ diff --git a/examples/privacy/gradient_inversion_attack/custom_data/1_img/80-80.jpg b/examples/privacy/gradient_inversion_attack/custom_data/1_img/80-80.jpg new file mode 100644 index 0000000000000000000000000000000000000000..530542aca1cfc90a66a9a28a803bcd054db3127c Binary files /dev/null and b/examples/privacy/gradient_inversion_attack/custom_data/1_img/80-80.jpg differ diff --git a/examples/privacy/gradient_inversion_attack/custom_data/1_img/82-82.jpg b/examples/privacy/gradient_inversion_attack/custom_data/1_img/82-82.jpg new file mode 100644 index 0000000000000000000000000000000000000000..aecde033d5f0d7cd7bd3aec46a73747132a1f6da Binary files /dev/null and b/examples/privacy/gradient_inversion_attack/custom_data/1_img/82-82.jpg differ diff --git a/examples/privacy/gradient_inversion_attack/custom_data/1_img/89-89.jpg b/examples/privacy/gradient_inversion_attack/custom_data/1_img/89-89.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f298fac34c5c8ce326b69fec5c47b34c5d492f83 Binary files /dev/null and b/examples/privacy/gradient_inversion_attack/custom_data/1_img/89-89.jpg differ diff --git a/examples/privacy/gradient_inversion_attack/custom_data/1_img/92-92.jpg b/examples/privacy/gradient_inversion_attack/custom_data/1_img/92-92.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7748bdbbdb6a0da3c756084373f7b256fd599406 Binary files /dev/null and b/examples/privacy/gradient_inversion_attack/custom_data/1_img/92-92.jpg differ diff --git a/examples/privacy/gradient_inversion_attack/custom_data/1_img/99-99.jpg b/examples/privacy/gradient_inversion_attack/custom_data/1_img/99-99.jpg new file mode 100644 index 0000000000000000000000000000000000000000..06e34874a213bb8ea33a8abf249bbc6da9aeac5a Binary files /dev/null and b/examples/privacy/gradient_inversion_attack/custom_data/1_img/99-99.jpg differ diff --git a/examples/privacy/gradient_inversion_attack/custom_dataset.py b/examples/privacy/gradient_inversion_attack/custom_dataset.py new file mode 100644 index 0000000000000000000000000000000000000000..2a877b5ea9e09d87a7e6509f95beb54143ff403b --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/custom_dataset.py @@ -0,0 +1,101 @@ +import hydra +from PIL import Image +import os +import random +import mindspore as ms +from mindspore import ops +from mindspore.dataset import transforms, vision +import numpy as np + + +class CustomData: + def __init__(self, data_dir, dataset_name, number_data_points): + self.data_dir = data_dir + self.dataset_name = dataset_name + self.num_data = number_data_points + self.extract_mean_std() + + def get_data_cfg(self): + with hydra.initialize(config_path='breaching/config/case/data', version_base='1.1'): + cfg = hydra.compose(config_name=self.dataset_name) + return cfg + + def extract_mean_std(self): + cfg = self.get_data_cfg() + self.mean = ms.Tensor(list(cfg.mean))[None,:,None,None] + self.std = ms.Tensor(list(cfg.std))[None,:,None,None] + + def process_data(self): + trans = transforms.Compose( + [ + vision.Resize(size=(224)), + vision.Rescale(1.0 / 255.0, 0), + vision.HWC2CHW(), + ] + ) + file_name_li = os.listdir(self.data_dir) + file_name_list = sorted(file_name_li, key=lambda x: int(x.split('-')[0])) + assert len(file_name_list) >= int(self.num_data) + imgs = [] + labels_ = [] + # 打乱 + # random.seed(215) + random.shuffle(file_name_list) + ##################################### + for file_name in file_name_list[0:int(self.num_data)]: + img = Image.open(self.data_dir+file_name).convert("RGB") + tmp_img = ms.Tensor(trans(img)[0]) + imgs.append(tmp_img[None,:]) + label = int(file_name.split('-')[0]) + labels_.append(label) + imgs = ops.concat(imgs, 0) + labels = ms.Tensor(labels_) + inputs = (imgs-self.mean)/self.std + return dict(inputs=inputs, labels=labels) + + def save_recover(self, recover, original=None, save_pth='', sature=False): + using_sqrt_row = False + if original is not None: + if isinstance(recover, dict): + recover_imgs = ops.clip_by_value(recover['data']*self.std+self.mean, 0, 1) + if sature: + recover_imgs = vision.AdjustSaturation(saturation_factor=sature)(recover_imgs) + origina_imgs = ops.clip_by_value(original['data'] * self.std + self.mean, 0, 1) + all = ops.concat([recover_imgs, origina_imgs], 2) + else: + recover_imgs = ops.clip_by_value(recover * self.std + self.mean, 0, 1) + if sature: + recover_imgs = vision.AdjustSaturation(saturation_factor=sature)(recover_imgs) + origina_imgs = ops.clip_by_value(original['data'] * self.std + self.mean, 0, 1) + all = ops.concat([recover_imgs, origina_imgs], 2) + else: + if isinstance(recover, dict): + recover_imgs = ops.clip_by_value(recover['data'] * self.std + self.mean, 0, 1) + if sature: + recover_imgs = vision.AdjustSaturation(saturation_factor=sature)(recover_imgs) + all = recover_imgs + else: + recover_imgs = ops.clip_by_value(recover * self.std + self.mean, 0, 1) + if sature: + recover_imgs = vision.AdjustSaturation(saturation_factor=sature)(recover_imgs) + all = recover_imgs + self.save_array_img(all, save_pth) + + def save_array_img(self, img_4d, save_pth): + # img_4d: msTensor n*3*H*W, 0-1 + imgs = img_4d.asnumpy()*225 + all_imgs = [im for im in imgs] + tmp1 = np.concatenate(all_imgs, axis=-1) + tmp2 = np.uint8(np.transpose(tmp1, [1,2,0])) + Image.fromarray(tmp2, mode='RGB').save(save_pth) + + +if __name__ == '__main__': + cus_data = CustomData(data_dir='custom_data/1_img/', dataset_name='ImageNet', number_data_points=4) + data = cus_data.process_data() + og = {} + og['data'] = data['inputs'] + og['data'][3] = 0 + cus_data.save_recover(data['inputs'], original=og, save_pth='custom_data/tmp/1.jpg') + print('ok') + diff --git a/examples/privacy/gradient_inversion_attack/func_inv_grad_res18_cifar.py b/examples/privacy/gradient_inversion_attack/func_inv_grad_res18_cifar.py new file mode 100644 index 0000000000000000000000000000000000000000..37fc14dc99e4cc54e1971ed3a54a3b165aa444fc --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/func_inv_grad_res18_cifar.py @@ -0,0 +1,65 @@ +import os +import breaching +import mindspore as ms +from custom_dataset import CustomData + + +def reset_cfg_by_client(cfg, args): + cfg.case.user.num_data_points = int(args['custom_parameter']['num_data_points']) + cfg.attack.optim.max_iterations = int(args['custom_parameter']['max_iterations']) + cfg.attack.optim.step_size = float(args['custom_parameter']['step_size']) + cfg.attack.regularization.total_variation.scale = float(args['custom_parameter']['TV_scale']) + cfg.attack.regularization.total_variation.tv_start = int(args['custom_parameter']['TV_start']) + cfg.attack.optim.callback = int(args['custom_parameter']['callback']) + + +def run_step_wise_GI(args): + try: + ms.set_context(device_target="GPU", device_id=0) + print('using mindspore with GPU context') + except: + ms.set_context(device_target="CPU") + print('using mindspore with CPU context') + + cfg = breaching.get_config(overrides=["case=11_small_batch_cifar", "attack=invertinggradients"]) + + cur_dir = os.path.dirname(__file__) + data_dir = cur_dir + '/custom_data/1_img/' + + cfg.attack.save_dir = args['out_put'] + cfg.case.data.path = args['data_path'] + + cfg.case.data.partition = 'balanced' + cfg.case.data.smooth = 0 + cfg.case.user.user_idx = 0 + cfg.case.model = "resnet18" + + cfg.case.user.provide_labels=False + cfg.case.user.provide_buffers=False + cfg.case.server.provide_public_buffers=True + cfg.case.server.pretrained=False + + # ---------根据用户自定义重置参数--------------------- + reset_cfg_by_client(cfg, args) + cus_defense = args['custom_parameter']['defense'] + sercure_input = True if cus_defense == 'Vicinal Augment' else False + apply_noise = True if cus_defense == 'Differential Privacy' else False + apply_prune = True if cus_defense == 'Gradient Prune' else False + + # --------------run-------------------------------- + user, server, model, loss_fn = breaching.cases.construct_case(cfg.case) + attacker = breaching.attacks.prepare_attack(server.model, server.loss, cfg.attack) + attacker.txt_path = args['out_put'] + args['eva_txt_file'] + + server_payload = server.distribute_payload() + + cus_data = CustomData(data_dir=data_dir, dataset_name='CIFAR100', number_data_points=cfg.case.user.num_data_points) + shared_data, true_user_data = user.compute_local_updates(server_payload, secure_input=sercure_input, apply_noise=apply_noise, apply_prune=apply_prune) + + true_pat = cfg.attack.save_dir + 'A_0.png' + cus_data.save_recover(true_user_data, save_pth=true_pat) + + ## ---------------attack part--------------------- + reconstructed_user_data = attacker.reconstruct([server_payload], [shared_data], {}, custom=cus_data) + recon_path__ = cfg.attack.save_dir + f'A_{attacker.save_flag}.png' + cus_data.save_recover(reconstructed_user_data, true_user_data, recon_path__) diff --git a/examples/privacy/gradient_inversion_attack/func_inv_grad_res18_tinyimgnet.py b/examples/privacy/gradient_inversion_attack/func_inv_grad_res18_tinyimgnet.py new file mode 100644 index 0000000000000000000000000000000000000000..2fa8cff41d824f5edcb2359db7dd437daec76ff5 --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/func_inv_grad_res18_tinyimgnet.py @@ -0,0 +1,64 @@ +import os +import breaching +import mindspore as ms +from custom_dataset import CustomData + + +def reset_cfg_by_client(cfg, args): + cfg.case.user.num_data_points = int(args['custom_parameter']['num_data_points']) + cfg.attack.optim.max_iterations = int(args['custom_parameter']['max_iterations']) + cfg.attack.optim.step_size = float(args['custom_parameter']['step_size']) + cfg.attack.regularization.total_variation.scale = float(args['custom_parameter']['TV_scale']) + cfg.attack.regularization.total_variation.tv_start = int(args['custom_parameter']['TV_start']) + cfg.attack.optim.callback = int(args['custom_parameter']['callback']) + + +def run_step_wise_GI(args): + try: + ms.set_context(device_target="GPU", device_id=0) + print('using mindspore with GPU context') + except: + ms.set_context(device_target="CPU") + print('using mindspore with CPU context') + + cfg = breaching.get_config(overrides=["case=13_custom_tinyimagenet", "attack=invertinggradients"]) + + cur_dir = os.path.dirname(__file__) + data_dir = cur_dir + '/custom_data/1_img/' + + cfg.attack.save_dir = args['out_put'] + cfg.case.data.path = args['data_path'] + + cfg.case.data.smooth = 0 + cfg.case.user.user_idx = 0 + cfg.case.model = "resnet18" + + cfg.case.user.provide_labels=False + cfg.case.user.provide_buffers=False + cfg.case.server.provide_public_buffers=True + cfg.case.server.pretrained=False + + # ---------根据用户自定义重置参数--------------------- + reset_cfg_by_client(cfg, args) + cus_defense = args['custom_parameter']['defense'] + sercure_input = True if cus_defense == 'Vicinal Augment' else False + apply_noise = True if cus_defense == 'Differential Privacy' else False + apply_prune = True if cus_defense == 'Gradient Prune' else False + + # --------------run-------------------------------- + user, server, model, loss_fn = breaching.cases.construct_case(cfg.case) + attacker = breaching.attacks.prepare_attack(server.model, server.loss, cfg.attack) + attacker.txt_path = args['out_put'] + args['eva_txt_file'] + + server_payload = server.distribute_payload() + + cus_data = CustomData(data_dir=data_dir, dataset_name='TinyImageNet', number_data_points=cfg.case.user.num_data_points) + shared_data, true_user_data = user.compute_local_updates(server_payload, secure_input=sercure_input, apply_noise=apply_noise, apply_prune=apply_prune) + + true_pat = cfg.attack.save_dir + 'A_0.png' + cus_data.save_recover(true_user_data, save_pth=true_pat) + + ## ---------------attack part--------------------- + reconstructed_user_data = attacker.reconstruct([server_payload], [shared_data], {}, custom=cus_data) + recon_path__ = cfg.attack.save_dir + f'A_{attacker.save_flag}.png' + cus_data.save_recover(reconstructed_user_data, true_user_data, recon_path__) diff --git a/examples/privacy/gradient_inversion_attack/func_inv_grad_res18_webimg.py b/examples/privacy/gradient_inversion_attack/func_inv_grad_res18_webimg.py new file mode 100644 index 0000000000000000000000000000000000000000..6a976268bffdedc114cd5dda1893b4e254aad9ff --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/func_inv_grad_res18_webimg.py @@ -0,0 +1,65 @@ +import os +import breaching +import mindspore as ms +from custom_dataset import CustomData + + +def reset_cfg_by_client(cfg, args): + cfg.case.user.num_data_points = int(args['custom_parameter']['num_data_points']) + cfg.attack.optim.max_iterations = int(args['custom_parameter']['max_iterations']) + cfg.attack.optim.step_size = float(args['custom_parameter']['step_size']) + cfg.attack.regularization.total_variation.scale = float(args['custom_parameter']['TV_scale']) + cfg.attack.regularization.total_variation.tv_start = int(args['custom_parameter']['TV_start']) + cfg.attack.optim.callback = int(args['custom_parameter']['callback']) + + +def run_step_wise_GI(args): + try: + ms.set_context(device_target="GPU", device_id=0) + print('using mindspore with GPU context') + except: + ms.set_context(device_target="CPU") + print('using mindspore with CPU context') + + cfg = breaching.get_config(overrides=["case=12_custom_imagenet", "attack=invertinggradients"]) + + cur_dir = os.path.dirname(__file__) + data_dir = cur_dir + '/custom_data/1_img/' + + cfg.attack.save_dir = args['out_put'] + cfg.case.data.path = args['data_path'] + + cfg.case.data.partition = 'balanced' + cfg.case.data.smooth = 0 + cfg.case.user.user_idx = 0 + cfg.case.model = "resnet18" + + cfg.case.user.provide_labels=False + cfg.case.user.provide_buffers=False + cfg.case.server.provide_public_buffers=True + cfg.case.server.pretrained=False + + # ---------根据用户自定义重置参数--------------------- + reset_cfg_by_client(cfg, args) + cus_defense = args['custom_parameter']['defense'] + sercure_input = True if cus_defense == 'Vicinal Augment' else False + apply_noise = True if cus_defense == 'Differential Privacy' else False + apply_prune = True if cus_defense == 'Gradient Prune' else False + + # --------------run-------------------------------- + user, server, model, loss_fn = breaching.cases.construct_case(cfg.case) + attacker = breaching.attacks.prepare_attack(server.model, server.loss, cfg.attack) + attacker.txt_path = args['out_put'] + args['eva_txt_file'] + + server_payload = server.distribute_payload() + + cus_data = CustomData(data_dir=data_dir, dataset_name='ImageNet', number_data_points=cfg.case.user.num_data_points) + shared_data, true_user_data = user.compute_local_updates(server_payload, custom_data=cus_data.process_data(), secure_input=sercure_input, apply_noise=apply_noise, apply_prune=apply_prune) + + true_pat = cfg.attack.save_dir + 'A_0.png' + cus_data.save_recover(true_user_data, save_pth=true_pat) + + ## ---------------attack part--------------------- + reconstructed_user_data = attacker.reconstruct([server_payload], [shared_data], {}, custom=cus_data) + recon_path__ = cfg.attack.save_dir + f'A_{attacker.save_flag}.png' + cus_data.save_recover(reconstructed_user_data, true_user_data, recon_path__) diff --git a/examples/privacy/gradient_inversion_attack/func_inv_grad_res34_cifar.py b/examples/privacy/gradient_inversion_attack/func_inv_grad_res34_cifar.py new file mode 100644 index 0000000000000000000000000000000000000000..f8a76401ea0ca7d8903e904285715f049374671f --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/func_inv_grad_res34_cifar.py @@ -0,0 +1,65 @@ +import os +import breaching +import mindspore as ms +from custom_dataset import CustomData + + +def reset_cfg_by_client(cfg, args): + cfg.case.user.num_data_points = int(args['custom_parameter']['num_data_points']) + cfg.attack.optim.max_iterations = int(args['custom_parameter']['max_iterations']) + cfg.attack.optim.step_size = float(args['custom_parameter']['step_size']) + cfg.attack.regularization.total_variation.scale = float(args['custom_parameter']['TV_scale']) + cfg.attack.regularization.total_variation.tv_start = int(args['custom_parameter']['TV_start']) + cfg.attack.optim.callback = int(args['custom_parameter']['callback']) + + +def run_step_wise_GI(args): + try: + ms.set_context(device_target="GPU", device_id=0) + print('using mindspore with GPU context') + except: + ms.set_context(device_target="CPU") + print('using mindspore with CPU context') + + cfg = breaching.get_config(overrides=["case=11_small_batch_cifar", "attack=invertinggradients"]) + + cur_dir = os.path.dirname(__file__) + data_dir = cur_dir + '/custom_data/1_img/' + + cfg.attack.save_dir = args['out_put'] + cfg.case.data.path = args['data_path'] + + cfg.case.data.partition = 'balanced' + cfg.case.data.smooth = 0 + cfg.case.user.user_idx = 0 + cfg.case.model = "resnet34" + + cfg.case.user.provide_labels=False + cfg.case.user.provide_buffers=False + cfg.case.server.provide_public_buffers=True + cfg.case.server.pretrained=False + + # ---------根据用户自定义重置参数--------------------- + reset_cfg_by_client(cfg, args) + cus_defense = args['custom_parameter']['defense'] + sercure_input = True if cus_defense == 'Vicinal Augment' else False + apply_noise = True if cus_defense == 'Differential Privacy' else False + apply_prune = True if cus_defense == 'Gradient Prune' else False + + # --------------run-------------------------------- + user, server, model, loss_fn = breaching.cases.construct_case(cfg.case) + attacker = breaching.attacks.prepare_attack(server.model, server.loss, cfg.attack) + attacker.txt_path = args['out_put'] + args['eva_txt_file'] + + server_payload = server.distribute_payload() + + cus_data = CustomData(data_dir=data_dir, dataset_name='CIFAR100', number_data_points=cfg.case.user.num_data_points) + shared_data, true_user_data = user.compute_local_updates(server_payload, secure_input=sercure_input, apply_noise=apply_noise, apply_prune=apply_prune) + + true_pat = cfg.attack.save_dir + 'A_0.png' + cus_data.save_recover(true_user_data, save_pth=true_pat) + + ## ---------------attack part--------------------- + reconstructed_user_data = attacker.reconstruct([server_payload], [shared_data], {}, custom=cus_data) + recon_path__ = cfg.attack.save_dir + f'A_{attacker.save_flag}.png' + cus_data.save_recover(reconstructed_user_data, true_user_data, recon_path__) diff --git a/examples/privacy/gradient_inversion_attack/func_inv_grad_res34_tinyimgnet.py b/examples/privacy/gradient_inversion_attack/func_inv_grad_res34_tinyimgnet.py new file mode 100644 index 0000000000000000000000000000000000000000..2592bc5927c327c700703d998f2bd2a27902b764 --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/func_inv_grad_res34_tinyimgnet.py @@ -0,0 +1,65 @@ +import os +import breaching +import mindspore as ms +from custom_dataset import CustomData + + +def reset_cfg_by_client(cfg, args): + cfg.case.user.num_data_points = int(args['custom_parameter']['num_data_points']) + cfg.attack.optim.max_iterations = int(args['custom_parameter']['max_iterations']) + cfg.attack.optim.step_size = float(args['custom_parameter']['step_size']) + cfg.attack.regularization.total_variation.scale = float(args['custom_parameter']['TV_scale']) + cfg.attack.regularization.total_variation.tv_start = int(args['custom_parameter']['TV_start']) + cfg.attack.optim.callback = int(args['custom_parameter']['callback']) + + +def run_step_wise_GI(args): + try: + ms.set_context(device_target="GPU", device_id=0) + print('using mindspore with GPU context') + except: + ms.set_context(device_target="CPU") + print('using mindspore with CPU context') + + cfg = breaching.get_config(overrides=["case=13_custom_tinyimagenet", "attack=invertinggradients"]) + + cur_dir = os.path.dirname(__file__) + data_dir = cur_dir + '/custom_data/1_img/' + + cfg.attack.save_dir = args['out_put'] + cfg.case.data.path = args['data_path'] + + cfg.case.data.partition = 'balanced' + cfg.case.data.smooth = 0 + cfg.case.user.user_idx = 0 + cfg.case.model = "resnet34" + + cfg.case.user.provide_labels=False + cfg.case.user.provide_buffers=False + cfg.case.server.provide_public_buffers=True + cfg.case.server.pretrained=False + + # ---------根据用户自定义重置参数--------------------- + reset_cfg_by_client(cfg, args) + cus_defense = args['custom_parameter']['defense'] + sercure_input = True if cus_defense == 'Vicinal Augment' else False + apply_noise = True if cus_defense == 'Differential Privacy' else False + apply_prune = True if cus_defense == 'Gradient Prune' else False + + # --------------run-------------------------------- + user, server, model, loss_fn = breaching.cases.construct_case(cfg.case) + attacker = breaching.attacks.prepare_attack(server.model, server.loss, cfg.attack) + attacker.txt_path = args['out_put'] + args['eva_txt_file'] + + server_payload = server.distribute_payload() + + cus_data = CustomData(data_dir=data_dir, dataset_name='TinyImageNet', number_data_points=cfg.case.user.num_data_points) + shared_data, true_user_data = user.compute_local_updates(server_payload, secure_input=sercure_input, apply_noise=apply_noise, apply_prune=apply_prune) + + true_pat = cfg.attack.save_dir + 'A_0.png' + cus_data.save_recover(true_user_data, save_pth=true_pat) + + ## ---------------attack part--------------------- + reconstructed_user_data = attacker.reconstruct([server_payload], [shared_data], {}, custom=cus_data) + recon_path__ = cfg.attack.save_dir + f'A_{attacker.save_flag}.png' + cus_data.save_recover(reconstructed_user_data, true_user_data, recon_path__) diff --git a/examples/privacy/gradient_inversion_attack/func_inv_grad_res34_webimg.py b/examples/privacy/gradient_inversion_attack/func_inv_grad_res34_webimg.py new file mode 100644 index 0000000000000000000000000000000000000000..ba2ca64d67e4a35fe05c2a2736e1cbac409c83f7 --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/func_inv_grad_res34_webimg.py @@ -0,0 +1,65 @@ +import os +import breaching +import mindspore as ms +from custom_dataset import CustomData + + +def reset_cfg_by_client(cfg, args): + cfg.case.user.num_data_points = int(args['custom_parameter']['num_data_points']) + cfg.attack.optim.max_iterations = int(args['custom_parameter']['max_iterations']) + cfg.attack.optim.step_size = float(args['custom_parameter']['step_size']) + cfg.attack.regularization.total_variation.scale = float(args['custom_parameter']['TV_scale']) + cfg.attack.regularization.total_variation.tv_start = int(args['custom_parameter']['TV_start']) + cfg.attack.optim.callback = int(args['custom_parameter']['callback']) + + +def run_step_wise_GI(args): + try: + ms.set_context(device_target="GPU", device_id=0) + print('using mindspore with GPU context') + except: + ms.set_context(device_target="CPU") + print('using mindspore with CPU context') + + cfg = breaching.get_config(overrides=["case=12_custom_imagenet", "attack=invertinggradients"]) + + cur_dir = os.path.dirname(__file__) + data_dir = cur_dir + '/custom_data/1_img/' + + cfg.attack.save_dir = args['out_put'] + cfg.case.data.path = args['data_path'] + + cfg.case.data.partition = 'balanced' + cfg.case.data.smooth = 0 + cfg.case.user.user_idx = 0 + cfg.case.model = "resnet34" + + cfg.case.user.provide_labels=False + cfg.case.user.provide_buffers=False + cfg.case.server.provide_public_buffers=True + cfg.case.server.pretrained=False + + # ---------根据用户自定义重置参数--------------------- + reset_cfg_by_client(cfg, args) + cus_defense = args['custom_parameter']['defense'] + sercure_input = True if cus_defense == 'Vicinal Augment' else False + apply_noise = True if cus_defense == 'Differential Privacy' else False + apply_prune = True if cus_defense == 'Gradient Prune' else False + + # --------------run-------------------------------- + user, server, model, loss_fn = breaching.cases.construct_case(cfg.case) + attacker = breaching.attacks.prepare_attack(server.model, server.loss, cfg.attack) + attacker.txt_path = args['out_put'] + args['eva_txt_file'] + + server_payload = server.distribute_payload() + + cus_data = CustomData(data_dir=data_dir, dataset_name='ImageNet', number_data_points=cfg.case.user.num_data_points) + shared_data, true_user_data = user.compute_local_updates(server_payload, custom_data=cus_data.process_data(), secure_input=sercure_input, apply_noise=apply_noise, apply_prune=apply_prune) + + true_pat = cfg.attack.save_dir + 'A_0.png' + cus_data.save_recover(true_user_data, save_pth=true_pat) + + ## ---------------attack part--------------------- + reconstructed_user_data = attacker.reconstruct([server_payload], [shared_data], {}, custom=cus_data) + recon_path__ = cfg.attack.save_dir + f'A_{attacker.save_flag}.png' + cus_data.save_recover(reconstructed_user_data, true_user_data, recon_path__) diff --git a/examples/privacy/gradient_inversion_attack/func_see_through_res18_cifar.py b/examples/privacy/gradient_inversion_attack/func_see_through_res18_cifar.py new file mode 100644 index 0000000000000000000000000000000000000000..812a579d01c6f0ab8d6f49525c2d794cf4429e77 --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/func_see_through_res18_cifar.py @@ -0,0 +1,67 @@ +import os +import breaching +import mindspore as ms +from custom_dataset import CustomData + + +def reset_cfg_by_client(cfg, args): + cfg.case.user.num_data_points = int(args['custom_parameter']['num_data_points']) + cfg.attack.optim.max_iterations = int(args['custom_parameter']['max_iterations']) + cfg.attack.optim.step_size = float(args['custom_parameter']['step_size']) + cfg.attack.regularization.total_variation.scale = float(args['custom_parameter']['TV_scale']) + cfg.attack.regularization.total_variation.tv_start = int(args['custom_parameter']['TV_start']) + cfg.attack.regularization.deep_inversion.scale = float(args['custom_parameter']['BN_scale']) + cfg.attack.regularization.deep_inversion.deep_inv_start = int(args['custom_parameter']['BN_start']) + cfg.attack.optim.callback = int(args['custom_parameter']['callback']) + + +def run_step_wise_GI(args): + try: + ms.set_context(device_target="GPU", device_id=0) + print('using mindspore with GPU context') + except: + ms.set_context(device_target="CPU") + print('using mindspore with CPU context') + + cfg = breaching.get_config(overrides=["case=11_small_batch_cifar", "attack=seethrough_res18"]) + + cur_dir = os.path.dirname(__file__) + data_dir = cur_dir + '/custom_data/1_img/' + + cfg.attack.save_dir = args['out_put'] + cfg.case.data.path = args['data_path'] + + cfg.case.data.partition = 'balanced' + cfg.case.data.smooth = 0 + cfg.case.user.user_idx = 0 + cfg.case.model = "resnet18" + + cfg.case.user.provide_labels=False + cfg.case.user.provide_buffers=False + cfg.case.server.provide_public_buffers=True + cfg.case.server.pretrained=False + + # ---------根据用户自定义重置参数--------------------- + reset_cfg_by_client(cfg, args) + cus_defense = args['custom_parameter']['defense'] + sercure_input = True if cus_defense == 'Vicinal Augment' else False + apply_noise = True if cus_defense == 'Differential Privacy' else False + apply_prune = True if cus_defense == 'Gradient Prune' else False + + # --------------run-------------------------------- + user, server, model, loss_fn = breaching.cases.construct_case(cfg.case) + attacker = breaching.attacks.prepare_attack(server.model, server.loss, cfg.attack) + attacker.txt_path = args['out_put'] + args['eva_txt_file'] + + server_payload = server.distribute_payload() + + cus_data = CustomData(data_dir=data_dir, dataset_name='CIFAR100', number_data_points=cfg.case.user.num_data_points) + shared_data, true_user_data = user.compute_local_updates(server_payload, secure_input=sercure_input, apply_noise=apply_noise, apply_prune=apply_prune) + + true_pat = cfg.attack.save_dir + 'A_0.png' + cus_data.save_recover(true_user_data, save_pth=true_pat) + + ## ---------------attack part--------------------- + reconstructed_user_data = attacker.reconstruct([server_payload], [shared_data], {}, custom=cus_data) + recon_path__ = cfg.attack.save_dir + f'A_{attacker.save_flag}.png' + cus_data.save_recover(reconstructed_user_data, true_user_data, recon_path__) diff --git a/examples/privacy/gradient_inversion_attack/func_see_through_res18_tinyimgnet.py b/examples/privacy/gradient_inversion_attack/func_see_through_res18_tinyimgnet.py new file mode 100644 index 0000000000000000000000000000000000000000..588cbdb7d37fe2e845436cfa54260161475be027 --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/func_see_through_res18_tinyimgnet.py @@ -0,0 +1,66 @@ +import os +import breaching +import mindspore as ms +from custom_dataset import CustomData + + +def reset_cfg_by_client(cfg, args): + cfg.case.user.num_data_points = int(args['custom_parameter']['num_data_points']) + cfg.attack.optim.max_iterations = int(args['custom_parameter']['max_iterations']) + cfg.attack.optim.step_size = float(args['custom_parameter']['step_size']) + cfg.attack.regularization.total_variation.scale = float(args['custom_parameter']['TV_scale']) + cfg.attack.regularization.total_variation.tv_start = int(args['custom_parameter']['TV_start']) + cfg.attack.regularization.deep_inversion.scale = float(args['custom_parameter']['BN_scale']) + cfg.attack.regularization.deep_inversion.deep_inv_start = int(args['custom_parameter']['BN_start']) + cfg.attack.optim.callback = int(args['custom_parameter']['callback']) + + +def run_step_wise_GI(args): + try: + ms.set_context(device_target="GPU", device_id=0) + print('using mindspore with GPU context') + except: + ms.set_context(device_target="CPU") + print('using mindspore with CPU context') + + cfg = breaching.get_config(overrides=["case=13_custom_tinyimagenet", "attack=seethrough_res18"]) + + cur_dir = os.path.dirname(__file__) + data_dir = cur_dir + '/custom_data/1_img/' + + cfg.attack.save_dir = args['out_put'] + cfg.case.data.path = args['data_path'] + + cfg.case.data.smooth = 0 + cfg.case.user.user_idx = 0 + cfg.case.model = "resnet18" + + cfg.case.user.provide_labels=False + cfg.case.user.provide_buffers=False + cfg.case.server.provide_public_buffers=True + cfg.case.server.pretrained=False + + # ---------根据用户自定义重置参数--------------------- + reset_cfg_by_client(cfg, args) + cus_defense = args['custom_parameter']['defense'] + sercure_input = True if cus_defense == 'Vicinal Augment' else False + apply_noise = True if cus_defense == 'Differential Privacy' else False + apply_prune = True if cus_defense == 'Gradient Prune' else False + + # --------------run-------------------------------- + user, server, model, loss_fn = breaching.cases.construct_case(cfg.case) + attacker = breaching.attacks.prepare_attack(server.model, server.loss, cfg.attack) + attacker.txt_path = args['out_put'] + args['eva_txt_file'] + + server_payload = server.distribute_payload() + + cus_data = CustomData(data_dir=data_dir, dataset_name='TinyImageNet', number_data_points=cfg.case.user.num_data_points) + shared_data, true_user_data = user.compute_local_updates(server_payload, secure_input=sercure_input, apply_noise=apply_noise, apply_prune=apply_prune) + + true_pat = cfg.attack.save_dir + 'A_0.png' + cus_data.save_recover(true_user_data, save_pth=true_pat) + + ## ---------------attack part--------------------- + reconstructed_user_data = attacker.reconstruct([server_payload], [shared_data], {}, custom=cus_data) + recon_path__ = cfg.attack.save_dir + f'A_{attacker.save_flag}.png' + cus_data.save_recover(reconstructed_user_data, true_user_data, recon_path__) diff --git a/examples/privacy/gradient_inversion_attack/func_see_through_res18_webimg.py b/examples/privacy/gradient_inversion_attack/func_see_through_res18_webimg.py new file mode 100644 index 0000000000000000000000000000000000000000..85d0c4e642dbdee7668816f17f0312da06c5b8cd --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/func_see_through_res18_webimg.py @@ -0,0 +1,67 @@ +import os +import breaching +import mindspore as ms +from custom_dataset import CustomData + + +def reset_cfg_by_client(cfg, args): + cfg.case.user.num_data_points = int(args['custom_parameter']['num_data_points']) + cfg.attack.optim.max_iterations = int(args['custom_parameter']['max_iterations']) + cfg.attack.optim.step_size = float(args['custom_parameter']['step_size']) + cfg.attack.regularization.total_variation.scale = float(args['custom_parameter']['TV_scale']) + cfg.attack.regularization.total_variation.tv_start = int(args['custom_parameter']['TV_start']) + cfg.attack.regularization.deep_inversion.scale = float(args['custom_parameter']['BN_scale']) + cfg.attack.regularization.deep_inversion.deep_inv_start = int(args['custom_parameter']['BN_start']) + cfg.attack.optim.callback = int(args['custom_parameter']['callback']) + + +def run_step_wise_GI(args): + try: + ms.set_context(device_target="GPU", device_id=0) + print('using mindspore with GPU context') + except: + ms.set_context(device_target="CPU") + print('using mindspore with CPU context') + + cfg = breaching.get_config(overrides=["case=12_custom_imagenet", "attack=seethrough_res18"]) + + cur_dir = os.path.dirname(__file__) + data_dir = cur_dir + '/custom_data/1_img/' + + cfg.attack.save_dir = args['out_put'] + cfg.case.data.path = args['data_path'] + + cfg.case.data.partition = 'balanced' + cfg.case.data.smooth = 0 + cfg.case.user.user_idx = 0 + cfg.case.model = "resnet18" + + cfg.case.user.provide_labels=False + cfg.case.user.provide_buffers=False + cfg.case.server.provide_public_buffers=True + cfg.case.server.pretrained=False + + # ---------根据用户自定义重置参数--------------------- + reset_cfg_by_client(cfg, args) + cus_defense = args['custom_parameter']['defense'] + sercure_input = True if cus_defense == 'Vicinal Augment' else False + apply_noise = True if cus_defense == 'Differential Privacy' else False + apply_prune = True if cus_defense == 'Gradient Prune' else False + + # --------------run-------------------------------- + user, server, model, loss_fn = breaching.cases.construct_case(cfg.case) + attacker = breaching.attacks.prepare_attack(server.model, server.loss, cfg.attack) + attacker.txt_path = args['out_put'] + args['eva_txt_file'] + + server_payload = server.distribute_payload() + + cus_data = CustomData(data_dir=data_dir, dataset_name='ImageNet', number_data_points=cfg.case.user.num_data_points) + shared_data, true_user_data = user.compute_local_updates(server_payload, custom_data=cus_data.process_data(), secure_input=sercure_input, apply_noise=apply_noise, apply_prune=apply_prune) + + true_pat = cfg.attack.save_dir + 'A_0.png' + cus_data.save_recover(true_user_data, save_pth=true_pat) + + ## ---------------attack part--------------------- + reconstructed_user_data = attacker.reconstruct([server_payload], [shared_data], {}, custom=cus_data) + recon_path__ = cfg.attack.save_dir + f'A_{attacker.save_flag}.png' + cus_data.save_recover(reconstructed_user_data, true_user_data, recon_path__) diff --git a/examples/privacy/gradient_inversion_attack/func_see_through_res34_cifar.py b/examples/privacy/gradient_inversion_attack/func_see_through_res34_cifar.py new file mode 100644 index 0000000000000000000000000000000000000000..606d4a8e262ce29d0756cec676c900a249789b6a --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/func_see_through_res34_cifar.py @@ -0,0 +1,67 @@ +import os +import breaching +import mindspore as ms +from custom_dataset import CustomData + + +def reset_cfg_by_client(cfg, args): + cfg.case.user.num_data_points = int(args['custom_parameter']['num_data_points']) + cfg.attack.optim.max_iterations = int(args['custom_parameter']['max_iterations']) + cfg.attack.optim.step_size = float(args['custom_parameter']['step_size']) + cfg.attack.regularization.total_variation.scale = float(args['custom_parameter']['TV_scale']) + cfg.attack.regularization.total_variation.tv_start = int(args['custom_parameter']['TV_start']) + cfg.attack.regularization.deep_inversion.scale = float(args['custom_parameter']['BN_scale']) + cfg.attack.regularization.deep_inversion.deep_inv_start = int(args['custom_parameter']['BN_start']) + cfg.attack.optim.callback = int(args['custom_parameter']['callback']) + + +def run_step_wise_GI(args): + try: + ms.set_context(device_target="GPU", device_id=0) + print('using mindspore with GPU context') + except: + ms.set_context(device_target="CPU") + print('using mindspore with CPU context') + + cfg = breaching.get_config(overrides=["case=11_small_batch_cifar", "attack=seethrough_res34"]) + + cur_dir = os.path.dirname(__file__) + data_dir = cur_dir + '/custom_data/1_img/' + + cfg.attack.save_dir = args['out_put'] + cfg.case.data.path = args['data_path'] + + cfg.case.data.partition = 'balanced' + cfg.case.data.smooth = 0 + cfg.case.user.user_idx = 0 + cfg.case.model = "resnet34" + + cfg.case.user.provide_labels=False + cfg.case.user.provide_buffers=False + cfg.case.server.provide_public_buffers=True + cfg.case.server.pretrained=False + + # ---------根据用户自定义重置参数--------------------- + reset_cfg_by_client(cfg, args) + cus_defense = args['custom_parameter']['defense'] + sercure_input = True if cus_defense == 'Vicinal Augment' else False + apply_noise = True if cus_defense == 'Differential Privacy' else False + apply_prune = True if cus_defense == 'Gradient Prune' else False + + # --------------run-------------------------------- + user, server, model, loss_fn = breaching.cases.construct_case(cfg.case) + attacker = breaching.attacks.prepare_attack(server.model, server.loss, cfg.attack) + attacker.txt_path = args['out_put'] + args['eva_txt_file'] + + server_payload = server.distribute_payload() + + cus_data = CustomData(data_dir=data_dir, dataset_name='CIFAR100', number_data_points=cfg.case.user.num_data_points) + shared_data, true_user_data = user.compute_local_updates(server_payload, secure_input=sercure_input, apply_noise=apply_noise, apply_prune=apply_prune) + + true_pat = cfg.attack.save_dir + 'A_0.png' + cus_data.save_recover(true_user_data, save_pth=true_pat) + + ## ---------------attack part--------------------- + reconstructed_user_data = attacker.reconstruct([server_payload], [shared_data], {}, custom=cus_data) + recon_path__ = cfg.attack.save_dir + f'A_{attacker.save_flag}.png' + cus_data.save_recover(reconstructed_user_data, true_user_data, recon_path__) diff --git a/examples/privacy/gradient_inversion_attack/func_see_through_res34_tinyimgnet.py b/examples/privacy/gradient_inversion_attack/func_see_through_res34_tinyimgnet.py new file mode 100644 index 0000000000000000000000000000000000000000..5161941a6aceb08588901487335ccc353abfab8a --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/func_see_through_res34_tinyimgnet.py @@ -0,0 +1,67 @@ +import os +import breaching +import mindspore as ms +from custom_dataset import CustomData + + +def reset_cfg_by_client(cfg, args): + cfg.case.user.num_data_points = int(args['custom_parameter']['num_data_points']) + cfg.attack.optim.max_iterations = int(args['custom_parameter']['max_iterations']) + cfg.attack.optim.step_size = float(args['custom_parameter']['step_size']) + cfg.attack.regularization.total_variation.scale = float(args['custom_parameter']['TV_scale']) + cfg.attack.regularization.total_variation.tv_start = int(args['custom_parameter']['TV_start']) + cfg.attack.regularization.deep_inversion.scale = float(args['custom_parameter']['BN_scale']) + cfg.attack.regularization.deep_inversion.deep_inv_start = int(args['custom_parameter']['BN_start']) + cfg.attack.optim.callback = int(args['custom_parameter']['callback']) + + +def run_step_wise_GI(args): + try: + ms.set_context(device_target="GPU", device_id=0) + print('using mindspore with GPU context') + except: + ms.set_context(device_target="CPU") + print('using mindspore with CPU context') + + cfg = breaching.get_config(overrides=["case=13_custom_tinyimagenet", "attack=seethrough_res34"]) + + cur_dir = os.path.dirname(__file__) + data_dir = cur_dir + '/custom_data/1_img/' + + cfg.attack.save_dir = args['out_put'] + cfg.case.data.path = args['data_path'] + + cfg.case.data.partition = 'balanced' + cfg.case.data.smooth = 0 + cfg.case.user.user_idx = 0 + cfg.case.model = "resnet34" + + cfg.case.user.provide_labels=False + cfg.case.user.provide_buffers=False + cfg.case.server.provide_public_buffers=True + cfg.case.server.pretrained=False + + # ---------根据用户自定义重置参数--------------------- + reset_cfg_by_client(cfg, args) + cus_defense = args['custom_parameter']['defense'] + sercure_input = True if cus_defense == 'Vicinal Augment' else False + apply_noise = True if cus_defense == 'Differential Privacy' else False + apply_prune = True if cus_defense == 'Gradient Prune' else False + + # --------------run-------------------------------- + user, server, model, loss_fn = breaching.cases.construct_case(cfg.case) + attacker = breaching.attacks.prepare_attack(server.model, server.loss, cfg.attack) + attacker.txt_path = args['out_put'] + args['eva_txt_file'] + + server_payload = server.distribute_payload() + + cus_data = CustomData(data_dir=data_dir, dataset_name='TinyImageNet', number_data_points=cfg.case.user.num_data_points) + shared_data, true_user_data = user.compute_local_updates(server_payload, secure_input=sercure_input, apply_noise=apply_noise, apply_prune=apply_prune) + + true_pat = cfg.attack.save_dir + 'A_0.png' + cus_data.save_recover(true_user_data, save_pth=true_pat) + + ## ---------------attack part--------------------- + reconstructed_user_data = attacker.reconstruct([server_payload], [shared_data], {}, custom=cus_data) + recon_path__ = cfg.attack.save_dir + f'A_{attacker.save_flag}.png' + cus_data.save_recover(reconstructed_user_data, true_user_data, recon_path__) diff --git a/examples/privacy/gradient_inversion_attack/func_see_through_res34_webimg.py b/examples/privacy/gradient_inversion_attack/func_see_through_res34_webimg.py new file mode 100644 index 0000000000000000000000000000000000000000..31f8fe538590964f1f05e91c9ce61750e538cc5d --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/func_see_through_res34_webimg.py @@ -0,0 +1,67 @@ +import os +import breaching +import mindspore as ms +from custom_dataset import CustomData + + +def reset_cfg_by_client(cfg, args): + cfg.case.user.num_data_points = int(args['custom_parameter']['num_data_points']) + cfg.attack.optim.max_iterations = int(args['custom_parameter']['max_iterations']) + cfg.attack.optim.step_size = float(args['custom_parameter']['step_size']) + cfg.attack.regularization.total_variation.scale = float(args['custom_parameter']['TV_scale']) + cfg.attack.regularization.total_variation.tv_start = int(args['custom_parameter']['TV_start']) + cfg.attack.regularization.deep_inversion.scale = float(args['custom_parameter']['BN_scale']) + cfg.attack.regularization.deep_inversion.deep_inv_start = int(args['custom_parameter']['BN_start']) + cfg.attack.optim.callback = int(args['custom_parameter']['callback']) + + +def run_step_wise_GI(args): + try: + ms.set_context(device_target="GPU", device_id=0) + print('using mindspore with GPU context') + except: + ms.set_context(device_target="CPU") + print('using mindspore with CPU context') + + cfg = breaching.get_config(overrides=["case=12_custom_imagenet", "attack=seethrough_res34"]) + + cur_dir = os.path.dirname(__file__) + data_dir = cur_dir + '/custom_data/1_img/' + + cfg.attack.save_dir = args['out_put'] + cfg.case.data.path = args['data_path'] + + cfg.case.data.partition = 'balanced' + cfg.case.data.smooth = 0 + cfg.case.user.user_idx = 0 + cfg.case.model = "resnet34" + + cfg.case.user.provide_labels=False + cfg.case.user.provide_buffers=False + cfg.case.server.provide_public_buffers=True + cfg.case.server.pretrained=False + + # ---------根据用户自定义重置参数--------------------- + reset_cfg_by_client(cfg, args) + cus_defense = args['custom_parameter']['defense'] + sercure_input = True if cus_defense == 'Vicinal Augment' else False + apply_noise = True if cus_defense == 'Differential Privacy' else False + apply_prune = True if cus_defense == 'Gradient Prune' else False + + # --------------run-------------------------------- + user, server, model, loss_fn = breaching.cases.construct_case(cfg.case) + attacker = breaching.attacks.prepare_attack(server.model, server.loss, cfg.attack) + attacker.txt_path = args['out_put'] + args['eva_txt_file'] + + server_payload = server.distribute_payload() + + cus_data = CustomData(data_dir=data_dir, dataset_name='ImageNet', number_data_points=cfg.case.user.num_data_points) + shared_data, true_user_data = user.compute_local_updates(server_payload, custom_data=cus_data.process_data(), secure_input=sercure_input, apply_noise=apply_noise, apply_prune=apply_prune) + + true_pat = cfg.attack.save_dir + 'A_0.png' + cus_data.save_recover(true_user_data, save_pth=true_pat) + + ## ---------------attack part--------------------- + reconstructed_user_data = attacker.reconstruct([server_payload], [shared_data], {}, custom=cus_data) + recon_path__ = cfg.attack.save_dir + f'A_{attacker.save_flag}.png' + cus_data.save_recover(reconstructed_user_data, true_user_data, recon_path__) diff --git a/examples/privacy/gradient_inversion_attack/func_step_wise_res18_cifar.py b/examples/privacy/gradient_inversion_attack/func_step_wise_res18_cifar.py new file mode 100644 index 0000000000000000000000000000000000000000..535343093c4eb05e5a9a7c06b3fbe08910e2800f --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/func_step_wise_res18_cifar.py @@ -0,0 +1,67 @@ +import os +import breaching +import mindspore as ms +from custom_dataset import CustomData + + +def reset_cfg_by_client(cfg, args): + cfg.case.user.num_data_points = int(args['custom_parameter']['num_data_points']) + cfg.attack.optim.max_iterations = int(args['custom_parameter']['max_iterations']) + cfg.attack.optim.step_size = float(args['custom_parameter']['step_size']) + cfg.attack.regularization.total_variation.scale = float(args['custom_parameter']['TV_scale']) + cfg.attack.regularization.total_variation.tv_start = int(args['custom_parameter']['TV_start']) + cfg.attack.regularization.deep_inversion.scale = float(args['custom_parameter']['BN_scale']) + cfg.attack.regularization.deep_inversion.deep_inv_start = int(args['custom_parameter']['BN_start']) + cfg.attack.optim.callback = int(args['custom_parameter']['callback']) + + +def run_step_wise_GI(args): + try: + ms.set_context(device_target="GPU", device_id=0) + print('using mindspore with GPU context') + except: + ms.set_context(device_target="CPU") + print('using mindspore with CPU context') + + cfg = breaching.get_config(overrides=["case=11_small_batch_cifar", "attack=our_res18_pretrained"]) + + cur_dir = os.path.dirname(__file__) + data_dir = cur_dir + '/custom_data/1_img/' + + cfg.attack.save_dir = args['out_put'] + cfg.case.data.path = args['data_path'] + + cfg.case.data.partition = 'balanced' + cfg.case.data.smooth = 0 + cfg.case.user.user_idx = 0 + cfg.case.model = "resnet18" + + cfg.case.user.provide_labels=False + cfg.case.user.provide_buffers=False + cfg.case.server.provide_public_buffers=True + cfg.case.server.pretrained=False + + # ---------根据用户自定义重置参数--------------------- + reset_cfg_by_client(cfg, args) + cus_defense = args['custom_parameter']['defense'] + sercure_input = True if cus_defense == 'Vicinal Augment' else False + apply_noise = True if cus_defense == 'Differential Privacy' else False + apply_prune = True if cus_defense == 'Gradient Prune' else False + + # --------------run-------------------------------- + user, server, model, loss_fn = breaching.cases.construct_case(cfg.case) + attacker = breaching.attacks.prepare_attack(server.model, server.loss, cfg.attack) + attacker.txt_path = args['out_put'] + args['eva_txt_file'] + + server_payload = server.distribute_payload() + + cus_data = CustomData(data_dir=data_dir, dataset_name='CIFAR100', number_data_points=cfg.case.user.num_data_points) + shared_data, true_user_data = user.compute_local_updates(server_payload, secure_input=sercure_input, apply_noise=apply_noise, apply_prune=apply_prune) + + true_pat = cfg.attack.save_dir + 'A_0.png' + cus_data.save_recover(true_user_data, save_pth=true_pat) + + ## ---------------attack part--------------------- + reconstructed_user_data = attacker.reconstruct([server_payload], [shared_data], {}, custom=cus_data) + recon_path__ = cfg.attack.save_dir + f'A_{attacker.save_flag}.png' + cus_data.save_recover(reconstructed_user_data, true_user_data, recon_path__) diff --git a/examples/privacy/gradient_inversion_attack/func_step_wise_res18_tinyimgnet.py b/examples/privacy/gradient_inversion_attack/func_step_wise_res18_tinyimgnet.py new file mode 100644 index 0000000000000000000000000000000000000000..a237f84a0a0e7ccd899ccd568e9af89c117a3471 --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/func_step_wise_res18_tinyimgnet.py @@ -0,0 +1,66 @@ +import os +import breaching +import mindspore as ms +from custom_dataset import CustomData + + +def reset_cfg_by_client(cfg, args): + cfg.case.user.num_data_points = int(args['custom_parameter']['num_data_points']) + cfg.attack.optim.max_iterations = int(args['custom_parameter']['max_iterations']) + cfg.attack.optim.step_size = float(args['custom_parameter']['step_size']) + cfg.attack.regularization.total_variation.scale = float(args['custom_parameter']['TV_scale']) + cfg.attack.regularization.total_variation.tv_start = int(args['custom_parameter']['TV_start']) + cfg.attack.regularization.deep_inversion.scale = float(args['custom_parameter']['BN_scale']) + cfg.attack.regularization.deep_inversion.deep_inv_start = int(args['custom_parameter']['BN_start']) + cfg.attack.optim.callback = int(args['custom_parameter']['callback']) + + +def run_step_wise_GI(args): + try: + ms.set_context(device_target="GPU", device_id=0) + print('using mindspore with GPU context') + except: + ms.set_context(device_target="CPU") + print('using mindspore with CPU context') + + cfg = breaching.get_config(overrides=["case=13_custom_tinyimagenet", "attack=our_res18_pretrained"]) + + cur_dir = os.path.dirname(__file__) + data_dir = cur_dir + '/custom_data/1_img/' + + cfg.attack.save_dir = args['out_put'] + cfg.case.data.path = args['data_path'] + + cfg.case.data.smooth = 0 + cfg.case.user.user_idx = 0 + cfg.case.model = "resnet18" + + cfg.case.user.provide_labels=False + cfg.case.user.provide_buffers=False + cfg.case.server.provide_public_buffers=True + cfg.case.server.pretrained=False + + # ---------根据用户自定义重置参数--------------------- + reset_cfg_by_client(cfg, args) + cus_defense = args['custom_parameter']['defense'] + sercure_input = True if cus_defense == 'Vicinal Augment' else False + apply_noise = True if cus_defense == 'Differential Privacy' else False + apply_prune = True if cus_defense == 'Gradient Prune' else False + + # --------------run-------------------------------- + user, server, model, loss_fn = breaching.cases.construct_case(cfg.case) + attacker = breaching.attacks.prepare_attack(server.model, server.loss, cfg.attack) + attacker.txt_path = args['out_put'] + args['eva_txt_file'] + + server_payload = server.distribute_payload() + + cus_data = CustomData(data_dir=data_dir, dataset_name='TinyImageNet', number_data_points=cfg.case.user.num_data_points) + shared_data, true_user_data = user.compute_local_updates(server_payload, secure_input=sercure_input, apply_noise=apply_noise, apply_prune=apply_prune) + + true_pat = cfg.attack.save_dir + 'A_0.png' + cus_data.save_recover(true_user_data, save_pth=true_pat) + + ## ---------------attack part--------------------- + reconstructed_user_data = attacker.reconstruct([server_payload], [shared_data], {}, custom=cus_data) + recon_path__ = cfg.attack.save_dir + f'A_{attacker.save_flag}.png' + cus_data.save_recover(reconstructed_user_data, true_user_data, recon_path__) diff --git a/examples/privacy/gradient_inversion_attack/func_step_wise_res18_webimg.py b/examples/privacy/gradient_inversion_attack/func_step_wise_res18_webimg.py new file mode 100644 index 0000000000000000000000000000000000000000..491320ff6b42be6b07f2bfee40ccd3eceb7b43b0 --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/func_step_wise_res18_webimg.py @@ -0,0 +1,67 @@ +import os +import breaching +import mindspore as ms +from custom_dataset import CustomData + + +def reset_cfg_by_client(cfg, args): + cfg.case.user.num_data_points = int(args['custom_parameter']['num_data_points']) + cfg.attack.optim.max_iterations = int(args['custom_parameter']['max_iterations']) + cfg.attack.optim.step_size = float(args['custom_parameter']['step_size']) + cfg.attack.regularization.total_variation.scale = float(args['custom_parameter']['TV_scale']) + cfg.attack.regularization.total_variation.tv_start = int(args['custom_parameter']['TV_start']) + cfg.attack.regularization.deep_inversion.scale = float(args['custom_parameter']['BN_scale']) + cfg.attack.regularization.deep_inversion.deep_inv_start = int(args['custom_parameter']['BN_start']) + cfg.attack.optim.callback = int(args['custom_parameter']['callback']) + + +def run_step_wise_GI(args): + try: + ms.set_context(device_target="GPU", device_id=0) + print('using mindspore with GPU context') + except: + ms.set_context(device_target="CPU") + print('using mindspore with CPU context') + + cfg = breaching.get_config(overrides=["case=12_custom_imagenet", "attack=our_res18_pretrained"]) + + cur_dir = os.path.dirname(__file__) + data_dir = cur_dir + '/custom_data/1_img/' + + cfg.attack.save_dir = args['out_put'] + cfg.case.data.path = args['data_path'] + + cfg.case.data.partition = 'balanced' + cfg.case.data.smooth = 0 + cfg.case.user.user_idx = 0 + cfg.case.model = "resnet18" + + cfg.case.user.provide_labels=False + cfg.case.user.provide_buffers=False + cfg.case.server.provide_public_buffers=True + cfg.case.server.pretrained=False + + # ---------根据用户自定义重置参数--------------------- + reset_cfg_by_client(cfg, args) + cus_defense = args['custom_parameter']['defense'] + sercure_input = True if cus_defense == 'Vicinal Augment' else False + apply_noise = True if cus_defense == 'Differential Privacy' else False + apply_prune = True if cus_defense == 'Gradient Prune' else False + + # --------------run-------------------------------- + user, server, model, loss_fn = breaching.cases.construct_case(cfg.case) + attacker = breaching.attacks.prepare_attack(server.model, server.loss, cfg.attack) + attacker.txt_path = args['out_put'] + args['eva_txt_file'] + + server_payload = server.distribute_payload() + + cus_data = CustomData(data_dir=data_dir, dataset_name='ImageNet', number_data_points=cfg.case.user.num_data_points) + shared_data, true_user_data = user.compute_local_updates(server_payload, custom_data=cus_data.process_data(), secure_input=sercure_input, apply_noise=apply_noise, apply_prune=apply_prune) + + true_pat = cfg.attack.save_dir + 'A_0.png' + cus_data.save_recover(true_user_data, save_pth=true_pat) + + ## ---------------attack part--------------------- + reconstructed_user_data = attacker.reconstruct([server_payload], [shared_data], {}, custom=cus_data) + recon_path__ = cfg.attack.save_dir + f'A_{attacker.save_flag}.png' + cus_data.save_recover(reconstructed_user_data, true_user_data, recon_path__) diff --git a/examples/privacy/gradient_inversion_attack/func_step_wise_res34_cifar.py b/examples/privacy/gradient_inversion_attack/func_step_wise_res34_cifar.py new file mode 100644 index 0000000000000000000000000000000000000000..c3a9125020fbbdbc659af886141bf2fef92d4368 --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/func_step_wise_res34_cifar.py @@ -0,0 +1,67 @@ +import os +import breaching +import mindspore as ms +from custom_dataset import CustomData + + +def reset_cfg_by_client(cfg, args): + cfg.case.user.num_data_points = int(args['custom_parameter']['num_data_points']) + cfg.attack.optim.max_iterations = int(args['custom_parameter']['max_iterations']) + cfg.attack.optim.step_size = float(args['custom_parameter']['step_size']) + cfg.attack.regularization.total_variation.scale = float(args['custom_parameter']['TV_scale']) + cfg.attack.regularization.total_variation.tv_start = int(args['custom_parameter']['TV_start']) + cfg.attack.regularization.deep_inversion.scale = float(args['custom_parameter']['BN_scale']) + cfg.attack.regularization.deep_inversion.deep_inv_start = int(args['custom_parameter']['BN_start']) + cfg.attack.optim.callback = int(args['custom_parameter']['callback']) + + +def run_step_wise_GI(args): + try: + ms.set_context(device_target="GPU", device_id=0) + print('using mindspore with GPU context') + except: + ms.set_context(device_target="CPU") + print('using mindspore with CPU context') + + cfg = breaching.get_config(overrides=["case=11_small_batch_cifar", "attack=our_res34_pretrained"]) + + cur_dir = os.path.dirname(__file__) + data_dir = cur_dir + '/custom_data/1_img/' + + cfg.attack.save_dir = args['out_put'] + cfg.case.data.path = args['data_path'] + + cfg.case.data.partition = 'balanced' + cfg.case.data.smooth = 0 + cfg.case.user.user_idx = 0 + cfg.case.model = "resnet34" + + cfg.case.user.provide_labels=False + cfg.case.user.provide_buffers=False + cfg.case.server.provide_public_buffers=True + cfg.case.server.pretrained=False + + # ---------根据用户自定义重置参数--------------------- + reset_cfg_by_client(cfg, args) + cus_defense = args['custom_parameter']['defense'] + sercure_input = True if cus_defense == 'Vicinal Augment' else False + apply_noise = True if cus_defense == 'Differential Privacy' else False + apply_prune = True if cus_defense == 'Gradient Prune' else False + + # --------------run-------------------------------- + user, server, model, loss_fn = breaching.cases.construct_case(cfg.case) + attacker = breaching.attacks.prepare_attack(server.model, server.loss, cfg.attack) + attacker.txt_path = args['out_put'] + args['eva_txt_file'] + + server_payload = server.distribute_payload() + + cus_data = CustomData(data_dir=data_dir, dataset_name='CIFAR100', number_data_points=cfg.case.user.num_data_points) + shared_data, true_user_data = user.compute_local_updates(server_payload, secure_input=sercure_input, apply_noise=apply_noise, apply_prune=apply_prune) + + true_pat = cfg.attack.save_dir + 'A_0.png' + cus_data.save_recover(true_user_data, save_pth=true_pat) + + ## ---------------attack part--------------------- + reconstructed_user_data = attacker.reconstruct([server_payload], [shared_data], {}, custom=cus_data) + recon_path__ = cfg.attack.save_dir + f'A_{attacker.save_flag}.png' + cus_data.save_recover(reconstructed_user_data, true_user_data, recon_path__) diff --git a/examples/privacy/gradient_inversion_attack/func_step_wise_res34_tinyimgnet.py b/examples/privacy/gradient_inversion_attack/func_step_wise_res34_tinyimgnet.py new file mode 100644 index 0000000000000000000000000000000000000000..393d403789885bb2c6684421be8f2f8350cbef45 --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/func_step_wise_res34_tinyimgnet.py @@ -0,0 +1,67 @@ +import os +import breaching +import mindspore as ms +from custom_dataset import CustomData + + +def reset_cfg_by_client(cfg, args): + cfg.case.user.num_data_points = int(args['custom_parameter']['num_data_points']) + cfg.attack.optim.max_iterations = int(args['custom_parameter']['max_iterations']) + cfg.attack.optim.step_size = float(args['custom_parameter']['step_size']) + cfg.attack.regularization.total_variation.scale = float(args['custom_parameter']['TV_scale']) + cfg.attack.regularization.total_variation.tv_start = int(args['custom_parameter']['TV_start']) + cfg.attack.regularization.deep_inversion.scale = float(args['custom_parameter']['BN_scale']) + cfg.attack.regularization.deep_inversion.deep_inv_start = int(args['custom_parameter']['BN_start']) + cfg.attack.optim.callback = int(args['custom_parameter']['callback']) + + +def run_step_wise_GI(args): + try: + ms.set_context(device_target="GPU", device_id=0) + print('using mindspore with GPU context') + except: + ms.set_context(device_target="CPU") + print('using mindspore with CPU context') + + cfg = breaching.get_config(overrides=["case=13_custom_tinyimagenet", "attack=our_res34_pretrained"]) + + cur_dir = os.path.dirname(__file__) + data_dir = cur_dir + '/custom_data/1_img/' + + cfg.attack.save_dir = args['out_put'] + cfg.case.data.path = args['data_path'] + + cfg.case.data.partition = 'balanced' + cfg.case.data.smooth = 0 + cfg.case.user.user_idx = 0 + cfg.case.model = "resnet34" + + cfg.case.user.provide_labels=False + cfg.case.user.provide_buffers=False + cfg.case.server.provide_public_buffers=True + cfg.case.server.pretrained=False + + # ---------根据用户自定义重置参数--------------------- + reset_cfg_by_client(cfg, args) + cus_defense = args['custom_parameter']['defense'] + sercure_input = True if cus_defense == 'Vicinal Augment' else False + apply_noise = True if cus_defense == 'Differential Privacy' else False + apply_prune = True if cus_defense == 'Gradient Prune' else False + + # --------------run-------------------------------- + user, server, model, loss_fn = breaching.cases.construct_case(cfg.case) + attacker = breaching.attacks.prepare_attack(server.model, server.loss, cfg.attack) + attacker.txt_path = args['out_put'] + args['eva_txt_file'] + + server_payload = server.distribute_payload() + + cus_data = CustomData(data_dir=data_dir, dataset_name='TinyImageNet', number_data_points=cfg.case.user.num_data_points) + shared_data, true_user_data = user.compute_local_updates(server_payload, secure_input=sercure_input, apply_noise=apply_noise, apply_prune=apply_prune) + + true_pat = cfg.attack.save_dir + 'A_0.png' + cus_data.save_recover(true_user_data, save_pth=true_pat) + + ## ---------------attack part--------------------- + reconstructed_user_data = attacker.reconstruct([server_payload], [shared_data], {}, custom=cus_data) + recon_path__ = cfg.attack.save_dir + f'A_{attacker.save_flag}.png' + cus_data.save_recover(reconstructed_user_data, true_user_data, recon_path__) diff --git a/examples/privacy/gradient_inversion_attack/func_step_wise_res34_webimg.py b/examples/privacy/gradient_inversion_attack/func_step_wise_res34_webimg.py new file mode 100644 index 0000000000000000000000000000000000000000..05e3d5fd60f767854577cdd50ad88bafddef5ac5 --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/func_step_wise_res34_webimg.py @@ -0,0 +1,67 @@ +import os +import breaching +import mindspore as ms +from custom_dataset import CustomData + + +def reset_cfg_by_client(cfg, args): + cfg.case.user.num_data_points = int(args['custom_parameter']['num_data_points']) + cfg.attack.optim.max_iterations = int(args['custom_parameter']['max_iterations']) + cfg.attack.optim.step_size = float(args['custom_parameter']['step_size']) + cfg.attack.regularization.total_variation.scale = float(args['custom_parameter']['TV_scale']) + cfg.attack.regularization.total_variation.tv_start = int(args['custom_parameter']['TV_start']) + cfg.attack.regularization.deep_inversion.scale = float(args['custom_parameter']['BN_scale']) + cfg.attack.regularization.deep_inversion.deep_inv_start = int(args['custom_parameter']['BN_start']) + cfg.attack.optim.callback = int(args['custom_parameter']['callback']) + + +def run_step_wise_GI(args): + try: + ms.set_context(device_target="GPU", device_id=0) + print('using mindspore with GPU context') + except: + ms.set_context(device_target="CPU") + print('using mindspore with CPU context') + + cfg = breaching.get_config(overrides=["case=12_custom_imagenet", "attack=our_res34_pretrained"]) + + cur_dir = os.path.dirname(__file__) + data_dir = cur_dir + '/custom_data/1_img/' + + cfg.attack.save_dir = args['out_put'] + cfg.case.data.path = args['data_path'] + + cfg.case.data.partition = 'balanced' + cfg.case.data.smooth = 0 + cfg.case.user.user_idx = 0 + cfg.case.model = "resnet34" + + cfg.case.user.provide_labels=False + cfg.case.user.provide_buffers=False + cfg.case.server.provide_public_buffers=True + cfg.case.server.pretrained=False + + # ---------根据用户自定义重置参数--------------------- + reset_cfg_by_client(cfg, args) + cus_defense = args['custom_parameter']['defense'] + sercure_input = True if cus_defense == 'Vicinal Augment' else False + apply_noise = True if cus_defense == 'Differential Privacy' else False + apply_prune = True if cus_defense == 'Gradient Prune' else False + + # --------------run-------------------------------- + user, server, model, loss_fn = breaching.cases.construct_case(cfg.case) + attacker = breaching.attacks.prepare_attack(server.model, server.loss, cfg.attack) + attacker.txt_path = args['out_put'] + args['eva_txt_file'] + + server_payload = server.distribute_payload() + + cus_data = CustomData(data_dir=data_dir, dataset_name='ImageNet', number_data_points=cfg.case.user.num_data_points) + shared_data, true_user_data = user.compute_local_updates(server_payload, custom_data=cus_data.process_data(), secure_input=sercure_input, apply_noise=apply_noise, apply_prune=apply_prune) + + true_pat = cfg.attack.save_dir + 'A_0.png' + cus_data.save_recover(true_user_data, save_pth=true_pat) + + ## ---------------attack part--------------------- + reconstructed_user_data = attacker.reconstruct([server_payload], [shared_data], {}, custom=cus_data) + recon_path__ = cfg.attack.save_dir + f'A_{attacker.save_flag}.png' + cus_data.save_recover(reconstructed_user_data, true_user_data, recon_path__) diff --git a/examples/privacy/gradient_inversion_attack/main.py b/examples/privacy/gradient_inversion_attack/main.py new file mode 100644 index 0000000000000000000000000000000000000000..3c823cc2883c2f577162127bc654de0a8a44ac6e --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/main.py @@ -0,0 +1,79 @@ +# Copyright 2024 Huawei Technologies Co., Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================ + +import copy +import argparse +import os + + +FILE_NAME_DICT = { + "InvGrad": 'inv_grad_', + "SeeThrough": 'see_through_', + "StepWise": 'step_wise_', + "resnet18": 'res18_', + "resnet34": 'res34_', + "CIFAR100": 'cifar', + "TinyImageNet": 'tinyimgnet', + "WebImage": 'webimg', +} + + +def get_exe_file_name(arg_dic): + return 'func_'+FILE_NAME_DICT[arg_dic['alg_name']]+FILE_NAME_DICT[arg_dic['model']]+FILE_NAME_DICT[arg_dic['dataset']] + + +def arg_parse(): + parse = argparse.ArgumentParser() + parse.add_argument('--out_put', type=str, default='output/', help='directory for save outputs') + parse.add_argument('--data_path', type=str, default='./data', help='path of dataset') + parse.add_argument('--dataset', type=str, default="WebImage", choices=['TinyImageNet', 'CIFAR100', 'WebImage']) + parse.add_argument('--model', type=str, default="resnet34", choices=['resnet18', 'resnet34']) + parse.add_argument('--alg_name', type=str, default="StepWise", choices=['InvGrad', 'SeeThrough', 'StepWise']) + parse.add_argument('--defense', type=str, default="None", choices=['None', 'Vicinal Augment', 'Differential Privacy', 'Gradient Prune']) + parse.add_argument('--num_data_points', type=int, default=4) + parse.add_argument('--max_iterations', type=int, default=7000) + parse.add_argument('--step_size', type=float, default=0.1) + parse.add_argument('--TV_scale', type=float, default=0.002) + parse.add_argument('--TV_start', type=int, default=2000) + parse.add_argument('--BN_scale', type=float, default=0.0001) + parse.add_argument('--BN_start', type=int, default=3000) + parse.add_argument('--callback', type=int, default=100) + + args = parse.parse_args() + args.eva_txt_file = 'resultTXT.txt' + + return args + + +def run_main(args): + arg_dic = copy.deepcopy(vars(args)) + arg_dic['custom_parameter'] = {} + for key in vars(args): + arg_dic['custom_parameter'][key] = getattr(args, key) + exe_file_name = get_exe_file_name(arg_dic) + if not os.path.exists(arg_dic['out_put']): + os.mkdir(arg_dic['out_put']) + try: + handle_py = __import__('.'+exe_file_name) + except: + handle_py = __import__(exe_file_name) + exe_func = getattr(handle_py, 'run_step_wise_GI') + exe_func(arg_dic) + print('Running over! Check the output in directory: ' + arg_dic['out_put']) + + +if __name__ == '__main__': + args = arg_parse() + run_main(args) diff --git a/examples/privacy/gradient_inversion_attack/minimal_environment.yml b/examples/privacy/gradient_inversion_attack/minimal_environment.yml new file mode 100644 index 0000000000000000000000000000000000000000..a56bcbe6d7176227828bb01ab497987f5e500f23 --- /dev/null +++ b/examples/privacy/gradient_inversion_attack/minimal_environment.yml @@ -0,0 +1,8 @@ +dependencies: + - python==3.9.0 + - mindspore==2.1.0 + - cuda==11.6 + - pip + - pip: + - hydra-core==1.2.0 + - omegaconf==2.2.0