2019-05-03 02:25:24 +00:00
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Introduction\n",
"\n",
"- Projet final présenté par: **François Pelletier**\n",
"- Matricule: **908144032**\n",
"- Dans le cadre du cours: **IFT-7025**\n",
"\n",
"# Librairies utilisées"
]
},
{
"cell_type": "code",
2019-05-03 04:11:36 +00:00
"execution_count": null,
2019-05-03 02:25:24 +00:00
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import load_datasets as ld\n",
"import matplotlib.pyplot as plt\n",
2019-05-03 04:11:36 +00:00
"import DecisionTree\n",
2019-05-03 02:25:24 +00:00
"import NeuralNet"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Iris Dataset\n",
"\n",
"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, seul les résultats et la discussion seront détaillés.\n",
"\n",
"- Chargement du jeu de données"
]
},
{
"cell_type": "code",
2019-05-03 04:11:36 +00:00
"execution_count": null,
2019-05-03 02:25:24 +00:00
"metadata": {},
"outputs": [],
"source": [
2019-05-03 04:36:22 +00:00
"train1, train_labels1, test1, test_labels1 = (\n",
" ld.load_iris_dataset(train_ratio = 0.7))"
2019-05-03 02:25:24 +00:00
]
},
2019-05-03 04:11:36 +00:00
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Entrainement de l'arbre de décision\n",
"\n",
"Dans cette section, on entraine un arbre de décision basé sur la mesure d'entropie."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"dt1 = DecisionTree.DecisionTree(attribute_type=\"continuous\")\n",
"_ = dt1.train(train1, train_labels1,verbose=False)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Courbe d'apprentissage\n",
"\n",
"Je trace une courbe d'apprentissage qui effectue une validation croisée sur 10 sous-ensembles de l'ensemble d'entrainement. Je vais 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.\n",
"\n",
"- Bogue connu: J'ai débuté à 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."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"accuracy_cum = []\n",
"range_lc = range(30,len(train_labels1))\n",
"for i in range_lc:\n",
" range_lc_split_test = np.array_split(range(i),10)\n",
2019-05-03 04:36:22 +00:00
" range_lc_split_train = (\n",
" [np.setdiff1d(range(i),t) for t in range_lc_split_test])\n",
2019-05-03 04:11:36 +00:00
" accuracy_cv = []\n",
" for r_i in range(10):\n",
" try:\n",
2019-05-03 04:36:22 +00:00
" training = dt1.train(train1[range_lc_split_train[r_i]], \n",
" train_labels1[range_lc_split_train[r_i]],\n",
" verbose=False)\n",
" test = dt1.test(train1[range_lc_split_test[r_i]], \n",
" train_labels1[range_lc_split_test[r_i]],\n",
" verbose=False)\n",
2019-05-03 04:11:36 +00:00
" accuracy_cv.append(test[1])\n",
" except:\n",
" pass\n",
" accuracy_cum.append(np.mean(accuracy_cv))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Voici le graphique de la courbe d'apprentissage"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plt.plot(range_lc,accuracy_cum)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Test et évaluation de la performance de l'arbre de décision"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"_ = dt1.test(test1, test_labels1)"
]
},
2019-05-03 02:25:24 +00:00
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Choix du nombre de neurones dans la couche cachée\n",
"\n",
"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 et on calcule l'accuracy moyenne. La dimension qui a la meilleure accuracy moyenne est choisie pour construire le réseau de neurones."
]
},
{
"cell_type": "code",
2019-05-03 04:11:36 +00:00
"execution_count": null,
2019-05-03 02:25:24 +00:00
"metadata": {},
"outputs": [],
"source": [
"choix_n_neurones = range(4,51)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- 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."
]
},
{
"cell_type": "code",
2019-05-03 04:11:36 +00:00
"execution_count": null,
2019-05-03 02:25:24 +00:00
"metadata": {},
"outputs": [],
"source": [
"k_cv = 5\n",
"all_indices = range(len(train_labels1))\n",
"np.random.seed(12345)\n",
2019-05-03 04:36:22 +00:00
"indices_cv_test = (\n",
" np.sort(np.array_split(np.random.permutation(all_indices),\n",
" k_cv)))"
2019-05-03 02:25:24 +00:00
]
},
{
"cell_type": "code",
2019-05-03 04:11:36 +00:00
"execution_count": null,
2019-05-03 02:25:24 +00:00
"metadata": {},
"outputs": [],
"source": [
2019-05-03 04:36:22 +00:00
"indices_cv_train = (\n",
" [np.setdiff1d(all_indices,indices_cv_test[i]) for i in range(k_cv)])"
2019-05-03 02:25:24 +00:00
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"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]$."
]
},
{
"cell_type": "code",
2019-05-03 04:11:36 +00:00
"execution_count": null,
"metadata": {},
"outputs": [],
2019-05-03 02:25:24 +00:00
"source": [
"accuracy_cum = []\n",
"for n_neurones in choix_n_neurones:\n",
" accuracy_cv=[]\n",
" for cv_set in range(k_cv):\n",
" nn1 = NeuralNet.NeuralNet(np.array([4,n_neurones,3]),range(3))\n",
2019-05-03 04:36:22 +00:00
" nn1.train(train1[indices_cv_train[cv_set]], \n",
" train_labels1[indices_cv_train[cv_set]], 0.1, 1, \n",
" verbose=False)\n",
" _,accuracy,_,_,_ = nn1.test(train1[indices_cv_test[cv_set]], \n",
" train_labels1[indices_cv_test[cv_set]], \n",
" verbose=False)\n",
2019-05-03 02:25:24 +00:00
" accuracy_cv.append(accuracy)\n",
" accuracy_cum.append(np.mean(np.array(accuracy_cv)))"
]
},
{
"cell_type": "code",
2019-05-03 04:11:36 +00:00
"execution_count": null,
"metadata": {},
"outputs": [],
2019-05-03 02:25:24 +00:00
"source": [
"plt.plot(choix_n_neurones,accuracy_cum)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Le nombre de neurones qui maximise l'accuracy est de:"
]
},
{
"cell_type": "code",
2019-05-03 04:11:36 +00:00
"execution_count": null,
"metadata": {},
"outputs": [],
2019-05-03 02:25:24 +00:00
"source": [
2019-05-03 04:36:22 +00:00
"n_neurones_optimal1 = (\n",
" choix_n_neurones[np.where(accuracy_cum==max(accuracy_cum))[0][0]])\n",
2019-05-03 02:25:24 +00:00
"n_neurones_optimal1"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Choix du nombre de couches cachées\n",
"\n",
"On choisit un nombre de 1 à 5 couches cachées. Le nombre de couche ayany l'accuracy maximale sera sélectionné pour la construction du réseau. On effectue 10 époques étant donné la taille des réseaux à entrainer."
]
},
{
"cell_type": "code",
2019-05-03 04:11:36 +00:00
"execution_count": null,
2019-05-03 02:25:24 +00:00
"metadata": {},
"outputs": [],
"source": [
"choix_n_couches = range(1,6)"
]
},
{
"cell_type": "code",
2019-05-03 04:11:36 +00:00
"execution_count": null,
2019-05-03 02:25:24 +00:00
"metadata": {},
"outputs": [],
"source": [
"accuracy_cum = []\n",
"lc_cum = []\n",
"for n_couches in choix_n_couches:\n",
" accuracy_cv=[]\n",
2019-05-03 04:36:22 +00:00
" nn1 = NeuralNet.NeuralNet(\n",
" np.hstack((4,\n",
" np.repeat(n_neurones_optimal1,n_couches),\n",
" 3)),\n",
" range(3))\n",
2019-05-03 02:25:24 +00:00
" lc = nn1.train(train1, train_labels1, 0.1, 10, verbose=False)\n",
" lc_cum.append(lc)\n",
" _,accuracy,_,_,_ = nn1.test(train1, train_labels1, verbose=False)\n",
" accuracy_cv.append(accuracy)\n",
" accuracy_cum.append(np.mean(np.array(accuracy_cv)))\n",
"lc_cum = np.array(lc_cum)"
]
},
2019-05-03 04:11:36 +00:00
{
"cell_type": "markdown",
"metadata": {},
"source": [
"L'accuracy pour les différentes profondeur est de :"
]
},
2019-05-03 02:25:24 +00:00
{
"cell_type": "code",
2019-05-03 04:11:36 +00:00
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"np.vstack((choix_n_couches,accuracy_cum))"
2019-05-03 02:25:24 +00:00
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Le nombre de couches cachées qui maximise l'accurary est de:"
]
},
{
"cell_type": "code",
2019-05-03 04:11:36 +00:00
"execution_count": null,
"metadata": {},
"outputs": [],
2019-05-03 02:25:24 +00:00
"source": [
"n_couches_optimal1 = choix_n_couches[np.where(accuracy_cum==max(accuracy_cum))[0][0]]\n",
"n_couches_optimal1"
]
},
2019-05-03 04:11:36 +00:00
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Un problème rencontré avec un nombre de couches élevées est appelé le *Vanishing gradient problem*. Dans ces situaitons, 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."
]
},
2019-05-03 02:25:24 +00:00
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Courbes d'apprentissage\n",
"\n",
"Ce graphique présente les courbes d'apprentissage pour chacun des niveaux de profondeur du réseau"
]
},
{
"cell_type": "code",
2019-05-03 04:11:36 +00:00
"execution_count": null,
"metadata": {},
"outputs": [],
2019-05-03 02:25:24 +00:00
"source": [
"plt.subplot(111)\n",
"for i in choix_n_couches:\n",
" plt.plot(range(10),lc_cum[i-1], label=\"%d couches\"%(i,))\n",
"leg = plt.legend(loc='best', ncol=2, mode=\"expand\", shadow=True, fancybox=True)\n",
"leg.get_frame().set_alpha(0.5)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Choix des poids initiaux\n",
2019-05-03 04:11:36 +00:00
"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.\n",
"\n",
"- Réseau initialisé avec les poids à 0 $RN_{0}$"
2019-05-03 02:25:24 +00:00
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
2019-05-03 04:11:36 +00:00
"source": [
2019-05-03 04:36:22 +00:00
"nn1_poidszero = NeuralNet.NeuralNet(\n",
" np.hstack((4,\n",
" np.repeat(n_neurones_optimal1,n_couches_optimal1),\n",
" 3)),\n",
" range(3),\n",
" input_weights=0)\n",
"lc_nn1_poidszero = (\n",
" nn1_poidszero.train(train1, train_labels1, 0.1, 10, verbose=False))"
2019-05-03 04:11:36 +00:00
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- Réseau initialisé avec les poids uniformes $RN_{\\neg{0}}$"
]
2019-05-03 02:25:24 +00:00
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
2019-05-03 04:11:36 +00:00
"source": [
2019-05-03 04:36:22 +00:00
"nn1_poidsunif = NeuralNet.NeuralNet(\n",
" np.hstack((4,\n",
" np.repeat(n_neurones_optimal1,n_couches_optimal1),\n",
" 3)),\n",
" range(3))\n",
2019-05-03 04:11:36 +00:00
"np.random.seed(12345)\n",
2019-05-03 04:36:22 +00:00
"lc_nn1_poidsunif = (\n",
" nn1_poidsunif.train(train1, train_labels1, 0.1, 10, verbose=False))"
2019-05-03 04:11:36 +00:00
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- Graphique des courbes d'apprentissage"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plt.subplot(111)\n",
"plt.plot(range(10),lc_nn1_poidszero, label=\"RN_Zero\")\n",
"plt.plot(range(10),lc_nn1_poidsunif, label=\"RN_Non_Zero)\")\n",
2019-05-03 04:36:22 +00:00
"leg = plt.legend(loc='best', \n",
" ncol=2, \n",
" mode=\"expand\", \n",
" shadow=True, \n",
" fancybox=True)\n",
2019-05-03 04:11:36 +00:00
"leg.get_frame().set_alpha(0.5)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"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."
]
2019-05-03 02:25:24 +00:00
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Entrainement et tests\n",
"On reprend les résultats du dernier entrainement, puisqu'il utilise les poids aléatoires et les hyperparamètres optimaux."
]
},
2019-05-03 04:11:36 +00:00
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"_ = nn1_poidsunif.test(test1, test_labels1)"
]
},
2019-05-03 02:25:24 +00:00
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"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.7.3"
}
},
"nbformat": 4,
"nbformat_minor": 2
}