{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import os.path\n", "import numpy as np\n", "from datetime import datetime\n", "import matplotlib.pyplot as plt\n", "\n", "import keras\n", "from keras.models import Model\n", "from keras.layers import Dense, Input, LSTM\n", "\n", "import sys\n", "sys.path.insert(0, \"src\")\n", "from Utils import load_processed_data, execute_layers, LABELS\n", "\n", "import random\n", "import IPython" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "max_review_length = 150\n", "NUM_LABELS = len(LABELS)\n", "data_train, labels_train, data_test, labels_test = load_processed_data(\"Processed Data 12.06.2019 00.05.csv\", \n", " review_length=max_review_length, \n", " pad_pos=\"start\",\n", " train_ratio=0.08)\n", "print(\"Train data: {}, Test data: {}\".format(len(labels_train), len(labels_test)))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class Host(object):\n", " def __init__(self, _param=None, _score=0):\n", " self.param = _param\n", " self.score = _score\n", "\n", " @property\n", " def param_str(self):\n", " return \",\".join(map(str, self.param))\n", " \n", " @param_str.setter\n", " def param_str(self, value):\n", " print(\"Permission denied!\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class Evolver(object):\n", " def __init__(self, mask=\"111111\", decay_rate=0.022, mutate_prob=0.8, log_file=None):\n", " self.mask = mask\n", " self.decay_rate = decay_rate # 0.022\n", " self.decay = self.getDecay(t=0)\n", " self.mutate_prob = mutate_prob\n", " self.hosts = []\n", " self.scores = []\n", " self.host_num = 0\n", " self.log_dir = \"Log\"\n", " self.log_file = log_file or \"Log {date}.txt\".format(date=datetime.now().strftime(\"%d.%m.%Y %H.%M\"))\n", " if not os.path.exists(self.log_dir):\n", " print(\"- Creating log directory {}\".format(self.log_dir))\n", " os.mkdir(self.log_dir)\n", " \n", " def generateModels(self, num_of_models=10, param=None, file_name=None):\n", " self.hosts.clear()\n", " if param:\n", " if type(param) in (list, tuple):\n", " print(\"Generating model from parameters!\")\n", " self.hosts += [Host(p, score=0) for p in param]\n", " else:\n", " print(\"x Invalid param type received; {}\".format(type(param)))\n", " elif file_name:\n", " print(\"Generating model from a file!\")\n", " self.loadParameters(file_name)\n", " else:\n", " print(\"Generating random models!\")\n", " for i in range(num_of_models):\n", " param = np.random.randint(low=1, high=256, size=4)\n", " #param = [random.randint(1+i*10, 10+(i+2)*10) for i in range(4, 0, -1)]\n", " self.hosts.append(Host(param, 0))\n", " self.host_num = len(self.hosts)\n", "\n", " def loadParameters(self, file_name):\n", " def str2list(string):\n", " string = string.rstrip(\"\\n\")\n", " param, score = string.split(\"=\")\n", " return (list(map(int, param.split(\",\"))), float(score))\n", "\n", " with open(file_name, \"r\") as file:\n", " self.hosts.clear()\n", " for param in file:\n", " _param, _score = str2list(param)\n", " self.hosts.append(Host(_param, _score))\n", " print(\"Parameters loaded from {}!\".format(file_name))\n", " \n", " def saveParameters(self, file_name, file_mode=\"w\"):\n", " list2str = lambda array: \",\".join(map(str, array))\n", " with open(os.path.join(self.log_dir, file_name), file_mode) as out_file:\n", " for host in self.hosts:\n", " out_file.write(\"{}={}\\n\".format(host.param_str, host.score))\n", " print(\"Parameters saved at {}!\".format(file_name))\n", " \n", " def createModel(self, param, input_shape, output_size, name=\"Unknown\"):\n", " input_x = Input(shape=input_shape, name=\"Acceleration_x\")\n", " input_y = Input(shape=input_shape, name=\"Acceleration_y\")\n", " input_z = Input(shape=input_shape, name=\"Acceleration_z\")\n", " shared_layers = (LSTM(param[0], activation=\"tanh\", name=\"Shared_LSTM\", dropout=0.5),\n", " Dense(param[1], activation=\"relu\", name=\"Shared_Dense_1\"),\n", " Dense(param[2], activation=\"relu\", name=\"Shared_Dense_2\"))\n", " shared_output = execute_layers(inputs=(input_x, input_y, input_z), layers=shared_layers)\n", " concat = keras.layers.concatenate(shared_output, name=\"Concatenate\")\n", " dense_1 = Dense(param[3], activation=\"relu\", name=\"Dense_1\")(concat)\n", " main_output = Dense(output_size, activation=\"softmax\", name=\"Classification_Layer\")(dense_1)\n", " return Model(inputs=[input_x, input_y, input_z], outputs=main_output)\n", "\n", " def testModel(self, model, epochs=8, batch_size=10, verbose=0):\n", " model.compile(loss='categorical_crossentropy', optimizer=\"adam\", metrics=['accuracy'])\n", " model.fit(x=[*data_train], y=labels_train, epochs=epochs, batch_size=batch_size, verbose=verbose)\n", " scores = model.evaluate(x=[*data_test], y=labels_test, batch_size=batch_size, verbose=verbose)\n", " #print(\"Accuracy: %.2f%%\" % (scores[1]*100))\n", " return scores[1]\n", "\n", " def runTest(self):\n", " progressPercent = lambda n: float(n)/self.host_num\n", " out = display(IPython.display.Pretty(\" \"), display_id=True)\n", " for i, host in enumerate(self.hosts):\n", " out.update(IPython.display.Pretty(\"@ Training progress: {:>4.1f}%\".format(progressPercent(i+1)*100)))\n", " if host.score == 0:\n", " model = self.createModel(host.param, (1, max_review_length), NUM_LABELS, name=\"Model {}\".format(i))\n", " fitness = self.testModel(model, epochs=5)\n", " keras.backend.clear_session()\n", " self.hosts[i].score = fitness\n", " self.sortFitness()\n", " self.saveParameters(self.log_file, \"a\")\n", " self.scores.append(self.averageScore(self.host_num))\n", " \n", " def evolve(self, t):\n", " evolve_num = int(self.host_num/2)\n", " new_hosts = []\n", " print(\"\\n- Evolving the hosts\")\n", " print(\" - Removing half of the weaker hosts\")\n", " del self.hosts[-evolve_num:]\n", " print(\" - Crossovering top 2 hosts\")\n", " crossover_param = self.crossover(self.hosts[0].param.copy(), self.hosts[1].param.copy(), 4)\n", " for param in crossover_param:\n", " new_hosts.append(Host(param, 0))\n", " print(\" - Mutating remaining top hosts\")\n", " mutation_num = evolve_num - len(crossover_param)\n", " self.decay = self.getDecay(t)\n", " for _ in range(mutation_num):\n", " param = random.choice(self.hosts).param.copy()\n", " mutated_param = self.mutate(param)\n", " new_hosts.append(Host(mutated_param, 0))\n", " print(\" - Adding hosts\")\n", " print(\" {}\".format(\", \".join(\"[{}]\".format(host.param_str) for host in new_hosts)))\n", " self.hosts += new_hosts\n", " new_hosts.clear()\n", "\n", " def sortFitness(self):\n", " self.hosts = sorted(self.hosts, key=lambda host: host.score, reverse=True)\n", "\n", " def _maskHost(self, host, mask):\n", " return [value for value, mask_bit in zip(host, mask) if mask_bit == \"1\"]\n", "\n", " def masking(*host_indexs):\n", " def decorator(func):\n", " @wraps(func)\n", " def wrapper(self, *args, **kwargs):\n", " mask = kwargs.get(\"mask\", self.mask)\n", " if args:\n", " args = list(args)\n", " for i in host_indexs:\n", " args[i] = self._maskHost(args[i], mask)\n", " result = func(self, *args, **kwargs)\n", " return result\n", " return wrapper\n", " return decorator\n", "\n", " def crossover(self, paramA, paramB, max_crossover=None, mask=None):\n", " assert len(paramA) == len(paramB), \"Host A and B are not of same length; {} and {}\".format(len(paramA), len(paramB))\n", " HOST_LEN = len(paramA)\n", " max_crossover = max_crossover or HOST_LEN\n", " assert 0 <= max_crossover <= HOST_LEN, \"Maximum cross number greater than crossable host length\"\n", "\n", " cross_index = {random.randint(0, HOST_LEN-1) for _ in range(max_crossover)}\n", " cross_index_A = list(cross_index.copy())\n", " cross_index_B = list(cross_index.copy())\n", " del cross_index\n", " random.shuffle(cross_index_B)\n", "\n", " print(\" {} & {}\".format(paramA, paramB), end=\" >> \")\n", " print(cross_index_A, cross_index_B, sep=\" & \", end=\" >> \")\n", " for i, j in zip(cross_index_A, cross_index_B):\n", " paramA[i], paramB[j] = paramB[j], paramA[i]\n", " print(\"{} & {}\".format(paramA, paramB))\n", " return paramA, paramB\n", "\n", " def getDecay(self, t=0):\n", " e = 2.718\n", " return e**(-self.decay_rate*t)\n", "\n", " def mutate(self, param, mask=None):\n", " PARAM_LEN = len(param)\n", " print(\" \", param, end=\" >> \")\n", " mutate_prob = self.mutate_prob*self.decay\n", " mutate_limit = max(1, round(20*self.decay))\n", " for i in range(PARAM_LEN):\n", " if random.random() <= mutate_prob:\n", " rand_value = random.randint(-mutate_limit, mutate_limit)\n", " param[i] = max(8, param[i] + rand_value)\n", " del rand_value\n", " print(param)\n", " return param\n", "\n", " def printHosts(self):\n", " print(\"\\n# All hosts\")\n", " for i in range(self.host_num):\n", " print(\" {:>2}) {}: {:.5f}\".format(i+1, self.hosts[i].param, self.hosts[i].score), end=\"\\t\\t\")\n", " if not (i+1)%2:\n", " print()\n", " print(\"- Average score: {:.5f}\".format(self.scores[-1]))\n", "\n", " def averageScore(self, num=3):\n", " assert 0 < num <= self.host_num, \"Given number out of range!\"\n", " mean_score = sum(self.hosts[i].score for i in range(num))/num\n", " return mean_score" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "evo = Evolver(decay_rate=0.001)\n", "evo.generateModels(20)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true }, "outputs": [], "source": [ "G = 250\n", "for g in range(G):\n", " print(\"# Generation\", g)\n", " evo.runTest()\n", " evo.printHosts()\n", " if (g < G-1):\n", " evo.evolve(g)\n", " print()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.plot(evo.scores)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "evo.saveParameters(\"Parameter {date}.txt\".format(date=datetime.now().strftime(\"%d.%m.%Y %H.%M\")))" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.7" } }, "nbformat": 4, "nbformat_minor": 2 }