Skip to content

Commit 4a4ad1c

Browse files
committed
Make requested changes and link notebook in README.md
Signed-off-by: GalHorowitz <[email protected]>
1 parent 4560202 commit 4a4ad1c

File tree

4 files changed

+25
-16
lines changed

4 files changed

+25
-16
lines changed

art/estimators/classification/blackbox.py

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,10 @@
2020
"""
2121
from __future__ import absolute_import, division, print_function, unicode_literals
2222

23+
from functools import total_ordering
2324
import logging
2425
from typing import Callable, List, Optional, Union, Tuple, TYPE_CHECKING
2526

26-
from functools import total_ordering
27-
2827
import numpy as np
2928

3029
from art.estimators.estimator import BaseEstimator, NeuralNetworkMixin
@@ -43,7 +42,7 @@ class BlackBoxClassifier(ClassifierMixin, BaseEstimator):
4342
Wrapper class for black-box classifiers.
4443
"""
4544

46-
estimator_params = Classifier.estimator_params + ["nb_classes", "input_shape", "predict"]
45+
estimator_params = Classifier.estimator_params + ["nb_classes", "input_shape", "predict_fn"]
4746

4847
def __init__(
4948
self,
@@ -171,7 +170,7 @@ class BlackBoxClassifierNeuralNetwork(NeuralNetworkMixin, ClassifierMixin, BaseE
171170
NeuralNetworkMixin.estimator_params
172171
+ ClassifierMixin.estimator_params
173172
+ BaseEstimator.estimator_params
174-
+ ["nb_classes", "input_shape", "predict"]
173+
+ ["nb_classes", "input_shape", "predict_fn"]
175174
)
176175

177176
def __init__(
@@ -309,14 +308,14 @@ def compute_loss(self, x: np.ndarray, y: np.ndarray, **kwargs) -> np.ndarray:
309308

310309

311310
@total_ordering
312-
class FuzzyMappingWrapper:
311+
class FuzzyMapping:
313312
"""
314-
Wrapper class for a sample, label pair to be used in a `SortedList`.
313+
Class for a sample/label pair to be used in a `SortedList`.
315314
"""
316315

317316
def __init__(self, key: np.ndarray, value=None):
318317
"""
319-
Create a wrapper for the key, value to pair to be used in a `SortedList`.
318+
Create an instance of a key/value to pair to be used in a `SortedList`.
320319
321320
:param key: The sample to be matched against.
322321
:param value: The mapped value.
@@ -327,20 +326,18 @@ def __init__(self, key: np.ndarray, value=None):
327326
def __eq__(self, other):
328327
return np.all(np.isclose(self.key, other.key))
329328

330-
def __ne__(self, other):
331-
return not self.__eq__(other)
332-
333329
def __ge__(self, other):
334330
# This implements >= comparison so we can use this class in a `SortedList`. The `total_ordering` decorator
335331
# automatically generates the rest of the comparison magic functions based on this one
336332

337-
if self.__eq__(other):
333+
close_cells = np.isclose(self.key, other.key)
334+
if np.all(close_cells):
338335
return True
339336

340337
# If the keys are not exactly the same (up to floating-point inaccuracies), we compare the value of the first
341338
# index which is not the same to decide on an ordering
342339

343-
compare_idx = np.unravel_index(np.argmin(np.isclose(self.key, other.key)), shape=self.key.shape)
340+
compare_idx = np.unravel_index(np.argmin(close_cells), shape=self.key.shape)
344341
return self.key[compare_idx] >= other.key[compare_idx]
345342

346343

@@ -360,13 +357,13 @@ def _make_lookup_predict_fn(existing_predictions: Tuple[np.ndarray, np.ndarray],
360357
from sortedcontainers import SortedList
361358

362359
# Construct a search-tree of the predictions, using fuzzy float comparison
363-
sorted_predictions = SortedList([FuzzyMappingWrapper(key, value) for key, value in zip(samples, labels)])
360+
sorted_predictions = SortedList([FuzzyMapping(key, value) for key, value in zip(samples, labels)])
364361

365362
def fuzzy_predict_fn(batch):
366363
predictions = []
367364
for row in batch:
368365
try:
369-
match_idx = sorted_predictions.index(FuzzyMappingWrapper(row))
366+
match_idx = sorted_predictions.index(FuzzyMapping(row))
370367
except ValueError as err:
371368
raise ValueError("No existing prediction for queried input") from err
372369

notebooks/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,11 @@ versatile classifier of ART requiring only a single predict function definition
8585
requirements. The notebook shows how use BlackBoxClassifier to attack a remote, deployed model (in this case on IBM
8686
Watson Machine Learning, https://cloud.ibm.com) using the HopSkiJump attack.
8787

88+
[classifier_blackbox_lookup_table.ipynb](classifier_blackbox_lookup_table.ipynb) [[on nbviewer](https://nbviewer.jupyter.org/github/Trusted-AI/adversarial-robustness-toolbox/blob/main/notebooks/classifier_blackbox_lookup_table.ipynb)]
89+
demonstrates using BlackBoxClassifier when the adversary does not have access to the model for making predictions, but
90+
does have a set of existing predictions produced before losing access. The notebook shows how to use BlackBoxClassifier
91+
to attack a model using only a table of samples and their labels, using a membership inference black-box attack.
92+
8893
[classifier_blackbox_tesseract.ipynb](classifier_blackbox_tesseract.ipynb) [[on nbviewer](https://nbviewer.jupyter.org/github/Trusted-AI/adversarial-robustness-toolbox/blob/main/notebooks/classifier_blackbox_tesseract.ipynb)]
8994
demonstrates a black-box attack on Tesseract OCR. It uses BlackBoxClassifier and HopSkipJump attack to change the image
9095
of one word into the image of another word and shows how to apply pre-processing defences.

notebooks/classifier_blackbox_lookup_table.ipynb

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,13 @@
192192
"### Black-box attack"
193193
]
194194
},
195+
{
196+
"cell_type": "markdown",
197+
"metadata": {},
198+
"source": [
199+
"We no longer need access to the model, and the attack is running using the set of predictions we have made earlier."
200+
]
201+
},
195202
{
196203
"cell_type": "code",
197204
"execution_count": 20,
@@ -251,4 +258,4 @@
251258
},
252259
"nbformat": 4,
253260
"nbformat_minor": 2
254-
}
261+
}

tests/estimators/classification/test_blackbox_existing_predictions.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
import numpy as np
2121

22-
from art.estimators.classification import BlackBoxClassifierNeuralNetwork, BlackBoxClassifier
22+
from art.estimators.classification.blackbox import BlackBoxClassifierNeuralNetwork, BlackBoxClassifier
2323
from tests.utils import ARTTestException
2424

2525

0 commit comments

Comments
 (0)