From 68c2fbd969fcb2d29702434ec0ea0ab08dba373b Mon Sep 17 00:00:00 2001 From: ZhidanLiu Date: Wed, 27 May 2020 11:15:08 +0800 Subject: [PATCH] add tutorial of differential privacy --- .../mindarmour/mindarmour.diff_privacy.rst | 5 + api/source_en/index.rst | 1 + .../mindarmour/mindarmour.diff_privacy.rst | 5 + api/source_zh_cn/index.rst | 1 + .../advanced_use/differential_privacy.md | 297 ++++++++++++++++++ .../advanced_use/images/DP_formula.png | Bin 0 -> 8329 bytes .../advanced_use/images/dp_res.png | Bin 0 -> 27034 bytes tutorials/source_zh_cn/index.rst | 3 +- 8 files changed, 311 insertions(+), 1 deletion(-) create mode 100644 api/source_en/api/python/mindarmour/mindarmour.diff_privacy.rst create mode 100644 api/source_zh_cn/api/python/mindarmour/mindarmour.diff_privacy.rst create mode 100644 tutorials/source_zh_cn/advanced_use/differential_privacy.md create mode 100644 tutorials/source_zh_cn/advanced_use/images/DP_formula.png create mode 100644 tutorials/source_zh_cn/advanced_use/images/dp_res.png diff --git a/api/source_en/api/python/mindarmour/mindarmour.diff_privacy.rst b/api/source_en/api/python/mindarmour/mindarmour.diff_privacy.rst new file mode 100644 index 0000000000..9ae8947a6e --- /dev/null +++ b/api/source_en/api/python/mindarmour/mindarmour.diff_privacy.rst @@ -0,0 +1,5 @@ +mindarmour.diff_privacy +======================= + +.. automodule:: mindarmour.diff_privacy + :members: \ No newline at end of file diff --git a/api/source_en/index.rst b/api/source_en/index.rst index 0b43288643..ed017211ba 100644 --- a/api/source_en/index.rst +++ b/api/source_en/index.rst @@ -38,6 +38,7 @@ MindSpore API api/python/mindarmour/mindarmour.attacks api/python/mindarmour/mindarmour.defenses api/python/mindarmour/mindarmour.fuzzing + api/python/mindarmour/mindarmour.diff_privacy .. toctree:: :maxdepth: 1 diff --git a/api/source_zh_cn/api/python/mindarmour/mindarmour.diff_privacy.rst b/api/source_zh_cn/api/python/mindarmour/mindarmour.diff_privacy.rst new file mode 100644 index 0000000000..9ae8947a6e --- /dev/null +++ b/api/source_zh_cn/api/python/mindarmour/mindarmour.diff_privacy.rst @@ -0,0 +1,5 @@ +mindarmour.diff_privacy +======================= + +.. automodule:: mindarmour.diff_privacy + :members: \ No newline at end of file diff --git a/api/source_zh_cn/index.rst b/api/source_zh_cn/index.rst index c703be92f6..bbef0e6d35 100644 --- a/api/source_zh_cn/index.rst +++ b/api/source_zh_cn/index.rst @@ -38,6 +38,7 @@ MindSpore API api/python/mindarmour/mindarmour.attacks api/python/mindarmour/mindarmour.defenses api/python/mindarmour/mindarmour.fuzzing + api/python/mindarmour/mindarmour.diff_privacy .. toctree:: :maxdepth: 1 diff --git a/tutorials/source_zh_cn/advanced_use/differential_privacy.md b/tutorials/source_zh_cn/advanced_use/differential_privacy.md new file mode 100644 index 0000000000..f3c62a7dd0 --- /dev/null +++ b/tutorials/source_zh_cn/advanced_use/differential_privacy.md @@ -0,0 +1,297 @@ +# 机器学习中的差分隐私 + +## 概述 + +差分隐私是一种保护用户数据隐私的机制。什么是隐私,隐私指的是单个用户的某些属性,一群用户的某一些属性可以不看做隐私。例如:“抽烟的人有更高的几率会得肺癌”,这个不泄露隐私,但是”张三抽烟,得了肺癌“,这个就泄露了张三的隐私。如果我们知道A医院,今天就诊的100个病人,其中有10个肺癌,并且我们知道了其中99个人的患病信息,就可以推测剩下一个人是否患有肺癌。这种窃取隐私的行为叫做差分攻击。差分隐私是防止差分攻击的方法,通过添加噪声,使得差别只有一条记录的两个数据集,通过模型推理获得相同结果的概率非常接近。 + +**机器学习中的差分隐私** + +机器学习算法一般是用大量数据并更新模型参数,学习数据特征。在理想情况下,这些算法学习到一些泛化性较好的模型,例如“吸烟患者更容易得肺癌”,而不是特定的个体特征,例如“张三是个吸烟者,患有肺癌”。然而,机器学习算法并不会区分通用特征还是个体特征。当我们用机器学习来完成某个重要的任务,例如肺癌诊断,发布的机器学习模型,可能在无意中透露训练集中的个体特征,恶意攻击者可能从发布的模型获得关于张三的隐私信息,因此使用差分隐私技术来保护机器学习模型是十分必要的。 + +**差分隐私定义**[1]为:![gs](images/DP_formula.png) + +对于两个差别只有一条记录的数据集$D, D'$,通过随机算法$\mathcal{K}$,输出为结果集合$S$子集的概率满足上面公式,$\epsilon$为差分隐私预算,$\delta$ 为扰动,$\epsilon, \delta$越小,$\mathcal{K}$在$D, D'$上输出的数据分布越接近。 + +**差分隐私的度量** + +差分隐私可以用$\epsilon, \delta$ 度量。 + +- $\epsilon$:数据集中增加或者减少一条记录,引起的输出概率可以改变的上限。我们通常希望$\epsilon$是一个较小的常数,值越小表示差分隐私条件越严格。 +- $\delta$:用于限制模型行为任意改变的概率,通常设置为一个小的常数,推荐设置小于训练数据集大小的倒数。 + +**MindArmour实现的差分隐私** + +MindArmour的差分隐私模块Differential-Privacy,实现了差分隐私优化器。目前支持基于高斯机制的差分隐私SGD、Momentum优化器,同时还提供RDP(R’enyi differential privacy)[2]用于监测差分隐私预算。 + +这里以LeNet模型,MNIST 数据集为例,说明如何在MindSpore上使用差分隐私优化器训练神经网络模型。 + +> 本例面向Ascend 910 AI处理器,支持PYNATIVE_MODE,你可以在这里下载完整的样例代码: + +## 实现阶段 + +### 导入需要的库文件 + +下列是我们需要的公共模块、MindSpore相关模块和差分隐私特性模块。 + +```python +import os +import argparse + +import mindspore.nn as nn +from mindspore import context +from mindspore.train.callback import ModelCheckpoint +from mindspore.train.callback import CheckpointConfig +from mindspore.train.callback import LossMonitor +from mindspore.nn.metrics import Accuracy +from mindspore.train.serialization import load_checkpoint, load_param_into_net +import mindspore.dataset as ds +import mindspore.dataset.transforms.vision.c_transforms as CV +import mindspore.dataset.transforms.c_transforms as C +from mindspore.dataset.transforms.vision import Inter +import mindspore.common.dtype as mstype + +from mindarmour.diff_privacy import DPModel +from mindarmour.diff_privacy import DPOptimizerClassFactory +from mindarmour.diff_privacy import PrivacyMonitorFactory +from mindarmour.utils.logger import LogUtil +from lenet5_net import LeNet5 +from lenet5_config import mnist_cfg as cfg +``` + +### 配置环境信息 + +1. 使用`parser`模块,传入运行必要的信息,如运行环境设置、数据集存放路径等,这样的好处是对于经常变化的配置,可以在运行代码时输入,使用更加灵活。 + + 参数说明: + + - device_target:运行环境,在'Ascend','GPU','CPU'上运行脚本。 + - data_path:数据集所在路径。 + - dataset_sink_mode:是否使用数据下沉模式。 + - micro_batches:差分隐私参数,将原始batch切割成micro_batches份,每次对batch/micro_batches个样本加噪声。 + - l2_norm_bound:差分隐私参数,梯度的二范数约束。 + - initial_noise_multiplier:差分隐私参数,高斯噪声的标准差等于initial_noise_multiplier乘以l2_norm_bound。 + + ```python + parser = argparse.ArgumentParser(description='MindSpore Example') + parser.add_argument('--device_target', type=str, default="Ascend", choices=['Ascend', 'GPU', 'CPU'], + help='device where the code will be implemented (default: Ascend)') + parser.add_argument('--data_path', type=str, default="./_unzip", + help='path where the dataset is saved') + parser.add_argument('--dataset_sink_mode', type=bool, default=False, help='dataset_sink_mode is False or True') + parser.add_argument('--micro_batches', type=float, default=None, + help='optional, if use differential privacy, need to set micro_batches') + parser.add_argument('--l2_norm_bound', type=float, default=1, + help='optional, if use differential privacy, need to set l2_norm_bound') + parser.add_argument('--initial_noise_multiplier', type=float, default=0.001, + help='optional, if use differential privacy, need to set initial_noise_multiplier') + args = parser.parse_args() + ``` + +2. 配置必要的信息,包括环境信息、执行的模式、后端信息及硬件信息。 + + ```python + context.set_context(mode=context.PYNATIVE_MODE, device_target=args.device_target) + ``` + + 详细的接口配置信息,请参见`context.set_context`接口说明。 + +### 预处理数据集 + +加载数据集并处理成MindSpore数据格式。 + +```python +def generate__dataset(data_path, batch_size=32, repeat_size=1, + num_parallel_workers=1, sparse=True): + """ + create dataset for training or testing + """ + # define dataset + ds1 = ds.Dataset(data_path) + + # define operation parameters + resize_height, resize_width = 32, 32 + rescale = 1.0 / 255.0 + shift = 0.0 + + # define map operations + resize_op = CV.Resize((resize_height, resize_width), + interpolation=Inter.LINEAR) + rescale_op = CV.Rescale(rescale, shift) + hwc2chw_op = CV.HWC2CHW() + type_cast_op = C.TypeCast(mstype.int32) + + # apply map operations on images + if not sparse: + one_hot_enco = C.OneHot(10) + ds1 = ds1.map(input_columns="label", operations=one_hot_enco, + num_parallel_workers=num_parallel_workers) + type_cast_op = C.TypeCast(mstype.float32) + ds1 = ds1.map(input_columns="label", operations=type_cast_op, + num_parallel_workers=num_parallel_workers) + ds1 = ds1.map(input_columns="image", operations=resize_op, + num_parallel_workers=num_parallel_workers) + ds1 = ds1.map(input_columns="image", operations=rescale_op, + num_parallel_workers=num_parallel_workers) + ds1 = ds1.map(input_columns="image", operations=hwc2chw_op, + num_parallel_workers=num_parallel_workers) + + # apply DatasetOps + buffer_size = 10000 + ds1 = ds1.shuffle(buffer_size=buffer_size) + ds1 = ds1.batch(batch_size, drop_remainder=True) + ds1 = ds1.repeat(repeat_size) + + return ds1 +``` + +### 建立模型 + +这里以`LeNet`模型为例,您也可以建立训练自己的模型。 + +```python +from mindspore import nn +from mindspore.common.initializer import TruncatedNormal + + +def conv(in_channels, out_channels, kernel_size, stride=1, padding=0): + weight = weight_variable() + return nn.Conv2d(in_channels, out_channels, + kernel_size=kernel_size, stride=stride, padding=padding, + weight_init=weight, has_bias=False, pad_mode="valid") + + +def fc_with_initialize(input_channels, out_channels): + weight = weight_variable() + bias = weight_variable() + return nn.Dense(input_channels, out_channels, weight, bias) + + +def weight_variable(): + return TruncatedNormal(0.02) + + +class LeNet5(nn.Cell): + """ + LeNet network + """ + def __init__(self): + super(LeNet5, self).__init__() + self.conv1 = conv(1, 6, 5) + self.conv2 = conv(6, 16, 5) + self.fc1 = fc_with_initialize(16*5*5, 120) + self.fc2 = fc_with_initialize(120, 84) + self.fc3 = fc_with_initialize(84, 10) + self.relu = nn.ReLU() + self.max_pool2d = nn.MaxPool2d(kernel_size=2, stride=2) + self.flatten = nn.Flatten() + + def construct(self, x): + x = self.conv1(x) + x = self.relu(x) + x = self.max_pool2d(x) + x = self.conv2(x) + x = self.relu(x) + x = self.max_pool2d(x) + x = self.flatten(x) + x = self.fc1(x) + x = self.relu(x) + x = self.fc2(x) + x = self.relu(x) + x = self.fc3(x) + return x +``` + +加载`LeNet`网络,定义损失函数、配置checkpoint、用上述定义的数据加载函数`generate__dataset`载入数据。 + +```python +network = LeNet5() +net_loss = nn.SoftmaxCrossEntropyWithLogits(is_grad=False, sparse=True, reduction="mean") +config_ck = CheckpointConfig(save_checkpoint_steps=cfg.save_checkpoint_steps, + keep_checkpoint_max=cfg.keep_checkpoint_max) +ckpoint_cb = ModelCheckpoint(prefix="checkpoint_lenet", + directory='./trained_ckpt_file/', + config=config_ck) + +ds_train = generate__dataset(os.path.join(args.data_path, "train"), + cfg.batch_size, + cfg.epoch_size) +``` + +### 引入差分隐私 + +1. 配置差分隐私优化器的参数。 + + - 实例化差分隐私工厂类。 + - 设置差分隐私的噪声机制,目前支持固定标准差的高斯噪声机制:'Gaussian'和自适应调整标准差的自适应高斯噪声机制:'AdaGaussian'。 + - 设置优化器类型,目前支持'SGD'和'Momentum'。 + - 设置差分隐私预算监测器RDP,用于观测每个step中的差分隐私预算$\epsilon$的变化。 + + ```python + gaussian_mech = DPOptimizerClassFactory(args.micro_batches) + gaussian_mech.set_mechanisms('Gaussian', + norm_bound=args.l2_norm_bound, + initial_noise_multiplier=args.initial_noise_multiplier) + net_opt = gaussian_mech.create('Momentum')(params=network.trainable_params(), + learning_rate=cfg.lr, + momentum=cfg.momentum) + rdp_monitor = PrivacyMonitorFactory.create('rdp', + num_samples=60000, + batch_size=16, + initial_noise_multiplier=5, + target_delta=0.5, + per_print_times=10) + ``` + +2. 将LeNet模型包装成差分隐私模型,只需要将网络传入`DPModel`即可。 + + ```python + model = DPModel(micro_batches=args.micro_batches, + norm_clip=args.l2_norm_bound, + dp_mech=gaussian_mech.mech, + network=network, + loss_fn=net_loss, + optimizer=net_opt, + metrics={"Accuracy": Accuracy()}) + ``` + +3. 模型训练与测试。 + + ```python + LOGGER.info(TAG, "============== Starting Training ==============") + model.train(cfg['epoch_size'], ds_train, callbacks=[ckpoint_cb, LossMonitor(), rdp_monitor], + dataset_sink_mode=args.dataset_sink_mode) + + LOGGER.info(TAG, "============== Starting Testing ==============") + ckpt_file_name = 'trained_ckpt_file/checkpoint_lenet-10_1875.ckpt' + param_dict = load_checkpoint(ckpt_file_name) + load_param_into_net(network, param_dict) + ds_eval = generate__dataset(os.path.join(args.data_path, 'test'), batch_size=cfg.batch_size) + acc = model.eval(ds_eval, dataset_sink_mode=False) + LOGGER.info(TAG, "============== Accuracy: %s ==============", acc) + + ``` + +4. 结果展示: + + 不加差分隐私的LeNet模型精度稳定在99%,加了自适应差分隐私AdaDP的LeNet模型收敛,精度稳定在96%,加了非自适应差分隐私DP[3]的LeNet模型收敛,精度稳定在94%左右。 + + ``` + ============== Starting Training ============== + ... + ============== Starting Testing ============== + ... + ============== Accuracy: 0.9635 ============== + ``` + + ![dp_res](images/dp_res.png) + +### 引用 + +[1] C. Dwork and J. Lei. Differential privacy and robust statistics. In STOC, pages 371–380. ACM, 2009. + +[2] Ilya Mironov. Rényi differential privacy. In IEEE Computer Security Foundations Symposium, 2017. + +[3] Abadi, M. e. a., 2016. *Deep learning with differential privacy.* s.l.:Proceedings of the 2016 ACM SIGSAC Conference on Computer and Communications Security. + + + diff --git a/tutorials/source_zh_cn/advanced_use/images/DP_formula.png b/tutorials/source_zh_cn/advanced_use/images/DP_formula.png new file mode 100644 index 0000000000000000000000000000000000000000..043272c7b8b15629b6eed6a27016aa21356bc0fa GIT binary patch literal 8329 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 literal 0 HcmV?d00001 diff --git a/tutorials/source_zh_cn/index.rst b/tutorials/source_zh_cn/index.rst index 7c8769abb9..d32a3c6774 100644 --- a/tutorials/source_zh_cn/index.rst +++ b/tutorials/source_zh_cn/index.rst @@ -67,6 +67,7 @@ MindSpore教程 .. toctree:: :glob: :maxdepth: 1 - :caption: AI安全 + :caption: AI安全和隐私 advanced_use/model_security + advanced_use/differential_privacy -- Gitee