0Pricing
Machine Learning Academy · Leçon

Extraction de caractéristiques : geler le réseau de base

Vous gèlerez toutes les couches sauf la tête de classification finale, n’entraînerez que les nouvelles couches sur un petit jeu de données personnalisé et confirmerez la forte réduction du temps d’entraînement.

Extraction de caractéristiques : geler le réseau de base est une leçon Machine Learning Academy gratuite sur CoddyKit. Ceci est la leçon 2 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage Machine Learning Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Machine Learning Academy comprend 4 leçons au total.

Certaines parties de cette leçon n'ont pas encore été traduites et s'affichent en anglais.

Feature Extraction vs Fine-Tuning

Transfer learning has two main strategies. In feature extraction, the pre-trained backbone is completely frozen — its weights do not change during training. Only the new classification head, which you add on top, learns from your data. In fine-tuning, the entire network or at least some backbone layers are also updated.

Feature extraction is the right choice when your dataset is small (less than a few thousand images) or when your images are similar to ImageNet (natural photographs of everyday objects). It is much faster since gradients do not flow through the backbone, and it avoids destroying carefully learned features with noisy updates from too little data.

Freezing Parameters in PyTorch

In PyTorch, each parameter tensor has a requires_grad attribute. Setting it to False prevents gradient computation for that tensor, effectively freezing it. The simplest way to freeze all backbone parameters is to iterate over model.parameters() and set requires_grad = False, then replace the classification head (which starts with new random weights, so requires_grad=True by default).

This is efficient: PyTorch's autograd skips frozen parameters during the backward pass, reducing memory usage and speeding up training significantly compared to fine-tuning the whole network.

import torchvision.models as models
import torch.nn as nn

model = models.resnet50(weights=models.ResNet50_Weights.IMAGENET1K_V1)

# Freeze ALL backbone parameters
for param in model.parameters():
    param.requires_grad = False

# Replace the classification head (creates new trainable parameters)
num_classes = 10
model.fc = nn.Linear(model.fc.in_features, num_classes)
# model.fc.parameters() have requires_grad=True by default

trainable = sum(p.numel() for p in model.parameters() if p.requires_grad)
total = sum(p.numel() for p in model.parameters())
print(f'Trainable: {trainable:,} / Total: {total:,} ({trainable/total:.1%})')

Why Frozen Features Work Well

ImageNet pre-trained models learn a hierarchy of features: early layers detect low-level edges and colours, middle layers detect textures and parts, and later layers detect abstract objects. These features are general visual features that transfer broadly across image domains.

When your task involves natural images — flowers, animals, medical scans, satellite photos — these pre-learned features are far more informative than anything a randomly initialised network could extract from a small dataset. Feature extraction leverages this by treating the frozen backbone as a fixed feature transformer and only training a small linear classifier on top of the extracted features.

import torchvision.models as models
import torch

# Pre-extract features for all images (faster than forward-passing every epoch)
model = models.resnet50(weights=models.ResNet50_Weights.IMAGENET1K_V1)
model.fc = torch.nn.Identity()  # Remove classification head
model.eval()

# Extract 2048-dim features for all training images once
all_features, all_labels = [], []
with torch.no_grad():
    for images, labels in train_loader:
        features = model(images)  # Shape: (batch, 2048)
        all_features.append(features)
        all_labels.append(labels)

X_train = torch.cat(all_features)  # (N, 2048)
y_train = torch.cat(all_labels)    # (N,)

Training Only the Classification Head

Once features are frozen, training becomes fast. The optimiser only updates the new head's weights. You can either train a simple nn.Linear layer in PyTorch, or even pass the pre-extracted feature vectors to scikit-learn's LogisticRegression or SVC — both approaches work well for linear classification on top of rich pre-trained features.

Using a single linear layer is equivalent to training a logistic regression on the extracted features. For more complex tasks or when your classes require non-linear decision boundaries, you can use a small multi-layer head with ReLU activations and dropout between the frozen backbone and the output.

import torch.nn as nn
import torch.optim as optim

# Option 1: Simple linear head (logistic regression on features)
classifier = nn.Linear(2048, num_classes)
optimizer = optim.Adam(classifier.parameters(), lr=1e-3)
criterion = nn.CrossEntropyLoss()

# Option 2: Small MLP head for more complex tasks
mlp_head = nn.Sequential(
    nn.Linear(2048, 512),
    nn.ReLU(),
    nn.Dropout(0.3),
    nn.Linear(512, num_classes)
)

# scikit-learn option (useful for small datasets)
from sklearn.linear_model import LogisticRegression
clf = LogisticRegression(max_iter=1000, C=1.0)
clf.fit(X_train.numpy(), y_train.numpy())

DataLoader and Transform Setup

During feature extraction, image preprocessing must match the transforms used when training the original model. For ImageNet pre-trained models this means: resize to 256, centre-crop to 224×224, convert to tensor, and normalise with ImageNet mean and std.

When you use weights.transforms(), PyTorch automatically provides the correct preprocessing pipeline associated with those specific weights. This eliminates a common source of subtle bugs where you accidentally use wrong normalisation constants, which can reduce transfer learning accuracy by several percentage points.

from torchvision import transforms, datasets
from torch.utils.data import DataLoader
import torchvision.models as models

weights = models.ResNet50_Weights.IMAGENET1K_V1
preprocess = weights.transforms()  # Includes correct resize, crop, normalize

train_dataset = datasets.ImageFolder('data/train', transform=preprocess)
val_dataset   = datasets.ImageFolder('data/val',   transform=preprocess)

train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True, num_workers=4)
val_loader   = DataLoader(val_dataset,   batch_size=32, shuffle=False, num_workers=4)

print('Classes:', train_dataset.classes)
print('Training samples:', len(train_dataset))

Training Speed Comparison

Feature extraction is dramatically faster than full fine-tuning. When all backbone parameters have requires_grad=False, PyTorch does not compute gradients through them during loss.backward(), saving memory and computation proportional to the number of frozen layers.

For ResNet-50 (25M parameters, 2048 frozen features, only ~2K parameters in the head), a training epoch on a 5000-image dataset completes in seconds on CPU, compared to minutes for full fine-tuning. Pre-extracting features offline and then training only the head as a standard sklearn classifier is even faster, since the backbone forward pass only runs once per image.

import time

# Measuring training time difference
# With frozen backbone (feature extraction):
start = time.time()
for batch in train_loader:
    images, labels = batch
    with torch.no_grad():
        features = backbone(images)  # Fast: no grad tracking
    loss = criterion(classifier(features), labels)
    loss.backward()  # Gradients only through tiny classifier
    optimizer.step()
    optimizer.zero_grad()
print(f'Feature extraction epoch: {time.time()-start:.1f}s')

# Full fine-tuning trains 25M params instead of ~2K

Adapting EfficientNet for Feature Extraction

The approach is the same for EfficientNet: freeze all parameters, then replace the final classification layer. For EfficientNet the classifier is a Sequential block accessed via model.classifier, not model.fc. Always check the model architecture to find the correct attribute name.

EfficientNet-B0's classifier expects 1280-dimensional input features. When writing code that works with multiple architectures, introspect the final layer with in_features instead of hard-coding the dimension, making your code more reusable across different backbone choices.

import torchvision.models as models
import torch.nn as nn

model = models.efficientnet_b0(weights=models.EfficientNet_B0_Weights.IMAGENET1K_V1)

# Freeze backbone
for param in model.parameters():
    param.requires_grad = False

# EfficientNet uses model.classifier, not model.fc
print('Old classifier:', model.classifier)
in_features = model.classifier[1].in_features  # Access Linear inside Sequential
model.classifier = nn.Linear(in_features, num_classes)

trainable = sum(p.numel() for p in model.parameters() if p.requires_grad)
print(f'Trainable parameters: {trainable:,}')

Adapting ViT for Feature Extraction

For ViT, the classification head is accessed via model.heads. The feature dimension from ViT-B/16's backbone is 768 (the transformer embedding dimension). After freezing all parameters, replace model.heads with a new nn.Linear(768, num_classes).

ViT benefits less from feature extraction than CNNs because its attention layers are more task-specific — they learn to attend to different image regions than what your task requires. If you use a ViT backbone, at minimum unfreeze the last few transformer encoder blocks for best performance. However, for a quick experiment, full feature extraction is still a valid starting point.

import torchvision.models as models
import torch.nn as nn

vit = models.vit_b_16(weights=models.ViT_B_16_Weights.IMAGENET1K_V1)

# Freeze all parameters
for param in vit.parameters():
    param.requires_grad = False

# Replace the classification head
print('Old head:', vit.heads)  # Sequential with Linear(768, 1000)
vit.heads = nn.Linear(768, num_classes)

print('ViT trainable params:', sum(p.numel() for p in vit.parameters() if p.requires_grad))

Evaluating Feature Extraction Results

After training with frozen features, evaluate on the validation set using standard classification metrics. A well-tuned feature extractor often achieves 90%+ accuracy on small custom datasets (500-5000 images per class) where training from scratch would overfit completely.

If accuracy is lower than expected, consider: (1) adding data augmentation during training, (2) using a dropout layer before the linear head, (3) using a slightly more expressive head (two linear layers with ReLU), or (4) moving to partial fine-tuning by unfreezing the last residual block. Monitor both train and validation accuracy to distinguish overfitting from underfitting.

from sklearn.metrics import classification_report
import torch

def evaluate(model, loader, device):
    model.eval()
    all_preds, all_labels = [], []
    with torch.no_grad():
        for images, labels in loader:
            images = images.to(device)
            logits = model(images)
            preds = logits.argmax(dim=1).cpu()
            all_preds.extend(preds.numpy())
            all_labels.extend(labels.numpy())
    print(classification_report(all_labels, all_preds,
                                target_names=class_names))

evaluate(model, val_loader, device)

When Feature Extraction Is Not Enough

Feature extraction works best when the source domain (ImageNet: natural photographs) and target domain are similar. When your data is very different — X-ray images, satellite imagery, microscopy, infrared thermal images — the low-level features still transfer (edge detectors are universal), but higher-level ImageNet features may be less useful.

Signs that feature extraction is underperforming: validation accuracy plateaus well below expectations, or train accuracy is much higher than validation (indicating the head is overfitting to too few features). In these cases, move to fine-tuning: unfreeze some backbone layers and train with a much lower learning rate to gradually adapt the pre-learned features to your domain.

Quick Check

Test your understanding of feature extraction with frozen backbones from this lesson.

Lesson Recap

In this lesson you learned: feature extraction freezes all backbone parameters and trains only a new classification head, giving fast training and strong results when your data resembles ImageNet, freezing is done by setting requires_grad=False on backbone parameters before replacing the final layer, and pre-extracting features offline is even faster by running the backbone once and caching the feature vectors. Next up we learn fine-tuning — how to carefully unfreeze backbone layers with low learning rates for even better accuracy.

Questions Fréquemment Posées

La leçon « Extraction de caractéristiques : geler le réseau de base » est-elle gratuite ?

Oui — le texte complet de « Extraction de caractéristiques : geler le réseau de base » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours Machine Learning Academy, passe à CoddyKit PRO. Le cours Machine Learning Academy comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « Extraction de caractéristiques : geler le réseau de base » ?

Vous gèlerez toutes les couches sauf la tête de classification finale, n’entraînerez que les nouvelles couches sur un petit jeu de données personnalisé et confirmerez la forte réduction du temps d’en… Tu pratiques Machine Learning Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer Machine Learning Academy ?

Aucune expérience préalable n'est requise. Machine Learning Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 2 sur 4.

Combien de temps prend la leçon « Extraction de caractéristiques : geler le réseau de base » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon Machine Learning Academy ?

Oui. Chaque leçon Machine Learning Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. Modèles préentraînés dans torchvision : ResNet, EfficientNet et ViT
  2. Extraction de caractéristiques : geler le réseau de base
  3. Ajustement fin : dégeler les couches et réduire le taux d’apprentissage
  4. Adaptation au domaine : imagerie médicale avec peu d’annotations
← Retour à Machine Learning Academy