def _attack_pgd_ls(self):
        params = {
            "classifier": self.classifier,
            "double_init_ds": self.tr,
            "distance": 'l1',
            "lb": self.lb,
            "ub": self.ub,
            "y_target": self.y_target,
            "attack_classes": self.attack_classes,
            "solver_params": {
                'eta': 0.5,
                'eps': 1e-2
            }
        }
        attack = CAttackEvasionPGDLS(**params)
        attack.verbose = 1

        # sec eval params
        param_name = 'dmax'
        dmax = 2
        dmax_step = 0.5
        param_values = CArray.arange(start=0,
                                     step=dmax_step,
                                     stop=dmax + dmax_step)

        return attack, param_name, param_values
    def _set_evasion(self, ds, params):
        """Prepare the evasion attack.

        - discretize data if necessary
        - train the classifier (if not trained)
        - train the surrogate classifier (if not trained)
        - create the evasion object
        - choose an attack starting point

        Parameters
        ----------
        ds : CDataset
        params : dict
            Parameters for the attack class.

        Returns
        -------
        evas : CAttackEvasion
        x0 : CArray
            Initial attack point.
        y0 : CArray
            Label of the initial attack point.

        """
        if not params["classifier"].is_fitted():
            self.logger.info("Training classifier...")
            params["classifier"].fit(ds.X, ds.Y)

        evas = CAttackEvasionPGDLS(**params)
        evas.verbose = 2

        # pick a malicious sample
        x0, y0 = self._choose_x0_2c(ds)

        return evas, x0, y0
    def _set_evasion(self, params, x0_img_class):
        """Prepare the evasion attack.

        - train the classifier (if not trained)
        - train the surrogate classifier (if not trained)
        - create the evasion object
        - choose an attack starting point

        Parameters
        ----------
        params : dict
            Parameters for the attack class.
        x0_img_class : int
            Class from which to choose the initial attack point.

        Returns
        -------
        evas : CAttackEvasion
        x0 : CArray
            Initial attack point.
        y0 : CArray
            Label of the initial attack point.

        """
        if not params["classifier"].is_fitted():
            self.logger.info("Training classifier...")
            params["classifier"].fit(self._tr.X, self._tr.Y)

        evas = CAttackEvasionPGDLS(**params)
        evas.verbose = 2

        # pick a malicious sample
        x0, y0 = self._choose_x0_2c(x0_img_class)

        return evas, x0, y0
    def test_attack_pgd_ls(self):
        """Test SecEval using CAttackEvasionPGDLS."""
        params = {
            "classifier": self.clf,
            "double_init_ds": self.tr,
            "distance": 'l2',
            "lb": -2,
            "ub": 2,
            "y_target": None,
            "solver_params": {'eta': 0.1, 'eps': 1e-2}
        }
        attack = CAttackEvasionPGDLS(**params)
        attack.verbose = 1

        param_name = 'dmax'

        self._set_and_run(attack, param_name)
    def test_attack_pgd_ls_discrete(self):
        """Test SecEval using CAttackEvasionPGDLS on a problematic
        discrete case with L1 constraint.
        We alter the classifier so that many weights have the same value.
        The optimizer should be able to evade the classifier anyway,
        by changing one feature each iteration. Otherwise, by changing
        all the feature with the same value at once, the evasion will always
        fail because the L1 constraint will be violated.
        """
        self.ds = self._discretize_data(self.ds, eta=1)
        self.ds.X[self.ds.X > 1] = 1
        self.ds.X[self.ds.X < -1] = -1

        self.tr = self.ds[:self.n_tr, :]
        self.ts = self.ds[self.n_tr:, :]

        self.clf.fit(self.tr.X, self.tr.Y)

        # Set few features to the same max value
        w_new = self.clf.w.deepcopy()
        w_new[CArray.randint(
            self.clf.w.size, shape=5, random_state=0)] = self.clf.w.max()
        self.clf._w = w_new

        params = {
            "classifier": self.clf,
            "double_init": False,
            "distance": 'l1',
            "lb": -1,
            "ub": 1,
            "y_target": None,
            "solver_params": {'eta': 1, 'eps': 1e-2}
        }
        attack = CAttackEvasionPGDLS(**params)
        attack.verbose = 1

        param_name = 'dmax'

        self._set_and_run(attack, param_name, dmax_step=1)
# Should be chosen depending on the optimization problem
solver_params = {
    'eta': 0.3,
    'eta_min': 0.1,
    'eta_max': None,
    'max_iter': 100,
    'eps': 1e-4
}

from secml.adv.attacks.evasion import CAttackEvasionPGDLS
pgd_ls_attack = CAttackEvasionPGDLS(
    classifier=clf,
    surrogate_classifier=clf,
    surrogate_data=tr,
    distance=noise_type,
    dmax=dmax,
    lb=lb, ub=ub,
    solver_params=solver_params,
    y_target=y_target)

print(x0)
# Run the evasion attack on x0
y_pred_pgdls, _, adv_ds_pgdls, _ = pgd_ls_attack.run(x0, y0)

print("Original x0 label: ", y0.item())
print("Adversarial example label (PGD-LS): ", y_pred_pgdls.item())

print("Number of classifier gradient evaluations: {:}"
      "".format(pgd_ls_attack.grad_eval))
def attack_keras_model(X, Y, S, nb_attack=25, dmax=0.1):
    """
    Generates an adversarial attack on a general model.

    :param X: Original inputs on which the model is trained
    :param Y: Original outputs on which the model is trained
    :param S: Original protected attributes on which the model is trained
    :return: Adversarial dataset (i.e. new data points + original input)
    """

    from secml.data import CDataset
    from secml.array import CArray

    # secML wants all dimensions to be homogeneous (we had previously float and int in X)
    data_set_encoded_secML = CArray(X, dtype=float, copy=True)
    data_set_encoded_secML = CDataset(data_set_encoded_secML, Y)

    n_tr = round(0.66 * X.shape[0])
    n_ts = X.shape[0] - n_tr

    logger.debug(X.shape)
    logger.debug(n_tr)
    logger.debug(n_ts)

    from secml.data.splitter import CTrainTestSplit
    splitter = CTrainTestSplit(train_size=n_tr, test_size=n_ts)

    # Use training set for the classifier and then pick points from an internal test set.
    tr_set_secML, ts_set_secML = splitter.split(data_set_encoded_secML)

    # tr_set_secML = CDataset(X_train,Y_train)
    # ts_set_secML = CDataset(X_test,Y_test)

    # Create a surrogate classifier

    # Creation of the multiclass classifier
    from secml.ml.classifiers import CClassifierSVM
    from secml.ml.classifiers.multiclass import CClassifierMulticlassOVA
    from secml.ml.kernel import CKernelRBF
    clf = CClassifierMulticlassOVA(CClassifierSVM, kernel=CKernelRBF())

    # Parameters for the Cross-Validation procedure
    xval_params = {'C': [1e-4, 1e-3, 1e-2, 0.1, 1], 'kernel.gamma': [0.01, 0.1, 1, 10, 100, 1e3]}

    # Let's create a 3-Fold data splitter
    random_state = 999

    from secml.data.splitter import CDataSplitterKFold
    xval_splitter = CDataSplitterKFold(num_folds=3, random_state=random_state)

    # Select and set the best training parameters for the classifier
    logger.debug("Estimating the best training parameters...")
    best_params = clf.estimate_parameters(
        dataset=tr_set_secML,
        parameters=xval_params,
        splitter=xval_splitter,
        metric='accuracy',
        perf_evaluator='xval'
    )
    logger.debug("The best training parameters are: ", best_params)

    logger.debug(clf.get_params())
    logger.debug(clf.num_classifiers)

    # Metric to use for training and performance evaluation
    from secml.ml.peval.metrics import CMetricAccuracy
    metric = CMetricAccuracy()

    # Train the classifier
    clf.fit(tr_set_secML)
    logger.debug(clf.num_classifiers)

    # Compute predictions on a test set
    y_pred = clf.predict(ts_set_secML.X)

    # Evaluate the accuracy of the classifier
    acc = metric.performance_score(y_true=ts_set_secML.Y, y_pred=y_pred)

    logger.debug("Accuracy on test set: {:.2%}".format(acc))

    # Prepare attack configuration

    noise_type = 'l2'   # Type of perturbation 'l1' or 'l2'
    lb, ub = 0, 1       # Bounds of the attack space. Can be set to `None` for unbounded
    y_target = None     # None if `error-generic` or a class label for `error-specific`

    # Should be chosen depending on the optimization problem
    solver_params = {
        'eta': 0.1,         # grid search resolution
        'eta_min': 0.1,
        'eta_max': None,    # None should be ok
        'max_iter': 1000,
        'eps': 1e-2         # Tolerance on the stopping crit.
    }

    # Run attack

    from secml.adv.attacks.evasion import CAttackEvasionPGDLS
    pgd_ls_attack = CAttackEvasionPGDLS(
        classifier=clf,
        surrogate_classifier=clf,
        surrogate_data=tr_set_secML,
        distance=noise_type,
        dmax=dmax,
        lb=lb, ub=ub,
        solver_params=solver_params,
        y_target=y_target)

    nb_feat = X.shape[1]

    result_pts = np.empty([nb_attack, nb_feat])
    result_class = np.empty([nb_attack, 1])

    # take a point at random being the starting point of the attack and run the attack
    import random
    for nb_iter in range(0, nb_attack):
        rn = random.randint(0, ts_set_secML.num_samples - 1)
        x0, y0 = ts_set_secML[rn, :].X, ts_set_secML[rn, :].Y,

        try:
            y_pred_pgdls, _, adv_ds_pgdls, _ = pgd_ls_attack.run(x0, y0)
            adv_pt = adv_ds_pgdls.X.get_data()
            # np.asarray([np.asarray(row, dtype=float) for row in y_tr], dtype=float)
            result_pts[nb_iter] = adv_pt
            result_class[nb_iter] = y_pred_pgdls.get_data()[0]
        except ValueError:
            logger.warning("value error on {}".format(nb_iter))

    return result_pts, result_class, ts_set_secML[:nb_attack, :].Y
Exemple #8
0
    def _test_evasion_multiclass(self, expected_x):

        # EVASION
        self.multiclass.verbose = 2

        if self.normalizer is not None:
            lb = self.normalizer.feature_range[0]
            ub = self.normalizer.feature_range[1]
        else:
            lb = None
            ub = None

        dmax = 2

        self.solver_params = {'eta': 1e-1, 'eta_min': 1.0}

        eva = CAttackEvasionPGDLS(classifier=self.multiclass,
                                  surrogate_classifier=self.multiclass,
                                  surrogate_data=self.ds,
                                  distance='l2',
                                  dmax=dmax,
                                  lb=lb,
                                  ub=ub,
                                  solver_params=self.solver_params,
                                  y_target=self.y_target)

        eva.verbose = 0  # 2

        # Points from class 2 region
        # p_idx = 0

        # Points from class 1 region
        # p_idx = 68

        # Points from class 3 region
        p_idx = 1  # Wrong classified point
        # p_idx = 53  # Evasion goes up usually

        # Points from class 0 region
        # p_idx = 49  # Wrong classified point
        # p_idx = 27  # Correctly classified point

        x0 = self.ds.X[p_idx, :]
        y0 = self.ds.Y[p_idx].item()

        x_seq = CArray.empty((0, x0.shape[1]))
        scores = CArray([])
        f_seq = CArray([])

        x = x0
        for d_idx, d in enumerate(range(0, dmax + 1)):

            self.logger.info("Evasion at dmax: " + str(d))

            eva.dmax = d
            x, f_opt = eva._run(x0=x0, y0=y0, x_init=x)
            y_pred, score = self.multiclass.predict(
                x, return_decision_function=True)
            f_seq = f_seq.append(f_opt)
            # not considering all iterations, just values at dmax
            # for all iterations, you should bring eva.x_seq and eva.f_seq
            x_seq = x_seq.append(x, axis=0)

            s = score[:, y0 if self.y_target is None else self.y_target]

            scores = scores.append(s)

        self.logger.info("Predicted label after evasion: " + str(y_pred))
        self.logger.info("Score after evasion: {:}".format(s))
        self.logger.info("Objective function after evasion: {:}".format(f_opt))

        # Compare optimal point with expected
        self.assert_array_almost_equal(eva.x_opt.todense().ravel(),
                                       expected_x,
                                       decimal=4)

        self._make_plots(x_seq, dmax, eva, x0, scores, f_seq)
Exemple #9
0
    def _test_evasion_multiclass(self, expected_x):

        # EVASION
        self.multiclass.verbose = 2

        if self.normalizer is not None:
            lb = self.normalizer.feature_range[0]
            ub = self.normalizer.feature_range[1]
        else:
            lb = None
            ub = None

        dmax = 3

        self.solver_params = {'eta': 0.5, 'max_iter': 3}

        eva = CAttackEvasionPGDLS(classifier=self.multiclass,
                                  double_init_ds=self.ds,
                                  distance='l2',
                                  dmax=dmax,
                                  lb=lb,
                                  ub=ub,
                                  solver_params=self.solver_params,
                                  y_target=self.y_target)

        eva.verbose = 0  # 2

        # Points from class 2 region
        # p_idx = 0

        # Points from class 1 region
        # p_idx = 68

        # Points from class 3 region
        p_idx = 1  # Wrong classified point
        # p_idx = 53  # Evasion goes up usually

        # Points from class 0 region
        # p_idx = 49  # Wrong classified point
        # p_idx = 27  # Correctly classified point

        x0 = self.ds.X[p_idx, :]
        y0 = self.ds.Y[p_idx].item()

        self.logger.info("Evasion at dmax: " + str(dmax))

        eva.dmax = dmax
        x_opt, f_opt = eva._run(x0=x0, y0=y0, x_init=x0)
        y_pred, score = self.multiclass.predict(x_opt,
                                                return_decision_function=True)

        s = score[:, y0 if self.y_target is None else self.y_target]

        self.logger.info(
            "Number of objective function evaluations: {:}".format(eva.f_eval))

        self.logger.info("Number of gradient function evaluations: {:}".format(
            eva.grad_eval))

        self.logger.info("Predicted label after evasion: {:}".format(y_pred))
        self.logger.info("Score after evasion: {:}".format(s))
        self.logger.info("Objective function after evasion: {:}".format(f_opt))

        # Compare optimal point with expected
        self.assert_array_almost_equal(eva.x_opt.todense().ravel(),
                                       expected_x,
                                       decimal=4)

        if self.y_target:

            s_ytarget_x0 = self.multiclass.decision_function(x0, self.y_target)
            s_ytarget_xopt = self.multiclass.decision_function(
                x_opt, self.y_target)

            self.logger.info(
                "Discriminat function w.r.t the target class first: {:} "
                "and after evasion: {:}".format(s_ytarget_x0, s_ytarget_xopt))

            self.assertLess(s_ytarget_x0, s_ytarget_xopt)

        else:  # indiscriminate attack

            s_ytrue_x0 = self.multiclass.decision_function(x0, y0)
            s_ytrue_xopt = self.multiclass.decision_function(x_opt, y0)

            self.logger.info(
                "Discriminat function w.r.t the true class first: {:} "
                "and after evasion: {:}".format(s_ytrue_x0, s_ytrue_xopt))

            self.assertGreater(s_ytrue_x0, s_ytrue_xopt)

        self._make_plot(p_idx, eva, dmax)
Exemple #10
0
    def setUp(self):
        
        classifier = CClassifierSVM(
            kernel='linear', C=1.0, grad_sampling=1.0)

        # data parameters
        discrete = False

        lb = -2
        ub = +2

        n_tr = 20
        n_ts = 10
        n_features = 2
        
        n_reps = 1

        self.sec_eval = []
        self.attack_ds = []
        for rep_i in range(n_reps):

            self.logger.info(
                "Loading `random_blobs` with seed: {:}".format(rep_i))
            loader = CDLRandomBlobs(
                n_samples=n_tr + n_ts,
                n_features=n_features,
                centers=[(-0.5, -0.5), (+0.5, +0.5)],
                center_box=(-0.5, 0.5),
                cluster_std=0.5,
                random_state=rep_i * 100 + 10)
            ds = loader.load()

            tr = ds[:n_tr, :]
            ts = ds[n_tr:, :]
            
            classifier.fit(tr)
            
            self.attack_ds.append(ts)

            # only manipulate positive samples, targeting negative ones
            self.y_target = None
            attack_classes = CArray([1])
        
            params = {
                "classifier": classifier,
                "surrogate_classifier": classifier,
                "surrogate_data": tr,
                "distance": 'l1',
                "lb": lb,
                "ub": ub,
                "discrete": discrete,
                "y_target": self.y_target,
                "attack_classes": attack_classes,
                "solver_params": {'eta': 0.5, 'eps': 1e-2}
            }
            attack = CAttackEvasionPGDLS(**params)
            attack.verbose = 1
        
            # sec eval params
            param_name = 'dmax'
            dmax = 2
            dmax_step = 0.5
            param_values = CArray.arange(
                start=0, step=dmax_step,
                stop=dmax + dmax_step)

            # set sec eval object
            self.sec_eval.append(
                CSecEval(
                    attack=attack,
                    param_name=param_name,
                    param_values=param_values,
                    )
            )