├── CIFAR-10 ├── attack.py ├── evaluate.py ├── fol_guided_fuzzing.py ├── gen_adv.py ├── metrics.py ├── models.py ├── select_retrain.py └── train_model.py ├── FASHION ├── models.py └── train_model.py ├── LICENSE ├── MNIST ├── attack.py ├── evaluate.py ├── fol_guided_fuzzing.py ├── gen_adv.py ├── metrics.py ├── mnist.npz ├── models.py ├── select_retrain.py └── train_model.py ├── README.md ├── SVHN ├── models.py └── train_model.py └── metrics.py /CIFAR-10/attack.py: -------------------------------------------------------------------------------- 1 | from tensorflow import keras 2 | import tensorflow as tf 3 | import numpy as np 4 | 5 | 6 | 7 | class FGSM: 8 | """ 9 | We use FGSM to generate a batch of adversarial examples. 10 | """ 11 | def __init__(self, model, ep=0.01, isRand=True): 12 | """ 13 | isRand is set True to improve the attack success rate. 14 | """ 15 | self.isRand = isRand 16 | self.model = model 17 | self.ep = ep 18 | 19 | def generate(self, x, y, randRate=1): 20 | """ 21 | x: clean inputs, shape of x: [batch_size, width, height, channel] 22 | y: ground truth, one hot vectors, shape of y: [batch_size, N_classes] 23 | """ 24 | fols = [] 25 | target = tf.constant(y) 26 | 27 | xi = x.copy() 28 | if self.isRand: 29 | x = x + np.random.uniform(-self.ep * randRate, self.ep * randRate, x.shape) 30 | x = np.clip(x, 0, 1) 31 | 32 | x = tf.Variable(x) 33 | with tf.GradientTape() as tape: 34 | loss = keras.losses.categorical_crossentropy(target, self.model(x)) 35 | grads = tape.gradient(loss, x) 36 | delta = tf.sign(grads) 37 | x_adv = x + self.ep * delta 38 | 39 | x_adv = tf.clip_by_value(x_adv, clip_value_min=xi-self.ep, clip_value_max=xi+self.ep) 40 | x_adv = tf.clip_by_value(x_adv, clip_value_min=0, clip_value_max=1) 41 | 42 | idxs = np.where(np.argmax(self.model(x_adv), axis=1) != np.argmax(y, axis=1))[0] 43 | print("SUCCESS:", len(idxs)) 44 | 45 | x_adv, xi, target = x_adv.numpy()[idxs], xi[idxs], target.numpy()[idxs] 46 | x_adv, target = tf.Variable(x_adv), tf.constant(target) 47 | 48 | preds = self.model(x_adv).numpy() 49 | ginis = np.sum(np.square(preds), axis=1) 50 | 51 | with tf.GradientTape() as tape: 52 | loss = keras.losses.categorical_crossentropy(target, self.model(x_adv)) 53 | grads = tape.gradient(loss, x_adv) 54 | grad_norm = np.linalg.norm(grads.numpy().reshape(x_adv.shape[0], -1), ord=1, axis=1) 55 | grads_flat = grads.numpy().reshape(x_adv.shape[0], -1) 56 | diff = (x_adv.numpy() - xi).reshape(x_adv.shape[0], -1) 57 | for i in range(x_adv.shape[0]): 58 | i_fol = -np.dot(grads_flat[i], diff[i]) + self.ep * grad_norm[i] 59 | fols.append(i_fol) 60 | 61 | return x_adv.numpy(), target.numpy(), np.array(fols), ginis 62 | 63 | 64 | 65 | class PGD: 66 | """ 67 | We use PGD to generate a batch of adversarial examples. PGD could be seen as iterative version of FGSM. 68 | """ 69 | def __init__(self, model, ep=0.01, step=None, epochs=10, isRand=True): 70 | """ 71 | isRand is set True to improve the attack success rate. 72 | """ 73 | self.isRand = isRand 74 | self.model = model 75 | self.ep = ep 76 | if step == None: 77 | self.step = ep/6 78 | self.epochs = epochs 79 | 80 | def generate(self, x, y, randRate=1): 81 | """ 82 | x: clean inputs, shape of x: [batch_size, width, height, channel] 83 | y: ground truth, one hot vectors, shape of y: [batch_size, N_classes] 84 | """ 85 | fols = [] 86 | target = tf.constant(y) 87 | 88 | xi = x.copy() 89 | if self.isRand: 90 | x = x + np.random.uniform(-self.ep * randRate, self.ep * randRate, x.shape) 91 | x = np.clip(x, 0, 1) 92 | 93 | x_adv = tf.Variable(x) 94 | for i in range(self.epochs): 95 | with tf.GradientTape() as tape: 96 | loss = keras.losses.categorical_crossentropy(target, self.model(x_adv)) 97 | grads = tape.gradient(loss, x_adv) 98 | delta = tf.sign(grads) 99 | x_adv.assign_add(self.step * delta) 100 | x_adv = tf.clip_by_value(x_adv, clip_value_min=xi-self.ep, clip_value_max=xi+self.ep) 101 | x_adv = tf.clip_by_value(x_adv, clip_value_min=0, clip_value_max=1) 102 | x_adv = tf.Variable(x_adv) 103 | 104 | idxs = np.where(np.argmax(self.model(x_adv), axis=1) != np.argmax(y, axis=1))[0] 105 | print("SUCCESS:", len(idxs)) 106 | 107 | x_adv, xi, target = x_adv.numpy()[idxs], xi[idxs], target.numpy()[idxs] 108 | x_adv, target = tf.Variable(x_adv), tf.constant(target) 109 | 110 | preds = self.model(x_adv).numpy() 111 | ginis = np.sum(np.square(preds), axis=1) 112 | 113 | with tf.GradientTape() as tape: 114 | loss = keras.losses.categorical_crossentropy(target, self.model(x_adv)) 115 | grads = tape.gradient(loss, x_adv) 116 | grad_norm = np.linalg.norm(grads.numpy().reshape(x_adv.shape[0], -1), ord=1, axis=1) 117 | grads_flat = grads.numpy().reshape(x_adv.shape[0], -1) 118 | diff = (x_adv.numpy() - xi).reshape(x_adv.shape[0], -1) 119 | for i in range(x_adv.shape[0]): 120 | i_fol = -np.dot(grads_flat[i], diff[i]) + self.ep * grad_norm[i] 121 | fols.append(i_fol) 122 | 123 | return x_adv.numpy(), target.numpy(), np.array(fols), ginis 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /CIFAR-10/evaluate.py: -------------------------------------------------------------------------------- 1 | from tensorflow import keras 2 | import tensorflow as tf 3 | import numpy as np 4 | import matplotlib.pyplot as plt 5 | # %matplotlib inline 6 | 7 | import os 8 | os.environ["CUDA_VISIBLE_DEVICES"]="0" 9 | 10 | gpus = tf.config.experimental.list_physical_devices('GPU') 11 | if gpus: 12 | try: 13 | for gpu in gpus: 14 | tf.config.experimental.set_memory_growth(gpu, True) 15 | except RuntimeError as e: 16 | print(e) 17 | 18 | 19 | # Load the generated adversarial inputs for Robustness evaluation. 20 | with np.load("./FGSM_Test.npz") as f: 21 | fgsm_test, fgsm_test_labels = f['advs'], f['labels'] 22 | 23 | with np.load("./PGD_Test.npz") as f: 24 | pgd_test, pgd_test_labels = f['advs'], f['labels'] 25 | 26 | fp_test = np.concatenate((fgsm_test, pgd_test)) 27 | fp_test_labels = np.concatenate((fgsm_test_labels, pgd_test_labels)) 28 | 29 | 30 | sNums = [500*i for i in [2,4,8,12,20]] 31 | strategies = ['best', 'kmst', 'gini'] 32 | acc_pure = [[] for i in range(len(strategies))] 33 | acc_fp = [[] for i in range(len(strategies))] 34 | 35 | 36 | for num in sNums: 37 | for i in range(len(strategies)): 38 | s = strategies[i] 39 | model_path = "./checkpoint/best_Resnet_MIX_%d_%s.h5" % (num, s) 40 | best_model = keras.models.load_model(model_path) 41 | lfp, afp = best_model.evaluate(fp_test, fp_test_labels, verbose=0) 42 | acc_fp[i].append(afp) 43 | 44 | 45 | 46 | colormap = ['r','limegreen', 'dodgerblue'] 47 | plt.figure(figsize=(8,6)) 48 | x = [i/max(sNums) for i in sNums] 49 | for i in range(len(strategies)): 50 | plt.plot(x, acc_fp[i],'o-', label=strategies[i], color=colormap[i], linewidth=3, markersize=8) 51 | 52 | plt.title("CIFAR-ATTACK", fontsize=20) 53 | plt.xlabel("# Percentage of test cases", fontsize=20) 54 | plt.ylabel("Robustness", fontsize=20) 55 | plt.xticks(x, [1,2,4,6,10],fontsize=15) 56 | plt.yticks(fontsize=15) 57 | plt.legend(fontsize=15) 58 | 59 | fig = plt.gcf() 60 | fig.savefig('./cifar_attack_robustness.pdf') 61 | 62 | -------------------------------------------------------------------------------- /CIFAR-10/fol_guided_fuzzing.py: -------------------------------------------------------------------------------- 1 | from tensorflow import keras 2 | import random 3 | import tensorflow as tf 4 | import numpy as np 5 | import time 6 | from tensorflow.keras.datasets import cifar10 7 | 8 | import os 9 | os.environ["CUDA_VISIBLE_DEVICES"]="-1" 10 | 11 | gpus = tf.config.experimental.list_physical_devices('GPU') 12 | if gpus: 13 | try: 14 | for gpu in gpus: 15 | tf.config.experimental.set_memory_growth(gpu, True) 16 | except RuntimeError as e: 17 | print(e) 18 | 19 | 20 | 21 | # cifar 22 | (x_train, y_train), (x_test, y_test) = cifar10.load_data() 23 | 24 | x_train = x_train.astype('float32') 25 | x_test = x_test.astype('float32') 26 | x_train = x_train/255 27 | x_test = x_test/255 28 | 29 | y_train = keras.utils.to_categorical(y_train, 10) 30 | y_test = keras.utils.to_categorical(y_test, 10) 31 | 32 | model = keras.models.load_model("./saved_models/cifar10_resnet20_model.h5") 33 | 34 | 35 | seeds = random.sample(list(range(x_train.shape[0])), 1000) 36 | images = x_train[seeds] 37 | labels = y_train[seeds] 38 | 39 | 40 | # some training samples is static, i.e., grad=<0>, hard to generate. 41 | seeds_filter = [] 42 | gen_img = tf.Variable(images) 43 | with tf.GradientTape() as g: 44 | loss = keras.losses.categorical_crossentropy(labels, model(gen_img)) 45 | grads = g.gradient(loss, gen_img) 46 | 47 | fols = np.linalg.norm((grads.numpy()+1e-20).reshape(images.shape[0], -1), ord=2, axis=1) 48 | seeds_filter = np.where(fols > 1e-3)[0] 49 | 50 | 51 | start_t = time.time() 52 | lr = 0.1 53 | total_sets = [] 54 | for idx in seeds_filter: 55 | # delta_t = time.time() - start_t 56 | # if delta_t > 300: 57 | # break 58 | img_list = [] 59 | tmp_img = images[[idx]] 60 | orig_img = tmp_img.copy() 61 | orig_norm = np.linalg.norm(orig_img) 62 | img_list.append(tf.identity(tmp_img)) 63 | logits = model(tmp_img) 64 | orig_index = np.argmax(logits[0]) 65 | target = keras.utils.to_categorical([orig_index], 10) 66 | label_top5 = np.argsort(logits[0])[-5:] 67 | 68 | folMAX = 0 69 | epoch = 0 70 | while len(img_list) > 0: 71 | gen_img = img_list.pop(0) 72 | for _ in range(2): 73 | gen_img = tf.Variable(gen_img) 74 | with tf.GradientTape(persistent=True) as g: 75 | loss = keras.losses.categorical_crossentropy(target, model(gen_img)) 76 | grads = g.gradient(loss, gen_img) 77 | fol = tf.norm(grads+1e-20) 78 | g.watch(fol) 79 | logits = model(gen_img) 80 | obj = fol - logits[0][orig_index] 81 | dl_di = g.gradient(obj, gen_img) 82 | del g 83 | 84 | gen_img = gen_img + dl_di * lr * (random.random() + 0.5) 85 | gen_img = tf.clip_by_value(gen_img, clip_value_min=0, clip_value_max=1) 86 | 87 | with tf.GradientTape() as t: 88 | t.watch(gen_img) 89 | loss = keras.losses.categorical_crossentropy(target, model(gen_img)) 90 | grad = t.gradient(loss, gen_img) 91 | fol = np.linalg.norm(grad.numpy()) # L2 adaption 92 | 93 | distance = np.linalg.norm(gen_img.numpy() - orig_img) / orig_norm 94 | if fol > folMAX and distance < 0.5: 95 | folMAX = fol 96 | img_list.append(tf.identity(gen_img)) 97 | 98 | gen_index = np.argmax(model(gen_img)[0]) 99 | if gen_index != orig_index: 100 | total_sets.append((fol, gen_img.numpy(), labels[idx])) 101 | 102 | 103 | fols = np.array([item[0] for item in total_sets]) 104 | advs = np.array([item[1].reshape(32,32,3) for item in total_sets]) 105 | labels = np.array([item[2] for item in total_sets]) 106 | 107 | np.savez('./FOL_Fuzz.npz', advs=advs, labels=labels, fols=fols) 108 | 109 | 110 | -------------------------------------------------------------------------------- /CIFAR-10/gen_adv.py: -------------------------------------------------------------------------------- 1 | from tensorflow import keras 2 | import tensorflow as tf 3 | from tensorflow.keras.datasets import cifar10 4 | import numpy as np 5 | from attack import FGSM, PGD 6 | import os 7 | os.environ["CUDA_VISIBLE_DEVICES"]="-1" 8 | 9 | 10 | (x_train, y_train), (x_test, y_test) = cifar10.load_data() 11 | 12 | # preprocess cifar dataset 13 | x_train = x_train.astype('float32') 14 | x_test = x_test.astype('float32') 15 | x_train = x_train/255 16 | x_test = x_test/255 17 | 18 | y_train = keras.utils.to_categorical(y_train, 10) 19 | y_test = keras.utils.to_categorical(y_test, 10) 20 | 21 | 22 | # load your model 23 | model = keras.models.load_model("./cifar10_resnet20_model.h5") 24 | 25 | fgsm = FGSM(model, ep=0.01, isRand=True) 26 | pgd = PGD(model, ep=0.01, epochs=10, isRand=True) 27 | 28 | # generate adversarial examples at once. 29 | advs, labels, fols, ginis = fgsm.generate(x_train, y_train) 30 | np.savez('./FGSM_TrainFull.npz', advs=advs, labels=labels, fols=fols, ginis=ginis) 31 | 32 | advs, labels, fols, ginis = pgd.generate(x_train, y_train) 33 | np.savez('./PGD_TrainFull.npz', advs=advs, labels=labels, fols=fols, ginis=ginis) 34 | 35 | advs, labels, _, _ = fgsm.generate(x_test, y_test) 36 | np.savez('./FGSM_Test.npz', advs=advs, labels=labels) 37 | 38 | advs, labels, _, _ = pgd.generate(x_test, y_test) 39 | np.savez('./PGD_Test.npz', advs=advs, labels=labels) -------------------------------------------------------------------------------- /CIFAR-10/metrics.py: -------------------------------------------------------------------------------- 1 | from tensorflow import keras 2 | import tensorflow as tf 3 | import numpy as np 4 | 5 | 6 | ## Metrics for quality evaluation for massive test cases. 7 | 8 | 9 | def gini(model, x): 10 | """ 11 | Different from the defination in DeepGini paper (deepgini = 1 - ginis), the smaller the ginis here, the larger the uncertainty. 12 | 13 | shape of x: [batch_size, width, height, channel] 14 | """ 15 | x = tf.Variable(x) 16 | preds = model(x).numpy() 17 | ginis = np.sum(np.square(preds), axis=1) 18 | return ginis 19 | 20 | 21 | def fol_Linf(model, x, xi, ep, y): 22 | """ 23 | x: perturbed inputs, shape of x: [batch_size, width, height, channel] 24 | xi: initial inputs, shape of xi: [batch_size, width, height, channel] 25 | ep: L_inf bound 26 | y: ground truth, one hot vectors, shape of y: [batch_size, N_classes] 27 | """ 28 | x, target = tf.Variable(x), tf.constant(y) 29 | fols = [] 30 | with tf.GradientTape() as tape: 31 | loss = keras.losses.categorical_crossentropy(target, model(x)) 32 | grads = tape.gradient(loss, x) 33 | grad_norm = np.linalg.norm(grads.numpy().reshape(x.shape[0], -1), ord=1, axis=1) 34 | grads_flat = grads.numpy().reshape(x.shape[0], -1) 35 | diff = (x.numpy() - xi).reshape(x.shape[0], -1) 36 | for i in range(x.shape[0]): 37 | i_fol = -np.dot(grads_flat[i], diff[i]) + ep * grad_norm[i] 38 | fols.append(i_fol) 39 | 40 | return np.array(fols) 41 | 42 | 43 | def fol_L2(model, x, y): 44 | """ 45 | x: perturbed inputs, shape of x: [batch_size, width, height, channel] 46 | y: ground truth, one hot vectors, shape of y: [batch_size, N_classes] 47 | """ 48 | x, target = tf.Variable(x), tf.constant(y) 49 | with tf.GradientTape() as tape: 50 | loss = keras.losses.categorical_crossentropy(target, model(x)) 51 | grads = tape.gradient(loss, x) 52 | grads_norm_L2 = np.linalg.norm(grads.numpy().reshape(x.shape[0], -1), ord=2, axis=1) 53 | 54 | return grads_norm_L2 55 | 56 | 57 | def zol(model, x, y): 58 | """ 59 | x: perturbed inputs, shape of x: [batch_size, width, height, channel] 60 | y: ground truth, one hot vectors, shape of y: [batch_size, N_classes] 61 | """ 62 | x, target = tf.Variable(x), tf.constant(y) 63 | loss = keras.losses.categorical_crossentropy(target, model(x)) 64 | loss.numpy().reshape(-1) 65 | 66 | return loss 67 | 68 | 69 | def robustness(model, x, y): 70 | """ 71 | x: perturbed inputs, shape of x: [batch_size, width, height, channel] 72 | y: ground truth labels, shape of y: [batch_size] 73 | """ 74 | return np.sum(np.argmax(model(x), axis=1) == y) / y.shape[0] 75 | 76 | -------------------------------------------------------------------------------- /CIFAR-10/models.py: -------------------------------------------------------------------------------- 1 | from tensorflow import keras 2 | from tensorflow.keras.layers import Dense, Conv2D, BatchNormalization, Activation 3 | from tensorflow.keras.layers import AveragePooling2D, Input, Flatten 4 | from tensorflow.keras.regularizers import l2 5 | from tensorflow.keras.models import Model 6 | 7 | 8 | 9 | def resnet_layer(inputs, 10 | num_filters=16, 11 | kernel_size=3, 12 | strides=1, 13 | activation='relu', 14 | batch_normalization=True, 15 | conv_first=True): 16 | 17 | conv = Conv2D(num_filters, 18 | kernel_size=kernel_size, 19 | strides=strides, 20 | padding='same', 21 | kernel_initializer='he_normal', 22 | kernel_regularizer=l2(1e-4)) 23 | 24 | x = inputs 25 | if conv_first: 26 | x = conv(x) 27 | if batch_normalization: 28 | x = BatchNormalization()(x) 29 | if activation is not None: 30 | x = Activation(activation)(x) 31 | else: 32 | if batch_normalization: 33 | x = BatchNormalization()(x) 34 | if activation is not None: 35 | x = Activation(activation)(x) 36 | x = conv(x) 37 | return x 38 | 39 | 40 | def resnet_v1(input_shape, depth, num_classes=10): 41 | if (depth - 2) % 6 != 0: 42 | raise ValueError('depth should be 6n+2 (eg 20, 32, 44)') 43 | 44 | num_filters = 16 45 | num_res_blocks = int((depth - 2) / 6) 46 | 47 | inputs = Input(shape=input_shape) 48 | x = resnet_layer(inputs=inputs) 49 | # Instantiate the stack of residual units 50 | for stack in range(3): 51 | for res_block in range(num_res_blocks): 52 | strides = 1 53 | if stack > 0 and res_block == 0: 54 | strides = 2 55 | y = resnet_layer(inputs=x, 56 | num_filters=num_filters, 57 | strides=strides) 58 | y = resnet_layer(inputs=y, 59 | num_filters=num_filters, 60 | activation=None) 61 | if stack > 0 and res_block == 0: 62 | x = resnet_layer(inputs=x, 63 | num_filters=num_filters, 64 | kernel_size=1, 65 | strides=strides, 66 | activation=None, 67 | batch_normalization=False) 68 | x = keras.layers.add([x, y]) 69 | x = Activation('relu')(x) 70 | num_filters *= 2 71 | 72 | # Add classifier on top. 73 | # v1 does not use BN after last shortcut connection-ReLU 74 | x = AveragePooling2D(pool_size=8)(x) 75 | y = Flatten()(x) 76 | outputs = Dense(num_classes, 77 | activation='softmax', 78 | kernel_initializer='he_normal')(y) 79 | 80 | # Instantiate model. 81 | model = Model(inputs=inputs, outputs=outputs) 82 | return model 83 | 84 | 85 | def ConvNet_2(input_shape=(32,32,3)): 86 | model = keras.models.Sequential() 87 | model.add(keras.layers.Conv2D(32, 3, padding="same", input_shape=input_shape, activation='relu')) 88 | model.add(keras.layers.Conv2D(32, 3, padding="same", activation='relu')) 89 | model.add(keras.layers.MaxPooling2D(pool_size=(2,2))) 90 | model.add(keras.layers.Conv2D(64, 3, padding="same", activation='relu')) 91 | model.add(keras.layers.Conv2D(64, 3, padding="same", activation='relu')) 92 | model.add(keras.layers.MaxPooling2D(pool_size=(2,2))) 93 | model.add(keras.layers.Conv2D(128, 3, padding="same", activation='relu')) 94 | model.add(keras.layers.Conv2D(128, 3, padding="same", activation='relu')) 95 | model.add(keras.layers.MaxPooling2D(pool_size=(2,2))) 96 | model.add(keras.layers.Flatten()) 97 | model.add(keras.layers.Dropout(0.5)) 98 | model.add(keras.layers.Dense(1024, kernel_regularizer=l2(0.01), bias_regularizer=l2(0.01), activation='relu')) 99 | model.add(keras.layers.Dropout(0.5)) 100 | model.add(keras.layers.Dense(512, kernel_regularizer=l2(0.01), bias_regularizer=l2(0.01), activation='relu')) 101 | model.add(keras.layers.Dropout(0.5)) 102 | model.add(keras.layers.Dense(10, activation='softmax')) 103 | return model 104 | 105 | 106 | -------------------------------------------------------------------------------- /CIFAR-10/select_retrain.py: -------------------------------------------------------------------------------- 1 | from tensorflow import keras 2 | import tensorflow as tf 3 | import numpy as np 4 | from tensorflow.keras.datasets import cifar10 5 | from tensorflow.keras.callbacks import ModelCheckpoint, LearningRateScheduler 6 | from tensorflow.keras.callbacks import ReduceLROnPlateau 7 | from tensorflow.keras.preprocessing.image import ImageDataGenerator 8 | from tensorflow.keras.regularizers import l2 9 | import random 10 | 11 | import os 12 | os.environ["CUDA_VISIBLE_DEVICES"]="0" 13 | 14 | # Suppress the GPU memory 15 | gpus = tf.config.experimental.list_physical_devices('GPU') 16 | if gpus: 17 | try: 18 | for gpu in gpus: 19 | tf.config.experimental.set_memory_growth(gpu, True) 20 | except RuntimeError as e: 21 | print(e) 22 | 23 | 24 | 25 | def lr_schedule_retrain(epoch): 26 | lr = 1e-4 27 | if epoch > 25: 28 | lr *= 1e-1 29 | print('Learning rate: ', lr) 30 | return lr 31 | 32 | 33 | 34 | def select(values, n, s='best', k=4): 35 | """ 36 | n: the number of selected test cases. 37 | s: strategy, ['best', 'random', 'kmst', 'gini'] 38 | k: for KM-ST, the number of ranges. 39 | """ 40 | ranks = np.argsort(values) 41 | 42 | if s == 'best': 43 | h = n//2 44 | return np.concatenate((ranks[:h],ranks[-h:])) 45 | 46 | elif s == 'r': 47 | return np.array(random.sample(list(ranks),n)) 48 | 49 | elif s == 'kmst': 50 | fol_max = values.max() 51 | th = fol_max / k 52 | section_nums = n // k 53 | indexes = [] 54 | for i in range(k): 55 | section_indexes = np.intersect1d(np.where(values=th*i)) 56 | if section_nums < len(section_indexes): 57 | index = random.sample(list(section_indexes), section_nums) 58 | indexes.append(index) 59 | else: 60 | indexes.append(section_indexes) 61 | index = random.sample(list(ranks), section_nums-len(section_indexes)) 62 | indexes.append(index) 63 | return np.concatenate(np.array(indexes)) 64 | 65 | # This is for gini strategy. There is little difference from DeepGini paper. See function ginis() in metrics.py 66 | else: 67 | return ranks[:n] 68 | 69 | 70 | 71 | (x_train, y_train), (x_test, y_test) = cifar10.load_data() 72 | x_train = x_train.astype('float32') 73 | x_test = x_test.astype('float32') 74 | 75 | # convert class vectors to binary class matrics 76 | y_train = keras.utils.to_categorical(y_train, 10) 77 | y_test = keras.utils.to_categorical(y_test, 10) 78 | x_train = x_train/255 79 | x_test = x_test/255 80 | 81 | 82 | # Load the generated adversarial inputs for training. FGSM and PGD. 83 | with np.load("./FGSM_TrainFull.npz") as f: 84 | fgsm_train, fgsm_train_labels, fgsm_train_fols, fgsm_train_ginis = f['advs'], f['labels'], f['fols'], f['ginis'] 85 | 86 | with np.load("./PGD_TrainFull.npz") as f: 87 | pgd_train, pgd_train_labels, pgd_train_fols, pgd_train_ginis= f['advs'], f['labels'], f['fols'], f['ginis'] 88 | 89 | # Load the generated adversarial inputs for testing. FGSM and PGD. 90 | with np.load("./FGSM_Test.npz") as f: 91 | fgsm_test, fgsm_test_labels = f['advs'], f['labels'] 92 | 93 | with np.load("./PGD_Test.npz") as f: 94 | pgd_test, pgd_test_labels = f['advs'], f['labels'] 95 | 96 | 97 | # Mix the adversarial inputs 98 | fp_train = np.concatenate((fgsm_train, pgd_train)) 99 | fp_train_labels = np.concatenate((fgsm_train_labels, pgd_train_labels)) 100 | fp_train_fols = np.concatenate((fgsm_train_fols, pgd_train_fols)) 101 | fp_train_ginis = np.concatenate((fgsm_train_ginis, pgd_train_ginis)) 102 | 103 | fp_test = np.concatenate((fgsm_test, pgd_test)) 104 | fp_test_labels = np.concatenate((fgsm_test_labels, pgd_test_labels)) 105 | 106 | 107 | sNums = [500*i for i in [2,4,8,12,20]] 108 | strategies = ['best', 'kmst', 'gini'] 109 | 110 | for num in sNums: 111 | print(num) 112 | for i in range(len(strategies)): 113 | s = strategies[i] 114 | model_path = "./checkpoint/best_Resnet_MIX_%d_%s.h5" % (num, s) 115 | checkpoint = ModelCheckpoint(filepath=model_path, monitor='val_accuracy', verbose=1, save_best_only=True) 116 | lr_scheduler = LearningRateScheduler(lr_schedule_retrain) 117 | lr_reducer = ReduceLROnPlateau(factor=np.sqrt(0.1), cooldown=0, patience=5, min_lr=0.5e-6) 118 | callbacks = [checkpoint, lr_reducer, lr_scheduler] 119 | 120 | if s == 'gini': 121 | indexes = select(fp_train_ginis, num, s=s) 122 | else: 123 | indexes = select(fp_train_fols, num, s=s) 124 | 125 | selectAdvs = fp_train[indexes] 126 | selectAdvsLabels = fp_train_labels[indexes] 127 | 128 | x_train_mix = np.concatenate((x_train, selectAdvs),axis=0) 129 | y_train_mix = np.concatenate((y_train, selectAdvsLabels),axis=0) 130 | 131 | 132 | # load old model 133 | model = keras.models.load_model("./saved_models/cifar10_resnet20_model.h5") 134 | # model.fit(x_train_mix, y_train_mix, epochs=40, batch_size=64, verbose=1, callbacks=callbacks, 135 | # validation_data=(fp_test, fp_test_labels)) 136 | 137 | datagen = ImageDataGenerator(rotation_range=10, width_shift_range=0.1, height_shift_range=0.1, horizontal_flip=True) 138 | datagen.fit(x_train_mix) 139 | batch_size = 64 140 | history = model.fit_generator(datagen.flow(x_train_mix, y_train_mix, batch_size=batch_size), 141 | validation_data=(fp_test, fp_test_labels), 142 | epochs=40, verbose=1, 143 | callbacks=callbacks, 144 | steps_per_epoch= x_train_mix.shape[0] // batch_size) 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /CIFAR-10/train_model.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | import numpy as np 3 | from tensorflow import keras 4 | from tensorflow.keras.layers import Dense, Conv2D, BatchNormalization, Activation 5 | from tensorflow.keras.layers import AveragePooling2D, Input, Flatten 6 | from tensorflow.keras.optimizers import Adam 7 | from tensorflow.keras.callbacks import ModelCheckpoint, LearningRateScheduler 8 | from tensorflow.keras.callbacks import ReduceLROnPlateau 9 | from tensorflow.keras.preprocessing.image import ImageDataGenerator 10 | from tensorflow.keras.regularizers import l2 11 | from tensorflow.keras.models import Model 12 | from tensorflow.keras.datasets import cifar10 13 | from models import resnet_layer, resnet_v1, ConvNet_2 14 | 15 | import os 16 | os.environ["CUDA_VISIBLE_DEVICES"]="0" 17 | 18 | gpus = tf.config.experimental.list_physical_devices('GPU') 19 | if gpus: 20 | try: 21 | for gpu in gpus: 22 | tf.config.experimental.set_memory_growth(gpu, True) 23 | except RuntimeError as e: 24 | print(e) 25 | 26 | 27 | 28 | def lr_schedule(epoch): 29 | lr = 1e-3 30 | if epoch > 90: 31 | lr *= 1e-3 32 | elif epoch > 75: 33 | lr *= 1e-2 34 | elif epoch > 50: 35 | lr *= 1e-1 36 | print('Learning rate: ', lr) 37 | return lr 38 | 39 | 40 | 41 | # hyper-parameters for training resnet-20 42 | batch_size = 64 43 | epochs = 100 44 | data_augmentation = True 45 | num_classes = 10 46 | depth = 20 47 | 48 | (x_train, y_train), (x_test, y_test) = cifar10.load_data() 49 | 50 | x_train = x_train.astype('float32') / 255 51 | x_test = x_test.astype('float32') / 255 52 | 53 | y_train = keras.utils.to_categorical(y_train, num_classes) 54 | y_test = keras.utils.to_categorical(y_test, num_classes) 55 | 56 | input_shape = x_train.shape[1:] 57 | 58 | model = resnet_v1(input_shape=input_shape, depth=depth) 59 | model.compile(loss='categorical_crossentropy', 60 | optimizer=Adam(lr=lr_schedule(0)), 61 | metrics=['accuracy']) 62 | 63 | print(model.summary()) 64 | 65 | # Prepare model model saving directory. 66 | save_dir = os.path.join(os.getcwd(), 'saved_models') 67 | model_name = 'cifar10_resnet20_model.{epoch:03d}.h5' 68 | if not os.path.isdir(save_dir): 69 | os.makedirs(save_dir) 70 | filepath = os.path.join(save_dir, model_name) 71 | 72 | # Prepare callbacks for model saving and for learning rate adjustment. 73 | checkpoint = ModelCheckpoint(filepath=filepath, 74 | monitor='val_accuracy', 75 | verbose=1, 76 | save_best_only=True, 77 | mode='auto') 78 | 79 | lr_scheduler = LearningRateScheduler(lr_schedule) 80 | 81 | lr_reducer = ReduceLROnPlateau(factor=np.sqrt(0.1), 82 | cooldown=0, 83 | patience=5, 84 | min_lr=0.5e-6) 85 | 86 | callbacks = [checkpoint, lr_reducer, lr_scheduler] 87 | 88 | 89 | 90 | # Run training, with or without data augmentation. 91 | if not data_augmentation: 92 | print('Not using data augmentation.') 93 | model.fit(x_train, y_train, 94 | batch_size=batch_size, 95 | epochs=epochs, 96 | validation_data=(x_test, y_test), 97 | shuffle=True, 98 | callbacks=callbacks) 99 | else: 100 | print('Using real-time data augmentation.') 101 | # This will do preprocessing and realtime data augmentation: 102 | datagen = ImageDataGenerator( 103 | rotation_range=10, 104 | # randomly shift images horizontally 105 | width_shift_range=0.1, 106 | # randomly shift images vertically 107 | height_shift_range=0.1, 108 | # set range for random shear 109 | horizontal_flip=True) 110 | 111 | datagen.fit(x_train) 112 | 113 | # Fit the model on the batches generated by datagen.flow(). 114 | history = model.fit_generator(datagen.flow(x_train, y_train, batch_size=batch_size), 115 | validation_data=(x_test, y_test), 116 | epochs=epochs, verbose=1, 117 | callbacks=callbacks, 118 | steps_per_epoch= x_train.shape[0] // batch_size) 119 | 120 | # Score trained model. 121 | scores = model.evaluate(x_test, y_test, verbose=1) 122 | print('Test loss:', scores[0]) 123 | print('Test accuracy:', scores[1]) 124 | 125 | -------------------------------------------------------------------------------- /FASHION/models.py: -------------------------------------------------------------------------------- 1 | from tensorflow import keras 2 | import tensorflow as tf 3 | 4 | 5 | 6 | def Lenet5(input_shape=(28, 28, 1)): 7 | input_tensor = keras.layers.Input(shape=input_shape) 8 | 9 | x = keras.layers.Convolution2D(6, (5, 5), activation='relu', padding='same', name='block1_conv1')(input_tensor) 10 | x = keras.layers.MaxPooling2D(pool_size=(2, 2), name='block1_pool1')(x) 11 | 12 | x = keras.layers.Convolution2D(16, (5, 5), activation='relu', padding='same', name='block2_conv1')(x) 13 | x = keras.layers.MaxPooling2D(pool_size=(2, 2), name='block2_pool1')(x) 14 | 15 | x = keras.layers.Flatten(name='flatten')(x) 16 | x = keras.layers.Dense(120, activation='relu', name='fc1')(x) 17 | x = keras.layers.Dense(84, activation='relu', name='fc2')(x) 18 | x = keras.layers.Dense(10, name='before_softmax')(x) 19 | x = keras.layers.Activation('softmax', name='redictions')(x) 20 | 21 | return keras.models.Model(input_tensor, x) 22 | 23 | 24 | 25 | def ConvNet_1(input_shape=(28,28,1)): 26 | model = keras.models.Sequential() 27 | model.add(keras.layers.Conv2D(32, 3, input_shape=input_shape, activation='relu')) 28 | 29 | model.add(keras.layers.Conv2D(32, 3, activation='relu')) 30 | model.add(keras.layers.MaxPooling2D(pool_size=(2,2))) 31 | model.add(keras.layers.Conv2D(64,3, activation='relu')) 32 | model.add(keras.layers.Conv2D(64,3, activation='relu')) 33 | model.add(keras.layers.MaxPooling2D(pool_size=(2,2))) 34 | 35 | model.add(keras.layers.Flatten()) 36 | model.add(keras.layers.Dense(512, activation='relu')) 37 | model.add(keras.layers.Dropout(0.5)) 38 | model.add(keras.layers.Dense(10, activation='softmax')) 39 | 40 | return model 41 | 42 | -------------------------------------------------------------------------------- /FASHION/train_model.py: -------------------------------------------------------------------------------- 1 | from tensorflow import keras 2 | import tensorflow as tf 3 | import numpy as np 4 | from models import Lenet5, ConvNet_1 5 | 6 | gpus = tf.config.experimental.list_physical_devices('GPU') 7 | if gpus: 8 | try: 9 | for gpu in gpus: 10 | tf.config.experimental.set_memory_growth(gpu, True) 11 | except RuntimeError as e: 12 | print(e) 13 | 14 | 15 | def load_fashion(path="./fashion.npz"): 16 | f = np.load(path) 17 | x_train, y_train = f['x_train'], f['y_train'] 18 | x_test, y_test = f['x_test'], f['y_test'] 19 | f.close() 20 | 21 | x_train = x_train.reshape(x_train.shape[0], 28, 28, 1) 22 | x_test = x_test.reshape(x_test.shape[0], 28, 28, 1) 23 | 24 | x_train = x_train.astype('float32') / 255. 25 | x_test = x_test.astype('float32') / 255. 26 | 27 | y_train = keras.utils.to_categorical(y_train, 10) 28 | y_test = keras.utils.to_categorical(y_test, 10) 29 | 30 | return x_train, x_test, y_train, y_test 31 | 32 | 33 | path = "./fashion.npz" 34 | x_train, x_test, y_train, y_test = load_fashion(path) 35 | 36 | 37 | lenet5 = Lenet5() 38 | lenet5.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy']) 39 | lenet5.fit(x_train, y_train, epochs=10, batch_size=64) 40 | 41 | lenet5.evaluate(x_test, y_test) 42 | 43 | lenet5.save("./Lenet5_fashion.h5") 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 SmallkeyChen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MNIST/attack.py: -------------------------------------------------------------------------------- 1 | from tensorflow import keras 2 | import tensorflow as tf 3 | import numpy as np 4 | 5 | 6 | 7 | class FGSM: 8 | """ 9 | We use FGSM to generate a batch of adversarial examples. 10 | """ 11 | def __init__(self, model, ep=0.3, isRand=True): 12 | """ 13 | isRand is set True to improve the attack success rate. 14 | """ 15 | self.isRand = isRand 16 | self.model = model 17 | self.ep = ep 18 | 19 | def generate(self, x, y, randRate=1): 20 | """ 21 | x: clean inputs, shape of x: [batch_size, width, height, channel] 22 | y: ground truth, one hot vectors, shape of y: [batch_size, N_classes] 23 | """ 24 | fols = [] 25 | target = tf.constant(y) 26 | 27 | xi = x.copy() 28 | if self.isRand: 29 | x = x + np.random.uniform(-self.ep * randRate, self.ep * randRate, x.shape) 30 | x = np.clip(x, 0, 1) 31 | 32 | x = tf.Variable(x) 33 | with tf.GradientTape() as tape: 34 | loss = keras.losses.categorical_crossentropy(target, self.model(x)) 35 | grads = tape.gradient(loss, x) 36 | delta = tf.sign(grads) 37 | x_adv = x + self.ep * delta 38 | 39 | x_adv = tf.clip_by_value(x_adv, clip_value_min=xi-self.ep, clip_value_max=xi+self.ep) 40 | x_adv = tf.clip_by_value(x_adv, clip_value_min=0, clip_value_max=1) 41 | 42 | idxs = np.where(np.argmax(self.model(x_adv), axis=1) != np.argmax(y, axis=1))[0] 43 | print("SUCCESS:", len(idxs)) 44 | 45 | x_adv, xi, target = x_adv.numpy()[idxs], xi[idxs], target.numpy()[idxs] 46 | x_adv, target = tf.Variable(x_adv), tf.constant(target) 47 | 48 | preds = self.model(x_adv).numpy() 49 | ginis = np.sum(np.square(preds), axis=1) 50 | 51 | with tf.GradientTape() as tape: 52 | loss = keras.losses.categorical_crossentropy(target, self.model(x_adv)) 53 | grads = tape.gradient(loss, x_adv) 54 | grad_norm = np.linalg.norm(grads.numpy().reshape(x_adv.shape[0], -1), ord=1, axis=1) 55 | grads_flat = grads.numpy().reshape(x_adv.shape[0], -1) 56 | diff = (x_adv.numpy() - xi).reshape(x_adv.shape[0], -1) 57 | for i in range(x_adv.shape[0]): 58 | i_fol = -np.dot(grads_flat[i], diff[i]) + self.ep * grad_norm[i] 59 | fols.append(i_fol) 60 | 61 | return x_adv.numpy(), target.numpy(), np.array(fols), ginis 62 | 63 | 64 | 65 | class PGD: 66 | """ 67 | We use PGD to generate a batch of adversarial examples. PGD could be seen as iterative version of FGSM. 68 | """ 69 | def __init__(self, model, ep=0.3, step=None, epochs=10, isRand=True): 70 | """ 71 | isRand is set True to improve the attack success rate. 72 | """ 73 | self.isRand = isRand 74 | self.model = model 75 | self.ep = ep 76 | if step == None: 77 | self.step = ep/6 78 | self.epochs = epochs 79 | 80 | def generate(self, x, y, randRate=1): 81 | """ 82 | x: clean inputs, shape of x: [batch_size, width, height, channel] 83 | y: ground truth, one hot vectors, shape of y: [batch_size, N_classes] 84 | """ 85 | fols = [] 86 | target = tf.constant(y) 87 | 88 | xi = x.copy() 89 | if self.isRand: 90 | x = x + np.random.uniform(-self.ep * randRate, self.ep * randRate, x.shape) 91 | x = np.clip(x, 0, 1) 92 | 93 | x_adv = tf.Variable(x) 94 | for i in range(self.epochs): 95 | with tf.GradientTape() as tape: 96 | loss = keras.losses.categorical_crossentropy(target, self.model(x_adv)) 97 | grads = tape.gradient(loss, x_adv) 98 | delta = tf.sign(grads) 99 | x_adv.assign_add(self.step * delta) 100 | x_adv = tf.clip_by_value(x_adv, clip_value_min=xi-self.ep, clip_value_max=xi+self.ep) 101 | x_adv = tf.clip_by_value(x_adv, clip_value_min=0, clip_value_max=1) 102 | x_adv = tf.Variable(x_adv) 103 | 104 | idxs = np.where(np.argmax(self.model(x_adv), axis=1) != np.argmax(y, axis=1))[0] 105 | print("SUCCESS:", len(idxs)) 106 | 107 | x_adv, xi, target = x_adv.numpy()[idxs], xi[idxs], target.numpy()[idxs] 108 | x_adv, target = tf.Variable(x_adv), tf.constant(target) 109 | 110 | preds = self.model(x_adv).numpy() 111 | ginis = np.sum(np.square(preds), axis=1) 112 | 113 | with tf.GradientTape() as tape: 114 | loss = keras.losses.categorical_crossentropy(target, self.model(x_adv)) 115 | grads = tape.gradient(loss, x_adv) 116 | grad_norm = np.linalg.norm(grads.numpy().reshape(x_adv.shape[0], -1), ord=1, axis=1) 117 | grads_flat = grads.numpy().reshape(x_adv.shape[0], -1) 118 | diff = (x_adv.numpy() - xi).reshape(x_adv.shape[0], -1) 119 | for i in range(x_adv.shape[0]): 120 | i_fol = -np.dot(grads_flat[i], diff[i]) + self.ep * grad_norm[i] 121 | fols.append(i_fol) 122 | 123 | return x_adv.numpy(), target.numpy(), np.array(fols), ginis 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /MNIST/evaluate.py: -------------------------------------------------------------------------------- 1 | from tensorflow import keras 2 | import tensorflow as tf 3 | import numpy as np 4 | import matplotlib.pyplot as plt 5 | # %matplotlib inline 6 | 7 | import os 8 | os.environ["CUDA_VISIBLE_DEVICES"]="0" 9 | 10 | gpus = tf.config.experimental.list_physical_devices('GPU') 11 | if gpus: 12 | try: 13 | for gpu in gpus: 14 | tf.config.experimental.set_memory_growth(gpu, True) 15 | except RuntimeError as e: 16 | print(e) 17 | 18 | 19 | # Load the generated adversarial inputs for Robustness evaluation. 20 | with np.load("./FGSM_Test.npz") as f: 21 | fgsm_test, fgsm_test_labels = f['advs'], f['labels'] 22 | 23 | with np.load("./PGD_Test.npz") as f: 24 | pgd_test, pgd_test_labels = f['advs'], f['labels'] 25 | 26 | fp_test = np.concatenate((fgsm_test, pgd_test)) 27 | fp_test_labels = np.concatenate((fgsm_test_labels, pgd_test_labels)) 28 | 29 | 30 | sNums = [600*i for i in [1,2,3,4,6,8,10,12,16,20]] 31 | strategies = ['best', 'kmst', 'gini'] 32 | acc_fp = [[] for i in range(len(strategies))] 33 | 34 | 35 | for num in sNums: 36 | for i in range(len(strategies)): 37 | s = strategies[i] 38 | model_path = "./checkpoint/best_Lenet5_MIX_%d_%s.h5" % (num, s) 39 | best_model = keras.models.load_model(model_path) 40 | lfp, afp = best_model.evaluate(fp_test, fp_test_labels, verbose=0) 41 | acc_fp[i].append(afp) 42 | 43 | 44 | colormap = ['r','limegreen', 'dodgerblue'] 45 | plt.figure(figsize=(8,6)) 46 | x = [i/max(sNums) for i in sNums] 47 | for i in range(len(strategies)): 48 | plt.plot(x, acc_fp[i],'o-', label=strategies[i], color=colormap[i], linewidth=3, markersize=8) 49 | 50 | plt.title("MNIST-ATTACK", fontsize=20) 51 | plt.xlabel("# Percentage of test cases", fontsize=20) 52 | plt.ylabel("Robustness", fontsize=20) 53 | plt.xticks(x, [0.5,1,1.5,2,3,4,5,6,8,10],fontsize=15) 54 | plt.yticks(fontsize=15) 55 | plt.legend(fontsize=15) 56 | 57 | fig = plt.gcf() 58 | fig.savefig('./mnist_attack_robustness.pdf') -------------------------------------------------------------------------------- /MNIST/fol_guided_fuzzing.py: -------------------------------------------------------------------------------- 1 | from tensorflow import keras 2 | import random 3 | import tensorflow as tf 4 | import numpy as np 5 | import time 6 | 7 | import os 8 | os.environ["CUDA_VISIBLE_DEVICES"]="-1" 9 | 10 | gpus = tf.config.experimental.list_physical_devices('GPU') 11 | if gpus: 12 | try: 13 | for gpu in gpus: 14 | tf.config.experimental.set_memory_growth(gpu, True) 15 | except RuntimeError as e: 16 | print(e) 17 | 18 | 19 | def load_mnist(path="./mnist.npz"): 20 | f = np.load(path) 21 | x_train, y_train = f['x_train'], f['y_train'] 22 | x_test, y_test = f['x_test'], f['y_test'] 23 | f.close() 24 | 25 | x_train = x_train.reshape(x_train.shape[0], 28, 28, 1) 26 | x_test = x_test.reshape(x_test.shape[0], 28, 28, 1) 27 | 28 | x_train = x_train.astype('float32') / 255. 29 | x_test = x_test.astype('float32') / 255. 30 | 31 | y_train = keras.utils.to_categorical(y_train, 10) 32 | y_test = keras.utils.to_categorical(y_test, 10) 33 | 34 | return x_train, x_test, y_train, y_test 35 | 36 | 37 | path = "./mnist.npz" 38 | x_train, x_test, y_train, y_test = load_mnist(path) 39 | 40 | model = keras.models.load_model("./Lenet5_mnist.h5") 41 | 42 | 43 | seeds = random.sample(list(range(x_train.shape[0])), 1000) 44 | images = x_train[seeds] 45 | labels = y_train[seeds] 46 | 47 | 48 | # some training samples is static, i.e., grad=<0>, hard to generate. 49 | seeds_filter = [] 50 | gen_img = tf.Variable(images) 51 | with tf.GradientTape() as g: 52 | loss = keras.losses.categorical_crossentropy(labels, model(gen_img)) 53 | grads = g.gradient(loss, gen_img) 54 | 55 | fols = np.linalg.norm((grads.numpy()+1e-20).reshape(images.shape[0], -1), ord=2, axis=1) 56 | seeds_filter = np.where(fols > 1e-3)[0] 57 | 58 | 59 | start_t = time.time() 60 | lr = 0.1 61 | total_sets = [] 62 | for idx in seeds_filter: 63 | # delta_t = time.time() - start_t 64 | # if delta_t > 300: 65 | # break 66 | img_list = [] 67 | tmp_img = images[[idx]] 68 | orig_img = tmp_img.copy() 69 | orig_norm = np.linalg.norm(orig_img) 70 | img_list.append(tf.identity(tmp_img)) 71 | logits = model(tmp_img) 72 | orig_index = np.argmax(logits[0]) 73 | target = keras.utils.to_categorical([orig_index], 10) 74 | label_top5 = np.argsort(logits[0])[-5:] 75 | 76 | folMAX = 0 77 | epoch = 0 78 | while len(img_list) > 0: 79 | gen_img = img_list.pop(0) 80 | for _ in range(2): 81 | gen_img = tf.Variable(gen_img) 82 | with tf.GradientTape(persistent=True) as g: 83 | loss = keras.losses.categorical_crossentropy(target, model(gen_img)) 84 | grads = g.gradient(loss, gen_img) 85 | fol = tf.norm(grads+1e-20) 86 | g.watch(fol) 87 | logits = model(gen_img) 88 | obj = fol - logits[0][orig_index] 89 | dl_di = g.gradient(obj, gen_img) 90 | del g 91 | 92 | gen_img = gen_img + dl_di * lr * (random.random() + 0.5) 93 | gen_img = tf.clip_by_value(gen_img, clip_value_min=0, clip_value_max=1) 94 | 95 | with tf.GradientTape() as t: 96 | t.watch(gen_img) 97 | loss = keras.losses.categorical_crossentropy(target, model(gen_img)) 98 | grad = t.gradient(loss, gen_img) 99 | fol = np.linalg.norm(grad.numpy()) # L2 adaption 100 | 101 | distance = np.linalg.norm(gen_img.numpy() - orig_img) / orig_norm 102 | if fol > folMAX and distance < 0.5: 103 | folMAX = fol 104 | img_list.append(tf.identity(gen_img)) 105 | 106 | gen_index = np.argmax(model(gen_img)[0]) 107 | if gen_index != orig_index: 108 | total_sets.append((fol, gen_img.numpy(), labels[idx])) 109 | 110 | 111 | fols = np.array([item[0] for item in total_sets]) 112 | advs = np.array([item[1].reshape(28,28,1) for item in total_sets]) 113 | labels = np.array([item[2] for item in total_sets]) 114 | 115 | np.savez('./FOL_Fuzz.npz', advs=advs, labels=labels, fols=fols) 116 | 117 | 118 | -------------------------------------------------------------------------------- /MNIST/gen_adv.py: -------------------------------------------------------------------------------- 1 | from tensorflow import keras 2 | import tensorflow as tf 3 | import numpy as np 4 | from attack import FGSM, PGD 5 | import os 6 | os.environ["CUDA_VISIBLE_DEVICES"]="-1" 7 | 8 | 9 | 10 | def load_mnist(path="./mnist.npz"): 11 | f = np.load(path) 12 | x_train, y_train = f['x_train'], f['y_train'] 13 | x_test, y_test = f['x_test'], f['y_test'] 14 | f.close() 15 | 16 | x_train = x_train.reshape(x_train.shape[0], 28, 28, 1) 17 | x_test = x_test.reshape(x_test.shape[0], 28, 28, 1) 18 | 19 | x_train = x_train.astype('float32') / 255. 20 | x_test = x_test.astype('float32') / 255. 21 | 22 | y_train = keras.utils.to_categorical(y_train, 10) 23 | y_test = keras.utils.to_categorical(y_test, 10) 24 | 25 | return x_train, x_test, y_train, y_test 26 | 27 | 28 | path = "./mnist.npz" 29 | x_train, x_test, y_train, y_test = load_mnist(path) 30 | 31 | 32 | # load your model 33 | model = keras.models.load_model("./Lenet5_mnist.h5") 34 | 35 | fgsm = FGSM(model, ep=0.3, isRand=True) 36 | pgd = PGD(model, ep=0.3, epochs=10, isRand=True) 37 | 38 | # generate adversarial examples at once. 39 | advs, labels, fols, ginis = fgsm.generate(x_train, y_train) 40 | np.savez('./FGSM_TrainFull.npz', advs=advs, labels=labels, fols=fols, ginis=ginis) 41 | 42 | advs, labels, fols, ginis = pgd.generate(x_train, y_train) 43 | np.savez('./PGD_TrainFull.npz', advs=advs, labels=labels, fols=fols, ginis=ginis) 44 | 45 | advs, labels, _, _ = fgsm.generate(x_test, y_test) 46 | np.savez('./FGSM_Test.npz', advs=advs, labels=labels) 47 | 48 | advs, labels, _, _ = pgd.generate(x_test, y_test) 49 | np.savez('./PGD_Test.npz', advs=advs, labels=labels) -------------------------------------------------------------------------------- /MNIST/metrics.py: -------------------------------------------------------------------------------- 1 | from tensorflow import keras 2 | import tensorflow as tf 3 | import numpy as np 4 | 5 | 6 | ## Metrics for quality evaluation for massive test cases. 7 | 8 | 9 | def gini(model, x): 10 | """ 11 | Different from the defination in DeepGini paper (deepgini = 1 - ginis), the smaller the ginis here, the larger the uncertainty. 12 | 13 | shape of x: [batch_size, width, height, channel] 14 | """ 15 | x = tf.Variable(x) 16 | preds = model(x).numpy() 17 | ginis = np.sum(np.square(preds), axis=1) 18 | return ginis 19 | 20 | 21 | def fol_Linf(model, x, xi, ep, y): 22 | """ 23 | x: perturbed inputs, shape of x: [batch_size, width, height, channel] 24 | xi: initial inputs, shape of xi: [batch_size, width, height, channel] 25 | ep: L_inf bound 26 | y: ground truth, one hot vectors, shape of y: [batch_size, N_classes] 27 | """ 28 | x, target = tf.Variable(x), tf.constant(y) 29 | fols = [] 30 | with tf.GradientTape() as tape: 31 | loss = keras.losses.categorical_crossentropy(target, model(x)) 32 | grads = tape.gradient(loss, x) 33 | grad_norm = np.linalg.norm(grads.numpy().reshape(x.shape[0], -1), ord=1, axis=1) 34 | grads_flat = grads.numpy().reshape(x.shape[0], -1) 35 | diff = (x.numpy() - xi).reshape(x.shape[0], -1) 36 | for i in range(x.shape[0]): 37 | i_fol = -np.dot(grads_flat[i], diff[i]) + ep * grad_norm[i] 38 | fols.append(i_fol) 39 | 40 | return np.array(fols) 41 | 42 | 43 | def fol_L2(model, x, y): 44 | """ 45 | x: perturbed inputs, shape of x: [batch_size, width, height, channel] 46 | y: ground truth, one hot vectors, shape of y: [batch_size, N_classes] 47 | """ 48 | x, target = tf.Variable(x), tf.constant(y) 49 | with tf.GradientTape() as tape: 50 | loss = keras.losses.categorical_crossentropy(target, model(x)) 51 | grads = tape.gradient(loss, x) 52 | grads_norm_L2 = np.linalg.norm(grads.numpy().reshape(x.shape[0], -1), ord=2, axis=1) 53 | 54 | return grads_norm_L2 55 | 56 | 57 | def zol(model, x, y): 58 | """ 59 | x: perturbed inputs, shape of x: [batch_size, width, height, channel] 60 | y: ground truth, one hot vectors, shape of y: [batch_size, N_classes] 61 | """ 62 | x, target = tf.Variable(x), tf.constant(y) 63 | loss = keras.losses.categorical_crossentropy(target, model(x)) 64 | loss.numpy().reshape(-1) 65 | 66 | return loss 67 | 68 | 69 | def robustness(model, x, y): 70 | """ 71 | x: perturbed inputs, shape of x: [batch_size, width, height, channel] 72 | y: ground truth labels, shape of y: [batch_size] 73 | """ 74 | return np.sum(np.argmax(model(x), axis=1) == y) / y.shape[0] 75 | 76 | -------------------------------------------------------------------------------- /MNIST/mnist.npz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Testing4AI/RobOT/e727ee91b84171beb2d2ed832755f1714ed38e92/MNIST/mnist.npz -------------------------------------------------------------------------------- /MNIST/models.py: -------------------------------------------------------------------------------- 1 | from tensorflow import keras 2 | import tensorflow as tf 3 | 4 | 5 | def Lenet1(input_shape=(28, 28, 1)): 6 | input_tensor = keras.layers.Input(shape=input_shape) 7 | x = keras.layers.Conv2D(4, (5, 5), activation='relu', padding='same')(input_tensor) 8 | x = keras.layers.MaxPooling2D(pool_size=(2, 2))(x) 9 | 10 | x = keras.layers.Conv2D(12, (5, 5), activation='relu', padding='same')(x) 11 | x = keras.layers.MaxPooling2D(pool_size=(2, 2))(x) 12 | 13 | x = keras.layers.Flatten()(x) 14 | x = keras.layers.Dense(10, activation='softmax')(x) 15 | 16 | return keras.models.Model(input_tensor, x) 17 | 18 | 19 | def Lenet5(input_shape=(28, 28, 1)): 20 | input_tensor = keras.layers.Input(shape=input_shape) 21 | 22 | x = keras.layers.Convolution2D(6, (5, 5), activation='relu', padding='same', name='block1_conv1')(input_tensor) 23 | x = keras.layers.MaxPooling2D(pool_size=(2, 2), name='block1_pool1')(x) 24 | 25 | x = keras.layers.Convolution2D(16, (5, 5), activation='relu', padding='same', name='block2_conv1')(x) 26 | x = keras.layers.MaxPooling2D(pool_size=(2, 2), name='block2_pool1')(x) 27 | 28 | x = keras.layers.Flatten(name='flatten')(x) 29 | x = keras.layers.Dense(120, activation='relu', name='fc1')(x) 30 | x = keras.layers.Dense(84, activation='relu', name='fc2')(x) 31 | x = keras.layers.Dense(10, name='before_softmax')(x) 32 | x = keras.layers.Activation('softmax', name='redictions')(x) 33 | 34 | return keras.models.Model(input_tensor, x) 35 | 36 | 37 | -------------------------------------------------------------------------------- /MNIST/select_retrain.py: -------------------------------------------------------------------------------- 1 | from tensorflow import keras 2 | import tensorflow as tf 3 | import numpy as np 4 | import random 5 | from tensorflow.keras.callbacks import ModelCheckpoint 6 | import os 7 | os.environ["CUDA_VISIBLE_DEVICES"]="0" 8 | 9 | # Suppress the GPU memory 10 | gpus = tf.config.experimental.list_physical_devices('GPU') 11 | if gpus: 12 | try: 13 | for gpu in gpus: 14 | tf.config.experimental.set_memory_growth(gpu, True) 15 | except RuntimeError as e: 16 | print(e) 17 | 18 | 19 | 20 | def select(foscs, n, s='best', k=1000): 21 | 22 | ranks = np.argsort(foscs) 23 | # we choose test cases with small and large fols. 24 | if s == 'best': 25 | h = n//2 26 | return np.concatenate((ranks[:h],ranks[-h:])) 27 | 28 | # we choose test cases with small and large fols. 29 | elif s == 'kmst': 30 | index = [] 31 | section_w = len(ranks) // k 32 | section_nums = n // section_w 33 | indexes = random.sample(list(range(k)), section_nums) 34 | for i in indexes: 35 | block = ranks[i*section_w: (i+1)*section_w] 36 | index.append(block) 37 | return np.concatenate(np.array(index)) 38 | 39 | # This is for gini strategy. There is little different from DeepGini paper. See function ginis() in metrics.py 40 | else: 41 | return ranks[:n] 42 | 43 | 44 | def select(values, n, s='best', k=4): 45 | """ 46 | n: the number of selected test cases. 47 | s: strategy, ['best', 'random', 'kmst', 'gini'] 48 | k: for KM-ST, the number of ranges. 49 | """ 50 | ranks = np.argsort(values) 51 | 52 | if s == 'best': 53 | h = n//2 54 | return np.concatenate((ranks[:h],ranks[-h:])) 55 | 56 | elif s == 'r': 57 | return np.array(random.sample(list(ranks),n)) 58 | 59 | elif s == 'kmst': 60 | fol_max = values.max() 61 | th = fol_max / k 62 | section_nums = n // k 63 | indexes = [] 64 | for i in range(k): 65 | section_indexes = np.intersect1d(np.where(values=th*i)) 66 | if section_nums < len(section_indexes): 67 | index = random.sample(list(section_indexes), section_nums) 68 | indexes.append(index) 69 | else: 70 | indexes.append(section_indexes) 71 | index = random.sample(list(ranks), section_nums-len(section_indexes)) 72 | indexes.append(index) 73 | return np.concatenate(np.array(indexes)) 74 | 75 | # This is for gini strategy. There is little difference from DeepGini paper. See function ginis() in metrics.py 76 | else: 77 | return ranks[:n] 78 | 79 | 80 | def load_mnist(path="./mnist.npz"): 81 | """ 82 | preprocessing for MNIST dataset, values are normalized to [0,1]. 83 | y_train and y_test are one-hot vectors. 84 | """ 85 | f = np.load(path) 86 | x_train, y_train = f['x_train'], f['y_train'] 87 | x_test, y_test = f['x_test'], f['y_test'] 88 | f.close() 89 | 90 | x_train = x_train.reshape(x_train.shape[0], 28, 28, 1) 91 | x_test = x_test.reshape(x_test.shape[0], 28, 28, 1) 92 | 93 | x_train = x_train.astype('float32') / 255. 94 | x_test = x_test.astype('float32') / 255. 95 | 96 | y_train = keras.utils.to_categorical(y_train, 10) 97 | y_test = keras.utils.to_categorical(y_test, 10) 98 | 99 | return x_train, x_test, y_train, y_test 100 | 101 | 102 | x_train, x_test, y_train, y_test = load_mnist(path="./mnist.npz") 103 | 104 | # Load the generated adversarial inputs for training. FGSM and PGD. 105 | with np.load("./FGSM_TrainFull.npz") as f: 106 | fgsm_train, fgsm_train_labels, fgsm_train_fols, fgsm_train_ginis = f['advs'], f['labels'], f['fols'], f['ginis'] 107 | 108 | with np.load("./PGD_TrainFull.npz") as f: 109 | pgd_train, pgd_train_labels, pgd_train_fols, pgd_train_ginis= f['advs'], f['labels'], f['fols'], f['ginis'] 110 | 111 | # Load the generated adversarial inputs for testing. FGSM and PGD. 112 | with np.load("./FGSM_Test.npz") as f: 113 | fgsm_test, fgsm_test_labels = f['advs'], f['labels'] 114 | 115 | with np.load("./PGD_Test.npz") as f: 116 | pgd_test, pgd_test_labels = f['advs'], f['labels'] 117 | 118 | 119 | # Mix the adversarial inputs 120 | fp_train = np.concatenate((fgsm_train, pgd_train)) 121 | fp_train_labels = np.concatenate((fgsm_train_labels, pgd_train_labels)) 122 | fp_train_fols = np.concatenate((fgsm_train_fols, pgd_train_fols)) 123 | fp_train_ginis = np.concatenate((fgsm_train_ginis, pgd_train_ginis)) 124 | 125 | fp_test = np.concatenate((fgsm_test, pgd_test)) 126 | fp_test_labels = np.concatenate((fgsm_test_labels, pgd_test_labels)) 127 | 128 | 129 | sNums = [600*i for i in [1,2,3,4,6,8,10,12,16,20]] 130 | strategies = ['best', 'kmst', 'gini'] 131 | acc_clean = [[] for i in range(len(strategies))] 132 | acc_fp = [[] for i in range(len(strategies))] 133 | 134 | 135 | for num in sNums: 136 | for i in range(len(strategies)): 137 | s = strategies[i] 138 | # model save path 139 | model_path = "./checkpoint/best_Lenet5_MIX_%d_%s.h5" % (num, s) 140 | model = keras.models.load_model("./Lenet5_mnist.h5") 141 | 142 | checkpoint = ModelCheckpoint(filepath=model_path, monitor='val_accuracy', verbose=0, save_best_only=True) 143 | callbacks = [checkpoint] 144 | 145 | if s == 'gini': 146 | indexes = select(fp_train_ginis, num, s=s) 147 | else: 148 | indexes = select(fp_train_fols, num, s=s) 149 | 150 | selectAdvs = fp_train[indexes] 151 | selectAdvsLabels = fp_train_labels[indexes] 152 | 153 | x_train_mix = np.concatenate((x_train, selectAdvs),axis=0) 154 | y_train_mix = np.concatenate((y_train, selectAdvsLabels),axis=0) 155 | 156 | # model retraining 157 | model.fit(x_train_mix, y_train_mix, epochs=10, batch_size=64, verbose=0, callbacks=callbacks, 158 | validation_data=(fp_test, fp_test_labels)) 159 | 160 | best_model = keras.models.load_model(model_path) 161 | _, aclean = best_model.evaluate(x_test, y_test, verbose=0) 162 | _, afp = best_model.evaluate(fp_test, fp_test_labels, verbose=0) 163 | 164 | acc_clean[i].append(aclean) 165 | acc_fp[i].append(afp) 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | -------------------------------------------------------------------------------- /MNIST/train_model.py: -------------------------------------------------------------------------------- 1 | from tensorflow import keras 2 | import tensorflow as tf 3 | import numpy as np 4 | from models import Lenet1, Lenet5 5 | 6 | gpus = tf.config.experimental.list_physical_devices('GPU') 7 | if gpus: 8 | try: 9 | for gpu in gpus: 10 | tf.config.experimental.set_memory_growth(gpu, True) 11 | except RuntimeError as e: 12 | print(e) 13 | 14 | 15 | def load_mnist(path="./mnist.npz"): 16 | f = np.load(path) 17 | x_train, y_train = f['x_train'], f['y_train'] 18 | x_test, y_test = f['x_test'], f['y_test'] 19 | f.close() 20 | 21 | x_train = x_train.reshape(x_train.shape[0], 28, 28, 1) 22 | x_test = x_test.reshape(x_test.shape[0], 28, 28, 1) 23 | 24 | x_train = x_train.astype('float32') / 255. 25 | x_test = x_test.astype('float32') / 255. 26 | 27 | y_train = keras.utils.to_categorical(y_train, 10) 28 | y_test = keras.utils.to_categorical(y_test, 10) 29 | 30 | return x_train, x_test, y_train, y_test 31 | 32 | 33 | path = "./mnist.npz" 34 | x_train, x_test, y_train, y_test = load_mnist(path) 35 | 36 | 37 | lenet5 = Lenet5() 38 | lenet5.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy']) 39 | lenet5.fit(x_train, y_train, epochs=10, batch_size=64) 40 | 41 | lenet5.evaluate(x_test, y_test) 42 | 43 | lenet5.save("./Lenet5_mnist.h5") 44 | 45 | 46 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RobOT: Robustness-Oriented Testing for Deep Learning Systems published at ICSE 2021 2 | See the ICSE2021 paper for more details. 3 | 4 | ## Prerequisite (Py3.6 & Tf2) 5 | The code are run successfully using Python 3.6 and Tensorflow 2.2.0. 6 | 7 | We recommend using conda to install the tensorflow-gpu environment 8 | ```shell 9 | conda create -n tf2-gpu tensorflow-gpu==2.2.0 10 | conda activate tf2-gpu 11 | ``` 12 | 13 | Checking installed environments 14 | ```shell 15 | conda env list 16 | ``` 17 | 18 | to run the code in jupyter, you should add the kernel in jupyter notebook 19 | ``` 20 | pip install ipykernel 21 | python -m ipykernel install --name tf2-gpu 22 | ``` 23 | 24 | then start jupyter notebook for experiments 25 | ``` 26 | jupyter notebook 27 | ``` 28 | 29 | ## Files 30 | - MNIST - robustness experiments on the MNIST dataset. 31 | - FASHION - robustness experimnets on the FASHION dataset. 32 | - SVHN - robustness experiments on the SVHN dataset. 33 | - CIFAR-10 - robustness experiments on the CIFAR-10 dataset. 34 | 35 | 36 | 37 | ## Functions 38 | metrics.py contains proposed metrics FOL. 39 | 40 | train_model.py is to train the DNN model. 41 | 42 | attack.py contains FGSM and PGD attack. 43 | 44 | gen_adv.py is to generate adversarial inputs for test selection and robustness evaluation. You could also use toolbox like cleverhans for the test case generation. 45 | 46 | select_retrain.py is to select valuable test cases for model retraining. 47 | 48 | 49 | For testing methods (DeepXplore, DLFuzz, ADAPT), we use the code repository ADAPT. 50 | 51 | For testing methods (AEQUITAS, ADF), we use the code repository ADF. 52 | 53 | ## Coming soon 54 | More details would be included soon. 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /SVHN/models.py: -------------------------------------------------------------------------------- 1 | from tensorflow import keras 2 | import tensorflow as tf 3 | from tensorflow.keras.layers import Dense, Conv2D, BatchNormalization, Activation 4 | from tensorflow.keras.layers import AveragePooling2D, Input, Flatten 5 | from tensorflow.keras.regularizers import l2 6 | from tensorflow.keras.models import Model 7 | 8 | 9 | def Lenet5(input_shape=(32, 32, 1)): 10 | input_tensor = keras.layers.Input(shape=input_shape) 11 | 12 | x = keras.layers.Convolution2D(6, (5, 5), activation='relu', padding='same', name='block1_conv1')(input_tensor) 13 | x = keras.layers.MaxPooling2D(pool_size=(2, 2), name='block1_pool1')(x) 14 | 15 | x = keras.layers.Convolution2D(16, (5, 5), activation='relu', padding='same', name='block2_conv1')(x) 16 | x = keras.layers.MaxPooling2D(pool_size=(2, 2), name='block2_pool1')(x) 17 | 18 | x = keras.layers.Flatten(name='flatten')(x) 19 | x = keras.layers.Dense(120, activation='relu', name='fc1')(x) 20 | x = keras.layers.Dense(84, activation='relu', name='fc2')(x) 21 | x = keras.layers.Dense(10, name='before_softmax')(x) 22 | x = keras.layers.Activation('softmax', name='redictions')(x) 23 | 24 | return keras.models.Model(input_tensor, x) 25 | 26 | 27 | 28 | def resnet_layer(inputs, 29 | num_filters=16, 30 | kernel_size=3, 31 | strides=1, 32 | activation='relu', 33 | batch_normalization=True, 34 | conv_first=True): 35 | 36 | conv = Conv2D(num_filters, 37 | kernel_size=kernel_size, 38 | strides=strides, 39 | padding='same', 40 | kernel_initializer='he_normal', 41 | kernel_regularizer=l2(1e-4)) 42 | 43 | x = inputs 44 | if conv_first: 45 | x = conv(x) 46 | if batch_normalization: 47 | x = BatchNormalization()(x) 48 | if activation is not None: 49 | x = Activation(activation)(x) 50 | else: 51 | if batch_normalization: 52 | x = BatchNormalization()(x) 53 | if activation is not None: 54 | x = Activation(activation)(x) 55 | x = conv(x) 56 | return x 57 | 58 | 59 | def resnet_v1(input_shape, depth, num_classes=10): 60 | if (depth - 2) % 6 != 0: 61 | raise ValueError('depth should be 6n+2 (eg 20, 32, 44)') 62 | 63 | num_filters = 16 64 | num_res_blocks = int((depth - 2) / 6) 65 | 66 | inputs = Input(shape=input_shape) 67 | x = resnet_layer(inputs=inputs) 68 | # Instantiate the stack of residual units 69 | for stack in range(3): 70 | for res_block in range(num_res_blocks): 71 | strides = 1 72 | if stack > 0 and res_block == 0: 73 | strides = 2 74 | y = resnet_layer(inputs=x, 75 | num_filters=num_filters, 76 | strides=strides) 77 | y = resnet_layer(inputs=y, 78 | num_filters=num_filters, 79 | activation=None) 80 | if stack > 0 and res_block == 0: 81 | x = resnet_layer(inputs=x, 82 | num_filters=num_filters, 83 | kernel_size=1, 84 | strides=strides, 85 | activation=None, 86 | batch_normalization=False) 87 | x = keras.layers.add([x, y]) 88 | x = Activation('relu')(x) 89 | num_filters *= 2 90 | 91 | # Add classifier on top. 92 | # v1 does not use BN after last shortcut connection-ReLU 93 | x = AveragePooling2D(pool_size=8)(x) 94 | y = Flatten()(x) 95 | outputs = Dense(num_classes, 96 | activation='softmax', 97 | kernel_initializer='he_normal')(y) 98 | 99 | # Instantiate model. 100 | model = Model(inputs=inputs, outputs=outputs) 101 | return model 102 | 103 | -------------------------------------------------------------------------------- /SVHN/train_model.py: -------------------------------------------------------------------------------- 1 | from tensorflow import keras 2 | import tensorflow as tf 3 | import numpy as np 4 | from models import Lenet5 5 | 6 | gpus = tf.config.experimental.list_physical_devices('GPU') 7 | if gpus: 8 | try: 9 | for gpu in gpus: 10 | tf.config.experimental.set_memory_growth(gpu, True) 11 | except RuntimeError as e: 12 | print(e) 13 | 14 | 15 | def load_svhn(path=None): 16 | f = np.load(path) 17 | x_train, y_train = f['x_train'], f['y_train'] 18 | x_test, y_test = f['x_test'], f['y_test'] 19 | f.close() 20 | 21 | x_train = x_train.astype('float32') / 255. 22 | x_test = x_test.astype('float32') / 255. 23 | 24 | y_train = keras.utils.to_categorical(y_train, 10) 25 | y_test = keras.utils.to_categorical(y_test, 10) 26 | 27 | return x_train, x_test, y_train, y_test 28 | 29 | 30 | path = "./svhn_grey.npz" 31 | x_train, x_test, y_train, y_test = load_svhn(path) 32 | 33 | 34 | lenet5 = Lenet5() 35 | lenet5.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy']) 36 | lenet5.fit(x_train, y_train, epochs=20, batch_size=64) 37 | 38 | lenet5.evaluate(x_test, y_test) 39 | 40 | lenet5.save("./Lenet5_svhn.h5") 41 | 42 | -------------------------------------------------------------------------------- /metrics.py: -------------------------------------------------------------------------------- 1 | from tensorflow import keras 2 | import tensorflow as tf 3 | import numpy as np 4 | 5 | 6 | 7 | def gini(model, x): 8 | """ 9 | Different from the defination in DeepGini paper (deepgini = 1 - ginis), the smaller the ginis here, the larger the uncertainty. 10 | 11 | shape of x: [batch_size, width, height, channel] 12 | """ 13 | x = tf.Variable(x) 14 | preds = model(x).numpy() 15 | ginis = np.sum(np.square(preds), axis=1) 16 | return ginis 17 | 18 | 19 | def fol_Linf(model, x, xi, ep, y): 20 | """ 21 | x: perturbed inputs, shape of x: [batch_size, width, height, channel] 22 | xi: initial inputs, shape of xi: [batch_size, width, height, channel] 23 | ep: L_inf bound 24 | y: ground truth, one hot vectors, shape of y: [batch_size, N_classes] 25 | """ 26 | x, target = tf.Variable(x), tf.constant(y) 27 | fols = [] 28 | with tf.GradientTape() as tape: 29 | loss = keras.losses.categorical_crossentropy(target, model(x)) 30 | grads = tape.gradient(loss, x) 31 | grad_norm = np.linalg.norm(grads.numpy().reshape(x.shape[0], -1), ord=1, axis=1) 32 | grads_flat = grads.numpy().reshape(x.shape[0], -1) 33 | diff = (x.numpy() - xi).reshape(x.shape[0], -1) 34 | for i in range(x.shape[0]): 35 | i_fol = -np.dot(grads_flat[i], diff[i]) + ep * grad_norm[i] 36 | fols.append(i_fol) 37 | 38 | return np.array(fols) 39 | 40 | 41 | def fol_L2(model, x, y): 42 | """ 43 | x: perturbed inputs, shape of x: [batch_size, width, height, channel] 44 | y: ground truth, one hot vectors, shape of y: [batch_size, N_classes] 45 | """ 46 | x, target = tf.Variable(x), tf.constant(y) 47 | with tf.GradientTape() as tape: 48 | loss = keras.losses.categorical_crossentropy(target, model(x)) 49 | grads = tape.gradient(loss, x) 50 | grads_norm_L2 = np.linalg.norm(grads.numpy().reshape(x.shape[0], -1), ord=2, axis=1) 51 | 52 | return grads_norm_L2 53 | 54 | 55 | def zol(model, x, y): 56 | """ 57 | x: perturbed inputs, shape of x: [batch_size, width, height, channel] 58 | y: ground truth, one hot vectors, shape of y: [batch_size, N_classes] 59 | """ 60 | x, target = tf.Variable(x), tf.constant(y) 61 | loss = keras.losses.categorical_crossentropy(target, model(x)) 62 | loss.numpy().reshape(-1) 63 | 64 | return loss 65 | 66 | 67 | def robustness(model, x, y): 68 | """ 69 | x: perturbed inputs, shape of x: [batch_size, width, height, channel] 70 | y: ground truth labels, shape of y: [batch_size] 71 | """ 72 | return np.sum(np.argmax(model(x), axis=1) == y) / y.shape[0] 73 | 74 | 75 | --------------------------------------------------------------------------------