-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path2_Reseaux_Convolutifs.Rmd
368 lines (256 loc) · 11.7 KB
/
2_Reseaux_Convolutifs.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
---
title: "Atelier #2 - Introduction aux réseaux convolutifs"
author: "Mikaël SWAWOLA et Éric HAMEL"
date: "14/05/2019"
output: html_document
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
Sys.setenv(TF_CPP_MIN_LOG_LEVEL = "3") # Car TensorFlow est extrèmement bavard...
```
```{r libraries}
suppressWarnings(library(dplyr))
suppressWarnings(library(ggplot2))
suppressWarnings(library(tidyr))
suppressWarnings(library(tibble))
library(keras)
library(tensorflow)
use_implementation("tensorflow")
```
```{r ws_2_banner, echo=FALSE, fig.cap="", out.width='100%'}
knitr::include_graphics("images/ws_2_banner.png")
```
## 1. Introduction aux réseaux de neurones convolutifs
Nous avons vu lors du premier atelier comment construire et entraîner un modèle de réseau de neurones permettant de **classer** des images du jeu de données **Fashion MNIST**. Les résultats, spectaculaires compte tenu du nombre de ligne de codes, peuvent être encore dépassés grâce aux **réseaux de neurones convolutifs profonds** (ou Convnets). Ce type de réseau a révolutionné la vision numérique et il n'existe aujourd'hui aucune autre méthode en mesure de le rivaliser.
Rendons nous sur la page [2D Visualization of a Convolutional Neural Network](http://scs.ryerson.ca/~aharley/vis/conv/flat.html) afin de comprendre l'intuition derrière ce type de réseau.
```{r ws_2_representations, echo=FALSE, out.width = '100%'}
knitr::include_graphics("images/ws_2_representations.png")
```
## 2. Chargement et préparation des données
Les étapes ci-dessous sont identiques à celles du premier atelier:
```{r}
fashion_mnist <- dataset_fashion_mnist()
c(train_images, train_labels) %<-% fashion_mnist$train
c(test_images, test_labels) %<-% fashion_mnist$test
class_names <- c('T-shirt/top',
'Trouser',
'Pullover',
'Dress',
'Coat',
'Sandal',
'Shirt',
'Sneaker',
'Bag',
'Ankle boot')
train_images_norm <- train_images / 255
test_images_norm <- test_images / 255
```
Les couches de convolutions que nous allons mettre en oeuvre requièrent un format d'entrée de dimension 3, c'est-à-dire **hauteur x largeur x canal**. "canal" représente le nombre de nombre de canaux dans l'image (1 pour niveau de gris, 3 pour couleur RGB).
Les images du jeu de données Fashion MNIST sont, rappelons-le, des tableaux de dimension 2, soit 28 x 28. Il sera nécessaire d'ajouter une dimension supplémentaire pour obtenir un tableau de dimension 3, c'est-à-dire **28x28x1**.
#### EXERCICE: Ajoutez une dimension pour le canal en utilisant la fonction `array_reshape` ou `k_expand_dims`. N'oubliez pas d'appliquer cette modification sur le jeu de test aussi.
[k_expand_dims](https://www.rdocumentation.org/packages/keras/versions/2.1.2/topics/k_expand_dims)
[array_reshape](https://rstudio.github.io/reticulate/reference/array_reshape.html)
```{r}
# ~ 1-2 lignes de code
```
## 2. Définition du modèle
Nous allons maintenant définir un modèle de réseau convolutif relativement simple:
Ce modèle, de type **séquentiel**, sera constitué successivement des couches suivantes:
* Deux couches convolutives successives 3x3 comprenant 32 filtres
* Une couche de MaxPooling
* Deux couches convolutives successives 3x3 comprenant 64 filtres
* Une couche de MaxPooling
* Une couche pleinement connectée composée de 128 neurones
* Une couche de sortie correspondant au nombre de catégories
Les couches convolutives utiliseront une activation de type **relu**
#### QUESTION: Quel type d'activation utilisez-vous pour la couche de sortie?
```{r ws_2_convnet, echo=FALSE, out.width = '100%'}
knitr::include_graphics("images/ws_2_convnet.png")
```
#### EXERCICE: Implémentez le réseau de neurones décrit ci-dessus.
```{r}
# ~ 11 lignes de code
```
Nous pouvons afficher l'architecture du modèle:
```{r}
summary(model)
```
## 3. Compilation du modèle
#### QUESTION: Quelle est la signification du paramètre "loss" de la fonction compile ?
```{r}
model %>% compile(
optimizer = optimizer_adam(lr=0.001),
loss = 'sparse_categorical_crossentropy',
metrics = c('accuracy')
)
```
## 4. Entraînement du modèle
#### EXERCICE: Entraînez le réseau de neurones sur 15 époques et avec une taille de batch de 32. Gardez un oeil sur le sur-apprentissage en utlisant un jeu de validation de 10%. Assignez la valeur de retour de `fit` à la variable `history_conv`.
```{r}
# ~ 1 ligne de code
```
## 5. Comparaison avec l'atelier #1 (Perceptron Multicouche)
```{r}
history_baseline <- read.csv("history_workshop_1.csv", header=TRUE, sep=",")
```
```{r}
compare_cx <- data.frame(
conv_train = history_conv$metrics$loss,
conv_val = history_conv$metrics$val_loss,
base_train = history_baseline$loss,
base_val = history_baseline$val_loss
) %>%
rownames_to_column() %>%
mutate(rowname = as.integer(rowname)) %>%
gather(key = "type", value = "value", -rowname)
ggplot(compare_cx, aes(x = rowname, y = value, color = type)) +
geom_line() +
xlab("epoch") +
ylab("loss")+
xlim(0, 15)
```
```{r}
compare_cx <- data.frame(
conv_train = history_conv$metrics$acc,
conv_val = history_conv$metrics$val_acc,
base_train = history_baseline$acc,
base_val = history_baseline$val_acc
) %>%
rownames_to_column() %>%
mutate(rowname = as.integer(rowname)) %>%
gather(key = "type", value = "value", -rowname)
ggplot(compare_cx, aes(x = rowname, y = value, color = type)) +
geom_line() +
xlab("epoch") +
ylab("accuracy") +
xlim(0, 15)
```
## 6. Normalisation de batch
La **normalisation de batch**, comme son nom l'indique, consiste à normaliser les activations d'une couche donnée avant de les transmettre à la couche suivante. Cette technique s'est montrée efficace pour réduire le nombre d’époques nécessaires pour entraîner un réseau de neurones.
```{r ws_2_batchnorm, echo=FALSE, out.width = '100%'}
knitr::include_graphics("images/ws_2_batchnorm.png")
```
#### EXERCICE: Ajoutez des couches de type `layer_batch_normalization`. Optionel: désactivez le biais des couches convolutives et denses.
```{r}
# ~ 21 lignes de code
```
```{r}
summary(model)
```
```{r}
model %>% compile(
optimizer = optimizer_adam(lr=0.001),
loss = 'sparse_categorical_crossentropy',
metrics = c('accuracy')
)
```
```{r}
history_batchnorm <- model %>% fit(train_images_norm, train_labels, epochs=15, validation_split=0.1, batch_size=32)
```
```{r}
compare_cx <- data.frame(
conv_train = history_conv$metrics$acc,
conv_val = history_conv$metrics$val_acc,
bn_train = history_batchnorm$metrics$acc,
bn_val = history_batchnorm$metrics$val_acc
) %>%
rownames_to_column() %>%
mutate(rowname = as.integer(rowname)) %>%
gather(key = "type", value = "value", -rowname)
ggplot(compare_cx, aes(x = rowname, y = value, color = type)) +
geom_line() +
xlab("epoch") +
ylab("loss")
```
## 7. Régularisation
Il existe plusieurs moyens de réduire le surapprentissage:
* Utiliser plus de données (nous verrons dans l'atelier comment augmenter la taille du jeu de données de manière artificielle)
* Réduire la capacité du réseau (nombre de couches, nombre de neurones, etc..)
* Ajouter une régularisation sur les poids
* Ajouter une régularisation de type **dropout**. **Nous allons voir cette méthode maintenant.**
**Dropout** est l’une des techniques de régularisation des réseaux de neurones les plus efficaces et les plus couramment utilisées. Elle a été mise au point par [Geoffrey Hinton](https://fr.wikipedia.org/wiki/Geoffrey_Hinton) et ses étudiants de l’Université de Toronto. Le **Dropout**, appliqué à une couche, consiste à «éteindre» de manière aléatoire un certain nombre de neurones de la couche **pendant l’entraînement**.
Par exemple, si une couche donnée avait normalement renvoyé le vecteur [0.2, 0.5, 1.3, 0.8, 1.1] pour un échantillon d’entrée donné pendant l’entraînement; après application du **Dropout**, ce vecteur comprendrait quelques zeros répartis de manière aléatoire, par ex. [0, 0,5, 1,3, 0, 1.1].
```{r ws_2_dropout, echo=FALSE, out.width = '100%'}
knitr::include_graphics("images/ws_2_dropout.png")
```
Le «taux de Dropout» correspond à la fraction des neurones mise à zéro. Très souvent, sa valeur varie entre 0.2 et 0.5. Au moment de l'inférence, aucun neurone n’est éteint et les valeurs de sortie de la couche sont réduites d’un facteur égal au taux de Dropout, de manière à compenser le fait que plus de neurones sont actifs lors de l'inférence que lors de l'entraînement.
Dans Keras, Le **Dropout** se rajoute comme une couche, via `layer_dropout` et `layer_spatial_dropout_2d`.
[layer_dropout](https://www.rdocumentation.org/packages/keras/versions/2.2.4.1/topics/layer_dropout)
[layer_spatial_dropout_2d](https://keras.rstudio.com/reference/layer_spatial_dropout_2d.html)
#### EXERCICE: Reprenez l'architecture de la partie 2 et ajoutez une couche de Dropout avant chaque opération de MaxPooling. Ajoutez une autre couche de dropout avant la couche de sortie. Utilisez 0.25 comme taux. Compilez et entraînez le réseau.
```{r}
# ~ 21 lignes de code
model %>%
save_model_weights_hdf5("model_2.h5")
```
```{r}
summary(model)
```
```{r}
model %>% compile(
optimizer = optimizer_adam(lr=0.001),
loss = 'sparse_categorical_crossentropy',
metrics = c('accuracy')
)
```
```{r}
history_reg <- model %>% fit(train_images_norm, train_labels, epochs=15, validation_split=0.1, batch_size=32)
```
Comparons l'évolution de la perte avec et sans dropout:
```{r}
compare_cx <- data.frame(
bn_train = history_batchnorm$metrics$loss,
bn_val = history_batchnorm$metrics$val_loss,
reg_train = history_reg$metrics$loss,
reg_val = history_reg$metrics$val_loss
) %>%
rownames_to_column() %>%
mutate(rowname = as.integer(rowname)) %>%
gather(key = "type", value = "value", -rowname)
ggplot(compare_cx, aes(x = rowname, y = value, color = type)) +
geom_line() +
xlab("epoch") +
ylab("loss")
```
## 8. Un mot sur les Callbacks
Les callbacks servent à sauvegarder automatiquement les points de contrôle (checkpoints) pendant l'entraînement. De cette façon, vous pouvez reprendre l'entraînement d'un modèle à n'importe quelle époque ou bien garder le modèle ayant la meilleure erreur de validation. Les poids sont sauvegardés sous le format HDF5.
```{r}
checkpoint_dir <- "checkpoints"
dir.create(checkpoint_dir, showWarnings = FALSE)
filepath <- file.path(checkpoint_dir, "weights.{epoch:02d}-{val_loss:.2f}.hdf5")
# Create checkpoint callback
cp_callback <- callback_model_checkpoint(
filepath = filepath,
save_weights_only = TRUE,
save_best_only = TRUE,
verbose = 1
)
list.files(checkpoint_dir)
```
```{r}
model %>% load_model_weights_hdf5('model_2.h5')
history_reg <- model %>% fit(
train_images_norm,
train_labels,
epochs=15,
validation_split=0.1,
batch_size=32,
callbacks = list(cp_callback)
)
```
## 9. Évaluation du modèle appris
Évaluons les performances du meilleur modèle sur le jeu de test:
#### EXERCICE: Chargez le meilleur modèle et évaluez le à l'aide de la fonction `evaluate`
```{r}
# ~ 2-3 lignes de code
```
## 10. EXERCICE OPTIONNEL: Essayez d'atteindre 95% de précision en modifiant l'architecture et les hyperparamètres du réseau.
```{r}
model <- keras_model_sequential()
# Compléter...
```
## Sources
[Fashion MNIST with Keras and Deep Learning](https://www.pyimagesearch.com/2019/02/11/fashion-mnist-with-keras-and-deep-learning/)
[Tutorial: Overfitting and Underfitting](https://keras.rstudio.com/articles/tutorial_overfit_underfit.html)
[How convolutional neural networks see the world](https://blog.keras.io/how-convolutional-neural-networks-see-the-world.html)
[Tutorial: Save and Restore Models](https://keras.rstudio.com/articles/tutorial_save_and_restore.html)