ml-trust-model

git clone git://git.codymlewis.com/ml-trust-model.git
Log | Files | Refs | README

commit 62e52d5be7f142fb723d217a3a857a0202de277a
parent 4ba7b2e1ee3554eee8862f2138496ff5679be5a3
Author: Cody Lewis <codymlewis@protonmail.com>
Date:   Thu, 18 Apr 2019 13:08:12 +1000

Added data analysis capabilities

Diffstat:
MFunctions.py | 35+++++++++++++++++++++++++++++++++--
MTrustManager/ANN.py | 14++++++++++++--
MTrustManager/SVM.py | 10++++++++++
MTrustManager/__init__.py | 129++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
MTrustModel.py | 65+++++++++++++++++++++++++++++++++++++++++++++++++----------------
Ddata/ANN.h5 | 0
6 files changed, 206 insertions(+), 47 deletions(-)

diff --git a/Functions.py b/Functions.py @@ -1,7 +1,15 @@ +import timeit import numpy as np +''' +A few utility functions. -def print_progress(current_epoch, total_epochs, progress_len=31): +Author: Cody Lewis +Date: 2019-03-30 +''' + + +def print_progress(current_epoch, total_epochs, progress_len=31, prefix=""): ''' Print a progress bar about how far a process has went through it's epochs. ''' @@ -19,7 +27,7 @@ def print_progress(current_epoch, total_epochs, progress_len=31): ) progress_bar += "".join(["." for _ in range(unprogressed)]) progress_bar += "]" - print(f"\r{progress_bar} {progress}%", end="\r") + print(f"\r{prefix} {progress_bar} {progress}%", end="\r") def wrong_note(note): @@ -41,3 +49,26 @@ def get_conditioned_ids(no_of_nodes, condition_factor): conditioned_list.append(ids.pop(np.random.randint(len(ids)))) return conditioned_list + + +def calc_percentage(amount, total): + ''' + Calculate the percentage of amount from the total. + ''' + return 100 * amount / total + + +def wrap_func(func, *args, **kwargs): + ''' + Create a wrapper around a function, so it can be timed. + ''' + def wrapped(): + return func(*args, **kwargs) + return wrapped + + +def time(func): + ''' + Time a function. + ''' + return timeit.timeit(func, number=1000) / 1000 diff --git a/TrustManager/ANN.py b/TrustManager/ANN.py @@ -2,6 +2,8 @@ from tensorflow import keras import numpy as np import sklearn.preprocessing as skp +import Functions + ''' Use an artificial neural network for trust management. @@ -15,7 +17,7 @@ def create_and_train_ann(train_data, train_labels, test_data, test_labels): Create a neural network and train it on the given data. ''' model = keras.models.Sequential() - model.add(keras.layers.Dense(64, input_shape=(4,))) + model.add(keras.layers.Dense(128, input_shape=(3,))) model.add(keras.layers.Activation('relu')) model.add(keras.layers.Dense(128)) model.add(keras.layers.Activation('relu')) @@ -31,7 +33,7 @@ def create_and_train_ann(train_data, train_labels, test_data, test_labels): model.compile(loss="mean_squared_error", optimizer=adam, metrics=['accuracy']) data = np.array(train_data + test_data) labels = skp.label_binarize(np.array(train_labels + test_labels), ["-1", "0", "1"]) - model.fit(x=data, y=labels, epochs=300, validation_split=0.5) + model.fit(x=data, y=labels, epochs=4000, validation_split=0.5) return model @@ -54,3 +56,11 @@ def unbinarize(arr): ''' value = list(arr) return [-1, 0, 1][value.index(max(value))] + + +def time_predict(ann, node_id, service_target, capability_target): + ''' + Find the average time to predict. + ''' + predict = Functions.wrap_func(ann.predict, np.array([[node_id, service_target, capability_target]])) + return Functions.time(predict) diff --git a/TrustManager/SVM.py b/TrustManager/SVM.py @@ -1,6 +1,8 @@ import numpy as np from sklearn.svm import SVC +import Functions + ''' Use a Kernel Machine for the trust management. ''' @@ -43,6 +45,14 @@ def get_trusted_list(svm, service_target, capability_target, no_of_nodes): return trusted_list +def time_predict(svm, node_id, service_target, capability_target): + ''' + Find the average time to predict. + ''' + predict = Functions.wrap_func(svm.predict, [[node_id, service_target, capability_target]]) + return Functions.time(predict) + + def evolve(train_inputs, train_labels, test_inputs, test_labels): ''' Perform an evolutionary algorithm to optimize SVM parameters. diff --git a/TrustManager/__init__.py b/TrustManager/__init__.py @@ -15,6 +15,13 @@ import TrustManager.ANN as ANN CAP_MAX = 10 SERVICE_MAX = 6 +''' +Manage the network and establish trust between nodes within it. + +Author: Cody Lewis +Date: 2019-03-30 +''' + class TrustManager: ''' @@ -93,7 +100,7 @@ class TrustManager: for i in range(1, epochs + 1): self.__artificial_transactions(i, self.__train_filename if filewrite else None) self.__artificial_transactions(i, self.__test_filename if filewrite else None) - Functions.print_progress(i, epochs) + Functions.print_progress(i, epochs, prefix=f"{i}/{epochs}") print() print("Done.") @@ -144,20 +151,20 @@ class TrustManager: Perform an evolutionary algorithm to find the optimal values of C and gamma for the respective SVMs. ''' - train_data, train_notes = read_data(self.__train_filename, dict_mode=True) - test_data, test_notes = read_data(self.__test_filename, dict_mode=True) + train_data, train_notes = read_data(self.__train_filename) + test_data, test_notes = read_data(self.__test_filename) svms = dict() total_reporters = len(train_data.keys()) progress = 0 - Functions.print_progress(progress, total_reporters) - for reporter_id in train_data.keys(): + Functions.print_progress(progress, total_reporters, prefix=f"{progress}/{total_reporters}") + for reporter_id, _ in train_data.items(): svms[reporter_id] = SVM.evolve( train_data[reporter_id], train_notes[reporter_id], test_data[reporter_id], test_notes[reporter_id] ) progress += 1 - Functions.print_progress(progress, total_reporters) + Functions.print_progress(progress, total_reporters, prefix=f"{progress}/{total_reporters}") if not os.path.exists("data"): os.makedirs("data") @@ -170,9 +177,12 @@ class TrustManager: ''' train_data, train_notes = read_data(self.__train_filename) test_data, test_notes = read_data(self.__test_filename) - if not os.path.exists("data"): - os.makedirs("data") - ANN.create_and_train_ann(train_data, train_notes, test_data, test_notes).save("data/ANN.h5") + + if not os.path.exists("data/ANN"): + os.makedirs("data/ANN") + for reporter_id, _ in train_data.items(): + ANN.create_and_train_ann(train_data[reporter_id], train_notes[reporter_id], + test_data[reporter_id], test_notes[reporter_id]).save(f"data/ANN/{reporter_id}.h5") def load_svms(self): ''' @@ -184,9 +194,14 @@ class TrustManager: ''' Load the neural network classifier. ''' - self.__predictor = keras.models.load_model("data/ANN.h5") + self.__predictor = dict() + for node_id in range(len(self.__network)): + self.__predictor[node_id] = keras.models.load_model(f"data/ANN/{node_id}.h5") def get_all_recommendations(self, service_target, capability_target): + ''' + Get all of the predicted recommendations from each node, for each node. + ''' trusted_lists = dict() no_of_nodes = self.get_no_of_nodes() @@ -249,6 +264,74 @@ class TrustManager: ) return trusted_list + def simulate_transactions(self, epochs): + ''' + Simulate epochs number of random transactions and return the percentage of bad + transactions that have occured. + ''' + print("Getting all predictions...") + predictions = dict() + for service in range(SERVICE_MAX + 1): + predictions[service] = dict() + for capability in range(CAP_MAX + 1): + predictions[service][capability] = self.get_all_recommendations(service, capability) + + bad_transactions = 0 + okay_transactions = 0 + good_transactions = 0 + print("Simulating transactions...") + for _ in range(0, epochs): + service = int(np.floor(np.random.rand() * (SERVICE_MAX + 1))) + capability = int(np.floor(np.random.rand() * (CAP_MAX + 1))) + client_index = int(np.floor(np.random.rand() * len(self.__network))) + good_indices = [] + okay_indices = [] + + for index, prediction in predictions[service][capability][client_index].items(): + if index != client_index: + if prediction == 1: + good_indices.append(index) + elif prediction == 0: + okay_indices.append(index) + + if good_indices: + server_index = good_indices[int(np.floor(np.random.rand() * len(good_indices)))] + note = self.__network[client_index].take_note(self.__network[server_index], service, capability) + elif okay_indices: + server_index = okay_indices[int(np.floor(np.random.rand() * len(okay_indices)))] + note = self.__network[client_index].take_note(self.__network[server_index], service, capability) + else: + note = -1 + + if note == -1: + bad_transactions += 1 + elif note == 0: + okay_transactions += 1 + else: + good_transactions += 1 + + return Functions.calc_percentage(bad_transactions, epochs), \ + Functions.calc_percentage(okay_transactions, epochs), \ + Functions.calc_percentage(good_transactions, epochs) + + def time_predict(self): + ''' + Find the average time it take to make a prediction. + ''' + client = 1 + server = 2 + service = 1 + capability = 1 + if self.__use_svm: + if not self.__predictor: + self.load_svms() + avg_time = SVM.time_predict(self.__predictor[client], server, service, capability) + else: + if not self.__predictor: + self.load_ann() + avg_time = ANN.time_predict(self.__predictor[client], server, service, capability) + return avg_time + def load(train_filename, test_filename, use_svm): ''' @@ -263,30 +346,22 @@ def load(train_filename, test_filename, use_svm): return trust_manager -def read_data(filename, delimiter=",", dict_mode=False): +def read_data(filename, delimiter=","): ''' Read data from a csv of reports. ''' - if dict_mode: - train_data = dict() - notes = dict() - else: - train_data = [] - notes = [] + train_data = dict() + notes = dict() with open(filename) as report_csv: csv_reader = csv.reader(report_csv, delimiter=delimiter) for row in csv_reader: - if dict_mode: - reporter_id = int(row[0]) - if train_data.get(reporter_id): - train_data[reporter_id].append(row[1:-1]) - notes[reporter_id].append(row[-1]) - else: - train_data[reporter_id] = [row[1:-1]] - notes[reporter_id] = [row[-1]] + reporter_id = int(row[0]) + if train_data.get(reporter_id): + train_data[reporter_id].append(row[1:-1]) + notes[reporter_id].append(row[-1]) else: - train_data.append(row[:-1]) - notes.append(row[-1]) + train_data[reporter_id] = [row[1:-1]] + notes[reporter_id] = [row[-1]] return train_data, notes diff --git a/TrustModel.py b/TrustModel.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 +import os import sys import argparse @@ -19,53 +20,85 @@ if __name__ == '__main__': PARSER.add_argument("-c", "--create-data", dest="is_creating", action="store_const", const=True, default=False, help="Create data and place it in the csv file.") PARSER.add_argument("-e", "--epochs", dest="epochs", type=int, action="store", default=200, - help="The number of epochs to bootstrap for.") - PARSER.add_argument("-trf", "--train-file", dest="train_filename", action="store", default="reports-train.csv", - help="Specify the training data file to read from or write to.") - PARSER.add_argument("-tef", "--test-file", dest="test_filename", action="store", default="reports-test.csv", - help="Specify the test file to read from or write to.") + help="The number of epochs to bootstrap for. [default 200]") PARSER.add_argument("-s", "--svm", dest="use_svm", action="store_const", const=True, default=False, - help="Use a svm as the predicter") + help="Use a svm as the predictor") PARSER.add_argument("-a", "--ann", dest="use_ann", action="store_const", const=True, default=False, - help="Use an ann as the predicter") + help="Use an ann as the predictor [default predictor]") PARSER.add_argument("-t", "--train", dest="train", action="store_const", const=True, default=False, - help="Train the predicter on the previously generated data") - PARSER.add_argument("-tra", "--transact", dest="transact", action="store", nargs=3, type=int, + help="Train the predictor on the previously generated data") + PARSER.add_argument("-tr", "--transact", dest="transact", action="store", nargs=3, type=int, metavar=("ID", "SERVICE", "CAPABILITY"), help="Simulate a single transaction for node ID for SERVICE at CAPABILITY and print out the trusted list.") + PARSER.add_argument("-si", "--simulate", dest="simulate", action="store_const", const=True, default=False, + help="Simulate EPOCH number of transactions and find the number of bad, okay, and good transactions that occured.") + PARSER.add_argument("-tp", "--time-predict", dest="time_predict", action="store_const", const=True, default=False, + help="Find the average time it takes for the trust manager to make a prediction.") ARGS = PARSER.parse_args() + if not os.path.exists("data"): + os.makedirs("data") + TRAIN_FILENAME = "data/reports-train.csv" + TEST_FILENAME = "data/reports-test.csv" + if len(sys.argv) == 1: - PARSER.print_help() + # First blank out file + with open(TRAIN_FILENAME, "w") as FILE: + FILE.write("") + with open(TEST_FILENAME, "w") as FILE: + FILE.write("") + + # Then create trust manager and bootstrap + TRUST_MANAGER = TrustManager.TrustManager( + train_filename=TRAIN_FILENAME, test_filename=TEST_FILENAME, use_svm=ARGS.use_svm + ) + TRUST_MANAGER.bootstrap(ARGS.epochs) + TRUST_MANAGER.train() + TRUST_MANAGER.graph_recommendations(1, 1, 1) + BAD_PER, OK_PER, GOOD_PER = TRUST_MANAGER.simulate_transactions(ARGS.epochs) + print(f"Percentage of bad transactions: {BAD_PER}") + print(f"Percentage of okay transactions: {OK_PER}") + print(f"Percentage of good transactions: {GOOD_PER}") TRUST_MANAGER = None if ARGS.is_creating: # First blank out file - with open(ARGS.train_filename, "w") as FILE: + with open(TRAIN_FILENAME, "w") as FILE: FILE.write("") - with open(ARGS.test_filename, "w") as FILE: + with open(TEST_FILENAME, "w") as FILE: FILE.write("") # Then create trust manager and bootstrap TRUST_MANAGER = TrustManager.TrustManager( - train_filename=ARGS.train_filename, test_filename=ARGS.test_filename, use_svm=ARGS.use_svm + train_filename=TRAIN_FILENAME, test_filename=TEST_FILENAME, use_svm=ARGS.use_svm ) TRUST_MANAGER.bootstrap(ARGS.epochs) if ARGS.train: print("Training...") - TRUST_MANAGER = TrustManager.load(ARGS.train_filename, ARGS.test_filename, ARGS.use_svm) + TRUST_MANAGER = TrustManager.load(TRAIN_FILENAME, TEST_FILENAME, ARGS.use_svm) TRUST_MANAGER.train() - print("Done.") if ARGS.transact: - TRUST_MANAGER = TrustManager.load(ARGS.train_filename, ARGS.test_filename, ARGS.use_svm) + TRUST_MANAGER = TrustManager.load(TRAIN_FILENAME, TEST_FILENAME, ARGS.use_svm) ID, SERVICE, CAP = ARGS.transact[0], ARGS.transact[1], ARGS.transact[2] print(f"Trusted list for node {ID} requesting service {SERVICE} at capability {CAP}") print() print(TRUST_MANAGER.find_best_servers(ID, SERVICE, CAP)) TRUST_MANAGER.graph_recommendations(ID, SERVICE, CAP) + if ARGS.simulate: + TRUST_MANAGER = TrustManager.load(TRAIN_FILENAME, TEST_FILENAME, ARGS.use_svm) + BAD_PER, OK_PER, GOOD_PER = TRUST_MANAGER.simulate_transactions(ARGS.epochs) + print(f"Percentage of bad transactions: {BAD_PER}%") + print(f"Percentage of okay transactions: {OK_PER}%") + print(f"Percentage of good transactions: {GOOD_PER}%") + + if ARGS.time_predict: + TRUST_MANAGER = TrustManager.load(TRAIN_FILENAME, TEST_FILENAME, ARGS.use_svm) + print(f"Average time to predict is {TRUST_MANAGER.time_predict()} seconds") + if TRUST_MANAGER: TRUST_MANAGER.save() + print("Done.") diff --git a/data/ANN.h5 b/data/ANN.h5 Binary files differ.