ml-trust-model

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

commit 5bf8b03f0031b6371c5cee5bacbfc104bc83fbe9
parent 6f4dbf0ccd5f0b429c1a059c2616e12d560200cb
Author: Cody Lewis <codymlewis@protonmail.com>
Date:   Thu, 11 Apr 2019 14:29:15 +1000

Started on evolutionary algorithm for SVM

Diffstat:
M.gitignore | 3++-
MTest.py | 2+-
MTrustManager/SVM.py | 83+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
MTrustManager/__init__.py | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
MTrustModel.py | 43+++++++++++++++++++++++++++++++++++++------
Mrequirements.txt | 3+++
6 files changed, 182 insertions(+), 18 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -391,4 +391,5 @@ TSWLatexianTemp* tags tags.lock Session.vim -reports.csv +*.csv +*.pkl diff --git a/Test.py b/Test.py @@ -113,7 +113,7 @@ class TestTrustModel(unittest.TestCase): no_of_transactions = 5 trust_manager.bootstrap(no_of_transactions) - self.assertEqual(np.shape(trust_manager.get_reports()), (200, 200)) + self.assertEqual(np.shape(trust_manager.get_reports()), (50, 50)) if __name__ == '__main__': diff --git a/TrustManager/SVM.py b/TrustManager/SVM.py @@ -1,3 +1,4 @@ +import numpy as np from sklearn.svm import SVC ''' @@ -28,3 +29,85 @@ def find_accuracy(svm, data, labels): corrects += 1 return 100 * corrects / len(labels) + + +def evolve(train_inputs, train_labels, test_inputs, test_labels): + genome, acc = hill_climb( + train_inputs, train_labels, test_inputs, test_labels + ) + return f"C: {genome[0]}, gamma: {genome[1]}, accuracy: {acc}" + + +def normalise_genome(genome): + for index_gene in enumerate(genome): + while genome[index_gene[0]] <= 0: + genome[index_gene[0]] = \ + float(np.random.normal(10, 8, 1)) + + +def generate_genome(): + ''' + Generate a random starting genome. + ''' + return [float(g) for g in list(np.random.normal(50, 20, 2))] + + +def mutate_genome(genome): + ''' + Take a genome and mutate it, return the mutant. + ''' + step_size = 0.1 * np.random.normal(0, 5) + mutant_genome = genome.copy() + + if np.random.normal() < 0: + return generate_genome() # Introduce annealing + + for index_mutant_genome in enumerate(mutant_genome): + mutant_genome[index_mutant_genome[0]] += \ + float(step_size * np.random.normal(0, 5)) + + return mutant_genome + + +def crossover(genome_a, genome_b): + ''' + Possibly crossover genome_b into genome_a and return the result. + ''' + crossover_genome = [] + crossed_over = False + + for gene_pair in zip(genome_a, genome_b): + if not crossed_over and np.random.normal() < 0: + crossover_genome.append(gene_pair[1]) + else: + crossover_genome.append(gene_pair[0]) + + return crossover_genome + + +def hill_climb(train_inputs, train_labels, test_inputs, test_labels, acc_goal=99): + ''' + Evolutionary algorithm to find the optimal number of neurons for the ANN. + ''' + counter = 0 + n_epochs = 100_000 + genome = generate_genome() + svm_champ = create_and_fit_svm( + train_inputs, train_labels, genome[0], genome[1] + ) + acc_champ = find_accuracy(svm_champ, test_inputs, test_labels) + + while (acc_champ < acc_goal) and (counter < n_epochs): + mutant_genome = mutate_genome(genome) + mutant_genome = crossover(mutant_genome, genome) + print(f"Epoch: {counter}, Current mutant genome: {mutant_genome}, Current champion genome: {genome} at accuracy: {acc_champ}") + svm_mutant = create_and_fit_svm( + train_inputs, train_labels, mutant_genome[0], mutant_genome[1] + ) + acc_mutant = find_accuracy(svm_mutant, test_inputs, test_labels) + + if acc_mutant > acc_champ: + genome = mutant_genome + acc_champ = acc_mutant + counter += 1 + return genome, acc_champ diff --git a/TrustManager/__init__.py b/TrustManager/__init__.py @@ -1,24 +1,32 @@ +import csv + import numpy as np import Functions import Node import BadMouther +import TrustManager.SVM as SVM class TrustManager: ''' Create and control the network. ''' - def __init__(self, no_of_nodes=200, constrained_nodes=0.5, - poor_witnesses=0.2, malicious_nodes=0.1): + def __init__(self, no_of_nodes=50, constrained_nodes=0.5, + poor_witnesses=0.2, malicious_nodes=0.1, + train_filename="reports-train.csv", test_filename="reports-test_csv"): self.__network = [] + self.__train_filename = train_filename + self.__test_filename = test_filename + # A real trust model would not be aware of these lists + # these are for the training constrained_list = Functions.get_conditioned_ids( no_of_nodes, constrained_nodes ) - poor_witness_list = Functions.get_conditioned_ids( + self.poor_witness_list = Functions.get_conditioned_ids( no_of_nodes, poor_witnesses ) - malicious_list = Functions.get_conditioned_ids( + self.malicious_list = Functions.get_conditioned_ids( no_of_nodes, malicious_nodes ) @@ -29,8 +37,8 @@ class TrustManager: else: service = 100 capability = 100 - note_acc = np.random.rand() if i in poor_witness_list else 1.0 - if i in malicious_list: + note_acc = np.random.rand() if i in self.poor_witness_list else 1.0 + if i in self.malicious_list: self.__network.append( BadMouther.BadMouther(service, capability, note_acc) ) @@ -41,6 +49,10 @@ class TrustManager: [None for _ in range(no_of_nodes)] for _ in range(no_of_nodes) ] + def set_filenames(self, train_filename, test_filename): + self.__train_filename = train_filename + self.__test_filename = test_filename + def get_network(self): return self.__network @@ -59,7 +71,7 @@ class TrustManager: Functions.print_progress(i, epochs) print("Done.") - def __artificial_transactions(self, current_epoch): + def __artificial_transactions(self, current_epoch, report_filename=None): ''' Perform some transactions through the entire network with random targets. @@ -75,9 +87,10 @@ class TrustManager: capability_target, current_epoch ) - self.save_reports_csv() + if report_filename: + self.save_reports_csv(report_filename) - def save_reports_csv(self, filename="reports.csv"): + def save_reports_csv(self, filename): ''' Save a csv on the report data ''' @@ -85,6 +98,39 @@ class TrustManager: for reports_from_node_i in enumerate(self.__reports): for reports_on_node_j in enumerate(reports_from_node_i[1]): if reports_from_node_i[0] != reports_on_node_j[0]: + if reports_from_node_i[0] in self.malicious_list: + observer_class = 2 + elif reports_from_node_i[0] in self.poor_witness_list: + observer_class = 1 + else: + observer_class = 0 report_csv.write( - f"{reports_from_node_i[0]},{reports_on_node_j[0]},{reports_on_node_j[1].csv_output()}\n" + f"{reports_from_node_i[0]},{reports_on_node_j[0]},{reports_on_node_j[1].csv_output()},{observer_class}\n" ) + + def read_data(self, filename, delimiter=","): + train_data = [] + notes = [] + observer_class = [] + + with open(filename) as report_csv: + csv_reader = csv.reader(report_csv, delimiter=delimiter) + for row in csv_reader: + train_data.append(row[:4] + row[5:-1]) + notes.append(row[4]) + observer_class.append(row[-1]) + + return train_data, notes, observer_class + + def train_svm(self): + print("Reading data...") + train_data, notes, observer_class = self.read_data() + print("Training SVMs...") + note_svm = SVM.create_and_fit_svm(train_data, notes, 5, 0.1) + # witness_svm = SVM.create_and_fit_svm(train_data, observer_class, 5, 0.1) + + return note_svm # , witness_svm + + def evolve_svm(self): + data, notes, observer_class = self.read_data() + return SVM.evolve(data, notes, data, notes) diff --git a/TrustModel.py b/TrustModel.py @@ -3,7 +3,10 @@ import sys import argparse +import joblib + import TrustManager +import TrustManager.SVM ''' A trust model simulation which uses machine learning techniques to find trust. @@ -18,15 +21,43 @@ if __name__ == '__main__': PARSER.add_argument("--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("-f", "--file", dest="filename", - action="store", default="reports.csv", - help="Specify the file to read from or write to.") + 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.") + PARSER.add_argument("--fit-svm", dest="fit_svm", action="store_const", + const=True, default=False, + help="Train an SVM on previously generated data and test on a new network.") + PARSER.add_argument("--evolve-svm", dest="evolve_svm", action="store_const", + const=True, default=False, + help="Perform an evolutionary algorithm to find the optimal values for C and gamma") ARGS = PARSER.parse_args() if len(sys.argv) == 1: PARSER.print_help() if ARGS.is_creating: - TRUST_MANAGER = TrustManager.TrustManager() - TRUST_MANAGER.bootstrap(500) - TRUST_MANAGER.save_reports_csv(ARGS.filename) + # First blank out file + with open(ARGS.filename, "w") as FILE: + FILE.write("") + + # Then create trust manager and bootstrap + TRUST_MANAGER = TrustManager.TrustManager(filename=ARGS.filename) + TRUST_MANAGER.bootstrap(1) + joblib.dump(TRUST_MANAGER, "trust_manager.pkl") + + if ARGS.evolve_svm: + print("Evolving...") + TRUST_MANAGER = joblib.load("trust_manager.pkl") + TRUST_MANAGER.set_filename(ARGS.filename) + print(TRUST_MANAGER.evolve_svm()) + + if ARGS.fit_svm: + TRUST_MANAGER = TrustManager.TrustManager(filename=ARGS.filename) + print("Fitting SVM...") + SVM = TRUST_MANAGER.train_svm() + print("SVM fitted") + joblib.dump(SVM, "svm.pkl") + print("Done. SVM saved as svm.pkl") diff --git a/requirements.txt b/requirements.txt @@ -1 +1,4 @@ numpy +joblib +scikit-learn +tensorflow