def __init__(self, network, eps=0.07, alpha=None, bounds=None, loss_fn=None): super(GradientMethod, self).__init__() self._network = check_model('network', network, Cell) self._eps = check_value_positive('eps', eps) self._dtype = None if bounds is not None: self._bounds = check_param_multi_types('bounds', bounds, [list, tuple]) for b in self._bounds: _ = check_param_multi_types('bound', b, [int, float]) else: self._bounds = bounds if alpha is not None: self._alpha = check_value_positive('alpha', alpha) else: self._alpha = alpha if loss_fn is None: loss_fn = SoftmaxCrossEntropyWithLogits(is_grad=False, sparse=False) with_loss_cell = WithLossCell(self._network, loss_fn) self._grad_all = GradWrapWithLoss(with_loss_cell) self._grad_all.set_train()
class IterativeGradientMethod(Attack): """ Abstract base class for all iterative gradient based attacks. Args: network (Cell): Target model. eps (float): Proportion of adversarial perturbation generated by the attack to data range. Default: 0.3. eps_iter (float): Proportion of single-step adversarial perturbation generated by the attack to data range. Default: 0.1. bounds (tuple): Upper and lower bounds of data, indicating the data range. In form of (clip_min, clip_max). Default: (0.0, 1.0). nb_iter (int): Number of iteration. Default: 5. loss_fn (Loss): Loss function for optimization. If None, the input network \ is already equipped with loss function. Default: None. """ def __init__(self, network, eps=0.3, eps_iter=0.1, bounds=(0.0, 1.0), nb_iter=5, loss_fn=None): super(IterativeGradientMethod, self).__init__() self._network = check_model('network', network, Cell) self._eps = check_value_positive('eps', eps) self._eps_iter = check_value_positive('eps_iter', eps_iter) self._nb_iter = check_int_positive('nb_iter', nb_iter) self._bounds = None if bounds is not None: self._bounds = check_param_multi_types('bounds', bounds, [list, tuple]) for b in self._bounds: _ = check_param_multi_types('bound', b, [int, float]) if loss_fn is None: self._loss_grad = network else: self._loss_grad = GradWrapWithLoss(WithLossCell(self._network, loss_fn)) self._loss_grad.set_train() @abstractmethod def generate(self, inputs, labels): """ Generate adversarial examples based on input samples and original/target labels. Args: inputs (Union[numpy.ndarray, tuple]): Benign input samples used as references to create adversarial examples. labels (Union[numpy.ndarray, tuple]): Original/target labels. \ For each input if it has more than one label, it is wrapped in a tuple. Raises: NotImplementedError: This function is not available in IterativeGradientMethod. Examples: >>> adv_x = attack.generate([[0.1, 0.9, 0.6], >>> [0.3, 0, 0.3]], >>> [[0, , 1, 0, 0, 0, 0, 0, 0, 0], >>> [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0]]) """ msg = 'The function generate() is an abstract method in class ' \ '`IterativeGradientMethod`, and should be implemented ' \ 'in child class.' LOGGER.error(TAG, msg) raise NotImplementedError(msg)
def __init__(self, network, eps=1e-5, bounds=(0.0, 1.0), is_targeted=True, nb_iter=150, search_iters=30, loss_fn=None, sparse=False): super(LBFGS, self).__init__() self._network = check_model('network', network, Cell) self._eps = check_value_positive('eps', eps) self._is_targeted = check_param_type('is_targeted', is_targeted, bool) self._nb_iter = check_int_positive('nb_iter', nb_iter) self._search_iters = check_int_positive('search_iters', search_iters) if loss_fn is None: loss_fn = SoftmaxCrossEntropyWithLogits(is_grad=False, sparse=False) with_loss_cell = WithLossCell(self._network, loss_fn) self._grad_all = GradWrapWithLoss(with_loss_cell) self._dtype = None self._bounds = check_param_multi_types('bounds', bounds, [list, tuple]) self._sparse = check_param_type('sparse', sparse, bool) for b in self._bounds: _ = check_param_multi_types('bound', b, [int, float]) box_max, box_min = bounds if box_max < box_min: self._box_min = box_max self._box_max = box_min else: self._box_min = box_min self._box_max = box_max
def __init__(self, network, eps=0.3, eps_iter=0.1, bounds=(0.0, 1.0), nb_iter=5, loss_fn=None): super(IterativeGradientMethod, self).__init__() self._network = check_model('network', network, Cell) self._eps = check_value_positive('eps', eps) self._eps_iter = check_value_positive('eps_iter', eps_iter) self._nb_iter = check_int_positive('nb_iter', nb_iter) self._bounds = None if bounds is not None: self._bounds = check_param_multi_types('bounds', bounds, [list, tuple]) for b in self._bounds: _ = check_param_multi_types('bound', b, [int, float]) if loss_fn is None: self._loss_grad = network else: self._loss_grad = GradWrapWithLoss(WithLossCell(self._network, loss_fn)) self._loss_grad.set_train()
def generate(self, target_features, iters=100): """ Reconstruct images based on target_features. Args: target_features (numpy.ndarray): Deep representations of original images. The first dimension of target_features should be img_num. It should be noted that the shape of target_features should be (1, dim2, dim3, ...) if img_num equals 1. iters (int): iteration times of inversion attack, which should be positive integers. Default: 100. Returns: numpy.ndarray, reconstructed images, which are expected to be similar to original images. Raises: TypeError: If the type of target_features is not numpy.ndarray. ValueError: If any value of iters is not positive int.Z Examples: >>> net = LeNet5() >>> inversion_attack = ImageInversionAttack(net, input_shape=(1, 32, 32), input_bound=(0, 1), >>> loss_weights=[1, 0.2, 5]) >>> features = np.random.random((2, 10)).astype(np.float32) >>> images = inversion_attack.generate(features, iters=10) >>> print(images.shape) (2, 1, 32, 32) """ target_features = check_numpy_param('target_features', target_features) iters = check_int_positive('iters', iters) # shape checking img_num = target_features.shape[0] test_input = np.random.random((img_num, ) + self._input_shape).astype( np.float32) test_out = self._network(Tensor(test_input)).asnumpy() if test_out.shape != target_features.shape: msg = "The shape of target_features ({}) is not in accordance with the shape" \ " of network output({})".format(target_features.shape, test_out.shape) raise ValueError(msg) loss_net = self._loss loss_grad = GradWrapWithLoss(loss_net) inversion_images = [] for i in range(img_num): target_feature_n = target_features[i] inversion_image_n = np.random.random( (1, ) + self._input_shape).astype(np.float32) * 0.05 for s in range(iters): x_grad = loss_grad(Tensor(inversion_image_n), Tensor(target_feature_n)).asnumpy() x_grad_sign = np.sign(x_grad) inversion_image_n -= x_grad_sign * 0.01 inversion_image_n = np.clip(inversion_image_n, self._input_bound[0], self._input_bound[1]) current_loss = loss_net(Tensor(inversion_image_n), Tensor(target_feature_n)) LOGGER.info( TAG, 'iteration step: {}, loss is {}'.format(s, current_loss)) inversion_images.append(inversion_image_n) return np.concatenate(np.array(inversion_images))
class GradientMethod(Attack): """ Abstract base class for all single-step gradient-based attacks. Args: network (Cell): Target model. eps (float): Proportion of single-step adversarial perturbation generated by the attack to data range. Default: 0.07. alpha (float): Proportion of single-step random perturbation to data range. Default: None. bounds (tuple): Upper and lower bounds of data, indicating the data range. In form of (clip_min, clip_max). Default: None. loss_fn (Loss): Loss function for optimization. Default: None. Examples: >>> inputs = np.array([[0.1, 0.2, 0.6], [0.3, 0, 0.4]]) >>> labels = np.array([[0, 1, 0, 0, 0], [0, 0, 1, 0, 0]]) >>> attack = FastGradientMethod(network) >>> adv_x = attack.generate(inputs, labels) """ def __init__(self, network, eps=0.07, alpha=None, bounds=None, loss_fn=None): super(GradientMethod, self).__init__() self._network = check_model('network', network, Cell) self._eps = check_value_positive('eps', eps) self._dtype = None if bounds is not None: self._bounds = check_param_multi_types('bounds', bounds, [list, tuple]) for b in self._bounds: _ = check_param_multi_types('bound', b, [int, float]) else: self._bounds = bounds if alpha is not None: self._alpha = check_value_positive('alpha', alpha) else: self._alpha = alpha if loss_fn is None: loss_fn = SoftmaxCrossEntropyWithLogits(is_grad=False, sparse=False) with_loss_cell = WithLossCell(self._network, loss_fn) self._grad_all = GradWrapWithLoss(with_loss_cell) self._grad_all.set_train() def generate(self, inputs, labels): """ Generate adversarial examples based on input samples and original/target labels. Args: inputs (numpy.ndarray): Benign input samples used as references to create adversarial examples. labels (numpy.ndarray): Original/target labels. Returns: numpy.ndarray, generated adversarial examples. """ inputs, labels = check_pair_numpy_param('inputs', inputs, 'labels', labels) self._dtype = inputs.dtype gradient = self._gradient(inputs, labels) # use random method or not if self._alpha is not None: random_part = self._alpha * np.sign( np.random.normal(size=inputs.shape)).astype(self._dtype) perturbation = (self._eps - self._alpha) * gradient + random_part else: perturbation = self._eps * gradient if self._bounds is not None: clip_min, clip_max = self._bounds perturbation = perturbation * (clip_max - clip_min) adv_x = inputs + perturbation adv_x = np.clip(adv_x, clip_min, clip_max) else: adv_x = inputs + perturbation return adv_x @abstractmethod def _gradient(self, inputs, labels): """ Calculate gradients based on input samples and original/target labels. Args: inputs (numpy.ndarray): Benign input samples used as references to create adversarial examples. labels (numpy.ndarray): Original/target labels. Raises: NotImplementedError: It is an abstract method. """ msg = 'The function _gradient() is an abstract method in class ' \ '`GradientMethod`, and should be implemented in child class.' LOGGER.error(TAG, msg) raise NotImplementedError(msg)