Comment nous avons construit une fonction de recherche de similarité visuelle de données

Comment nous avons construit une fonction de recherche de similarité visuelle de données

Comme nous l'avons vu dans notre dernier article , l'exploration et le filtrage des données font partie des caractéristiques essentielles d'un système de gestion des données efficace. Nous le défendons depuis longtemps, mais nous n'avons jamais eu le temps d'ajouter cette fonctionnalité à notre plateforme. Ce temps est révolu ! 

Dans cet article, nous vous expliquerons le concept général de l'intégration d'images et comment nous avons mis en œuvre notre fonction de recherche visuelle évolutive pour trouver des images similaires parmi des millions d'images pour plusieurs clients en même temps.

Qu'est-ce qu'un embarquement ?

Les encastrements sont un moyen de mettre en correspondance des variables discrètes avec des nombres continus. Dans le contexte des réseaux neuronaux, les embeddings sont des représentations vectorielles à faible dimension de variables catégorielles.

Les encastrements de réseaux neuronaux permettent d'avoir des voisins proches dans l'espace et peuvent être utilisés pour faire des recommandations basées sur les intérêts de l'utilisateur, des catégories de grappes, ou des entrées dans des modèles d'apprentissage automatique pour des tâches supervisées qui nécessitent des vecteurs en entrée, comme des tâches de classification qui utilisent des étiquettes apprises à partir de données étiquetées (comme la détection de spam). 

La visualisation intégrée est utile car elle permet aux gens de voir les concepts et les relations entre les différentes catégories d'un ensemble de données donné, plus clairement que ne le font les méthodes traditionnelles, en réduisant la dimensionnalité sans perdre les informations sur ce qui est représenté.

Ici, notre objectif est de tirer parti des encastrements pour identifier rapidement les similarités dans les images (sans information a priori sur les caractéristiques de similarité).

Comment générer des incorporations d'images ?

Descripteurs basés sur la transformation

Vous disposez de plusieurs stratégies pour générer vos incorporations d'images. L'objectif est de sélectionner un ensemble de caractéristiques qui représenteront vos images de la meilleure façon possible. Pour ce faire, vous pouvez utiliser des descripteurs classiques comme SIFT (Scale-Invariant Feature Transform) ou SURF (Speeded Up Robust Features). Ces approches se concentrent sur l'identification et la mise en correspondance des points d'intérêt, ce qui est un excellent moyen de trouver des objets similaires dans une image qui se trouvent dans des positions différentes.

Voici une bonne introduction à SURF !

Pour les générer, vous pouvez utiliser OpenCV. Voici un lien vers un tutoriel OpenCV sur le calcul des SURF.

Veuillez noter que les algorithmes SURF et SIFT sont brevetés et ne peuvent pas être utilisés commercialement. Une excellente alternative peut être ORB (Oriented FAST and Rotated BRIEF). 

Descripteurs basés sur les réseaux de convolution

Comme nous l'avons vu, les descripteurs classiques sont parfaits pour identifier tout type de transformation et faire correspondre deux images qui se ressemblent beaucoup. Mais, si vous voulez créer une recherche de similarité plus symbolique, vous aurez besoin d'une autre méthode.

C'est pourquoi les réseaux neuronaux convolutifs sont si puissants. Au cours des dix dernières années, les modèles d'apprentissage profond ont atteint des niveaux de précision très élevés pour classer les images. Ces réseaux convolutifs d'apprentissage profond peuvent être utilisés pour extraire des caractéristiques des images qui sont invariantes, non seulement lorsqu'il s'agit de transformation géométrique, mais aussi dans l'instance elle-même ! Qu'est-ce que cela signifie ? Deux images de la même catégorie auront la même représentation. 

L'objectif est d'utiliser le vecteur de caractéristiques généré par l'extracteur de caractéristiques ConvNet, pour construire un espace vectoriel correspondant à toutes les images de votre ensemble. 

Il existe tellement de modèles ConvNet qu'il est devenu complexe de décider lequel utiliser. Lors de la création d'une fonction de recherche visuelle évolutive, vous devrez générer différents embeddings au fil du temps pour l'ensemble de votre lac de données. C'est donc une bonne idée de trouver un bon compromis entre la taille du modèle, le temps d'inférence et la précision. 

Source : Blog Google AI

Les dernières architectures EfficientNet publiées par l'équipe de Google constituent un excellent choix puisque le nombre de paramètres (donc la taille et le temps d'inférence) du modèle est nettement inférieur à ceux de ResNet, par exemple. Ainsi, un EfficientNet-b0 peut être un bon choix pour notre cas d'utilisation. Pour générer les embeddings, nous utilisons le paquet Python img2vec.

Maintenant que nous avons tout ce dont nous avons besoin pour générer nos encastrements, nous pouvons réfléchir à la stratégie de recherche de similarité.

Comment mettre en œuvre la recherche visuelle ? 

Une fois que nous avons des embeddings pour toutes nos images, nous devons créer un index pour chaque donnée. Ici, comme nous construisons une fonctionnalité pour interagir avec les images stockées dans le lac de données de Picsellia, nous allons utiliser l'UUID de nos données comme index. 

Ensuite, nous voulons trouver, étant donné un index, les N images les plus similaires.

Recherche par force brute (Euclidienne, Cosinus, etc.)

Une façon simple d'implémenter une recherche de similarité est de calculer la distance d'un vecteur caractéristique donné entre tous les autres vecteurs, puis de sélectionner les N plus proches voisins. Pour cette approche, il suffit de considérer la distance que l'on veut calculer, la similarité des vecteurs est souvent calculée par la distance cosinus.

Le pseudo-code associé à cette recherche serait :

x = vecteur cible

pour tous les index :

calculer la cosinus_distance entre x et l'indice

extraire les K plus proches voisins

Cette approche est considérée comme de la force brute puisque la complexité de la recherche est linéaire (comme le montre le graphique ci-dessous). Pour nous, il est totalement impossible d'utiliser de telles approches car nous gérons des millions d'images pour de multiples clients. 

HNSW (Hierarchical Navigable Small World Graphs) - une approche plus intelligente

Cet algorithme a été présenté dans l'article de recherche "Efficient and robust approximate nearest neighbor search using Hierarchical Navigable Small World graphs" par Yu. A. Malkov, D. A. Yashunin.

Vous pouvez trouver les liaisons Python de l'implémentation C++ ici.

L'algorithme génère un graphe où chaque nœud est un vecteur de caractéristiques lié à son plus proche voisin. Pour rechercher le K plus proche voisin, il suffit de parcourir le graphe et d'extraire le K plus proche point. 

L'objectif est de créer une approximation de la recherche afin de réduire le nombre de calculs effectués et de réduire la complexité informatique de la recherche. En bref, cela nous permet d'effectuer une recherche dans une base de données de 1m d'index en quelques millisecondes ! 

Maintenant, terminons en utilisant le Picsellia !

Les coulisses de l'implémentation de la recherche visuelle de Picsellia

Chez Picsellia, nous fournissons une plateforme de gestion des données pour surcharger le stockage d'objets en nuage avec l'indexation, le filtrage, la recherche, la visualisation et plus encore. C'est pourquoi il est logique pour nous de créer des fonctions de recherche visuelle. 

Le lac de données de Picsellia

 

Une grande vitesse, non ? Eh bien, voyons comment nous avons construit ça.

Nos exigences

Pour répondre à nos normes de développement, notre fonction de recherche visuelle doit présenter ces caractéristiques :

  • Être autonome dans un microservice web
  • Travailler sur la collecte d'index multiples en silo pour chaque client.
  • Parcourir des millions de lignes en quelques millisecondes
  • Avoir une complexité non linéaire

Ce sont des besoins essentiels, mais si nous voulons tout développer en interne, nous devrons déployer des efforts pour construire une solution évolutive répondant à ces exigences. Heureusement, comme le domaine de la recherche neuronale est en plein essor, il existe de nombreuses solutions sur le marché pour répondre à ces exigences. 

Présentation de Qdrant 

Qdrant

"Qdrant (lire : quadrant) est un moteur de recherche de similarité vectorielle. Il fournit un service prêt pour la production avec une API pratique pour stocker, rechercher et gérer des points-vecteurs avec une charge utile supplémentaire. Qdrant est adapté à un support de filtrage étendu. Cela le rend utile pour toutes sortes de réseaux neuronaux ou de correspondances basées sur la sémantique, de recherches à facettes et d'autres applications.

Qdrant est publié sous la licence open-source Apache 2.0. Son code source est disponible sur GitHub." Source : Documentation de Qdrant. Il met en œuvre une implémentation personnalisée de l'algorithme HSNW nous permettant d'ajouter des filtres supplémentaires à notre requête, et nous donnant une modularité complète sur notre recherche, ce qui est génial pour nous !

Leur solution open-source se présente sous la forme d'une image Docker unique exposant un serveur web avec lequel communiquer. Pour notre équipe technique, c'est parfait car nous pouvons l'intégrer dans un service personnalisé qui génère les embeddings et les stocke facilement dans la collection Qdrant.

En outre, ils fournissent un ensemble d'API permettant d'enregistrer un nouvel index et un identifiant correspondant, pour récupérer ultérieurement les éléments. Nous utilisons l'identifiant unique de l'image stockée sur nos buckets, ce qui garantit une communication fluide entre nos services.  

Mise en œuvre 

La phase clé est la création d'embeddings, et comment la réaliser à grande échelle sans impacter les performances globales du moteur de recherche et de la plateforme. Pour ce faire, nous utilisons des tâches asynchrones avec Celery pour mettre en file d'attente tout le travail et garder la création des embeddings sur le CPU.  

 

Conclusion

Cette nouvelle implémentation nous permet de générer des embeddings pour des millions d'images de manière asynchrone sans aucun impact sur la performance globale des produits Picsellia. 

Une fois que les embeddings sont indexés et liés à notre ID d'image unique, il devient très facile de trouver des images similaires dans votre ensemble de données en un rien de temps ! Cela rend l'exploration des ensembles de données aussi facile que l'ABC pour vous !

Si vous souhaitez bénéficier d'une suite complète de gestion des données intégrée à une plateforme de vision par ordinateur de bout en bout, demandez votre essai de 14 jours!

Commencez à gérer vos données d'IA de la bonne façon.

Demander un essai gratuit

Recommandé pour vous :