@@ -86,9 +86,7 @@ def test_salt_and_pepper_attack_on_mnist(): | |||
# attacking | |||
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: | |||
targeted_labels = np.random.randint(0, 10, size=len(true_labels)) | |||
for i, true_l in enumerate(true_labels): | |||
@@ -97,8 +95,7 @@ def test_salt_and_pepper_attack_on_mnist(): | |||
else: | |||
targeted_labels = true_labels | |||
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] | |||
LOGGER.info(TAG, 'success_list: %s', success_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 = np.array(adv_preds) | |||
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] | |||
attack_evaluate = AttackEvaluate(np.concatenate(test_images), | |||
test_labels_onehot, adv_data, | |||
adv_preds, targeted=is_target, | |||
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()) | |||
@@ -15,12 +15,10 @@ | |||
SaltAndPepperNoise-Attack. | |||
""" | |||
import time | |||
import numpy as np | |||
from mindarmour.utils._check_param import check_model, check_pair_numpy_param, \ | |||
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 ..attack import Attack | |||
from .black_model import BlackModel | |||
@@ -31,26 +29,21 @@ TAG = 'SaltAndPepperNoise-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: | |||
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: | |||
>>> 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__() | |||
self._model = check_model('model', model, BlackModel) | |||
self._bounds = check_param_multi_types('bounds', bounds, [tuple, list]) | |||
@@ -76,12 +69,9 @@ class SaltAndPepperNoiseAttack(Attack): | |||
- numpy.ndarray, query times for each sample. | |||
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: | |||
arr_y = np.argmax(arr_y, axis=1) | |||
@@ -94,9 +84,8 @@ class SaltAndPepperNoiseAttack(Attack): | |||
is_adv_list.append(is_adv) | |||
adv_list.append(perturbed) | |||
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) | |||
adv_list = np.array(adv_list) | |||
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): | |||
""" | |||
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: | |||
one_input (numpy.ndarray): The original, unperturbed input. | |||
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: | |||
- numpy.ndarray, bool values for result. | |||
@@ -128,9 +115,7 @@ class SaltAndPepperNoiseAttack(Attack): | |||
high_ = 1.0 | |||
query_count = 0 | |||
input_shape = one_input.shape | |||
input_dtype = one_input.dtype | |||
one_input = one_input.reshape(-1) | |||
depth = np.abs(np.subtract(self._bounds[0], self._bounds[1])) | |||
best_adv = np.copy(one_input) | |||
best_eps = high_ | |||
find_adv = False | |||
@@ -142,15 +127,11 @@ class SaltAndPepperNoiseAttack(Attack): | |||
noise = np.random.uniform(low=low_, high=high_, size=one_input.size) | |||
eps = (min_eps + max_eps) / 2 | |||
# add salt | |||
adv[noise < eps] = -depth | |||
adv[noise < eps] = self._bounds[0] | |||
# 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 | |||
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: | |||
find_adv = True | |||
if best_eps > eps: | |||
@@ -14,22 +14,22 @@ | |||
""" | |||
SaltAndPepper Attack Test | |||
""" | |||
import os | |||
import numpy as np | |||
import pytest | |||
import mindspore.ops.operations as M | |||
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 mindarmour import BlackModel | |||
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(device_target="Ascend") | |||
# for user | |||
class ModelToBeAttacked(BlackModel): | |||
"""model to be attack""" | |||
@@ -43,33 +43,6 @@ class ModelToBeAttacked(BlackModel): | |||
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.platform_arm_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. | |||
""" | |||
batch_size = 6 | |||
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) | |||
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) | |||
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.' |