From 571a5d9d7ec956c69abb15d3f1f30f3c768a3a42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Pelletier?= Date: Fri, 3 May 2019 13:14:26 -0400 Subject: [PATCH] version finale remise --- Code/README.txt | 14 +- Code/Rapport-Final.ipynb | 311 ++++----- Code/classifieur.py | 90 --- Code/export_notebook_script.sh | 1 + Code/main.py | 1146 ++++++++++++++++++++++++++++++-- 5 files changed, 1245 insertions(+), 317 deletions(-) delete mode 100644 Code/classifieur.py diff --git a/Code/README.txt b/Code/README.txt index 8ec9a8d..57a53b0 100644 --- a/Code/README.txt +++ b/Code/README.txt @@ -2,15 +2,21 @@ Tâches effectuées entièrement par François Pelletier 908144032 . ├── BayesNaif.py (Classe pour le modèle Bayes Naif) -├── classifieur.py (Classe exemple) +├── DecisionTree.py (Classe pour le modèle DecisionTree) ├── datasets (Jeux de données) -├── entrainer_tester.py (Code pour exécuter tous les modèles, créé depuis Rapport-Partiel.ipynb avec export_notebook_script.sh) +├── entrainer_tester.py (Code pour exécuter les modèles BayesNaif et Knn, créé depuis Rapport-Partiel.ipynb avec export_notebook_script.sh) ├── export_notebook_script.sh (Script pour créer entrainer_tester.py depuis Rapport-Partiel.ipynb) ├── Knn.py (Classe pour le modèle KNN) ├── load_datasets.py (Classe pour charger les données) +├── main.py (Code pour exécuter DecisionTree et NeuralNet, créé depuis Rapport-Final.ipynb avec export_notebook_script.sh) ├── metrics.py (Fonctions pour le calcul des métriques) -├── Rapport-Partiel.ipynb (Code source du rapport) -├── Rapport-Partiel.pdf (Version PDF du rapport) +├── NeuralNet.py (Classe pour le modèle NeuralNet) +├── NeuralNetUtils.py (Fonctions utiles pour le modèle NeuralNet) +├── NeuralNode.py (Classe pour les noeuds du modèle NeuralNet) +├── Rapport-Final.ipynb (Code source du rapport final) +├── Rapport-Final.pdf (Version PDF du rapport final) +├── Rapport-Partiel.ipynb (Code source du rapport partiel) +├── Rapport-Partiel.pdf (Version PDF du rapport partiel) └── README.txt (Ce fichier-ci) Discussion, enjeux et difficultés: voir rapport PDF diff --git a/Code/Rapport-Final.ipynb b/Code/Rapport-Final.ipynb index 46d2f41..eb5ca28 100644 --- a/Code/Rapport-Final.ipynb +++ b/Code/Rapport-Final.ipynb @@ -15,7 +15,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ @@ -40,7 +40,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ @@ -59,7 +59,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ @@ -82,7 +82,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ @@ -111,7 +111,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 5, "metadata": {}, "outputs": [ { @@ -136,16 +136,16 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "[]" + "[]" ] }, - "execution_count": 9, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" }, @@ -175,7 +175,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 7, "metadata": {}, "outputs": [ { @@ -197,7 +197,7 @@ "[1.0, 0.9411764705882353, 1.0]\n", "\n", "Calculé en:\n", - "0.00035953521728515625s\n" + "0.0002942085266113281s\n" ] } ], @@ -216,7 +216,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 8, "metadata": {}, "outputs": [], "source": [ @@ -232,7 +232,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 9, "metadata": {}, "outputs": [], "source": [ @@ -246,7 +246,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 10, "metadata": {}, "outputs": [], "source": [ @@ -263,7 +263,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 11, "metadata": {}, "outputs": [], "source": [ @@ -284,16 +284,16 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "[]" + "[]" ] }, - "execution_count": 15, + "execution_count": 12, "metadata": {}, "output_type": "execute_result" }, @@ -323,7 +323,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 13, "metadata": {}, "outputs": [ { @@ -332,7 +332,7 @@ "49" ] }, - "execution_count": 16, + "execution_count": 13, "metadata": {}, "output_type": "execute_result" } @@ -354,7 +354,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 14, "metadata": {}, "outputs": [], "source": [ @@ -363,7 +363,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 15, "metadata": {}, "outputs": [], "source": [ @@ -393,7 +393,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 16, "metadata": {}, "outputs": [ { @@ -403,7 +403,7 @@ " [0.6952381 , 0.97142857, 0.88571429, 0.93333333, 0.79047619]])" ] }, - "execution_count": 19, + "execution_count": 16, "metadata": {}, "output_type": "execute_result" } @@ -421,7 +421,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 17, "metadata": {}, "outputs": [ { @@ -430,13 +430,14 @@ "2" ] }, - "execution_count": 20, + "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "n_couches_optimal1 = choix_n_couches[np.where(accuracy_cum==max(accuracy_cum))[0][0]]\n", + "n_couches_optimal1 = (\n", + " choix_n_couches[np.where(accuracy_cum==max(accuracy_cum))[0][0]])\n", "n_couches_optimal1" ] }, @@ -458,7 +459,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 18, "metadata": {}, "outputs": [ { @@ -494,7 +495,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 19, "metadata": {}, "outputs": [], "source": [ @@ -517,7 +518,7 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 20, "metadata": {}, "outputs": [], "source": [ @@ -542,7 +543,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 21, "metadata": {}, "outputs": [ { @@ -587,7 +588,7 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 22, "metadata": {}, "outputs": [ { @@ -609,7 +610,7 @@ "[1.0, 0.9411764705882353, 0.7692307692307693]\n", "\n", "Calculé en:\n", - "0.0332188606262207s\n" + "0.040042877197265625s\n" ] } ], @@ -628,7 +629,7 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 23, "metadata": {}, "outputs": [], "source": [ @@ -651,7 +652,7 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 24, "metadata": {}, "outputs": [], "source": [ @@ -679,13 +680,16 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 25, "metadata": {}, "outputs": [], "source": [ - "dt_range_lc2,dt_accuracy_cum2 = courbe_apprentissage_dt(dt2,train2,train_labels2)\n", - "dt_range_lc3,dt_accuracy_cum3 = courbe_apprentissage_dt(dt3,train3,train_labels3)\n", - "dt_range_lc4,dt_accuracy_cum4 = courbe_apprentissage_dt(dt4,train4,train_labels4)" + "dt_range_lc2,dt_accuracy_cum2 = (\n", + " courbe_apprentissage_dt(dt2,train2,train_labels2))\n", + "dt_range_lc3,dt_accuracy_cum3 = (\n", + " courbe_apprentissage_dt(dt3,train3,train_labels3))\n", + "dt_range_lc4,dt_accuracy_cum4 = (\n", + " courbe_apprentissage_dt(dt4,train4,train_labels4))" ] }, { @@ -698,16 +702,16 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "[]" + "[]" ] }, - "execution_count": 29, + "execution_count": 26, "metadata": {}, "output_type": "execute_result" }, @@ -737,16 +741,16 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": 27, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "[]" + "[]" ] }, - "execution_count": 30, + "execution_count": 27, "metadata": {}, "output_type": "execute_result" }, @@ -776,16 +780,16 @@ }, { "cell_type": "code", - "execution_count": 31, + "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "[]" + "[]" ] }, - "execution_count": 31, + "execution_count": 28, "metadata": {}, "output_type": "execute_result" }, @@ -822,7 +826,7 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 29, "metadata": {}, "outputs": [ { @@ -843,7 +847,7 @@ "[0.6605504587155964, 0.39351851851851855]\n", "\n", "Calculé en:\n", - "0.0012059211730957031s\n" + "0.0011060237884521484s\n" ] } ], @@ -853,7 +857,7 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": 30, "metadata": {}, "outputs": [ { @@ -874,7 +878,7 @@ "[0.7525773195876289, 0.3888888888888889]\n", "\n", "Calculé en:\n", - "0.001070261001586914s\n" + "0.0016949176788330078s\n" ] } ], @@ -884,7 +888,7 @@ }, { "cell_type": "code", - "execution_count": 34, + "execution_count": 31, "metadata": {}, "outputs": [ { @@ -905,7 +909,7 @@ "[0.14634146341463414, 0.8922413793103449]\n", "\n", "Calculé en:\n", - "0.001104116439819336s\n" + "0.001772165298461914s\n" ] } ], @@ -929,7 +933,7 @@ }, { "cell_type": "code", - "execution_count": 35, + "execution_count": 32, "metadata": {}, "outputs": [], "source": [ @@ -949,7 +953,7 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": 33, "metadata": {}, "outputs": [], "source": [ @@ -970,7 +974,7 @@ }, { "cell_type": "code", - "execution_count": 37, + "execution_count": 34, "metadata": {}, "outputs": [], "source": [ @@ -991,16 +995,16 @@ }, { "cell_type": "code", - "execution_count": 38, + "execution_count": 35, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "[]" + "[]" ] }, - "execution_count": 38, + "execution_count": 35, "metadata": {}, "output_type": "execute_result" }, @@ -1030,7 +1034,7 @@ }, { "cell_type": "code", - "execution_count": 39, + "execution_count": 36, "metadata": {}, "outputs": [ { @@ -1039,7 +1043,7 @@ "17" ] }, - "execution_count": 39, + "execution_count": 36, "metadata": {}, "output_type": "execute_result" } @@ -1052,7 +1056,7 @@ }, { "cell_type": "code", - "execution_count": 40, + "execution_count": 37, "metadata": {}, "outputs": [], "source": [ @@ -1073,16 +1077,16 @@ }, { "cell_type": "code", - "execution_count": 41, + "execution_count": 38, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "[]" + "[]" ] }, - "execution_count": 41, + "execution_count": 38, "metadata": {}, "output_type": "execute_result" }, @@ -1112,7 +1116,7 @@ }, { "cell_type": "code", - "execution_count": 42, + "execution_count": 39, "metadata": {}, "outputs": [ { @@ -1121,7 +1125,7 @@ "15" ] }, - "execution_count": 42, + "execution_count": 39, "metadata": {}, "output_type": "execute_result" } @@ -1134,7 +1138,7 @@ }, { "cell_type": "code", - "execution_count": 43, + "execution_count": 40, "metadata": {}, "outputs": [], "source": [ @@ -1155,16 +1159,16 @@ }, { "cell_type": "code", - "execution_count": 44, + "execution_count": 41, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "[]" + "[]" ] }, - "execution_count": 44, + "execution_count": 41, "metadata": {}, "output_type": "execute_result" }, @@ -1194,7 +1198,7 @@ }, { "cell_type": "code", - "execution_count": 45, + "execution_count": 42, "metadata": {}, "outputs": [ { @@ -1203,7 +1207,7 @@ "31" ] }, - "execution_count": 45, + "execution_count": 42, "metadata": {}, "output_type": "execute_result" } @@ -1223,7 +1227,7 @@ }, { "cell_type": "code", - "execution_count": 46, + "execution_count": 43, "metadata": {}, "outputs": [], "source": [ @@ -1248,13 +1252,16 @@ }, { "cell_type": "code", - "execution_count": 47, + "execution_count": 44, "metadata": {}, "outputs": [], "source": [ - "accuracy_cum2, lc_cum2 = accuracy_couches(train2,train_labels2,n_neurones_optimal2)\n", - "accuracy_cum3, lc_cum3 = accuracy_couches(train3,train_labels3,n_neurones_optimal3)\n", - "accuracy_cum4, lc_cum4 = accuracy_couches(train4,train_labels4,n_neurones_optimal4)" + "accuracy_cum2, lc_cum2 = (\n", + " accuracy_couches(train2,train_labels2,n_neurones_optimal2))\n", + "accuracy_cum3, lc_cum3 = (\n", + " accuracy_couches(train3,train_labels3,n_neurones_optimal3))\n", + "accuracy_cum4, lc_cum4 = (\n", + " accuracy_couches(train4,train_labels4,n_neurones_optimal4))" ] }, { @@ -1266,7 +1273,7 @@ }, { "cell_type": "code", - "execution_count": 48, + "execution_count": 45, "metadata": {}, "outputs": [ { @@ -1278,7 +1285,7 @@ " [0.62295082, 0.69672131, 0.87704918, 0.51639344, 0.50819672]])" ] }, - "execution_count": 48, + "execution_count": 45, "metadata": {}, "output_type": "execute_result" } @@ -1296,7 +1303,7 @@ }, { "cell_type": "code", - "execution_count": 49, + "execution_count": 46, "metadata": {}, "outputs": [ { @@ -1305,15 +1312,18 @@ "(4, 1, 3)" ] }, - "execution_count": 49, + "execution_count": 46, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "n_couches_optimal2 = choix_n_couches[np.where(accuracy_cum2==max(accuracy_cum2))[0][0]]\n", - "n_couches_optimal3 = choix_n_couches[np.where(accuracy_cum3==max(accuracy_cum3))[0][0]]\n", - "n_couches_optimal4 = choix_n_couches[np.where(accuracy_cum4==max(accuracy_cum4))[0][0]]\n", + "n_couches_optimal2 = (\n", + " choix_n_couches[np.where(accuracy_cum2==max(accuracy_cum2))[0][0]])\n", + "n_couches_optimal3 = (\n", + " choix_n_couches[np.where(accuracy_cum3==max(accuracy_cum3))[0][0]])\n", + "n_couches_optimal4 = (\n", + " choix_n_couches[np.where(accuracy_cum4==max(accuracy_cum4))[0][0]])\n", "(n_couches_optimal2,n_couches_optimal3,n_couches_optimal4)" ] }, @@ -1330,7 +1340,7 @@ }, { "cell_type": "code", - "execution_count": 50, + "execution_count": 47, "metadata": {}, "outputs": [ { @@ -1363,7 +1373,7 @@ }, { "cell_type": "code", - "execution_count": 51, + "execution_count": 48, "metadata": {}, "outputs": [ { @@ -1396,7 +1406,7 @@ }, { "cell_type": "code", - "execution_count": 52, + "execution_count": 49, "metadata": {}, "outputs": [ { @@ -1432,7 +1442,7 @@ }, { "cell_type": "code", - "execution_count": 53, + "execution_count": 50, "metadata": {}, "outputs": [], "source": [ @@ -1448,7 +1458,7 @@ }, { "cell_type": "code", - "execution_count": 54, + "execution_count": 51, "metadata": {}, "outputs": [], "source": [ @@ -1464,7 +1474,7 @@ }, { "cell_type": "code", - "execution_count": 55, + "execution_count": 52, "metadata": {}, "outputs": [], "source": [ @@ -1487,7 +1497,7 @@ }, { "cell_type": "code", - "execution_count": 56, + "execution_count": 53, "metadata": {}, "outputs": [], "source": [ @@ -1505,7 +1515,7 @@ }, { "cell_type": "code", - "execution_count": 57, + "execution_count": 54, "metadata": {}, "outputs": [], "source": [ @@ -1523,7 +1533,7 @@ }, { "cell_type": "code", - "execution_count": 58, + "execution_count": 55, "metadata": {}, "outputs": [], "source": [ @@ -1555,7 +1565,7 @@ }, { "cell_type": "code", - "execution_count": 59, + "execution_count": 56, "metadata": {}, "outputs": [ { @@ -1592,7 +1602,7 @@ }, { "cell_type": "code", - "execution_count": 60, + "execution_count": 57, "metadata": {}, "outputs": [ { @@ -1629,7 +1639,7 @@ }, { "cell_type": "code", - "execution_count": 61, + "execution_count": 58, "metadata": {}, "outputs": [ { @@ -1674,7 +1684,7 @@ }, { "cell_type": "code", - "execution_count": 62, + "execution_count": 59, "metadata": {}, "outputs": [ { @@ -1695,7 +1705,7 @@ "[0.0, 0.9953703703703703]\n", "\n", "Calculé en:\n", - "0.20783138275146484s\n" + "0.20888018608093262s\n" ] } ], @@ -1705,7 +1715,7 @@ }, { "cell_type": "code", - "execution_count": 63, + "execution_count": 60, "metadata": {}, "outputs": [ { @@ -1726,7 +1736,7 @@ "[0.8793103448275862, 0.11267605633802817]\n", "\n", "Calculé en:\n", - "0.04411029815673828s\n" + "0.049660444259643555s\n" ] } ], @@ -1736,7 +1746,7 @@ }, { "cell_type": "code", - "execution_count": 64, + "execution_count": 61, "metadata": {}, "outputs": [ { @@ -1757,7 +1767,7 @@ "[0.9950980392156863, 0.12719298245614036]\n", "\n", "Calculé en:\n", - "0.2925841808319092s\n" + "0.30426526069641113s\n" ] } ], @@ -1776,7 +1786,7 @@ }, { "cell_type": "code", - "execution_count": 65, + "execution_count": 62, "metadata": {}, "outputs": [], "source": [ @@ -1795,7 +1805,7 @@ }, { "cell_type": "code", - "execution_count": 66, + "execution_count": 63, "metadata": {}, "outputs": [], "source": [ @@ -1814,11 +1824,12 @@ }, { "cell_type": "code", - "execution_count": 67, + "execution_count": 64, "metadata": {}, "outputs": [], "source": [ - "dt_range_lc5,dt_accuracy_cum5 = courbe_apprentissage_dt(dt5,train5,train_labels5)" + "dt_range_lc5,dt_accuracy_cum5 = (\n", + " courbe_apprentissage_dt(dt5,train5,train_labels5))" ] }, { @@ -1830,16 +1841,16 @@ }, { "cell_type": "code", - "execution_count": 68, + "execution_count": 65, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "[]" + "[]" ] }, - "execution_count": 68, + "execution_count": 65, "metadata": {}, "output_type": "execute_result" }, @@ -1869,7 +1880,7 @@ }, { "cell_type": "code", - "execution_count": 69, + "execution_count": 66, "metadata": {}, "outputs": [ { @@ -1890,7 +1901,7 @@ "[0.41935483870967744, 0.8933333333333333]\n", "\n", "Calculé en:\n", - "0.0005872249603271484s\n" + "0.0005347728729248047s\n" ] } ], @@ -1914,7 +1925,7 @@ }, { "cell_type": "code", - "execution_count": 70, + "execution_count": 67, "metadata": {}, "outputs": [], "source": [ @@ -1927,7 +1938,7 @@ }, { "cell_type": "code", - "execution_count": 71, + "execution_count": 68, "metadata": {}, "outputs": [], "source": [ @@ -1944,7 +1955,7 @@ }, { "cell_type": "code", - "execution_count": 72, + "execution_count": 69, "metadata": {}, "outputs": [], "source": [ @@ -1969,16 +1980,16 @@ }, { "cell_type": "code", - "execution_count": 73, + "execution_count": 70, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "[]" + "[]" ] }, - "execution_count": 73, + "execution_count": 70, "metadata": {}, "output_type": "execute_result" }, @@ -2008,7 +2019,7 @@ }, { "cell_type": "code", - "execution_count": 74, + "execution_count": 71, "metadata": {}, "outputs": [ { @@ -2017,7 +2028,7 @@ "25" ] }, - "execution_count": 74, + "execution_count": 71, "metadata": {}, "output_type": "execute_result" } @@ -2037,7 +2048,7 @@ }, { "cell_type": "code", - "execution_count": 75, + "execution_count": 72, "metadata": {}, "outputs": [], "source": [ @@ -2067,7 +2078,7 @@ }, { "cell_type": "code", - "execution_count": 76, + "execution_count": 73, "metadata": {}, "outputs": [ { @@ -2077,7 +2088,7 @@ " [0.94736842, 0.92105263, 0.92763158, 0.90460526, 0.8125 ]])" ] }, - "execution_count": 76, + "execution_count": 73, "metadata": {}, "output_type": "execute_result" } @@ -2095,7 +2106,7 @@ }, { "cell_type": "code", - "execution_count": 77, + "execution_count": 74, "metadata": {}, "outputs": [ { @@ -2104,13 +2115,14 @@ "1" ] }, - "execution_count": 77, + "execution_count": 74, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "n_couches_optimal5 = choix_n_couches[np.where(accuracy_cum5==max(accuracy_cum5))[0][0]]\n", + "n_couches_optimal5 = (\n", + " choix_n_couches[np.where(accuracy_cum5==max(accuracy_cum5))[0][0]])\n", "n_couches_optimal5" ] }, @@ -2125,7 +2137,7 @@ }, { "cell_type": "code", - "execution_count": 78, + "execution_count": 75, "metadata": {}, "outputs": [ { @@ -2161,7 +2173,7 @@ }, { "cell_type": "code", - "execution_count": 79, + "execution_count": 76, "metadata": {}, "outputs": [], "source": [ @@ -2184,7 +2196,7 @@ }, { "cell_type": "code", - "execution_count": 80, + "execution_count": 77, "metadata": {}, "outputs": [], "source": [ @@ -2209,7 +2221,7 @@ }, { "cell_type": "code", - "execution_count": 81, + "execution_count": 78, "metadata": {}, "outputs": [ { @@ -2254,7 +2266,7 @@ }, { "cell_type": "code", - "execution_count": 82, + "execution_count": 79, "metadata": {}, "outputs": [ { @@ -2275,7 +2287,7 @@ "[0.9661016949152542, 0.9027777777777778]\n", "\n", "Calculé en:\n", - "0.02217245101928711s\n" + "0.021606922149658203s\n" ] } ], @@ -2299,7 +2311,7 @@ }, { "cell_type": "code", - "execution_count": 86, + "execution_count": 80, "metadata": {}, "outputs": [ { @@ -2309,7 +2321,7 @@ " [0.91111111, 0.49768519, 0.62731481, 0.53703704, 0.93129771]])" ] }, - "execution_count": 86, + "execution_count": 80, "metadata": {}, "output_type": "execute_result" } @@ -2336,19 +2348,19 @@ }, { "cell_type": "code", - "execution_count": 87, + "execution_count": 81, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "array([[7.98967150e-06, 2.79148420e-06, 2.47745602e-06, 2.55582509e-06,\n", - " 4.48263328e-06],\n", - " [7.38196903e-04, 4.81091164e-04, 1.02107172e-04, 6.77278196e-04,\n", - " 1.69255351e-04]])" + "array([[6.53796726e-06, 2.56024025e-06, 3.92342055e-06, 4.10223449e-06,\n", + " 4.08223567e-06],\n", + " [8.89841715e-04, 4.83518949e-04, 1.14954732e-04, 7.04317733e-04,\n", + " 1.64938337e-04]])" ] }, - "execution_count": 87, + "execution_count": 81, "metadata": {}, "output_type": "execute_result" } @@ -2375,19 +2387,19 @@ }, { "cell_type": "code", - "execution_count": 88, + "execution_count": 82, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "array([[1.85799599e-02, 2.40612030e-03, 2.02822685e-03, 1.84917450e-03,\n", - " 9.10449028e-03],\n", - " [4.40478587e+00, 3.11064458e+00, 8.43454361e-01, 4.58273411e+00,\n", - " 2.55364871e+00]])" + "array([[9.11688805e-03, 2.06351280e-03, 2.00963020e-03, 1.85656548e-03,\n", + " 1.11479759e-02],\n", + " [4.42183232e+00, 2.92573667e+00, 7.95306206e-01, 4.50003695e+00,\n", + " 2.64667988e+00]])" ] }, - "execution_count": 88, + "execution_count": 82, "metadata": {}, "output_type": "execute_result" } @@ -2423,13 +2435,6 @@ "\n", "Les réseaux de neurones nécessitent beaucoup plus de temps d'entrainement que les arbres de décisions, et il faut aussi considérer que ce temps est multiplié lorsque l'on effectue une recherche des hyperparamètres optimaux. Ce besoin de capacités physique explique pourquoi il a fallu attendre l'apparition des processeurs graphiques très performants pour que la recherche avec les réseaux de neurones explose. La complexité est d'autant plus élevée, car le nombre de connexions croit de façon exponentielle avec l'ajout de nouvelles couches cachées." ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { diff --git a/Code/classifieur.py b/Code/classifieur.py deleted file mode 100644 index cb440e4..0000000 --- a/Code/classifieur.py +++ /dev/null @@ -1,90 +0,0 @@ -""" -Vous allez definir une classe pour chaque algorithme que vous allez développer, -votre classe doit contenit au moins les 3 methodes definies ici bas, - * train : pour entrainer le modèle sur l'ensemble d'entrainement - * predict : pour prédire la classe d'un exemple donné - * test : pour tester sur l'ensemble de test -vous pouvez rajouter d'autres méthodes qui peuvent vous etre utiles, mais moi -je vais avoir besoin de tester les méthodes test, predict et test de votre code. -""" - -import numpy as np - - -# le nom de votre classe -# BayesNaif pour le modèle bayesien naif -# Knn pour le modèle des k plus proches voisins - -class Classifier: #nom de la class à changer - - def __init__(self, **kwargs): - """ - c'est un Initializer. - Vous pouvez passer d'autre paramètres au besoin, - c'est à vous d'utiliser vos propres notations - """ - - - def train(self, train, train_labels): #vous pouvez rajouter d'autres attribus au besoin - """ - c'est la méthode qui va entrainer votre modèle, - train est une matrice de type Numpy et de taille nxm, avec - n : le nombre d'exemple d'entrainement dans le dataset - m : le mobre d'attribus (le nombre de caractéristiques) - - train_labels : est une matrice numpy de taille nx1 - - vous pouvez rajouter d'autres arguments, il suffit juste de - les expliquer en commentaire - - - - ------------ - Après avoir fait l'entrainement, faites maintenant le test sur - les données d'entrainement - IMPORTANT : - Vous devez afficher ici avec la commande print() de python, - - la matrice de confision (confusion matrix) - - l'accuracy - - la précision (precision) - - le rappel (recall) - - Bien entendu ces tests doivent etre faits sur les données d'entrainement - nous allons faire d'autres tests sur les données de test dans la méthode test() - """ - - def predict(self, exemple, label): - """ - Prédire la classe d'un exemple donné en entrée - exemple est de taille 1xm - - si la valeur retournée est la meme que la veleur dans label - alors l'exemple est bien classifié, si non c'est une missclassification - - """ - - def test(self, test, test_labels): - """ - c'est la méthode qui va tester votre modèle sur les données de test - l'argument test est une matrice de type Numpy et de taille nxm, avec - n : le nombre d'exemple de test dans le dataset - m : le mobre d'attribus (le nombre de caractéristiques) - - test_labels : est une matrice numpy de taille nx1 - - vous pouvez rajouter d'autres arguments, il suffit juste de - les expliquer en commentaire - - Faites le test sur les données de test, et afficher : - - la matrice de confision (confusion matrix) - - l'accuracy - - la précision (precision) - - le rappel (recall) - - Bien entendu ces tests doivent etre faits sur les données de test seulement - - """ - - - # Vous pouvez rajouter d'autres méthodes et fonctions, - # il suffit juste de les commenter. diff --git a/Code/export_notebook_script.sh b/Code/export_notebook_script.sh index e46b7df..fa3e61e 100644 --- a/Code/export_notebook_script.sh +++ b/Code/export_notebook_script.sh @@ -1,2 +1,3 @@ #!/bin/bash jupyter nbconvert --to script --output entrainer_tester Rapport-Partiel.ipynb +jupyter nbconvert --to script --output main Rapport-Final.ipynb diff --git a/Code/main.py b/Code/main.py index f8ab11a..50756af 100644 --- a/Code/main.py +++ b/Code/main.py @@ -1,70 +1,1076 @@ -# -*- coding: utf-8 -*- -import numpy as np -import matplotlib.pyplot as plt -import sys -import load_datasets as ld -import NeuralNet # importer la classe du Réseau de Neurones -import DecisionTree # importer la classe de l'Arbre de Décision -import NeuralNetUtils as nnu -# importer d'autres fichiers et classes si vous en avez développés -# importer d'autres bibliothèques au besoin, sauf celles qui font du machine learning - -train1, train_labels1, test1, test_labels1 = ld.load_iris_dataset(train_ratio = 0.7) -train2, train_labels2, test2, test_labels2 = ld.load_monks_dataset(1) -train3, train_labels3, test3, test_labels3 = ld.load_monks_dataset(2) -train4, train_labels4, test4, test_labels4 = ld.load_monks_dataset(3) -train5, train_labels5, test5, test_labels5 = ld.load_congressional_dataset(train_ratio = 0.7) - - -dt1 = DecisionTree.DecisionTree(attribute_type="continuous") -dt1.train(train1, train_labels1) -dt1.predict(test1[0],test_labels1[0]) -dt1.test(test1, test_labels1) - -dt2 = DecisionTree.DecisionTree(attribute_type="discrete") -dt2.train(train2, train_labels2) -dt2.tree -dt2.predict(test2[0],test_labels2[0]) -dt2.test(test2, test_labels2) - -dt3 = DecisionTree.DecisionTree(attribute_type="discrete") -dt3.train(train3, train_labels3) -dt3.tree -dt3.predict(test3[0],test_labels3[0]) -dt3.test(test3, test_labels3) - -dt4 = DecisionTree.DecisionTree(attribute_type="discrete") -dt4.train(train4, train_labels4) -dt4.tree -dt4.predict(test4[0],test_labels4[0]) -dt4.test(test4, test_labels4) - -dt5 = DecisionTree.DecisionTree(attribute_type="discrete") -dt5.train(train5, train_labels5) -dt5.predict(test5[0],test_labels5[0]) -dt5.test(test5, test_labels5) - -nn1 = NeuralNet.NeuralNet(np.array([4,4,3]),range(3)) -nn1.train(train1, train_labels1, 0.1, 10) -nn1.predict(test1[0],test_labels1[0]) -nn1.test(test1,test_labels1) - -nn2 = NeuralNet.NeuralNet(np.array([6,12,2]),range(2)) -nn2.train(train2, train_labels2, 0.1, 10) -nn2.predict(test2[0],test_labels2[0]) -nn2.test(test2,test_labels2) - -nn3 = NeuralNet.NeuralNet(np.array([6,12,2]),range(2)) -nn3.train(train3, train_labels3, 0.1, 10) -nn3.predict(test3[0],test_labels3[0]) -nn3.test(test3,test_labels3) - -nn4 = NeuralNet.NeuralNet(np.array([6,12,2]),range(2)) -nn4.train(train4, train_labels4, 0.1, 10) -nn4.predict(test4[0],test_labels4[0]) -nn4.test(test4,test_labels4) - -nn5 = NeuralNet.NeuralNet(np.array([16,128,3]),range(3)) -nn5.train(train5, train_labels5, 0.1, 10) -nn5.predict(test5[0],test_labels5[0]) -nn5.test(test5,test_labels5) +#!/usr/bin/env python +# coding: utf-8 + +# # Introduction +# +# - Projet final présenté par: **François Pelletier** +# - Matricule: **908144032** +# - Dans le cadre du cours: **IFT-7025** +# +# # Librairies utilisées + +# In[1]: + + +import numpy as np +import load_datasets as ld +import matplotlib.pyplot as plt +import DecisionTree +import NeuralNet +import time + + +# ## Iris Dataset +# +# La présentation des résultats liés à ce jeu de données servira aussi à expliquer les concepts et répondre aux questions. Pour les autres jeux de données, seuls les résultats et la discussion seront détaillés. +# +# - Chargement du jeu de données + +# In[2]: + + +train1, train_labels1, test1, test_labels1 = ( + ld.load_iris_dataset(train_ratio = 0.7)) + + +# ### Entrainement de l'arbre de décision +# +# Dans cette section, on entraine un arbre de décision basé sur la mesure d'entropie. + +# In[3]: + + +dt1 = DecisionTree.DecisionTree(attribute_type="continuous") +start_time = time.time() +_ = dt1.train(train1, train_labels1,verbose=False) +dt1_compute_time = time.time() - start_time + + +# ### Courbe d'apprentissage +# +# Je trace une courbe d'apprentissage qui effectue une validation croisée sur 10 sous-ensembles de l'ensemble d'entrainement. Je fais la moyenne de l'accuracy pour chaque sous-ensemble de test, puis j'itère en ajoutant un exemple à la fois à l'ensemble d'entrainement. +# +# - Bogue connu: J'ai débuté la courbe d'apprentissage avec 30 données, car j'ai de la difficulté à exécuter la validation croisée avec moins sans que ça plante vu que je crée les sous-groupes à l'avance. + +# In[4]: + + +def courbe_apprentissage_dt(dt,train,train_labels,nb_cv_split=10): + accuracy_cum = [] + range_lc = range(30,len(train_labels)) + for i in range_lc: + range_lc_split_test = np.array_split(range(i),nb_cv_split) + range_lc_split_train = ( + [np.setdiff1d(range(i),t) for t in range_lc_split_test]) + accuracy_cv = [] + for r_i in range(nb_cv_split): + try: + training = dt.train(train[range_lc_split_train[r_i]], + train_labels[range_lc_split_train[r_i]], + verbose=False) + testres = dt.test(train[range_lc_split_test[r_i]], + train_labels[range_lc_split_test[r_i]], + verbose=False) + accuracy_cv.append(testres[1]) + except: + pass + accuracy_cum.append(np.mean(accuracy_cv)) + return range_lc,accuracy_cum + + +# In[5]: + + +dt_range_lc1,dt_accuracy_cum1 = courbe_apprentissage_dt(dt1,train1,train_labels1) + + +# Voici le graphique de la courbe d'apprentissage + +# In[6]: + + +plt.plot(dt_range_lc1,dt_accuracy_cum1) + + +# ### Test et évaluation de la performance de l'arbre de décision + +# In[7]: + + +dt1_testres = dt1.test(test1, test_labels1) + + +# ### Réseaux de neurones: Choix du nombre de neurones dans la couche cachée +# +# On doit identifier le nombre optimal de neurones dans la couche cachée dans l'intervalle $[4,50]$ pour chacun des 5 jeux de données. On itère sur chacun des jeux de validation croisée, pour chaque dimension, puis on calcule l'*accuracy* moyenne. La dimension qui a la meilleure *accuracy* moyenne est choisie pour construire le réseau de neurones. + +# In[8]: + + +choix_n_neurones = range(4,51) + + +# - Pour faire la séparation du jeu de données en $k_{cv}=5$ jeux de validation croisée, on génère une permutation sur les indices du jeu d'entrainement, puis, on sépare cet ensemble en 5 groupes. + +# In[9]: + + +k_cv = 5 +all_indices = range(len(train_labels1)) +np.random.seed(12345) +indices_cv_test = ( + np.sort(np.array_split(np.random.permutation(all_indices), + k_cv))) + + +# In[10]: + + +indices_cv_train = ( + [np.setdiff1d(all_indices,indices_cv_test[i]) for i in range(k_cv)]) + + +# Ce jeu de données a trois classes possibles comme variable de sortie. On utilisera donc un réseau de neurones avec 3 neurones dans la couche de sortie, une pour chacune des valeurs possibles. Les valeurs de sortie du jeu de données sont transformées à l'aide d'un encodage binaire où la valeur de sortie est convertie en rang dans un vecteur (on commence à 0), prenant la valeur 1. Par exemple, la valeur 2 devient $[0,0,1]$. + +# In[11]: + + +accuracy_cum = [] +for n_neurones in choix_n_neurones: + accuracy_cv=[] + for cv_set in range(k_cv): + nn1 = NeuralNet.NeuralNet(np.array([4,n_neurones,3]),range(3)) + nn1.train(train1[indices_cv_train[cv_set]], + train_labels1[indices_cv_train[cv_set]], 0.1, 1, + verbose=False) + _,accuracy,_,_,_ = nn1.test(train1[indices_cv_test[cv_set]], + train_labels1[indices_cv_test[cv_set]], + verbose=False) + accuracy_cv.append(accuracy) + accuracy_cum.append(np.mean(np.array(accuracy_cv))) + + +# In[12]: + + +plt.plot(choix_n_neurones,accuracy_cum) + + +# Le nombre de neurones qui maximise l'*accuracy* est de: + +# In[13]: + + +n_neurones_optimal1 = ( + choix_n_neurones[np.where(accuracy_cum==max(accuracy_cum))[0][0]]) +n_neurones_optimal1 + + +# ### Choix du nombre de couches cachées +# +# On choisit un nombre de 1 à 5 couches cachées. Le nombre de couches ayant l'*accuracy* maximale sera sélectionné pour la construction du réseau. On effectue 10 époques étant donné la taille des réseaux à entrainer. + +# In[14]: + + +choix_n_couches = range(1,6) + + +# In[15]: + + +accuracy_cum = [] +lc_cum = [] +for n_couches in choix_n_couches: + accuracy_cv=[] + nn1 = NeuralNet.NeuralNet( + np.hstack((4, + np.repeat(n_neurones_optimal1,n_couches), + 3)), + range(3)) + lc = nn1.train(train1, train_labels1, 0.1, 10, verbose=False) + lc_cum.append(lc) + _,accuracy,_,_,_ = nn1.test(train1, train_labels1, verbose=False) + accuracy_cv.append(accuracy) + accuracy_cum.append(np.mean(np.array(accuracy_cv))) +lc_cum = np.array(lc_cum) + + +# L'*accuracy* pour les différentes profondeur est de : + +# In[16]: + + +np.vstack((choix_n_couches,accuracy_cum)) + + +# Le nombre de couches cachées qui maximise l'*accuracy* est de: + +# In[17]: + + +n_couches_optimal1 = ( + choix_n_couches[np.where(accuracy_cum==max(accuracy_cum))[0][0]]) +n_couches_optimal1 + + +# Un problème rencontré avec un nombre de couches élevées est appelé le *Vanishing gradient problem*. Dans ces situations, le nombre de multiplications nécessaires ainsi que le fait que les valeurs $\Delta$ sont suffisamment petites pour que le gradient tende vers 0 et ainsi ne permette pas de mettre les poids à jour. Dans ces situations, l'entrainement va stagner. + +# ### Courbes d'apprentissage +# +# Ce graphique présente les courbes d'apprentissage pour chacun des niveaux de profondeur du réseau + +# In[18]: + + +plt.subplot(111) +for i in choix_n_couches: + plt.plot(range(10),lc_cum[i-1], label="%d couches"%(i,)) +leg = plt.legend(loc='best', ncol=2, mode="expand", shadow=True, fancybox=True) +leg.get_frame().set_alpha(0.5) + + +# ### Choix des poids initiaux +# Les poids initiaux ont été choisis à partir d'une distribution uniforme sur $[-1,1]$. On compare ici les courbes d'apprentissage en initialisant les poids à 0 et en initialisant les poids aléatoirement, pour le réseau de dimension et de profondeur optimale sélectionnées précédemment. +# +# - Réseau initialisé avec les poids à 0 $RN_{0}$ + +# In[19]: + + +nn1_poidszero = NeuralNet.NeuralNet( + np.hstack((4, + np.repeat(n_neurones_optimal1,n_couches_optimal1), + 3)), + range(3), + input_weights=0) +lc_nn1_poidszero = ( + nn1_poidszero.train(train1, train_labels1, 0.1, 10, verbose=False)) + + +# - Réseau initialisé avec les poids uniformes $RN_{\neg{0}}$ + +# In[20]: + + +nn1_poidsunif = NeuralNet.NeuralNet( + np.hstack((4, + np.repeat(n_neurones_optimal1,n_couches_optimal1), + 3)), + range(3)) +np.random.seed(12345) +start_time = time.time() +lc_nn1_poidsunif = ( + nn1_poidsunif.train(train1, train_labels1, 0.1, 10, verbose=False)) +nn1_compute_time = time.time() - start_time + + +# ### Graphique des courbes d'apprentissage + +# In[21]: + + +plt.subplot(111) +plt.plot(range(10),lc_nn1_poidszero, label="RN_Zero") +plt.plot(range(10),lc_nn1_poidsunif, label="RN_Non_Zero)") +leg = plt.legend(loc='best', + ncol=2, + mode="expand", + shadow=True, + fancybox=True) +leg.get_frame().set_alpha(0.5) + + +# On remarque clairement que l'initialisation des poids à 0 ne permet pas de démarrer l'entrainement du réseau. Il est donc nécessaire d'initialiser les poids aléatoirement pour permettre l'apprentissage et éviter que les différentes fonctions pour calculer la rétropropagation des erreurs aient toutes des valeurs de 0. + +# ### Entrainement et tests +# On reprend les résultats du dernier entrainement, puisqu'il utilise les poids aléatoires et les hyperparamètres optimaux. + +# In[22]: + + +res_test1 = nn1_poidsunif.test(test1, test_labels1) + + +# ## MONKS Dataset +# +# - Chargement des jeux de données + +# In[23]: + + +train2, train_labels2, test2, test_labels2 = ( + ld.load_monks_dataset(1)) +train3, train_labels3, test3, test_labels3 = ( + ld.load_monks_dataset(2)) +train4, train_labels4, test4, test_labels4 = ( + ld.load_monks_dataset(3)) + + +# ### Entrainement de l'arbre de décision +# +# Dans cette section, on entraine un arbre de décision basé sur la mesure d'entropie. + +# In[24]: + + +dt2 = DecisionTree.DecisionTree(attribute_type="discrete") +dt3 = DecisionTree.DecisionTree(attribute_type="discrete") +dt4 = DecisionTree.DecisionTree(attribute_type="discrete") + +start_time = time.time() +_ = dt2.train(train2, train_labels2,verbose=False) +dt2_compute_time = time.time() - start_time +start_time = time.time() +_ = dt3.train(train3, train_labels3,verbose=False) +dt3_compute_time = time.time() - start_time +start_time = time.time() +_ = dt4.train(train4, train_labels4,verbose=False) +dt4_compute_time = time.time() - start_time + + +# ### Courbe d'apprentissage +# + +# In[25]: + + +dt_range_lc2,dt_accuracy_cum2 = ( + courbe_apprentissage_dt(dt2,train2,train_labels2)) +dt_range_lc3,dt_accuracy_cum3 = ( + courbe_apprentissage_dt(dt3,train3,train_labels3)) +dt_range_lc4,dt_accuracy_cum4 = ( + courbe_apprentissage_dt(dt4,train4,train_labels4)) + + +# Voici les graphiques de la courbe d'apprentissage pour les 3 jeux de données +# - 1er jeu de données + +# In[26]: + + +plt.plot(dt_range_lc2,dt_accuracy_cum2) + + +# - 2e jeu de données + +# In[27]: + + +plt.plot(dt_range_lc3,dt_accuracy_cum3) + + +# - 3e jeu de données + +# In[28]: + + +plt.plot(dt_range_lc4,dt_accuracy_cum4) + + +# On peut facilement observer que dans les trois cas, il y a très peu d'apprentissage de réalisé par l'algorithme avec les exemples fournis. + +# ### Test et évaluation de la performance de l'arbre de décision + +# In[29]: + + +dt2_testres = dt2.test(test2, test_labels2) + + +# In[30]: + + +dt3_testres = dt3.test(test3, test_labels3) + + +# In[31]: + + +dt4_testres = dt4.test(test4, test_labels4) + + +# ### Réseaux de neurones: choix du nombre de neurones dans la couche cachée + +# - Pour faire la séparation du jeu de données en $k_{cv}=5$ jeux de validation croisée, on génère une permutation sur les indices du jeu d'entrainement, puis, on sépare cet ensemble en 5 groupes. + +# In[32]: + + +all_indices2 = range(len(train_labels2)) +all_indices3 = range(len(train_labels3)) +all_indices4 = range(len(train_labels4)) +np.random.seed(12345) +indices_cv_test2 = ( + [np.sort(x) for x in np.array_split(np.random.permutation(all_indices2),k_cv)]) +np.random.seed(12345) +indices_cv_test3 = ( + [np.sort(x) for x in np.array_split(np.random.permutation(all_indices3),k_cv)]) +np.random.seed(12345) +indices_cv_test4 = ( + [np.sort(x) for x in np.array_split(np.random.permutation(all_indices4),k_cv)]) + + +# In[33]: + + +indices_cv_train2 = ( + [np.setdiff1d(all_indices,indices_cv_test2[i]) for i in range(k_cv)]) +indices_cv_train3 = ( + [np.setdiff1d(all_indices,indices_cv_test3[i]) for i in range(k_cv)]) +indices_cv_train4 = ( + [np.setdiff1d(all_indices,indices_cv_test4[i]) for i in range(k_cv)]) + + +# Ces jeux de données ont deux classes possibles comme variable de sortie. On utilisera donc un réseau de neurones avec deux neurone dans la couche de sortie, une pour chacune des valeurs possibles. Les valeurs de sortie du jeu de données sont transformées à l'aide d'un encodage binaire où la valeur de sortie est convertie en rang dans un vecteur (on commence à 0), prenant la valeur 1. Par exemple, la valeur 1 devient $[0,1]$. + +# In[34]: + + +accuracy_cum2 = [] +for n_neurones in choix_n_neurones: + accuracy_cv=[] + for cv_set in range(k_cv): + nn2 = NeuralNet.NeuralNet(np.array([6,n_neurones,2]),range(2)) + nn2.train(train2[indices_cv_train2[cv_set]], + train_labels2[indices_cv_train2[cv_set]], 0.1, 1, + verbose=False) + _,accuracy,_,_,_ = nn2.test(train2[indices_cv_test2[cv_set]], + train_labels2[indices_cv_test2[cv_set]], + verbose=False) + accuracy_cv.append(accuracy) + accuracy_cum2.append(np.mean(np.array(accuracy_cv))) + + +# In[35]: + + +plt.plot(choix_n_neurones,accuracy_cum2) + + +# Le nombre de neurones qui maximise l'accuracy est de: + +# In[36]: + + +n_neurones_optimal2 = ( + choix_n_neurones[np.where(accuracy_cum2==max(accuracy_cum2))[0][0]]) +n_neurones_optimal2 + + +# In[37]: + + +accuracy_cum3 = [] +for n_neurones in choix_n_neurones: + accuracy_cv=[] + for cv_set in range(k_cv): + nn3 = NeuralNet.NeuralNet(np.array([6,n_neurones,2]),range(2)) + nn3.train(train3[indices_cv_train3[cv_set]], + train_labels3[indices_cv_train3[cv_set]], 0.1, 1, + verbose=False) + _,accuracy,_,_,_ = nn3.test(train3[indices_cv_test3[cv_set]], + train_labels3[indices_cv_test3[cv_set]], + verbose=False) + accuracy_cv.append(accuracy) + accuracy_cum3.append(np.mean(np.array(accuracy_cv))) + + +# In[38]: + + +plt.plot(choix_n_neurones,accuracy_cum3) + + +# Le nombre de neurones qui maximise l'accuracy est de: + +# In[39]: + + +n_neurones_optimal3 = ( + choix_n_neurones[np.where(accuracy_cum3==max(accuracy_cum3))[0][0]]) +n_neurones_optimal3 + + +# In[40]: + + +accuracy_cum4 = [] +for n_neurones in choix_n_neurones: + accuracy_cv=[] + for cv_set in range(k_cv): + nn4 = NeuralNet.NeuralNet(np.array([6,n_neurones,2]),range(2)) + nn4.train(train4[indices_cv_train4[cv_set]], + train_labels4[indices_cv_train4[cv_set]], 0.1, 1, + verbose=False) + _,accuracy,_,_,_ = nn4.test(train4[indices_cv_test4[cv_set]], + train_labels4[indices_cv_test4[cv_set]], + verbose=False) + accuracy_cv.append(accuracy) + accuracy_cum4.append(np.mean(np.array(accuracy_cv))) + + +# In[41]: + + +plt.plot(choix_n_neurones,accuracy_cum4) + + +# Le nombre de neurones qui maximise l'*accuracy* est de: + +# In[42]: + + +n_neurones_optimal4 = ( + choix_n_neurones[np.where(accuracy_cum4==max(accuracy_cum4))[0][0]]) +n_neurones_optimal4 + + +# ### Choix du nombre de couches cachées + +# In[43]: + + +def accuracy_couches(train,train_labels,n_neurones_optimal): + accuracy_cum = [] + lc_cum = [] + for n_couches in choix_n_couches: + accuracy_cv=[] + nn = NeuralNet.NeuralNet( + np.hstack((6, + np.repeat(n_neurones_optimal,n_couches), + 2)), + range(2)) + lc = nn.train(train, train_labels, 0.1, 10, verbose=False) + lc_cum.append(lc) + _,accuracy,_,_,_ = nn.test(train, train_labels, verbose=False) + accuracy_cv.append(accuracy) + accuracy_cum.append(np.mean(np.array(accuracy_cv))) + lc_cum = np.array(lc_cum) + return accuracy_cum, lc_cum + + +# In[44]: + + +accuracy_cum2, lc_cum2 = ( + accuracy_couches(train2,train_labels2,n_neurones_optimal2)) +accuracy_cum3, lc_cum3 = ( + accuracy_couches(train3,train_labels3,n_neurones_optimal3)) +accuracy_cum4, lc_cum4 = ( + accuracy_couches(train4,train_labels4,n_neurones_optimal4)) + + +# L'*accuracy* pour les différentes profondeur est respectivement (un jeu de données par ligne) de : + +# In[45]: + + +np.vstack((choix_n_couches,accuracy_cum2,accuracy_cum3,accuracy_cum4)) + + +# Le nombre de couches cachées qui maximise l'*accuracy* est, pour chacun des 3 jeux de données, respectivement de: + +# In[46]: + + +n_couches_optimal2 = ( + choix_n_couches[np.where(accuracy_cum2==max(accuracy_cum2))[0][0]]) +n_couches_optimal3 = ( + choix_n_couches[np.where(accuracy_cum3==max(accuracy_cum3))[0][0]]) +n_couches_optimal4 = ( + choix_n_couches[np.where(accuracy_cum4==max(accuracy_cum4))[0][0]]) +(n_couches_optimal2,n_couches_optimal3,n_couches_optimal4) + + +# ### Courbes d'apprentissage +# +# Ce graphique présente les courbes d'apprentissage pour chacun des niveaux de profondeur du réseau +# +# - MONKS1 + +# In[47]: + + +plt.subplot(111) +for i in choix_n_couches: + plt.plot(range(10),lc_cum2[i-1], label="%d couches"%(i,)) +leg = plt.legend(loc='best', ncol=2, mode="expand", shadow=True, fancybox=True) +leg.get_frame().set_alpha(0.5) + + +# - MONKS2 + +# In[48]: + + +plt.subplot(111) +for i in choix_n_couches: + plt.plot(range(10),lc_cum3[i-1], label="%d couches"%(i,)) +leg = plt.legend(loc='best', ncol=2, mode="expand", shadow=True, fancybox=True) +leg.get_frame().set_alpha(0.5) + + +# - MONKS3 + +# In[49]: + + +plt.subplot(111) +for i in choix_n_couches: + plt.plot(range(10),lc_cum4[i-1], label="%d couches"%(i,)) +leg = plt.legend(loc='best', ncol=2, mode="expand", shadow=True, fancybox=True) +leg.get_frame().set_alpha(0.5) + + +# ### Choix des poids initiaux +# Les poids initiaux ont été choisis à partir d'une distribution uniforme sur $[-1,1]$. On compare ici les courbes d'apprentissage en initialisant les poids à 0 et en initialisant les poids aléatoirement, pour le réseau de dimension et de profondeur optimale sélectionnées précédemment. +# +# - Réseau initialisé avec les poids à 0 $RN_{0}$ + +# In[50]: + + +nn2_poidszero = NeuralNet.NeuralNet( + np.hstack((6, + np.repeat(n_neurones_optimal2,n_couches_optimal2), + 2)), + range(2), + input_weights=0) +lc_nn2_poidszero = ( + nn2_poidszero.train(train2, train_labels2, 0.1, 10, verbose=False)) + + +# In[51]: + + +nn3_poidszero = NeuralNet.NeuralNet( + np.hstack((6, + np.repeat(n_neurones_optimal3,n_couches_optimal3), + 2)), + range(2), + input_weights=0) +lc_nn3_poidszero = ( + nn3_poidszero.train(train3, train_labels3, 0.1, 10, verbose=False)) + + +# In[52]: + + +nn4_poidszero = NeuralNet.NeuralNet( + np.hstack((6, + np.repeat(n_neurones_optimal4,n_couches_optimal4), + 2)), + range(2), + input_weights=0) +lc_nn4_poidszero = ( + nn4_poidszero.train(train4, train_labels4, 0.1, 10, verbose=False)) + + +# - Réseau initialisé avec les poids uniformes $RN_{\neg{0}}$ + +# In[53]: + + +nn2_poidsunif = NeuralNet.NeuralNet( + np.hstack((6, + np.repeat(n_neurones_optimal2,n_couches_optimal2), + 2)), + range(2)) +np.random.seed(12345) +start_time = time.time() +lc_nn2_poidsunif = ( + nn2_poidsunif.train(train2, train_labels2, 0.1, 10, verbose=False)) +nn2_compute_time = time.time() - start_time + + +# In[54]: + + +nn3_poidsunif = NeuralNet.NeuralNet( + np.hstack((6, + np.repeat(n_neurones_optimal3,n_couches_optimal3), + 2)), + range(2)) +np.random.seed(12345) +start_time = time.time() +lc_nn3_poidsunif = ( + nn3_poidsunif.train(train3, train_labels3, 0.1, 10, verbose=False)) +nn3_compute_time = time.time() - start_time + + +# In[55]: + + +nn4_poidsunif = NeuralNet.NeuralNet( + np.hstack((6, + np.repeat(n_neurones_optimal4,n_couches_optimal4), + 2)), + range(2)) +np.random.seed(12345) +start_time = time.time() +lc_nn4_poidsunif = ( + nn4_poidsunif.train(train4, train_labels4, 0.1, 10, verbose=False)) +nn4_compute_time = time.time() - start_time + + +# ### Graphique des courbes d'apprentissage + +# - MONKS1 + +# In[56]: + + +plt.subplot(111) +plt.plot(range(10),lc_nn2_poidszero, label="MONKS1: RN_Zero") +plt.plot(range(10),lc_nn2_poidsunif, label="MONKS1: RN_Non_Zero)") +leg = plt.legend(loc='best', + ncol=2, + mode="expand", + shadow=True, + fancybox=True) +leg.get_frame().set_alpha(0.5) + + +# - MONKS2 + +# In[57]: + + +plt.subplot(111) +plt.plot(range(10),lc_nn3_poidszero, label="MONKS2: RN_Zero") +plt.plot(range(10),lc_nn3_poidsunif, label="MONKS2: RN_Non_Zero)") +leg = plt.legend(loc='best', + ncol=2, + mode="expand", + shadow=True, + fancybox=True) +leg.get_frame().set_alpha(0.5) + + +# - MONKS3 + +# In[58]: + + +plt.subplot(111) +plt.plot(range(10),lc_nn4_poidszero, label="MONKS3: RN_Zero") +plt.plot(range(10),lc_nn4_poidsunif, label="MONKS3: RN_Non_Zero)") +leg = plt.legend(loc='best', + ncol=2, + mode="expand", + shadow=True, + fancybox=True) +leg.get_frame().set_alpha(0.5) + + +# On remarque ici aussi que l'initialisation des poids à 0 ne permet pas de démarrer l'entrainement du réseau. Dans le second jeu de données, cependant, l'initialisation aléatoire ne permet pas non plus de démarrer l'apprentissage. + +# ### Entrainement et tests +# On reprend les résultats du dernier entrainement, puisqu'il utilise les poids aléatoires et les hyperparamètres optimaux. + +# In[59]: + + +res_test2 = nn2_poidsunif.test(test2, test_labels2) + + +# In[60]: + + +res_test3 = nn3_poidsunif.test(test3, test_labels3) + + +# In[61]: + + +res_test4 = nn4_poidsunif.test(test4, test_labels4) + + +# ## Congressionnal Dataset +# +# - Chargement du jeu de données + +# In[62]: + + +train5, train_labels5, test5, test_labels5 = ( + ld.load_congressional_dataset(train_ratio = 0.7)) + + +# ### Entrainement de l'arbre de décision +# +# Dans cette section, on entraine un arbre de décision basé sur la mesure d'entropie. + +# In[63]: + + +dt5 = DecisionTree.DecisionTree(attribute_type="discrete") +start_time = time.time() +_ = dt5.train(train5, train_labels5, verbose=False) +dt5_compute_time = time.time() - start_time + + +# ### Courbe d'apprentissage + +# In[64]: + + +dt_range_lc5,dt_accuracy_cum5 = ( + courbe_apprentissage_dt(dt5,train5,train_labels5)) + + +# Voici le graphique de la courbe d'apprentissage + +# In[65]: + + +plt.plot(dt_range_lc5,dt_accuracy_cum5) + + +# ### Test et évaluation de la performance de l'arbre de décision + +# In[66]: + + +dt5_testres = dt5.test(test5, test_labels5) + + +# ### Réseaux de neurones: Choix du nombre de neurones dans la couche cachée + +# - Pour faire la séparation du jeu de données en $k_{cv}=5$ jeux de validation croisée, on génère une permutation sur les indices du jeu d'entrainement, puis, on sépare cet ensemble en 5 groupes. + +# In[67]: + + +all_indices5 = range(len(train_labels5)) +np.random.seed(12345) +indices_cv_test5 = ( + [np.sort(x) for x in (np.array_split(np.random.permutation(all_indices5), + k_cv))]) + + +# In[68]: + + +indices_cv_train5 = ( + [np.setdiff1d(all_indices5,indices_cv_test5[i]) for i in range(k_cv)]) + + +# Ce jeux de données a trois classes possibles comme variable de sortie. On utilisera donc un réseau de neurones avec 3 neurones dans la couche de sortie, une pour chacune des valeurs possibles. Les valeurs de sortie du jeu de données sont transformées à l'aide d'un encodage binaire où la valeur de sortie est convertie en rang dans un vecteur (on commence à 0), prenant la valeur 1. Par exemple, la valeur 2 devient $[0,0,1]$. + +# In[69]: + + +accuracy_cum5 = [] +for n_neurones in choix_n_neurones: + accuracy_cv=[] + for cv_set in range(k_cv): + accuracy=0 + try: + nn5 = NeuralNet.NeuralNet(np.array([16,n_neurones,3]),range(3)) + nn5.train(train5[indices_cv_train5[cv_set]], + train_labels5[indices_cv_train5[cv_set]], 0.1, 1, + verbose=False) + _,accuracy,_,_,_ = nn5.test(train5[indices_cv_test5[cv_set]], + train_labels5[indices_cv_test5[cv_set]], + verbose=False) + except: + pass + accuracy_cv.append(accuracy) + accuracy_cum5.append(np.mean(np.array(accuracy_cv))) + + +# In[70]: + + +plt.plot(choix_n_neurones,accuracy_cum5) + + +# Le nombre de neurones qui maximise l'*accuracy* est de: + +# In[71]: + + +n_neurones_optimal5 = ( + choix_n_neurones[np.where(accuracy_cum5==max(accuracy_cum5))[0][0]]) +n_neurones_optimal5 + + +# ### Choix du nombre de couches cachées + +# In[72]: + + +accuracy_cum5 = [] +lc_cum5 = [] +for n_couches in choix_n_couches: + accuracy_cv=[] + nn5 = NeuralNet.NeuralNet( + np.hstack((16, + np.repeat(n_neurones_optimal5,n_couches), + 3)), + range(3)) + lc = nn5.train(train5, train_labels5, 0.1, 10, verbose=False) + lc_cum5.append(lc) + _,accuracy,_,_,_ = nn5.test(train5, train_labels5, verbose=False) + accuracy_cv.append(accuracy) + accuracy_cum5.append(np.mean(np.array(accuracy_cv))) +lc_cum5 = np.array(lc_cum5) + + +# L'*accuracy* pour les différentes profondeur est de : + +# In[73]: + + +np.vstack((choix_n_couches,accuracy_cum5)) + + +# Le nombre de couches cachées qui maximise l'*accuracy* est de: + +# In[74]: + + +n_couches_optimal5 = ( + choix_n_couches[np.where(accuracy_cum5==max(accuracy_cum5))[0][0]]) +n_couches_optimal5 + + +# ### Courbes d'apprentissage +# +# Ce graphique présente les courbes d'apprentissage pour chacun des niveaux de profondeur du réseau + +# In[75]: + + +plt.subplot(111) +for i in choix_n_couches: + plt.plot(range(10),lc_cum5[i-1], label="%d couches"%(i,)) +leg = plt.legend(loc='best', ncol=2, mode="expand", shadow=True, fancybox=True) +leg.get_frame().set_alpha(0.5) + + +# ### Choix des poids initiaux +# Les poids initiaux ont été choisis à partir d'une distribution uniforme sur $[-1,1]$. On compare ici les courbes d'apprentissage en initialisant les poids à 0 et en initialisant les poids aléatoirement, pour le réseau de dimension et de profondeur optimale sélectionnées précédemment. +# +# - Réseau initialisé avec les poids à 0 $RN_{0}$ + +# In[76]: + + +nn5_poidszero = NeuralNet.NeuralNet( + np.hstack((16, + np.repeat(n_neurones_optimal5,n_couches_optimal5), + 3)), + range(3), + input_weights=0) +lc_nn5_poidszero = ( + nn5_poidszero.train(train5, train_labels5, 0.1, 10, verbose=False)) + + +# - Réseau initialisé avec les poids uniformes $RN_{\neg{0}}$ + +# In[77]: + + +nn5_poidsunif = NeuralNet.NeuralNet( + np.hstack((16, + np.repeat(n_neurones_optimal5,n_couches_optimal5), + 3)), + range(3)) +np.random.seed(12345) +start_time = time.time() +lc_nn5_poidsunif = ( + nn5_poidsunif.train(train5, train_labels5, 0.1, 10, verbose=False)) +nn5_compute_time = time.time() - start_time + + +# ### Graphique des courbes d'apprentissage + +# In[78]: + + +plt.subplot(111) +plt.plot(range(10),lc_nn5_poidszero, label="RN_Zero") +plt.plot(range(10),lc_nn5_poidsunif, label="RN_Non_Zero)") +leg = plt.legend(loc='best', + ncol=2, + mode="expand", + shadow=True, + fancybox=True) +leg.get_frame().set_alpha(0.5) + + +# On remarque ici aussi que l'initialisation des poids à 0 ne permet pas de démarrer l'entrainement du réseau. + +# ### Entrainement et tests +# On reprend les résultats du dernier entrainement, puisqu'il utilise les poids aléatoires et les hyperparamètres optimaux. + +# In[79]: + + +res_test5 = nn5_poidsunif.test(test5, test_labels5) + + +# ## Comparaison entre arbre de décision et réseau de neurones + +# - Taux d'erreur sur l'ensemble de test. Sur la première ligne, les erreurs pour les arbres de décision, sur la seconde, pour les réseaux de neurones + +# In[80]: + + +np.array([[dt1_testres[1], + dt2_testres[1], + dt3_testres[1], + dt4_testres[1], + dt5_testres[1]], + [res_test1[1], + res_test2[1], + res_test3[1], + res_test4[1], + res_test5[1]]]) + + +# - Temps de prédiction d’un seul exemple. Sur la première ligne, les temps de prédiction moyens pour un exemple de l'ensemble de test pour les arbres de décision, sur la seconde, pour les réseaux de neurones + +# In[81]: + + +np.array([[dt1_testres[4]/len(test_labels1), + dt2_testres[4]/len(test_labels2), + dt3_testres[4]/len(test_labels3), + dt4_testres[4]/len(test_labels4), + dt5_testres[4]/len(test_labels5)], + [res_test1[4]/len(test_labels1), + res_test2[4]/len(test_labels2), + res_test3[4]/len(test_labels3), + res_test4[4]/len(test_labels4), + res_test5[4]/len(test_labels5)]]) + + +# - Temps d’apprentissage du modèle. Sur la première ligne, les temps d'entrainement pour les arbres de décision, sur la seconde, pour les réseaux de neurones + +# In[82]: + + +np.array([ + [dt1_compute_time, + dt2_compute_time, + dt3_compute_time, + dt4_compute_time, + dt5_compute_time], + [nn1_compute_time, + nn2_compute_time, + nn3_compute_time, + nn4_compute_time, + nn5_compute_time]]) + + +# ## Conclusion + +# Les arbres de décisions sont des algorithmes simples à mettre en oeuvre et démontrent une exactitude supérieure et comparable aux arbres de décisions lorsque le nombre d'attributs est limité. Cependant, lorsque le nombre d'attributs croît, les réseaux de neurones sont beaucoup plus performants. Ceci est démontré entre autres par la performance sur le jeu de données Congressionnal où le réseau de neurones est beaucoup plus performant. Pour les jeux de données plus difficiles tels que MONKS, on ne remarque pas une grande différence entre les deux algorithmes au niveau du taux d'erreur. +# +# Le temps de prédiction est deux ordres de magnitude plus élevé pour les réseaux de neurones que pour les arbres de décisions, car il faut effectuer toutes les multiplications des valeurs par les poids pour chacune des couches, ce qui est une opération $O(d^2)$ pour une dimension $d$. Pour l'arbre de décision, la prédiction est une recherche dans un arbre binaire, de complexité $O(log_2(d))$ pour une profondeur $d$. +# +# Les réseaux de neurones nécessitent beaucoup plus de temps d'entrainement que les arbres de décisions, et il faut aussi considérer que ce temps est multiplié lorsque l'on effectue une recherche des hyperparamètres optimaux. Ce besoin de capacités physique explique pourquoi il a fallu attendre l'apparition des processeurs graphiques très performants pour que la recherche avec les réseaux de neurones explose. La complexité est d'autant plus élevée, car le nombre de connexions croit de façon exponentielle avec l'ajout de nouvelles couches cachées.