-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwhite_box_attack.py
162 lines (125 loc) · 5.26 KB
/
white_box_attack.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#!/usr/bin/env python
import torch
import argparse
from src.loadopts import *
from src.utils import timemeter
from src.config import SAVED_FILENAME
METHOD = "WhiteBox"
FMT = "{description}={attack}-{epsilon_min:.4f}-{epsilon_max}-{epsilon_times}-{stepsize:.5f}-{steps}"
parser = argparse.ArgumentParser()
parser.add_argument("model", type=str)
parser.add_argument("dataset", type=str)
parser.add_argument("info_path", type=str)
parser.add_argument("--filename", type=str, default=SAVED_FILENAME)
# adversarial settings
parser.add_argument("--attack", type=str, default="pgd-linf")
parser.add_argument("--epsilon_min", type=float, default=8/255)
parser.add_argument("--epsilon_max", type=float, default=1.)
parser.add_argument("--epsilon_times", type=int, default=1)
parser.add_argument("--stepsize", type=float, default=0.25,
help="pgd:rel_stepsize, cwl2:step_size, deepfool:overshoot, bb:lr")
parser.add_argument("--steps", type=int, default=20)
# basic settings
parser.add_argument("-b", "--batch_size", type=int, default=256)
parser.add_argument("--transform", type=str, default='tensor,none')
parser.add_argument("--progress", action="store_false", default=True,
help="show the progress if true")
parser.add_argument("--log2file", action="store_false", default=True,
help="False: remove file handler")
parser.add_argument("--log2console", action="store_false", default=True,
help="False: remove console handler if log2file is True ...")
parser.add_argument("--seed", type=int, default=1)
parser.add_argument("--benchmark", action="store_false", default=True,
help="cudnn.benchmark == True ?")
parser.add_argument("-m", "--description", type=str, default=METHOD)
opts = parser.parse_args()
opts.description = FMT.format(**opts.__dict__)
@timemeter("Setup")
def load_cfg() -> 'Config':
from src.dict2obj import Config
from src.base import FBAdversary
from src.utils import set_seed, activate_benchmark, load, set_logger
from models.base import ADArch
cfg = Config()
# generate the log path
_, cfg['log_path'] = generate_path(
method=METHOD, dataset_type=opts.dataset,
model=opts.model, description=opts.description
)
# set logger
logger = set_logger(
path=cfg.log_path,
log2file=opts.log2file,
log2console=opts.log2console
)
logger.debug(opts.info_path)
activate_benchmark(opts.benchmark)
set_seed(opts.seed)
# the model and other settings for training
model = load_model(opts.model)(num_classes=get_num_classes(opts.dataset))
mean, std = load_normalizer(opts.dataset)
model = ADArch(model=model, mean=mean, std=std)
load(
model=model,
path=opts.info_path,
filename=opts.filename
)
# load the testset
testset = load_dataset(
dataset_type=opts.dataset,
transforms=opts.transform,
train=False
)
cfg['testloader'] = load_dataloader(
dataset=testset,
batch_size=opts.batch_size,
train=False,
show_progress=opts.progress
)
# set the attacker
attack = load_fb_attack(
attack_type=opts.attack,
stepsize=opts.stepsize,
steps=opts.steps
)
epsilons = torch.linspace(opts.epsilon_min, opts.epsilon_max, opts.epsilon_times).tolist()
cfg['attacker'] = FBAdversary(
model=model, attacker=attack,
epsilon=epsilons
)
return cfg
@timemeter("Main")
def main(attacker, testloader, log_path):
from src.utils import distance_lp, getLogger
logger = getLogger()
running_success = [0.] * opts.epsilon_times
running_distance_linf = [0.] * opts.epsilon_times
running_distance_l2 = [0.] * opts.epsilon_times
for inputs, labels in testloader:
inputs = inputs.to(attacker.device)
labels = labels.to(attacker.device)
_, clipped, is_adv = attacker(inputs, labels)
dim_ = list(range(1, inputs.dim()))
for epsilon in range(opts.epsilon_times):
inputs_ = inputs[is_adv[epsilon]]
clipped_ = clipped[epsilon][is_adv[epsilon]]
running_success[epsilon] += is_adv[epsilon].sum().item()
running_distance_linf[epsilon] += distance_lp(inputs_, clipped_, p=float('inf'), dim=dim_).sum().item()
running_distance_l2[epsilon] += distance_lp(inputs_, clipped_, p=2, dim=dim_).sum().item()
datasize = len(testloader.dataset)
for epsilon in range(opts.epsilon_times):
running_distance_linf[epsilon] /= running_success[epsilon]
running_distance_l2[epsilon] /= running_success[epsilon]
running_success[epsilon] /= datasize
running_accuracy = list(map(lambda x: 1. - x, running_success))
running_accuracy = ', '.join([f"{acc:.3%}" for acc in running_accuracy])
running_distance_linf = ', '.join([f"{dis_linf:.5f}" for dis_linf in running_distance_linf])
running_distance_l2 = ', '.join([f"{dis_l2:.5f}" for dis_l2 in running_distance_l2])
logger.info(f"Accuracy: {running_accuracy}")
logger.info(f"Distance-Linf: {running_distance_linf}")
logger.info(f"Distance-L2: {running_distance_l2}")
if __name__ == "__main__":
from src.utils import readme
cfg = load_cfg()
readme(cfg.log_path, opts, mode="a")
main(**cfg)