IntroductionGenèse du projetIdentification des objetsArchitecture
DealTracker

DealTracker - Le problème de l'identification des objets

La véritable nature de cette tâche de Machine Learning

Le problème adressé par DealTracker, identifier de façon fiable des objets sur le marché de l'occasion, est un problème de classification d'images fine-grained marqué par un déséquilibre de classes extrêmes. C'est à dire que l'on cherche à identifier les images vendant un objet précis parmis un océan d'images diverses et variées publiées sur le marché de l'occasion. Les caractéristiques visuelles utilisées pour la différenciation sont souvent très fines (comme par exemple la disposition des boutons sur une enceinte).

Statistiquement, en passant des millions d'images en revue, il y en aura toujours qui feront douter votre modèle et seront classées comme des images d'intérêt. S'il s'agit ne serait-ce que de 0.01% des images, cela fait 100 fausses détections pour 1 000 000 images passées en revue, alors que vous en avez peut-être 50 qui sont bonnes.

Comment j'ai approché ce problème

L'entrainement sur un premier objet

Comme mentionné dans la page précédente, lorsque j'ai commencé à essayer de détecter des Aeron d'une manière précise, je me suis retrouvé face à un problème: mon modèle avait beaucoup de faux positifs, ce que je n'étais pas sûr de comprendre.

L'une de mes premières intuitions, c'est que si je n'avais pas de bons résultats, c'est parce que le modèle manquait de données d'entrainement. Les quelques exemples que je lui avait donné ne permettaient pas de définir précisément "ce qui est l'objet" et "ce qui n'est pas l'objet". Il me fallait donc plus de données, et bien sûr les données les plus pertinentes à fournir au modèle, ce sont ses propres erreurs. Car ces erreurs représentent des "trous" dans l'espace de décision du modèle, qu'il convient de combler.

Donc à ce moment là, mon procédé était le suivant:

  • Entrainer mon modèle
  • Faire de l'inférence sur une série d'images
  • Prendre les résultats, et les annoter
  • Réentrainer un modèle

Au départ, les erreurs du modèle étaient grossières, et les images n'avaient rien à voir avec la chaise de bureau que je tentais de reconnaitre. Puis petit à petit, des ressemblances ont commencé à apparaître. Une courbure, ou une forme qui ressemblait un peu à la chaise, que j'annotais systématiquement dans la catégorie "image non intéressante".

Je devais également rajouter des exemples de "vrais positifs" our éviter un trop gros déséquilibre au niveau de mon dataset, car j'ajoutais un nombre considérable de faux positifs dans la classe "non intéressante". Pour faciliter ces annotations, je clusterisais l'ensemble des images prédites. C'était assez fascinant, j'obtenais des clusters d'accoudoirs, des clusters de dossiers... que je triais par rapport à la distance au centre du cluster, les images se ressemblant le plus dans le cluster étaient donc regroupées. Je n'incluais pas les images qui ne montraient pas l'objet dans son ensemble, car le modèle devait apprendre à reconnaitre l'objet dans son ensemble, et pas ses sous parties individuellement.

Et puis finalement, je suis arrivé à un stade où chaque haque itération d'entrainement n'améliorait que très peu le modèle. À ce moment:

  • Le modèle était correct (pas parfait, mais la plupart de ses prédictions étaient exactes)
  • Ses erreurs étaient très compréhensible, car les images présentaient de grandes similitudes avec l'objet recherché

À ce moment là, j'ai donc décidé d'aller plus loin. J'ai expérimenté avec de nouvelles valeurs d'hyperparamètres et fonctions de perte. Mais surtout, j'ai cherché d'autres modèles qui seraient susceptibles de mieux apprendre sur cette tâche. J'ai donc analysé une série de modèles sur timm, cherchant le meilleur compromis entre qualité et vitesse d'apprentissage / inférence.

J'ai finalement décidé de mélanger les résultats des différents modèles, pour profiter des forces et des faiblesses de chacun. J'ai donc appliqué un niveau de stacking, c'est à dire que j'ai entrainé un méta-modèle pour faire la prédiction finale sur la base des résultats des premiers modèles.

L'ajout d'objets supplémentaires

À ce moment là, j'avais déjà fait un front-end opérationnel, et j'étais très content de mon radar à chaises d'occasions. Ce qu'il lui manquait, c'était plus de produits.

De nouveaux problèmes se sont posés en reproduisant le processus pour de nouveaux objets:

Comment annoter une image sur laquelle il y a deux objets différents ?

Dans une classification multi-classe, je n'ai pas de méthode pour gérer la détection simultanée de plusieurs objets d'intérêt.

Que faire alors ? Si je classe l'image comme une image d'intérêt, c'est une pente glissante pour mon modèle, qui doit désormais apprendre à favoriser une classe choisie d'une manière arbitraire en cas de détection multiple. Si je la classe comme "objet pertinent non détecté", ça n'est pas correct non plus, car les objets sont bel et bien présents.

Au final, j'ai décidé de en tout simplement pas annoter ces exemples, et de les classer dans la catégorie "image non intéressante" à l'inférence. C'est à dire que lorsque le modèle hésite entre deux classes, je sélectionne "image non intéressante" par défaut.

J'ai choisi de ne pas inclure d'images montrant des sous parties de l'objet, mais à partir de quel moment est-ce qu'on considère qu'il s'agit d'une sous partie ?

Là, la règle est simple: pour chaque objet, il faut trouver de véritables "indicateurs d'appartenance à la classe". Des caractéristiques visuelles précises qui permettent de savoir si l'objet appartient bien à la classe, ou non.

Par exemple, pour les enceintes Bose Soundlink Mini, j'ai déterminé que les indicateurs d'appartenance à la classe, ce sont les boutons sur le dessus de l'enceinte, qui doivent être clairement visibles. Toute image qui montre l'enceinte sans montrer ces boutons est considérée comme une image non intéressante.