Vous êtes sur la page 1sur 13

2.

2 Implémenter des MPC avec Keras 65

2.2 IMPLÉMENTER DES MPC AVEC KERAS


Keras est une API de haut niveau pour le Deep Learning. Elle permet de construire,
d’entraîner, d’évaluer et d’exécuter facilement toutes sortes de réseaux de neurones.
Sa documentation (ou spécification) est disponible à l’adresse https://keras.io/.
L’implémentation de référence (https://github.com/keras-team/keras), également
nommée Keras, a été développée par François Chollet dans le cadre d’un projet de
recherche40 et publiée en tant que projet open source en mars 2015. Elle est rapi-
dement devenue populaire, en raison de sa facilité d’utilisation, de sa souplesse et
de sa belle conception. Pour effectuer les lourds calculs imposés par les réseaux de
neurones, cette implémentation de référence se fonde sur un backend de calcul.

218
Pour le moment, nous avons le choix entre trois bibliothèques open source de Deep
Learning répandues : TensorFlow, Microsoft Cognitive Toolkit (CNTK) et Theano.

2585
Afin d’éviter toute confusion, nous désignerons cette implémentation de référence
sous le terme Keras multibackend.

:168
Depuis la fin 2016, d’autres implémentations sont apparues. Nous pouvons à pré-

8.10
sent exécuter Keras sur Apache MXNet, Core ML d’Apple, Javascript ou Typescript
(pour exécuter du code Keras dans un navigateur web) et PlaidML (qui peut fonc-

52.4
tionner sur toutes sortes de cartes graphiques, pas uniquement celles de Nvidia).
TensorFlow fournit sa propre implémentation de Keras, tf.keras. Dans ce cas, le seul
193.
backend pris en charge est TensorFlow, mais elle a l’avantage d’offrir des possibilités
supplémentaires très utiles (voir la figure 2.10). Par exemple, elle reconnaît l’API
681:

Data de TensorFlow, ce qui permet de charger et de prétraiter efficacement des don-


nées. Voilà pourquoi nous utilisons tf.keras dans cet ouvrage. Cependant, dans ce
8902

chapitre, nous n’utiliserons aucune des caractéristiques spécifiques à TensorFlow. Le


code devrait donc être pleinement compatible avec d’autres implémentations de
51:8

Keras (tout au moins dans Python), avec seulement quelques changements mineurs,
comme la modification des importations.
9533

Votre code Votre code


2110

API K eras API K eras Fonctionnalités


Sud:

propres à TF
Keras
© Dunod – Toute reproduction non autorisée est un délit.

multibackend tf. keras


gne
Breta
e

Figure 2.10 – Deux implémentations de l’API Keras : Keras multibackend (à gauche)


sité d

et tf.keras (à droite)
niver

Après Keras et TensorFlow, la bibliothèque de Deep Learning la plus populaire


est PyTorch de Facebook (https://pytorch.org/). Elle est assez semblable à Keras (en
om:U
c

40. Projet ONEIROS (Open-ended Neuro-Electronic Intelligent Robot Operating System).


rvox.
la
scho
66 Chapitre 2. Introduction aux réseaux de neurones artificiels avec Keras

partie parce que ces deux API se sont inspirées de Scikit-Learn et de Chainer, https://
chainer.org/) et, si vous maîtrisez Keras, vous n’aurez pas de difficultés à basculer sur
PyTorch en cas de besoin. La popularité de PyTorch a considérablement augmenté
en 2018, essentiellement grâce à sa simplicité et à son excellente documentation, ce
qui n’était pas véritablement les points forts de TensorFlow 1.x. Toutefois, certains
estiment que TensorFlow 2 est aussi simple que PyTorch, puisque Keras est devenue
son API de haut niveau officielle et que le reste de l’API a également été largement
simplifié et nettoyé. La documentation a également été totalement réorganisée et il
est beaucoup plus facile d’y trouver ce que l’on cherche. De façon comparable, les
principales faiblesses de PyTorch (par exemple une portabilité limitée et aucune ana-
lyse du graphe de calcul) ont été grandement comblées dans PyTorch 1.0. Une saine

218
compétition est bénéfique pour tout le monde.
À présent, du code ! Puisque tf.keras vient avec TensorFlow, commençons par

2585
installer ce dernier.

:168
2.2.1 Installer TensorFlow 2

8.10
Si vous avez bien suivi les instructions d’installation du chapitre 1, TensorFlow est
déjà installé sur votre ordinateur. Pour tester votre installation, ouvrez un terminal,

52.4
activez l’environnement conda tf2, démarrez un shell Python, importez tensorflow
et keras, et affichez leurs versions : 193.
$ conda activate tf2
$ python
681:

>>> import tensorflow as tf


>>> from tensorflow import keras
8902

>>> tf.__version__
'2.1.0'
51:8

>>> keras.__version__
'2.2.4-tf'
9533

La deuxième version est celle de l’API Keras mise en œuvre par tf.keras. Vous
remarquerez qu’elle se termine par -tf, ce qui indique que tf.keras implémente non
2110

seulement l’API Keras, mais également quelques fonctionnalités supplémentaires


propres à TensorFlow.
Sud:

Si vous disposez d’une carte graphique (GPU) compatible avec TensorFlow et


que vous avez installé son pilote, alors vous pouvez vérifier que votre GPU est bien
gne

détecté :
Breta

>>> tf.test.is_gpu_available()
True

Commençons à utiliser tf.keras, en construisant un classificateur d’images simple.


e
sité d

2.2.2 Construire un classificateur d’images avec l’API Sequential


niver

Nous devons tout d’abord charger un jeu de données. Nous choisissons Fashion MNIST,
qui est un équivalent exact de MNIST41. Leur format est identique (70 000 images en
om:U
c

41. Voir le chapitre 3 de l’ouvrage Machine Learning avec Scikit-Learn, A. Géron, Dunod (2e édition, 2019).
rvox.
la
scho
2.2 Implémenter des MPC avec Keras 67

niveaux de gris de 28×28 pixels chacune, avec 10 classes), mais les images de Fashion
MNIST représentent des articles de mode à la place de chiffres manuscrits. Chaque
classe est donc plus variée et le problème se révèle plus compliqué. Par exemple, un
modèle linéaire simple donne une précision de 92 % avec MNIST, mais seulement
de 83 % avec Fashion MNIST.

Charger le jeu de données avec Keras


Keras dispose de fonctions utilitaires pour récupérer et charger des jeux de don-
nées communs, comme MNIST, Fashion MNIST et le jeu de données California
Housing42. Chargeons Fashion MNIST :
fashion_mnist = keras.datasets.fashion_mnist

218
(X_train_full, y_train_full), (X_test, y_test) = fashion_mnist.load_data()

2585
Le chargement de MNIST ou de Fashion MNIST avec Keras, à la place de
Scikit-Learn, présente une différence importante : chaque image est représentée

:168
non pas sous forme d’un tableau à une dimension de 784 éléments, mais sous
forme d’un tableau 28×28. Par ailleurs, les intensités des pixels sont représentées

8.10
par des entiers (de 0 à 255) plutôt que par des nombres à virgule flottante (de 0,0
à 255,0). Jetons un coup d’œil à la forme et au type de données du jeu d’entraî-

52.4
nement :
>>> X_train_full.shape
193.
(60000, 28, 28)
>>> X_train_full.dtype
681:

dtype('uint8)

Notez que le jeu de données est déjà divisé en un jeu d’entraînement et un


8902

jeu de test, mais qu’il n’y a pas de jeu de validation. Nous allons donc en créer
un. De plus, puisque nous allons entraîner le réseau de neurones avec la descente
51:8

de gradient, nous devons mettre à l’échelle les caractéristiques d’entrée. Pour


9533

une question de simplicité, nous allons réduire les intensités de pixels à la plage
0‑1 en les divisant par 255,0 (cela les convertit également en nombres à virgule
2110

flottante) :
X_valid, X_train = X_train_full[:5000] / 255.0, X_train_full[5000:] / 255.0
Sud:

y_valid, y_train = y_train_full[:5000], y_train_full[5000:]


© Dunod – Toute reproduction non autorisée est un délit.

Avec MNIST, lorsque l’étiquette est égale à 5, cela signifie que l’image représente
gne

le chiffre manuscrit 5. Facile. En revanche, avec Fashion MNIST, nous avons besoin
de la liste des noms de classes pour savoir ce que nous manipulons :
Breta

class_names = ["T-shirt/top", "Trouser", "Pullover", "Dress", "Coat",


"Sandal", "Shirt", "Sneaker", "Bag", "Ankle boot"]
e

Par exemple, la première image du jeu d’entraînement représente un manteau :


sité d

>>> class_names[y_train[0]]
'Coat'
niver
om:U

42. Ce jeu de données, aussi utilisé dans l’ouvrage Machine Learning avec Scikit-Learn, A. Géron, Dunod
(2e édition, 2019), a été originellement présenté par R. Kelley Pace et Ronald Barry (1997), dans « Sparse
c

Spatial Autoregressions », Statistics and Probability Letters, 33, n° 3, 291‑297.


rvox.
la
scho
68 Chapitre 2. Introduction aux réseaux de neurones artificiels avec Keras

La figure 2.11 montre quelques éléments du jeu de données Fashion MNIST.

218
2585
:168
Figure 2.11 – Quelques exemples tirés de Fashion MNIST

8.10
Créer le modèle en utilisant l’API Sequential

52.4
Construisons à présent le réseau de neurones ! Voici un MPC de classification avec
deux couches cachées : 193.
model = keras.models.Sequential()
model.add(keras.layers.Flatten(input_shape=[28, 28]))
681:

model.add(keras.layers.Dense(300, activation="relu"))
model.add(keras.layers.Dense(100, activation="relu"))
8902

model.add(keras.layers.Dense(10, activation="softmax"))

Détaillons ce code :
51:8

• La première ligne crée un modèle Sequential. C’est le modèle Keras le plus


simple pour les réseaux de neurones : il est constitué d’une seule pile de couches
9533

connectées de façon séquentielle. Il s’agit de l’API Sequential.


• Ensuite, nous construisons la première couche et l’ajoutons au modèle. Il s’agit
2110

d’une couche Flatten dont le rôle est de convertir chaque image d’entrée en
un tableau à une dimension : si elle reçoit une donnée d’entrée X, elle calcule
Sud:

X.reshape(-1, 1). Cette couche ne prend aucun paramètre et a pour


seule fonction d’effectuer un prétraitement simple. Puisqu’elle est la première
gne

couche du modèle, nous devons préciser le input_shape, qui n’inclut pas


Breta

la taille du lot, seulement la forme des instances. Il serait également possible


d’ajouter en première couche un keras.layers.InputLayer, en
précisant input_shape=[28,28].
e
sité d

• Puis, nous ajoutons une couche cachée Dense constituée de 300 neurones.
Elle utilise la fonction d’activation ReLU. Chaque couche Dense gère sa
niver

propre matrice de poids, qui contient tous les poids des connexions entre les
neurones et leurs entrées. Elle gère également un vecteur de termes constants
om:U

(un par neurone). Lorsqu’elle reçoit des données d’entrée, elle calcule
l’équation 2.2.
c
rvox.
la
scho
2.2 Implémenter des MPC avec Keras 69

• Une deuxième couche cachée Dense de 100 neurones est ensuite ajoutée, elle
aussi avec la fonction d’activation ReLU.
• Enfin, nous ajoutons une couche de sortie Dense avec 10 neurones (un
par classe) en utilisant la fonction d’activation softmax (car les classes sont
exclusives).

Spécifier activation="relu" équivaut à spécifier activation=


keras.activations.relu. D’autres fonctions d’activation sont dis-
ponibles dans le package keras.activations et nous en utilisons plu-
sieurs dans cet ouvrage. La liste complète est disponible à l’adresse https://
keras.io/activations/.

218
Au lieu d’ajouter les couches une par une comme nous l’avons fait, nous pouvons
passer une liste de couches au moment de la création du modèle Sequential :

2585
model = keras.models.Sequential([
keras.layers.Flatten(input_shape=[28, 28]),

:168
keras.layers.Dense(300, activation="relu"),
keras.layers.Dense(100, activation="relu"),

8.10
keras.layers.Dense(10, activation="softmax")
])

52.4
193.
Utiliser les exemples de code provenant de keras.io
Les exemples de code documentés sur keras.io fonctionneront parfaitement avec
681:

tf.keras, mais il vous faudra modifier des importations. Examinons, par exemple, le
code keras.io suivant :
8902

from keras.layers import Dense


output_layer = Dense(10)
51:8

Voici comment modifier l’importation :


from tensorflow.keras.layers import Dense
9533

output_layer = Dense(10)
Ou, si vous le préférez, utilisez simplement des chemins complets :
2110

from tensorflow import keras


output_layer = keras.layers.Dense(10)
Sud:

Même si cette solution est plus verbeuse, nous l’avons retenue dans cet ouvrage
© Dunod – Toute reproduction non autorisée est un délit.

car elle permet de voir plus facilement les packages à employer et d’éviter toute
gne

confusion entre les classes standard et les classes personnalisées. Dans un code de
production, nous préférons l’approche précédente. Nombreux sont également ceux
Breta

à utiliser from tensorflow.keras import layers suivi de layers.


Dense(10).
e
sité d

La méthode summary() du modèle affiche toutes les couches du modèle43, y


compris leur nom (généré automatiquement, sauf s’il est précisé au moment de la
niver

création de la couche), la forme de leur sortie (None signifie que la taille du lot peut
être quelconque) et leur nombre de paramètres. Le résumé se termine par le nombre
om:U
c

43. Vous pouvez utiliser keras.utils.plot_model() pour générer une image du modèle.
rvox.
la
scho
70 Chapitre 2. Introduction aux réseaux de neurones artificiels avec Keras

total de paramètres, qu’ils soient entraînables ou non. Dans notre exemple, nous
avons uniquement des paramètres entraînables (nous verrons des exemples de para-
mètres non entraînables au chapitre 3) :
>>> model.summary()
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
flatten (Flatten) (None, 784) 0
_________________________________________________________________
dense (Dense) (None, 300) 235500
_________________________________________________________________

218
dense_1 (Dense) (None, 100) 30100
_________________________________________________________________

2585
dense_2 (Dense) (None, 10) 1010
=================================================================
Total params: 266,610

:168
Trainable params: 266,610
Non-trainable params: 0

8.10
_________________________________________________________________

Les couches Dense possèdent souvent un grand nombre de paramètres. Par


52.4
exemple, la première couche cachée a 784 × 300 poids de connexions et 300 termes
193.
constants. Au total, cela fait 235 500 paramètres ! Le modèle dispose ainsi d’une
grande souplesse d’ajustement aux données d’entraînement, mais le risque de surajus-
681:

tement est accru, en particulier lorsque les données d’entraînement sont peu nom-
breuses. Nous y reviendrons ultérieurement.
8902

Nous pouvons aisément obtenir une liste des couches du modèle, pour ensuite
retrouver une couche par son indice ou son nom :
51:8

>>> model.layers
9533

[<tensorflow.python.keras.layers.core.Flatten at 0x132414e48>,
<tensorflow.python.keras.layers.core.Dense at 0x1324149b0>,
<tensorflow.python.keras.layers.core.Dense at 0x1356ba8d0>,
2110

<tensorflow.python.keras.layers.core.Dense at 0x13240d240>]
>>> hidden1 = model.layers[1]
Sud:

>>> hidden1.name
'dense'
>>> model.get_layer('dense') is hidden1
gne

True
Breta

Tous les paramètres d’une couche sont accessibles à l’aide des méthodes get_
weights() et set_weights(). Dans le cas d’une couche Dense, cela ­comprend
à la fois les poids des connexions et les termes constants :
e
sité d

>>> weights, biases = hidden1.get_weights()


>>> weights
niver

array([[ 0.02448617, -0.00877795, -0.02189048, ..., -0.02766046,


0.03859074, -0.06889391],
...,
om:U

[-0.06022581, 0.01577859, -0.02585464, ..., -0.00527829,


0.00272203, -0.06793761]], dtype=float32)
c

>>> weights.shape
rvox.
la
scho
2.2 Implémenter des MPC avec Keras 71

(784, 300)
>>> biases
array([0., 0., 0., 0., 0., 0., 0., 0., 0., ..., 0., 0., 0.], dtype=float32)
>>> biases.shape
(300,)

La couche Dense initialise les poids des connexions de façon aléatoire (indispen-
sable pour briser la symétrie, comme nous l’avons expliqué) et les termes constants à
zéro, ce qui convient parfaitement. Pour employer une méthode d’initialisation diffé-
rente, il suffit de fixer kernel_initializer (kernel, ou noyau, est un autre nom
pour la matrice des poids des connexions) ou bias_initializer au moment de
la création de la couche. Nous reviendrons sur les initialiseurs au chapitre 3, mais
vous en trouverez la liste complète à l’adresse https://keras.io/initializers/.

218
La forme de la matrice des poids dépend du nombre d’entrées. C’est pour-

2585
quoi il est conseillé de préciser le input_shape lors de la création de la
première couche dans un modèle Sequential. Vous pouvez très bien ne

:168
pas le faire, auquel cas Keras attendra simplement de connaître la forme de
l’entrée pour construire réellement le modèle. Cela se produira lorsque vous

8.10
lui fournirez des données réelles (par exemple, au cours de l’entraînement)
ou lorsque vous appellerez sa méthode build(). Tant que le modèle n’est

52.4
pas véritablement construit, les couches n’auront aucun poids et certaines
opérations ne seront pas possibles (comme sauvegarder le modèle ou affi-
193.
cher son résumé). Par conséquent, si vous connaissez la forme de l’entrée
au moment de la création du modèle, il est préférable de l’indiquer.
681:

Compiler le modèle
8902

Après qu’un modèle a été créé, nous devons invoquer sa méthode compile() de
manière à préciser la fonction de perte et l’optimiseur. Nous pouvons également indi-
51:8

quer une liste d’indicateurs supplémentaires qui seront mesurés au cours de l’entraî-
nement et de l’évaluation :
9533

model.compile(loss="sparse_categorical_crossentropy",
optimizer="sgd",
2110

metrics=["accuracy"])
Sud:

Utiliser loss="sparse_categorical_crossentropy" équi-


© Dunod – Toute reproduction non autorisée est un délit.

vaut à utiliser loss=keras.losses.sparse_categorical_­


gne

crossentropy. De même, spécifier optimizer="sgd" équi-


vaut à spécifier optimizer=keras.optimizers.SGD(), et
Breta

­metrics=["accuracy"] est équivalent à metrics=[keras.


­metrics.sparse_categorical_accuracy] (lorsque cette fonc-
tion de perte est employée). Nous utiliserons beaucoup d’autres fonctions
e
sité d

de perte, optimiseurs et indicateurs dans cet ouvrage. Vous en trouverez


les listes complètes aux adresses https://keras.io/losses/, https://keras.io/
optimizers/ et https://keras.io/metrics/.
niver

Ce code mérite quelques explications. Tout d’abord, nous utilisons la perte


om:U

"sparse_categorical_crossentropy" car nous avons des étiquettes clair-


semées (pour chaque instance, il n’existe qu’un seul indice de classe cible, de 0 à 9
c

dans ce cas) et les classes sont exclusives. Si, à la place, nous avions une probabilité
rvox.
la
scho
72 Chapitre 2. Introduction aux réseaux de neurones artificiels avec Keras

cible par classe pour chaque instance (comme des vecteurs one-hot, par exemple [0.,
0., 0., 1., 0., 0., 0., 0., 0., 0.] pour représenter une classe 3),
nous opterions pour la fonction de perte "categorical_crossentropy". Si
nous réalisions une classification binaire (avec une ou plusieurs étiquettes binaires),
nous choisirions alors la fonction d’activation "sigmoid" (c’est-à-dire logistique)
dans la couche de sortie à la place de la fonction d’activation "softmax", ainsi que
la fonction de perte "binary_crossentropy".

Pour convertir des étiquettes clairsemées (c’est-à-dire des indices de


classes) en étiquettes de vecteurs one-hot, servez-vous de la fonction
­keras.utils.to_categorical(). La fonction np.argmax(), avec
axis=1, effectue l’opération inverse.

218
2585
Quant à l’optimiseur, "sgd" signifie que nous entraînerons le modèle à l’aide
d’une descente de gradient stochastique simple. Autrement dit, Keras mettra en

:168
œuvre l’algorithme de rétropropagation décrit précédemment (c’est-à-dire une dif-
férentiation automatique en mode inverse plus une descente de gradient). Nous

8.10
verrons des optimiseurs plus efficaces au chapitre 3 (ils améliorent la descente de

52.4
gradient, non la différentiation automatique).
193.
Lorsqu’on utilise l’optimiseur SGD, le réglage du taux d’apprentissage est im-
portant. Par conséquent, pour fixer le taux d’apprentissage, nous utiliserons
681:

généralement optimizer=keras.optimizers.SGD(lr=???) plu-


tôt que optimizer="sgd", qui prend par défaut lr=0.01.
8902

Enfin, puisqu’il s’agit d’un classificateur, il est utile de mesurer sa précision


51:8

("accuracy") pendant un entraînement et une évaluation.


9533

Entraîner et évaluer le modèle


Le modèle est maintenant prêt pour l’entraînement. Pour cela, nous devons simple-
2110

ment appeler sa méthode fit() :


>>> history = model.fit(X_train, y_train, epochs=30,
Sud:

... validation_data=(X_valid, y_valid))


...
gne

Train on 55000 samples, validate on 5000 samples


Epoch 1/30
Breta

55000/55000 [======] - 3s 49us/sample - loss: 0.7218 - accuracy: 0.7660


- val_loss: 0.4973 - val_accuracy:
0.8366
e

Epoch 2/30
sité d

55000/55000 [======] - 2s 45us/sample - loss: 0.4840 - accuracy: 0.8327


- val_loss: 0.4456 - val_accuracy:
niver

0.8480
[...]
Epoch 30/30
om:U

55000/55000 [======] - 3s 53us/sample - loss: 0.2252 - accuracy: 0.9192


- val_loss: 0.2999 - val_accuracy:
c

0.8926
rvox.
la
scho
2.2 Implémenter des MPC avec Keras 73

Nous lui fournissons les caractéristiques d’entrée (X_train) et les classes cibles
(y_train), ainsi que le nombre d’époques d’entraînement (dans le cas contraire,
il n’y en aurait qu’une, ce qui serait clairement insuffisant pour converger vers une
bonne solution). Nous passons également un jeu de validation (facultatif). Keras
mesurera la perte et les indicateurs supplémentaires sur ce jeu à la fin de chaque
époque, ce qui se révélera très utile pour déterminer les performances réelles du
modèle. Si les performances sur le jeu d’entraînement sont bien meilleures que sur le
jeu de validation, il est probable que le modèle surajuste le jeu d’entraînement (ou
qu’il y ait une erreur, comme une différence entre les données du jeu d’entraînement
et celles du jeu de validation).
Et voilà, le réseau de neurones est entraîné44. Au cours de chaque époque de l’en-

218
traînement, Keras affiche le nombre d’instances traitées (ainsi qu’une barre de pro-
gression), le temps moyen d’entraînement par échantillon, ainsi que la perte et la

2585
précision (ou tout autre indicateur supplémentaire demandé) à la fois sur le jeu d’en-
traînement et sur celui de validation. Vous constatez que la perte dans l’entraînement

:168
a diminué, ce qui est bon signe, et que la précision de la validation a atteint 89,26 %

8.10
après 30 époques, ce qui n’est pas très loin de la précision de l’entraînement. Nous
pouvons donc en conclure que s’il y a surajustement, il n’est pas trop important.

52.4
Au lieu de passer un jeu de validation avec l’argument validation_
193.
data, vous pouvez indiquer dans validation_split la portion du
jeu d’entraînement que Keras doit utiliser pour la validation. Par exemple,
681:

validation_split=0.1 lui demande d’utiliser les derniers 10 % des


données (avant mélange) pour la validation.
8902

Si le jeu d’entraînement est assez inégal, avec certaines classes surreprésentées et


d’autres sous-représentées, il peut être utile de définir l’argument class_weight
51:8

lors de l’appel à la méthode fit() afin de donner un poids plus important aux
classes sous-représentées et un poids plus faible à celle surreprésentées. Ils seront uti-
9533

lisés par Keras dans le calcul de la perte. Si des poids sont nécessaires pour chaque
instance, nous pouvons utiliser l’argument sample_weight (si class_weight
2110

et sample_weight sont tous deux précisés, Keras les multiplie). Les poids par ins-
tance peuvent être utiles lorsque certaines instances ont été libellées par des experts
Sud:

tandis que d’autres l’ont été au travers d’une collaboration participative : les pre-
© Dunod – Toute reproduction non autorisée est un délit.

mières peuvent avoir un poids plus important. Nous pouvons également fournir des
gne

poids d’instance (mais pas de classe) pour le jeu de validation en les ajoutant en
Breta

troisième élément du paramètre validation_data.


e
sité d

44. Si les données d’entraînement ou de validation n’ont pas la forme attendue, une exception est générée.
Cette erreur étant probablement la plus fréquente, vous devez vous familiariser avec le message d’erreur. Il
niver

est relativement clair. Par exemple, si vous tentez d’entraîner ce modèle avec un tableau qui contient des
images applaties (X_train.reshape(-1, 784)), vous recevez l’exception suivante : « ValueError:
om:U

Error when checking input: expected flatten_input to have 3 dimensions, but got array with shape (60000,
784) ». Le message explique que flatten_input doit avoir trois dimensions alors que l’entrée fournie
c

est un tableau de format (60000, 784).


rvox.
la
scho
74 Chapitre 2. Introduction aux réseaux de neurones artificiels avec Keras

La méthode fit() retourne un objet History qui contient les paramètres


d’entraînement (history.params), la liste des époques effectuées (history.
epoch) et, le plus important, un dictionnaire (history.history) donnant la
perte et les indicateurs supplémentaires mesurés à la fin de chaque époque sur le jeu
d’entraînement et le jeu de validation (si présent). En utilisant ce dictionnaire pour
créer un DataFrame pandas et en invoquant sa méthode plot(), nous obtenons les
courbes d’apprentissage illustrées à la figure 2.12 :
import pandas as pd
import matplotlib.pyplot as plt

pd.DataFrame(history.history).plot(figsize=(8, 5))
plt.grid(True)

218
plt.gca().set_ylim(0, 1) # Régler la plage verticale sur [0‑1]
plt.show()

2585
1,0

:168
4

8.10
0,8

52.4
2
193.
0,6
1
681:

3
0,4
8902
51:8

0,2
9533
2110

0,0
0 5 10 15 20 25
Sud:

Figure 2.12 – Courbes d’apprentissage : la perte (1) et la précision (2)


d’entraînement moyennes mesurées sur chaque époque, ainsi que la perte (3)
gne

et la précision (4) de validation moyennes mesurées à la fin de chaque époque


Breta

La précision d’entraînement et celle de validation augmentent toutes deux régu-


lièrement au cours de l’entraînement, tandis que les pertes d’entraînement et de
e
sité d

validation décroissent. Parfait ! Par ailleurs, les courbes de validation sont proches
des courbes d’entraînement, ce qui signifie que le surentraînement n’est pas très
niver

important. Dans ce cas particulier, le modèle semble présenter de meilleures perfor-


mances sur le jeu de validation que sur le jeu d’entraînement en début d’entraîne-
om:U

ment. Mais ce n’est pas le cas : l’erreur de validation est calculée à la fin de chaque
époque, tandis que l’erreur d’entraînement est calculée à l’aide d’une moyenne glis-
c

sante pendant chaque époque. La courbe d’entraînement doit donc être décalée d’une
rvox.
la
scho
2.2 Implémenter des MPC avec Keras 75

moitié d’époque vers la gauche. Avec ce décalage, nous constatons que les courbes
d’entraînement et de validation se chevauchent presque parfaitement au début de
l’entraînement.

Lors de son affichage, la courbe d’entraînement doit être décalée d’une


moitié d’époque vers la gauche.

Les performances du jeu d’entraînement finissent par dépasser celles du jeu de


validation, comme c’est généralement le cas lorsque l’entraînement est suffisamment

218
long. Nous pouvons voir que le modèle n’a pas encore assez convergé, car la perte
de validation continue à diminuer. Il serait donc préférable de poursuivre l’entraî-

2585
nement. Il suffit d’invoquer une nouvelle fois la méthode fit(), car Keras reprend
l’entraînement là où il s’était arrêté (une précision de validation proche de 89 %

:168
devrait pouvoir être atteinte).

8.10
Si vous n’êtes pas satisfait des performances de votre modèle, revenez en arrière
et ajustez les hyperparamètres. Le premier à examiner est le taux d’apprentissage. Si

52.4
cela ne change rien, essayez un autre optimiseur (réajustez toujours le taux d’appren-
tissage après chaque changement d’un hyperparamètre). Si les performances sont 193.
toujours mauvaises, essayez d’ajuster les hyperparamètres du modèle, par exemple le
nombre de couches, le nombre de neurones par couche et le type des fonctions d’ac-
681:

tivation attribuées à chaque couche cachée. Vous pouvez également affiner d’autres
hyperparamètres, comme la taille du lot (fixée dans la méthode fit() à l’aide de
8902

l’argument batch_size, dont la valeur par défaut est 32). Nous reviendrons sur
le réglage des hyperparamètres à la fin de ce chapitre. Dès que vous êtes satisfait
51:8

de la précision de validation de votre modèle, vous devez, avant de le mettre en


production, l’évaluer sur le jeu de test afin d’estimer l’erreur de généralisation. Pour
9533

cela, il suffit d’utiliser la méthode evaluate() (elle reconnaît plusieurs autres


arguments, comme batch_size et sample_weight ; voir sa documentation
2110

pour plus de détails) :


Sud:

>>> model.evaluate(X_test, y_test)


10000/10000 [==========] - 0s 29us/sample - loss: 0.3340 - accuracy: 0.8851
© Dunod – Toute reproduction non autorisée est un délit.

[0.3339798209667206, 0.8851]
gne

Il est fréquent d’obtenir des performances légèrement moins bonnes sur le jeu
Breta

de test que sur le jeu de validation45. En effet, les hyperparamètres sont ajustés non
pas sur le jeu de test mais sur le jeu de validation (cependant, dans cet exemple,
puisque les hyperparamètres n’ont pas été affinés, la précision inférieure est juste
e
sité d

due au manque de chance). Résistez à la tentation d’ajuster les hyperparamètres


sur le jeu de test car votre estimation de l’erreur de généralisation sera alors trop
optimiste.
niver
om:U
c

45. Voir le chapitre 2 de l’ouvrage Machine Learning avec Scikit-Learn, A. Géron, Dunod (2e édition, 2019).
rvox.
la
scho
76 Chapitre 2. Introduction aux réseaux de neurones artificiels avec Keras

Utiliser le modèle pour faire des prédictions


Nous pouvons ensuite utiliser la méthode predict() pour effectuer des prédic-
tions sur de nouvelles instances. Puisque nous n’avons pas de véritables nouvelles
instances, nous utilisons simplement les trois premières du jeu de test :
>>> X_new = X_test[:3]
>>> y_proba = model.predict(X_new)
>>> y_proba.round(2)
array([[0. , 0. , 0. , 0. , 0. , 0.03, 0. , 0.01, 0. , 0.96],
[0. , 0. , 0.98, 0. , 0.02, 0. , 0. , 0. , 0. , 0. ],
[0. , 1. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. ]],
dtype=float32)

Pour chaque instance, le modèle estime une probabilité par classe, de la classe 0

218
à la classe 9. Par exemple, pour la première image, il estime que la probabilité de

2585
la classe 9 (bottine) est de 96 %, que celle de la classe 5 (sandale) est de 3 %, que
celle de la classe 7 (basket) est de 1 %, et que celles des autres classes sont négli-

:168
geables. Autrement dit, il « croit » que la première image est une chaussure, pro-
bablement une bottine, mais éventuellement une sandale ou une basket. Si nous

8.10
nous intéressons uniquement à la classe dont la probabilité estimée est la plus élevée
(même si celle-ci est relativement faible), nous pouvons utiliser à la place la méthode

52.4
­predict_classes() : 193.
>>> y_pred = model.predict_classes(X_new)
>>> y_pred
681:

array([9, 2, 1])
>>> np.array(class_names)[y_pred]
array(['Ankle boot', 'Pullover', 'Trouser'], dtype='<U11')
8902

Le classificateur réalise une classification correcte des trois images (elles sont
51:8

représentées à la figure 2.13) :


>>> y_new = y_test[:3]
9533

>>> y_new
array([9, 2, 1])
2110
Sud:
gne
Breta
e
sité d
niver

Figure 2.13 – Classification correcte d’images du jeu Fashion MNIST


om:U

Vous savez à présent utiliser l’API Sequential pour construire, entraîner, évaluer et
c

utiliser un MPC de classification. Mais qu’en est-il de la régression ?


rvox.
la
scho
2.2 Implémenter des MPC avec Keras 77

2.2.3 Construire un MPC de régression avec l’API Sequential


Passons au problème de logement en Californie et abordons-le en utilisant un réseau
de neurones de régression. Pour une question de simplicité, nous chargerons les
données avec la fonction fetch_california_housing() de Scikit-Learn46.
Après que les données ont été chargées, nous les répartissons en jeux d’entraînement,
de validation et de test, et nous dimensionnons toutes les caractéristiques :
from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler

housing = fetch_california_housing()

218
X_train_full, X_test, y_train_full, y_test = train_test_split(

2585
housing.data, housing.target)
X_train, X_valid, y_train, y_valid = train_test_split(
X_train_full, y_train_full)

:168
scaler = StandardScaler()

8.10
X_train = scaler.fit_transform(X_train)
X_valid = scaler.transform(X_valid)

52.4
X_test = scaler.transform(X_test)

Avec l’API Sequential, la méthode de construction, d’entraînement, d’évalua-


193.
tion et d’utilisation d’un MPC de régression de façon à effectuer des prédictions est
681:

­comparable à celle employée dans le cas de la classification. Les principales différences


résident dans le fait que la couche de sortie comprend un seul neurone (puisque nous
8902

voulons prédire une seule valeur) et aucune fonction d’activation, et que la fonction
de perte est l’erreur quadratique moyenne. Puisque le jeu de données contient beau-
51:8

coup de bruit, nous utilisons simplement une seule couche cachée avec moins de
neurones que précédemment. Cela permet d’éviter le surajustement :
9533

model = keras.models.Sequential([
keras.layers.Dense(30, activation="relu", input_shape=X_train.shape[1:]),
2110

keras.layers.Dense(1)
])
model.compile(loss="mean_squared_error", optimizer="sgd")
Sud:

history = model.fit(X_train, y_train, epochs=20,


© Dunod – Toute reproduction non autorisée est un délit.

validation_data=(X_valid, y_valid))
gne

mse_test = model.evaluate(X_test, y_test)


X_new = X_test[:3] # Prétendre qu’il s’agit de nouvelles instances
Breta

y_pred = model.predict(X_new)

Vous le constatez, l’utilisation de l’API Sequential n’a rien de compliqué.


e

Cependant, bien que les modèles séquentiels soient extrêmement courants, il est
sité d

parfois utile de construire des réseaux de neurones à la topologie plus complexe ou


possédant plusieurs entrées ou sorties. Pour cela, Keras offre l’API Functional.
niver
om:U

46. Ce jeu de données est plus simple que California Housing, utilisé au chapitre 5, car il contient uni-
quement des caractéristiques numériques (la caractéristique ocean_proximity est absente) et il ne
c

manque aucune valeur.


rvox.
la
scho

Vous aimerez peut-être aussi