Compare commits

...

30 Commits
master ... r0.7

Author SHA1 Message Date
  mindspore-ci-bot 95e30f35e3 !102 Avoid error of graph topological order 4 years ago
  mindspore-ci-bot 12d4873180 !100 fixed exception detection 4 years ago
  liuluobin 0921714ab5 Fix param check of metric 4 years ago
  mindspore-ci-bot 3a3ff1734e !98 Fixed exception detection and added log printing. 4 years ago
  liuluobin dfb30f0426 Fixed exception detection and added log printing 4 years ago
  mindspore-ci-bot c789bf3142 !97 Append parameter verification for 'attack_config' 4 years ago
  liuluobin dcc64ddde9 Append parameter verification for 'attack_config' 4 years ago
  mindspore-ci-bot b69a303257 !96 keep the type of parameters in fuzzing consistent with that in the called methods 4 years ago
  mindspore-ci-bot 08276a4b03 !95 Rectify the legal types for the parameter 'bias_coefficient' and add parameter check for 'mutate_config' . 4 years ago
  ZhidanLiu 437e61c93f keep the type of parameters in fuzzing consistent with that in the called methods 4 years ago
  jin-xiulang c4dd954356 Fix two api issues. 4 years ago
  mindspore-ci-bot 3746066c56 !93 Append description for get_attacker_model and train. 4 years ago
  liuluobin 7dc09aed90 Append description for get_attacker_model and train 4 years ago
  mindspore-ci-bot b34693ac3b !94 fix issues about rotate and delete redundant parameters 4 years ago
  ZhidanLiu a30128b681 fix issues 4 years ago
  mindspore-ci-bot 9d4e395924 !91 fix issues 4 years ago
  ZhidanLiu afa3f75fc3 fix issues 4 years ago
  mindspore-ci-bot 3d8877679b !90 Append the parameter verification of class MembershipInference. 4 years ago
  liuluobin ce15e7811e Append the parameter verification of class MembershipInference. 4 years ago
  mindspore-ci-bot 29e303a893 !88 fix a bug in evaluate of fuzzing 4 years ago
  ZhidanLiu 8113cb2482 fix a bug in evaluate of fuzzing 4 years ago
  mindspore-ci-bot f932834870 !86 Fix three issues. 4 years ago
  jin-xiulang a4a2f5d2f6 Fix Three issues. 4 years ago
  mindspore-ci-bot 3f35041b3e !87 modify notations of fuzzing to fix two issues 4 years ago
  ZhidanLiu b58ac94d5b modity the notation of fuzzing 4 years ago
  mindspore-ci-bot 9ef5a5a61b !85 Fix several api issues. 4 years ago
  jin-xiulang 0b17c39dca Fix several api issues 4 years ago
  mindspore-ci-bot 339595a3ee !84 add 0.7.0 release info 4 years ago
  mindspore-ci-bot 76af12e31f !83 Append membership inference reference in __init__.py 4 years ago
  liuluobin 0c4da595bb append reference in __init__.py 4 years ago
13 changed files with 260 additions and 95 deletions
Split View
  1. +3
    -2
      example/membership_inference_demo/train.py
  2. +1
    -1
      example/mnist_demo/lenet5_mnist_coverage.py
  3. +14
    -6
      example/mnist_demo/lenet5_mnist_fuzzing.py
  4. +3
    -1
      mindarmour/diff_privacy/__init__.py
  5. +22
    -3
      mindarmour/diff_privacy/evaluation/attacker.py
  6. +107
    -22
      mindarmour/diff_privacy/evaluation/membership_inference.py
  7. +77
    -38
      mindarmour/fuzzing/fuzzing.py
  8. +9
    -5
      mindarmour/fuzzing/image_transform.py
  9. +12
    -9
      mindarmour/fuzzing/model_coverage_metrics.py
  10. +5
    -1
      mindarmour/utils/logger.py
  11. +1
    -1
      mindarmour/utils/util.py
  12. +2
    -2
      tests/ut/python/fuzzing/test_coverage_metrics.py
  13. +4
    -4
      tests/ut/python/fuzzing/test_fuzzer.py

+ 3
- 2
example/membership_inference_demo/train.py View File

@@ -27,7 +27,7 @@ import mindspore.nn as nn
from mindspore import Tensor
from mindspore import context
from mindspore.nn.optim.momentum import Momentum
from mindspore.train.callback import ModelCheckpoint, CheckpointConfig
from mindspore.train.callback import ModelCheckpoint, CheckpointConfig, LossMonitor
from mindspore.train.model import Model
from mindspore.train.serialization import load_param_into_net, load_checkpoint
from mindarmour.utils import LogUtil
@@ -187,12 +187,13 @@ if __name__ == '__main__':
amp_level="O2", keep_batchnorm_fp32=False, loss_scale_manager=None)

# checkpoint save
callbacks = [LossMonitor()]
if args.rank_save_ckpt_flag:
ckpt_config = CheckpointConfig(save_checkpoint_steps=args.ckpt_interval*args.steps_per_epoch,
keep_checkpoint_max=args.ckpt_save_max)
ckpt_cb = ModelCheckpoint(config=ckpt_config,
directory=args.outputs_dir,
prefix='{}'.format(args.rank))
callbacks = ckpt_cb
callbacks.append(ckpt_cb)

model.train(args.max_epoch, dataset, callbacks=callbacks)

+ 1
- 1
example/mnist_demo/lenet5_mnist_coverage.py View File

@@ -51,7 +51,7 @@ def test_lenet_mnist_coverage():
train_images = np.concatenate(train_images, axis=0)

# initialize fuzz test with training dataset
model_fuzz_test = ModelCoverageMetrics(model, 10000, 10, train_images)
model_fuzz_test = ModelCoverageMetrics(model, 10, 1000, train_images)

# fuzz test with original test data
# get test data


+ 14
- 6
example/mnist_demo/lenet5_mnist_fuzzing.py View File

@@ -41,12 +41,20 @@ def test_lenet_mnist_fuzzing():
mutate_config = [{'method': 'Blur',
'params': {'auto_param': True}},
{'method': 'Contrast',
'params': {'factor': 2}},
'params': {'auto_param': True}},
{'method': 'Translate',
'params': {'x_bias': 0.1, 'y_bias': 0.2}},
'params': {'auto_param': True}},
{'method': 'Brightness',
'params': {'auto_param': True}},
{'method': 'Noise',
'params': {'auto_param': True}},
{'method': 'Scale',
'params': {'auto_param': True}},
{'method': 'Shear',
'params': {'auto_param': True}},
{'method': 'FGSM',
'params': {'eps': 0.1, 'alpha': 0.1}}
]
'params': {'eps': 0.3, 'alpha': 0.1}}
]

# get training data
data_list = "./MNIST_unzip/train"
@@ -59,7 +67,7 @@ def test_lenet_mnist_fuzzing():
train_images = np.concatenate(train_images, axis=0)

# initialize fuzz test with training dataset
model_coverage_test = ModelCoverageMetrics(model, 1000, 10, train_images)
model_coverage_test = ModelCoverageMetrics(model, 10, 1000, train_images)

# fuzz test with original test data
# get test data
@@ -79,7 +87,7 @@ def test_lenet_mnist_fuzzing():

# make initial seeds
for img, label in zip(test_images, test_labels):
initial_seeds.append([img, label, 0])
initial_seeds.append([img, label])

initial_seeds = initial_seeds[:100]
model_coverage_test.calculate_coverage(


+ 3
- 1
mindarmour/diff_privacy/__init__.py View File

@@ -11,6 +11,7 @@ from .monitor.monitor import RDPMonitor
from .monitor.monitor import ZCDPMonitor
from .optimizer.optimizer import DPOptimizerClassFactory
from .train.model import DPModel
from .evaluation.membership_inference import MembershipInference

__all__ = ['NoiseGaussianRandom',
'NoiseAdaGaussianRandom',
@@ -21,4 +22,5 @@ __all__ = ['NoiseGaussianRandom',
'RDPMonitor',
'ZCDPMonitor',
'DPOptimizerClassFactory',
'DPModel']
'DPModel',
'MembershipInference']

+ 22
- 3
mindarmour/diff_privacy/evaluation/attacker.py View File

@@ -21,6 +21,11 @@ from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import RandomizedSearchCV

from mindarmour.utils.logger import LogUtil

LOGGER = LogUtil.get_instance()
TAG = "Attacker"


def _attack_knn(features, labels, param_grid):
"""
@@ -114,17 +119,31 @@ def get_attack_model(features, labels, config):
features (numpy.ndarray): Loss and logits characteristics of each sample.
labels (numpy.ndarray): Labels of each sample whether belongs to training set.
config (dict): Config of attacker, with key in ["method", "params"].
The format is {"method": "knn", "params": {"n_neighbors": [3, 5, 7]}},
params of each method must within the range of changeable parameters.
Tips of params implement can be found in
"https://scikit-learn.org/0.16/modules/generated/sklearn.grid_search.GridSearchCV.html".

Returns:
sklearn.BaseEstimator, trained model specify by config["method"].

Examples:
>>> features = np.random.randn(10, 10)
>>> labels = np.random.randint(0, 2, 10)
>>> config = {"method": "knn", "params": {"n_neighbors": [3, 5, 7]}}
>>> attack_model = get_attack_model(features, labels, config)
"""
method = str.lower(config["method"])

if method == "knn":
return _attack_knn(features, labels, config["params"])
if method in ["lr", "logitic regression"]:
if method == "lr":
return _attack_lr(features, labels, config["params"])
if method == "mlp":
return _attack_mlpc(features, labels, config["params"])
if method in ["rf", "random forest"]:
if method == "rf":
return _attack_rf(features, labels, config["params"])
raise ValueError("Method {} is not support.".format(config["method"]))

msg = "Method {} is not supported.".format(config["method"])
LOGGER.error(TAG, msg)
raise ValueError(msg)

+ 107
- 22
mindarmour/diff_privacy/evaluation/membership_inference.py View File

@@ -19,10 +19,14 @@ import numpy as np

import mindspore as ms
from mindspore.train import Model
import mindspore.nn as nn
import mindspore.context as context
from mindspore.dataset.engine import Dataset
from mindspore import Tensor
from mindarmour.diff_privacy.evaluation.attacker import get_attack_model
from mindarmour.utils.logger import LogUtil

LOGGER = LogUtil.get_instance()
TAG = "MembershipInference"


def _eval_info(pred, truth, option):
"""
@@ -42,7 +46,9 @@ def _eval_info(pred, truth, option):
ValueError, value of parameter option must be in ["precision", "accuracy", "recall"].
"""
if pred.size == 0 or truth.size == 0:
raise ValueError("Size of pred or truth is 0.")
msg = "Size of pred or truth is 0."
LOGGER.error(TAG, msg)
raise ValueError(msg)

if option == "accuracy":
count = np.sum(pred == truth)
@@ -58,7 +64,25 @@ def _eval_info(pred, truth, option):
return -1
return count / np.sum(truth)

raise ValueError("The metric value {} is undefined.".format(option))
msg = "The metric value {} is undefined.".format(option)
LOGGER.error(TAG, msg)
raise ValueError(msg)


def _softmax_cross_entropy(logits, labels):
"""
Calculate the SoftmaxCrossEntropy result between logits and labels.

Args:
logits (numpy.ndarray): Numpy array of shape(N, C).
labels (numpy.ndarray): Numpy array of shape(N, )

Returns:
numpy.ndarray: Numpy array of shape(N, ), containing loss value for each vector in logits.
"""
labels = np.eye(logits.shape[1])[labels].astype(np.int32)
logits = np.exp(logits) / np.sum(np.exp(logits), axis=1, keepdims=True)
return -1*np.sum(labels*np.log(logits), axis=1)


class MembershipInference:
@@ -66,22 +90,23 @@ class MembershipInference:
Evaluation proposed by Shokri, Stronati, Song and Shmatikov is a grey-box attack.
The attack requires obtain loss or logits results of training samples.

References: Reza Shokri, Marco Stronati, Congzheng Song, Vitaly Shmatikov.
References: `Reza Shokri, Marco Stronati, Congzheng Song, Vitaly Shmatikov.
Membership Inference Attacks against Machine Learning Models. 2017.
arXiv:1610.05820v2 <https://arxiv.org/abs/1610.05820v2>`_
<https://arxiv.org/abs/1610.05820v2>`_

Args:
model (Model): Target model.

Examples:
>>> # ds_train, eval_train are non-overlapping datasets from training dataset.
>>> # eval_train, eval_test are non-overlapping datasets from test dataset.
>>> train_1, train_2 are non-overlapping datasets from training dataset of target model.
>>> test_1, test_2 are non-overlapping datasets from test dataset of target model.
>>> We use train_1, test_1 to train attack model, and use train_2, test_2 to evaluate attack model.
>>> model = Model(network=net, loss_fn=loss, optimizer=opt, metrics={'acc', 'loss'})
>>> inference_model = MembershipInference(model)
>>> config = [{"method": "KNN", "params": {"n_neighbors": [3, 5, 7]}}]
>>> inference_model.train(ds_train, ds_test, config)
>>> inference_model.train(train_1, test_1, config)
>>> metrics = ["precision", "recall", "accuracy"]
>>> result = inference_model.eval(eval_train, eval_test, metrics)
>>> result = inference_model.eval(train_2, test_2, metrics)

Raises:
TypeError: If type of model is not mindspore.train.Model.
@@ -89,8 +114,12 @@ class MembershipInference:

def __init__(self, model):
if not isinstance(model, Model):
raise TypeError("Type of model must be {}, but got {}.".format(type(Model), type(model)))
msg = "Type of parameter 'model' must be Model, but got {}.".format(type(model))
LOGGER.error(TAG, msg)
raise TypeError(msg)

self.model = model
self.method_list = ["knn", "lr", "mlp", "rf"]
self.attack_list = []

def train(self, dataset_train, dataset_test, attack_config):
@@ -101,11 +130,48 @@ class MembershipInference:
Args:
dataset_train (mindspore.dataset): The training dataset for the target model.
dataset_test (mindspore.dataset): The test set for the target model.
attack_config (list): Parameter setting for the attack model.
attack_config (list): Parameter setting for the attack model. The format is
[{"method": "knn", "params": {"n_neighbors": [3, 5, 7]}},
{"method": "lr", "params": {"C": np.logspace(-4, 2, 10)}}].
The support methods list is in self.method_list, and the params of each method
must within the range of changeable parameters. Tips of params implement
can be found in
"https://scikit-learn.org/0.16/modules/generated/sklearn.grid_search.GridSearchCV.html".

Raises:
ValueError: If the method in attack_config is not in ["LR", "KNN", "RF", "MLPC"].
KeyError: If each config in attack_config doesn't have keys {"method", "params"}
ValueError: If the method(case insensitive) in attack_config is not in ["lr", "knn", "rf", "mlp"].
"""
if not isinstance(dataset_train, Dataset):
msg = "Type of parameter 'dataset_train' must be Dataset, but got {}".format(type(dataset_train))
LOGGER.error(TAG, msg)
raise TypeError(msg)

if not isinstance(dataset_test, Dataset):
msg = "Type of parameter 'test_train' must be Dataset, but got {}".format(type(dataset_train))
LOGGER.error(TAG, msg)
raise TypeError(msg)

if not isinstance(attack_config, list):
msg = "Type of parameter 'attack_config' must be list, but got {}.".format(type(attack_config))
LOGGER.error(TAG, msg)
raise TypeError(msg)

for config in attack_config:
if not isinstance(config, dict):
msg = "Type of each config in 'attack_config' must be dict, but got {}.".format(type(config))
LOGGER.error(TAG, msg)
raise TypeError(msg)
if {"params", "method"} != set(config.keys()):
msg = "Each config in attack_config must have keys 'method' and 'params'," \
"but your key value is {}.".format(set(config.keys()))
LOGGER.error(TAG, msg)
raise KeyError(msg)
if str.lower(config["method"]) not in self.method_list:
msg = "Method {} is not support.".format(config["method"])
LOGGER.error(TAG, msg)
raise ValueError(msg)

features, labels = self._transform(dataset_train, dataset_test)
for config in attack_config:
self.attack_list.append(get_attack_model(features, labels, config))
@@ -124,6 +190,28 @@ class MembershipInference:
Returns:
list, Each element contains an evaluation indicator for the attack model.
"""
if not isinstance(dataset_train, Dataset):
msg = "Type of parameter 'dataset_train' must be Dataset, but got {}".format(type(dataset_train))
LOGGER.error(TAG, msg)
raise TypeError(msg)

if not isinstance(dataset_test, Dataset):
msg = "Type of parameter 'test_train' must be Dataset, but got {}".format(type(dataset_train))
LOGGER.error(TAG, msg)
raise TypeError(msg)

if not isinstance(metrics, (list, tuple)):
msg = "Type of parameter 'config' must be Union[list, tuple], but got {}.".format(type(metrics))
LOGGER.error(TAG, msg)
raise TypeError(msg)

metrics = set(metrics)
metrics_list = {"precision", "accuracy", "recall"}
if not metrics <= metrics_list:
msg = "Element in 'metrics' must be in {}, but got {}.".format(metrics_list, metrics)
LOGGER.error(TAG, msg)
raise ValueError(msg)

result = []
features, labels = self._transform(dataset_train, dataset_test)
for attacker in self.attack_list:
@@ -170,17 +258,12 @@ class MembershipInference:
N is the number of sample. C = 1 + dim(logits).
- numpy.ndarray, Labels for each sample, Shape is (N,).
"""
if context.get_context("device_target") != "Ascend":
raise RuntimeError("The target device must be Ascend, "
"but current is {}.".format(context.get_context("device_target")))
loss_logits = np.array([])
for batch in dataset_x.create_dict_iterator():
batch_data = Tensor(batch['image'], ms.float32)
batch_labels = Tensor(batch['label'], ms.int32)
batch_logits = self.model.predict(batch_data)
loss = nn.SoftmaxCrossEntropyWithLogits(sparse=True, is_grad=False, reduction=None)
batch_loss = loss(batch_logits, batch_labels).asnumpy()
batch_logits = batch_logits.asnumpy()
batch_labels = batch['label'].astype(np.int32)
batch_logits = self.model.predict(batch_data).asnumpy()
batch_loss = _softmax_cross_entropy(batch_logits, batch_labels)

batch_feature = np.hstack((batch_loss.reshape(-1, 1), batch_logits))
if loss_logits.size == 0:
@@ -193,5 +276,7 @@ class MembershipInference:
elif label == 0:
labels = np.zeros(len(loss_logits), np.int32)
else:
raise ValueError("The value of label must be 0 or 1, but got {}.".format(label))
msg = "The value of label must be 0 or 1, but got {}.".format(label)
LOGGER.error(TAG, msg)
raise ValueError(msg)
return loss_logits, labels

+ 77
- 38
mindarmour/fuzzing/fuzzing.py View File

@@ -22,7 +22,8 @@ from mindspore import Tensor

from mindarmour.fuzzing.model_coverage_metrics import ModelCoverageMetrics
from mindarmour.utils._check_param import check_model, check_numpy_param, \
check_param_multi_types, check_norm_level, check_param_in_range
check_param_multi_types, check_norm_level, check_param_in_range, \
check_param_type, check_int_positive
from mindarmour.fuzzing.image_transform import Contrast, Brightness, Blur, \
Noise, Translate, Scale, Shear, Rotate
from mindarmour.attacks import FastGradientSignMethod, \
@@ -93,7 +94,7 @@ class Fuzzer:
>>> {'method': 'Translate', 'params': {'x_bias': 0.1, 'y_bias': 0.2}},
>>> {'method': 'FGSM', 'params': {'eps': 0.1, 'alpha': 0.1}}]
>>> train_images = np.random.rand(32, 1, 32, 32).astype(np.float32)
>>> model_fuzz_test = Fuzzer(model, train_images, 1000, 10)
>>> model_fuzz_test = Fuzzer(model, train_images, 10, 1000)
>>> samples, labels, preds, strategies, report = model_fuzz_test.fuzzing(mutate_config, initial_seeds)
"""

@@ -101,8 +102,9 @@ class Fuzzer:
self._target_model = check_model('model', target_model, Model)
train_dataset = check_numpy_param('train_dataset', train_dataset)
self._coverage_metrics = ModelCoverageMetrics(target_model,
neuron_num,
segmented_num,
neuron_num, train_dataset)
train_dataset)
# Allowed mutate strategies so far.
self._strategies = {'Contrast': Contrast, 'Brightness': Brightness,
'Blur': Blur, 'Noise': Noise, 'Translate': Translate,
@@ -115,23 +117,21 @@ class Fuzzer:
'Noise']
self._attacks_list = ['FGSM', 'PGD', 'MDIIM']
self._attack_param_checklists = {
'FGSM': {'params': {'eps': {'dtype': [float, int], 'range': [0, 1]},
'alpha': {'dtype': [float, int],
'FGSM': {'params': {'eps': {'dtype': [float], 'range': [0, 1]},
'alpha': {'dtype': [float],
'range': [0, 1]},
'bounds': {'dtype': [list, tuple],
'range': None}}},
'PGD': {'params': {'eps': {'dtype': [float, int], 'range': [0, 1]},
'eps_iter': {'dtype': [float, int],
'range': [0, 1e5]},
'nb_iter': {'dtype': [float, int],
'bounds': {'dtype': [tuple]}}},
'PGD': {'params': {'eps': {'dtype': [float], 'range': [0, 1]},
'eps_iter': {'dtype': [float],
'range': [0, 1]},
'nb_iter': {'dtype': [int],
'range': [0, 1e5]},
'bounds': {'dtype': [list, tuple],
'range': None}}},
'bounds': {'dtype': [tuple]}}},
'MDIIM': {
'params': {'eps': {'dtype': [float, int], 'range': [0, 1]},
'norm_level': {'dtype': [str], 'range': None},
'prob': {'dtype': [float, int], 'range': [0, 1]},
'bounds': {'dtype': [list, tuple], 'range': None}}}}
'params': {'eps': {'dtype': [float], 'range': [0, 1]},
'norm_level': {'dtype': [str]},
'prob': {'dtype': [float], 'range': [0, 1]},
'bounds': {'dtype': [tuple]}}}}

def fuzzing(self, mutate_config, initial_seeds, coverage_metric='KMNC',
eval_metrics='auto', max_iters=10000, mutate_num_per_seed=20):
@@ -140,16 +140,29 @@ class Fuzzer:

Args:
mutate_config (list): Mutate configs. The format is
[{'method': 'Blur', 'params': {'auto_param': True}}, {'method': 'Contrast', 'params': {'factor': 2}}].
The support methods list is in `self._strategies`, and the params of each
method must within the range of changeable parameters.
initial_seeds (numpy.ndarray): Initial seeds used to generate
mutated samples.
coverage_metric (str): Model coverage metric of neural networks.
Default: 'KMNC'.
eval_metrics (Union[list, tuple, str]): Evaluation metrics. If the type is 'auto',
it will calculate all the metrics, else if the type is list or tuple, it will
calculate the metrics specified by user. Default: 'auto'.
[{'method': 'Blur', 'params': {'auto_param': True}},
{'method': 'Contrast', 'params': {'factor': 2}}]. The
supported methods list is in `self._strategies`, and the
params of each method must within the range of changeable parameters. 
Supported methods are grouped in three types:
Firstly, pixel value based transform methods include:
'Contrast', 'Brightness', 'Blur' and 'Noise'. Secondly, affine
transform methods include: 'Translate', 'Scale', 'Shear' and
'Rotate'. Thirdly, attack methods include: 'FGSM', 'PGD' and 'MDIIM'.
`mutate_config` must have method in the type of pixel value based
transform methods. The way of setting parameters for first and
second type methods can be seen in 'mindarmour/fuzzing/image_transform.py'.
For third type methods, you can refer to the corresponding class.
initial_seeds (list[list]): Initial seeds used to generate mutated
samples. The format of initial seeds is [[image_data, label],
[...], ...].
coverage_metric (str): Model coverage metric of neural networks. All
supported metrics are: 'KMNC', 'NBC', 'SNAC'. Default: 'KMNC'.
eval_metrics (Union[list, tuple, str]): Evaluation metrics. If the
type is 'auto', it will calculate all the metrics, else if the
type is list or tuple, it will calculate the metrics specified
by user. All supported evaluate methods are 'accuracy',
'attack_success_rate', 'kmnc', 'nbc', 'snac'. Default: 'auto'.
max_iters (int): Max number of select a seed to mutate.
Default: 10000.
mutate_num_per_seed (int): The number of mutate times for a seed.
@@ -173,16 +186,10 @@ class Fuzzer:
ValueError: If metric in list `eval_metrics` is not in ['accuracy', 'attack_success_rate',
'kmnc', 'nbc', 'snac'].
"""
eval_metrics_ = None
if isinstance(eval_metrics, (list, tuple)):
eval_metrics_ = []
avaliable_metrics = ['accuracy', 'attack_success_rate', 'kmnc', 'nbc', 'snac']
for elem in eval_metrics:
if not isinstance(elem, str):
msg = 'the type of metric in list `eval_metrics` must be str, but got {}.' \
.format(type(elem))
LOGGER.error(TAG, msg)
raise TypeError(msg)
if elem not in avaliable_metrics:
msg = 'metric in list `eval_metrics` must be in {}, but got {}.' \
.format(avaliable_metrics, elem)
@@ -203,7 +210,33 @@ class Fuzzer:
raise TypeError(msg)

# Check whether the mutate_config meet the specification.
mutate_config = check_param_type('mutate_config', mutate_config, list)
for config in mutate_config:
check_param_type("config['params']", config['params'], dict)
if set(config.keys()) != {'method', 'params'}:
msg = "Config must contain 'method' and 'params', but got {}." \
.format(set(config.keys()))
LOGGER.error(TAG, msg)
raise TypeError(msg)
if config['method'] not in self._strategies.keys():
msg = "Config methods must be in {}, but got {}." \
.format(self._strategies.keys(), config['method'])
LOGGER.error(TAG, msg)
raise TypeError(msg)
if coverage_metric not in ['KMNC', 'NBC', 'SNAC']:
msg = "coverage_metric must be in ['KMNC', 'NBC', 'SNAC'], but got {}." \
.format(coverage_metric)
LOGGER.error(TAG, msg)
raise ValueError(msg)
max_iters = check_int_positive('max_iters', max_iters)
mutate_num_per_seed = check_int_positive('mutate_num_per_seed', mutate_num_per_seed)
mutates = self._init_mutates(mutate_config)
initial_seeds = check_param_type('initial_seeds', initial_seeds, list)
for seed in initial_seeds:
check_param_type('seed', seed, list)
check_numpy_param('seed[0]', seed[0])
check_numpy_param('seed[1]', seed[1])
seed.append(0)
seed, initial_seeds = _select_next(initial_seeds)
fuzz_samples = []
gt_labels = []
@@ -248,7 +281,7 @@ class Fuzzer:
for index in range(len(samples)):
mutate = samples[:index + 1]
self._coverage_metrics.calculate_coverage(mutate.astype(np.float32))
if coverage_metric == "KMNC":
if coverage_metric == 'KMNC':
coverages.append(self._coverage_metrics.get_kmnc())
if coverage_metric == 'NBC':
coverages.append(self._coverage_metrics.get_nbc())
@@ -357,18 +390,24 @@ class Fuzzer:
dict, evaluate metrics include accuarcy, attack success rate
and neural coverage.
"""
gt_labels = np.asarray(gt_labels)
fuzz_preds = np.asarray(fuzz_preds)
temp = np.argmax(gt_labels, axis=1) == np.argmax(fuzz_preds, axis=1)
metrics_report = {}
if metrics == 'auto' or 'accuracy' in metrics:
gt_labels = np.asarray(gt_labels)
fuzz_preds = np.asarray(fuzz_preds)
acc = np.sum(temp) / np.size(temp)
if temp.any():
acc = np.sum(temp) / np.size(temp)
else:
acc = 0
metrics_report['Accuracy'] = acc

if metrics == 'auto' or 'attack_success_rate' in metrics:
cond = [elem in self._attacks_list for elem in fuzz_strategies]
temp = temp[cond]
attack_success_rate = 1 - np.sum(temp) / np.size(temp)
if temp.any():
attack_success_rate = 1 - np.sum(temp) / np.size(temp)
else:
attack_success_rate = None
metrics_report['Attack_success_rate'] = attack_success_rate

if metrics == 'auto' or 'kmnc' in metrics or 'nbc' in metrics or 'snac' in metrics:


+ 9
- 5
mindarmour/fuzzing/image_transform.py View File

@@ -350,8 +350,10 @@ class Translate(ImageTransform):
Translate an image.

Args:
x_bias ([int, float): X-direction translation, x=x+x_bias. Default: 0.
y_bias ([int, float): Y-direction translation, y=y+y_bias. Default: 0.
x_bias ([int, float): X-direction translation, x=x+x_bias*image_length.
Default: 0.
y_bias ([int, float): Y-direction translation, y=y+y_bias*image_wide.
Default: 0.
"""

def __init__(self, x_bias=0, y_bias=0):
@@ -363,8 +365,10 @@ class Translate(ImageTransform):
Set translate parameters.

Args:
x_bias ([float, int]): X-direction translation, x=x+x_bias. Default: 0.
y_bias ([float, int]): Y-direction translation, y=y+y_bias. Default: 0.
x_bias ([float, int]): X-direction translation, x=x+x_bias*image_length.
Default: 0.
y_bias ([float, int]): Y-direction translation, y=y+y_bias*image_wide.
Default: 0.
auto_param (bool): True if auto generate parameters. Default: False.
"""
self.auto_param = auto_param
@@ -579,7 +583,7 @@ class Rotate(ImageTransform):
"""
_, chw, normalized, gray3dim, image = self._check(image)
img = to_pil(image)
trans_image = img.rotate(self.angle, expand=True)
trans_image = img.rotate(self.angle, expand=False)
trans_image = self._original_format(trans_image, chw, normalized,
gray3dim)
return trans_image

+ 12
- 9
mindarmour/fuzzing/model_coverage_metrics.py View File

@@ -21,7 +21,7 @@ from mindspore import Tensor
from mindspore import Model

from mindarmour.utils._check_param import check_model, check_numpy_param, \
check_int_positive
check_int_positive, check_param_multi_types
from mindarmour.utils.logger import LogUtil

LOGGER = LogUtil.get_instance()
@@ -43,8 +43,8 @@ class ModelCoverageMetrics:

Args:
model (Model): The pre-trained model which waiting for testing.
segmented_num (int): The number of segmented sections of neurons' output intervals.
neuron_num (int): The number of testing neurons.
segmented_num (int): The number of segmented sections of neurons' output intervals.
train_dataset (numpy.ndarray): Training dataset used for determine
the neurons' output boundaries.

@@ -52,17 +52,18 @@ class ModelCoverageMetrics:
ValueError: If neuron_num is too big (for example, bigger than 1e+9).

Examples:
>>> train_images = np.random.random((10000, 128)).astype(np.float32)
>>> test_images = np.random.random((5000, 128)).astype(np.float32)
>>> net = LeNet5()
>>> train_images = np.random.random((10000, 1, 32, 32)).astype(np.float32)
>>> test_images = np.random.random((5000, 1, 32, 32)).astype(np.float32)
>>> model = Model(net)
>>> model_fuzz_test = ModelCoverageMetrics(model, 10000, 10, train_images)
>>> model_fuzz_test.test_adequacy_coverage_calculate(test_images)
>>> model_fuzz_test = ModelCoverageMetrics(model, 10, 1000, train_images)
>>> model_fuzz_test.calculate_coverage(test_images)
>>> print('KMNC of this test is : %s', model_fuzz_test.get_kmnc())
>>> print('NBC of this test is : %s', model_fuzz_test.get_nbc())
>>> print('SNAC of this test is : %s', model_fuzz_test.get_snac())
"""

def __init__(self, model, segmented_num, neuron_num, train_dataset):
def __init__(self, model, neuron_num, segmented_num, train_dataset):
self._model = check_model('model', model, Model)
self._segmented_num = check_int_positive('segmented_num', segmented_num)
self._neuron_num = check_int_positive('neuron_num', neuron_num)
@@ -139,8 +140,8 @@ class ModelCoverageMetrics:

Args:
dataset (numpy.ndarray): Data for fuzz test.
bias_coefficient (float): The coefficient used for changing the
neurons' output boundaries. Default: 0.
bias_coefficient (Union[int, float]): The coefficient used
for changing the neurons' output boundaries. Default: 0.
batch_size (int): The number of samples in a predict batch.
Default: 32.

@@ -148,8 +149,10 @@ class ModelCoverageMetrics:
>>> model_fuzz_test = ModelCoverageMetrics(model, 10000, 10, train_images)
>>> model_fuzz_test.calculate_coverage(test_images)
"""

dataset = check_numpy_param('dataset', dataset)
batch_size = check_int_positive('batch_size', batch_size)
bias_coefficient = check_param_multi_types('bias_coefficient', bias_coefficient, [int, float])
self._lower_bounds -= bias_coefficient*self._var
self._upper_bounds += bias_coefficient*self._var
intervals = (self._upper_bounds - self._lower_bounds) / self._segmented_num


+ 5
- 1
mindarmour/utils/logger.py View File

@@ -78,7 +78,11 @@ class LogUtil:
def set_level(self, level):
"""
Set the logging level of this logger, level must be an integer or a
string.
string. Supported levels are 'NOTSET'(integer: 0), 'ERROR'(integer: 1-40),
'WARNING'('WARN', integer: 1-30), 'INFO'(integer: 1-20) and 'DEBUG'(integer: 1-10).
For example, if logger.set_level('WARNING') or logger.set_level(21), then
logger.warn() and logger.error() in scripts would be printed while running,
while logger.info() or logger.debug() would not be printed.

Args:
level (Union[int, str]): Level of logger.


+ 1
- 1
mindarmour/utils/util.py View File

@@ -98,7 +98,7 @@ class GradWrapWithLoss(Cell):

Examples:
>>> data = Tensor(np.ones([1, 1, 32, 32]).astype(np.float32)*0.01)
>>> label = Tensor(np.ones([1, 10]).astype(np.float32))
>>> labels = Tensor(np.ones([1, 10]).astype(np.float32))
>>> net = NET()
>>> loss_fn = nn.SoftmaxCrossEntropyWithLogits()
>>> loss_net = WithLossCell(net, loss_fn)


+ 2
- 2
tests/ut/python/fuzzing/test_coverage_metrics.py View File

@@ -71,7 +71,7 @@ def test_lenet_mnist_coverage_cpu():

# initialize fuzz test with training dataset
training_data = (np.random.random((10000, 10))*20).astype(np.float32)
model_fuzz_test = ModelCoverageMetrics(model, 10000, 10, training_data)
model_fuzz_test = ModelCoverageMetrics(model, 10, 1000, training_data)

# fuzz test with original test data
# get test data
@@ -105,7 +105,7 @@ def test_lenet_mnist_coverage_ascend():

# initialize fuzz test with training dataset
training_data = (np.random.random((10000, 10))*20).astype(np.float32)
model_fuzz_test = ModelCoverageMetrics(model, 10000, 10, training_data)
model_fuzz_test = ModelCoverageMetrics(model, 10, 1000, training_data)

# fuzz test with original test data
# get test data


+ 4
- 4
tests/ut/python/fuzzing/test_fuzzer.py View File

@@ -102,7 +102,7 @@ def test_fuzzing_ascend():
]
# initialize fuzz test with training dataset
train_images = np.random.rand(32, 1, 32, 32).astype(np.float32)
model_coverage_test = ModelCoverageMetrics(model, 1000, 10, train_images)
model_coverage_test = ModelCoverageMetrics(model, 10, 1000, train_images)

# fuzz test with original test data
# get test data
@@ -113,7 +113,7 @@ def test_fuzzing_ascend():
initial_seeds = []
# make initial seeds
for img, label in zip(test_images, test_labels):
initial_seeds.append([img, label, 0])
initial_seeds.append([img, label])

initial_seeds = initial_seeds[:100]
model_coverage_test.calculate_coverage(
@@ -148,7 +148,7 @@ def test_fuzzing_cpu():
]
# initialize fuzz test with training dataset
train_images = np.random.rand(32, 1, 32, 32).astype(np.float32)
model_coverage_test = ModelCoverageMetrics(model, 1000, 10, train_images)
model_coverage_test = ModelCoverageMetrics(model, 10, 1000, train_images)

# fuzz test with original test data
# get test data
@@ -159,7 +159,7 @@ def test_fuzzing_cpu():
initial_seeds = []
# make initial seeds
for img, label in zip(test_images, test_labels):
initial_seeds.append([img, label, 0])
initial_seeds.append([img, label])

initial_seeds = initial_seeds[:100]
model_coverage_test.calculate_coverage(


Loading…
Cancel
Save