-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathattack.py
122 lines (107 loc) · 3.81 KB
/
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
import os
import os.path as osp
import pickle
import random
import json
import argparse
import copy
import itertools
import numpy as np
import scipy.sparse as sp
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.nn.init as init
import torch.optim as optim
class AttackerStep:
'''
Generic class for attacker steps, under perturbation constraints
specified by an "origin input" and a perturbation magnitude.
Must implement project, step, and random_perturb
'''
def __init__(self, orig_input, B, eta, delta, alpha, C=None, use_grad=True):
'''
Initialize the attacker step with a given perturbation magnitude.
Args:
eps (float): the perturbation magnitude
orig_input (ch.tensor): the original input
'''
self.orig_input = orig_input # torch type
self.B = B
self.eta = eta
self.delta = delta
self.alpha = alpha
self.C = C
self.use_grad = use_grad
def project(self, s,radius=1.):
'''
Given an input s, project it back into the feasible set
Args:
ch.tensor s : the input to project back into the feasible set.
Returns:
A `ch.tensor` that is the input projected back into
the feasible set, that is,
.. math:: \min_{s' \in S} \|s' - s\|_2
'''
raise NotImplementedError
def step(self, s, g):
'''
Given a gradient, make the appropriate step according to the
perturbation constraint (e.g. dual norm maximization for :math:`\ell_p`
norms).
Parameters:
g (ch.tensor): the raw gradient
Returns:
The new input, a ch.tensor for the next step.
'''
raise NotImplementedError
def random_perturb(self, s):
'''
Given a starting input, take a random step within the feasible set
'''
raise NotImplementedError
class BlackBoxStep(AttackerStep):
def __init__(self, orig_input, B, eta, delta, alpha, attack_loss,C=None, costVector = None, use_grad=False,cuda=True):
super( BlackBoxStep, self).__init__(orig_input, B, eta, delta, alpha, C, use_grad)
self.attack_loss = attack_loss
self.N = orig_input.numel()
self.cuda=cuda
self.costVector = costVector
self.vt = torch.zeros(self.N)
def project(self, s,radius=1.):
s = s.unsqueeze(0)
s = s.renorm(p=1, dim=0, maxnorm=radius*self.B)
if self.C != None:
s = s * self.costVector
s = s.renorm(p=1, dim=0, maxnorm=radius*self.C)
s = s.view(-1)
return s
def step(self, s, g): # v_{t+1}
update = s - self.eta * g
update = self.project(update,1-self.alpha)
return update
def random_perturb(self):
top_B = random.sample(range(self.N),self.B)
st = torch.zeros(self.N)
st[top_B] = 1
return st
def randomUnitVector(self):
vec = np.array([np.random.normal(0., 1.) for i in range(self.N)])
mag = np.linalg.norm(vec)
return vec / mag
def Bandit_step(self,node):
with torch.no_grad():
if self.cuda:
u = torch.from_numpy(self.randomUnitVector()).cuda()
else:
u = torch.from_numpy(self.randomUnitVector())
self.vt = self.vt + self.delta * u
top_B = self.vt.sort(descending=True).indices[:self.B]
st = torch.zeros(self.N)
st[top_B] = 1
L = self.attack_loss(st,node,0)
sign=1
coef=self.N/self.delta
gradEst = coef*sign*L* u
self.vt = self.step(self.vt,gradEst)
return st