diff --git a/mlp.ipynb b/mlp.ipynb index 0091941..7953a8b 100644 --- a/mlp.ipynb +++ b/mlp.ipynb @@ -4,182 +4,12 @@ "cell_type": "code", "execution_count": 1, "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "from pnmimage import PnmImage\n", - "\n", - "class LettersData(object):\n", - " def __init__(self):\n", - " self.expected_data_list = []\n", - " self.expected_letters = []\n", - " self.letter_to_int = {}\n", - " self.letters_classes = {}\n", - " self.extract_vocab = []\n", - " self.vocab = {}\n", - " self._images = []\n", - " self._expected_values = []\n", - " self.nb_vocab = 0\n", - " self.input_image_size = 0\n", - " self.selection_vocab = {}\n", - " self.selection_batch = []\n", - " self.letter_to_vector = {}\n", - " self.vector_to_letter = {}\n", - "\n", - " def _gen_ext_filenames_list(self):\n", - " for ln in range(100):\n", - " for car in range(100):\n", - " n = \"data/ext_ln{}_car{}.pgm\".format(ln, car)\n", - " if os.path.exists(n) and n.replace('data/', '') in self.filenames_list:\n", - " yield(n)\n", - "\n", - " def _get_expected_letters_list(self):\n", - " \"\"\"Get expected letters list from expected data file.\n", - "\n", - " :return: list of tuples with the letter and the corresponding filename\n", - "\n", - " \"\"\"\n", - " data_list = []\n", - " name = \"list_expected_data.txt\"\n", - " with open(name) as f:\n", - " lst = [(line.split(\" \")[0], line.split(\" \", 1)[1].replace('\\n', '')) for line in f.readlines() if line.strip() != '']\n", - " # list of tuples with (letter, filename)\n", - " data_list = [(e[1], e[0]) for e in lst]\n", - " return data_list\n", - "\n", - " def _extract_data(self):\n", - " \"\"\"Extract data.\n", - " Create list of expected letters/filenames, base letters with info, classes.\n", - " \"\"\"\n", - " self.expected_data_list = self._get_expected_letters_list()\n", - " \"\"\"list of tuples with letter and filename\"\"\"\n", - " self.extract_vocab = sorted(set([l[0] for l in self.expected_data_list]))\n", - " \"\"\"list of data vocab letters sorted\"\"\"\n", - " self.nb_vocab = len(self.extract_vocab)\n", - "\n", - " self.vocab = {}\n", - " letters_list = [l[0] for l in self.expected_data_list]\n", - " for i, c in enumerate(self.extract_vocab):\n", - " vec = [0] * self.nb_vocab\n", - " vec[i] = 1\n", - " self.vocab[c] = {\n", - " 'index': i,\n", - " 'count': letters_list.count(c),\n", - " 'vector': vec\n", - " }\n", - " self.letter_to_int = {c: i for i, c in enumerate(self.extract_vocab)}\n", - " \"\"\"dict of letters with index of each\"\"\"\n", - " self.letters_classes = {}\n", - " \"\"\"dict of letters with vector representation of each letter\"\"\"\n", - "\n", - " for letter, idx in self.letter_to_int.items():\n", - " cls = [0] * self.nb_vocab\n", - " cls[idx] = 1\n", - " self.letters_classes[letter] = cls\n", - "\n", - " def get_vocab_with_min_count(self, min_count):\n", - " \"\"\"Get the vocab. A dictionary of letters with count, index and vector.\n", - " The index is re-computed and also the vector to match the number of subelements\n", - " \"\"\"\n", - " subvocab = {}\n", - " i = 0\n", - " for c, info in self.vocab.items():\n", - " if info['count'] >= min_count:\n", - " subvocab[c] = {\n", - " 'count': info['count'],\n", - " 'index': i,\n", - " 'vector': None\n", - " }\n", - " i += 1\n", - " nb_vocab = len(subvocab)\n", - " self.letter_to_vector = {}\n", - " self.vector_to_letter = {}\n", - " for c in subvocab:\n", - " vec = [0] * nb_vocab\n", - " vec[subvocab[c]['index']] = 1\n", - " subvocab[c]['vector'] = vec\n", - " self.letter_to_vector[c] = vec\n", - " return subvocab\n", - "\n", - " def get_letter_of_vector(self, vector):\n", - " \"\"\"Get the letter corresponding to a given vector.\n", - "\n", - " :return: the found letter else None\n", - " \"\"\"\n", - " ret = None\n", - " for letter, vec in self.letter_to_vector.items():\n", - " if vec == vector:\n", - " ret = letter\n", - " break\n", - " return ret\n", - "\n", - " def get_batches(self, min_count=0, mini_batch_size=None):\n", - " \"\"\"Get the selection data based on min count of letters in the dataset\n", - "\n", - " :param min_count: minimal count of same letters to be added (default 0 for the whole dataset)\n", - " :param mini_batch_size: size of a mini batch, if None the whole dataset size (default None)\n", - " if whole size is not factor of the mini batch size then the last mini batch\n", - " has a size < mini batch size\n", - " :return: a list of mini batches (at least list of one)\n", - " \"\"\"\n", - " if mini_batch_size is None:\n", - " mini_batch_size = len(self.expected_data_list)\n", - " self.selection_vocab = self.get_vocab_with_min_count(min_count)\n", - " self.selection_batch = []\n", - " X = []\n", - " Y = []\n", - " bsize = 0\n", - " for letter, name in self.expected_data_list:\n", - " path = 'data/{}'.format(name)\n", - " if letter in self.selection_vocab:\n", - " img = PnmImage()\n", - " if img.load(path) == False:\n", - " print(\"ERROR: failed to open '{}'\".format(path))\n", - " image_size = img.get_size()\n", - " bsize += 1\n", - " X.append(img.get_data_bin())\n", - " Y.append(self.selection_vocab[letter]['vector'])\n", - " if bsize >= mini_batch_size:\n", - " self.selection_batch.append((X, Y))\n", - " X = []\n", - " Y = []\n", - " bsize = 0\n", - " if bsize > 0:\n", - " self.selection_batch.append((X, Y))\n", - " return self.selection_batch\n", - "\n", - " def process(self):\n", - " self._extract_data()\n", - "\n", - " def get_data_with_min_count(self, min_count):\n", - " vocab = self.get_vocab_with_min_count(min_count)\n", - " #todo\n", - " return images, expected_values\n", - " \n", - " def get_vocab(self):\n", - " \"\"\"Get the vocab. A dictionary of letters with count, index and vector\"\"\"\n", - " return self.vocab\n", - "\n", - " def get_classes(self):\n", - " return self.letters_classes\n", - "\n", - " def get_class_element_size(self):\n", - " return self.nb_vocab\n", - "\n", - " def get_input_image_size(self):\n", - " return self.input_image_size" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "{'a': {'vector': [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0], 'index': 8, 'count': 36}, 'e': {'vector': [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'index': 1, 'count': 117}, 'i': {'vector': [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], 'index': 7, 'count': 75}, 'o': {'vector': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], 'index': 10, 'count': 39}, 'c': {'vector': [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'index': 0, 'count': 30}, 'u': {'vector': [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0], 'index': 9, 'count': 55}, 'd': {'vector': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 'index': 11, 'count': 45}, 'l': {'vector': [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'index': 2, 'count': 64}, 'r': {'vector': [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0], 'index': 3, 'count': 42}, 'n': {'vector': [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0], 'index': 4, 'count': 75}, 't': {'vector': [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], 'index': 6, 'count': 64}, 's': {'vector': [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0], 'index': 5, 'count': 40}}\n", + "{'i': {'count': 75, 'index': 4, 'vector': [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]}, 'a': {'count': 36, 'index': 6, 'vector': [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0]}, 'd': {'count': 45, 'index': 5, 'vector': [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]}, 'l': {'count': 64, 'index': 0, 'vector': [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]}, 't': {'count': 64, 'index': 2, 'vector': [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]}, 'n': {'count': 75, 'index': 7, 'vector': [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0]}, 'c': {'count': 30, 'index': 8, 'vector': [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0]}, 'e': {'count': 117, 'index': 1, 'vector': [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]}, 's': {'count': 40, 'index': 9, 'vector': [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0]}, 'u': {'count': 55, 'index': 3, 'vector': [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0]}, 'r': {'count': 42, 'index': 10, 'vector': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0]}, 'o': {'count': 39, 'index': 11, 'vector': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]}}\n", "12\n", "1\n", "number of batches=1\n", @@ -190,7 +20,8 @@ } ], "source": [ - "data = LettersData()\n", + "from letters import LettersData\n", + "data = LettersData(\"data/\", \"list_expected_data.txt\")\n", "data.process()\n", "#x,y = data.get_data()\n", "#classes = data.get_classes()\n", @@ -219,7 +50,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 2, "metadata": {}, "outputs": [ { @@ -278,7 +109,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 3, "metadata": {}, "outputs": [ { @@ -331,28 +162,28 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "[0, 0, 1, 0, 0, 0, 0, 0, 0]\n", + "[0, 0, 0, 0, 0, 0, 0, 0, 1]\n", "tanh factor=0.05773502691896258\n", "tanh factor=0.023570226039551584\n", "tanh factor=0.040824829046386304\n", "tanh factor=0.05773502691896258\n", "softmax factor=0.01\n", - "nb errors before training=457/577\n", + "nb errors before training=561/577\n", "Training...\n" ] }, { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -362,9 +193,9 @@ "name": "stdout", "output_type": "stream", "text": [ - "learning duration=313.1954004764557(s)\n", - "{'cost_function': 0.165661765655898, 'iterations': 400}\n", - "nb errors=55/577\n" + "learning duration=311.9925892353058(s)\n", + "{'iterations': 400, 'cost_function': 0.01926710779513728}\n", + "nb errors=0/577\n" ] } ], @@ -392,7 +223,7 @@ "# Proceed learning with gradient descent\n", "print(\"Training...\")\n", "t0 = time.time()\n", - "res = mlp.learning(X.T, Y.T, m, min_cost=0.0005, max_iter=400, plot=True)\n", + "res = mlp.learning(X.T, Y.T, m, min_cost=0.005, max_iter=400, plot=True)\n", "t1 = time.time()\n", "print(\"learning duration={}(s)\".format(t1-t0))\n", "print(res)\n",