Source code for hyperion.torch.adv_attacks.art_attack_factory

"""
 Copyright 2020 Johns Hopkins University  (Author: Jesus Villalba)
 Apache 2.0  (http://www.apache.org/licenses/LICENSE-2.0)
"""

from jsonargparse import ArgumentParser, ActionParser
import numpy as np

try:
    from art.attacks import evasion as attacks
except ImportError:
    pass


[docs]class ARTAttackFactory(object):
[docs] @staticmethod def create( model, attack_type, eps=0, delta=0.01, step_adapt=0.667, num_trial=25, sample_size=20, init_size=100, norm=np.inf, eps_step=0.1, num_random_init=0, minimal=False, random_eps=False, min_eps=None, beta=0.001, theta=0.1, gamma=1.0, etha=0.01, confidence=0.0, lr=1e-2, lr_decay=0.5, lr_num_decay=20, momentum=0.8, binary_search_steps=9, max_iter=10, overshoot=1.1, num_grads=10, c=1e-3, max_halving=5, max_doubling=5, decision_rule="EN", init_eval=100, max_eval=10000, num_parallel=128, variable_h=1e-4, use_importance=False, abort_early=True, th=None, sigma=0.5, lambda_tv=0.3, labmda_c=1.0, lambda_s=0.5, reg=3000, kernel_size=5, eps_factor=1.1, eps_iter=10, conj_sinkhorn_iter=400, proj_sinkhorn_iter=400, targeted=False, num_samples=1, eps_scale=1, batch_size=1, ): eps = eps * eps_scale eps_step = eps_step * eps_scale if min_eps is not None: min_eps = min_eps * eps_scale attack_set = set( ["fgm", "pgd", "auto-pgd", "boundary", "cw-linf", "wasserstein"] ) if attack_type in attack_set: if norm == 1: eps = eps * num_samples eps_step = eps_step * num_samples if min_eps is not None: min_eps = min_eps * num_samples elif norm == 2 or attack_type in ["wasserstein"]: eps = eps * np.sqrt(num_samples) eps_step = eps_step * np.sqrt(num_samples) if min_eps is not None: min_eps = min_eps * np.sqrt(num_samples) if attack_type == "boundary": return attacks.BoundaryAttack( model, targeted=targeted, delta=delta, epsilon=eps, step_adapt=step_adapt, max_iter=max_iter, num_trials=num_trials, sample_size=sample_size, init_size=init_size, min_epsilon=min_eps, ) if attack_type == "hop-skin-jump": return attacks.HopSkinJump( model, targeted=targeted, norm=norm, max_iter=max_iter, max_eval=max_eval, init_eval=init_eval, init_size=init_size, ) if attack_type == "brendel": return attacks.BrendelBethgeAttack( model, norm=norm, targeted=targeted, overshoot=overshoot, steps=max_iter, lr=lr, lr_decay=lr_decay, lr_num_decay=lr_num_decay, momentum=momentum, binary_search_steps=binary_search_steps, init_size=init_size, batch_size=batch_size, ) if attack_type == "deepfool": attacks.DeepFool( model, max_iter=max_iter, epsilon=eps, nb_grads=num_grads, batch_size=batch_size, ) if attack_type == "elasticnet": attacks.ElasticNet( model, confidence=confidence, targeted=targeted, learning_rate=lr, binary_search_steps=binary_search_steps, max_iter=max_iter, beta=beta, initial_const=c, batch_size=batch_size, decision_rule=decision_rule, ) if attack_type == "threshold": attacks.ThresholdAttack(model, th=th, es=es, targeted=targeted) if attack_type == "fgm": return attacks.FastGradientMethod( model, norm=norm, eps=eps, eps_step=eps_step, targeted=targeted, num_random_init=num_random_init, minimal=minimal, batch_size=batch_size, ) if attack_type == "bim": return attacks.BasicIterativeMethod( model, eps=eps, eps_step=eps_step, max_iter=max_iter, targeted=targeted, batch_size=batch_size, ) if attack_type == "pgd": return attacks.ProjectedGradientDescentPyTorch( model, norm=norm, eps=eps, eps_step=eps_step, max_iter=max_iter, targeted=targeted, num_random_init=num_random_init, random_eps=random_eps, batch_size=batch_size, ) if attack_type == "auto-pgd": return attacks.AutoProjectedGradientDescent( model, norm=norm, eps=eps, eps_step=eps_step, max_iter=max_iter, targeted=targeted, nb_random_init=num_random_init, random_eps=random_eps, batch_size=batch_size, ) if attack_type == "jsma": return attacks.SaliencyMapMethod( model, theta=theta, gamma=gamma, batch_size=batch_size ) if attack_type == "newtonfool": return attacks.NewtonFool( model, eta=eta, max_iter=max_iter, batch_size=batch_size ) if attack_type == "threshold": return attacks.NewtonFool( model, eta=eta, max_iter=max_iter, batch_size=batch_size ) if attack_type == "cw-l2": return attacks.CarliniL2Method( model, confidence, learning_rate=lr, binary_search_steps=binary_search_steps, max_iter=max_iter, initial_const=c, targeted=targeted, max_halving=max_halving, max_doubling=max_doubling, batch_size=batch_size, ) if attack_type == "cw-linf": return attacks.CarliniLInfMethod( model, confidence, learning_rate=lr, max_iter=max_iter, targeted=targeted, max_halving=max_halving, max_doubling=max_doubling, eps=eps, batch_size=batch_size, ) if attack_type == "zoo": return attacks.ZooMethod( model, confidence, learning_rate=lr, max_iter=max_iter, initial_const=c, targeted=targeted, binary_search_steps=binary_search_steps, abort_early=abort_early, use_resize=False, use_importance=use_importance, nb_parallel=num_parallel, variable_h=variable_h, batch_size=batch_size, ) if attack_type == "shadow": return attacks.ShadowAttack( model, sigma=sigma, num_steps=num_iters, learning_rate=lr, lambda_tv=lambda_tv, lambda_c=lambda_c, lambda_s=lambda_s, batch_norm=batch_norm, targeted=targeted, ) if attack_type == "wasserstein": return attacks.Wasserstein( model, targeted=targeted, regularization=reg, kernel_size=kernel_size, eps=eps, eps_step=eps_step, eps_factor=eps_factor, eps_iter=eps_iter, max_iter=max_iter, conjugate_sinkhorn_max_iter=conj_sinkhorn_iter, projected_sinkhorn_max_iter=proj_sinkhorn_iter, batch_size=batch_size, ) raise Exception("%s is not a valid attack type" % (attack_type))
[docs] @staticmethod def filter_args(**kwargs): if "no_abort" in kwargs: kwargs["abort_early"] = not kwargs["no_abort"] if "norm" in kwargs: if kwargs["norm"] == "inf": kwargs["norm"] = np.inf else: kwargs["norm"] = int(kwargs["norm"]) valid_args = ( "attack_type", "eps", "delta", "step_adapt", "num_trial", "sample_size", "init_size", "norm", "eps_step", "num_random_init", "minimal", "random_eps", "min_eps", "beta", "theta", "gamma", "etha", "confidence", "decision_rule", "lr", "lr_decay", "lr_num_decay", "momentum", "binary_search_steps", "max_iter", "init_eval", "max_eval", "overshoot", "num_grads", "c", "max_halving", "max_doubling", "variable_h", "abort_early", "num_parallel", "use_importance", "th", "sigma", "lambda_tv", "labmda_c", "lambda_s", "reg", "kernel_size", "eps_factor", "eps_iter", "conj_sinkhorn_iter", "proj_sinkhorn_iter", "targeted", ) args = dict((k, kwargs[k]) for k in valid_args if k in kwargs) return args
[docs] @staticmethod def add_class_args(parser, prefix=None): if prefix is not None: outer_parser = parser parser = ArgumentParser(prog="") parser.add_argument( "--attack-type", type=str.lower, default="fgsm", choices=[ "boundary", "brendel", "deepfool", "fgm", "bim", "pgd", "auto-pgd", "jsma", "newtonfool", "cw-l2", "cw-linf", "elasticnet", "hop-skin-jump", "zoo", "threshold", "shadow", "wasserstein", ], help=("Attack type"), ) parser.add_argument( "--norm", type=str.lower, default="inf", choices=["inf", "1", "2"], help=("Attack norm"), ) parser.add_argument( "--eps", default=0, type=float, help=("attack epsilon, upper bound for the perturbation norm"), ) parser.add_argument( "--eps-step", default=0.1, type=float, help=("Step size of input variation for minimal perturbation computation"), ) parser.add_argument( "--delta", default=0.1, type=float, help=("Initial step size for the orthogonal step in boundary-attack"), ) parser.add_argument( "--step-adapt", default=0.667, type=float, help=( "Factor by which the step sizes are multiplied or divided, " "must be in the range (0, 1)." ), ) parser.add_argument( "--confidence", default=0, type=float, help=("confidence for carlini-wagner attack"), ) parser.add_argument( "--lr", default=1e-2, type=float, help=("learning rate for attack optimizers"), ) parser.add_argument( "--lr-decay", default=0.5, type=float, help=("learning rate decay for attack optimizers"), ) parser.add_argument( "--lr-num-decay", default=10, type=int, help=("learning rate decay steps for attack optimizers"), ) parser.add_argument( "--momentum", default=0.8, type=float, help=("momentum for attack optimizers"), ) parser.add_argument( "--overshoot", default=1.1, type=float, help=("overshoot param. for Brendel attack"), ) parser.add_argument( "--binary-search-steps", default=9, type=int, help=("num bin. search steps in carlini-wagner-l2 attack"), ) parser.add_argument( "--max-iter", default=10, type=int, help=("max. num. of optim iters in attack"), ) parser.add_argument( "--num-trial", default=25, type=int, help=("Maximum number of trials per iteration (boundary attack)."), ) parser.add_argument( "--num-grads", default=10, type=int, help=("number of class gradients (deepfool attack)."), ) parser.add_argument( "--sample-size", default=20, type=int, help=("Number of samples per trial (boundary attack)."), ) parser.add_argument( "--init-size", default=100, type=int, help=( "Maximum number of trials for initial generation of " "adversarial examples. (boundary attack)." ), ) parser.add_argument( "--init-eval", default=100, type=int, help=("Initial number of evaluations for estimating gradient."), ) parser.add_argument( "--max-eval", default=10000, type=int, help=("Maximum number of evaluations for estimating gradient."), ) parser.add_argument( "--num-random-init", default=0, type=int, help=( "Number of random initialisations within the epsilon ball. " "For random_init=0 starting at the original input." ), ) parser.add_argument( "--minimal", default=False, action="store_true", help=( "Indicates if computing the minimal perturbation (True). " "If True, also define eps_step for the step size and eps " "for the maximum perturbation." ), ) parser.add_argument( "--random-eps", default=False, action="store_true", help=( "When True, epsilon is drawn randomly from " "truncated normal distribution. " "The literature suggests this for FGSM based training to " "generalize across different epsilons. eps_step is modified " "to preserve the ratio of eps / eps_step. " "The effectiveness of this method with PGD is untested" ), ) parser.add_argument( "--min-eps", default=None, type=float, help=("Stop attack if perturbation is smaller than min_eps."), ) parser.add_argument( "--theta", default=0.1, type=float, help=( "Amount of Perturbation introduced to each modified " "feature per step (can be positive or negative)." ), ) parser.add_argument( "--gamma", default=1.0, type=float, help=("Maximum fraction of features being perturbed (between 0 and 1)."), ) parser.add_argument( "--beta", default=0.001, type=float, help=("Hyperparameter trading off L2 minimization for L1 minimization"), ) parser.add_argument( "--decision-rule", default="EN", choices=["EN", "L1", "L2"], help=( "Decision rule. ‘EN’ means Elastic Net rule, ‘L1’ means L1 rule, ‘L2’ means L2 rule. (elasticnet)" ), ) parser.add_argument( "--eta", default=0.01, type=float, help=("Eta coeff. for NewtonFool") ) parser.add_argument( "--c", default=1e-2, type=float, help=("Initial weight of constraint function f in carlini-wagner attack"), ) parser.add_argument( "--max-halving", default=5, type=int, help=("Maximum number of halving steps in the line search optimization."), ) parser.add_argument( "--max-doubling", default=5, type=int, help=("Maximum number of doubling steps in the line search optimization."), ) parser.add_argument( "--no-abort", default=False, action="store_true", help=("do not abort early in optimizer iterations"), ) parser.add_argument( "--use-importance", default=False, action="store_true", help=("to use importance sampling when choosing coordinates to update."), ) parser.add_argument( "--variable-h", default=0.0001, type=float, help=("Step size for numerical estimation of derivatives."), ) parser.add_argument( "--num-parallel", default=128, type=int, help=("Number of coordinate updates to run in parallel"), ) parser.add_argument( "--th", default=None, type=int, help=( "Threshold for threshold attack, None indicates finding and minimum threshold" ), ) parser.add_argument( "--sigma", default=0.5, type=float, help=("Standard deviation random Gaussian Noise"), ) parser.add_argument( "--lambda-tv", default=0.3, type=float, help=( "Scalar penalty weight for total variation of the perturbation (shadow)" ), ) parser.add_argument( "--lambda-c", default=1.0, type=float, help=( "Scalar penalty weight for change in the mean of each color channel of the perturbation" ), ) parser.add_argument( "--lambda-s", default=0.5, type=float, help=( "Scalar penalty weight for similarity of color channels in perturbation" ), ) parser.add_argument( "--reg", default=3000, type=float, help=("Entropy regularization.(wasserstein)"), ) parser.add_argument( "--kernel-size", default=5, type=int, help=("Kernel size for computing the cost matrix"), ) parser.add_argument( "--eps-factor", default=1.1, type=float, help=("Factor to increase the epsilon"), ) parser.add_argument( "--eps-iter", default=10, type=int, help=("Number of iterations to increase the epsilon."), ) parser.add_argument( "--conj-sinkhorn-iter", default=400, type=int, help=("maximum number of iterations for the conjugate sinkhorn optimizer"), ) parser.add_argument( "--proj-sinkhorn-iter", default=400, type=int, help=("maximum number of iterations for the projected sinkhorn optimizer"), ) parser.add_argument( "--targeted", default=False, action="store_true", help="use targeted attack intead of non-targeted", ) if prefix is not None: outer_parser.add_argument("--" + prefix, action=ActionParser(parser=parser))
# help='ART attack options') add_argparse_args = add_class_args