utils.py 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540
  1. import os
  2. import pickle
  3. import math
  4. from PIL import Image
  5. import warnings
  6. import datetime
  7. import configparser
  8. import numpy as np
  9. #np.random.seed(20200501)
  10. warnings.filterwarnings("ignore")
  11. """Set seed and Init cuda"""
  12. os.environ["TF_CPP_MIN_LOG_LEVEL"] = '2' # 只显示 warning 和 Error
  13. os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID"
  14. os.environ["CUDA_VISIBLE_DEVICES"] = ""
  15. class ModelUtils:
  16. def __init__(self):
  17. pass
  18. @staticmethod
  19. def model_copy(model, mode=''):
  20. from mutation_utils import LayerUtils
  21. import keras
  22. suffix = '_copy_' + mode
  23. if model.__class__.__name__ == 'Sequential':
  24. new_layers = []
  25. for layer in model.layers:
  26. new_layer = LayerUtils.clone(layer)
  27. new_layer.name += suffix
  28. new_layers.append(new_layer)
  29. new_model = keras.Sequential(layers=new_layers, name=model.name + suffix)#序贯模型,单输入单输出
  30. else:
  31. new_model = ModelUtils.functional_model_operation(model, suffix=suffix)
  32. s = datetime.datetime.now()
  33. new_model.set_weights(model.get_weights())
  34. e1 = datetime.datetime.now()
  35. td1 = e1 - s
  36. h, m, s = ToolUtils.get_HH_mm_ss(td1)
  37. print("Set model weights! {} hour,{} min,{} sec".format(h, m, s))
  38. del model
  39. return new_model
  40. @staticmethod
  41. def functional_model_operation(model, operation=None, suffix=None):
  42. from mutation_utils import LayerUtils
  43. input_layers = {}
  44. output_tensors = {}
  45. model_output = None
  46. for layer in model.layers:
  47. for node in layer._outbound_nodes:
  48. layer_name = node.outbound_layer.name
  49. if layer_name not in input_layers.keys():
  50. input_layers[layer_name] = [layer.name]
  51. else:
  52. input_layers[layer_name].append(layer.name)
  53. output_tensors[model.layers[0].name] = model.input
  54. for layer in model.layers[1:]:
  55. layer_input_tensors = [output_tensors[l] for l in input_layers[layer.name]]
  56. if len(layer_input_tensors) == 1:
  57. layer_input_tensors = layer_input_tensors[0]
  58. if operation is not None and layer.name in operation.keys():
  59. x = layer_input_tensors
  60. cloned_layer = LayerUtils.clone(layer)
  61. if suffix is not None:
  62. cloned_layer.name += suffix
  63. x = operation[layer.name](x, cloned_layer)
  64. else:
  65. cloned_layer = LayerUtils.clone(layer)
  66. if suffix is not None:
  67. cloned_layer.name += suffix
  68. x = cloned_layer(layer_input_tensors)
  69. output_tensors[layer.name] = x
  70. model_output = x
  71. import keras
  72. return keras.Model(inputs=model.inputs, outputs=model_output)
  73. @staticmethod
  74. def save_initial_weights(model):
  75. weights = model.get_weights()
  76. np.save('initial_weights.npy', weights)
  77. @staticmethod
  78. def load_initial_weights(model):
  79. weights = np.load('initial_weights.npy')
  80. model.set_weights(weights)
  81. return model
  82. @staticmethod
  83. def save_layers_output(path, layers_output):
  84. dirname = os.path.dirname(path)
  85. if len(dirname)>0 and (not os.path.exists(dirname)):
  86. os.makedirs(dirname)
  87. with open(path,'wb') as f:
  88. pickle.dump(layers_output,f)
  89. @staticmethod
  90. def load_layers_output(path):
  91. if not os.path.exists(path):
  92. return None
  93. with open(path,'rb') as f:
  94. layers_output = pickle.load(f)
  95. return layers_output
  96. @staticmethod
  97. def layer_divation(model, model_nodes, layer_index, layers_output_1, layers_output_2, epsilon=1e-7):
  98. layer = model.layers[layer_index]
  99. # get all of its input layers
  100. input_layers_index = []
  101. for node in layer._inbound_nodes:
  102. if node not in model_nodes:
  103. continue
  104. for l in node.inbound_layers:
  105. from keras.engine.input_layer import InputLayer
  106. if isinstance(l, InputLayer):
  107. continue
  108. # find the index of l in model
  109. for i, model_layer in enumerate(model.layers):
  110. if l == model_layer:
  111. input_layers_index.append(i)
  112. break
  113. else:
  114. raise Exception('can not find the layer in model')
  115. # calculate the divation of current layer
  116. cur_output_1 = layers_output_1[layer_index]
  117. cur_output_2 = layers_output_2[layer_index]
  118. delta_cur = MetricsUtils.delta(cur_output_1, cur_output_2)[0] # the second value of delta is sum()
  119. if len(input_layers_index) == 0:
  120. delta_pre = 0
  121. else:
  122. delta_pre_list = []
  123. for i in input_layers_index:
  124. pre_output_1 = layers_output_1[i]
  125. pre_output_2 = layers_output_2[i]
  126. delta_pre_list.append(MetricsUtils.delta(pre_output_1, pre_output_2)[0])
  127. delta_pre = np.max(delta_pre_list, axis=0)
  128. return delta_cur, (delta_cur - delta_pre) / (delta_pre + epsilon), [model.layers[i].name for i in input_layers_index]
  129. @staticmethod
  130. def layers_divation(model, layers_output_1, layers_output_2):
  131. relevant_nodes = []
  132. for v in model._nodes_by_depth.values():
  133. relevant_nodes += v
  134. layers_divation = []
  135. for i in range(len(model.layers)):
  136. layers_divation.append(ModelUtils.layer_divation(model, relevant_nodes, i, layers_output_1, layers_output_2))
  137. return layers_divation
  138. @staticmethod
  139. def layers_output(model, input):
  140. from keras import backend as K
  141. # print(K.backend()+" in loadmodel")
  142. from keras.engine.input_layer import InputLayer
  143. get_layer_output = K.function([model.layers[0].input, K.learning_phase()],
  144. [l.output for l in
  145. (model.layers[1:]
  146. if isinstance(model.layers[0], InputLayer)
  147. else model.layers)])
  148. if isinstance(model.layers[0], InputLayer):
  149. layers_output = [input]
  150. layers_output.extend(get_layer_output([input, 0]))
  151. else:
  152. layers_output = get_layer_output([input, 0])
  153. return layers_output
  154. @staticmethod
  155. def layers_input(model, input):
  156. inputs = [[input]]
  157. from keras import backend as K
  158. from keras.engine.input_layer import InputLayer
  159. for i, layer in enumerate(model.layers):
  160. if i == 0:
  161. continue
  162. if i == 1 and isinstance(model.layers[0], InputLayer):
  163. continue
  164. get_layer_input = K.function([model.layers[0].input, K.learning_phase()],
  165. layer.input if isinstance(layer.input, list) else [layer.input])
  166. inputs.append(get_layer_input([input, 0]))
  167. return inputs
  168. @staticmethod
  169. def generate_permutation(size_of_permutation, extract_portion):
  170. assert extract_portion <= 1
  171. num_of_extraction = math.floor(size_of_permutation * extract_portion)
  172. permutation = np.random.permutation(size_of_permutation)
  173. permutation = permutation[:num_of_extraction]
  174. return permutation
  175. @staticmethod
  176. def shuffle(a):
  177. shuffled_a = np.empty(a.shape, dtype=a.dtype)
  178. length = len(a)
  179. permutation = np.random.permutation(length)
  180. index_permutation = np.arange(length)
  181. shuffled_a[permutation] = a[index_permutation]
  182. return shuffled_a
  183. @staticmethod
  184. def compile_model(model, optimer, loss, metric:list):
  185. model.compile(optimizer=optimer,
  186. loss=loss,
  187. metrics=metric)
  188. return model
  189. @staticmethod
  190. def custom_objects():
  191. from scripts.mutation.mutation_utils import ActivationUtils
  192. objects = {}
  193. objects['no_activation'] = ActivationUtils.no_activation
  194. objects['leakyrelu'] = ActivationUtils.leakyrelu
  195. return objects
  196. @staticmethod
  197. def weighted_layer_indices(model):
  198. indices = []
  199. for i, layer in enumerate(model.layers):
  200. weight_count = layer.count_params()
  201. if weight_count > 0:
  202. indices.append(i)
  203. return indices
  204. @staticmethod
  205. def is_valid_model(inputs_backends,backends_nums, threshold=0.95):
  206. invalid_status_num = 0
  207. inputs_values = list(inputs_backends.values())
  208. # results like (1500,1) is valid
  209. if inputs_values[0].shape[1] == 1:
  210. return True
  211. else:
  212. for inputs in inputs_backends.values():
  213. indice_map = {}
  214. for input in inputs:
  215. max_indice = np.argmax(input)
  216. if max_indice not in indice_map.keys():
  217. indice_map[max_indice] = 1
  218. else:
  219. indice_map[max_indice] += 1
  220. for indice in indice_map.keys():
  221. if indice_map[indice] > len(inputs) * threshold:
  222. invalid_status_num += 1
  223. return False if invalid_status_num == backends_nums else True
  224. class DataUtils:
  225. @staticmethod
  226. def image_resize(x, shape):
  227. x_return = []
  228. for x_test in x:
  229. tmp = np.copy(x_test)
  230. img = Image.fromarray(tmp.astype('uint8')).convert('RGB')
  231. img = img.resize(shape, Image.ANTIALIAS)
  232. x_return.append(np.array(img))
  233. return np.array(x_return)
  234. @staticmethod
  235. def get_data_by_exp(exp):
  236. import keras
  237. import keras.backend as K
  238. K.set_image_data_format("channels_last")
  239. grandparent_directory = os.path.dirname(os.path.dirname(os.getcwd()))
  240. lemon_cfg = configparser.ConfigParser()
  241. lemon_cfg.read("./config/experiments.conf")
  242. dataset_dir = lemon_cfg['parameters']['dataset_dir']
  243. x_test = y_test = []
  244. if 'fashion-mnist' in exp:
  245. _, (x_test, y_test) = keras.datasets.fashion_mnist.load_data()
  246. x_test = DataUtils.get_fashion_mnist_data(x_test)
  247. y_test = keras.utils.to_categorical(y_test, num_classes=10)
  248. elif 'fashion2' in exp:
  249. basedir = os.path.abspath(os.getcwd())
  250. labels_path = grandparent_directory + '/run/data/t10k-labels-idx1-ubyte.gz'
  251. images_path = grandparent_directory + '/run/data/t10k-images-idx3-ubyte.gz'
  252. import gzip
  253. with gzip.open(labels_path, 'rb') as lbpath:
  254. labels = np.frombuffer(lbpath.read(), dtype=np.uint8,
  255. offset=8)
  256. with gzip.open(images_path, 'rb') as imgpath:
  257. images = np.frombuffer(imgpath.read(), dtype=np.uint8,
  258. offset=16).reshape(len(labels), 28, 28, 1)
  259. X_test = images.astype('float32') / 255.0
  260. Y_test = keras.utils.to_categorical(labels, 10)
  261. x_test,y_test=X_test, Y_test
  262. elif 'mnist' in exp:
  263. _, (x_test, y_test) = keras.datasets.mnist.load_data()
  264. x_test = DataUtils.get_mnist_data(x_test)
  265. y_test = keras.utils.to_categorical(y_test, num_classes=10)
  266. elif 'cifar100' in exp:
  267. from keras.datasets import cifar100
  268. subtract_pixel_mean = True
  269. # Load the CIFAR10 data.
  270. (X_train, Y_train), (X_test, Y_test) = cifar100.load_data()
  271. # Normalize data.
  272. X_train = X_train.astype('float32') / 255
  273. X_test = X_test.astype('float32') / 255
  274. # If subtract pixel mean is enabled
  275. if subtract_pixel_mean:
  276. X_train_mean = np.mean(X_train, axis=0)
  277. X_train -= X_train_mean
  278. X_test -= X_train_mean
  279. Y_test = keras.utils.to_categorical(Y_test, 100)
  280. x_test,y_test=X_test,Y_test
  281. elif 'cifar10' in exp:
  282. _, (x_test, y_test) = keras.datasets.cifar10.load_data()
  283. x_test = DataUtils.get_cifar10_data(x_test)
  284. y_test = keras.utils.to_categorical(y_test, num_classes=10)
  285. elif 'svhn' in exp:
  286. import run.SVNH_DatasetUtil
  287. (_, _), (X_test, Y_test) = run.SVNH_DatasetUtil.load_data()
  288. x_test,y_test=X_test, Y_test
  289. elif 'imagenet' in exp:
  290. input_precessor = DataUtils.imagenet_preprocess_dict()
  291. input_shapes_dict = DataUtils.imagenet_shape_dict()
  292. model_name = exp.split("-")[0]
  293. shape = input_shapes_dict[model_name]
  294. data_path = os.path.join(dataset_dir,"sampled_imagenet-1500.npz")
  295. data = np.load(data_path)
  296. x, y = data['x_test'], data['y_test']
  297. x_resize = DataUtils.image_resize(np.copy(x),shape)
  298. x_test = input_precessor[model_name](x_resize)
  299. y_test = keras.utils.to_categorical(y, num_classes=1000)
  300. elif 'sinewave' in exp:
  301. """
  302. see more details in
  303. https://github.com/StevenZxy/CIS400/tree/f69489c0624157ae86b5d8ddb1fa99c89a927256/code/LSTM-Neural-Network-for-Time-Series-Prediction-master
  304. """
  305. import pandas as pd
  306. dataframe = pd.read_csv(f"{dataset_dir}/sinewave.csv")
  307. test_size,seq_len = 1500, 50
  308. data_test = dataframe.get("sinewave").values[-(test_size + 50):]
  309. data_windows = []
  310. for i in range(test_size):
  311. data_windows.append(data_test[i:i + seq_len])
  312. data_windows = np.array(data_windows).astype(float).reshape((test_size,seq_len,1))
  313. data_windows = np.array(data_windows).astype(float)
  314. x_test = data_windows[:, :-1]
  315. y_test = data_windows[:, -1, [0]]
  316. elif 'price' in exp:
  317. """see more details in https://github.com/omerbsezer/LSTM_RNN_Tutorials_with_Demo/tree/master/StockPricesPredictionProject"""
  318. x_test, y_test = DataUtils.get_price_data(dataset_dir)
  319. # TODO: Add your own data preprocessing here
  320. # Note: The returned inputs should be preprocessed and labels should decoded as one-hot vector which could be directly feed in model.
  321. # Both of them should be returned in batch, e.g. shape like (1500,28,28,1) and (1500,10)
  322. # elif 'xxx' in exp:
  323. # x_test, y_test = get_your_data(dataset_dir)
  324. return x_test, y_test
  325. @staticmethod
  326. def save_img_from_array(path,array,index,exp):
  327. im = Image.fromarray(array)
  328. #path = path.rstrip("/")
  329. #save_path = "{}/{}_{}.png".format(path,exp,index)
  330. save_path = os.path.join(path,"{}_{}.png".format(exp, index))
  331. im.save(save_path)
  332. return save_path
  333. @staticmethod
  334. def shuffled_data(x, y, bs=None):
  335. ds = x.shape[0]
  336. all_idx = np.arange(ds)
  337. np.random.shuffle(all_idx)
  338. shuffle_idx = all_idx
  339. # shuffle_idx = all_idx[:bs]
  340. return x[shuffle_idx], y[shuffle_idx]
  341. @staticmethod
  342. def get_mnist_data(x_test):
  343. x_test = x_test.astype('float32') / 255.0
  344. x_test = x_test.reshape(x_test.shape[0], 28, 28, 1)
  345. return x_test
  346. @staticmethod
  347. def get_fashion_mnist_data(x_test):
  348. x_test = x_test.astype('float32') / 255.0
  349. w, h = 28, 28
  350. x_test = x_test.reshape(x_test.shape[0], w, h, 1)
  351. return x_test
  352. @staticmethod
  353. def get_cifar10_data(x_test):
  354. x_test = x_test.astype('float32') / 255.0
  355. w, h = 32, 32
  356. x_test = x_test.reshape(x_test.shape[0], w, h, 3)
  357. return x_test
  358. @staticmethod
  359. def get_price_data(data_dir):
  360. import pandas as pd
  361. from sklearn.preprocessing import MinMaxScaler
  362. def create_dataset(dataset, look_back=1):
  363. dataX, dataY = [], []
  364. for i in range(len(dataset) - look_back - 1):
  365. a = dataset[i:(i + look_back), 0]
  366. dataX.append(a)
  367. dataY.append(dataset[i + look_back, 0])
  368. return np.array(dataX), np.array(dataY)
  369. input_file = r"dataset/DIS.csv"
  370. df = pd.read_csv(input_file, header=None, index_col=None, delimiter=',')
  371. all_y = df[5].values
  372. dataset = all_y.reshape(-1, 1)
  373. scaler = MinMaxScaler(feature_range=(0, 1))
  374. dataset = scaler.fit_transform(dataset)
  375. train_size = int(len(dataset) * 0.5)
  376. test_size = len(dataset) - train_size
  377. train, test = dataset[0:train_size, :], dataset[train_size:len(dataset), :]
  378. # reshape into X=t and Y=t+1, timestep 240
  379. look_back = 240
  380. trainX, trainY = create_dataset(train, look_back)
  381. # reshape input to be [samples, time steps, features]
  382. trainX = np.reshape(trainX, (trainX.shape[0], 1, trainX.shape[1]))
  383. return trainX,trainY
  384. @staticmethod
  385. def imagenet_preprocess_dict():
  386. import keras
  387. keras_preprocess_dict = dict()
  388. keras_preprocess_dict['resnet50'] = keras.applications.resnet50.preprocess_input
  389. keras_preprocess_dict['densenet121'] = keras.applications.densenet.preprocess_input
  390. keras_preprocess_dict['mobilenet.1.00.224'] = keras.applications.mobilenet.preprocess_input
  391. keras_preprocess_dict['vgg16'] = keras.applications.vgg16.preprocess_input
  392. keras_preprocess_dict['vgg19'] = keras.applications.vgg19.preprocess_input
  393. keras_preprocess_dict['inception.v3'] = keras.applications.inception_v3.preprocess_input
  394. keras_preprocess_dict['inception.v2'] = keras.applications.inception_resnet_v2.preprocess_input
  395. keras_preprocess_dict['xception'] = keras.applications.xception.preprocess_input
  396. return keras_preprocess_dict
  397. @staticmethod
  398. def imagenet_shape_dict():
  399. image_shapes = dict()
  400. image_shapes['resnet50'] = (224,224)
  401. image_shapes['densenet121'] = (224,224)
  402. image_shapes['mobilenet.1.00.224'] = (224,224)
  403. image_shapes['vgg16'] = (224,224)
  404. image_shapes['vgg19'] = (224, 224)
  405. image_shapes['inception.v3'] = (299,299)
  406. image_shapes['inception.v2'] = (299, 299)
  407. image_shapes['xception'] = (299,299)
  408. return image_shapes
  409. class ToolUtils:
  410. @staticmethod
  411. def select_mutant(roulette,**kwargs):
  412. return roulette.choose_mutant()
  413. @staticmethod
  414. def select_mutator(logic, **kwargs):
  415. # import numpy as np
  416. # return np.random.permutation(mutate_ops)[0]
  417. last_used_mutator = kwargs['last_used_mutator']
  418. return logic.choose_mutator(last_used_mutator)
  419. @staticmethod
  420. def get_HH_mm_ss(td):
  421. days, seconds = td.days, td.seconds
  422. hours = days * 24 + seconds // 3600
  423. minutes = (seconds % 3600) // 60
  424. secs = seconds % 60
  425. return hours, minutes, secs
  426. class MetricsUtils:
  427. @staticmethod
  428. def delta(y1_pred, y2_pred,y_true=None):
  429. y1_pred = np.reshape(y1_pred, [np.shape(y1_pred)[0], -1])
  430. y2_pred = np.reshape(y2_pred, [np.shape(y2_pred)[0], -1])
  431. return np.mean(np.abs(y1_pred - y2_pred), axis=1), np.sum(np.abs(y1_pred - y2_pred), axis=1)
  432. @staticmethod
  433. def D_MAD_metrics(y1_pred, y2_pred,y_true, epsilon=1e-7):
  434. # sum could be remove and use mean in branch.
  435. theta_y1,sum_y1 = MetricsUtils.delta(y1_pred, y_true)
  436. theta_y2,sum_y2 = MetricsUtils.delta(y2_pred, y_true)
  437. return [
  438. 0
  439. if (sum_y1[i] == 0 and sum_y2[i] == 0)
  440. else
  441. np.abs(theta_y1[i] - theta_y2[i]) / (theta_y1[i] + theta_y2[i])
  442. for i in range(len(y_true))
  443. ]
  444. @staticmethod
  445. def get_all_metrics():
  446. metrics_dict = {}
  447. metrics_dict['D_MAD'] = MetricsUtils.D_MAD_metrics
  448. return metrics_dict
  449. @staticmethod
  450. def get_metrics_by_name(name):
  451. metrics = MetricsUtils.get_all_metrics()
  452. return metrics[name]
  453. @staticmethod
  454. def generate_result_by_metrics(metrics_list,lemon_results,save_dir,exp):
  455. for metrics_name in metrics_list:
  456. file_name = "{}/{}_{}_result.csv".format(save_dir,exp,metrics_name)
  457. metrics_result_dict = lemon_results[metrics_name]
  458. with open(file_name, "w") as writer:
  459. writer.write("Mutation-Backend-Pair,Inconsistency Score\n")
  460. for dm_k,dm_v in metrics_result_dict.items():
  461. writer.write("{},{}\n".format(dm_k,dm_v))
  462. if __name__ == '__main__':
  463. pass