Ejemplo n.º 1
0
    def __init__(self, model, back='tf', sess=None):
        """
        Create a FastGradientMethod instance.
        """
        super(FastGradientMethod, self).__init__(model, back, sess)
        self.feedable_kwargs = {
            'eps': np.float32,
            'y': np.float32,
            'clip_min': np.float32,
            'clip_max': np.float32
        }
        self.structural_kwargs = ['ord']

        if not isinstance(self.model, Model):
            self.model = CallableModelWrapper(self.model, 'probs')
Ejemplo n.º 2
0
    def __init__(self, models, back='tf', sess=None):
        """
        Create a BasicIterativeMethod instance.
        """
        super(MultiModelIterativeMethod, self).__init__(models, back, sess)
        self.feedable_kwargs = {
            'eps': np.float32,
            'eps_iter': np.float32,
            'y': np.float32,
            'clip_min': np.float32,
            'clip_max': np.float32
        }
        self.structural_kwargs = ['ord', 'nb_iter']

        if not isinstance(self.model1, Model):
            self.model1 = CallableModelWrapper(self.model1, 'probs')

        if not isinstance(self.model2, Model):
            self.model2 = CallableModelWrapper(self.model2, 'probs')

        if not isinstance(self.model3, Model):
            self.model3 = CallableModelWrapper(self.model3, 'probs')
Ejemplo n.º 3
0
class MultiModelIterativeMethod(MultipleModelAttack):
    """
    The Basic Iterative Method (Kurakin et al. 2016). The original paper used
    hard labels for this attack; no label smoothing.
    """
    def __init__(self, models, back='tf', sess=None):
        """
        Create a BasicIterativeMethod instance.
        """
        super(MultiModelIterativeMethod, self).__init__(models, back, sess)
        self.feedable_kwargs = {
            'eps': np.float32,
            'eps_iter': np.float32,
            'y': np.float32,
            'clip_min': np.float32,
            'clip_max': np.float32
        }
        self.structural_kwargs = ['ord', 'nb_iter']

        if not isinstance(self.model1, Model):
            self.model1 = CallableModelWrapper(self.model1, 'probs')

        if not isinstance(self.model2, Model):
            self.model2 = CallableModelWrapper(self.model2, 'probs')

        if not isinstance(self.model3, Model):
            self.model3 = CallableModelWrapper(self.model3, 'probs')

    def generate(self, x, **kwargs):
        """
        Generate symbolic graph for adversarial examples and return.
        :param x: The model's symbolic inputs.
        :param eps: (required float) maximum distortion of adversarial example
                    compared to original input
        :param eps_iter: (required float) step size for each attack iteration
        :param nb_iter: (required int) Number of attack iterations.
        :param y: (required) A tensor with the model labels.
        :param ord: (optional) Order of the norm (mimics Numpy).
                    Possible values: np.inf, 1 or 2.
        :param clip_min: (optional float) Minimum input component value
        :param clip_max: (optional float) Maximum input component value
        """
        import tensorflow as tf

        # Parse and save attack-specific parameters
        assert self.parse_params(**kwargs)

        # Initialize loop variables
        eta = 0

        # Fix labels to the first model predictions for loss computation
        # model_preds1 = self.model1.get_probs(x)
        # model_preds2 = self.model2.get_probs(x)
        model_preds3 = self.model3.get_probs(x)
        model_preds = model_preds3

        preds_max = tf.reduce_max(model_preds, 1, keep_dims=True)
        y = tf.to_float(tf.equal(model_preds, preds_max))
        fgsm_params = {'eps': self.eps_iter, 'y': y, 'ord': self.ord}

        for i in range(self.nb_iter):

            FGSM1 = FastGradientMethod(self.model1,
                                       back=self.back,
                                       sess=self.sess)
            FGSM2 = FastGradientMethod(self.model2,
                                       back=self.back,
                                       sess=self.sess)
            FGSM3 = FastGradientMethod(self.model3,
                                       back=self.back,
                                       sess=self.sess)

            # Compute this step's perturbation
            eta1 = FGSM1.generate(x + eta, **fgsm_params) - x
            eta2 = FGSM2.generate(x + eta, **fgsm_params) - x
            eta3 = FGSM3.generate(x + eta, **fgsm_params) - x
            eta = eta1 * 0.333 + eta2 * 0.333 + eta3 * 0.333

            # Clipping perturbation eta to self.ord norm ball
            if self.ord == np.inf:
                eta = tf.clip_by_value(eta, -self.eps, self.eps)
            elif self.ord in [1, 2]:
                reduc_ind = list(xrange(1, len(eta.get_shape())))
                if self.ord == 1:
                    norm = tf.reduce_sum(tf.abs(eta),
                                         reduction_indices=reduc_ind,
                                         keep_dims=True)
                elif self.ord == 2:
                    norm = tf.sqrt(
                        tf.reduce_sum(tf.square(eta),
                                      reduction_indices=reduc_ind,
                                      keep_dims=True))
                eta = eta * self.eps / norm

        # Define adversarial example (and clip if necessary)
        adv_x = x + eta
        if self.clip_min is not None and self.clip_max is not None:
            adv_x = tf.clip_by_value(adv_x, self.clip_min, self.clip_max)

        return adv_x

    def parse_params(self,
                     eps=0.3,
                     eps_iter=0.05,
                     nb_iter=10,
                     y=None,
                     ord=np.inf,
                     clip_min=None,
                     clip_max=None,
                     **kwargs):
        """
        Take in a dictionary of parameters and applies attack-specific checks
        before saving them as attributes.

        Attack-specific parameters:
        :param eps: (required float) maximum distortion of adversarial example
                    compared to original input
        :param eps_iter: (required float) step size for each attack iteration
        :param nb_iter: (required int) Number of attack iterations.
        :param y: (required) A tensor with the model labels.
        :param ord: (optional) Order of the norm (mimics Numpy).
                    Possible values: np.inf, 1 or 2.
        :param clip_min: (optional float) Minimum input component value
        :param clip_max: (optional float) Maximum input component value
        """

        # Save attack-specific parameters
        self.eps = eps
        self.eps_iter = eps_iter
        self.nb_iter = nb_iter
        self.y = y
        self.ord = ord
        self.clip_min = clip_min
        self.clip_max = clip_max

        # Check if order of the norm is acceptable given current implementation
        if self.ord not in [np.inf, 1, 2]:
            raise ValueError("Norm order must be either np.inf, 1, or 2.")
        if self.back == 'th':
            error_string = "BasicIterativeMethod is not implemented in Theano"
            raise NotImplementedError(error_string)

        return True
Ejemplo n.º 4
0
class FastGradientMethod(Attack):
    """
    This attack was originally implemented by Goodfellow et al. (2015) with the
    infinity norm (and is known as the "Fast Gradient Sign Method"). This
    implementation extends the attack to other norms, and is therefore called
    the Fast Gradient Method.
    Paper link: https://arxiv.org/abs/1412.6572
    """
    def __init__(self, model, back='tf', sess=None):
        """
        Create a FastGradientMethod instance.
        """
        super(FastGradientMethod, self).__init__(model, back, sess)
        self.feedable_kwargs = {
            'eps': np.float32,
            'y': np.float32,
            'clip_min': np.float32,
            'clip_max': np.float32
        }
        self.structural_kwargs = ['ord']

        if not isinstance(self.model, Model):
            self.model = CallableModelWrapper(self.model, 'probs')

    def generate(self, x, **kwargs):
        """
        Generate symbolic graph for adversarial examples and return.
        :param x: The model's symbolic inputs.
        :param eps: (optional float) attack step size (input variation)
        :param ord: (optional) Order of the norm (mimics Numpy).
                    Possible values: np.inf, 1 or 2.
        :param y: (optional) A tensor with the model labels. Only provide
                  this parameter if you'd like to use true labels when crafting
                  adversarial samples. Otherwise, model predictions are used as
                  labels to avoid the "label leaking" effect (explained in this
                  paper: https://arxiv.org/abs/1611.01236). Default is None.
                  Labels should be one-hot-encoded.
        :param clip_min: (optional float) Minimum input component value
        :param clip_max: (optional float) Maximum input component value
        """
        # Parse and save attack-specific parameters
        assert self.parse_params(**kwargs)

        if self.back == 'tf':
            from .attacks_tf import fgm
        else:
            from .attacks_th import fgm

        return fgm(x,
                   self.model.get_probs(x),
                   y=self.y,
                   eps=self.eps,
                   ord=self.ord,
                   clip_min=self.clip_min,
                   clip_max=self.clip_max)

    def parse_params(self,
                     eps=0.3,
                     ord=np.inf,
                     y=None,
                     clip_min=None,
                     clip_max=None,
                     **kwargs):
        """
        Take in a dictionary of parameters and applies attack-specific checks
        before saving them as attributes.

        Attack-specific parameters:
        :param eps: (optional float) attack step size (input variation)
        :param ord: (optional) Order of the norm (mimics Numpy).
                    Possible values: np.inf, 1 or 2.
        :param y: (optional) A tensor with the model labels. Only provide
                  this parameter if you'd like to use true labels when crafting
                  adversarial samples. Otherwise, model predictions are used as
                  labels to avoid the "label leaking" effect (explained in this
                  paper: https://arxiv.org/abs/1611.01236). Default is None.
                  Labels should be one-hot-encoded.
        :param clip_min: (optional float) Minimum input component value
        :param clip_max: (optional float) Maximum input component value
        """
        # Save attack-specific parameters
        self.eps = eps
        self.ord = ord
        self.y = y
        self.clip_min = clip_min
        self.clip_max = clip_max

        # Check if order of the norm is acceptable given current implementation
        if self.ord not in [np.inf, int(1), int(2)]:
            raise ValueError("Norm order must be either np.inf, 1, or 2.")
        if self.back == 'th' and self.ord != np.inf:
            raise NotImplementedError("The only FastGradientMethod norm "
                                      "implemented for Theano is np.inf.")
        return True