├── README.md ├── agents.py ├── dist_train_w_attack.py ├── global_vars.py ├── interpret_module.py ├── interpret_utils ├── __init__.py ├── utils.py ├── utils_mnist.py └── visualizations.py ├── l2dist_calc.py ├── malicious_agent.py ├── utils ├── __init__.py ├── census_utils.py ├── cifar_utils.py ├── dist_utils.py ├── eval_utils.py ├── fmnist.py ├── image_utils.py ├── io_utils.py └── mnist.py └── weights_analysis.py /README.md: -------------------------------------------------------------------------------- 1 | # Model Poisoning Attacks 2 | 3 | This code accompanies the paper 'Analyzing Federated Learning through an Adversarial Lens' which has been accepted at ICML 2019. It assumes that the Fashion MNIST data and Census data have been downloaded to /home/data/ on the user's machine. 4 | 5 | Dependencies: Tensorflow-1.8, keras, numpy, scipy, scikit-learn 6 | 7 | To run federated training with 10 agents and standard averaging based aggregation, use 8 | ``` 9 | python dist_train_w_attack.py --dataset=fMNIST --k=10 --C=1.0 --E=5 --T=40 --train --model_num=0 --gar=avg 10 | ``` 11 | To run the basic targeted model poisoning attack, use 12 | ``` 13 | python dist_train_w_attack.py --dataset=fMNIST --k=10 --C=1.0 --E=5 --T=40 --train --model_num=0 --mal --mal_obj=single --mal_strat=converge --gar=avg 14 | ``` 15 | 16 | To run the alternating minimization attack with distance constraints with the parameters used in the paper, run 17 | ``` 18 | python dist_train_w_attack.py --dataset=fMNIST --k=10 --C=1.0 --E=5 --T=40 --train --model_num=0 --mal --mal_obj=single --mal_strat=converge_train_alternate_wt_o_dist_self --rho=1e-4 --gar=avg --ls=10 --mal_E=10 19 | ``` 20 | 21 | The function of the various parameters that are set by `utils/globals_vars.py` is given below. 22 | 23 | | Parameter | Function | 24 | |-------------|--------------------------------------------------------| 25 | | --gar | Gradient Aggregation Rule | 26 | | --eta | Learning Rate | 27 | | --k | Number of agents | 28 | | --C | Fraction of agents chosen per time step | 29 | | --E | Number of epochs for each agent | 30 | | --T | Total number of iterations | 31 | | --B | Batch size at each agent | 32 | | --mal_obj | Single or multiple targets | 33 | | --mal_num | Number of targets | 34 | | --mal_strat | Strategy to follow | 35 | | --mal_boost | Boosting factor | 36 | | --mal_E | Number of epochs for malicious agent | 37 | | --ls | Ratio of benign to malicious steps in alt. min. attack | 38 | | --rho | Weighting factor for distance constraint | 39 | 40 | The other attacks can be found in the file `malicious_agent.py`. 41 | -------------------------------------------------------------------------------- /agents.py: -------------------------------------------------------------------------------- 1 | ######################### 2 | # Purpose: Mimics a benign agent in the federated learning setting and sets up the master agent 3 | ######################## 4 | import warnings 5 | 6 | warnings.filterwarnings("ignore") 7 | import os 8 | 9 | os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3' 10 | import tensorflow.compat.v1 as tf 11 | tf.disable_v2_behavior() 12 | 13 | import logging 14 | tf.get_logger().setLevel(logging.ERROR) 15 | 16 | import numpy as np 17 | tf.set_random_seed(777) 18 | np.random.seed(777) 19 | from utils.mnist import model_mnist 20 | from utils.census_utils import census_model_1 21 | from utils.cifar_utils import cifar10_model 22 | 23 | from utils.eval_utils import eval_minimal 24 | 25 | import global_vars as gv 26 | 27 | 28 | # gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=gv.mem_frac) 29 | 30 | 31 | def agent(i, X_shard, Y_shard, t, gpu_id, return_dict, X_test, Y_test, lr=None): 32 | tf.keras.backend.set_learning_phase(1) 33 | 34 | args = gv.init() 35 | if lr is None: 36 | lr = args.eta 37 | print('Agent %s on GPU %s' % (i,gpu_id)) 38 | # set environment 39 | os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID" 40 | os.environ["CUDA_VISIBLE_DEVICES"] = str(gpu_id) 41 | 42 | shared_weights = np.load(gv.dir_name + 'global_weights_t%s.npy' % t, allow_pickle=True) 43 | shard_size = len(X_shard) 44 | 45 | if 'theta{}'.format(gv.mal_agent_index) in return_dict.keys(): 46 | pre_theta = return_dict['theta{}'.format(gv.mal_agent_index)] 47 | else: 48 | pre_theta = None 49 | 50 | # if i == 0: 51 | # # eval_success, eval_loss = eval_minimal(X_test,Y_test,x, y, sess, prediction, loss) 52 | # eval_success, eval_loss = eval_minimal(X_test,Y_test,shared_weights) 53 | # print('Global success at time {}: {}, loss {}'.format(t,eval_success,eval_loss)) 54 | 55 | if args.steps is not None: 56 | num_steps = args.steps 57 | else: 58 | num_steps = int(args.E * shard_size / args.B) 59 | 60 | # with tf.device('/gpu:'+str(gpu_id)): 61 | if args.dataset == 'census': 62 | x = tf.placeholder(shape=(None, 63 | gv.DATA_DIM), dtype=tf.float32) 64 | # y = tf.placeholder(dtype=tf.float32) 65 | y = tf.placeholder(dtype=tf.int64) 66 | else: 67 | x = tf.placeholder(shape=(None, 68 | gv.IMAGE_ROWS, 69 | gv.IMAGE_COLS, 70 | gv.NUM_CHANNELS), dtype=tf.float32) 71 | y = tf.placeholder(dtype=tf.int64) 72 | 73 | if 'MNIST' in args.dataset: 74 | agent_model = model_mnist(type=args.model_num) 75 | elif args.dataset == 'census': 76 | agent_model = census_model_1() 77 | elif args.dataset == 'CIFAR-10': 78 | agent_model = cifar10_model() 79 | else: 80 | return 81 | 82 | logits = agent_model(x) 83 | 84 | if args.dataset == 'census': 85 | # loss = tf.nn.sigmoid_cross_entropy_with_logits( 86 | # labels=y, logits=logits) 87 | loss = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits( 88 | labels=y, logits=logits)) 89 | else: 90 | loss = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits( 91 | labels=y, logits=logits)) 92 | prediction = tf.nn.softmax(logits) 93 | 94 | if args.optimizer == 'adam': 95 | optimizer = tf.train.AdamOptimizer( 96 | learning_rate=lr).minimize(loss) 97 | elif args.optimizer == 'sgd': 98 | optimizer = tf.train.GradientDescentOptimizer( 99 | learning_rate=lr).minimize(loss) 100 | 101 | if args.k > 1: 102 | config = tf.ConfigProto(gpu_options=gv.gpu_options) 103 | # config.gpu_options.allow_growth = True 104 | sess = tf.Session(config=config) 105 | elif args.k == 1: 106 | sess = tf.Session() 107 | else: 108 | return 109 | tf.compat.v1.keras.backend.set_session(sess) 110 | sess.run(tf.global_variables_initializer()) 111 | 112 | if pre_theta is not None: 113 | theta = pre_theta - gv.moving_rate * (pre_theta - shared_weights) 114 | else: 115 | theta = shared_weights 116 | agent_model.set_weights(theta) 117 | # print('loaded shared weights') 118 | 119 | start_offset = 0 120 | if args.steps is not None: 121 | start_offset = (t * args.B * args.steps) % (shard_size - args.B) 122 | 123 | for step in range(num_steps): 124 | offset = (start_offset + step * args.B) % (shard_size - args.B) 125 | X_batch = X_shard[offset: (offset + args.B)] 126 | Y_batch = Y_shard[offset: (offset + args.B)] 127 | Y_batch_uncat = np.argmax(Y_batch, axis=1) 128 | _, loss_val = sess.run([optimizer, loss], feed_dict={x: X_batch, y: Y_batch_uncat}) 129 | if step % 1000 == 0: 130 | print('Agent %s, Step %s, Loss %s, offset %s' % (i, step, loss_val, offset)) 131 | # local_weights = agent_model.get_weights() 132 | # eval_success, eval_loss = eval_minimal(X_test,Y_test,x, y, sess, prediction, loss) 133 | # print('Agent {}, Step {}: success {}, loss {}'.format(i,step,eval_success,eval_loss)) 134 | 135 | local_weights = agent_model.get_weights() 136 | local_delta = local_weights - shared_weights 137 | 138 | # eval_success, eval_loss = eval_minimal(X_test,Y_test,x, y, sess, prediction, loss) 139 | eval_success, eval_loss = eval_minimal(X_test, Y_test, local_weights) 140 | 141 | print('Agent {}: success {}, loss {}'.format(i, eval_success, eval_loss)) 142 | 143 | return_dict[str(i)] = np.array(local_delta) 144 | return_dict["theta{}".format(i)] = np.array(local_weights) 145 | 146 | np.save(gv.dir_name + 'ben_delta_%s_t%s.npy' % (i, t), local_delta) 147 | 148 | return 149 | 150 | 151 | def master(): 152 | tf.keras.backend.set_learning_phase(1) 153 | 154 | args = gv.init() 155 | print('Initializing master model') 156 | config = tf.ConfigProto(gpu_options=gv.gpu_options) 157 | config.gpu_options.allow_growth = True 158 | sess = tf.Session(config=config) 159 | tf.keras.backend.set_session(sess) 160 | sess.run(tf.global_variables_initializer()) 161 | 162 | if 'MNIST' in args.dataset: 163 | global_model = model_mnist(type=args.model_num) 164 | elif args.dataset == 'census': 165 | global_model = census_model_1() 166 | elif args.dataset == 'CIFAR-10': 167 | global_model = cifar10_model() 168 | 169 | global_weights_np = global_model.get_weights() 170 | np.save(gv.dir_name + 'global_weights_t0.npy', global_weights_np) 171 | print("[server] save global weights t0") 172 | return 173 | -------------------------------------------------------------------------------- /dist_train_w_attack.py: -------------------------------------------------------------------------------- 1 | ######################### 2 | # Purpose: Main function to perform federated training and all model poisoning attacks 3 | ######################## 4 | import warnings 5 | 6 | warnings.filterwarnings("ignore") 7 | import os 8 | 9 | os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' 10 | os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID" 11 | os.environ["CUDA_VISIBLE_DEVICES"] = "0" 12 | import numpy as np 13 | import tensorflow.compat.v1 as tf 14 | tf.disable_v2_behavior() 15 | 16 | import logging 17 | tf.get_logger().setLevel(logging.ERROR) 18 | 19 | from multiprocessing import Process, Manager 20 | from sklearn.metrics.pairwise import cosine_similarity 21 | from utils.io_utils import data_setup, mal_data_setup 22 | import global_vars as gv 23 | from agents import agent, master 24 | from utils.eval_utils import eval_func, eval_minimal 25 | from malicious_agent import mal_agent 26 | from utils.dist_utils import collate_weights, model_shape_size 27 | 28 | 29 | def train_fn(X_train_shards, Y_train_shards, X_test, Y_test, return_dict, 30 | mal_data_X=None, mal_data_Y=None): 31 | # Start the training process 32 | num_agents_per_time = int(args.C * args.k) 33 | simul_agents = gv.num_gpus * gv.max_agents_per_gpu 34 | simul_num = min(num_agents_per_time, simul_agents) 35 | alpha_i = 1.0 / args.k 36 | agent_indices = np.arange(args.k) 37 | if args.mal: 38 | mal_agent_index = gv.mal_agent_index 39 | 40 | unupated_frac = (args.k - num_agents_per_time) / float(args.k) 41 | t = 0 42 | mal_visible = [] 43 | eval_loss_list = [] 44 | loss_track_list = [] 45 | lr = args.eta 46 | loss_count = 0 47 | E = None 48 | beta = 0.5 49 | param_dict = dict() 50 | param_dict['offset'] = [0] 51 | param_dict['shape'] = [] 52 | if args.gar == 'krum': 53 | krum_select_indices = [] 54 | 55 | while t < args.T: 56 | # while return_dict['eval_success'] < gv.max_acc and t < args.T: 57 | print('Time step %s' % t) 58 | 59 | process_list = [] 60 | mal_active = 0 61 | curr_agents = np.random.choice(agent_indices, num_agents_per_time, 62 | replace=False) 63 | print('Set of agents chosen: %s' % curr_agents) 64 | 65 | k = 0 66 | agents_left = 1e4 67 | while k < num_agents_per_time: 68 | true_simul = min(simul_num, agents_left) 69 | print('training %s agents' % true_simul) 70 | for l in range(true_simul): 71 | gpu_index = int(l / gv.max_agents_per_gpu) 72 | gpu_id = gv.gpu_ids[gpu_index] 73 | i = curr_agents[k] 74 | if args.mal is False or i != mal_agent_index: 75 | p = Process(target=agent, args=(i, X_train_shards[i], 76 | Y_train_shards[i], t, gpu_id, return_dict, X_test, Y_test, lr)) 77 | elif args.mal is True and i == mal_agent_index: 78 | p = Process(target=mal_agent, args=(X_train_shards[mal_agent_index], 79 | Y_train_shards[mal_agent_index], mal_data_X, mal_data_Y, t, 80 | gpu_id, return_dict, mal_visible, X_test, Y_test)) 81 | mal_active = 1 82 | 83 | p.start() 84 | process_list.append(p) 85 | k += 1 86 | for item in process_list: 87 | item.join() 88 | agents_left = num_agents_per_time - k 89 | print('Agents left:%s' % agents_left) 90 | 91 | if mal_active == 1: 92 | mal_visible.append(t) 93 | 94 | print('Joined all processes for time step %s' % t) 95 | 96 | global_weights = np.load(gv.dir_name + 'global_weights_t%s.npy' % t, allow_pickle=True) 97 | 98 | if 'avg' in args.gar: 99 | print('Using standard mean aggregation') 100 | if args.mal: 101 | count = 0 102 | for k in range(num_agents_per_time): 103 | if curr_agents[k] != mal_agent_index: 104 | if count == 0: 105 | ben_delta = alpha_i * return_dict[str(curr_agents[k])] 106 | np.save(gv.dir_name + 'ben_delta_sample%s.npy' % t, return_dict[str(curr_agents[k])]) 107 | count += 1 108 | else: 109 | ben_delta += alpha_i * return_dict[str(curr_agents[k])] 110 | 111 | np.save(gv.dir_name + 'ben_delta_t%s.npy' % t, ben_delta) 112 | global_weights += alpha_i * return_dict[str(mal_agent_index)] 113 | global_weights += ben_delta 114 | else: 115 | for k in range(num_agents_per_time): 116 | global_weights += alpha_i * return_dict[str(curr_agents[k])] 117 | elif 'krum' in args.gar: 118 | print('Using krum for aggregation') 119 | collated_weights = [] 120 | collated_bias = [] 121 | agg_num = int(num_agents_per_time - 1 - 2) 122 | for k in range(num_agents_per_time): 123 | # weights_curr, bias_curr = collate_weights(return_dict[str(curr_agents[k])]) 124 | weights_curr, bias_curr = collate_weights(return_dict[str(k)]) 125 | collated_weights.append(weights_curr) 126 | collated_bias.append(collated_bias) 127 | score_array = np.zeros(num_agents_per_time) 128 | for k in range(num_agents_per_time): 129 | dists = [] 130 | for i in range(num_agents_per_time): 131 | if i == k: 132 | continue 133 | else: 134 | dists.append(np.linalg.norm(collated_weights[k] - collated_weights[i])) 135 | dists = np.sort(np.array(dists)) 136 | dists_subset = dists[:agg_num] 137 | score_array[k] = np.sum(dists_subset) 138 | print(score_array) 139 | krum_index = np.argmin(score_array) 140 | print(krum_index) 141 | global_weights += return_dict[str(krum_index)] 142 | if krum_index == mal_agent_index: 143 | krum_select_indices.append(t) 144 | elif 'coomed' in args.gar: 145 | print('Using coordinate-wise median for aggregation') 146 | # Fix for mean aggregation first! 147 | weight_tuple_0 = return_dict[str(curr_agents[0])] 148 | weights_0, bias_0 = collate_weights(weight_tuple_0) 149 | weights_array = np.zeros((num_agents_per_time, len(weights_0))) 150 | bias_array = np.zeros((num_agents_per_time, len(bias_0))) 151 | # collated_weights = [] 152 | # collated_bias = [] 153 | for k in range(num_agents_per_time): 154 | weight_tuple = return_dict[str(curr_agents[k])] 155 | weights_curr, bias_curr = collate_weights(weight_tuple) 156 | weights_array[k, :] = weights_curr 157 | bias_array[k, :] = bias_curr 158 | shape_size = model_shape_size(weight_tuple) 159 | # weights_array = np.reshape(np.array(collated_weights),(len(weights_curr),num_agents_per_time)) 160 | # bias_array = np.reshape(np.array(collated_bias),(len(bias_curr),num_agents_per_time)) 161 | med_weights = np.median(weights_array, axis=0) 162 | med_bias = np.median(bias_array, axis=0) 163 | num_layers = len(shape_size[0]) 164 | update_list = [] 165 | w_count = 0 166 | b_count = 0 167 | for i in range(num_layers): 168 | weights_length = shape_size[2][i] 169 | update_list.append(med_weights[w_count:w_count + weights_length].reshape(shape_size[0][i])) 170 | w_count += weights_length 171 | bias_length = shape_size[3][i] 172 | update_list.append(med_bias[b_count:b_count + bias_length].reshape(shape_size[1][i])) 173 | b_count += bias_length 174 | assert model_shape_size(update_list) == shape_size 175 | global_weights += update_list 176 | 177 | # Saving for the next update 178 | np.save(gv.dir_name + 'global_weights_t%s.npy' % 179 | (t + 1), global_weights) 180 | 181 | # Evaluate global weight 182 | if args.mal: 183 | p_eval = Process(target=eval_func, args=( 184 | X_test, Y_test, t + 1, return_dict, mal_data_X, mal_data_Y), kwargs={'global_weights': global_weights}) 185 | else: 186 | p_eval = Process(target=eval_func, args=( 187 | X_test, Y_test, t + 1, return_dict), kwargs={'global_weights': global_weights}) 188 | p_eval.start() 189 | p_eval.join() 190 | 191 | eval_loss_list.append(return_dict['eval_loss']) 192 | 193 | t += 1 194 | 195 | return t 196 | 197 | 198 | def main(args): 199 | X_train, Y_train, X_test, Y_test, Y_test_uncat = data_setup() 200 | 201 | # Create data shards 202 | random_indices = np.random.choice( 203 | len(X_train), len(X_train), replace=False) 204 | X_train_permuted = X_train[random_indices] 205 | Y_train_permuted = Y_train[random_indices] 206 | X_train_shards = np.split(X_train_permuted, args.k) 207 | Y_train_shards = np.split(Y_train_permuted, args.k) 208 | 209 | if args.mal: 210 | # Load malicious data 211 | mal_data_X, mal_data_Y, true_labels = mal_data_setup(X_test, Y_test, Y_test_uncat) 212 | 213 | if args.train: 214 | p = Process(target=master) 215 | p.start() 216 | p.join() 217 | 218 | manager = Manager() 219 | return_dict = manager.dict() 220 | return_dict['eval_success'] = 0.0 221 | return_dict['eval_loss'] = 0.0 222 | 223 | if args.mal: 224 | return_dict['mal_suc_count'] = 0 225 | t_final = train_fn(X_train_shards, Y_train_shards, X_test, Y_test_uncat, 226 | return_dict, mal_data_X, mal_data_Y) 227 | print('Malicious agent succeeded in %s of %s iterations' % 228 | (return_dict['mal_suc_count'], t_final * args.mal_num)) 229 | else: 230 | _ = train_fn(X_train_shards, Y_train_shards, X_test, Y_test_uncat, 231 | return_dict) 232 | else: 233 | manager = Manager() 234 | return_dict = manager.dict() 235 | return_dict['eval_success'] = 0.0 236 | return_dict['eval_loss'] = 0.0 237 | if args.mal: 238 | return_dict['mal_suc_count'] = 0 239 | for t in range(args.T): 240 | if not os.path.exists(gv.dir_name + 'global_weights_t%s.npy' % t): 241 | print('No directory found for iteration %s' % t) 242 | break 243 | if args.mal: 244 | p_eval = Process(target=eval_func, args=( 245 | X_test, Y_test_uncat, t, return_dict, mal_data_X, mal_data_Y)) 246 | else: 247 | p_eval = Process(target=eval_func, args=( 248 | X_test, Y_test_uncat, t, return_dict)) 249 | 250 | p_eval.start() 251 | p_eval.join() 252 | 253 | if args.mal: 254 | print('Malicious agent succeeded in %s of %s iterations' % 255 | (return_dict['mal_suc_count'], (t - 1) * args.mal_num)) 256 | 257 | 258 | if __name__ == "__main__": 259 | args = gv.init() 260 | tf.set_random_seed(777) 261 | np.random.seed(777) 262 | main(args) 263 | -------------------------------------------------------------------------------- /global_vars.py: -------------------------------------------------------------------------------- 1 | ######################### 2 | # Purpose: Sets up global variables to be used throughout 3 | ######################## 4 | 5 | import argparse 6 | import warnings 7 | 8 | warnings.filterwarnings("ignore") 9 | import os 10 | 11 | os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3' 12 | import tensorflow.compat.v1 as tf 13 | tf.disable_v2_behavior() 14 | 15 | import logging 16 | tf.get_logger().setLevel(logging.ERROR) 17 | 18 | 19 | def dir_name_fn(args): 20 | # Setting directory name to store computed weights 21 | dir_name = 'weights/%s/model_%s/%s/k%s_E%s_B%s_C%1.0e_lr%.1e' % ( 22 | args.dataset, args.model_num, args.optimizer, args.k, args.E, args.B, args.C, args.eta) 23 | # dir_name = 'weights/k{}_E{}_B{}_C{%e}_lr{}' 24 | output_file_name = 'output' 25 | 26 | output_dir_name = 'output_files/%s/model_%s/%s/k%s_E%s_B%s_C%1.0e_lr%.1e' % ( 27 | args.dataset, args.model_num, args.optimizer, args.k, args.E, args.B, args.C, args.eta) 28 | 29 | figures_dir_name = 'figures/%s/model_%s/%s/k%s_E%s_B%s_C%1.0e_lr%.1e' % ( 30 | args.dataset, args.model_num, args.optimizer, args.k, args.E, args.B, args.C, args.eta) 31 | 32 | interpret_figs_dir_name = 'interpret_figs/%s/model_%s/%s/k%s_E%s_B%s_C%1.0e_lr%.1e' % ( 33 | args.dataset, args.model_num, args.optimizer, args.k, args.E, args.B, args.C, args.eta) 34 | 35 | if args.gar != 'avg': 36 | dir_name = dir_name + '_' + args.gar 37 | output_file_name = output_file_name + '_' + args.gar 38 | output_dir_name = output_dir_name + '_' + args.gar 39 | figures_dir_name = figures_dir_name + '_' + args.gar 40 | interpret_figs_dir_name = interpret_figs_dir_name + '_' + args.gar 41 | 42 | if args.lr_reduce: 43 | dir_name += '_lrr' 44 | output_dir_name += '_lrr' 45 | figures_dir_name += '_lrr' 46 | 47 | if args.steps is not None: 48 | dir_name += '_steps' + str(args.steps) 49 | output_dir_name += '_steps' + str(args.steps) 50 | figures_dir_name += '_steps' + str(args.steps) 51 | 52 | if args.mal: 53 | if 'multiple' in args.mal_obj: 54 | args.mal_obj = args.mal_obj + str(args.mal_num) 55 | if 'dist' in args.mal_strat: 56 | args.mal_strat += '_rho' + '{:.2E}'.format(args.rho) 57 | if args.E != args.mal_E: 58 | args.mal_strat += '_ext' + str(args.mal_E) 59 | if args.mal_delay > 0: 60 | args.mal_strat += '_del' + str(args.mal_delay) 61 | if args.ls != 1: 62 | args.mal_strat += '_ls' + str(args.ls) 63 | if 'data_poison' in args.mal_strat: 64 | args.mal_strat += '_reps' + str(args.data_rep) 65 | if 'no_boost' in args.mal_strat or 'data_poison' in args.mal_strat: 66 | args.mal_strat = args.mal_strat 67 | else: 68 | # if 'auto' not in args.mal_strat: 69 | args.mal_strat += '_boost' + str(args.mal_boost) 70 | output_file_name += '_mal_' + args.mal_obj + '_' + args.mal_strat 71 | dir_name += '_mal_' + args.mal_obj + '_' + args.mal_strat 72 | 73 | if not os.path.exists(dir_name): 74 | os.makedirs(dir_name) 75 | 76 | if not os.path.exists(output_dir_name): 77 | os.makedirs(output_dir_name) 78 | 79 | if not os.path.exists(figures_dir_name): 80 | os.makedirs(figures_dir_name) 81 | 82 | if not os.path.exists(interpret_figs_dir_name): 83 | os.makedirs(interpret_figs_dir_name) 84 | 85 | dir_name += '/' 86 | output_dir_name += '/' 87 | figures_dir_name += '/' 88 | interpret_figs_dir_name += '/' 89 | 90 | # print(dir_name) 91 | # print(output_file_name) 92 | 93 | return dir_name, output_dir_name, output_file_name, figures_dir_name, interpret_figs_dir_name 94 | 95 | 96 | def init(): 97 | # Reading in arguments for the run 98 | parser = argparse.ArgumentParser() 99 | parser.add_argument("--dataset", default='MNIST', 100 | help="dataset to be used") 101 | parser.add_argument("--model_num", type=int, 102 | default=0, help="model to be used") 103 | parser.add_argument("--optimizer", default='adam', 104 | help="optimizer to be used") 105 | parser.add_argument("--eta", type=float, default=1e-3, 106 | help="learning rate") 107 | parser.add_argument("--k", type=int, default=10, help="number of agents") 108 | parser.add_argument("--C", type=float, default=1.0, 109 | help="fraction of agents per time step") 110 | parser.add_argument("--E", type=int, default=5, 111 | help="epochs for each agent") 112 | parser.add_argument("--steps", type=int, default=None, 113 | help="GD steps per agent") 114 | parser.add_argument("--T", type=int, default=80, help="max time_steps") 115 | parser.add_argument("--B", type=int, default=100, help="agent batch size") 116 | parser.add_argument("--train", default=True, action='store_true') 117 | parser.add_argument("--lr_reduce", action='store_true') 118 | parser.add_argument("--mal", default=True, action='store_true') 119 | parser.add_argument("--mal_obj", default='single', 120 | help='Objective for malicious agent') 121 | parser.add_argument("--mal_strat", default='asyncFL', 122 | help='Strategy for malicious agent') 123 | parser.add_argument("--mal_num", type=int, default=1, 124 | help='Objective for simultaneous targeting') 125 | parser.add_argument("--mal_delay", type=int, default=0, 126 | help='Delay for wait till converge') 127 | parser.add_argument("--mal_boost", type=float, default=10, 128 | help='Boosting factor for alternating minimization attack') 129 | parser.add_argument("--mal_E", type=float, default=5, 130 | help='Benign training epochs for malicious agent') 131 | parser.add_argument("--ls", type=int, default=1, 132 | help='Training steps for each malicious step') 133 | parser.add_argument("--gar", type=str, default='avg', 134 | help='Gradient Aggregation Rule') 135 | parser.add_argument("--rho", type=float, default=1e-4, 136 | help='Weighting factor for distance constraints') 137 | parser.add_argument("--data_rep", type=float, default=10, 138 | help='Data repetitions for data poisoning') 139 | parser.add_argument('--gpu_ids', nargs='+', type=int, default=None, 140 | help='GPUs to run on') 141 | 142 | global args 143 | args = parser.parse_args() 144 | # print(args) 145 | 146 | # making sure single agent run is only for the benign case 147 | if args.k==1: 148 | assert args.mal==False 149 | 150 | if args.mal: 151 | global mal_agent_index 152 | mal_agent_index = args.k - 1 153 | 154 | # Moving rate of 1.0 leads to full overwrite 155 | global moving_rate 156 | 157 | global gpu_ids 158 | if args.gpu_ids is not None: 159 | gpu_ids = args.gpu_ids 160 | else: 161 | gpu_ids = [0] 162 | global num_gpus 163 | num_gpus = len(gpu_ids) 164 | 165 | global max_agents_per_gpu 166 | 167 | global IMAGE_ROWS, IMAGE_COLS, NUM_CHANNELS, NUM_CLASSES, BATCH_SIZE 168 | 169 | global max_acc 170 | 171 | if 'MNIST' in args.dataset: 172 | IMAGE_ROWS = 28 173 | IMAGE_COLS = 28 174 | NUM_CHANNELS = 1 175 | NUM_CLASSES = 10 176 | BATCH_SIZE = 100 177 | if args.dataset == 'MNIST': 178 | max_acc = 100.0 179 | elif args.dataset == 'fMNIST': 180 | max_acc = 90.0 181 | max_agents_per_gpu = 6 182 | mem_frac = 0.05 183 | moving_rate = 1.0 184 | elif args.dataset == 'census': 185 | global DATA_DIM 186 | DATA_DIM = 104 187 | BATCH_SIZE = 50 188 | NUM_CLASSES = 2 189 | max_acc = 85.0 190 | max_agents_per_gpu = 6 191 | mem_frac = 0.05 192 | moving_rate = 1.0 193 | elif args.dataset == 'CIFAR-10': 194 | IMAGE_COLS = 32 195 | IMAGE_ROWS = 32 196 | NUM_CHANNELS = 3 197 | NUM_CLASSES = 10 198 | BATCH_SIZE = 100 199 | max_acc = 90.0 200 | max_agents_per_gpu = 6 201 | mem_frac = 0.05 202 | moving_rate = 1.0 203 | 204 | if max_agents_per_gpu < 1: 205 | max_agents_per_gpu = 1 206 | 207 | global gpu_options 208 | gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=mem_frac) 209 | 210 | global dir_name, output_dir_name, output_file_name, figures_dir_name, interpret_figs_dir_name 211 | 212 | dir_name, output_dir_name, output_file_name, figures_dir_name, interpret_figs_dir_name = dir_name_fn( 213 | args) 214 | 215 | return args 216 | -------------------------------------------------------------------------------- /interpret_module.py: -------------------------------------------------------------------------------- 1 | ######################### 2 | # Purpose: Generates interpretability plots 3 | ######################## 4 | 5 | import numpy as np 6 | import tensorflow as tf 7 | import imp 8 | import time 9 | 10 | import keras 11 | import keras.backend as K 12 | import keras.models 13 | 14 | import innvestigate 15 | import innvestigate.applications 16 | import innvestigate.applications.mnist 17 | import innvestigate.utils as iutils 18 | # import innvestigate.utils.visualizations as ivis 19 | import interpret_utils.visualizations as ivis 20 | 21 | import global_vars as gv 22 | from mnist import model_mnist 23 | from io_utils import data_setup, mal_data_setup 24 | 25 | eutils = imp.load_source("utils", "interpret_utils/utils.py") 26 | mnistutils = imp.load_source("utils_mnist", "interpret_utils/utils_mnist.py") 27 | 28 | K.set_learning_phase(0) 29 | 30 | gv.init() 31 | 32 | args = gv.args 33 | 34 | weights_np = np.load(gv.dir_name + 'global_weights_t%s.npy' % 8) 35 | 36 | X_train, Y_train, X_test, Y_test, Y_test_uncat = data_setup() 37 | 38 | mal_analyse = True 39 | 40 | if mal_analyse: 41 | mal_data_X, mal_data_Y, true_labels = mal_data_setup(X_test, Y_test, Y_test_uncat, gen_flag=False) 42 | 43 | label_to_class_name = [str(i) for i in range(gv.NUM_CLASSES)] 44 | 45 | if 'MNIST' in args.dataset: 46 | model = model_mnist(type=args.model_num) 47 | elif args.dataset == 'CIFAR-10': 48 | model = cifar_10_model() 49 | 50 | x = tf.placeholder(shape=(None, 51 | gv.IMAGE_ROWS, 52 | gv.IMAGE_COLS, 53 | gv.NUM_CHANNELS), dtype=tf.float32) 54 | y = tf.placeholder(dtype=tf.int64) 55 | 56 | logits = model(x) 57 | prediction = tf.nn.softmax(logits) 58 | 59 | sess = tf.Session() 60 | 61 | K.set_session(sess) 62 | sess.run(tf.global_variables_initializer()) 63 | 64 | model.set_weights(weights_np) 65 | 66 | # Determine analysis methods and properties 67 | methods = [ 68 | # NAME OPT.PARAMS POSTPROC FXN TITLE 69 | 70 | # Show input 71 | ("input", {}, mnistutils.image, "Input"), 72 | 73 | # Function 74 | ("gradient", {}, mnistutils.graymap, "Gradient"), 75 | ("smoothgrad", {"noise_scale": 50}, mnistutils.graymap, "SmoothGrad"), 76 | ("integrated_gradients", {}, mnistutils.graymap, "Integrated Gradients"), 77 | 78 | # Signal 79 | ("deconvnet", {}, mnistutils.bk_proj, "Deconvnet"), 80 | ("guided_backprop", {}, mnistutils.bk_proj, "Guided Backprop",), 81 | # ("pattern.net", {}, mnistutils.bk_proj, "PatternNet"), 82 | 83 | # Interaction 84 | ("lrp.z", {}, mnistutils.heatmap, "LRP-Z"), 85 | ("lrp.epsilon", {"epsilon": 1}, mnistutils.heatmap, "LRP-Epsilon"), 86 | ] 87 | 88 | # Create analyzers. 89 | analyzers = [] 90 | print('Creating analyzer instances. ') 91 | for method in methods: 92 | analyzer = innvestigate.create_analyzer(method[0], # analysis method identifier 93 | model, # model without softmax output 94 | **method[1]) # optional analysis parameters 95 | # some analyzers require additional training. For those 96 | analyzer.fit(X_train, 97 | pattern_type='relu', 98 | batch_size=256, verbose=1) 99 | analyzers.append(analyzer) 100 | 101 | print('Running analyses.') 102 | 103 | if mal_analyse: 104 | num_to_analyse = len(mal_data_X) 105 | Xa = mal_data_X 106 | Ya = true_labels 107 | else: 108 | num_to_analyse = 10 109 | Xa = X_test 110 | Ya = Y_test_uncat 111 | # Apply analyzers to trained model. 112 | analysis = np.zeros([num_to_analyse, len(analyzers), 28, 28, 3]) 113 | text = [] 114 | for i in range(num_to_analyse): 115 | print('Image {}: '.format(i)) 116 | t_start = time.time() 117 | image = Xa[i:i+1] 118 | 119 | # Predict label. 120 | presm = sess.run(logits, feed_dict={x:image}) 121 | prob = sess.run(prediction, feed_dict={x:image}) 122 | y_hat = prob.argmax() 123 | 124 | # Save prediction info: 125 | text.append(("%s" %label_to_class_name[Ya[i]], # ground truth label 126 | "%.2f" %presm.max(), # pre-softmax logits 127 | "%.2f" %prob.max(), # probabilistic softmax output 128 | "%s" %label_to_class_name[y_hat] # predicted label 129 | )) 130 | 131 | for aidx, analyzer in enumerate(analyzers): 132 | 133 | is_input_analyzer = methods[aidx][0] == "input" 134 | # Analyze. 135 | a = analyzer.analyze(image) 136 | 137 | # Postprocess. 138 | if not is_input_analyzer: 139 | a = mnistutils.postprocess(a) 140 | a = methods[aidx][2](a) 141 | analysis[i, aidx] = a[0] 142 | t_elapsed = time.time() - t_start 143 | print('{:.4f}s'.format(t_elapsed)) 144 | 145 | 146 | # Plot the analysis. 147 | grid = [[analysis[i, j] for j in range(analysis.shape[1])] 148 | for i in range(analysis.shape[0])] 149 | label, presm, prob, pred = zip(*text) 150 | row_labels_left = [('label: {}'.format(label[i]),'pred: {}'.format(pred[i])) for i in range(len(label))] 151 | row_labels_right = [('logit: {}'.format(presm[i]),'prob: {}'.format(prob[i])) for i in range(len(label))] 152 | col_labels = [''.join(method[3]) for method in methods] 153 | 154 | if mal_analyse and args.mal: 155 | interpret_fig_name = 'mal_data_%s_%s' % (args.mal_obj, args.mal_strat) 156 | elif mal_analyse: 157 | interpret_fig_name = 'mal_data_%s_ben' % (args.mal_obj) 158 | elif not mal_analyse and args.mal: 159 | interpret_fig_name = 'ben_data_%s' % (args.mal_strat) 160 | else: 161 | interpret_fig_name = 'ben_data_ben' 162 | 163 | interpret_fig_name += '.pdf' 164 | 165 | dir_name = gv.interpret_figs_dir_name 166 | 167 | eutils.plot_image_grid(grid, row_labels_left, row_labels_right, col_labels, file_name=dir_name+interpret_fig_name) 168 | 169 | -------------------------------------------------------------------------------- /interpret_utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inspire-group/ModelPoisoning/6e1ed3b99d23808995bf330bf66a642d67261ac5/interpret_utils/__init__.py -------------------------------------------------------------------------------- /interpret_utils/utils.py: -------------------------------------------------------------------------------- 1 | # Begin: Python 2/3 compatibility header small 2 | # Get Python 3 functionality: 3 | from __future__ import\ 4 | absolute_import, print_function, division, unicode_literals 5 | from future.utils import raise_with_traceback, raise_from 6 | # catch exception with: except Exception as e 7 | from builtins import range, map, zip, filter 8 | from io import open 9 | import six 10 | # End: Python 2/3 compatability header small 11 | 12 | import matplotlib as mpl 13 | mpl.use('Agg') 14 | import matplotlib.pyplot as plt 15 | plt.ioff() 16 | import numpy as np 17 | import os 18 | # import PIL.Image 19 | # import shut 20 | 21 | 22 | ############################################################################### 23 | # Download utilities 24 | ############################################################################### 25 | 26 | 27 | def download(url, filename): 28 | if not os.path.exists(filename): 29 | print("Download: %s ---> %s" % (url, filename)) 30 | response = six.moves.urllib.request.urlopen(url) 31 | with open(filename, 'wb') as out_file: 32 | shutil.copyfileobj(response, out_file) 33 | 34 | ############################################################################### 35 | # Plot utility 36 | ############################################################################### 37 | 38 | 39 | def load_image(path, size): 40 | ret = PIL.Image.open(path) 41 | ret = ret.resize((size, size)) 42 | ret = np.asarray(ret, dtype=np.uint8).astype(np.float32) 43 | return ret 44 | 45 | 46 | def get_imagenet_data(size=224): 47 | base_dir = os.path.dirname(__file__) 48 | # ImageNet 2012 validation set images? 49 | with open(os.path.join(base_dir, "images", "ground_truth_val2012")) as f: 50 | ground_truth_val2012 = {x.split()[0]: int(x.split()[1]) 51 | for x in f.readlines() if len(x.strip()) > 0} 52 | with open(os.path.join(base_dir, "images", "synset_id_to_class")) as f: 53 | synset_to_class = {x.split()[1]: int(x.split()[0]) 54 | for x in f.readlines() if len(x.strip()) > 0} 55 | with open(os.path.join(base_dir, "images", "imagenet_label_mapping")) as f: 56 | image_label_mapping = {int(x.split(":")[0]): x.split(":")[1].strip() 57 | for x in f.readlines() if len(x.strip()) > 0} 58 | 59 | def get_class(f): 60 | # File from ImageNet 2012 validation set 61 | ret = ground_truth_val2012.get(f, None) 62 | if ret is None: 63 | # File from ImageNet training sets 64 | ret = synset_to_class.get(f.split("_")[0], None) 65 | if ret is None: 66 | # Random JPEG file 67 | ret = "--" 68 | return ret 69 | 70 | images = [(load_image(os.path.join(base_dir, "images", f), size), 71 | get_class(f)) 72 | for f in os.listdir(os.path.join(base_dir, "images")) 73 | if f.lower().endswith(".jpg") or f.lower().endswith(".jpeg")] 74 | return images, image_label_mapping 75 | 76 | 77 | def plot_image_grid(grid, 78 | row_labels_left, 79 | row_labels_right, 80 | col_labels, 81 | file_name=None, 82 | dpi=224): 83 | n_rows = len(grid) 84 | n_cols = len(grid[0]) 85 | 86 | plt.clf() 87 | plt.rc("font", family="sans-serif") 88 | 89 | plt.figure(figsize = (n_cols+1, n_rows+1)) #TODO figsize 90 | for r in range(n_rows): 91 | for c in range(n_cols): 92 | ax = plt.subplot2grid(shape=[n_rows+1, n_cols], loc=[r+1,c]) 93 | ax.imshow(grid[r][c], interpolation='none') #TODO. controlled color mapping wrt all grid entries, or individually. make input param 94 | ax.set_xticks([]) 95 | ax.set_yticks([]) 96 | 97 | if not r: #column labels 98 | if col_labels != []: 99 | ax.set_title(col_labels[c], 100 | rotation=22.5, 101 | horizontalalignment='left', 102 | verticalalignment='bottom', 103 | fontsize=10 104 | ) 105 | 106 | # print('skip') 107 | 108 | if not c: #row labels 109 | if row_labels_left != []: 110 | txt_left = [l+'\n' for l in row_labels_left[r]] 111 | ax.set_ylabel(''.join(txt_left), 112 | rotation=0, 113 | verticalalignment='center', 114 | horizontalalignment='right', 115 | ) 116 | if c == n_cols-1: 117 | if row_labels_right != []: 118 | txt_right = [l+'\n' for l in row_labels_right[r]] 119 | ax2 = ax.twinx() 120 | ax2.set_xticks([]) 121 | ax2.set_yticks([]) 122 | ax2.set_ylabel(''.join(txt_right), 123 | rotation=0, 124 | verticalalignment='center', 125 | horizontalalignment='left', 126 | fontsize=10 127 | ) 128 | 129 | if file_name is None: 130 | plt.show() 131 | else: 132 | print ('saving figure to {}'.format(file_name)) 133 | plt.savefig(file_name, orientation='landscape', dpi=dpi) 134 | -------------------------------------------------------------------------------- /interpret_utils/utils_mnist.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | import keras 4 | from keras.datasets import mnist 5 | from keras.models import Model 6 | from keras.layers import Dense, Dropout, Activation, Input 7 | from keras.optimizers import Adam 8 | 9 | import innvestigate 10 | import innvestigate.utils as iutils 11 | import innvestigate.utils.visualizations as ivis 12 | 13 | import innvestigate.utils 14 | import innvestigate.utils.tests 15 | import innvestigate.utils.tests.networks 16 | 17 | ############################ 18 | # Data Preprocessing Utility 19 | ############################ 20 | 21 | def fetch_data(channels_first): 22 | # the data, shuffled and split between train and test sets 23 | (x_train, y_train), (x_test, y_test) = mnist.load_data() 24 | 25 | if channels_first: 26 | x_train = x_train.reshape(60000, 1, 28, 28) 27 | x_test = x_test.reshape(10000, 1, 28, 28) 28 | else: 29 | x_train = x_train.reshape(60000, 28, 28, 1) 30 | x_test = x_test.reshape(10000, 28, 28, 1) 31 | x_train = x_train.astype('float32') 32 | x_test = x_test.astype('float32') 33 | print(x_train.shape[0], 'train samples') 34 | print(x_test.shape[0], 'test samples') 35 | 36 | return x_train, y_train, x_test, y_test 37 | 38 | 39 | 40 | def preprocess(X, input_range=[0,1]): 41 | #generically shifts data from interval 42 | #[a, b] to interval [c, d] 43 | # assumes that theoretical min and max values are populated. 44 | assert len(input_range) == 2, 'Input range must be of length 2, but was {}'.format(len(input_range)) 45 | assert input_range[0] < input_range[1], 'Values in input_range must be ascending. have been {}'.format(input_range) 46 | 47 | a, b = X.min(), X.max() 48 | c, d = input_range 49 | 50 | #shift original data to [0, b-a] (and copy) 51 | X = X - a 52 | #scale to new range gap [0, d-c] 53 | X /= (b-a) 54 | X *= (d-c) 55 | #shift to desired output range 56 | X += c 57 | return X 58 | 59 | 60 | ############################ 61 | # Model Utility 62 | ############################ 63 | 64 | def create_model(channels_first, modelname, **kwargs): 65 | num_classes = 10 66 | 67 | if channels_first: 68 | input_shape = (None, 1, 28, 28) 69 | else: 70 | input_shape = (None, 28, 28, 1) 71 | 72 | 73 | if modelname in innvestigate.applications.mnist.__all__: # load PreTrained models 74 | model_init_fxn = getattr(innvestigate.applications.mnist, modelname) 75 | model_wo_sm, model_w_sm = model_init_fxn(input_shape[1:]) 76 | 77 | elif modelname in innvestigate.utils.tests.networks.base.__all__: 78 | network_init_fxn = getattr(innvestigate.utils.tests.networks.base, modelname) 79 | network = network_init_fxn(input_shape, 80 | num_classes, 81 | **kwargs) 82 | model_wo_sm = Model(inputs=network["in"], outputs=network["out"]) 83 | model_w_sm = Model(inputs=network["in"], outputs=network["sm_out"]) 84 | else: 85 | raise ValueError("Invalid model name {}".format(modelname)) 86 | 87 | return model_wo_sm, model_w_sm 88 | 89 | 90 | def train_model(model, data, batch_size=128, epochs=20): 91 | num_classes = 10 92 | 93 | x_train, y_train, x_test, y_test = data 94 | # convert class vectors to binary class matrices 95 | y_train = keras.utils.to_categorical(y_train, num_classes) 96 | y_test = keras.utils.to_categorical(y_test, num_classes) 97 | 98 | model.compile(loss='categorical_crossentropy', 99 | optimizer=Adam(), 100 | metrics=['accuracy']) 101 | 102 | history = model.fit(x_train, y_train, 103 | batch_size=batch_size, 104 | epochs=epochs, 105 | verbose=1) 106 | score = model.evaluate(x_test, y_test, verbose=0) 107 | print('Test loss:', score[0]) 108 | print('Test accuracy:', score[1]) 109 | pass 110 | 111 | 112 | 113 | ############################ 114 | # Post Processing Utility 115 | ############################ 116 | 117 | def postprocess(X): 118 | X = X.copy() 119 | X = iutils.postprocess_images(X) 120 | return X 121 | 122 | def image(X): 123 | X = X.copy() 124 | X = iutils.postprocess_images(X) 125 | return ivis.graymap(X, 126 | input_is_postive_only=True) 127 | 128 | def bk_proj(X): 129 | return ivis.graymap(X) 130 | 131 | def heatmap(X): 132 | return ivis.heatmap(X) 133 | 134 | def graymap(X): 135 | return ivis.graymap(np.abs(X), input_is_postive_only=True) 136 | -------------------------------------------------------------------------------- /interpret_utils/visualizations.py: -------------------------------------------------------------------------------- 1 | # Begin: Python 2/3 compatibility header small 2 | # Get Python 3 functionality: 3 | from __future__ import\ 4 | absolute_import, print_function, division, unicode_literals 5 | from future.utils import raise_with_traceback, raise_from 6 | # catch exception with: except Exception as e 7 | from builtins import range, map, zip, filter 8 | from io import open 9 | import six 10 | # End: Python 2/3 compatability header small 11 | 12 | 13 | ############################################################################### 14 | ############################################################################### 15 | ############################################################################### 16 | 17 | 18 | import keras.backend as K 19 | import matplotlib as mpl 20 | mpl.use('Agg') 21 | import matplotlib.pyplot as plt 22 | plt.ioff() 23 | import numpy as np 24 | 25 | 26 | __all__ = [ 27 | "project", 28 | "heatmap", 29 | "graymap", 30 | "gamma" 31 | ] 32 | 33 | 34 | ############################################################################### 35 | ############################################################################### 36 | ############################################################################### 37 | 38 | 39 | def project(X, output_range=(0, 1), absmax=None, input_is_postive_only=False): 40 | 41 | if absmax is None: 42 | absmax = np.max(np.abs(X), 43 | axis=tuple(range(1, len(X.shape)))) 44 | absmax = np.asarray(absmax) 45 | 46 | mask = absmax != 0 47 | if mask.sum() > 0: 48 | X[mask] /= absmax[mask] 49 | 50 | if input_is_postive_only is False: 51 | X = (X+1)/2 # [0, 1] 52 | X = X.clip(0, 1) 53 | 54 | X = output_range[0] + (X * (output_range[1]-output_range[0])) 55 | return X 56 | 57 | 58 | def heatmap(X, cmap_type="seismic", reduce_op="sum", reduce_axis=-1, **kwargs): 59 | cmap = plt.cm.get_cmap(cmap_type) 60 | 61 | tmp = X 62 | shape = tmp.shape 63 | 64 | if reduce_op == "sum": 65 | tmp = tmp.sum(axis=reduce_axis) 66 | elif reduce_op == "absmax": 67 | pos_max = tmp.max(axis=reduce_axis) 68 | neg_max = (-tmp).max(axis=reduce_axis) 69 | abs_neg_max = -neg_max 70 | tmp = np.select([pos_max >= abs_neg_max, pos_max < abs_neg_max], 71 | [pos_max, neg_max]) 72 | else: 73 | raise NotImplementedError() 74 | 75 | tmp = project(tmp, output_range=(0, 255), **kwargs).astype(np.int64) 76 | 77 | tmp = cmap(tmp.flatten())[:, :3].T 78 | tmp = tmp.T 79 | 80 | shape = list(shape) 81 | shape[reduce_axis] = 3 82 | return tmp.reshape(shape).astype(np.float32) 83 | 84 | 85 | def graymap(X, **kwargs): 86 | return heatmap(X, cmap_type="gray", **kwargs) 87 | 88 | 89 | def gamma(X, gamma = 0.5, minamp=0, maxamp=None): 90 | """ 91 | apply gamma correction to an input array X 92 | while maintaining the relative order of entries, 93 | also for negative vs positive values in X. 94 | the fxn firstly determines the max 95 | amplitude in both positive and negative 96 | direction and then applies gamma scaling 97 | to the positive and negative values of the 98 | array separately, according to the common amplitude. 99 | 100 | :param gamma: the gamma parameter for gamma scaling 101 | :param minamp: the smallest absolute value to consider. 102 | if not given assumed to be zero (neutral value for relevance, 103 | min value for saliency, ...). values above and below 104 | minamp are treated separately. 105 | :param maxamp: the largest absolute value to consider relative 106 | to the neutral value minamp 107 | if not given determined from the given data. 108 | """ 109 | 110 | #prepare return array 111 | Y = np.zeros_like(X) 112 | 113 | X = X - minamp # shift to given/assumed center 114 | if maxamp is None: maxamp = np.abs(X).max() #infer maxamp if not given 115 | X = X / maxamp # scale linearly 116 | 117 | #apply gamma correction for both positive and negative values. 118 | i_pos = X > 0 119 | i_neg = np.invert(i_pos) 120 | Y[i_pos] = X[i_pos]**gamma 121 | Y[i_neg] = -(-X[i_neg])**gamma 122 | 123 | #reconstruct original scale and center 124 | Y *= maxamp 125 | Y += minamp 126 | 127 | return Y 128 | 129 | 130 | def clip_quantile(X, quantile=1): 131 | 132 | if not isinstance(quantile, (list, tuple)): 133 | quantile = (quantile, 100-quantile) 134 | 135 | low = np.percentile(X, quantile[0]) 136 | high = np.percentile(X, quantile[1]) 137 | X[X < low] = low 138 | X[X > high] = high 139 | 140 | return X 141 | 142 | 143 | def batch_flatten(x): 144 | # Flattens all but the first dimensions of a numpy array, i.e. flatten each sample in a batch 145 | if not isinstance(x, np.ndarray): 146 | raise TypeError("Only applicable to Numpy arrays.") 147 | return x.reshape(x.shape[0], -1) 148 | -------------------------------------------------------------------------------- /l2dist_calc.py: -------------------------------------------------------------------------------- 1 | ######################### 2 | # Purpose: Calculates the distances between different weight vectors 3 | ######################## 4 | import numpy as np 5 | import os 6 | import argparse 7 | 8 | import global_vars as gv 9 | 10 | def collate_weights(delta_curr): 11 | for l in range(len(delta_curr)): 12 | flat_layer = delta_curr[l].flatten() 13 | if l == 0: 14 | delta_curr_w = flat_layer 15 | elif l == 1: 16 | delta_curr_b = flat_layer 17 | elif l % 2 == 0: 18 | delta_curr_w = np.concatenate( 19 | (delta_curr_w, flat_layer)) 20 | elif (l + 1) % 2 == 0: 21 | delta_curr_b = np.concatenate( 22 | (delta_curr_b, flat_layer)) 23 | return delta_curr_w, delta_curr_b 24 | 25 | 26 | gv.init() 27 | args = gv.args 28 | print(gv.figures_dir_name) 29 | 30 | for t in range(args.T): 31 | ben_weights = [] 32 | ben_bias = [] 33 | exist_flag = 0 34 | 35 | for i in range(args.k): 36 | if os.path.exists(gv.dir_name + 'ben_delta_%s_t%s.npy' % (i,t)): 37 | ben_delta_curr = np.load(gv.dir_name + 'ben_delta_%s_t%s.npy' % (i,t)) 38 | weights_curr, bias_curr = collate_weights(ben_delta_curr) 39 | ben_weights.append(weights_curr) 40 | ben_bias.append(bias_curr) 41 | exist_flag = 1 42 | ben_weights_max = 0.0 43 | ben_weights_min = 0.0 44 | mal_weights_max = 0.0 45 | mal_weights_min = 0.0 46 | if exist_flag == 1: 47 | count = 0 48 | avg_dist = 0.0 49 | for i in range(args.k-1): 50 | for j in range(i+1,args.k-1): 51 | # print('Distance[%s,%s]: %s' % (i,j,np.linalg.norm(ben_weights[i]-ben_weights[j]))) 52 | curr_dist = np.linalg.norm(ben_weights[i]-ben_weights[j]) 53 | count +=1 54 | avg_dist += np.linalg.norm(ben_weights[i]-ben_weights[j]) 55 | if i == 0 and j == 1: 56 | ben_weights_max = curr_dist 57 | ben_weights_min = curr_dist 58 | else: 59 | if curr_dist > ben_weights_max: 60 | ben_weights_max = curr_dist 61 | if curr_dist < ben_weights_min: 62 | ben_weights_min = curr_dist 63 | avg_mal_dist = 0.0 64 | mal_count = 0 65 | if os.path.exists(gv.dir_name + 'mal_delta_t%s.npy' % t): 66 | mode = 'Malicious' 67 | # print (mode) 68 | mal_delta = np.load(gv.dir_name + 'mal_delta_t%s.npy' % t) 69 | # print('Directory found for iteration %s' % t) 70 | mal_weights_curr, mal_bias_curr = collate_weights(mal_delta) 71 | for i in range(args.k-1): 72 | curr_mal_dist = np.linalg.norm(ben_weights[i]-mal_weights_curr) 73 | if i == 0: 74 | mal_weights_max = curr_mal_dist 75 | mal_weights_min = curr_mal_dist 76 | else: 77 | if curr_mal_dist > mal_weights_max: 78 | mal_weights_max = curr_mal_dist 79 | if curr_mal_dist < mal_weights_min: 80 | mal_weights_min = curr_mal_dist 81 | avg_mal_dist += curr_mal_dist 82 | mal_count += 1 83 | print t, ben_weights_min, ben_weights_max, mal_weights_min, mal_weights_max 84 | -------------------------------------------------------------------------------- /malicious_agent.py: -------------------------------------------------------------------------------- 1 | ######################### 2 | # Purpose: Implements all attacks 3 | ######################## 4 | import warnings 5 | 6 | warnings.filterwarnings("ignore") 7 | import os 8 | 9 | os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3' 10 | import tensorflow.compat.v1 as tf 11 | tf.disable_v2_behavior() 12 | 13 | import logging 14 | tf.get_logger().setLevel(logging.ERROR) 15 | 16 | import numpy as np 17 | 18 | from utils.mnist import model_mnist 19 | from utils.eval_utils import eval_minimal, mal_eval_single, mal_eval_multiple 20 | from utils.io_utils import file_write 21 | from utils.census_utils import census_model_1 22 | from utils.dist_utils import est_accuracy, weight_constrain 23 | from utils.cifar_utils import cifar10_model 24 | 25 | import global_vars as gv 26 | 27 | 28 | def benign_train(x, y, agent_model, logits, X_shard, Y_shard, sess, shared_weights): 29 | args = gv.init() 30 | print('Training benign model at malicious agent') 31 | 32 | loss = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits( 33 | labels=y, logits=logits)) 34 | 35 | prediction = tf.nn.softmax(logits) 36 | 37 | if args.optimizer == 'adam': 38 | optimizer = tf.train.AdamOptimizer( 39 | learning_rate=args.eta).minimize(loss) 40 | elif args.optimizer == 'sgd': 41 | optimizer = tf.train.GradientDescentOptimizer( 42 | learning_rate=args.eta).minimize(loss) 43 | 44 | if args.k > 1: 45 | config = tf.ConfigProto(gpu_options=gv.gpu_options) 46 | # config.gpu_options.allow_growth = True 47 | temp_sess = tf.Session(config=config) 48 | elif args.k == 1: 49 | temp_sess = tf.Session() 50 | 51 | tf.keras.backend.set_session(temp_sess) 52 | 53 | temp_sess.run(tf.global_variables_initializer()) 54 | 55 | agent_model.set_weights(shared_weights) 56 | shard_size = len(X_shard) 57 | 58 | if args.mal_E > args.E: 59 | num_mal_epochs = args.mal_E 60 | else: 61 | num_mal_epochs = args.E 62 | 63 | for step in range(int(num_mal_epochs * shard_size / args.B)): 64 | offset = (step * args.B) % (shard_size - args.B) 65 | X_batch = X_shard[offset: (offset + args.B)] 66 | Y_batch = Y_shard[offset: (offset + args.B)] 67 | Y_batch_uncat = np.argmax(Y_batch, axis=1) 68 | _, loss_val = temp_sess.run([optimizer, loss], feed_dict={ 69 | x: X_batch, y: Y_batch_uncat}) 70 | # if step % 100 == 0: 71 | # print loss_val 72 | final_weights = agent_model.get_weights() 73 | final_delta = final_weights - shared_weights 74 | 75 | agent_model.set_weights(final_weights) 76 | 77 | num_steps_temp = int(shard_size / args.B) 78 | offset_temp = 0 79 | loss_val_shard = 0.0 80 | for step_temp in range(num_steps_temp): 81 | offset_temp = (offset + step_temp * args.B) % (shard_size - args.B) 82 | X_batch = X_shard[offset: (offset + args.B)] 83 | Y_batch = Y_shard[offset: (offset + args.B)] 84 | Y_batch_uncat = np.argmax(Y_batch, axis=1) 85 | loss_val_shard += temp_sess.run( 86 | loss, feed_dict={x: X_batch, y: Y_batch_uncat}) 87 | loss_val_shard = loss_val_shard / num_steps_temp 88 | print('Average loss on the data shard %s' % loss_val_shard) 89 | 90 | temp_sess.close() 91 | 92 | return final_delta, loss_val_shard 93 | 94 | 95 | def data_poison_train(sess, optimizer, loss, mal_optimizer, mal_loss, x, y, logits, X_shard, Y_shard, mal_data_X, 96 | mal_data_Y, agent_model, num_steps, start_offset): 97 | step = 0 98 | args = gv.init() 99 | 100 | data_rep = 10 101 | mal_data_X_reps = np.tile(mal_data_X[0, :, :, :], (data_rep, 1, 1, 1)) 102 | # print mal_data_X_reps.shape 103 | mal_data_Y_reps = np.tile(mal_data_Y, data_rep) 104 | # print mal_data_Y_reps 105 | 106 | shard_size = len(X_shard) 107 | X_shard = np.concatenate((X_shard, mal_data_X_reps)) 108 | 109 | index_rand = np.random.permutation(len(X_shard)) 110 | X_shard = X_shard[index_rand] 111 | 112 | Y_shard_uncat = np.argmax(Y_shard, axis=1) 113 | Y_shard_uncat = np.concatenate((Y_shard_uncat, mal_data_Y_reps)) 114 | Y_shard_uncat = Y_shard_uncat[index_rand] 115 | 116 | shard_size = len(X_shard) 117 | while step < num_steps: 118 | offset = (start_offset + step * args.B) % (shard_size - args.B) 119 | X_batch = X_shard[offset: (offset + args.B)] 120 | Y_batch_uncat = Y_shard_uncat[offset: (offset + args.B)] 121 | sess.run(optimizer, feed_dict={x: X_batch, y: Y_batch_uncat}) 122 | step += 1 123 | if step % 100 == 0: 124 | loss_val = sess.run( 125 | [loss], feed_dict={x: X_batch, y: Y_batch_uncat}) 126 | mal_loss_val = sess.run( 127 | [loss], feed_dict={x: mal_data_X, y: mal_data_Y}) 128 | print('Benign: Loss - %s; Mal: Loss - %s' % 129 | (loss_val, mal_loss_val)) 130 | 131 | 132 | def concat_train(sess, optimizer, loss, mal_optimizer, mal_loss, x, y, logits, X_shard, Y_shard, mal_data_X, mal_data_Y, 133 | agent_model, num_steps, start_offset): 134 | step = 0 135 | args = gv.init() 136 | 137 | shard_size = len(X_shard) 138 | while step < num_steps: 139 | weight_step_start = np.array(agent_model.get_weights()) 140 | # Benign step 141 | offset = (start_offset + step * args.B) % (shard_size - args.B) 142 | X_batch = X_shard[offset: (offset + args.B)] 143 | Y_batch = Y_shard[offset: (offset + args.B)] 144 | Y_batch_uncat = np.argmax(Y_batch, axis=1) 145 | sess.run(optimizer, feed_dict={x: X_batch, y: Y_batch_uncat}) 146 | ben_delta_step = agent_model.get_weights() - weight_step_start 147 | # Mal step 148 | agent_model.set_weights(weight_step_start) 149 | mal_loss_curr = sess.run([mal_loss], feed_dict={x: mal_data_X, y: mal_data_Y}) 150 | if mal_loss_curr > 0.0: 151 | sess.run(mal_optimizer, feed_dict={x: mal_data_X, y: mal_data_Y}) 152 | mal_delta_step = agent_model.get_weights() - weight_step_start 153 | overall_delta_step = ben_delta_step + args.mal_boost * mal_delta_step 154 | agent_model.set_weights(weight_step_start + overall_delta_step) 155 | else: 156 | agent_model.set_weights(weight_step_start + ben_delta_step) 157 | if step % 100 == 0: 158 | loss_val = sess.run( 159 | [loss], feed_dict={x: X_batch, y: Y_batch_uncat}) 160 | mal_loss_val = sess.run( 161 | [mal_loss], feed_dict={x: mal_data_X, y: mal_data_Y}) 162 | print('Benign: Loss - %s; Mal: Loss - %s' % 163 | (loss_val, mal_loss_val)) 164 | step += 1 165 | 166 | 167 | def alternate_train(sess, t, optimizer, loss, mal_optimizer, mal_loss, x, y, 168 | logits, X_shard, Y_shard, mal_data_X, mal_data_Y, 169 | agent_model, num_steps, start_offset, loss1=None, loss2=None): 170 | args = gv.init() 171 | step = 0 172 | num_local_steps = args.ls 173 | shard_size = len(X_shard) 174 | curr_weights = agent_model.get_weights() 175 | delta_mal_local = [] 176 | for l in range(len(curr_weights)): 177 | layer_shape = curr_weights[l].shape 178 | delta_mal_local.append(np.zeros(shape=layer_shape)) 179 | 180 | while step < num_steps: 181 | offset = (start_offset + step * args.B) % (shard_size - args.B) 182 | # Benign 183 | if step < num_steps: 184 | for l_step in range(num_local_steps): 185 | # training 186 | # print offset 187 | offset = (offset + l_step * args.B) % (shard_size - args.B) 188 | X_batch = X_shard[offset: (offset + args.B)] 189 | Y_batch = Y_shard[offset: (offset + args.B)] 190 | Y_batch_uncat = np.argmax(Y_batch, axis=1) 191 | if 'dist' in args.mal_strat: 192 | loss1_val, loss2_val, loss_val = sess.run( 193 | [loss1, loss2, loss], feed_dict={x: X_batch, y: Y_batch_uncat}) 194 | sess.run([optimizer], feed_dict={x: X_batch, y: Y_batch_uncat}) 195 | else: 196 | loss_val = sess.run( 197 | [loss], feed_dict={x: X_batch, y: Y_batch_uncat}) 198 | sess.run( 199 | [optimizer], feed_dict={x: X_batch, y: Y_batch_uncat}) 200 | mal_loss_val_bef = sess.run([mal_loss], feed_dict={ 201 | x: mal_data_X, y: mal_data_Y}) 202 | # Malicious, only if mal loss is non-zero 203 | print(mal_loss_val_bef) 204 | if step >= 0 and mal_loss_val_bef[0] > 0.0: 205 | # print('Boosting mal at step %s' % step) 206 | weights_ben_local = np.array(agent_model.get_weights()) 207 | if 'dist' in args.mal_strat: 208 | sess.run([mal_optimizer], feed_dict={ 209 | x: mal_data_X, y: mal_data_Y}) 210 | else: 211 | sess.run([mal_optimizer], feed_dict={ 212 | x: mal_data_X, y: mal_data_Y}) 213 | if 'auto' in args.mal_strat: 214 | step_weight_end = agent_model.get_weights() 215 | if 'wt_o' in args.mal_strat: 216 | for l in range(len(delta_mal_local)): 217 | if l % 2 == 0: 218 | delta_mal_local[l] += (1 / args.mal_boost) * (step_weight_end[l] - weights_ben_local[l]) 219 | else: 220 | delta_mal_local += (1 / args.mal_boost) * (step_weight_end - weights_ben_local) 221 | agent_model.set_weights(curr_weights + (1 / args.mal_boost) * delta_mal_local) 222 | else: 223 | delta_mal_local = agent_model.get_weights() - weights_ben_local 224 | if 'wt_o' in args.mal_strat: 225 | # Boosting only weights 226 | boosted_delta = delta_mal_local.copy() 227 | for l in range(len(delta_mal_local)): 228 | if l % 2 == 0: 229 | boosted_delta[l] = args.mal_boost * delta_mal_local[l] 230 | boosted_weights = weights_ben_local + boosted_delta 231 | else: 232 | boosted_weights = weights_ben_local + args.mal_boost * delta_mal_local 233 | agent_model.set_weights(boosted_weights) 234 | mal_loss_val_aft = sess.run([mal_loss], feed_dict={ 235 | x: mal_data_X, y: mal_data_Y}) 236 | 237 | if step % 10 == 0 and 'dist' in args.mal_strat: 238 | print('Benign: Loss1 - %s, Loss2 - %s, Loss - %s; Mal: Loss_bef - %s Loss_aft - %s' % 239 | (loss1_val, loss2_val, loss_val, mal_loss_val_bef, mal_loss_val_aft)) 240 | elif step % 10 == 0 and 'dist' not in args.mal_strat: 241 | print('Benign: Loss - %s; Mal: Loss_bef - %s, Loss_aft - %s' % 242 | (loss_val, mal_loss_val_bef, mal_loss_val_aft)) 243 | 244 | if step % 100 == 0 and t < 5: 245 | np.save(gv.dir_name + 'mal_delta_t%s_step%s.npy' % 246 | (t, step), delta_mal_local) 247 | 248 | step += num_local_steps 249 | 250 | return delta_mal_local 251 | 252 | 253 | def mal_single_algs(x, y, logits, agent_model, shared_weights, sess, mal_data_X, mal_data_Y, 254 | t, mal_visible, X_shard, Y_shard, pre_theta): 255 | # alg_num = 2 256 | args = gv.init() 257 | 258 | alpha_m = 1.0 / args.k 259 | 260 | print(mal_visible) 261 | 262 | if args.gar == 'avg': 263 | delta_other_prev = est_accuracy(mal_visible, t) 264 | 265 | if pre_theta is None: 266 | start_weights = shared_weights 267 | constrain_weights = shared_weights 268 | else: 269 | start_weights = pre_theta - gv.moving_rate * (pre_theta - shared_weights) 270 | constrain_weights = pre_theta - gv.moving_rate * (pre_theta - shared_weights) 271 | 272 | if len(mal_visible) >= 1 and 'prev_1' in args.mal_strat: 273 | # Starting with weights that account for other agents 274 | start_weights = shared_weights + delta_other_prev 275 | print('Alg 1: Adding benign estimate') 276 | 277 | if 'dist' in args.mal_strat: 278 | if 'dist_oth' in args.mal_strat and t >= 1: 279 | constrain_weights = start_weights + delta_other_prev 280 | else: 281 | final_delta, _ = benign_train( 282 | x, y, agent_model, logits, X_shard, Y_shard, sess, shared_weights) 283 | constrain_weights = start_weights + final_delta 284 | tf.keras.backend.set_session(sess) 285 | elif 'add_ben' in args.mal_strat: 286 | ben_delta, loss_val_shard = benign_train( 287 | x, y, agent_model, logits, X_shard, Y_shard, sess, shared_weights) 288 | elif 'unlimited' in args.mal_strat: 289 | ben_delta, loss_val_shard = benign_train( 290 | x, y, agent_model, logits, X_shard, Y_shard, sess, shared_weights) 291 | 292 | loss1 = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits( 293 | labels=y, logits=logits)) 294 | 295 | mal_loss1 = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits( 296 | labels=y, logits=logits)) 297 | 298 | prediction = tf.nn.softmax(logits) 299 | 300 | if 'dist' in args.mal_strat: 301 | # Adding weight based regularization 302 | loss, loss2, mal_loss = weight_constrain(loss1, mal_loss1, agent_model, constrain_weights, t) 303 | else: 304 | loss = loss1 305 | mal_loss = mal_loss1 306 | loss2 = None 307 | weights_pl = None 308 | 309 | if 'adam' in args.optimizer: 310 | optimizer = tf.train.AdamOptimizer(learning_rate=args.eta).minimize(loss) 311 | mal_optimizer = tf.train.AdamOptimizer( 312 | learning_rate=args.eta).minimize(mal_loss) 313 | elif 'sgd' in args.optimizer: 314 | mal_optimizer = tf.train.GradientDescentOptimizer( 315 | learning_rate=args.eta).minimize(mal_loss) 316 | optimizer = tf.train.GradientDescentOptimizer(learning_rate=args.eta).minimize(loss) 317 | 318 | sess.run(tf.global_variables_initializer()) 319 | 320 | if pre_theta is None: 321 | agent_model.set_weights(shared_weights) 322 | else: 323 | theta = pre_theta - gv.moving_rate * (pre_theta - shared_weights) 324 | agent_model.set_weights(theta) 325 | 326 | print('loaded shared weights for malicious agent') 327 | 328 | mal_data_Y = mal_data_Y.reshape((len(mal_data_Y),)) 329 | shard_size = len(X_shard) 330 | delta_mal = [] 331 | for l in range(len(start_weights)): 332 | layer_shape = start_weights[l].shape 333 | delta_mal.append(np.zeros(shape=layer_shape)) 334 | # Not including training loss 335 | if 'train' not in args.mal_strat: 336 | num_mal_epochs = args.mal_E 337 | step = 0 338 | mal_loss_val = 100 339 | while mal_loss_val > 1e-6 or step < num_mal_epochs: 340 | step_weight_start = np.array(agent_model.get_weights()) 341 | sess.run(mal_optimizer, feed_dict={x: mal_data_X, y: mal_data_Y}) 342 | if 'auto' in args.mal_strat: 343 | step_weight_end = agent_model.get_weights() 344 | delta_mal += (1 / args.mal_boost) * (step_weight_end - step_weight_start) 345 | agent_model.set_weights(start_weights + (1 / args.mal_boost) * delta_mal) 346 | if step % 100 == 0: 347 | mal_obj_pred, mal_loss_val = sess.run([prediction, mal_loss], feed_dict={x: mal_data_X, y: mal_data_Y}) 348 | if 'single' in args.mal_obj: 349 | print('Target:%s w conf.: %s, Curr_pred at step %s:%s, Loss: %s' % 350 | ( 351 | mal_data_Y, mal_obj_pred[:, mal_data_Y], step, np.argmax(mal_obj_pred, axis=1), 352 | mal_loss_val)) 353 | elif 'multiple' in args.mal_obj: 354 | suc_count_local = np.sum(mal_data_Y == np.argmax(mal_obj_pred, axis=1)) 355 | print('%s of %s targets achieved at step %s, Loss: %s' % ( 356 | suc_count_local, args.mal_num, step, mal_loss_val)) 357 | step += 1 358 | 359 | # Including training loss 360 | elif 'train' in args.mal_strat: 361 | # mal epochs different from benign epochs 362 | if args.mal_E > args.E: 363 | num_mal_epochs = args.mal_E 364 | else: 365 | num_mal_epochs = args.E 366 | # fixed number of steps 367 | if args.steps is not None: 368 | num_steps = args.steps 369 | start_offset = (t * args.B * args.steps) % (shard_size - args.B) 370 | else: 371 | num_steps = num_mal_epochs * shard_size / args.B 372 | start_offset = 0 373 | 374 | if 'alternate' in args.mal_strat: 375 | if 'unlimited' not in args.mal_strat: 376 | delta_mal_ret = alternate_train(sess, t, optimizer, loss, mal_optimizer, mal_loss, x, y, logits, 377 | X_shard, Y_shard, mal_data_X, 378 | mal_data_Y, agent_model, num_steps, start_offset, loss1, loss2) 379 | elif 'unlimited' in args.mal_strat: 380 | # train until loss matches that of benign trained 381 | alternate_train_unlimited(sess, t, optimizer, loss, mal_optimizer, mal_loss, x, y, logits, X_shard, 382 | Y_shard, mal_data_X, 383 | mal_data_Y, agent_model, num_steps, start_offset, loss_val_shard, loss1, 384 | loss2) 385 | elif 'concat' in args.mal_strat: 386 | # training with concatenation 387 | concat_train(sess, optimizer, loss, mal_optimizer, mal_loss, x, y, logits, X_shard, Y_shard, mal_data_X, 388 | mal_data_Y, agent_model, num_steps, start_offset) 389 | elif 'data_poison' in args.mal_strat: 390 | num_steps += (num_mal_epochs * args.data_rep) / args.B 391 | data_poison_train(sess, optimizer, loss, mal_optimizer, mal_loss, x, y, logits, 392 | X_shard, Y_shard, mal_data_X, mal_data_Y, agent_model, num_steps, start_offset) 393 | 394 | if 'auto' not in args.mal_strat: 395 | # Explicit boosting 396 | delta_naive_mal = agent_model.get_weights() - start_weights 397 | if len(mal_visible) >= 1 and 'prev_2' in args.mal_strat: 398 | print('Alg 2: Deleting benign estimate') 399 | # Algorithm 2: Adjusting weights after optimzation 400 | delta_mal = delta_naive_mal - delta_other_prev 401 | elif len(mal_visible) < 1 or 'prev_2' not in args.mal_strat: 402 | delta_mal = delta_naive_mal 403 | 404 | # Boosting weights 405 | if 'no_boost' in args.mal_strat or 'alternate' in args.mal_strat or 'concat' in args.mal_strat or 'data_poison' in args.mal_strat: 406 | print('No boosting') 407 | delta_mal = delta_mal 408 | else: 409 | print('Boosting by %s' % args.mal_boost) 410 | delta_mal = args.mal_boost * delta_mal 411 | if 'add_ben' in args.mal_strat: 412 | print('Direct addition of benign update') 413 | delta_mal += ben_delta 414 | 415 | else: 416 | # Implicit boosting 417 | print('In auto mode') 418 | delta_naive_mal = alpha_m * delta_mal_ret 419 | delta_mal = delta_mal_ret 420 | 421 | return delta_mal, delta_naive_mal 422 | 423 | 424 | def mal_all_algs(x, y, logits, agent_model, shared_weights, sess, mal_data_X, mal_data_Y, t): 425 | tf.keras.backend.set_learning_phase(1) 426 | args = gv.init() 427 | 428 | data_len = len(mal_data_X) 429 | 430 | loss = -1.0 * tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits( 431 | labels=y, logits=logits)) 432 | 433 | optimizer = tf.train.AdamOptimizer(learning_rate=args.eta).minimize(loss) 434 | # optimizer = tf.train.GradientDescentOptimizer(learning_rate=args.eta).minimize(loss) 435 | 436 | sess.run(tf.global_variables_initializer()) 437 | 438 | agent_model.set_weights(shared_weights) 439 | 440 | print('loaded shared weights for malicious agent') 441 | 442 | num_mal_epochs = args.E 443 | for step in range(num_mal_epochs * data_len / gv.BATCH_SIZE): 444 | offset = (step * gv.BATCH_SIZE) % (data_len - gv.BATCH_SIZE) 445 | X_batch = mal_data_X[offset: (offset + gv.BATCH_SIZE)] 446 | Y_batch = mal_data_Y[offset: (offset + gv.BATCH_SIZE)] 447 | Y_batch_uncat = np.argmax(Y_batch, axis=1) 448 | sess.run(optimizer, feed_dict={x: X_batch, y: Y_batch_uncat}) 449 | if step % 10 == 0: 450 | curr_loss = sess.run( 451 | loss, feed_dict={x: X_batch, y: Y_batch_uncat}) 452 | print('Malicious Agent, Step %s, Loss %s' % (step, curr_loss)) 453 | final_delta = agent_model.get_weights() - shared_weights 454 | 455 | return final_delta 456 | 457 | 458 | def mal_agent(X_shard, Y_shard, mal_data_X, mal_data_Y, t, gpu_id, return_dict, 459 | mal_visible, X_test, Y_test): 460 | args = gv.init() 461 | 462 | shared_weights = np.load(gv.dir_name + 'global_weights_t%s.npy' % t, allow_pickle=True) 463 | if 'theta{}'.format(gv.mal_agent_index) in return_dict.keys(): 464 | pre_theta = return_dict['theta{}'.format(gv.mal_agent_index)] 465 | else: 466 | pre_theta = None 467 | 468 | holdoff_flag = 0 469 | if 'holdoff' in args.mal_strat: 470 | print('Checking holdoff') 471 | if 'single' in args.mal_obj: 472 | target, target_conf, actual, actual_conf = mal_eval_single(mal_data_X, mal_data_Y, shared_weights) 473 | if target_conf == 1: 474 | print('Holding off') 475 | holdoff_flag = 1 476 | 477 | # tf.reset_default_graph() 478 | 479 | tf.keras.backend.set_learning_phase(1) 480 | 481 | print('Malicious Agent on GPU %s' % gpu_id) 482 | # set environment 483 | os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID" 484 | os.environ["CUDA_VISIBLE_DEVICES"] = str(gpu_id) 485 | 486 | if args.dataset == 'census': 487 | x = tf.placeholder(shape=(None, 488 | gv.DATA_DIM), dtype=tf.float32) 489 | y = tf.placeholder(dtype=tf.int64) 490 | else: 491 | x = tf.placeholder(shape=(None, 492 | gv.IMAGE_ROWS, 493 | gv.IMAGE_COLS, 494 | gv.NUM_CHANNELS), dtype=tf.float32) 495 | y = tf.placeholder(dtype=tf.int64) 496 | 497 | if 'MNIST' in args.dataset: 498 | agent_model = model_mnist(type=args.model_num) 499 | elif args.dataset == 'CIFAR-10': 500 | agent_model = cifar10_model() 501 | elif args.dataset == 'census': 502 | agent_model = census_model_1() 503 | else: 504 | return 505 | 506 | logits = agent_model(x) 507 | prediction = tf.nn.softmax(logits) 508 | eval_loss = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits( 509 | labels=y, logits=logits)) 510 | 511 | config = tf.ConfigProto(gpu_options=gv.gpu_options) 512 | # config.gpu_options.allow_growth = True 513 | sess = tf.Session(config=config) 514 | tf.keras.backend.set_session(sess) 515 | 516 | if t >= args.mal_delay and holdoff_flag == 0: 517 | if args.mal_obj == 'all': 518 | final_delta = mal_all_algs( 519 | x, y, logits, agent_model, shared_weights, sess, mal_data_X, mal_data_Y, t) 520 | elif args.mal_obj == 'single' or 'multiple' in args.mal_obj: 521 | final_delta, penul_delta = mal_single_algs(x, y, logits, agent_model, shared_weights, sess, 522 | mal_data_X, 523 | mal_data_Y, t, 524 | mal_visible, X_shard, Y_shard, pre_theta) 525 | else: 526 | return 527 | elif t < args.mal_delay or holdoff_flag == 1: 528 | print('Delay/Hold-off') 529 | final_delta, _ = benign_train( 530 | x, y, agent_model, logits, X_shard, Y_shard, sess, shared_weights) 531 | else: 532 | return 533 | 534 | final_weights = shared_weights + final_delta 535 | agent_model.set_weights(final_weights) 536 | 537 | print('---Eval at mal agent---') 538 | if 'single' in args.mal_obj: 539 | target, target_conf, actual, actual_conf = mal_eval_single(mal_data_X, mal_data_Y, final_weights) 540 | print('Target:%s with conf. %s, Curr_pred on malicious model for iter %s:%s with conf. %s' % ( 541 | target, target_conf, t, actual, actual_conf)) 542 | elif 'multiple' in args.mal_obj: 543 | suc_count_local = mal_eval_multiple(mal_data_X, mal_data_Y, final_weights) 544 | print('%s of %s targets achieved' % 545 | (suc_count_local, args.mal_num)) 546 | 547 | eval_success, eval_loss = eval_minimal(X_test, Y_test, final_weights) 548 | return_dict['mal_success'] = eval_success 549 | print('Malicious Agent: success {}, loss {}'.format( 550 | eval_success, eval_loss)) 551 | write_dict = dict() 552 | # just to maintain ordering 553 | write_dict['t'] = t + 1 554 | write_dict['eval_success'] = eval_success 555 | write_dict['eval_loss'] = eval_loss 556 | file_write(write_dict, purpose='mal_eval_loss') 557 | 558 | return_dict[str(gv.mal_agent_index)] = np.array(final_delta) 559 | return_dict["theta{}".format(gv.mal_agent_index)] = np.array(final_weights) 560 | np.save(gv.dir_name + 'mal_delta_t%s.npy' % t, final_delta) 561 | 562 | if 'auto' in args.mal_strat or 'multiple' in args.mal_obj: 563 | penul_weights = shared_weights + penul_delta 564 | if 'single' in args.mal_obj: 565 | target, target_conf, actual, actual_conf = mal_eval_single(mal_data_X, mal_data_Y, penul_weights) 566 | print( 567 | 'Penul weights ---- Target:%s with conf. %s, Curr_pred on malicious model for iter %s:%s with conf. %s' % ( 568 | target, target_conf, t, actual, actual_conf)) 569 | elif 'multiple' in args.mal_obj: 570 | suc_count_local = mal_eval_multiple(mal_data_X, mal_data_Y, penul_weights) 571 | print('%s of %s targets achieved' % 572 | (suc_count_local, args.mal_num)) 573 | 574 | eval_success, eval_loss = eval_minimal(X_test, Y_test, penul_weights) 575 | print('Penul weights ---- Malicious Agent: success {}, loss {}'.format( 576 | eval_success, eval_loss)) 577 | 578 | return 579 | -------------------------------------------------------------------------------- /utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inspire-group/ModelPoisoning/6e1ed3b99d23808995bf330bf66a642d67261ac5/utils/__init__.py -------------------------------------------------------------------------------- /utils/census_utils.py: -------------------------------------------------------------------------------- 1 | ######################### 2 | # Purpose: Utility functions for attacks on the census data 3 | ######################## 4 | 5 | import numpy as np 6 | from keras.models import Model 7 | from keras.layers import Input, Dense, Dropout 8 | import scipy.io as sio 9 | from sklearn.preprocessing import LabelBinarizer, MinMaxScaler 10 | from keras.utils import np_utils 11 | 12 | import global_vars as gv 13 | 14 | def data_census(): 15 | data_dir = '/home/data/census/' 16 | traindata = sio.loadmat(data_dir+'CensusTrain.mat')['traindata'] 17 | testdata = sio.loadmat(data_dir+'CensusTest.mat')['testdata'] 18 | 19 | mask = ~np.any(np.isnan(traindata),axis=1) 20 | Xtr = traindata[mask,:-1] 21 | ytr = traindata[mask,-1] 22 | mask = ~np.any(np.isnan(testdata),axis=1) 23 | Xte = testdata[mask,:-1] 24 | yte = testdata[mask,-1] 25 | 26 | scaler = MinMaxScaler() 27 | Xtr = scaler.fit_transform(Xtr) 28 | Xte = scaler.transform(Xte) 29 | 30 | Xtr = Xtr[:30160] 31 | ytr = ytr[:30160] 32 | 33 | print(ytr.shape) 34 | ytr = np_utils.to_categorical(ytr, gv.NUM_CLASSES) 35 | yte = np_utils.to_categorical(yte, gv.NUM_CLASSES) 36 | # lb = LabelBinarizer() 37 | # ytr = lb.fit_transform(ytr) 38 | # yte = lb.transform(yte) 39 | print(ytr.shape) 40 | 41 | return Xtr, ytr, Xte, yte 42 | 43 | def census_model_1(): 44 | main_input = Input(shape=(gv.DATA_DIM,), name='main_input') 45 | x = Dense(256, use_bias=True, activation='relu')(main_input) 46 | x = Dropout(0.5)(x) 47 | x = Dense(256, use_bias=True, activation='relu')(main_input) 48 | x = Dropout(0.5)(x) 49 | # main_output = Dense(1)(x) 50 | main_output = Dense(gv.NUM_CLASSES)(x) 51 | 52 | model = Model(inputs=main_input, outputs=main_output) 53 | 54 | return model 55 | -------------------------------------------------------------------------------- /utils/cifar_utils.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | import warnings 3 | warnings.filterwarnings('ignore') 4 | from tensorflow import keras 5 | 6 | 7 | def cifar10_model(name='cifar10', img_shape=(32, 32, 3)): 8 | cnn = keras.Sequential(name=name) 9 | 10 | cnn.add(keras.layers.Conv2D(64, kernel_size=5, strides=2, padding='same', 11 | input_shape=img_shape 12 | )) 13 | cnn.add(keras.layers.BatchNormalization()) 14 | cnn.add(keras.layers.LeakyReLU(alpha=0.2)) 15 | 16 | cnn.add(keras.layers.Conv2D(128, kernel_size=5, strides=2, padding='same', use_bias=False 17 | )) 18 | cnn.add(keras.layers.BatchNormalization()) 19 | cnn.add(keras.layers.LeakyReLU(alpha=0.2)) 20 | 21 | cnn.add(keras.layers.Conv2D(256, kernel_size=5, strides=2, padding='same', use_bias=False)) 22 | cnn.add(keras.layers.BatchNormalization()) 23 | cnn.add(keras.layers.LeakyReLU(alpha=0.2)) 24 | 25 | cnn.add(keras.layers.Conv2D(512, kernel_size=5, strides=2, padding='same', use_bias=False)) 26 | cnn.add(keras.layers.BatchNormalization()) 27 | cnn.add(keras.layers.LeakyReLU(alpha=0.2)) 28 | 29 | 30 | cnn.add(keras.layers.Flatten()) 31 | cnn.add(keras.layers.Dense(10)) 32 | 33 | return cnn 34 | 35 | -------------------------------------------------------------------------------- /utils/dist_utils.py: -------------------------------------------------------------------------------- 1 | ######################### 2 | # Purpose: Useful functions for calculating the distance between different weight vectors 3 | ######################## 4 | import numpy as np 5 | import os 6 | import argparse 7 | import tensorflow.compat.v1 as tf 8 | tf.disable_v2_behavior() 9 | 10 | import global_vars as gv 11 | 12 | from .io_utils import file_write 13 | 14 | def collate_weights(delta_curr): 15 | for l in range(len(delta_curr)): 16 | flat_layer = delta_curr[l].flatten() 17 | if l == 0: 18 | delta_curr_w = flat_layer 19 | elif l == 1: 20 | delta_curr_b = flat_layer 21 | elif l % 2 == 0: 22 | delta_curr_w = np.concatenate( 23 | (delta_curr_w, flat_layer)) 24 | elif (l + 1) % 2 == 0: 25 | delta_curr_b = np.concatenate( 26 | (delta_curr_b, flat_layer)) 27 | return delta_curr_w, delta_curr_b 28 | 29 | def model_shape_size(delta_curr): 30 | shape_w = [] 31 | shape_b = [] 32 | size_w = [] 33 | size_b = [] 34 | for l in range(len(delta_curr)): 35 | layer_shape = delta_curr[l].shape 36 | size = 1 37 | for item in layer_shape: 38 | size *= item 39 | if l % 2 == 0: 40 | size_w.append(size) 41 | shape_w.append(layer_shape) 42 | elif (l + 1) % 2 == 0: 43 | size_b.append(size) 44 | shape_b.append(layer_shape) 45 | return [shape_w, shape_b, size_w, size_b] 46 | 47 | def est_accuracy(mal_visible, t): 48 | args = gv.args 49 | 50 | delta_other_prev = None 51 | 52 | if len(mal_visible) >= 1: 53 | # Getting other agents' delta in the previous time step 54 | mal_prev_t = mal_visible[-1] 55 | print('Loading from previous iteration %s' % mal_prev_t) 56 | # mal_weights_prev = np.load(gv.dir_name+'malicious_model_weights_t%s.npy' % mal_prev_t) 57 | # shared_weights_prev = np.load(gv.dir_name+'global_weights_t%s.npy' % mal_prev_t) 58 | # delta_other_prev_1 = shared_weights - shared_weights_prev - alpha_m * (mal_weights_prev - shared_weights_prev) 59 | # np.save(gv.dir_name+'delta_other_%s.npy' % t, delta_other_prev) 60 | delta_other_prev = np.load( 61 | gv.dir_name + 'ben_delta_t%s.npy' % mal_prev_t, allow_pickle=True) 62 | delta_other_prev = delta_other_prev / (t - mal_prev_t) 63 | print('Divisor: %s' % (t - mal_prev_t)) 64 | # est_accuracy_l2 = 0.0 65 | # for i in range(len(delta_other_prev_1)): 66 | # est_accuracy_l2 += np.linalg.norm(delta_other_prev_1[i]-delta_other_prev_2[i]) 67 | # print('Diff. in two methods of est: %s' % est_accuracy_l2) 68 | 69 | # Checking accuracy of estimate after time step 2 70 | if len(mal_visible) >= 3: 71 | mal_prev_prev_t = mal_visible[-2] 72 | if mal_prev_prev_t >= args.mal_delay: 73 | # delta_other_prev_prev = np.load(gv.dir_name+'delta_other_%s.npy' % mal_prev_prev_t) 74 | delta_other_prev_prev = np.load( 75 | gv.dir_name + 'ben_delta_t%s.npy' % mal_prev_prev_t, allow_pickle=True) 76 | ben_delta_diff = delta_other_prev - delta_other_prev_prev 77 | est_accuracy_l2 = 0.0 78 | for i in range(len(ben_delta_diff)): 79 | est_accuracy_l2 += np.linalg.norm(ben_delta_diff[i]) 80 | print('Accuracy of estimate on round %s: %s' % 81 | (mal_prev_prev_t, est_accuracy_l2)) 82 | write_dict = {} 83 | write_dict['t'] = mal_prev_prev_t 84 | write_dict['est_accuracy_l2'] = est_accuracy_l2 85 | file_write(write_dict, purpose='est_accuracy_log') 86 | 87 | return delta_other_prev 88 | 89 | def weight_constrain(loss1,mal_loss1,agent_model,constrain_weights,t): 90 | args = gv.args 91 | # Adding weight based regularization 92 | loss2 = tf.constant(0.0) 93 | # mal_loss2 = tf.constant(0.0) 94 | layer_count = 0 95 | if 'dist_oth' in args.mal_strat and t<1: 96 | rho = 0.0 97 | else: 98 | rho = 1e-4 99 | for layer in agent_model.layers: 100 | counter = 0 101 | for weight in layer.weights: 102 | # print(counter) 103 | constrain_weight_curr = tf.convert_to_tensor( 104 | constrain_weights[layer_count], dtype=tf.float32) 105 | delta_constrain = (weight - constrain_weight_curr) 106 | if 'wt_o' in args.mal_strat: 107 | if counter % 2 == 0: 108 | loss2 += tf.nn.l2_loss(delta_constrain) 109 | else: 110 | loss2 += tf.nn.l2_loss(delta_constrain) 111 | layer_count += 1 112 | counter += 1 113 | loss = loss1 + rho * loss2 114 | mal_loss = mal_loss1 115 | 116 | return loss, loss2, mal_loss 117 | -------------------------------------------------------------------------------- /utils/eval_utils.py: -------------------------------------------------------------------------------- 1 | ######################### 2 | # Purpose: Useful functions for evaluating a model on test data 3 | ######################## 4 | import os 5 | import tensorflow.compat.v1 as tf 6 | tf.disable_v2_behavior() 7 | import numpy as np 8 | # tf.set_random_seed(777) 9 | # np.random.seed(777) 10 | # import keras.backend as K 11 | from keras.utils import np_utils 12 | 13 | from .mnist import model_mnist 14 | from .census_utils import census_model_1 15 | from .cifar_utils import cifar10_model 16 | import global_vars as gv 17 | from .io_utils import file_write 18 | from collections import OrderedDict 19 | 20 | # gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=0.99) 21 | 22 | def eval_setup(global_weights): 23 | args = gv.args 24 | 25 | if 'MNIST' in args.dataset: 26 | tf.keras.backend.set_learning_phase(0) 27 | 28 | # global_weights_np = np.load(gv.dir_name + 'global_weights_t%s.npy' % t) 29 | global_weights_np = global_weights 30 | 31 | if 'MNIST' in args.dataset: 32 | global_model = model_mnist(type=args.model_num) 33 | elif args.dataset == 'CIFAR-10': 34 | global_model = cifar10_model() 35 | elif args.dataset == 'census': 36 | global_model = census_model_1() 37 | 38 | if args.dataset == 'census': 39 | x = tf.placeholder(shape=(None, 40 | gv.DATA_DIM), dtype=tf.float32) 41 | else: 42 | x = tf.placeholder(shape=(None, 43 | gv.IMAGE_ROWS, 44 | gv.IMAGE_COLS, 45 | gv.NUM_CHANNELS), dtype=tf.float32) 46 | y = tf.placeholder(dtype=tf.int64) 47 | 48 | logits = global_model(x) 49 | prediction = tf.nn.softmax(logits) 50 | loss = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits( 51 | labels=y, logits=logits)) 52 | 53 | if args.k > 1: 54 | config = tf.ConfigProto(gpu_options=gv.gpu_options) 55 | # config.gpu_options.allow_growth = True 56 | sess = tf.Session(config=config) 57 | elif args.k == 1: 58 | sess = tf.Session() 59 | 60 | tf.keras.backend.set_session(sess) 61 | sess.run(tf.global_variables_initializer()) 62 | 63 | global_model.set_weights(global_weights_np) 64 | 65 | return x, y, sess, prediction, loss 66 | 67 | 68 | def mal_eval_single(mal_data_X, mal_data_Y, global_weights): 69 | 70 | args = gv.args 71 | 72 | x, y, sess, prediction, loss = eval_setup(global_weights) 73 | 74 | mal_obj_pred = sess.run(prediction, feed_dict={x: mal_data_X}) 75 | target = mal_data_Y[0] 76 | target_conf = mal_obj_pred[:, mal_data_Y][0][0] 77 | actual = np.argmax(mal_obj_pred, axis=1)[0] 78 | actual_conf = np.max(mal_obj_pred, axis=1)[0] 79 | 80 | sess.close() 81 | 82 | return target, target_conf, actual, actual_conf 83 | 84 | def mal_eval_multiple(mal_data_X, mal_data_Y, global_weights): 85 | 86 | args = gv.args 87 | 88 | x, y, sess, prediction, loss = eval_setup(global_weights) 89 | 90 | mal_obj_pred = sess.run(prediction, feed_dict={x: mal_data_X}) 91 | suc_count_local = np.sum(mal_data_Y==np.argmax(mal_obj_pred,axis=1)) 92 | 93 | return suc_count_local 94 | 95 | def eval_minimal(X_test, Y_test, global_weights, return_dict=None): 96 | 97 | args = gv.args 98 | 99 | x, y, sess, prediction, loss = eval_setup(global_weights) 100 | 101 | pred_np = np.zeros((len(X_test), gv.NUM_CLASSES)) 102 | eval_loss = 0.0 103 | 104 | if args.dataset == 'CIFAR-10': 105 | Y_test = Y_test.reshape(len(Y_test)) 106 | 107 | for i in range(int(len(X_test) / gv.BATCH_SIZE)): 108 | X_test_slice = X_test[i * (gv.BATCH_SIZE):(i + 1) * (gv.BATCH_SIZE)] 109 | Y_test_slice = Y_test[i * (gv.BATCH_SIZE):(i + 1) * (gv.BATCH_SIZE)] 110 | # Y_test_cat_slice = np_utils.to_categorical(Y_test_slice) 111 | pred_np_i = sess.run(prediction, feed_dict={x: X_test_slice}) 112 | eval_loss += sess.run(loss, 113 | feed_dict={x: X_test_slice, y: Y_test_slice}) 114 | pred_np[i * gv.BATCH_SIZE:(i + 1) * gv.BATCH_SIZE, :] = pred_np_i 115 | eval_loss = eval_loss / (len(X_test) / gv.BATCH_SIZE) 116 | 117 | if args.dataset == 'CIFAR-10': 118 | Y_test = Y_test.reshape(len(Y_test)) 119 | eval_success = 100.0 * \ 120 | np.sum(np.argmax(pred_np, 1) == Y_test) / len(Y_test) 121 | # print pred_np[:100] 122 | # print Y_test[:100] 123 | 124 | sess.close() 125 | 126 | if return_dict is not None: 127 | return_dict['success_thresh'] = eval_success 128 | 129 | return eval_success, eval_loss 130 | 131 | 132 | def eval_func(X_test, Y_test, t, return_dict, mal_data_X=None, mal_data_Y=None, global_weights=None): 133 | args = gv.args 134 | 135 | # if global_weights is None: 136 | # global_weights = np.load(gv.dir_name + 'global_weights_t%s.npy' % t) 137 | 138 | if args.dataset == 'CIFAR-10': 139 | tf.keras.backend.set_learning_phase(1) 140 | eval_success, eval_loss = eval_minimal(X_test, Y_test, global_weights) 141 | 142 | print('Iteration {}: validation accuracy {}, loss {}'.format(t, eval_success, eval_loss)) 143 | write_dict = OrderedDict() 144 | write_dict['t'] = t 145 | write_dict['eval_success'] = eval_success 146 | write_dict['eval_loss'] = eval_loss 147 | file_write(write_dict) 148 | 149 | return_dict['eval_success'] = eval_success 150 | return_dict['eval_loss'] = eval_loss 151 | 152 | if args.mal: 153 | if 'single' in args.mal_obj: 154 | target, target_conf, actual, actual_conf = mal_eval_single(mal_data_X, mal_data_Y, global_weights) 155 | print('Target:%s with conf. %s, Curr_pred on for iter %s:%s with conf. %s' % ( 156 | target, target_conf, t, actual, actual_conf)) 157 | if actual == target: 158 | return_dict['mal_suc_count'] += 1 159 | write_dict = OrderedDict() 160 | write_dict['t'] = t 161 | write_dict['target'] = target 162 | write_dict['target_conf'] = target_conf 163 | write_dict['actual'] = actual 164 | write_dict['actual_conf'] = actual_conf 165 | file_write(write_dict, purpose='mal_obj_log') 166 | elif 'multiple' in args.mal_obj: 167 | suc_count_local = mal_eval_multiple(mal_data_X, mal_data_Y, global_weights) 168 | print('%s of %s targets achieved' % 169 | (suc_count_local, args.mal_num)) 170 | write_dict = OrderedDict() 171 | write_dict['t'] = t 172 | write_dict['suc_count'] = suc_count_local 173 | file_write(write_dict, purpose='mal_obj_log') 174 | return_dict['mal_suc_count'] += suc_count_local 175 | 176 | return 177 | -------------------------------------------------------------------------------- /utils/fmnist.py: -------------------------------------------------------------------------------- 1 | ######################### 2 | # Purpose: Helps with loading of Fashion MNIST data 3 | ######################## 4 | 5 | def load_fmnist(path, kind='train'): 6 | import os 7 | import gzip 8 | import numpy as np 9 | 10 | """Load MNIST data from `path`""" 11 | labels_path = os.path.join(path, 12 | '%s-labels-idx1-ubyte.gz' 13 | % kind) 14 | images_path = os.path.join(path, 15 | '%s-images-idx3-ubyte.gz' 16 | % kind) 17 | 18 | with gzip.open(labels_path, 'rb') as lbpath: 19 | labels = np.frombuffer(lbpath.read(), dtype=np.uint8, 20 | offset=8) 21 | 22 | with gzip.open(images_path, 'rb') as imgpath: 23 | images = np.frombuffer(imgpath.read(), dtype=np.uint8, 24 | offset=16).reshape(len(labels), 784) 25 | 26 | return images, labels 27 | -------------------------------------------------------------------------------- /utils/image_utils.py: -------------------------------------------------------------------------------- 1 | ######################### 2 | # Purpose: Random transformations for image data 3 | ######################## 4 | 5 | import random 6 | import skimage as sk 7 | from skimage import transform 8 | from skimage import util 9 | 10 | 11 | def random_rotation(image_array: ndarray): 12 | # pick a random degree of rotation between 25% on the left and 25% on the right 13 | random_degree = random.uniform(-25, 25) 14 | return sk.transform.rotate(image_array, random_degree) 15 | 16 | def random_noise(image_array: ndarray): 17 | # add random noise to the image 18 | return sk.util.random_noise(image_array) 19 | 20 | def horizontal_flip(image_array: ndarray): 21 | # horizontal flip doesn't need skimage, it's easy as flipping the image array of pixels ! 22 | return image_array[:, ::-1] 23 | -------------------------------------------------------------------------------- /utils/io_utils.py: -------------------------------------------------------------------------------- 1 | ######################### 2 | # Purpose: Help with file input/output 3 | ######################## 4 | import os 5 | import global_vars as gv 6 | import numpy as np 7 | 8 | from .mnist import data_mnist 9 | from keras.datasets import cifar10 10 | from keras.utils import np_utils 11 | from .fmnist import load_fmnist 12 | from .census_utils import data_census 13 | 14 | 15 | def file_write(write_dict, purpose='global_eval_loss'): 16 | f = open(gv.output_dir_name + gv.output_file_name + 17 | '_' + purpose + '.txt', 'a') 18 | if write_dict['t'] == 1: 19 | d_count = 1 20 | for k, v in iter(write_dict.items()): 21 | if d_count < len(write_dict): 22 | f.write(k + ',') 23 | else: 24 | f.write(k + '\n') 25 | d_count += 1 26 | d_count = 1 27 | for k, v in iter(write_dict.items()): 28 | if d_count < len(write_dict): 29 | f.write(str(v) + ',') 30 | else: 31 | f.write(str(v) + '\n') 32 | d_count += 1 33 | elif write_dict['t'] != 1: 34 | d_count = 1 35 | for k, v in iter(write_dict.items()): 36 | if d_count < len(write_dict): 37 | f.write(str(v) + ',') 38 | else: 39 | f.write(str(v) + '\n') 40 | d_count += 1 41 | f.close() 42 | 43 | 44 | def data_setup(): 45 | args = gv.args 46 | if 'MNIST' in args.dataset: 47 | X_train, Y_train, X_test, Y_test = data_mnist() 48 | Y_test_uncat = np.argmax(Y_test, axis=1) 49 | print('Loaded f/MNIST data') 50 | elif args.dataset == 'CIFAR-10': 51 | (X_train, Y_train_uncat), (X_test, Y_test_uncat) = cifar10.load_data() 52 | 53 | # Convert class vectors to binary class matrices. 54 | Y_train = np_utils.to_categorical(Y_train_uncat, gv.NUM_CLASSES) 55 | Y_test = np_utils.to_categorical(Y_test_uncat, gv.NUM_CLASSES) 56 | 57 | X_train = X_train.astype('float32') 58 | X_test = X_test.astype('float32') 59 | 60 | # subtract mean and normalize 61 | mean_image = np.mean(X_train, axis=0) 62 | X_train -= mean_image 63 | X_test -= mean_image 64 | X_train /= 128. 65 | X_test /= 128. 66 | print('Loaded CIFAR-10 data') 67 | elif args.dataset == 'census': 68 | X_train, Y_train, X_test, Y_test = data_census() 69 | Y_test_uncat = np.argmax(Y_test, axis=1) 70 | # print Y_test 71 | # print Y_test_uncat 72 | print('Loaded Census data') 73 | 74 | return X_train, Y_train, X_test, Y_test, Y_test_uncat 75 | 76 | 77 | def mal_data_create(X_test, Y_test, Y_test_uncat): 78 | args = gv.args 79 | 80 | if args.mal_obj == 'all': 81 | mal_data_X = X_test 82 | mal_data_Y = Y_test 83 | true_labels = Y_test 84 | elif args.mal_obj == 'single': 85 | r = np.random.choice(len(X_test)) 86 | print(r) 87 | mal_data_X = X_test[r:r + 1] 88 | allowed_targets = list(range(gv.NUM_CLASSES)) 89 | print("Initial class: %s" % Y_test_uncat[r]) 90 | true_labels = Y_test_uncat[r:r+1] 91 | allowed_targets.remove(Y_test_uncat[r]) 92 | mal_data_Y = np.random.choice(allowed_targets) 93 | mal_data_Y = mal_data_Y.reshape(1,) 94 | print("Target class: %s" % mal_data_Y[0]) 95 | elif 'multiple' in args.mal_obj: 96 | target_indices = np.random.choice(len(X_test), args.mal_num) 97 | mal_data_X = X_test[target_indices] 98 | print("Initial classes: %s" % Y_test_uncat[target_indices]) 99 | true_labels = Y_test_uncat[target_indices] 100 | mal_data_Y = [] 101 | for i in range(args.mal_num): 102 | allowed_targets = list(range(gv.NUM_CLASSES)) 103 | allowed_targets.remove(Y_test_uncat[target_indices[i]]) 104 | mal_data_Y.append(np.random.choice(allowed_targets)) 105 | mal_data_Y = np.array(mal_data_Y) 106 | return mal_data_X, mal_data_Y, true_labels 107 | 108 | def mal_data_setup(X_test, Y_test, Y_test_uncat, gen_flag=True): 109 | args = gv.args 110 | 111 | data_path = 'data/mal_X_%s_%s.npy' % (args.dataset, args.mal_obj) 112 | 113 | print(data_path) 114 | 115 | if not os.path.exists('data/mal_X_%s_%s.npy' % (args.dataset, args.mal_obj)): 116 | if gen_flag: 117 | mal_data_X, mal_data_Y, true_labels = mal_data_create(X_test, Y_test, Y_test_uncat) 118 | else: 119 | raise ValueError('Tried to generate mal data when disallowed') 120 | else: 121 | mal_data_X = np.load('data/mal_X_%s_%s.npy' % (args.dataset, args.mal_obj)) 122 | mal_data_Y = np.load('data/mal_Y_%s_%s.npy' % (args.dataset, args.mal_obj)) 123 | true_labels = np.load('data/true_labels_%s_%s.npy' % (args.dataset, args.mal_obj)) 124 | print("Initial classes: %s" % true_labels) 125 | print("Target classes: %s" % mal_data_Y) 126 | 127 | return mal_data_X, mal_data_Y, true_labels 128 | 129 | -------------------------------------------------------------------------------- /utils/mnist.py: -------------------------------------------------------------------------------- 1 | ######################### 2 | # Purpose: Model definitions and other utlities for MNIST and Fashion MNIST 3 | ######################## 4 | 5 | from keras.datasets import mnist 6 | from keras.models import Sequential, model_from_json 7 | from keras.layers import Dense, Dropout, Activation, Flatten, Input 8 | from keras.layers import Conv2D, MaxPooling2D, BatchNormalization 9 | from keras.preprocessing.image import ImageDataGenerator 10 | from keras.utils import np_utils 11 | 12 | from .fmnist import load_fmnist 13 | import global_vars as gv 14 | 15 | import argparse 16 | import numpy as np 17 | # np.random.seed(777) 18 | 19 | def data_mnist(one_hot=True): 20 | """ 21 | Preprocess MNIST dataset 22 | """ 23 | # the data, shuffled and split between train and test sets 24 | if gv.args.dataset == 'MNIST': 25 | (X_train, y_train), (X_test, y_test) = mnist.load_data() 26 | 27 | elif gv.args.dataset == 'fMNIST': 28 | X_train, y_train = load_fmnist('/home/data/', kind='train') 29 | X_test, y_test = load_fmnist('/home/data/', kind='t10k') 30 | 31 | 32 | X_train = X_train.reshape(X_train.shape[0], 33 | gv.IMAGE_ROWS, 34 | gv.IMAGE_COLS, 35 | gv.NUM_CHANNELS) 36 | 37 | X_test = X_test.reshape(X_test.shape[0], 38 | gv.IMAGE_ROWS, 39 | gv.IMAGE_COLS, 40 | gv.NUM_CHANNELS) 41 | 42 | X_train = X_train.astype('float32') 43 | X_test = X_test.astype('float32') 44 | X_train /= 255 45 | X_test /= 255 46 | print('X_train shape:', X_train.shape) 47 | print(X_train.shape[0], 'train samples') 48 | print(X_test.shape[0], 'test samples') 49 | 50 | if one_hot: 51 | # convert class vectors to binary class matrices 52 | y_train = np_utils.to_categorical(y_train, gv.NUM_CLASSES).astype(np.float32) 53 | y_test = np_utils.to_categorical(y_test, gv.NUM_CLASSES).astype(np.float32) 54 | 55 | return X_train, y_train, X_test, y_test 56 | 57 | 58 | def modelA(): 59 | model = Sequential() 60 | model.add(Conv2D(64, (5, 5), padding='valid', input_shape=(gv.IMAGE_ROWS, 61 | gv.IMAGE_COLS, 62 | gv.NUM_CHANNELS))) 63 | model.add(Activation('relu')) 64 | 65 | model.add(Conv2D(64, (5, 5))) 66 | model.add(Activation('relu')) 67 | 68 | model.add(Dropout(0.25)) 69 | 70 | model.add(Flatten()) 71 | model.add(Dense(128)) 72 | model.add(Activation('relu')) 73 | 74 | model.add(Dropout(0.5)) 75 | model.add(Dense(gv.NUM_CLASSES)) 76 | return model 77 | 78 | 79 | def modelB(): 80 | model = Sequential() 81 | model.add(Dropout(0.2, input_shape=(gv.IMAGE_ROWS, 82 | gv.IMAGE_COLS, 83 | gv.NUM_CHANNELS))) 84 | model.add(Convolution2D(64, 8, 8, 85 | subsample=(2, 2), 86 | border_mode='same')) 87 | model.add(Activation('relu')) 88 | 89 | model.add(Convolution2D(128, 6, 6, 90 | subsample=(2, 2), 91 | border_mode='valid')) 92 | model.add(Activation('relu')) 93 | 94 | model.add(Convolution2D(128, 5, 5, 95 | subsample=(1, 1))) 96 | model.add(Activation('relu')) 97 | 98 | model.add(Dropout(0.5)) 99 | 100 | model.add(Flatten()) 101 | model.add(Dense(gv.NUM_CLASSES)) 102 | return model 103 | 104 | 105 | def modelC(): 106 | model = Sequential() 107 | model.add(Convolution2D(128, 3, 3, 108 | border_mode='valid', 109 | input_shape=(gv.IMAGE_ROWS, 110 | gv.IMAGE_COLS, 111 | gv.NUM_CHANNELS))) 112 | model.add(Activation('relu')) 113 | 114 | model.add(Convolution2D(64, 3, 3)) 115 | model.add(Activation('relu')) 116 | 117 | model.add(Dropout(0.25)) 118 | 119 | model.add(Flatten()) 120 | model.add(Dense(128)) 121 | model.add(Activation('relu')) 122 | 123 | model.add(Dropout(0.5)) 124 | model.add(Dense(gv.NUM_CLASSES)) 125 | return model 126 | 127 | 128 | def modelD(): 129 | model = Sequential() 130 | 131 | model.add(Flatten(input_shape=(gv.IMAGE_ROWS, 132 | gv.IMAGE_COLS, 133 | gv.NUM_CHANNELS))) 134 | 135 | model.add(Dense(300, init='he_normal', activation='relu')) 136 | model.add(Dropout(0.5)) 137 | model.add(Dense(300, init='he_normal', activation='relu')) 138 | model.add(Dropout(0.5)) 139 | model.add(Dense(300, init='he_normal', activation='relu')) 140 | model.add(Dropout(0.5)) 141 | model.add(Dense(300, init='he_normal', activation='relu')) 142 | model.add(Dropout(0.5)) 143 | 144 | model.add(Dense(gv.NUM_CLASSES)) 145 | return model 146 | 147 | def modelE(): 148 | model = Sequential() 149 | 150 | model.add(Flatten(input_shape=(gv.IMAGE_ROWS, 151 | gv.IMAGE_COLS, 152 | gv.NUM_CHANNELS))) 153 | 154 | model.add(Dense(100, activation='relu')) 155 | model.add(Dense(100, activation='relu')) 156 | 157 | model.add(Dense(gv.NUM_CLASSES)) 158 | 159 | return model 160 | 161 | def modelF(): 162 | model = Sequential() 163 | 164 | model.add(Conv2D(32, (5, 5), 165 | padding='valid', 166 | input_shape=(gv.IMAGE_ROWS, 167 | gv.IMAGE_COLS, 168 | gv.NUM_CHANNELS))) 169 | model.add(Activation('relu')) 170 | 171 | model.add(MaxPooling2D(pool_size=(2, 2))) 172 | 173 | model.add(Conv2D(64, (5, 5))) 174 | model.add(Activation('relu')) 175 | 176 | model.add(MaxPooling2D(pool_size=(2, 2))) 177 | 178 | model.add(Flatten()) 179 | model.add(Dense(512)) 180 | model.add(Activation('relu')) 181 | 182 | model.add(Dense(gv.NUM_CLASSES)) 183 | 184 | return model 185 | 186 | def modelG(): 187 | model = Sequential() 188 | 189 | model.add(Conv2D(filters = 32, kernel_size = (5,5),padding = 'Same', 190 | activation ='relu', input_shape = (28,28,1))) 191 | model.add(Conv2D(filters = 32, kernel_size = (5,5),padding = 'Same', 192 | activation ='relu')) 193 | model.add(MaxPooling2D(pool_size=(2,2))) 194 | model.add(Dropout(0.25)) 195 | 196 | 197 | model.add(Conv2D(filters = 64, kernel_size = (3,3),padding = 'Same', 198 | activation ='relu')) 199 | model.add(Conv2D(filters = 64, kernel_size = (3,3),padding = 'Same', 200 | activation ='relu')) 201 | model.add(MaxPooling2D(pool_size=(2,2), strides=(2,2))) 202 | model.add(Dropout(0.25)) 203 | 204 | 205 | model.add(Flatten()) 206 | model.add(Dense(512, activation = "relu")) 207 | model.add(BatchNormalization()) 208 | model.add(Dropout(0.5)) 209 | model.add(Dense(10)) 210 | 211 | return model 212 | 213 | def model_LR(): 214 | model = Sequential() 215 | 216 | model.add(Flatten(input_shape=(gv.IMAGE_ROWS, 217 | gv.IMAGE_COLS, 218 | gv.NUM_CHANNELS))) 219 | 220 | model.add(Dense(gv.NUM_CLASSES)) 221 | 222 | return model 223 | 224 | 225 | def model_mnist(type): 226 | """ 227 | Defines MNIST model using Keras sequential model 228 | """ 229 | 230 | models = [modelA, modelB, modelC, modelD, modelE, modelF, modelG, model_LR] 231 | 232 | return models[type]() 233 | 234 | 235 | def data_gen_mnist(X_train): 236 | datagen = ImageDataGenerator() 237 | 238 | datagen.fit(X_train) 239 | return datagen 240 | 241 | 242 | def load_model(model_path, type=0): 243 | 244 | try: 245 | with open(model_path+'.json', 'r') as f: 246 | json_string = f.read() 247 | model = model_from_json(json_string) 248 | print('Loaded using json') 249 | except IOError: 250 | model = model_mnist(type=type) 251 | 252 | model.load_weights(model_path) 253 | return model 254 | -------------------------------------------------------------------------------- /weights_analysis.py: -------------------------------------------------------------------------------- 1 | ######################### 2 | # Purpose: Generates weight distribution plots 3 | ######################## 4 | 5 | import numpy as np 6 | import os 7 | import argparse 8 | import matplotlib as mpl 9 | mpl.use('Agg') 10 | import matplotlib.pyplot as plt 11 | plt.ioff() 12 | import collections 13 | # from mpl_toolkits.mplot3d import Axes3D 14 | # from scipy.stats import wasserstein_distance 15 | 16 | import global_vars as gv 17 | 18 | top_k = 10 19 | 20 | 21 | def two_d_convert(indices, values, cutoffs, shape_list): 22 | two_d_indices = collections.OrderedDict() 23 | for i, item in enumerate(indices): 24 | layer_nums = np.where(item > cutoffs)[0] 25 | if list(layer_nums): 26 | layer_num = layer_nums[-1] 27 | curr_layer_index = item - cutoffs[layer_num] 28 | layer_num = layer_nums[-1] + 1 29 | else: 30 | layer_num = 0 31 | curr_layer_index = item 32 | curr_shape = shape_list[layer_num] 33 | row_index = curr_layer_index / curr_shape[1] 34 | column_index = curr_layer_index % curr_shape[1] 35 | two_d_indices[str(top_k - i)] = [item, (layer_num, row_index, 36 | column_index), values[i]] 37 | return two_d_indices 38 | 39 | 40 | def one_d_convert(indices, cutoffs, shape_list): 41 | one_d_indices = {} 42 | for item in indices: 43 | layer_num = np.where(item > cutoffs)[0] 44 | curr_layer_index = item - cutoffs[layer_num] 45 | one_d_indices[str(layer_num)] = curr_layer_index 46 | return one_d_indices 47 | 48 | 49 | def model_shape_size(delta_curr): 50 | shape_w = [] 51 | shape_b = [] 52 | size_w = [] 53 | size_b = [] 54 | for l in range(len(delta_curr)): 55 | layer_shape = delta_curr[l].shape 56 | size = 1 57 | for item in layer_shape: 58 | size *= item 59 | if l % 2 == 0: 60 | size_w.append(size) 61 | shape_w.append(layer_shape) 62 | elif (l + 1) % 2 == 0: 63 | size_b.append(size) 64 | shape_b.append(layer_shape) 65 | return shape_w, shape_b, size_w, size_b 66 | 67 | 68 | def collate_weights(delta_curr): 69 | for l in range(len(delta_curr)): 70 | flat_layer = delta_curr[l].flatten() 71 | if l == 0: 72 | delta_curr_w = flat_layer 73 | elif l == 1: 74 | delta_curr_b = flat_layer 75 | elif l % 2 == 0: 76 | delta_curr_w = np.concatenate( 77 | (delta_curr_w, flat_layer)) 78 | elif (l + 1) % 2 == 0: 79 | delta_curr_b = np.concatenate( 80 | (delta_curr_b, flat_layer)) 81 | return delta_curr_w, delta_curr_b 82 | 83 | 84 | def top_k_finder(delta_curr, t, mode=None, step=None): 85 | delta_curr_w, delta_curr_b = collate_weights(delta_curr) 86 | 87 | delta_curr_w_nz = delta_curr_w[np.where(np.abs(delta_curr_w) > 1e-7)] 88 | 89 | manual_bins = np.linspace(-0.2,0.2,500) 90 | # print manual_bins 91 | 92 | hist, bins = np.histogram(delta_curr_w_nz, bins=manual_bins) 93 | # hist, bins = np.histogram(delta_curr_w_nz, bins=500) 94 | 95 | x = (bins[:-1] + bins[1:])/2 96 | 97 | width = 2*abs(x[0]-x[1]) 98 | 99 | if mode == 'Malicious': 100 | # ax_mal.bar(x, hist, zs=t, zdir='y', width=width) 101 | mal_bars = ax_ben.bar(x, hist, width=width, color='red',alpha=0.5) 102 | mal_max.append(np.amax(delta_curr_w)) 103 | mal_min.append(np.amin(delta_curr_w)) 104 | elif mode == 'Benign': 105 | ben_bars = ax_ben.bar(x, hist, width=width, alpha=0.3) 106 | ben_max.append(np.amax(delta_curr_w)) 107 | ben_min.append(np.amin(delta_curr_w)) 108 | 109 | min_signed_weight = np.amin(delta_curr_w) 110 | max_signed_weight = np.amax(delta_curr_w) 111 | 112 | print('Range of weights is from %s to %s' % 113 | (min_signed_weight, max_signed_weight)) 114 | abs_weights = np.abs(delta_curr_w) 115 | 116 | min_abs_weight = np.amin(abs_weights) 117 | max_abs_weight = np.amax(abs_weights) 118 | 119 | print('Range of absolute weights is from %s to %s' % 120 | (min_abs_weight, max_abs_weight)) 121 | print('No. of large weights is %s' % 122 | (len(np.where(abs_weights > 1e-6)[0]))) 123 | 124 | ind_weights = np.argpartition(abs_weights, -top_k)[-top_k:] 125 | top_k_weights = abs_weights[ind_weights] 126 | 127 | ind_weights_sorted = ind_weights[np.argsort(top_k_weights)] 128 | top_k_weights_sorted = top_k_weights[np.argsort(top_k_weights)] 129 | 130 | ind_proper = two_d_convert( 131 | ind_weights_sorted, top_k_weights_sorted, cutoffs_w, shape_w) 132 | # print ind_proper 133 | 134 | if mode == 'Malicious': 135 | return hist, mal_bars 136 | elif mode == 'Benign': 137 | return hist, ben_bars 138 | 139 | 140 | gv.init() 141 | args = gv.args 142 | print(gv.figures_dir_name) 143 | global_weights_0 = np.load( 144 | gv.dir_name + 'global_weights_t%s.npy' % 0) 145 | 146 | shape_w, shape_b, size_w, size_b = model_shape_size(global_weights_0) 147 | 148 | cutoffs_w = np.cumsum(np.asarray(size_w)) 149 | cutoffs_b = np.cumsum(np.asarray(size_b)) 150 | 151 | mal_max = [] 152 | mal_min = [] 153 | ben_max = [] 154 | ben_min = [] 155 | 156 | 157 | 158 | fig = plt.figure() 159 | ax_ben = fig.add_subplot(111) 160 | 161 | 162 | ax_ben.set_xlabel('Weight values') 163 | 164 | 165 | ax_ben.grid(False) 166 | 167 | final_t = 0 168 | for t in range(4,5): 169 | print('Time Step %s' % t) 170 | if not args.mal: 171 | global_weights_curr = np.load( 172 | gv.dir_name + 'global_weights_t%s.npy' % t) 173 | global_weights_next = np.load( 174 | gv.dir_name + 'global_weights_t%s.npy' % (t + 1)) 175 | global_delta = global_weights_next - global_weights_curr 176 | 177 | top_k_finder(global_delta, t) 178 | else: 179 | mode = 'Benign' 180 | print (mode) 181 | ben_flag = 0 182 | 183 | if os.path.exists(gv.dir_name + 'ben_delta_sample%s.npy' % t): 184 | ben_delta_curr = np.load(gv.dir_name + 'ben_delta_sample%s.npy' % t) 185 | weights_curr, bias_curr = collate_weights(ben_delta_curr) 186 | ben_delta_hist_1d, ben_bars = top_k_finder(ben_delta_curr, t, mode) 187 | ben_flag = 1 188 | final_t = t 189 | 190 | if os.path.exists(gv.dir_name + 'mal_delta_t%s.npy' % t): 191 | mode = 'Malicious' 192 | print (mode) 193 | mal_delta = np.load(gv.dir_name + 'mal_delta_t%s.npy' % t) 194 | print('Directory found for iteration %s' % t) 195 | mal_weights_curr, mal_bias_curr = collate_weights(mal_delta) 196 | mal_delta_hist_1d, mal_bars = top_k_finder(mal_delta, t, mode) 197 | mal_flag = 1 198 | 199 | ax_ben.legend((ben_bars[0],mal_bars[0]),('Benign','Malicious')) 200 | 201 | 202 | plt.savefig(gv.figures_dir_name + 'hist_delta_2d_%s_%s.pdf' % 203 | (args.mal_obj, args.mal_strat),format='pdf') 204 | plt.savefig(gv.figures_dir_name + 'hist_delta_2d_%s_%s.png' % 205 | (args.mal_obj, args.mal_strat),format='png') 206 | 207 | plt.clf() 208 | --------------------------------------------------------------------------------