YOLO Vision 2026 :

Comment affiner YOLO sur un jeu de données personnalisé#

Le fine-tuning adapte un modèle pré-entraîné pour reconnaître de nouvelles classes en partant de poids déjà appris plutôt que d'une initialisation aléatoire. Au lieu d'entraîner à partir de zéro pendant des centaines d'époques, le fine-tuning exploite des caractéristiques pré-entraînées COCO et converge sur des données personnalisées en une fraction du temps.

Ce guide couvre le fine-tuning de YOLO26 sur des jeux de données personnalisés, de l'utilisation de base aux techniques avancées comme le gel des couches et l'entraînement en deux étapes.

Fine-tuning vs entraînement à partir de zéro#

Un modèle pré-entraîné a déjà appris des caractéristiques visuelles générales — détection de contours, reconnaissance de textures, compréhension des formes — à partir de millions d'images. Le transfer learning par le biais du fine-tuning réutilise ces connaissances et enseigne uniquement au modèle à quoi ressemblent les nouvelles classes, ce qui explique pourquoi il converge plus rapidement et nécessite moins de données. S'entraîner à partir de zéro jette tout cela aux oubliettes et force le modèle à tout apprendre depuis les motifs au niveau des pixels, ce qui demande nettement plus de ressources.

Fine-TuningEntraînement à partir de zéro
Poids de départPré-entraîné sur COCO (80 classes)Initialisation aléatoire
CommandeYOLO("yolo26n.pt")YOLO("yolo26n.yaml")
ConvergencePlus rapide - le backbone est déjà entraînéPlus lente - toutes les couches apprennent de zéro
Exigences en donnéesPlus faibles - les caractéristiques pré-entraînées compensent le manque de donnéesPlus élevées - le modèle doit apprendre toutes les caractéristiques à partir du jeu de données seul
Quand utiliserClasses personnalisées avec des images naturellesDomaines fondamentalement différents de COCO (médical, satellite, radar)
Le fine-tuning ne nécessite aucun code supplémentaire

Lorsqu'un fichier .pt est chargé avec YOLO("yolo26n.pt"), les poids pré-entraînés sont stockés dans le modèle. L'appel de .train(data="custom.yaml") par la suite transfère automatiquement tous les poids compatibles vers la nouvelle architecture du modèle, réinitialise toutes les couches qui ne correspondent pas (telles que la tête de détection lorsque le nombre de classes diffère) et lance l'entraînement. Aucun chargement manuel des poids, manipulation de couches ou code de transfer learning personnalisé n'est requis.

Comment fonctionne le transfert de poids pré-entraînés#

Lorsqu'un modèle pré-entraîné est affiné sur un jeu de données avec un nombre différent de classes (par exemple, 80 classes COCO vers 5 classes personnalisées), Ultralytics effectue un transfert de poids conscient de la forme :

  1. Le backbone et le neck sont entièrement transférés - ces couches extraient des caractéristiques visuelles générales et leurs formes sont indépendantes du nombre de classes.
  2. La tête de détection est partiellement réinitialisée : les couches de sortie de classification (cv3, one2one_cv3) ont des formes liées au nombre de classes (80 contre 5), elles ne peuvent donc pas être transférées et sont initialisées aléatoirement. Les couches de régression de boîtes englobantes (cv2, one2one_cv2) dans la tête ont des formes fixes quel que soit le nombre de classes, elles se transfèrent donc normalement.
  3. La grande majorité des poids sont transférés lors du changement de nombre de classes. Par exemple, l'affinage de YOLO26n depuis COCO (80 classes) vers un jeu de données à 5 classes transfère 606 des 708 tenseurs de poids : seules les couches de classification dépendantes du nombre de classes sont réinitialisées, tandis que le backbone, le neck et les branches de régression de boîte restent intacts.

Pour les jeux de données ayant le même nombre de classes que le modèle pré-entraîné (par exemple, l'affinage de poids pré-entraînés sur COCO sur un autre jeu de données à 80 classes), 100 % des poids sont transférés, y compris la tête de détection.

Transférer des classes avec des alias de noms#

Ultralytics transfère les lignes de classification correspondantes par nom de classe entre les jeux de données, en ignorant la casse et les espaces environnants. Lorsque des classes équivalentes utilisent des noms différents, renomme les classes du checkpoint source en mémoire avant le chargement. Cela préserve les poids de classification pré-entraînés pour les concepts partagés qui seraient autrement traités comme non correspondants et initialisés aléatoirement.

Cet exemple Objects365 v2 vers COCO renomme les classes source sur le point de contrôle chargé, que train() transmet ensuite en tant que poids pré-entraînés :

from ultralytics import YOLO

# Source Objects365 v2 name -> target COCO name
ALIASES = {
    "wild bird": "bird",
    "handbag/satchel": "handbag",
    "luggage": "suitcase",
    "bowl/basin": "bowl",
    "orange/tangerine": "orange",
    "monitor/tv": "tv",
    "stuffed toy": "teddy bear",
    "hair dryer": "hair drier",
}

model = YOLO("path/to/yolo26s-objects365.pt")
model.model.names = {i: ALIASES.get(name, name) for i, name in model.model.names.items()}
model.train(data="coco.yaml", epochs=100, imgsz=640)

Exemple de fine-tuning de base#

Exemple
from ultralytics import YOLO

model = YOLO("yolo26n.pt")  # load pretrained model
model.train(data="custom.yaml", epochs=50, imgsz=640)

Choisir une taille de modèle#

Les modèles plus grands offrent plus de capacité mais aussi davantage de paramètres à mettre à jour, ce qui peut accroître le risque de surapprentissage lorsque les données d'entraînement sont limitées. Commencer avec un modèle plus petit (YOLO26n ou YOLO26s) et monter en puissance uniquement si les métriques de validation stagnent est une approche pragmatique. La taille de modèle optimale dépend de la complexité de la tâche, du nombre de classes, de la diversité du jeu de données et du matériel disponible pour le déploiement. Consulte la page du modèle YOLO26 complète pour connaître les tailles disponibles et les benchmarks de performance.

Sélection de l'optimiseur et du taux d'apprentissage#

Le paramètre par défaut optimizer=auto sélectionne l'optimiseur et le taux d'apprentissage en fonction du nombre total d'itérations d'entraînement :

  • < 10 000 itérations (petits jeux de données ou peu d'époques) : AdamW avec un taux d'apprentissage faible et calculé automatiquement
  • > 10 000 itérations (grands jeux de données) : MuSGD (un optimiseur hybride Muon+SGD) avec lr=0,01

Pour la plupart des tâches de fine-tuning, le paramètre par défaut fonctionne bien sans aucun réglage manuel. Envisage de définir l'optimiseur explicitement lorsque :

  • L'entraînement est instable (pics de perte ou divergence) : essaie optimizer=AdamW, lr0=0.001 pour une convergence plus stable
  • Fine-tuning d'un grand modèle sur un petit jeu de données : un taux d'apprentissage plus faible comme lr0=0.001 aide à préserver les caractéristiques pré-entraînées
L'optimiseur auto remplace le lr0 manuel

Quand optimizer=auto, les valeurs lr0 et momentum sont ignorées. Pour contrôler manuellement le taux d'apprentissage, définis explicitement l'optimiseur : optimizer=SGD, lr0=0.005.

Geler les couches#

Le gel empêche des couches spécifiques de se mettre à jour pendant l'entraînement. Cela accélère l'entraînement et réduit le surapprentissage lorsque le jeu de données est petit par rapport à la capacité du modèle.

Le paramètre freeze accepte soit un entier, soit une liste. Un entier freeze=10 gèle les 10 premières couches (indices 0 à 9), ce qui couvre l'essentiel du backbone YOLO26. Le backbone s'étend des couches 0 à 10, donc freeze=10 laisse le dernier bloc C2PSA (couche 10) entraînable ; utilise freeze=11 pour geler l'intégralité du backbone. Une liste peut contenir des indices de couches comme freeze=[0, 3, 5] pour un gel partiel du backbone, ou des chaînes de caractères de noms de modules comme freeze=["23.cv2", "23.one2one_cv2"] pour un contrôle fin sur des branches spécifiques au sein d'une couche (ici, les deux branches de régression de boîtes englobantes de la tête de détection).

Exemple
model.train(data="custom.yaml", epochs=50, freeze=10)

La profondeur de gel appropriée dépend de la similitude du domaine cible avec les données pré-entraînées et de la quantité de données d'entraînement disponibles :

ScénarioRecommandationJustification
Grand jeu de données, domaine similairefreeze=None (par défaut)Assez de données pour adapter toutes les couches sans surapprentissage
Petit jeu de données, domaine similairefreeze=10Préserve les caractéristiques du backbone, réduit les paramètres entraînables
Très petit jeu de donnéesfreeze=23Seule la tête de détection s'entraîne, minimisant le risque de surapprentissage
Domaine éloigné de COCOfreeze=NoneLes caractéristiques du backbone peuvent ne pas bien se transférer et nécessitent un réentraînement

La profondeur de gel peut aussi être traitée comme un hyperparamètre - essayer quelques valeurs (0, 5, 10) et comparer le mAP de validation est un moyen pratique de trouver le meilleur réglage pour un jeu de données spécifique.

Hyperparamètres clés pour le fine-tuning#

Le fine-tuning nécessite généralement moins d'ajustements d'hyperparamètres qu'un entraînement à partir de zéro. Les paramètres qui comptent le plus sont :

  • epochs : Le fine-tuning converge plus rapidement qu'un entraînement à partir de zéro. Commence avec une valeur modérée et utilise patience pour arrêter l'entraînement prématurément lorsque les métriques de validation stagnent.
  • patience : La valeur par défaut de 100 est conçue pour de longs cycles d'entraînement. La réduire à 10-20 évite de perdre du temps sur des exécutions qui ont déjà convergé.
  • warmup_epochs : L'échauffement (warmup) par défaut (3 époques) augmente progressivement le taux d'apprentissage à partir de zéro, ce qui évite que de grandes mises à jour de gradients n'endommagent les caractéristiques pré-entraînées lors des premières itérations. Conserver la valeur par défaut est recommandé, même pour le fine-tuning.

Pour consulter la liste complète des paramètres d'entraînement, reporte-toi à la référence de la configuration d'entraînement.

Fine-tuning en deux étapes#

Le fine-tuning en deux étapes divise l'entraînement en deux phases. La première étape gèle le backbone et n'entraîne que le neck et la tête, permettant aux couches de détection de s'adapter aux nouvelles classes sans perturber les caractéristiques pré-entraînées. La seconde étape dégèle toutes les couches et entraîne le modèle complet avec un taux d'apprentissage plus faible pour affiner le backbone pour le domaine cible.

Cette approche est particulièrement utile lorsque le domaine cible diffère significativement de COCO (images médicales, imagerie aérienne, microscopie), cas dans lesquels le backbone peut nécessiter une adaptation, mais où tout entraîner en même temps provoque de l'instabilité. Pour un dégel automatique avec une approche basée sur un callback, consulte Gel et dégel du backbone.

Fine-tuning en deux étapes
from ultralytics import YOLO

# Stage 1: freeze backbone, train head and neck
model = YOLO("yolo26n.pt")
model.train(data="custom.yaml", epochs=20, freeze=10, name="stage1", exist_ok=True)

# Stage 2: unfreeze all, fine-tune with lower lr
model = YOLO("runs/detect/stage1/weights/best.pt")
model.train(data="custom.yaml", epochs=30, lr0=0.001, name="stage2", exist_ok=True)

Pièges courants#

Le modèle ne produit aucune prédiction#

  • Données d'entraînement insuffisantes : l'entraînement avec très peu d'échantillons est la cause la plus fréquente - le modèle ne peut pas apprendre ou généraliser à partir de trop peu de données. Assure-toi d'avoir suffisamment d'exemples diversifiés par classe avant d'enquêter sur d'autres causes.
  • Vérifie les chemins des jeux de données : des chemins incorrects dans data.yaml génèrent silencieusement zéro étiquette. Exécute yolo detect val model=yolo26n.pt data=custom.yaml avant l'entraînement pour confirmer que les étiquettes se chargent correctement.
  • Abaisse le seuil de confiance : si des prédictions existent mais sont filtrées, essaie conf=0.1 pendant l'inférence.
  • Vérifie le nombre de classes : assure-toi que nc dans data.yaml correspond au nombre réel de classes dans les fichiers d'étiquettes.

Le mAP de validation stagne tôt#

  • Ajoute plus de données : le fine-tuning bénéficie considérablement de données d'entraînement supplémentaires, surtout d'exemples diversifiés avec des angles, éclairages et arrière-plans variés.
  • Vérifie l'équilibre des classes : les classes sous-représentées auront un AP faible. Utilise cls_pw pour appliquer une pondération de classe par fréquence inverse (commence avec cls_pw=0.25 pour un déséquilibre modéré, augmente à 1.0 pour un déséquilibre sévère).
  • Réduis l'augmentation : pour de très petits jeux de données, une forte augmentation peut nuire plus qu'elle ne  aide. Essaie mosaic=0.5 ou mosaic=0.0.
  • Augmente la résolution : pour les jeux de données comportant de petits objets, essaie imgsz=1280 pour préserver les détails.

La performance se dégrade sur les classes originales après le fine-tuning#

Ceci est connu sous le nom d'oubli catastrophique - le modèle perd des connaissances précédemment apprises lorsqu'il est affiné exclusivement sur de nouvelles données. L'oubli est pratiquement inévitable sans inclure des images du jeu de données original avec les nouvelles données. Pour atténuer cela :

  • Fusionne les jeux de données : inclus des exemples des classes originales avec les nouvelles classes lors du fine-tuning. C'est le seul moyen fiable d'éviter l'oubli.
  • Gèle le backbone et le neck : geler à la fois le backbone et le neck pour que seule la tête de détection s'entraîne aide pour les sessions de fine-tuning courtes avec un taux d'apprentissage très faible.
  • Entraîne sur moins d'époques : plus le modèle s'entraîne exclusivement sur de nouvelles données, plus l'oubli augmente.

FAQ#

  • Il n'y a pas de minimum fixe - les résultats dépendent de la complexité de la tâche, du nombre de classes et de la similitude du domaine avec COCO. Des images plus diversifiées (éclairage, angles, arrière-plans variés) comptent plus que la quantité brute. Commence avec ce que tu as et augmente si les métriques de validation sont insuffisantes.

  • Charge un fichier .pt pré-entraîné et appelle .train() avec le chemin d'un fichier data.yaml personnalisé. Ultralytics gère automatiquement le transfert des poids, la réinitialisation de la tête de détection et la sélection de l'optimiseur. Consulte la section Fine-Tuning de Base pour l'exemple de code complet.

  • Les causes les plus fréquentes sont des chemins incorrects dans data.yaml (ce qui produit silencieusement zéro étiquette), une non-correspondance entre nc dans le fichier YAML et les fichiers d'étiquettes réels, ou un seuil de confiance trop élevé. Consulte les Pièges courants pour une liste de contrôle complète de dépannage.

  • Cela dépend de la taille du jeu de données et de la similarité des domaines. Pour les petits jeux de données avec un domaine similaire à COCO, geler le backbone (freeze=10) évite le surapprentissage. Pour des domaines très différents de COCO, laisser toutes les couches non gelées (freeze=None) permet au backbone de s'adapter. Consulte Gel des couches pour des recommandations détaillées.

  • Inclus des exemples des classes d'origine dans les données d'entraînement aux côtés des nouvelles classes. Si ce n'est pas possible, geler davantage de couches (freeze=10 ou plus) et utiliser un taux d'apprentissage plus faible aide à préserver les connaissances pré-entraînées. Consulte Les performances se dégradent sur les classes d'origine pour plus de détails.

Commentaires