Project Oxygen & Ideo-LabIDEO LAB Dashboard 2026

🏛️ ResNet – Le Guide Ultime

Deep Dive : Le Problème de Dégradation, 🚀 Blocs Résiduels (Skip Connection), VGG vs ResNet50, Transfer Learning.

1.1 Facile

1. C'est quoi ResNet ?

Residual Network. Gagnant ILSVRC 2015. 3.57% d'erreur (mieux que l'humain).

ResNet ILSVRC 2015
1.2 Moyen

2. Le Problème (Dégradation)

Le paradoxe : un réseau 56-couches était *moins bon* qu'un 20-couches (Vanishing Gradient).

Degradation Vanishing Gradient
1.3 Avancé

3. 🚀 La Solution : Skip Connection

Le "plugin" de génie : H(x) = F(x) + x. Le réseau apprend le "résidu" (F(x)).

Skip Connection Residual Block
1.4 Moyen

4. 📈 Architecture (ResNet-50)

Une pile de "Bottleneck Blocks". 152 couches deviennent possibles.

ResNet-50 Architecture
1.5 Avancé

5. Le "Bottleneck Block"

Le "plugin" d'optimisation. 1x1 (réduit) -> 3x3 (traite) -> 1x1 (étend).

Bottleneck 1x1 Conv
1.6 Moyen

6. 📊 ResNet-18 vs 50 vs 152

VGG16 (138M params) vs ResNet50 (25M params). Plus profond, plus léger, plus précis.

VGG vs ResNet Params
2.1 Moyen

7. Code (PyTorch)

torchvision.models.resnet50(pretrained=True). model.fc = nn.Identity().

PyTorch torchvision
2.2 Moyen

8. Code (Keras)

tf.keras.applications.ResNet50(). include_top=False (usage n°1).

Keras TensorFlow
2.3 Avancé

9. 🚀 Cas: Transfer Learning

L'usage moderne. Geler le "backbone", remplacer la "tête" (Dense) pour un projet custom.

Transfer Learning Fine-Tuning
3.1 Avancé

10. Projet: "Backbone" (Addon)

ResNet comme "Feature Extractor" (plugin) pour YOLO, Faster R-CNN, U-Net.

Backbone YOLO U-Net
3.2 Avancé

11. Frameworks Dérivés

L'héritage : ResNeXt (Groupes), DenseNet (Concat), ViT (Transformers).

DenseNet ViT
3.3 Moyen

12. Chiffres & Liens

Stats (FPS, GFLOPs). Liens vers le papier original, PyTorch, Keras.

Paper Links
1.1 C'est quoi ResNet ? (Le Tournant de 2015)

ResNet (Residual Network) est une architecture de réseau de neurones convolutif (CNN) qui a remporté le concours ILSVRC 2015 (ImageNet) sur *toutes* les catégories (Classification, Détection, Segmentation).

Il a été créé par Kaiming He (et al.) de Microsoft Research. Son impact est comparable à celui d'AlexNet (2012).

L'Impact (Les Chiffres)

ResNet a été le premier modèle à dépasser la performance humaine sur ImageNet.

ModèleAnnéeTaux d'Erreur (Top-5)Profondeur
AlexNet201215.3%8 couches
VGG-1620147.3%16 couches
GoogLeNet20146.7%22 couches
ResNet-15220153.57%152 couches
Humain (A. Karpathy)~2014~5.1%N/A

La question à laquelle ResNet a répondu est : "VGG a prouvé que 'plus profond' (19 couches) est mieux qu'AlexNet (8 couches). Peut-on aller *beaucoup* plus profond (50, 100, 150 couches) ?"

1.2 Le Problème de Dégradation (Vanishing Gradient)

Avant ResNet, il y avait un paradoxe : l'ajout de couches (ex: passer de 20 à 50) rendait le modèle *moins bon*. Non seulement sur le set de *test* (overfitting), mais aussi sur le set *d'entraînement* (training) !

C'est le Problème de Dégradation (Degradation Problem).

La Cause : "Vanishing Gradient"

Pendant l'entraînement (backpropagation), le "signal d'erreur" (le gradient) doit remonter de la dernière couche à la première. Dans un réseau très profond (50+ couches), ce gradient est multiplié (par la "Chain Rule"). S'il est < 1, il tend vers zéro (0.9 * 0.9 * ... * 0.9 = 0.00...).

Résultat : Les premières couches (celles qui apprennent les features de base) ne reçoivent *aucun* signal d'apprentissage. Elles ne s'entraînent pas. Le réseau "s'effondre".

AlexNet a "résolu" cela avec ReLU (voir 1.4, AlexNet), mais cela n'a fonctionné que jusqu'à ~20 couches (VGG). ResNet a introduit la *vraie* solution.

1.3 🚀 La Solution : Le Bloc Résiduel (Skip Connection)

L'idée de Kaiming He est d'une simplicité géniale. Si un bloc de couches (ex: 3 couches) a du mal à apprendre une fonction (H(x)), on va lui faciliter la tâche.

On va lui demander d'apprendre *seulement* le "Résidu" (F(x)) - la *différence* entre ce qu'il devrait apprendre (H(x)) et son entrée (x).

Mathématiquement : H(x) = F(x) + x

Le Diagramme : "Skip Connection"

Pour ce faire, ils ont introduit une "connexion de saut" (Skip Connection) qui "contourne" (bypass) le bloc.

(Input: x)
   |
   +-----> (Connexion "Identité" / "Skip") ----+
   |                                          |
   ▼                                          |
[ Conv 3x3 (Poids W1) ]                       |
[ Batch Norm ]                                |
[ ReLU ]                                      |
[ Conv 3x3 (Poids W2) ]                       |
[ Batch Norm ]                                |
   |                                          |
   ▼                                          |
( F(x) )                                      |
   |                                          |
   +-----------> [ ADDITION ] <---------------+
                       |
                       ▼
                 [ ReLU ]
                       |
                       ▼
                 (Sortie: H(x))
Pourquoi ça marche ?

Le "Vanishing Gradient" est résolu : Le gradient (signal d'erreur) peut *toujours* remonter par le "pont" (le "skip" + x), même si les gradients des couches F(x) deviennent nuls. Il a une autoroute directe vers les premières couches.

Apprentissage "facile" : Si un bloc n'est pas nécessaire (la meilleure fonction est H(x) = x), le réseau peut *très* facilement apprendre à F(x) = 0 (mettre les poids W1/W2 à 0). Sans le "skip", il aurait dû apprendre la fonction "identité" (H(x)=x), ce qui est très difficile pour des convolutions.

1.4 📈 Architecture (ResNet-50)

L'architecture de ResNet-50 (et plus) n'est pas juste un "stack" de 50 couches. C'est un stack de "Blocs Résiduels" (voir 1.3).

Diagramme (Architecture ResNet-50)
(Input: Image 224x224x3)
     |
     ▼
[ Stage 0: (Conv 7x7, 64) + MaxPool(3x3, S2) ] (-> 56x56x64)
     |
     ▼
[ Stage 1: (Bloc "Bottleneck") x 3 ] (-> 56x56x256)
     |
     ▼
[ Stage 2: (Bloc "Bottleneck") x 4 ] (-> 28x28x512)
     |
     ▼
[ Stage 3: (Bloc "Bottleneck") x 6 ] (-> 14x14x1024)
     |
     ▼
[ Stage 4: (Bloc "Bottleneck") x 3 ] (-> 7x7x2048)
     |
     | (Flatten -> 7x7x2048)
     ▼
[ Global Average Pooling (GAP) ] (-> 2048)
     |
     ▼
[ FC (Fully Connected) (1000 neurones) + Softmax ]
     |
     ▼
(Sortie: 1000 classes ImageNet)
Global Average Pooling (GAP)

ResNet a (presque) tué les couches "Fully Connected" (FC) de VGG/AlexNet.
VGG : Prend la sortie (7x7x512), l'aplatit (Flatten) en 25 088 neurones, puis utilise 2 couches FC (100M+ de poids !).
ResNet : Prend la sortie (7x7x2048), applique un Global Average Pooling (fait la *moyenne* de chaque canal) -> (résultat 1x1x2048), puis 1 seule couche FC.
Résultat : Réduction *massive* du nombre de paramètres (poids) et de l'overfitting.

1.5 Le "Bottleneck Block" (1x1 Conv)

Les "petits" ResNets (ResNet-18, ResNet-34) utilisent des "Blocs Basiques" (2x Conv 3x3).

Les "gros" ResNets (50, 101, 152) utilisent le "plugin" "Bottleneck Block" pour être *plus profonds* avec *moins* de calculs. C'est une optimisation cruciale (inspirée de GoogLeNet).

L'astuce : Le 1x1 Conv (Réduction de Dimension)

Une convolution 1x1 est un "plugin" qui ne fait que "compresser" (ou "étendre") le nombre de *canaux* (features), sans changer la taille (hauteur/largeur).

Diagramme (Bloc "Bottleneck")
(Input: 28x28x256)
     |
     +------------(Skip)------------+
     |                              |
     ▼                              |
[ 1. Conv 1x1, 64 filtres ]  (Réduit : 28x28x64)
     |                              |
     ▼                              |
[ 2. Conv 3x3, 64 filtres ]  (Traite : 28x28x64)
     |                              |
     ▼                              |
[ 3. Conv 1x1, 256 filtres ] (Étend  : 28x28x256)
     |                              |
     ▼                              |
     +----------[ ADDITION ] <-------+
                    |
                    ▼
                  [ ReLU ]

Gains de calcul (vs 2x Conv 3x3) : Ce "goulot d'étranglement" (bottleneck) (256 -> 64 -> 256) est *beaucoup* moins coûteux en calculs que de faire du Conv 3x3 sur 256 filtres.

1.6 📊 Comparaison (VGG vs ResNet-50)

La comparaison VGG vs ResNet montre l'évolution :

ModèleProfondeurParamètres (Poids)Taille (Disque)FLOPs (Calcul)Erreur Top-1 (ImageNet)
VGG-1616 couches~138 Millions~528 MB~15.5 GFLOPs28.5%
ResNet-5050 couches~25.6 Millions~98 MB~4.1 GFLOPs22.8%

Conclusion : ResNet-50 est 3 fois plus profond (50 vs 16), 5 fois plus léger (25M vs 138M params), 4 fois plus rapide (4.1 vs 15.5 GFLOPs) et beaucoup plus précis (22.8% vs 28.5%) que VGG16.

La Famille ResNet
ModèleType de BlocProfondeurParamètres
ResNet-18Basic (2x 3x3)1811.7 M
ResNet-34Basic (2x 3x3)3421.8 M
ResNet-50Bottleneck (1x1, 3x3, 1x1)5025.6 M
ResNet-101Bottleneck10144.5 M
ResNet-152Bottleneck15260.2 M
2.1 Code : Inférence (Plugin PyTorch)

Le "plugin" torchvision (l'addon officiel de PyTorch pour la vision) fournit le modèle ResNet pré-entraîné sur ImageNet.

Exemple (Inférence simple)
import torch
from torchvision import models, transforms
from PIL import Image

# 1. Charger ResNet-50 pré-entraîné
# (Télécharge ~98MB la 1ère fois)
# (Pour VGG: models.vgg16(pretrained=True))
model = models.resnet50(pretrained=True)
model.eval() # IMPORTANT: Mode évaluation (désactive BatchNorm/Dropout)

# 2. Définir les "Transforms" (standard ImageNet)
preprocess = transforms.Compose([
    transforms.Resize(256),
    transforms.CenterCrop(224),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406], 
                         std=[0.229, 0.224, 0.225]),
])

# 3. Charger & Pré-processer l'image
img = Image.open("mon_chien.jpg")
img_t = preprocess(img)
batch_t = torch.unsqueeze(img_t, 0) # (Ajoute la dimension batch)

# 4. Inférence (avec 'no_grad' pour économiser la mémoire)
with torch.no_grad():
    output = model(batch_t) # (Output: [1, 1000])

# 5. Obtenir la prédiction
probabilities = torch.nn.functional.softmax(output[0], dim=0)
top_class_index = torch.argmax(probabilities).item()

# (Charger les 1000 labels d'ImageNet...)
print(f"Prédiction: Classe {top_class_index}")
2.2 Code : Inférence (Plugin Keras)

L'écosystème Keras (intégré à TensorFlow) fournit également ResNet comme "plugin" (keras.applications).

include_top=False (Le "Plugin" Transfer Learning)

Keras rend le Transfer Learning (voir 2.3) *très* facile avec l'argument include_top.

import tensorflow as tf
from tensorflow.keras.applications.resnet50 import ResNet50, preprocess_input, decode_predictions
from tensorflow.keras.preprocessing import image
import numpy as np

# --- 1. Inférence Simple (Avec la "Tête") ---
model_full = ResNet50(weights='imagenet', include_top=True)

img = image.load_img('mon_chien.jpg', target_size=(224, 224))
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)
x = preprocess_input(x) # (Normalisation Keras)

preds = model_full.predict(x)
print(decode_predictions(preds, top=3)[0])
# (Affiche les 3 top prédictions ImageNet)


# --- 2. Mode "Feature Extractor" (Sans la "Tête") ---
# (C'est la base du Transfer Learning, voir 2.3)
model_features = ResNet50(weights='imagenet', include_top=False)

# 'preds_features' n'est PAS (1, 1000), 
# c'est la sortie du "Backbone" (1, 7, 7, 2048)
preds_features = model_features.predict(x)
2.3 🚀 Cas: Transfer Learning (Feature Extractor)

C'est l'usage n°1 de ResNet (et VGG) aujourd'hui.
Le Problème : Je veux classer "Chat" vs "Chien", mais je n'ai que 1000 images.
La Solution : Le Transfer Learning (Apprentissage par Transfert).

Les premières couches d'un CNN (comme ResNet) apprennent des features *génériques* (détection de bords, textures, coins). Ces "yeux" (entraînés sur 1.1M d'images ImageNet) sont *plus performants* que tout ce qu'on peut entraîner sur 1000 images.

Le Workflow (Keras)
  1. Charger le "Backbone" : On charge ResNet-50 *sans* sa tête (include_top=False).
  2. Geler (Freeze) : On dit à Keras de ne *pas* ré-entraîner les 25M de poids (trainable = False).
  3. Ajouter notre "Tête" : On ajoute *nos propres* couches (Dense) à la fin (ex: Dense(1, 'sigmoid') pour "chat" / "chien").
  4. Entraîner : On n'entraîne *que* notre (petite) tête sur nos 1000 images.
import tensorflow as tf
from tensorflow.keras import layers, models

# 1. Charger ResNet-50 (le "backbone") pré-entraîné
base_model = tf.keras.applications.ResNet50(
    weights='imagenet',
    include_top=False, # (Ne pas inclure la tête de 1000 classes)
    input_shape=(224, 224, 3)
)

# 2. Geler (Freeze) le backbone
base_model.trainable = False

# 3. Créer notre nouveau modèle (le "plugin" par-dessus)
model = models.Sequential([
    base_model, # (Le backbone gelé)
    
    # 4. Notre "Tête" (Classifier)
    layers.GlobalAveragePooling2D(), # (Mieux que Flatten)
    layers.Dense(256, activation='relu'),
    layers.Dropout(0.5),
    layers.Dense(1, activation='sigmoid') # (1 neurone: chat/chien)
])

# 5. Compiler et entraîner
# (On n'entraîne QUE les 3 couches Dense)
model.compile(optimizer='adam', loss='binary_crossentropy', ...)
model.fit(mon_dataset, ...)
3.1 Projet: ResNet comme "Backbone" (Addon)

L'usage "plugin" le plus avancé de ResNet n'est pas pour la classification, mais comme "Backbone" (épine dorsale) pour des tâches plus complexes comme la Détection d'Objet ou la Segmentation.

L'idée est de *remplacer* le "feature extractor" d'un autre modèle (ex: YOLO, U-Net) par un ResNet-50.

Projet 1 : Détection d'Objet (ex: YOLO / Faster R-CNN)

Un modèle comme YOLOv8 a son propre backbone (C2f). Mais de nombreux autres détecteurs (ex: Faster R-CNN, RetinaNet) vous laissent *choisir* votre "plugin" backbone.

Workflow :
1. On prend un ResNet-50 (include_top=False).
2. On attache un "Neck" (FPN - Feature Pyramid Network) qui prend les sorties des *différents* stages (Stage 2, 3, 4, 5) pour avoir des features multi-échelles.
3. On attache la "Tête" (Head) de détection (ex: RPN + Classifier).

Projet 2 : Segmentation (ex: U-Net)

U-Net (utilisé en imagerie médicale) a un "Encoder" (descente) et un "Decoder" (remontée).

Workflow :
1. On *remplace* l'Encoder de U-Net par un ResNet-34 pré-entraîné (gelé).
2. On garde le Decoder (qui "remonte" l'image) et on connecte les "skip connections" de U-Net aux "skip connections" de ResNet.
Résultat : Le "U-Net-ResNet34" converge 100x plus vite et est beaucoup plus précis qu'un U-Net "from scratch".

3.2 Frameworks Dérivés (ResNeXt, DenseNet)

ResNet (2015) a lancé une "explosion" de nouvelles architectures basées sur son "plugin" de "skip connection".

Modèle (Dérivé)DateInnovation (Le "Plugin")
ResNeXt2016"Cardinality" (Grouped Convolutions).
Au lieu d'un "bottleneck" (1x1->3x3->1x1), utilise *plusieurs* chemins parallèles (groupes) moins larges. (Inspiré de GoogLeNet).
DenseNet2017"Dense" Skip Connections.
Au lieu de H(x) = F(x) + x (Addition), il concatène les features : H(x) = Concat(F(x), x).
Chaque couche est connectée à *toutes* les couches précédentes.
Vision Transformer (ViT)2020La nouvelle révolution.
Abandonne *totalement* les Convolutions (CNNs). Utilise 100% le "plugin" Transformer (Self-Attention) (venu du NLP/Langage).