CSI 4506 - Automne 2024
Version: nov. 7, 2024 17h55
“Un MLP avec une seule couche cachée peut théoriquement modéliser même les fonctions les plus complexes, à condition qu’il dispose d’assez de neurones. Mais pour des problèmes complexes, les réseaux profonds ont une efficacité paramétrique bien plus élevée que les réseaux peu profonds : ils peuvent modéliser des fonctions complexes en utilisant exponentiellement moins de neurones que les réseaux peu profonds, leur permettant d’atteindre de bien meilleures performances avec la même quantité de données d’entraînement.”
Prenons un réseau de neurones feed-forward (FFN) et son modèle :
\[ h_{W,b}(X) = \phi_k(\ldots \phi_2(\phi_1(X)) \ldots) \]
où
\[ \phi_l(Z) = \sigma(W_l Z + b_l) \]
pour \(l=1 \ldots k\). - Le nombre de paramètres augmente rapidement :
\[ (\text{taille de la couche}_{l-1} + 1) \times \text{taille de la couche}_{l} \]
Deux couches de 1 000 unités impliquent 1 000 000 paramètres !
Les informations cruciales sur les motifs sont souvent locales.
Les couches convolutionnelles réduisent significativement les paramètres.
Contrairement aux couches denses, les neurones dans une couche convolutionnelle ne sont pas complètement connectés à la couche précédente.
Les neurones ne se connectent qu’à leurs champs récepteurs (zones rectangulaires).
Contrairement au traitement d’images, où les noyaux sont définis manuellement par l’utilisateur, dans le cas des réseaux convolutifs, les noyaux sont automatiquement appris par le réseau.
Zero padding. Pour conserver des couches de même taille, la grille peut être remplie de zéros.
Stride. Il est possible de connecter une couche \((l-1)\) plus grande à une couche \((l)\) plus petite en sautant des unités. Le nombre d’unités sautées est appelé stride, \(s_h\) et \(s_w\).
Une fenêtre de taille \(f_h \times f_w\) est déplacée sur la sortie des couches \(l-1\), appelée carte de attributs d’entrée, position par position.
Pour chaque emplacement, le produit est calculé entre la partie extraite et une matrice de la même taille, appelée noyau convolutionnel ou filtre. La somme des valeurs dans la matrice résultante constitue la sortie pour cet emplacement.
\[ z_{i,j,k} = b_k + \sum_{u=0}^{f_h-1} \sum_{v=0}^{f_w-1} \sum_{k'=0}^{f_{n'}-1} x_{i',j',k'} \cdot w_{u,v,k',k} \]
où \(i' = i \times s_h + u\) et \(j' = j \times s_w + v\).
“Ainsi, une couche remplie de neurones utilisant le même filtre produit une carte de d’attributs.”
“Bien sûr, il n’est pas nécessaire de définir les filtres manuellement : au lieu de cela, pendant l’entraînement, la couche convolutionnelle apprendra automatiquement les filtres les plus utiles pour sa tâche.”
“(…) et les couches supérieures apprendront à les combiner en des motifs plus complexes.”
“Le fait que tous les neurones d’une carte d’attributs partagent les mêmes paramètres réduit considérablement le nombre de paramètres du modèle.”
Une couche de pooling présente des similitudes avec une couche convolutionnelle.
Cependant, contrairement aux couches convolutionnelles, les couches de pooling ne possèdent pas de poids.
Ce processus de sous-échantillonnage conduit à une réduction de la taille du réseau ; chaque fenêtre de dimensions \(f_h \times f_w\) est condensée en une seule valeur, généralement le maximum ou la moyenne de cette fenêtre.
Selon Géron (2019), une couche de pooling max offre un certain degré d’invariance aux petites translations (§ 14).
import tensorflow as tf
from functools import partial
DefaultConv2D = partial(tf.keras.layers.Conv2D, kernel_size=3, padding="same", activation="relu", kernel_initializer="he_normal")
model = tf.keras.Sequential([
DefaultConv2D(filters=64, kernel_size=7, input_shape=[28, 28, 1]),
tf.keras.layers.MaxPool2D(),
DefaultConv2D(filters=128),
DefaultConv2D(filters=128),
tf.keras.layers.MaxPool2D(),
DefaultConv2D(filters=256),
DefaultConv2D(filters=256),
tf.keras.layers.MaxPool2D(),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(units=128, activation="relu", kernel_initializer="he_normal"),
tf.keras.layers.Dropout(0.5),
tf.keras.layers.Dense(units=64, activation="relu", kernel_initializer="he_normal"),
tf.keras.layers.Dropout(0.5),
tf.keras.layers.Dense(units=10, activation="softmax") ])
model.summary()
Model: "sequential_1"
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ ┃ Layer (type) ┃ Output Shape ┃ Param # ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ │ conv2d_5 (Conv2D) │ (None, 28, 28, 64) │ 3,200 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ max_pooling2d_3 (MaxPooling2D) │ (None, 14, 14, 64) │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ conv2d_6 (Conv2D) │ (None, 14, 14, 128) │ 73,856 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ conv2d_7 (Conv2D) │ (None, 14, 14, 128) │ 147,584 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ max_pooling2d_4 (MaxPooling2D) │ (None, 7, 7, 128) │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ conv2d_8 (Conv2D) │ (None, 7, 7, 256) │ 295,168 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ conv2d_9 (Conv2D) │ (None, 7, 7, 256) │ 590,080 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ max_pooling2d_5 (MaxPooling2D) │ (None, 3, 3, 256) │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ flatten_1 (Flatten) │ (None, 2304) │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dense_3 (Dense) │ (None, 128) │ 295,040 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dropout_2 (Dropout) │ (None, 128) │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dense_4 (Dense) │ (None, 64) │ 8,256 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dropout_3 (Dropout) │ (None, 64) │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dense_5 (Dense) │ (None, 10) │ 650 │ └─────────────────────────────────┴────────────────────────┴───────────────┘
Total params: 1,413,834 (5.39 MB)
Trainable params: 1,413,834 (5.39 MB)
Non-trainable params: 0 (0.00 B)
Krizhevsky, Sutskever, et Hinton (2012)
Simonyan et Zisserman (2015)
Comme vous pouvez l’imaginer, le nombre de couches et de filtres sont des hyperparamètres qui sont optimisés par le biais de l’ajustement des hyperparamètres.
Lors de l’intégration des CNN dans vos projets, envisagez d’explorer les sujets suivants :
Attribution de attributs : Diverses techniques sont disponibles pour visualiser ce que le réseau a appris. Par exemple, dans le contexte des voitures autonomes, il est crucial de s’assurer que le réseau se concentre sur des attributs pertinentes, évitant les distractions.
Apprentissage par transfert : Cette approche permet la réutilisation des poids de réseaux pré-entraînés, ce qui accélère le processus d’apprentissage, réduit les besoins en calcul et facilite l’entraînement du réseau même avec un nombre limité d’exemples.
Understanding Deep Learning (Prince 2023) est un manuel récemment publié qui se concentre sur les concepts fondamentaux de l’apprentissage profond.
Il commence par les principes de base et s’étend à des sujets contemporains tels que les transformateurs, les modèles de diffusion, les réseaux de neurones graphiques, les autoencodeurs, les réseaux adversariaux et l’apprentissage par renforcement.
Le manuel vise à aider les lecteurs à comprendre ces concepts sans entrer excessivement dans les détails théoriques.
Il comprend soixante-huit exercices sous forme de cahiers Python.
Le livre suit un modèle “lire d’abord, payer plus tard”.
Marcel Turcotte
École de science informatique et de génie électrique (SIGE)
Université d’Ottawa