├── README.md ├── paper ├── DFAL_actif.pdf ├── DFAL_supplementary.pdf └── supplementary_Transferability.pdf ├── bayesian_cnn.py ├── regulizer.py ├── core_set.py ├── adversarial_active_criterion.py └── active_framework.py /README.md: -------------------------------------------------------------------------------- 1 | # Adversarial_Active_Learning 2 | Adversarial Active Learning for Deep Networks 3 | -------------------------------------------------------------------------------- /paper/DFAL_actif.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AAAI2018submission/Adversarial_Active_Learning/HEAD/paper/DFAL_actif.pdf -------------------------------------------------------------------------------- /paper/DFAL_supplementary.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AAAI2018submission/Adversarial_Active_Learning/HEAD/paper/DFAL_supplementary.pdf -------------------------------------------------------------------------------- /paper/supplementary_Transferability.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AAAI2018submission/Adversarial_Active_Learning/HEAD/paper/supplementary_Transferability.pdf -------------------------------------------------------------------------------- /bayesian_cnn.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Mon Nov 13 14:10:27 2017 4 | 5 | @author: mducoffe 6 | 7 | Bayesian CNN 8 | """ 9 | import keras.backend as K 10 | import numpy as np 11 | 12 | def predict_bayesian(model): 13 | 14 | f = K.function([K.learning_phase(), model.get_input_at(0)], model.get_output_at(0)) 15 | 16 | def function(x): 17 | return f([1, x]) 18 | 19 | return function 20 | 21 | def bald(data, model, T): 22 | f_bayes = predict_bayesian(model) 23 | samples = np.array([ f_bayes(data) for i in range(T)]) # shape (T, N, c) 24 | var_A = (1./T)*np.sum(samples, axis=0) 25 | var_B = np.log(var_A) 26 | 27 | var_C = (1./T)*np.sum(samples*np.log(samples), axis=(0,2)) 28 | 29 | bald_scores = -np.sum(var_A*var_B, axis=1) + var_C 30 | 31 | index = np.argsort(bald_scores)[::-1] 32 | 33 | return index 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /regulizer.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Mon Dec 18 11:30:26 2017 4 | 5 | @author: mducoffe 6 | 7 | SVD regularization 8 | """ 9 | import keras 10 | import keras.backend as K 11 | import numpy as np 12 | from numpy.linalg import norm 13 | from keras.regularizers import Regularizer 14 | from keras.constraints import Constraint 15 | 16 | def get_SVD(Mat): 17 | #Mat = mat.get_value() 18 | n = Mat.shape[0] 19 | m = Mat.shape[1] 20 | 21 | v_0 = np.random.ranf(m) 22 | 23 | error = 11 24 | for i in range(1): 25 | w_1=np.dot(Mat, v_0) 26 | alpha_1=norm(w_1) 27 | u_1=w_1/alpha_1 28 | z_1=np.dot(Mat.T, u_1) 29 | beta_1=norm(z_1) 30 | v_1=z_1/beta_1 31 | 32 | v_0=v_1 33 | 34 | error = norm( np.dot(Mat, v_1)-beta_1*u_1) 35 | return beta_1, u_1.astype('float32'), v_1.astype('float32') 36 | # return u_1, v_1 37 | 38 | def get_SVD_support(mat, U, V): 39 | Mat = mat.get_value() 40 | _, u, v = get_SVD(Mat) 41 | U.set_value(u) 42 | V.set_value(v) 43 | 44 | #%% 45 | def get_SVD_gpu(Mat): 46 | n = Mat.shape[0] 47 | m = Mat.shape[1] 48 | 49 | 50 | #%% 51 | class SVD_Lipschitz(Regularizer): 52 | """Regularizer for maximum singular value. 53 | # Arguments 54 | """ 55 | 56 | def __init__(self, alpha=1.): 57 | self.alpha=alpha 58 | self.shape=None 59 | self.U=None 60 | self.V=None 61 | 62 | def svd(self, x): 63 | if self.shape is None: 64 | self.shape=x.shape.eval() 65 | self.U=K.variable(np.zeros((self.shape[0],))) 66 | self.V=K.variable(np.zeros((self.shape[1],))) 67 | 68 | get_SVD_support(x, self.U, self.V) 69 | return K.dot(self.U, K.dot(x, self.V)) 70 | 71 | def __call__(self, x): 72 | regularization = 0. 73 | 74 | if x.ndim==2: 75 | regularization=self.svd(x) 76 | return self.alpha*regularization 77 | 78 | def get_config(self): 79 | return {} 80 | 81 | def get_regularizer(reg_name, reg_value): 82 | if reg_name is None: 83 | return None 84 | assert (reg_name in ['l2', 'spectral']), ('unknown regularization method {}'.format(reg_name)) 85 | 86 | reg_obj=None 87 | if reg_name=='spectral': 88 | reg_obj= SVD_Lipschitz(reg_value) 89 | if reg_name=='jacobian': 90 | raise NotImplementedError() 91 | if reg_name=='l2': 92 | reg_obj=keras.regularizers.l2(0.) 93 | 94 | return reg_obj 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /core_set.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Wed Jan 24 08:57:40 2018 4 | 5 | @author: mducoffe 6 | 7 | heuristic for the k center problem 8 | with distance metric d 9 | """ 10 | 11 | # Mixed Integer Programming Solver 12 | from ortools.linear_solver import pywraplp 13 | import numpy as np 14 | 15 | def create_variables(solver, N=100): 16 | # create u : N variables 17 | u = [solver.IntVar(0.0, 1.1, 'u_{}'.format(i)) for i in range(N)] 18 | # create w: NxN variables 19 | w = [[solver.IntVar(-0.1, 1.1, 'w_{}_{}'.format(i, j)) for i in range(N)] for j in range(N)] 20 | # create eta: NxN variables 21 | e= [[solver.IntVar(0.0, 1.1, 'e_{}_{}'.format(i, j)) for i in range(N)] for j in range(N)] 22 | 23 | return u, w, e 24 | 25 | def create_constraints(solver, u, w, e, dict_values, delta): 26 | b = dict_values['b'] 27 | s_0 = dict_values['s_0'] 28 | 29 | N = len(u) 30 | constraints=[] 31 | 32 | constraints_1 = [[solver.Constraint(-solver.infinity(), 0) for i in range(N)] for j in range(N)] 33 | constraints_2 =[] 34 | constraints_3 = [] 35 | constraints_4 = [solver.Constraint(1, 1) for i in range(N)] 36 | constraint_5 = solver.Constraint(len(s_0)+b, len(s_0)+b) 37 | for i in range(N): 38 | constraint_5.SetCoefficient(u[i], 1.) 39 | 40 | if i in s_0: 41 | constraint_3_tmp = solver.Constraint(1, 1) 42 | constraint_3_tmp.SetCoefficient(u[i], 1.) 43 | constraints_3.append(constraint_3_tmp) 44 | 45 | for j in range(N): 46 | 47 | constraints_1[i][j].SetCoefficient(u[i], -1.) 48 | constraints_1[i][j].SetCoefficient(w[i][j], 1.) 49 | 50 | if delta[i][j]==0: 51 | constraint_2_tmp = solver.Constraint(0, 0) 52 | constraint_2_tmp.SetCoefficient(w[j][i], 1.) 53 | constraint_2_tmp.SetCoefficient(e[j][i], -1.) 54 | constraints_2.append(constraint_2_tmp) 55 | constraints_4[i].SetCoefficient(w[j][i], 1.) 56 | 57 | 58 | 59 | constraints+=constraints_1 60 | constraints+=constraints_2 61 | constraints+=constraints_3 62 | #constraints+=constraints_4 63 | #constraints.append(constraint_5) 64 | 65 | return constraints 66 | 67 | def create_objective(solver, e): 68 | objective = solver.Objective() 69 | N = len(e) 70 | for i in range(N): 71 | for j in range(N): 72 | objective.SetCoefficient(e[i][j], 1.) 73 | objective.SetMinimization() 74 | 75 | def feasible(dict_values, delta): 76 | solver = pywraplp.Solver('CoreSetIntegerProblem', 77 | pywraplp.Solver.CBC_MIXED_INTEGER_PROGRAMMING) 78 | N = len(delta) 79 | u,w, e = create_variables(solver, N) 80 | constraints=create_constraints(solver, u, w, e, dict_values, delta) 81 | objective=create_objective(solver, e) 82 | 83 | # Invoke the solver and display the results 84 | result_status=solver.Solve() 85 | # the solution looks legit 86 | assert solver.VerifySolution(1e-7, True) 87 | 88 | u_values = [u[i].solution_value() for i in range(N)] 89 | e_values=[[e[j][i].solution_value() for i in range(N)] for j in range(N)] 90 | e_values = np.array(e_values) 91 | 92 | outliers = dict_values['outliers'] 93 | return np.sum(e_values)<=outliers, u_values 94 | 95 | """ 96 | for variable in u: 97 | print('%s=%d'%(variable.name(), variable.solution_value())) 98 | 99 | e_values=[[e[j][i].solution_value() for i in range(N)] for j in range(N)] 100 | e_values = np.array(e_values) 101 | #print(e_values) 102 | 103 | w_values=[[w[j][i].solution_value() for i in range(N)] for j in range(N)] 104 | w_values = np.array(w_values) 105 | #print(w_values) 106 | """ 107 | 108 | #%% 109 | def build_delta(model, x, threshold): 110 | 111 | 112 | N = len(x) 113 | delta = np.zeros((N,N), dtype='uint8') 114 | lb = np.inf 115 | ub = threshold 116 | for i in range(N): 117 | for j in range(N): 118 | distance = np.linalg.norm(x[i] - x[j]) 119 | if distance <= threshold: 120 | delta[i,j]=1 121 | delta[j,i]=1 122 | if distance >ub: 123 | ub = distance 124 | else: 125 | if distance=ub or (ub - lb)<5*1e-3: 168 | break 169 | 170 | n_start = len(labelled_data[0]) 171 | assignment = np.array(assignment[n_start:]) 172 | return np.where(assignment==1), np.where(assignment==0) 173 | 174 | 175 | 176 | #%% 177 | def toy_example(): 178 | delta=[] 179 | delta.append([1,1,1,0,0,0,0,0]) #0 180 | delta.append([1,1,0,0,0,0,0,0]) #1 181 | delta.append([1,0,1,0,0,0,0,0]) #2 182 | delta.append([0,0,0,1,0,0,0,0]) #3 183 | delta.append([0,0,0,0,1,1,1,0]) #4 184 | delta.append([0,0,0,0,1,1,0,0]) #5 185 | delta.append([0,0,0,0,1,0,1,0]) #6 186 | delta.append([0,0,0,0,0,0,0,1]) #7 187 | 188 | delta = np.array(delta).astype(np.uint) 189 | 190 | s_0=[4] 191 | outliers=1 192 | b=1 193 | dict_values={'s_0':s_0, 'outliers': outliers, 'b':b} 194 | 195 | bool_test, centroids = feasible(dict_values, delta) 196 | print(bool_test) 197 | 198 | 199 | 200 | 201 | #%% 202 | if __name__=="__main__": 203 | # Instantiate a mixed-integer solver, naming it SolveIntegerProblem. 204 | toy_example() 205 | -------------------------------------------------------------------------------- /adversarial_active_criterion.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Éditeur de Spyder 4 | 5 | Ceci est un script temporaire. 6 | 7 | author : mducoffe 8 | 9 | Step 1 : deep fool as an active learning criterion 10 | """ 11 | import numpy as np 12 | import keras.backend as K 13 | import scipy 14 | from contextlib import closing 15 | import pickle as pkl 16 | import os 17 | from keras.models import Model 18 | 19 | 20 | class Adversarial_example(object): 21 | 22 | def __init__(self, model, n_channels=3, img_nrows=32, img_ncols=32, 23 | nb_class=10): 24 | """ 25 | if K.image_dim_ordering() == 'th': 26 | img_shape = (1, n_channels, img_nrows, img_ncols) 27 | adversarial_image = K.placeholder((1, n_channels, img_nrows, img_ncols)) 28 | adversarial_target = K.placeholder((1, nb_class)) 29 | adv_noise = K.placeholder((1, n_channels, img_nrows, img_ncols)) 30 | else: 31 | img_shape = (1,img_nrows, img_ncols, n_channels) 32 | adversarial_image = K.placeholder((1, img_nrows, img_ncols, n_channels)) 33 | adversarial_target = K.placeholder((1, nb_class)) 34 | adv_noise = K.placeholder((1, img_nrows, img_ncols, n_channels)) 35 | """ 36 | 37 | img_shape = (1,n_channels, img_nrows, img_ncols) 38 | self.img_shape=img_shape 39 | adversarial_image = K.placeholder((1, n_channels, img_nrows, img_ncols)) 40 | adversarial_target = K.placeholder((1, nb_class)) 41 | adv_noise = K.placeholder((1, n_channels, img_nrows, img_ncols)) 42 | 43 | self.model = model 44 | 45 | def get_weights(): 46 | layers = self.model.layers 47 | norm_weights = 1 48 | for layer in layers: 49 | if hasattr(layer, 'kernel'): 50 | w = np.linalg.norm(layer.kernel.get_value().flatten()) 51 | norm_weights*=w 52 | return norm_weights 53 | 54 | self.norm_weights = get_weights() 55 | 56 | 57 | """ 58 | self.model.trainable=False 59 | for layer in self.model.layers: 60 | layer.trainable=False 61 | """ 62 | self.adversarial_image= adversarial_image 63 | self.adversarial_target = adversarial_target 64 | self.adv_noise = adv_noise 65 | self.img_shape = img_shape 66 | self.nb_class = nb_class 67 | 68 | 69 | prediction = self.model.call(self.adversarial_image) 70 | self.predict_ = K.function([K.learning_phase(), self.adversarial_image], K.argmax(prediction, axis=1)) 71 | 72 | def generate(data): 73 | raise NotImplementedError() 74 | 75 | def predict(self,image): 76 | return self.predict_([0, image]) 77 | 78 | def prediction(self, image): 79 | return self.output_([0, image]) 80 | 81 | def generate_sample(self, true_image): 82 | raise NotImplementedError() 83 | 84 | class Adversarial_Szegedy(Adversarial_example): 85 | 86 | def __init__(self,**kwargs): 87 | super(Adversarial_Szegedy, self).__init__(**kwargs) 88 | 89 | loss_classif=K.mean(K.categorical_crossentropy(self.model(self.adv_noise), self.adversarial_target)) +\ 90 | 0.001*K.sum(K.abs(self.adv_noise - self.adversarial_image)) 91 | 92 | grad_adversarial = K.gradients(loss_classif, self.adv_noise) 93 | 94 | f_loss = K.function([K.learning_phase(), self.adv_noise, self.adversarial_image, self.adversarial_target], loss_classif) 95 | f_grad = K.function([K.learning_phase(), self.adv_noise, self.adversarial_image, self.adversarial_target], grad_adversarial) 96 | 97 | def eval_loss(adv_label, true_image): 98 | 99 | def function(noise): 100 | r = noise.astype('float32') 101 | r = r.reshape(self.img_shape) 102 | x = true_image.astype('float32') 103 | x = x.reshape(self.img_shape) 104 | y = np.array([0.]*(self.nb_class)) 105 | # pick random choice 106 | y[adv_label] = 1. 107 | y = y[None,:] 108 | return f_loss([0, r, x, y]).astype('float64') 109 | return function 110 | 111 | self.eval_loss = eval_loss 112 | 113 | def eval_grad(adv_label, true_image): 114 | 115 | def function(noise): 116 | r = noise.astype('float32') 117 | r = r.reshape(self.img_shape) 118 | x = true_image.astype('float32') 119 | x = x.reshape(self.img_shape) 120 | y = np.array([0.]*(self.nb_class)) 121 | # pick random choice 122 | y[adv_label] = 1. 123 | y = y[None,:] 124 | return f_grad([0, r, x, y]).flatten().astype('float64') 125 | return function 126 | 127 | self.eval_grad = eval_grad 128 | prediction = self.model.call(self.adv_noise) 129 | 130 | 131 | def generate_sample(self, x, adv_label): 132 | 133 | 134 | image_adv = np.copy(x.flatten()) 135 | for i in range(100): 136 | image_adv = image_adv.flatten() 137 | eval_loss = self.eval_loss(adv_label, image_adv) 138 | eval_grad = self.eval_grad(adv_label, image_adv) 139 | noise = np.copy(x).flatten() 140 | results = scipy.optimize.fmin_l_bfgs_b(eval_loss, noise, 141 | fprime=eval_grad, 142 | maxfun=100) 143 | noise = results[0].astype('float32') 144 | image_adv = noise.reshape((self.img_shape[0], self.img_shape[1], self.img_shape[2], self.img_shape[3])) 145 | label_pred = self.predict(image_adv) 146 | if label_pred == adv_label: 147 | return image_adv, True 148 | #print('FAIL') 149 | return x, False 150 | 151 | class Adversarial_DeepFool(Adversarial_example): 152 | 153 | def __init__(self, **kwargs): 154 | super(Adversarial_DeepFool, self).__init__(**kwargs) 155 | 156 | # HERE check for the softmax 157 | 158 | # the network is evaluated without the softmax 159 | # you need to retrieve the last layer (Activation('softmax')) 160 | last_dense = self.model.layers[-2].output 161 | second_model = Model(self.model.input, last_dense) 162 | loss_classif = K.mean(second_model.call(self.adversarial_image)[0, K.argmax(self.adversarial_target)]) 163 | grad_adversarial = K.gradients(loss_classif, self.adversarial_image) 164 | self.f_loss = K.function([K.learning_phase(), self.adversarial_image, self.adversarial_target], loss_classif) 165 | self.f_grad = K.function([K.learning_phase(), self.adversarial_image, self.adversarial_target], grad_adversarial) 166 | 167 | def eval_loss(x,y): 168 | y_vec = np.zeros((1, self.nb_class)) 169 | y_vec[:,y] +=1 170 | return self.f_loss([0., x, y_vec]) 171 | 172 | def eval_grad(x,y): 173 | y_vec = np.zeros((1, self.nb_class)) 174 | y_vec[:,y] +=1 175 | return self.f_grad([0., x, y_vec]) 176 | 177 | self.eval_loss = eval_loss 178 | self.eval_grad = eval_grad 179 | 180 | 181 | def generate(self, data, option='euclidian'): 182 | #perturbations=[self.generate_sample(data[i:i+1]) for i in range(len(data))] 183 | 184 | perturbations = [] 185 | adv_attacks = [] 186 | for i in range(len(data)): 187 | r_i, x_i = self.generate_sample(data[i:i+1], option=option) 188 | perturbations.append(r_i) 189 | adv_attacks.append(x_i[0]) 190 | 191 | """ 192 | # compute also the second bar 193 | uncertainty = [] 194 | for i in range(len(data)): 195 | uncertainty.append(self.lower_bound_sample(data[i:i+1])) 196 | """ 197 | 198 | index_perturbation = np.argsort(perturbations) 199 | tmp = np.array(adv_attacks) 200 | return index_perturbation, tmp[index_perturbation] 201 | """ 202 | uncertainty = np.array(uncertainty)/self.norm_weights 203 | index_perturbation = np.argsort(perturbations) 204 | 205 | perturbations = perturbations[index_perturbation] 206 | uncertainty = uncertainty[index_perturbation] 207 | 208 | N = len(data) 209 | sorted_index = np.arange(N) 210 | 211 | sorted_index = self.priv_sort_interval(perturbations, uncertainty, sorted_index) 212 | import pdb; pdb.set_trace() 213 | index_perturbation = index_perturbation[sorted_index] 214 | #return np.argsort(perturbations) 215 | return index_perturbation 216 | """ 217 | 218 | def priv_sort_interval(self,array_a, array_b, sorted_index): 219 | 220 | # array_a : upper bound 221 | # array_b : lower bound 222 | N = len(array_a) 223 | for i in range(N-1): 224 | index_0 = sorted_index[i] 225 | index_1 = sorted_index[i+1] 226 | if array_a[index_0]<=array_b[index_1]: 227 | continue 228 | # array_a[i] > array_b[i+1] 229 | if array_b[index_1]>=array_b[index_0]: 230 | continue 231 | 232 | if array_b[index_0]> array_b[index_1]: 233 | proba = (array_b[index_0] - array_b[index_1])/(array_a[index_0] - array_b[index_1]) 234 | if proba >=0.5: 235 | 236 | sorted_index[i]=index_1 237 | sorted_index[i+1]=index_0 238 | return self.priv_sort_interval(array_a, array_b, sorted_index) 239 | else: 240 | continue 241 | return sorted_index 242 | 243 | 244 | def lower_bound_sample(self, true_image): 245 | true_label = self.predict(true_image) 246 | f_x = self.model.predict(true_image).flatten() 247 | 248 | score = np.inf 249 | index=-1 250 | for i in range(self.nb_class): 251 | if i==true_label: 252 | continue 253 | vector = np.zeros((self.nb_class)) 254 | vector[true_label]=np.sqrt(2) 255 | vector[i]=-np.sqrt(2) 256 | score_i = np.dot(vector, f_x) 257 | 258 | if score_i