Source code for aijack.attack.evasion.evasion_attack
import copy
import numpy as np
import sklearn
from ..base_attack import BaseAttacker
[docs]class Evasion_attack_sklearn(BaseAttacker):
"""Creates an adversarial example against sklearn objects based on https://arxiv.org/abs/1708.06131
Args:
target_model (sklearn): sklearn classifier
X_minus_1 (numpy.array): datasets that contains
only the class you want to misclasssify
dmax (float): max distance between the adversarial example
and initial one
max_iter (int): maxium number of iterations
gamma (float): parameter gamma of svm (used for only svm)
lam (float): trade - off parameter
t (float): step_size
h (float): a badwidtch paramter for a KDE
distance (str): type of distance such as L2 or L1
kde_type (str): type of kernel density estimator
Attributes:
target_model (sklearn): sklearn classifier
X_minus_1 (numpy.array): datasets that contains only the class you want to misclasssify
dmax (float): max distance between the adversarial example and initial one
max_iter (int): maxium number of iterations
gamma (float): parameter gamma of svm (used for only svm)
lam (float): trade - off parameter
t (float): step_size
h (float): a badwidtch paramter for a KDE
distance (str): type of distance such as L2 or L1
kde_type (str): type of kernel density estimator
n_minus_1 (int): number of rows of X_minus_1
delta_g (func): deviation of he discriminant function of a surrogate classifier f learnt on D
Raises:
ValueError: if given distance is not supported.
"""
def __init__(
self,
target_model,
X_minus_1,
dmax,
max_iter,
gamma,
lam,
t,
h,
distance="L1",
kde_type="L1",
):
super().__init__(target_model)
self.X_minus_1 = X_minus_1
self.dmax = dmax
self.max_iter = max_iter
self.gamma = gamma
self.lam = lam
self.t = t
self.h = h
self.kde_type = kde_type
self.n_minus_1 = X_minus_1.shape[0]
self.delta_g = None
self.distance = None
_ = self._detect_type_of_classifier()
if distance == "L1":
self.distance = lambda x1, x2: np.sum(np.abs(x1 - x2))
else:
raise ValueError(f"distance type {distance} is not defined")
def _detect_type_of_classifier(self):
"""Sets proper attributes based on the type of classifier
Returns:
return True (bool) if there is no error
Raises:
ValueError : if target classifier is not supported
"""
target_type = type(self.target_model)
if target_type == sklearn.svm._classes.SVC:
params = self.target_model.get_params()
kernel_type = params["kernel"]
if kernel_type == "rbf":
def kernel(xm):
return np.exp(
-self.gamma * ((xm - self.target_model.support_vectors_) ** 2)
)
def delta_kernel(xm):
return (
(-2 * self.gamma)
* kernel(xm)
* (xm - self.target_model.support_vectors_)
)
elif kernel_type == "linear":
def delta_kernel(xm):
return self.target_model.support_vectors_
elif kernel_type == "poly":
p = params["degree"]
c = self.target_model.intercept_
def delta_kernel(xm):
return (
p
* (((xm * self.target_model.support_vectors_) + c) ** (p - 1))
* self.target_model.support_vectors_
)
else:
raise ValueError(f"kernel type {kernel_type} is not supported")
self.delta_g = lambda xm: self.target_model.dual_coef_.dot(delta_kernel(xm))
else:
raise ValueError(f"target type {target_type} is not supported")
return True
def _get_delta_p(self, xm):
"""Calculates deviation of the estimated density p(xm−1 |yc = −1)
Args:
xm (np.array) : an adversarial example
Returns:
delta_p (np.array) : deviation of p
"""
if self.kde_type == "L1":
a = -1 / (self.n_minus_1 * self.h)
b = np.exp(-(np.sum(np.abs(xm - self.X_minus_1), axis=1)) / self.h).dot(
xm - self.X_minus_1
)
delta_p = a * b
return delta_p
def _get_grad_f(self, xm, norm="l1"):
"""Calculates deviation of objective function F
Args:
xm (np.array) : an adversarial example
norm (str) : type of distance for normalization
Returns:
delta_f (np.array) : deviation of F
Raises:
ValueError : if the type of norm is not supported
"""
delta_f = self.delta_g(xm) - self.lam * self._get_delta_p(xm)
if norm == "l1":
delta_f /= np.sum(np.abs(delta_f)) + 1e-5
elif norm == "l2":
delta_f /= np.sqrt(np.sum(delta_f**2, axis=0)) + 1e-5
else:
raise ValueError(f"norm type {norm} is not defined")
return delta_f
[docs] def attack(self, x0):
"""Executes evasion attack
Args:
x0 (np.array) : initial data point
Returns:
xm (np.array) : created adversarial example
g_list (list) : lof of decision function (only for svm)
(need future improvement)
"""
g_list = []
xm = copy.copy(x0)
for i in range(self.max_iter):
delta_f = self._get_grad_f(xm)
xm -= self.t * delta_f.reshape(-1)
d = self.distance(xm, x0) # + i * (10/255)
if d > self.dmax:
xm = x0 + ((xm - x0) / d) * self.dmax
g_list.append(self.target_model.decision_function(xm.reshape(1, -1)))
return xm, g_list