Transfert de recette CV
Porter des travaux CV publiés sur les données client sans hériter des bugs silencieux qui rendent les nombres résultants dénués de sens.
L'idée centrale
Ce travail se divise en deux phases avec un statut épistémique fondamentalement différent :
- Phase A (Port) — faire fonctionner le code officiel fidèlement. Il existe une vérité au sol externe ici : le checkpoint publié par les auteurs et le nombre rapporté.
- Phase B (Transfert) — déplacer la recette sur les données client. Il n'y a pas de vérité au sol externe. Le nombre du papier cesse d'être significatif dès que l'ensemble de données change.
Tout ce qui est vérifiable doit être vérifié en Phase A, car le filet de sécurité disparaît à la frontière. Une fois en Phase B, un bug d'implémentation et une vraie inadéquation de domaine produisent des symptômes identiques : un nombre médiocre avec une courbe de perte propre.
Deux conséquences qui gouvernent tout ce qui suit :
- Ne sautez jamais la porte Phase A pour « gagner du temps ». Cela coûte des heures et c'est la seule chose qui autorise la confiance dans chaque nombre qui suit.
- Arrêtez de traiter le nombre du papier comme la cible une fois l'ensemble de données changé. La cible est battre la ligne de base bon marché la plus forte sur l'ensemble de test du client, mesuré à un point d'exploitation délibérément choisi.
Sélection du mode
Lisez la demande et choisissez un mode. Dites lequel vous avez choisi et pourquoi.
Mode post-mortem — une exécution a déjà eu lieu et le résultat était mauvais, décevant ou suspecieusement bon. Allez à references/postmortem.md. Ne commencez pas par relancer quoi que ce soit. Parcourez les vérifications par ordre de probabilité et trouvez la porte qui a été sautée.
Mode forward — aucune exécution encore, ou recommencer. Travaillez Phase 0 → A → G → T → R → E ci-dessous.
Mode audit — un pipeline existe et fonctionne, quelqu'un veut qu'il soit vérifiée avant de le proposer à un client. Exécutez la porte Phase A et le rapport Phase G sur les artefacts existants, puis les scripts de parité et de fuite. Sautez le travail de portage.
Si la demande est ambiguë, demandez lequel des trois c'est avant de faire quoi que ce soit de coûteux.
Phase 0 — Porte de faisabilité
Bon marché, et cela prévient la classe d'erreur la plus coûteuse. Faites-le avant de lire tout code.
Posez-vous et répondez, par écrit :
- Est-ce que cela nécessite un entraînement du tout ? Les modèles zero-shot et promptables couvrent une grande partie de ce qui avait l'habitude de nécessiter un fine-tune — Grounding DINO, SAM-family, OWL-ViT, CLIP, et les détecteurs COCO pré-entraînés simples. Si les classes du client chevauchent le vocabulaire COCO/LVIS, ou si la tâche est « trouver l'objet évident », mesurez d'abord une ligne de base pré-entraînée. Une fraction surprenante des projets de fine-tuning de trois semaines sont résolus par une après-midi de prompting.
- Est-ce le bon papier ? Les papiers sont choisis par rang sur benchmark, mais le rang sur COCO prédit très peu la performance sur 800 images de pièces d'usine. Vérifiez que le benchmark du papier ressemble aux données du client sur les axes en Phase G.
- Licence. Les clauses research-only, non-commercial et AGPL sont courantes dans les repos CV et c'est du travail orienté client. Vérifiez la licence du repo, la licence des poids (souvent différente du code), et la licence de tout backbone pré-entraîné. C'est une porte dure — signalez-la maintenant, pas après trois semaines de travail.
- Y a-t-il assez de données étiquetées, et existe-t-il un ensemble de test qui reflète la production ? Si les seules données sont une export aléatoire, l'ensemble de test sera optimiste peu importe ce que vous faites.
Enregistrez les réponses. Si la porte de faisabilité échoue, dites-le clairement et arrêtez — c'est un résultat réussi de cette compétence, pas un échec.
Phase A — Port
Objectif : prouver que le code, le pipeline de données, le prétraitement et l'implémentation des métriques sont tous fidèles. Lisez references/port-gate.md pour la procédure détaillée.
La porte, en bref :
- Épinglez le commit. Les repos dérivent et le code publié diffère régulièrement du papier. Épinglez le hash. Ensuite, lisez les threads de problèmes du repo — hyperparamètres non documentés, incohérences connues avec le papier, et « pourquoi ne puis-je pas reproduire le Tableau 2 » vivent là. Supposez que le code et le papier ne s'accordent pas quelque part jusqu'à preuve du contraire.
- Construisez l'environnement. Les ops CUDA personnalisés (attention déformable, DCN, NMS personnalisé) dans les repos de recherche plus anciens sont le plus grand goulet d'étranglement spécifique à CV. Détectez-les tôt et containerisez. Ne combattez pas la chaîne d'outils hôte.
- LA PORTE : lancez leur checkpoint via leur eval sur leur benchmark et faites correspondre le nombre rapporté. Cette seule vérification valide l'environnement, le pipeline de données, le prétraitement et l'implémentation des métriques sans entraîner quoi que ce soit. Des heures, pas des jours.
- Faire correspondre à ~0,2 points près : passer.
- Décalé de 0,5–2 points : quelque chose dans le prétraitement ou la config d'eval est mauvais. Ne pas continuer.
- Décalé beaucoup : mauvais checkpoint, mauvaise correspondance de classes, ou un chargement de dict d'état silencieusement partiel. Voir l'atlas des défaillances.
- Validez le chemin d'entraînement avec une courte exécution sur un sous-ensemble de benchmark. Vous vérifiez la forme de la courbe de perte et qu'elle descend comme prévu, pas le nombre final.
- Balayez les hypothèses de benchmark codées en dur. Le code officiel est écrit pour exactement un ensemble de données. Les nombres de classes, les constantes de normalisation, les priors d'ancrage, la structure des chemins, et parfois la taille de l'image sont intégrés — occasionnellement à l'intérieur de la définition du modèle plutôt que de la config. Les trouver tous est l'essentiel du travail de portage.
references/port-gate.mda les motifs grep.
Ne pas entrer en Phase B jusqu'à ce que l'étape 3 réussisse. Si cela ne peut pas réussir, dites-le et rapportez l'écart — « ce repo ne reproduit pas son propre papier » est une conclusion légitime et précieuse.
Phase G — Rapport sur l'écart de domaine
Rendez l'écart mesurable plutôt qu'supposé. Exécutez :
python scripts/domain_gap_report.py --source <source_annotations> --target <target_annotations> --out gap_report.md
Il compare le benchmark source et l'ensemble client sur le nombre d'images, la résolution et la distribution d'aspect, les objets par image, l'équilibre des classes, et — le plus important — la taille de l'objet en tant que fraction de la zone de l'image.
Cet axe dernier drive plus de décisions de recette que n'importe quel autre. Les objets COCO représentent en moyenne quelques pour-cent de la zone de l'image. Si l'imagerie aérienne, de microscopie ou d'inspection du client les place à 0,1 %, cela implique immédiatement la résolution d'entrée, l'affectation du niveau FPN, les échelles d'ancrage, et exclut l'augmentation de style mosaïque. Le script émet ceux-ci comme des drapeaux explicites avec des raisons, pas des avertissements génériques.
L'ampleur de l'écart sur chaque axe vous dit quels champs de recette en Phase T sont à risque. Portez les drapeaux vers l'avant — ce sont la justification pour chaque déviation du papier.
Exécutez aussi la vérification d'hygiène de la division ici, avant tout entraînement :
python scripts/split_leakage_check.py --splits train=<dir> val=<dir> test=<dir> --report leakage.md
Les images quasi-dupliquées dans les divisions sont la plus grande source unique de nombres CV gonflés. Les images vidéo échantillonnées à 5fps, la même scène d'une caméra fixe, le même patient, le même lot de production — une division aléatoire donne 0,95 mAP et un modèle qui s'effondre lors du déploiement. Détectable via hachage perceptif et métadonnées de groupe ; presque personne ne vérifie. Si cette compétence fait bien une chose, que ce soit ceci.
Phase T — Transférer la recette
Le cœur intellectuel. Classifiez chaque champ de la recette du papier dans l'un de trois compartiments avant d'écrire une config. references/recipe-fields.md a la table complète champ par champ ; les compartiments sont :
- Transfer-invariant — architecture, formulation de la perte, choix de l'optimiseur, la plupart des types d'augmentation. Reporter sans changement.
- Scale-dependent — durée du planning, LR (via taille de batch et mise à l'échelle linéaire), force d'augmentation, décroissance de poids, décroissance EMA. Doit être ajusté à la taille de l'ensemble de données, et la direction d'ajustement est généralement prévisible.
- Dataset-derived — priors de taille d'ancrage et de boîte, résolution d'entrée, pondération des classes, affectation du niveau FPN, seuils NMS/score. Doit être recalculé à partir des données du client, jamais copié.
Le piège qui attrape presque tout le monde
Si vous initialisez à partir du checkpoint publié des auteurs — ce que vous devriez presque toujours faire sur un petit ensemble de données client — leur planning est mauvais pour vous d'un grand facteur. Leur recette suppose l'initialisation ImageNet ou l'entraînement from-scratch sur 118k images. Vous êtes en fine-tuning sur 2 000. Copier le planning de 300 épochs du papier est une erreur courante, coûteuse et entièrement prévisible. Attendez-vous à : planning beaucoup plus court, LR plus bas (souvent 10x), réchauffage plus court, possiblement une tige gelée, et augmentation plus faible.
Énoncez l'initialisation explicitement dans la config et dérivez le planning à partir de celle-ci. Si vous ne pouvez pas dire en une phrase si vous faites du fine-tuning ou un entraînement from-scratch, arrêtez et résolvez cela d'abord.
Le prétraitement est un artefact unique
Écrivez la spec de prétraitement — politique de redimensionnement (letterbox vs stretch), ordre des canaux, constantes de normalisation, ordonnancement d'augmentation — dans un fichier que le pipeline d'entraînement, le chemin d'eval et le chemin d'export lisent tous. Ensuite, vérifiez numériquement :
python scripts/preprocess_parity.py --config <preproc.yaml> --image <sample.jpg> --paths train,eval,export
L'inadéquation du prétraitement entre l'entraînement et l'inférence est le mode de défaillance qui tue réellement les déploiements : mAP de validation excellent, garbage en production, et une longue boucle de débogage car rien ne signale jamais d'erreur. Affirmez l'égalité des tenseurs plutôt que de faire confiance à deux chemins de code faisant la même chose.
Phase R — Exécuter
Appliquez l'échelle de vérification de references/verification-ladder.md avant de dépenser de vraies heures GPU. Abrégé :
- Trace de forme et dtype ; nombre de paramètres par rapport au compte indiqué du papier
- Perte à l'initialisation égale sa valeur analytique
- Flux de gradient — chaque paramètre qui devrait avoir un gradient l'a, rien n'est silencieusement gelé
- Surapprenez un seul batch vers une perte quasi-nulle. Si ce n'est pas possible, le pipeline est mauvais, point final
- Surapprenez ~100 images ; confirmez que le chemin d'eval convient avec le chemin d'entraînement sur ces données
- Planning court à l'échelle réduite ; vérifiez la tendance
- Exécution complète
Échouez tôt, échouez bon marché. La plupart des catastrophes sont un mauvais pipeline entraîné pendant trois jours.
Parallèlement à la piste complète, gardez une suite de régression : la ligne de base pré-entraînée de Phase 0 et tout modèle précédent meilleur, évalués sur le même ensemble de test gelé. Enregistrez la version du jeu de données, la config et le hash du commit ensemble afin que tout checkpoint soit reproductible.
Phase E — Évaluer et rapporter
Choisissez un point d'exploitation. Tout le monde rapporte mAP@50-95 puis déploie à un seuil de confiance que personne n'a choisi délibérément. Sélectionnez le seuil à partir de la courbe PR par rapport au compromis précision/rappel réel du client — le coût d'une omission par rapport à une fausse alerte est une question métier, posez-la — et rapportez des métriques à ce seuil aux côtés de l'agrégat.
Ventillez, ne moyennez pas. Par classe et par tranche (taille de l'objet, éclairage, caméra, site, heure de la journée). Un seul mAP cache le fait que le modèle échoue complètement sur la seule classe que le client se soucie.
Analyse d'erreurs. Pour la détection, séparez les erreurs de classification, les erreurs de localisation, les doublons, les faux positifs de fond et les détections manquées — ils ont des fixes différentes. Les faux positifs à haute confiance sont souvent des annotations manquantes, pas des erreurs de modèle : une boîte manquante n'est pas une étiquette manquante, c'est une étiquette mauvaise, et le modèle a été explicitement enseigné à supprimer cet objet. Alimentez-les en arrière dans le QA d'annotation.
Artefact de statut — émettez-en un à chaque évaluation, y compris pendant l'exécution. Écrivez status.json et rendez-le :
python scripts/render_status.py --status status.json --out status.html
Il montre exactement deux choses : le delta par rapport au papier en haut, et le meilleur résultat jusqu'à présent contre sa ligne de base en bas. assets/status.example.json est le schéma par exemple. Deux règles qui le rendent honnête :
- Une métrique que le papier n'a jamais publiée reçoit
"paper": null, qui rend commen/psans delta. Ne remplissez jamais cette colonne avec un nombre d'une variante différente ou d'un blog post. - Si l'ensemble de données client n'a aucun résultat publié — le cas normal — dites-le dans
calloutet nommez ce contre quoi la comparaison est réellement. « versus la piste précédente » et « versus un résultat publié » sont des affirmations différentes.
Mid-run est un état de première classe : étiquetez les cartes still climbing et dites-le dans la note de bas de page, afin que personne ne cite un nombre partiel comme final.
Structure du rapport — utilisez ce modèle :
# <Task> recipe transfer: <paper> → <customer dataset>
## Outcome
Un paragraphe. Le nombre, au point d'exploitation choisi, par rapport à la ligne de base.
## Phase A verification
Le checkpoint officiel a-t-il reproduit le nombre rapporté ? Chiffres exacts.
## Domain gap
L'écart mesuré et quels champs de recette il nous a forcé à changer.
## Recipe deviations
Tableau : champ | valeur du papier | notre valeur | compartiment | raison.
## Results
Par classe et par tranche au seuil choisi. Courbe PR. Régression par rapport à la ligne de base.
## Error analysis
Catégories de défaillance avec nombres et exemples.
## Known risks
Ce que nous n'avons pas pu vérifier, et ce qui changerait la conclusion.
La section « Known risks » n'est pas optionnelle. C'est la différence entre un nombre qu'un client peut agir et un nombre qui embarrassera quelqu'un dans trois mois.
Fichiers de référence
Lisez ceux-ci au besoin plutôt que d'avance :
references/postmortem.md— diagnostiquez une piste échouée. Ordonnée par symptôme, vérifications les moins chères d'abord. Commencez ici en mode post-mortem.references/port-gate.md— Détail Phase A : épinglage de commit, survie de l'op CUDA, procédure de porte de checkpoint, motifs grep d'hypothèse codée en dur.references/recipe-fields.md— la table complète de classification des champs, par famille de tâches.references/verification-ladder.md— les sept échelons, avec les valeurs analytiques attendues.references/failure-atlas.md— symptôme → cause → vérification, pour les ~25 défaillances récurrentes.references/stacks.md— notes spécifiques au framework : repo de recherche brut, MMDetection / Detectron2, Ultralytics, timm / torchvision, TAO. Lisez uniquement le pertinent.
Scripts
scripts/domain_gap_report.py— écart source-vs-cible quantifié avec drapeaux de risquescripts/split_leakage_check.py— détection de quasi-doublons par hachage perceptif via les divisionsscripts/preprocess_parity.py— affirmation numérique que le prétraitement train/eval/export convientscripts/render_status.py— l'artefact de statut Phase E : delta du papier + meilleur résultat jusqu'à présent
Exécutez-les avec --help pour les options. Les trois premiers sont légers en dépendances (numpy + Pillow) et render_status.py est stdlib uniquement, afin que tous les exécutent à l'intérieur du conteneur d'un repo de recherche sans perturber son environnement.
Cadrage honnête
Pour une tâche privée du client il n'y a pas de SOTA. Il n'y a aucun classement pour « trouver les défauts dans les pièces de ce client ». Il y a uniquement la ligne de base et votre nombre. Donc ne promettez pas l'état de l'art ; promettez un résultat bien validé sans bugs méthodologiques, défendable par quelqu'un qui veut l'examiner.
C'est worth plus que ça ne semble, car une grande part des résultats de fine-tuning impressionnants sont gonflés par la fuite de test, l'évaluation sur la distribution d'entraînement, ou la comparaison avec une ligne de base délibérément faible. Ces erreurs sont mécaniques, et cette compétence existe pour les attraper.