@@ -86,9 +86,7 @@ def test_salt_and_pepper_attack_on_mnist(): | |||||
# attacking | # attacking | ||||
is_target = False | is_target = False | ||||
attack = SaltAndPepperNoiseAttack(model=model, | |||||
is_targeted=is_target, | |||||
sparse=True) | |||||
attack = SaltAndPepperNoiseAttack(model=model, is_targeted=is_target, sparse=True) | |||||
if is_target: | if is_target: | ||||
targeted_labels = np.random.randint(0, 10, size=len(true_labels)) | targeted_labels = np.random.randint(0, 10, size=len(true_labels)) | ||||
for i, true_l in enumerate(true_labels): | for i, true_l in enumerate(true_labels): | ||||
@@ -97,8 +95,7 @@ def test_salt_and_pepper_attack_on_mnist(): | |||||
else: | else: | ||||
targeted_labels = true_labels | targeted_labels = true_labels | ||||
LOGGER.debug(TAG, 'input shape is: {}'.format(np.concatenate(test_images).shape)) | LOGGER.debug(TAG, 'input shape is: {}'.format(np.concatenate(test_images).shape)) | ||||
success_list, adv_data, query_list = attack.generate( | |||||
np.concatenate(test_images), targeted_labels) | |||||
success_list, adv_data, query_list = attack.generate(np.concatenate(test_images), targeted_labels) | |||||
success_list = np.arange(success_list.shape[0])[success_list] | success_list = np.arange(success_list.shape[0])[success_list] | ||||
LOGGER.info(TAG, 'success_list: %s', success_list) | LOGGER.info(TAG, 'success_list: %s', success_list) | ||||
LOGGER.info(TAG, 'average of query times is : %s', np.mean(query_list)) | LOGGER.info(TAG, 'average of query times is : %s', np.mean(query_list)) | ||||
@@ -110,21 +107,16 @@ def test_salt_and_pepper_attack_on_mnist(): | |||||
adv_preds.extend(pred_logits_adv) | adv_preds.extend(pred_logits_adv) | ||||
adv_preds = np.array(adv_preds) | adv_preds = np.array(adv_preds) | ||||
accuracy_adv = np.mean(np.equal(np.max(adv_preds, axis=1), true_labels)) | accuracy_adv = np.mean(np.equal(np.max(adv_preds, axis=1), true_labels)) | ||||
LOGGER.info(TAG, "prediction accuracy after attacking is : %g", | |||||
accuracy_adv) | |||||
LOGGER.info(TAG, "prediction accuracy after attacking is : %g", accuracy_adv) | |||||
test_labels_onehot = np.eye(10)[true_labels] | test_labels_onehot = np.eye(10)[true_labels] | ||||
attack_evaluate = AttackEvaluate(np.concatenate(test_images), | attack_evaluate = AttackEvaluate(np.concatenate(test_images), | ||||
test_labels_onehot, adv_data, | test_labels_onehot, adv_data, | ||||
adv_preds, targeted=is_target, | adv_preds, targeted=is_target, | ||||
target_label=targeted_labels) | target_label=targeted_labels) | ||||
LOGGER.info(TAG, 'mis-classification rate of adversaries is : %s', | |||||
attack_evaluate.mis_classification_rate()) | |||||
LOGGER.info(TAG, 'The average confidence of adversarial class is : %s', | |||||
attack_evaluate.avg_conf_adv_class()) | |||||
LOGGER.info(TAG, 'The average confidence of true class is : %s', | |||||
attack_evaluate.avg_conf_true_class()) | |||||
LOGGER.info(TAG, 'The average distance (l0, l2, linf) between original ' | |||||
'samples and adversarial samples are: %s', | |||||
LOGGER.info(TAG, 'mis-classification rate of adversaries is : %s', attack_evaluate.mis_classification_rate()) | |||||
LOGGER.info(TAG, 'The average confidence of adversarial class is : %s', attack_evaluate.avg_conf_adv_class()) | |||||
LOGGER.info(TAG, 'The average confidence of true class is : %s', attack_evaluate.avg_conf_true_class()) | |||||
LOGGER.info(TAG, 'The average distance (l0, l2, linf) between original samples and adversarial samples are: %s', | |||||
attack_evaluate.avg_lp_distance()) | attack_evaluate.avg_lp_distance()) | ||||
@@ -15,12 +15,10 @@ | |||||
SaltAndPepperNoise-Attack. | SaltAndPepperNoise-Attack. | ||||
""" | """ | ||||
import time | import time | ||||
import numpy as np | import numpy as np | ||||
from mindarmour.utils._check_param import check_model, check_pair_numpy_param, \ | from mindarmour.utils._check_param import check_model, check_pair_numpy_param, \ | ||||
check_param_type, check_int_positive, check_param_multi_types | check_param_type, check_int_positive, check_param_multi_types | ||||
from mindarmour.utils._check_param import normalize_value | |||||
from mindarmour.utils.logger import LogUtil | from mindarmour.utils.logger import LogUtil | ||||
from ..attack import Attack | from ..attack import Attack | ||||
from .black_model import BlackModel | from .black_model import BlackModel | ||||
@@ -31,26 +29,21 @@ TAG = 'SaltAndPepperNoise-Attack' | |||||
class SaltAndPepperNoiseAttack(Attack): | class SaltAndPepperNoiseAttack(Attack): | ||||
""" | """ | ||||
Increases the amount of salt and pepper noise to generate adversarial | |||||
samples. | |||||
Increases the amount of salt and pepper noise to generate adversarial samples. | |||||
Args: | Args: | ||||
model (BlackModel): Target model. | model (BlackModel): Target model. | ||||
bounds (tuple): Upper and lower bounds of data. In form of (clip_min, | |||||
clip_max). Default: (0.0, 1.0) | |||||
max_iter (int): Max iteration to generate an adversarial example. | |||||
Default: 100 | |||||
is_targeted (bool): If True, targeted attack. If False, untargeted | |||||
attack. Default: False. | |||||
sparse (bool): If True, input labels are sparse-encoded. If False, | |||||
input labels are one-hot-encoded. Default: True. | |||||
bounds (tuple): Upper and lower bounds of data. In form of (clip_min, clip_max). Default: (0.0, 1.0) | |||||
max_iter (int): Max iteration to generate an adversarial example. Default: 100 | |||||
is_targeted (bool): If True, targeted attack. If False, untargeted attack. Default: False. | |||||
sparse (bool): If True, input labels are sparse-encoded. If False, input labels are one-hot-encoded. | |||||
Default: True. | |||||
Examples: | Examples: | ||||
>>> attack = SaltAndPepperNoiseAttack(model) | >>> attack = SaltAndPepperNoiseAttack(model) | ||||
""" | """ | ||||
def __init__(self, model, bounds=(0.0, 1.0), max_iter=100, | |||||
is_targeted=False, sparse=True): | |||||
def __init__(self, model, bounds=(0.0, 1.0), max_iter=100, is_targeted=False, sparse=True): | |||||
super(SaltAndPepperNoiseAttack, self).__init__() | super(SaltAndPepperNoiseAttack, self).__init__() | ||||
self._model = check_model('model', model, BlackModel) | self._model = check_model('model', model, BlackModel) | ||||
self._bounds = check_param_multi_types('bounds', bounds, [tuple, list]) | self._bounds = check_param_multi_types('bounds', bounds, [tuple, list]) | ||||
@@ -76,12 +69,9 @@ class SaltAndPepperNoiseAttack(Attack): | |||||
- numpy.ndarray, query times for each sample. | - numpy.ndarray, query times for each sample. | ||||
Examples: | Examples: | ||||
>>> adv_list = attack.generate(([[0.1, 0.2, 0.6], | |||||
>>> [0.3, 0, 0.4]], | |||||
>>> [1, 2]) | |||||
>>> adv_list = attack.generate(([[0.1, 0.2, 0.6], [0.3, 0, 0.4]], [1, 2]) | |||||
""" | """ | ||||
arr_x, arr_y = check_pair_numpy_param('inputs', inputs, 'labels', | |||||
labels) | |||||
arr_x, arr_y = check_pair_numpy_param('inputs', inputs, 'labels', labels) | |||||
if not self._sparse: | if not self._sparse: | ||||
arr_y = np.argmax(arr_y, axis=1) | arr_y = np.argmax(arr_y, axis=1) | ||||
@@ -94,9 +84,8 @@ class SaltAndPepperNoiseAttack(Attack): | |||||
is_adv_list.append(is_adv) | is_adv_list.append(is_adv) | ||||
adv_list.append(perturbed) | adv_list.append(perturbed) | ||||
query_times_each_adv.append(query_times) | query_times_each_adv.append(query_times) | ||||
LOGGER.info(TAG, 'Finished one sample, adversarial is {}, ' | |||||
'cost time {:.2}s' | |||||
.format(is_adv, time.time() - start_t)) | |||||
LOGGER.info(TAG, 'Finished one sample, adversarial is {}, cost time {:.2}s'.format(is_adv, | |||||
time.time() - start_t)) | |||||
is_adv_list = np.array(is_adv_list) | is_adv_list = np.array(is_adv_list) | ||||
adv_list = np.array(adv_list) | adv_list = np.array(adv_list) | ||||
query_times_each_adv = np.array(query_times_each_adv) | query_times_each_adv = np.array(query_times_each_adv) | ||||
@@ -104,14 +93,12 @@ class SaltAndPepperNoiseAttack(Attack): | |||||
def _generate_one(self, one_input, label, epsilons=10): | def _generate_one(self, one_input, label, epsilons=10): | ||||
""" | """ | ||||
Increases the amount of salt and pepper noise to generate adversarial | |||||
samples. | |||||
Increases the amount of salt and pepper noise to generate adversarial samples. | |||||
Args: | Args: | ||||
one_input (numpy.ndarray): The original, unperturbed input. | one_input (numpy.ndarray): The original, unperturbed input. | ||||
label (numpy.ndarray): The target label. | label (numpy.ndarray): The target label. | ||||
epsilons (int) : Number of steps to try probability between 0 | |||||
and 1. Default: 10 | |||||
epsilons (int) : Number of steps to try probability between 0 and 1. Default: 10 | |||||
Returns: | Returns: | ||||
- numpy.ndarray, bool values for result. | - numpy.ndarray, bool values for result. | ||||
@@ -128,9 +115,7 @@ class SaltAndPepperNoiseAttack(Attack): | |||||
high_ = 1.0 | high_ = 1.0 | ||||
query_count = 0 | query_count = 0 | ||||
input_shape = one_input.shape | input_shape = one_input.shape | ||||
input_dtype = one_input.dtype | |||||
one_input = one_input.reshape(-1) | one_input = one_input.reshape(-1) | ||||
depth = np.abs(np.subtract(self._bounds[0], self._bounds[1])) | |||||
best_adv = np.copy(one_input) | best_adv = np.copy(one_input) | ||||
best_eps = high_ | best_eps = high_ | ||||
find_adv = False | find_adv = False | ||||
@@ -142,15 +127,11 @@ class SaltAndPepperNoiseAttack(Attack): | |||||
noise = np.random.uniform(low=low_, high=high_, size=one_input.size) | noise = np.random.uniform(low=low_, high=high_, size=one_input.size) | ||||
eps = (min_eps + max_eps) / 2 | eps = (min_eps + max_eps) / 2 | ||||
# add salt | # add salt | ||||
adv[noise < eps] = -depth | |||||
adv[noise < eps] = self._bounds[0] | |||||
# add pepper | # add pepper | ||||
adv[noise >= (high_ - eps)] = depth | |||||
# normalized sample | |||||
adv = normalize_value(np.expand_dims(adv, axis=0), 'l2').astype(input_dtype) | |||||
adv[noise >= (high_ - eps)] = self._bounds[1] | |||||
query_count += 1 | query_count += 1 | ||||
ite_bool = self._model.is_adversarial(adv.reshape(input_shape), | |||||
label, | |||||
is_targeted=self._is_targeted) | |||||
ite_bool = self._model.is_adversarial(adv.reshape(input_shape), label, is_targeted=self._is_targeted) | |||||
if ite_bool: | if ite_bool: | ||||
find_adv = True | find_adv = True | ||||
if best_eps > eps: | if best_eps > eps: | ||||
@@ -14,22 +14,22 @@ | |||||
""" | """ | ||||
SaltAndPepper Attack Test | SaltAndPepper Attack Test | ||||
""" | """ | ||||
import os | |||||
import numpy as np | import numpy as np | ||||
import pytest | import pytest | ||||
import mindspore.ops.operations as M | |||||
from mindspore import Tensor | from mindspore import Tensor | ||||
from mindspore.nn import Cell | |||||
from mindspore.train.serialization import load_checkpoint, load_param_into_net | |||||
from mindspore import context | from mindspore import context | ||||
from mindarmour import BlackModel | from mindarmour import BlackModel | ||||
from mindarmour.adv_robustness.attacks import SaltAndPepperNoiseAttack | from mindarmour.adv_robustness.attacks import SaltAndPepperNoiseAttack | ||||
from tests.ut.python.utils.mock_net import Net | |||||
context.set_context(mode=context.GRAPH_MODE) | context.set_context(mode=context.GRAPH_MODE) | ||||
context.set_context(device_target="Ascend") | context.set_context(device_target="Ascend") | ||||
# for user | |||||
class ModelToBeAttacked(BlackModel): | class ModelToBeAttacked(BlackModel): | ||||
"""model to be attack""" | """model to be attack""" | ||||
@@ -43,33 +43,6 @@ class ModelToBeAttacked(BlackModel): | |||||
return result.asnumpy() | return result.asnumpy() | ||||
# for user | |||||
class SimpleNet(Cell): | |||||
""" | |||||
Construct the network of target model. | |||||
Examples: | |||||
>>> net = SimpleNet() | |||||
""" | |||||
def __init__(self): | |||||
""" | |||||
Introduce the layers used for network construction. | |||||
""" | |||||
super(SimpleNet, self).__init__() | |||||
self._softmax = M.Softmax() | |||||
def construct(self, inputs): | |||||
""" | |||||
Construct network. | |||||
Args: | |||||
inputs (Tensor): Input data. | |||||
""" | |||||
out = self._softmax(inputs) | |||||
return out | |||||
@pytest.mark.level0 | @pytest.mark.level0 | ||||
@pytest.mark.platform_arm_ascend_training | @pytest.mark.platform_arm_ascend_training | ||||
@pytest.mark.platform_x86_ascend_training | @pytest.mark.platform_x86_ascend_training | ||||
@@ -79,44 +52,21 @@ def test_salt_and_pepper_attack_method(): | |||||
""" | """ | ||||
Salt and pepper attack method unit test. | Salt and pepper attack method unit test. | ||||
""" | """ | ||||
batch_size = 6 | |||||
np.random.seed(123) | np.random.seed(123) | ||||
net = SimpleNet() | |||||
inputs = np.random.rand(batch_size, 10) | |||||
# upload trained network | |||||
current_dir = os.path.dirname(os.path.abspath(__file__)) | |||||
ckpt_path = os.path.join(current_dir, | |||||
'../../../dataset/trained_ckpt_file/checkpoint_lenet-10_1875.ckpt') | |||||
net = Net() | |||||
load_dict = load_checkpoint(ckpt_path) | |||||
load_param_into_net(net, load_dict) | |||||
# get one mnist image | |||||
inputs = np.load(os.path.join(current_dir, '../../../dataset/test_images.npy'))[:3] | |||||
labels = np.load(os.path.join(current_dir, '../../../dataset/test_labels.npy'))[:3] | |||||
model = ModelToBeAttacked(net) | model = ModelToBeAttacked(net) | ||||
labels = np.random.randint(low=0, high=10, size=batch_size) | |||||
labels = np.eye(10)[labels] | |||||
labels = labels.astype(np.float32) | |||||
attack = SaltAndPepperNoiseAttack(model, sparse=False) | |||||
attack = SaltAndPepperNoiseAttack(model, sparse=True) | |||||
_, adv_data, _ = attack.generate(inputs, labels) | _, adv_data, _ = attack.generate(inputs, labels) | ||||
assert np.any(adv_data[0] != inputs[0]), 'Salt and pepper attack method: ' \ | |||||
'generate value must not be equal' \ | |||||
' to original value.' | |||||
@pytest.mark.level0 | |||||
@pytest.mark.platform_arm_ascend_training | |||||
@pytest.mark.platform_x86_ascend_training | |||||
@pytest.mark.env_card | |||||
@pytest.mark.component_mindarmour | |||||
def test_salt_and_pepper_attack_in_batch(): | |||||
""" | |||||
Salt and pepper attack method unit test in batch. | |||||
""" | |||||
batch_size = 32 | |||||
np.random.seed(123) | |||||
net = SimpleNet() | |||||
inputs = np.random.rand(batch_size*2, 10) | |||||
model = ModelToBeAttacked(net) | |||||
labels = np.random.randint(low=0, high=10, size=batch_size*2) | |||||
labels = np.eye(10)[labels] | |||||
labels = labels.astype(np.float32) | |||||
attack = SaltAndPepperNoiseAttack(model, sparse=False) | |||||
adv_data = attack.batch_generate(inputs, labels, batch_size=32) | |||||
assert np.any(adv_data[0] != inputs[0]), 'Salt and pepper attack method: ' \ | |||||
'generate value must not be equal' \ | |||||
assert np.any(adv_data[0] != inputs[0]), 'Salt and pepper attack method: generate value must not be equal' \ | |||||
' to original value.' | ' to original value.' |