Trusted-AI / adversarial-robustness-toolbox

Adversarial Robustness Toolbox (ART) - Python Library for Machine Learning Security - Evasion, Poisoning, Extraction, Inference - Red and Blue Teams
https://adversarial-robustness-toolbox.readthedocs.io/en/latest/
MIT License
4.78k stars 1.16k forks source link

Bug art.exceptions.EstimatorError #2105

Closed TaurusLegend closed 1 year ago

TaurusLegend commented 1 year ago

Describe the bug Can't apply the evasion attack FastGradientMethod on a SklearnClassifier. The SklearnClassifier is a DecisionTreeClassifier which is optimized using sklearn GridSearchCV and imblearn Pipeline. I tried to follow the example get_started_scikit_learn.py and adapt it to my needs.

To Reproduce

from sklearn.model_selection import train_test_split, GridSearchCV, RepeatedStratifiedKFold
from sklearn.metrics import classification_report
from sklearn.preprocessing import LabelBinarizer
from sklearn.tree import DecisionTreeClassifier
import numpy as np
import pandas as pd
from imblearn.over_sampling import SMOTE
from imblearn.pipeline import Pipeline as ImblearnPipeline
from utils import load_dataset
from art.estimators.classification import SklearnClassifier
from art.attacks.evasion import FastGradientMethod, SaliencyMapMethod, DeepFool, CarliniL2Method

def sampling(ratio):
    def _sampling(y):
        unique, counts = np.unique(y, return_counts=True)
        counts[unique != np.argmax(counts)] = (counts[unique != np.argmax(counts)] + counts[unique != np.argmax(counts)] * ratio)
        samples = dict(zip(unique, counts))
        return samples
    return _sampling

def main():
    train_size = 0.7
    test_size = 0.3
    ratio = 0.3
    smote = SMOTE(sampling_strategy=sampling(ratio))
    model = DecisionTreeClassifier()

    # Multiclass dataset with 10 classes
    X, y = load_dataset('UNSW-NB15_processed.csv')

    labelBinarizer = LabelBinarizer()
    labelBinarizer = labelBinarizer.fit(y)
    y = labelBinarizer.transform(y)

    X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=train_size, test_size=test_size, stratify=y)

    pipeline = ImblearnPipeline(steps = [['smote', smote],
                                         ['classifier', model]])

    repeatedStratifiedKFold = RepeatedStratifiedKFold(n_splits=5, n_repeats=3)

    param_grid = {'classifier__criterion': ['gini', 'entropy'],
                  'classifier__max_depth': [None]}

    grid_search = GridSearchCV(estimator=pipeline,
                           param_grid=param_grid,
                           scoring='roc_auc_ovr',
                           error_score="raise",
                           cv=repeatedStratifiedKFold,
                           verbose=3)

    classifier = SklearnClassifier(model=grid_search, clip_values=(0, 1))

    classifier.fit(X_train, y_train)

    y_pred = classifier.predict(X_test)

    attack = FastGradientMethod(estimator=classifier, norm='inf', eps=0.1)
    X_test_adv = attack.generate(X_test)

    y_pred_adv = classifier.predict(X_test_adv)

if __name__ == '__main__':
    main()

Expected behavior I expected the program to generate adversarial examples using the Fast Gradient Method and using the trained SklearnClassifier to classify them.

Screenshots

Traceback (most recent call last):
  File "decision_tree_adv2.py", line 142, in <module>
    main()
  File "decision_tree_adv2.py", line 120, in main
    attack = FastGradientMethod(estimator=classifier, norm='inf', eps=0.1)
  File "/home/quadmin/.local/lib/python3.8/site-packages/art/attacks/evasion/fast_gradient.py", line 104, in __init__
    super().__init__(estimator=estimator, summary_writer=summary_writer)
  File "/home/quadmin/.local/lib/python3.8/site-packages/art/attacks/attack.py", line 197, in __init__
    super().__init__(**kwargs)
  File "/home/quadmin/.local/lib/python3.8/site-packages/art/attacks/attack.py", line 125, in __init__
    raise EstimatorError(self.__class__, self.estimator_requirements, estimator)
art.exceptions.EstimatorError: FastGradientMethod requires an estimator derived from <class 'art.estimators.estimator.BaseEstimator'> and <class 'art.estimators.estimator.LossGradientsMixin'>, the provided classifier is an instance of <class 'art.estimators.classification.scikitlearn.ScikitlearnClassifier'> and is derived from (<class 'art.estimators.classification.classifier.ClassifierMixin'>, <class 'art.estimators.scikitlearn.ScikitlearnEstimator'>).

System information:

beat-buesser commented 1 year ago

Hi @TaurusLegend Thank you for using ART! This is the expected behavior of ART indicating that attack and estimator/model are not compatible, in this case because FastGradientMethod requires loss gradients and a decision tree model cannot provide loss gradients.

I convert this issue into a discussion in the Discussion tab to continue