TNI+VO · Exercice de Programmation

EP09_01 — 🟢 Convolution 2D Manuelle ( Forward d’une Couche Apprise)

9.10.1 EP09_01 🟢 Convolution 2D Manuelle (Forward d’une Couche Apprise)

PyTorch, présenté dans ce chapitre, exécute nn.Conv2d(x) en un seul appel — mais derrière cela se cache simplement la corrélation croisée entre un kernel (déjà entraîné) et un voisinage de l’entrée, suivie de la somme d’un biais et d’une activation, exactement comme formalisé dans la Section « Couche Convolutionnelle ». La différence essentielle par rapport à la convolution de kernels fixes du Chapitre 3 est qu’ici, les valeurs du kernel et du biais sont déjà prêtes (comme si elles avaient été apprises par descente de gradient), et il vous revient de reproduire manuellement la passe directe (forward pass) que le framework exécute en interne.

Avant d’entraîner une véritable CNN, vous êtes chargé d’implémenter cette passe directe à partir de zéro, pour une seule couche convolutionnelle avec un seul canal d’entrée et un seul filtre de sortie, incluant la prise en charge d’un padding et d’un stride arbitraires.

9.10.1.1 📋 Directives d’Implémentation

  1. Entrée : Lire les dimensions \(H \times W\) de la carte de caractéristiques d’entrée, puis ses \(H \times W\) valeurs réelles.

  2. Kernel et biais : Lire les dimensions \(k_h \times k_w\) du kernel (déjà entraîné), ses valeurs réelles, et le biais \(b\) (réel, scalaire).

  3. Hyperparamètres : Lire le padding \(p\) (entier, nombre de zéros ajoutés à chaque bord) et le stride \(s\) (entier, pas de glissement).

  4. Remplissage : Ajouter \(p\) zéros sur chacune des quatre bordures de la carte d’entrée avant la corrélation.

  5. Corrélation croisée : Pour chaque position de sortie \((i, j)\), calculer \[ z(i,j) = b + \sum_{u=0}^{k_h-1} \sum_{v=0}^{k_w-1} K(u,v) \cdot X_{pad}(i \cdot s + u,\; j \cdot s + v), \] en parcourant l’entrée sans inverser le kernel (convention des frameworks d’apprentissage profond, différente de la convolution mathématique classique).

  6. Activation : Appliquer ReLU à chaque valeur : \(a(i,j) = \max(0, z(i,j))\).

  7. Dimensions de sortie : \(O_h = \lfloor (H + 2p - k_h)/s \rfloor + 1\) et \(O_w = \lfloor (W + 2p - k_w)/s \rfloor + 1\).

  8. Sortie : Imprimer \(O_h\) et \(O_w\) sur la première ligne, suivis de \(O_h\) lignes avec chacune \(O_w\) valeurs réelles (la carte de caractéristiques de sortie, déjà avec ReLU appliquée), formatées avec 4 décimales.

9.10.1.2 📌 Contraintes Computationnelles

  • Un canal d’entrée, un filtre de sortie : Il n’est pas nécessaire de gérer plusieurs canaux ou plusieurs filtres dans cette version simplifiée.
  • Sans inversion du kernel : Implémentez la corrélation croisée, et non la convolution mathématique classique avec kernel inversé — c’est l’opération que PyTorch (et la plupart des frameworks) appelle « convolution ».
  • Remplissage par zéros : Les \(p\) pixels ajoutés à chaque bord valent toujours \(0\).
  • Formatage : Toutes les valeurs de sortie doivent avoir exactement 4 décimales, même lorsque la valeur est entière (ex. : 2.0000).

9.10.1.3 🧠 Fondements Théoriques

Élément Rôle dans la couche convolutionnelle
Kernel \(K\) Paramètres appris par descente de gradient, analogues aux coefficients d’un filtre fixe du Chapitre 3, mais ajustés par rétropropagation
Biais \(b\) Décalage appris, ajouté après la corrélation — permet au neurone de « s’activer » même avec une entrée nulle
Padding Contrôle la dimension spatiale de sortie et évite la perte d’information aux bords à chaque couche
Stride Contrôle le pas du déplacement ; des valeurs \(> 1\) réduisent la résolution spatiale, comme une forme de sous-échantillonnage intégrée à la convolution elle-même
ReLU Introduit une non-linéarité après la combinaison linéaire, exactement comme dans la Section « Fonction d’Activation »

9.10.1.4 🧩 Méthodes de morph.py pouvant aider

  • mm.readImg(h, w, dtype='float') — lit directement une matrice \(h \times w\) de valeurs réelles depuis l’entrée standard, évitant ainsi le parsing manuel de la carte de caractéristiques et du kernel.
  • mm.correlacao0(f, kernel, bias) — implémente la même somme de corrélation croisée + biais que vous allez calculer à la main, mais sans prise en charge du padding ou du stride, et convertit le résultat en uint8 (tronque les valeurs négatives et décimales). Peut servir de référence conceptuelle ou pour vérifier le cas le plus simple (\(p=0\), \(s=1\)), mais ne remplace pas votre implémentation complète — qui doit préserver le signe, les décimales, le padding, le stride et ReLU.

9.10.1.5 📦 Spécification d’Entrée et de Sortie (VPL)

Entrée :

  • Ligne 1 : Entiers \(H\) et \(W\).
  • Les \(H\) lignes suivantes : \(W\) valeurs réelles chacune (carte d’entrée).
  • Ligne suivante : Entiers \(k_h\) et \(k_w\).
  • Les \(k_h\) lignes suivantes : \(k_w\) valeurs réelles chacune (kernel).
  • Ligne suivante : Réel \(b\) (biais).
  • Ligne suivante : Entiers \(p\) et \(s\).

Sortie :

  • Ligne 1 : Entiers \(O_h\) et \(O_w\).
  • Les \(O_h\) lignes suivantes : \(O_w\) valeurs réelles chacune, avec 4 décimales.

9.10.1.6 📌 Exemples

Entrée Sortie Observation
3 3
1 2 0
0 1 2
1 0 1
2 2
1 1
1 1
-2
0 1
2 2
2.0000 3.0000
0.0000 2.0000
Padding 0, stride 1 : sortie \(2\times2\) sans remplissage.
3 3
1 2 0
0 1 2
1 0 1
2 2
1 0
0 1
0
1 2
2 2
1.0000 0.0000
1.0000 2.0000
Padding 1, stride 2 : entrée remplie de zéros avant la corrélation.
🎮 Simulateur : Convolution 2D manuelle 🟢 corrélation croisée + biais + ReLU

Entrée fixe 4×4, noyau fixe 2×2 (surligné en bleu) — ajustez padding (p), stride (s) et biais (b), exactement les paramètres que l'EP09_01 demande en entrée, et voyez comment ils modifient la taille et les valeurs de la sortie.

Padding (p)
Pas (s)
Biais (b)
(0,0)
Entrée X rembourrée (avec padding)
original padding (0) fenêtre actuelle
Noyau K (2×2)
Sortie Y = ReLU(X⊛K + b)

💡 Chaque position du curseur révèle une cellule de la matrice de sortie. Parcourez toutes les positions pour compléter la carte de sortie. Changer p, s ou b réinitialise l'exploration, car la carte de sortie change de taille et/ou de valeurs.

Figure 9.43: Simulateur EP09_01 : Convolution 2D manuelle (corrélation croisée + biais + ReLU, avec padding et stride ajustables)
%%writefile EP09_01.py
# Code Python
Overwriting EP09_01.py
TestSuite("EP09_01.py").run()
✔️ EP09_01.cases existe déjà dans casos/
📋 3 cas chargé(s) depuis casos/EP09_01.cases

🔍 Test de Python : EP09_01.py
⚠️ EP09_01.py : fichier vide (moins de 3 lignes). Tests ignorés.