Cet article commente le tutoriel Tensorflow #1 de Magnus Erik Hvass Pedersen  : Simple Linear Model.

La vidéo du tutoriel est ci-dessous (en anglais).

A moins d’être déjà bien familier avec Tensorflow (Tf) et le Machine Learning (ML), il est peu probable que tout soit très clair pour vous – non pas que ce tutoriel est mauvais (au contraire) mais parce qu’il suppose quelques prérequis apportés ici.

You should be familiar with basic linear algebra, Python and the Jupyter Notebook editor. It also helps if you have a basic understanding of Machine Learning and classification.

Le code du tutoriel est ici (pour Jupyter) . Ce code est commenté dans notre article.

Pour voir la vidéo Youtube, c’est ici

MNIST

MNIST ( Modified ou Mixed National Institute of Standards and Technolog,) est le Hello World du Machine Learning. Il s’agit d’une base de données de chiffres manuscrits qu’il s’agit de reconnaitre.

En 2018, la meilleure performance de reconnaissance  annonce un taux d’erreur de 0,18% (en 2013, c’était 0,21%).

Imports

Si vous lisez régulièrement nos articles, vous savez que l’environnement de développement suppose Anaconda auquel est ajouté Tensorflow.

%matplotlib

%matplotlib is a magic function in IPython. I’ll quote the relevant documentation here for you to read for convenience:

IPython has a set of predefined ‘magic functions’ that you can call with a command line style syntax. There are two kinds of magics, line-oriented and cell-oriented. Line magics are prefixed with the % character and work much like OS command-line calls: they get as an argument the rest of the line, where arguments are passed without parentheses or quotes. Lines magics can return results and can be used in the right hand side of an assignment. Cell magics are prefixed with a double %%, and they are functions that get as an argument not only the rest of the line, but also the lines below it in a separate argument.

%matplotlib inline sets the backend of matplotlib to the ‘inline’ backend:

With this backend, the output of plotting commands is displayed inline within frontends like the Jupyter notebook, directly below the code cell that produced it. The resulting plots will then also be stored in the notebook document.

En clair, avec la magic function %matplotlib, les graphique sont affichés dans Jupyter après l’appel des fonctions.

tf.__version__

La version de Tf utilisée au moment de la rédaction de cet article est la 1.10.0. Au moment de la rédaction de l’article de Magnus, la version était : 1.9.0

Lecture des données

Dans d’autres tutoriels on lit les données MNIST de cette façon :
our avec keras :
Les données lues ont les caractéristiques suivantes :
Les classes sont codées sous 2 formes, en hot encoding et avec un chiffre.

Affichage des images

La fonction plot_images qui permet d’afficher 9 images en même temps n’est pas commentée

Pour afficher une seule image du jeu de données, sans légende, utiliser :

ou

ce qui vous donnera :

Tensorflow

Les avantages de Tf, d’après l’auteur, sont l’existence du graphe (computational graph), le calcul automatique du gradient, la distribution sur CPU/GPU.

Placeholders

Placeholder variables serve as the input to the graph that we may change each time we execute the graph. We call this feeding the placeholder variables and it is demonstrated further below.

La définition du placeholder n’est pas évidente.

So far we have used Variables to manage our data, but there is a more basic structure, the placeholder. A placeholder is simply a variable that we will assign data to at a later date. It allows us to create our operations and build our computation graph, without needing the data. In TensorFlow terminology, we then feed data into the graph through these placeholders.

La différence entre un placeholder et une variable :

Think of Variable in tensorflow as a normal variables which we use in programming languages. We initialize variables, we can modify it later as well. Whereas placeholder doesn’t require initial value. Placeholder simply allocates block of memory for future use. Later, we can use feed_dict to feed the data into placeholder. By default, placeholder has an unconstrained shape, which allows you to feed tensors of different shapes in a session. You can make constrained shape by passing optional argument -shape, as I have done below.

Si cette explication n’est pas satisfaisante pour vous, dites-vous qu’on utilise :

The difference is that with tf.Variable you have to provide an initial value when you declare it. With tf.placeholder you don’t have to provide an initial value and you can specify it at run time with the feed_dict argument inside Session.run

In short, you use tf.Variable for trainable variables such as weights (W) and biases (B) for your model.

Cette explication est plus complète :

Since Tensor computations compose of graphs then it’s better to interpret the two in terms of graphs.

Take for example the simple linear regression WX+B=Y(where W and B stand for the weights and bias and X for the observations’ inputs and Y for the observations’ outputs). Obviously X and Y are of the same nature which differs from that of W and B. X and Y are values of the samples(observations) and hence need a place to be filled, while W and B are the weights and bias, Variables(the previous value affects the later) in the graph which should be trained using different X and Y pairs. We place different samples to the Placeholders to train the Variables.

We can and only need to save or restore the Variables to save or rebuild the graph. Placeholders are mostly holders for the different datasets (for example training data or test data) but Variables are trained in the training process and remain the same(to predict the outcome of the input or map the inputs and outputs[labels] of the samples) later until you retrain the model(using different or the same samples to fill into the Placeholders often through the dict, for instance session.run(a_graph, dict={a_placeholder_name: sample_values}), Placeholders are also passed as parameters to set models).

If you change placeholders(add or delete or change the shape and etc) of a model in the middle of training, you still can reload the checkpoint without any other modifications. But if the variables of a saved model are changed you should adjust the checkpoint accordingly to reload it and continue the training.

To sum up, if the values are from the samples(observations you already have) you safely make a placeholder to hold them, while if you need a parameter to be trained harness a Variable(simply put, set the Variables for the values you want to get using TF automatically).

Ce qui veut dire :

Placeholder :

  1. A placeholder is simply a variable that we will assign data to at a later date. It allows us to create our operations and build our computation graph, without needing the data. In TensorFlow terminology, we then feed data into the graph through these placeholders.
  2. Initial values are not required but can have default values with tf.placeholder_with_default)
  3. We have to provide value at runtime like :

Variable :

  1. A TensorFlow variable is the best way to represent shared, persistent state manipulated by your program.
  2. Variables are manipulated via the tf.Variable class. A tf.Variable represents a tensor whose value can be changed by running ops on it.

Example :

Dans notre code, on définit un palceholder pour les images et d’autres pour les labels (les étiquettes des images), codés en one-hot encoding et en classe numérique.

Variables

Nous sommes dans le cas  WX+B=Y. Nous avons nos placeholders pour X et Y (images et labels). Il nous faut désormais nous intéresser aux poids et aux biais.

Les poids et les biais sont initialisés à 0. Ce sont des variables.

Il y a img_size_flat * num_classes poids, soit 784*10 poids et il y a 10 biais.

Model

Le modèle est classique (et déjà discuté) :  WX+B=Y.

On applique un softmax (voir ici) et on recherche l’index ayant la plus grande valeur (c’est à dire la classe).

Fonction de coût

La fonction de coût retenue est cross entropy tf.nn.softmax_cross_entropy_with_logits_v2

Il n’est pas simple de savoir quelle est la meilleure fonction de coût pour un problème donné. (voir ici).

Pour rappel, une fonction de coût mesure la distance entre la prédiction du modèle et les échantillons d’entraînement.

L’objectif est de minimiser cette fonction de coût.

Optimisation

Une descente de gradient classique. Il faudra essayer avec un autre learning_rate. Jeremy Howard présente dans son cours une façon de trouver le meilleur learning_rate sans avoir à faire manuellement des essais.

Mesure des performances

Les fonctions suivantes ne servent pas directement à calculer les poids/biais du système. Il s’agit seulement de nous aider à analyser plus correctement l’amélioration des performances.

TensorFlow Run

Avec Tf, après que le graphe soit construit, avant l’exécution, on commence par créer une session et initialiser les variables.

On a souvent des hyper-paramètres à définir, ici le batch size.

Optimize

Les données sont transmises au moteur par batch de données prises au hasard.

Accuracy

Pour la mesure de l’exactitude, on utilise les données de test.

Confusion matrix

En Machine Learning, on aime bien les matrices de confusion car elles permettent d’analyser facilement les résultats obtenus.

Images mal classifiées

Une fonction toute simple pour afficher des images mal classifiées

Affichage des poids

Performance avant optimisation

Lorsqu’on mesure l’exactitude des résultats obtenus avant le lancement de l’optimisation, on obtient 9,8% – parce que le logiciel prévoir toujours un 0 (les poids) et qu’il y a 9,8% de 0 dans le test-set !

Performance après 1 optimisation

Après une itération on obtient déjà 40,7% de résultats corrects.

Affichage des poids

Il faut voir l’affichage des poids comme un filtre Les poids positifs sont rouges et les négatifs sont bleus.

Performance après 10 optimisations

10 optimisations c’est 1 déjà faite + 9 autres.

Le résultat progresse :

On a désormais 76,8% de bons résultats.

L’affichage des poids est encore lisible.

Performance après 1000 optimisations

On peut se dire que 91,4% de résultats c’est pas mal.

L’affichage des poids fournit des images de moins en moins compréhensibles.

Matrice de confusion

On constate que le 5 est souvent confondu avec le 3, le 5 et le 8.

Exercices

learning_rate

On nous propose de tester ce qu’apporte un changement de learning rate.

En effet, pourquoi learning_rate=0.5 est-il égal à 0.5 et pas à 0.6 ou 0.1 ?

On constate qu’en mettant learning_rate=0.1, on a le même résultat après 0 optimisation (normal), accuracy = 52,7% après 1 optimisation (au lieu de 40,7%)

accuracy = 75% après 10 optimisations (au lieu de 76,8%)

et accuracy = 91,4% après 1000 optimisations (comme avec lr = 0.5)

Faites l’exercice avec d’autres valeurs de learning_rate. On voit peu de différences.

optimizer

Si on change l’optimizer (au lieu de GradientDescentOptimizer on utilise AdagradOptimizer ou AdamOptimizer

est remplacé par :

après 1 optimisation accuracy = 19,1% (au lieu de 40,7%), après 10 optimisations 77,5% (au lieu de 76,8%) et 91,9% au lieu de 91,4%.

Cet optimizer donne de meilleurs résultats après un nombre élevé d’optimisations (91,9% au lieu de 91,4%).

 

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *