Transfer learning

include_top=False base_model.trainable = False


On a vu

et plein d'autres choses


Transfer Learning

transfer learning : construire sur la base d'un méga modèle


Changement de paradygme

Le process classique du machine learning

Nouvelle methode

Ce qui a amené ce changement : la libre mise à disposition des modèles


Transfer Learning vs Fine tuning

Transfer learning est le concept général : prendre un modèle entraîné sur une tâche A et l'appliquer à une tâche B. C'est l'idée, la stratégie.

Fine-tuning est une technique pour faire du transfer learning. La vraie distinction se fait entre les techniques de transfer learning :

Donc quand on oppose "transfer learning vs fine-tuning", c'est un abus de langage. On devrait dire "feature extraction vs fine-tuning", les deux étant des formes de transfer learning.


Use cases

Transfer learning / Feature extraction :

Prototypage rapide / POC

  • Peu de données d'entraînement disponibles (risque d'overfitting si on dégèle tout)
  • Tâche cible proche de la tâche d'origine (ex : classifier des chats/chiens avec un modèle pré-entraîné sur ImageNet)
  • Ressources de calcul limitées (plus rapide à entraîner)

Fine-tuning :

Adaptation de LLMs à un domaine spécifique (ex : fine-tuner GPT ou LLaMA sur des données juridiques, médicales, etc.)

  • Dataset suffisamment large sur la nouvelle tâche
  • Tâche cible significativement différente du domaine d'origine (ex : imagerie médicale à partir d'un modèle entraîné sur des photos classiques)
  • On veut des performances maximales et on a le budget GPU pour ça

Geler des couches

Exemple Keras minimal :

from tensorflow.keras.applications import VGG16
from tensorflow.keras import layers, Model

# Charger VGG16 pré-entraîné, sans la tête de classification
base_model = VGG16(weights='imagenet', include_top=False, input_shape=(224,224,3))

# Geler toutes les couches du modèle de base
for layer in base_model.layers:
    layer.trainable = False

# Ajouter notre propre classifieur
x = layers.Flatten()(base_model.output)
x = layers.Dense(128, activation='relu')(x)
output = layers.Dense(10, activation='softmax')(x)

model = Model(base_model.input, output)
model.compile(optimizer='adam', loss='categorical_crossentropy')

Example Transfer Learning

Contexte: une startup de dermatologie qui veut créer une app pour détecter des mélanomes à partir de photos de grains de beauté.

Le problème : ils ont seulement 2 000 images de grains de beauté étiquetées (bénin/malin). C'est beaucoup trop peu pour entraîner un réseau de vision from scratch : il faudrait des centaines de milliers d'images.

La solution : Le transfer learning : Ils prennent un ResNet pré-entraîné sur ImageNet (1,4 million d'images de chats, voitures, paysages, etc.). Ce réseau a déjà appris à reconnaître des features visuelles universelles : bords, textures, formes, contrastes, motifs...

Sans transfer learning, avec seulement 2 000 images et un réseau from scratch, ils auraient probablement plafonné à 60-65% avec un overfitting massif.

C'est exactement pour ça que le transfer learning a révolutionné la vision par ordinateur : on ne part plus jamais de zéro.


Learning rate


Cas usage fine tuning

Contexte : un cabinet d'avocats veut détecter les clauses à risque dans des contrats.

Le problème : ils reçoivent des centaines de contrats par mois et veulent un modèle qui détecte automatiquement les clauses à risque (clauses abusives, pénalités cachées, ambiguïtés juridiques). Un LLM généraliste comme GPT ou LLaMA comprend bien le français, mais il ne connaît pas les subtilités du droit commercial français.

Un simple transfer learning (feature extraction) ne suffit pas ici : le langage juridique est tellement spécifique (formulations latines, tournures archaïques, vocabulaire technique) que les couches profondes du modèle doivent elles aussi s'adapter. Un simple classifieur greffé à la fin ne capte pas ces nuances.


Le fine-tuning est plus coûteux, car :

Le transfer learning est bien plus léger : on n'entraîne que la tête de classification, donc c'est quasi comme entraîner un petit réseau classique.

Ordre de grandeur typique : pour un modèle comme VGG16,

soit un facteur ~300x de différence.


Quelques cas où le transfer learning ne marche pas bien :

1. Domaines trop éloignés : Negative transfer

Un modèle entraîné sur ImageNet (photos naturelles) appliqué à des images satellite radar ou des spectrogrammes audio. Les features apprises (textures, formes d'objets) ne sont pas pertinentes. Le modèle transfère du bruit plutôt que du signal utile.

2. Données de nature très différente

Un modèle NLP entraîné sur du texte Wikipedia appliqué à du code source, des séquences ADN ou des logs serveur. Les embeddings pré-appris n'ont aucune valeur pour ces structures.

3. Biais hérités du modèle source

On hérite des biais du dataset d'origine. Un modèle de vision entraîné majoritairement sur des peaux claires performera mal en dermatologie sur des peaux foncées. Le transfer learning propage et parfois amplifie ces biais.

4. Tâche cible trop simple Si la tâche est triviale (classifier 2 catégories très distinctes avec peu d'images), un modèle classique ou du feature engineering suffit. Le transfer learning apporte une complexité inutile.

5. Architecture incompatible On ne peut pas transférer efficacement les poids d'un CNN vers un problème séquentiel (séries temporelles longues). L'architecture source doit correspondre à la structure du problème cible.

Le transfer learning fonctionne quand les features du modèle source sont pertinentes et réutilisables pour la tâche cible. Sinon, on transfère du bruit et c'est pire que de partir de zéro.


Excellent article

https://neptune.ai/blog/transfer-learning-guide-examples-for-images-and-text-in-keras


Transfer Learning en 6 étapes

Source : Neptune.ai – Transfer Learning Guide


Étape 1 : Obtenir un modèle pré-entraîné

On choisit un modèle déjà entraîné sur un large dataset (ImageNet, GloVe, etc.).

Les sources principales :

Le modèle apporte des features génériques apprises sur des millions d'exemples.


Étape 2 : Créer le modèle de base

On instancie l'architecture choisie avec ses poids pré-entraînés, mais sans la couche de sortie finale (include_top=False).

base_model = keras.applications.Xception(
    weights='imagenet',
    input_shape=(150, 150, 3),
    include_top=False)

On retire la dernière couche car elle est spécifique au dataset d'origine (ex : 1000 classes ImageNet). Elle sera remplacée par une couche adaptée à notre problème.


Étape 3 : Geler les couches

On gèle toutes les couches du modèle de base pour préserver les poids pré-entraînés.

base_model.trainable = False

Sans cette étape, les poids seraient réinitialisés pendant l'entraînement. On perdrait tout le bénéfice du transfer learning.

Point important : les couches de BatchNormalization doivent aussi être gelées, sinon leurs statistiques (moyenne, variance) seront mises à jour et dégraderont les performances.


Rappel : Batch Normalization

À quoi ça sert ? :

Au fil de l'entraînement, les poids changent → les valeurs de sortie de chaque couche (les activations) dérivent.

La couche suivante reçoit des entrées de plus en plus instables et doit constamment se réadapter (internal covariate shift).

La BatchNorm recentre ces activations (moyenne ≈ 0, écart-type ≈ 1) à chaque couche → entrées stables, convergence plus rapide.

La Batch Normalization normalise les activations de chaque couche sur le mini-batch en cours :

x^i=xiμBσB2+ϵ\hat{x}_i = \frac{x_i - \mu_B}{\sqrt{\sigma_B^2 + \epsilon}}


Pourquoi geler BatchNorm en transfer learning ?

Si on laisse trainable=True, les stats glissantes se mettent à jour avec nos nouvelles données, qui ont une distribution différente d'ImageNet. Les couches gelées en amont reçoivent alors des entrées renormalisées de façon incohérente → les features pré-apprises sont corrompues.

# Geler explicitement les couches BatchNorm
for layer in base_model.layers:
    if isinstance(layer, tf.keras.layers.BatchNormalization):
        layer.trainable = False

Étape 4 : Ajouter de nouvelles couches entraînables

On greffe de nouvelles couches au-dessus du modèle gelé pour adapter la sortie à notre problème.

x = base_model(inputs, training=False)
x = keras.layers.GlobalAveragePooling2D()(x)
x = keras.layers.Dropout(0.2)(x)
outputs = keras.layers.Dense(1)(x)  # 1 sortie = classification binaire
model = keras.Model(inputs, outputs)

Ces nouvelles couches sont les seules qui seront entraînées. Elles transforment les features extraites par le modèle de base en prédictions adaptées à notre tâche.


Étape 5 : Entraîner les nouvelles couches

On compile et entraîne le modèle. Seules les couches ajoutées à l'étape 4 sont mises à jour.

model.compile(optimizer='adam',
              loss=BinaryCrossentropy(from_logits=True),
              metrics=[BinaryAccuracy()])
model.fit(training_set, epochs=20, validation_data=val_dataset)

L'entraînement est rapide car très peu de paramètres sont concernés. La validation accuracy démarre déjà haut grâce aux features pré-apprises.

C'est l'étape de feature extraction : souvent suffisante pour obtenir de bons résultats.


Étape 6 : Améliorer par fine-tuning (optionnel)

On dégèle tout ou partie du modèle de base et on réentraîne l'ensemble avec un learning rate très faible.

base_model.trainable = True

model.compile(optimizer=keras.optimizers.Adam(1e-5),
              loss=BinaryCrossentropy(from_logits=True),
              metrics=[BinaryAccuracy()])

model.fit(training_set, epochs=15,
          validation_data=val_dataset,
          callbacks=[EarlyStopping(patience=5)])

Points clés :


sources de modèles pré-entraînés mentionnées :

1. Keras Applications : Plus de 20 modèles de vision (ResNet, VGG, Xception, MobileNet…).

model = tf.keras.applications.MobileNet(
    weights="imagenet",
    include_top=True,
    classes=1000
)

Les poids sont téléchargés automatiquement et stockés dans ~/.keras/models/.


2. TensorFlow Hub : Des modèles prêts à intégrer directement dans un Sequential.

model = tf.keras.Sequential([
    hub.KerasLayer("https://tfhub.dev/google/imagenet/mobilenet_v2.../feature_vector/4",
                   trainable=False),
    tf.keras.layers.Dense(num_classes, activation='softmax')
])

3. Hugging Face : Des milliers de modèles

from transformers import pipeline
classifier = pipeline('sentiment-analysis')

Pratique

Demo transfer Learning : transfer_learning_inception_fr.ipynb

Atelier : transfer_learning_hands_on_claude_flowers.ipynb


DeepDream

deep_dream_claude.ipynb

1 / 0