{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# La reconnaissance des chiffres manuscrits MNIST (TensorFlow)\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Description du données Mnist" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "L'ensemble de données MNIST se compose d'un total de 70 000 images ; 60 000 images de formation (utilisés pour créer un modèle IR) et 10 000 images de test (utilisés pour évaluer l'exactitude du modèle). Chaque image MNIST est une image numérisée d'un personnage à un seul chiffre manuscrites. Chaque image est 28 x 28 pixels de taille. Chaque valeur de pixel est entre 0, qui représente le blanc, et 255, ce qui représente le noir. Valeurs des pixels intermédiaires représentent des nuances de gris." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "![title](MNIST.png)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Chargement du jeu de donnée d'Images Mnist" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "C:\\Users\\Chhimy\\Anaconda3\\lib\\site-packages\\h5py\\__init__.py:36: FutureWarning: Conversion of the second argument of issubdtype from `float` to `np.floating` is deprecated. In future, it will be treated as `np.float64 == np.dtype(float).type`.\n", " from ._conv import register_converters as _register_converters\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "WARNING:tensorflow:From :6: read_data_sets (from tensorflow.contrib.learn.python.learn.datasets.mnist) is deprecated and will be removed in a future version.\n", "Instructions for updating:\n", "Please use alternatives such as official/mnist/dataset.py from tensorflow/models.\n", "WARNING:tensorflow:From C:\\Users\\Chhimy\\Anaconda3\\lib\\site-packages\\tensorflow\\contrib\\learn\\python\\learn\\datasets\\mnist.py:260: maybe_download (from tensorflow.contrib.learn.python.learn.datasets.base) is deprecated and will be removed in a future version.\n", "Instructions for updating:\n", "Please write your own downloading logic.\n", "WARNING:tensorflow:From C:\\Users\\Chhimy\\Anaconda3\\lib\\site-packages\\tensorflow\\contrib\\learn\\python\\learn\\datasets\\mnist.py:262: extract_images (from tensorflow.contrib.learn.python.learn.datasets.mnist) is deprecated and will be removed in a future version.\n", "Instructions for updating:\n", "Please use tf.data to implement this functionality.\n", "Extracting yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz\n", "WARNING:tensorflow:From C:\\Users\\Chhimy\\Anaconda3\\lib\\site-packages\\tensorflow\\contrib\\learn\\python\\learn\\datasets\\mnist.py:267: extract_labels (from tensorflow.contrib.learn.python.learn.datasets.mnist) is deprecated and will be removed in a future version.\n", "Instructions for updating:\n", "Please use tf.data to implement this functionality.\n", "Extracting yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz\n", "WARNING:tensorflow:From C:\\Users\\Chhimy\\Anaconda3\\lib\\site-packages\\tensorflow\\contrib\\learn\\python\\learn\\datasets\\mnist.py:110: dense_to_one_hot (from tensorflow.contrib.learn.python.learn.datasets.mnist) is deprecated and will be removed in a future version.\n", "Instructions for updating:\n", "Please use tf.one_hot on tensors.\n", "Extracting yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz\n", "Extracting yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz\n", "WARNING:tensorflow:From C:\\Users\\Chhimy\\Anaconda3\\lib\\site-packages\\tensorflow\\contrib\\learn\\python\\learn\\datasets\\mnist.py:290: DataSet.__init__ (from tensorflow.contrib.learn.python.learn.datasets.mnist) is deprecated and will be removed in a future version.\n", "Instructions for updating:\n", "Please use alternatives such as official/mnist/dataset.py from tensorflow/models.\n" ] } ], "source": [ "import numpy as np\n", "import tensorflow as tf\n", "\n", "from tensorflow.examples.tutorials.mnist import input_data\n", "\n", "mnist=input_data.read_data_sets('yann.lecun.com/exdb/mnist/', one_hot=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# La Configuration des hyperparamètres" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "hidden_layer_size=1000 # la taille de chaque couche caché est de 1000 neurones\n", "input_size=784 # chaque Image est de 28*28=784 pixels c-à-d nous avons 784 entrés\n", "output_size=10 # la sortie est une classe de 10 chiffres de 0 jusqu'à 9\n", "\n", "# La fonction tf.reset_default_graph() permet d'effacer les anciens paramètres. \n", "# A partir de là, une formation complètement nouvelle commence.\n", "tf.reset_default_graph()\n", "\n", "# Déclarer les caractères génériques dans lesquels les données seront introduites.\n", "inputs=tf.placeholder(tf.float32,[None,input_size])\n", "targets=tf.placeholder(tf.float32,[None,output_size])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Introduction du modèle" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "nous allons utiliser trois des couches cachées(hidden layers) pour trainer notre modèle, en effet on a choisi 2 couches mais la précision n'était pas bonne (95%) c'est pour on a augmenté le nombre des couches pour augmenter la précision du modèle." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "![title](réseaux.png)" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "# Poids et biais pour la première combinaison linéaire entre les entrées et la première couche cachée.\n", "# la méthode get_variable pour utiliser l'initialisateur par défaut de TensorFlow qui est Xavier.\n", "weights_1=tf.get_variable(\"weights_1\",[input_size,hidden_layer_size])\n", "biases_1=tf.get_variable(\"biases_1\",[hidden_layer_size])\n", "\n", "# Fonctionnement entre les entrées et la première couche cachée.\n", "# Nous avons choisi ReLu comme fonction d'activation. Vous pouvez essayer de jouer avec différentes non-linéarités.\n", "outputs_1=tf.nn.relu(tf.matmul(inputs,weights_1)+biases_1)\n", "\n", "\n", "# Poids et biais pour la deuxième combinaison linéaire.\n", "# C'est entre la première et la deuxième couche cachée.\n", "weights_2=tf.get_variable(\"weights_2\",[hidden_layer_size,hidden_layer_size])\n", "biases_2=tf.get_variable(\"biases_2\",[hidden_layer_size])\n", "\n", "# Opération entre la première et la deuxième couche cachée. Encore une fois, nous utilisons ReLu.\n", "outputs_2=tf.nn.relu(tf.matmul(outputs_1,weights_2)+biases_2)\n", "\n", "\n", "# N'oubliez pas de changer la forme des poids_3 et des biais_3. \n", "# Ils menaient à la couche de sortie, mais maintenant ils mènent à la troisième couche cachée.\n", "weights_3=tf.get_variable(\"weights_3\",[hidden_layer_size,hidden_layer_size])\n", "biases_3=tf.get_variable(\"biases_3\",[hidden_layer_size])\n", "\n", "# Créer une variable output_3. Je vais utiliser ReLu encore une fois.\n", "outputs_3=tf.nn.sigmoid(tf.matmul(outputs_2,weights_3)+biases_3)\n", "\n", "\n", "# les poids_4 et les biais_4 sont liés directement à les sorties(outputs) de note modèle.\n", "weights_4=tf.get_variable(\"weights_4\",[hidden_layer_size,output_size])\n", "biases_4=tf.get_variable(\"biases_4\",[output_size])\n", "\n", "# Les sorties(outputs) sont fonction des sorties_3, des poids_4 et des biais_4.\n", "outputs = tf.matmul(outputs_3, weights_4) + biases_4\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### the loss function (la fonction de perte)" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "WARNING:tensorflow:From :7: softmax_cross_entropy_with_logits (from tensorflow.python.ops.nn_ops) is deprecated and will be removed in a future version.\n", "Instructions for updating:\n", "\n", "Future major versions of TensorFlow will allow gradients to flow\n", "into the labels input on backprop by default.\n", "\n", "See `tf.nn.softmax_cross_entropy_with_logits_v2`.\n", "\n" ] } ], "source": [ "# Calculer la fonction de perte pour chaque paire sortie(output) / cible(target).\n", "# La fonction utilisée est la même que l'application de softmax à la dernière couche et le calcul de l'entropie croisée.\n", "# avec la fonction que nous avons vu dans les conférences. Cette fonction, cependant, les combine d'une manière intelligente, \n", "# ce qui le rend à la fois plus rapide et plus stable numériquement (lorsqu'il s'agit de très petits nombres).\n", "# Logits signifie ici : probabilités non mises à l'échelle (donc, les sorties, avant qu'elles ne soient mises à l'échelle par le softmax)\n", "# les étiquettes sont les cibles.\n", "loss=tf.nn.softmax_cross_entropy_with_logits(logits=outputs, labels=targets)\n", "\n", "# Obtenir la moyen de perte.\n", "mean_loss=tf.reduce_mean(loss)\n", "\n", "# Définir l'étape d'optimisation. Utilisation d'optimiseurs adaptatifs comme Adam dans TensorFlow.\n", "optimizer=tf.train.AdamOptimizer(learning_rate=0.001).minimize(mean_loss) \n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### La mésure de prècision" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "la précision est le facteur qui détermine la puissance de notre modèle puisque nous allons la calculer sur le jeu de données d'entrainement (Train) et tester sa performance sur le jeu de données de test(Test)." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "# Obtenir un 0 ou un 1 pour chaque entrée du lot en indiquant si la réponse correcte est sortie sur les 10.\n", "out_equals_target=tf.equal(tf.argmax(outputs,1),tf.argmax(targets,1))\n", "\n", "# Obtenir la précision moyenne des sorties.\n", "accuracy=tf.reduce_mean(tf.cast(out_equals_target,tf.float32))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### lancement d'une session" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "pour démarrer le programme." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "# Déclarer la variable de session.\n", "sess=tf.InteractiveSession()\n", "\n", "# Initialiser les variables. L'initialisateur par défaut est Xavier.\n", "initializer=tf.global_variables_initializer()\n", "sess.run(initializer)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# l'entrainement du modèle (Train)" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Epoch1.Training loss0.258.Validation loss0.096.Validation accuracy97.06%\n", "Epoch2.Training loss0.084.Validation loss0.081.Validation accuracy97.76%\n", "Epoch3.Training loss0.051.Validation loss0.069.Validation accuracy97.98%\n", "Epoch4.Training loss0.036.Validation loss0.059.Validation accuracy98.22%\n", "Epoch5.Training loss0.028.Validation loss0.071.Validation accuracy97.88%\n", "end of trainig\n", "Training time: 281.324090719223 seconds\n" ] } ], "source": [ "# la mise en lot de jeu de données d'entrainement(train).\n", "batch_size=200\n", "\n", "# Calculez le nombre de lots par époque pour l'ensemble d'entraînement {(60000/100)=60 batches} .\n", "batches_number= mnist.train._num_examples // batch_size\n", "\n", "# Définir un nombre minimum d'époques à pourcourir avant d'arréter le traitement.\n", "max_epochs=50\n", "\n", "# Gardez la trace de la perte de validation de l'époque précédente.\n", "# Si la perte de validation augmente, nous voulons déclencher un arrêt anticipé.\n", "# Nous l'avons d'abord fixé à un nombre arbitrairement élevé pour nous assurer de ne pas le déclencher.\n", "# à la première époque.\n", "prev_validation_loss= 9999999.\n", "\n", "# importer la classe time pour déterminer le temps d'exécution de l'algorithme\n", "import time\n", "start_time=time.time()\n", "\n", "\n", "# Créez une boucle pour les époques. Epoch_counter est une variable qui part automatiquement de 0.\n", "for epoch_counter in range(max_epochs):\n", " \n", " \n", " # Gardez une trace de la somme des pertes de lots à l'époque.\n", " curr_epoch_loss= 0.\n", " \n", " \n", " # Itérer sur les lots de cette époque.\n", " for batch_counter in range(batches_number):\n", " \n", " \n", " # Le lot d'entrée et le lot cible sont des valeurs assignées à partir de l'ensemble de données du train.\n", " input_batch,target_batch=mnist.train.next_batch(batch_size)\n", " \n", " \n", " # Exécutez l'étape d'optimisation et obtenez la perte moyenne pour ce lot.\n", " # On l'alimente avec les entrées et les cibles qu'on vient d'avoir dans les données du train.\n", " _, batch_loss=sess.run([optimizer,mean_loss],\n", " feed_dict={inputs:input_batch, targets:target_batch}) \n", " \n", " \n", " \n", " # incrémenter la somme des pertes de lots.\n", " curr_epoch_loss+=batch_loss\n", " \n", " \n", " # Jusqu'à présent curr_epoch_loss contenait la somme de tous les lots de l'époque\n", " # Nous voulons trouver la moyenne des pertes de lots sur l'ensemble de l'époque\n", " # La perte moyenne par lot est une bonne approximation de la perte de l'époque actuelle.\n", " curr_epoch_loss /= batches_number\n", " \n", " \n", " # Obtenir le lot d'entrée et le lot cible à partir de l'ensemble de données de validation.\n", " input_batch,target_batch=mnist.validation.next_batch(mnist.validation._num_examples)\n", "\n", " \n", " # Exécuter sans l'étape d'optimisation simplement propager vers l'avant (forward propagation).\n", " # A la fin de chaque époque, obtenez la perte de validation et la précision.\n", " validation_loss,validation_accuracy=sess.run([mean_loss,accuracy], \n", " feed_dict= {inputs: input_batch,\n", " targets: target_batch})\n", " # Imprimer les statistiques pour l'époque actuelle\n", " # Compteur d'époque + 1, car epoch_counter démarre automatiquement à partir de 0, au lieu de 1\n", " # Nous formaterons les pertes avec 3 chiffres après le point\n", " # Nous formaterons l'exactitude en pourcentages pour faciliter l'interprétation.\n", " print('Epoch'+str(epoch_counter+1)+\n", " '.Training loss'+'{0:.3f}'.format(curr_epoch_loss)+\n", " '.Validation loss'+'{0:.3f}'.format(validation_loss)+\n", " '.Validation accuracy'+'{0:.2f}'.format(validation_accuracy*100.)+'%')\n", " \n", " \n", " # Déclenchement de l'arrêt anticipé si la perte de validation commence à augmenter.\n", " if validation_loss > prev_validation_loss:\n", " break\n", " \n", " # Stockez la perte de validation de cette époque pour l'utiliser comme perte de validation précédente lors de la prochaine itération.\n", " prev_validation_loss = validation_loss \n", "\n", "# Pas essentiel, mais c'est bien de savoir quand l'algorithme a cessé de fonctionner dans la section output,\n", "# et savoir le nombre d'époque qu'il a traversé.\n", "print('end of trainig') \n", "\n", "# Le temps de l'entrainement.\n", "print(\"Training time: %s seconds\" % (time.time() - start_time))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Le test de la précision prédictive" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Comme nous en avons discuté dans les exposés, après un apprentissage sur les ensembles de d'entrainement et de validation, nous testons la puissance de prédiction finale de notre modèle en l'exécutant sur l'ensemble de données de test que l'algorithme n'a jamais vu auparavant.\n", "\n", "Il est très important de se rendre compte que le fait de manipuler les hyperparamètres surdimensionne l'ensemble des données de validation. Le test est l'instance finale absolue. Vous ne devez pas tester avant d'avoir terminé d'ajuster votre modèle.\n", "\n" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Test accuracy:98.09%\n" ] } ], "source": [ "# Obtenir le lot d'entrée et le lot cible à partir de l'ensemble de données de test.\n", "input_batch, target_batch = mnist.test.next_batch(mnist.test._num_examples)\n", "test_accuracy = sess.run([accuracy], \n", " feed_dict={inputs: input_batch,\n", " targets: target_batch})\n", "\n", "\n", "# La précision du test est une liste avec 1 valeur, nous voulons donc en extraire la valeur, en utilisant x[0].\n", "test_accuracy_percent=test_accuracy[0]*100.\n", "\n", "\n", "# retourné la précision du test en pourcentages\n", "print('Test accuracy:'+'{0:.2f}'.format(test_accuracy_percent)+'%')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "En utilisant le modèle initial et les hyperparamètres donnés dans ce projet, la précision de l'essai final devrait se situer approximativement entre 97 % et 98 %. Chaque fois que le code est réexécuté, nous obtenons une précision différente car les lots sont mélangés, les poids sont initialisés d'une manière différente, etc.\n", "\n", "Enfin, nous avons délibérément atteint une solution sous-optimale, de sorte que vous pouvez avoir de l'espace pour construire dessus.\n" ] } ], "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.5" } }, "nbformat": 4, "nbformat_minor": 2 }