Segmentation d’image sans apprentissage préalable avec CLIPSeg

'Segmentation d'image avec CLIPSeg'

Ce guide montre comment vous pouvez utiliser CLIPSeg, un modèle de segmentation d’image sans apprentissage, en utilisant 🤗 transformers. CLIPSeg crée des masques de segmentation approximatifs qui peuvent être utilisés pour la perception des robots, l’embellissement des images et de nombreuses autres tâches. Si vous avez besoin de masques de segmentation plus précis, nous vous montrerons comment vous pouvez affiner les résultats de CLIPSeg sur Segments.ai.

La segmentation d’image est une tâche bien connue dans le domaine de la vision par ordinateur. Elle permet à un ordinateur de savoir non seulement ce qui se trouve dans une image (classification), où se trouvent les objets dans l’image (détection), mais aussi quelles sont les contours de ces objets. La connaissance des contours des objets est essentielle dans des domaines tels que la robotique et la conduite autonome. Par exemple, un robot doit connaître la forme d’un objet pour le saisir correctement. La segmentation peut également être combinée avec l’embellissement des images pour permettre aux utilisateurs de décrire la partie de l’image qu’ils souhaitent remplacer.

Une limitation de la plupart des modèles de segmentation d’image est qu’ils ne fonctionnent qu’avec une liste fixe de catégories. Par exemple, vous ne pouvez pas simplement utiliser un modèle de segmentation formé sur des oranges pour segmenter des pommes. Pour enseigner au modèle de segmentation une catégorie supplémentaire, vous devez étiqueter des données de la nouvelle catégorie et former un nouveau modèle, ce qui peut être coûteux et prend du temps. Mais que se passerait-il s’il existait un modèle qui puisse déjà segmenter presque n’importe quel type d’objet, sans aucun apprentissage supplémentaire ? C’est exactement ce que réalise CLIPSeg, un modèle de segmentation sans apprentissage.

Actuellement, CLIPSeg a encore ses limites. Par exemple, le modèle utilise des images de 352 x 352 pixels, de sorte que la sortie a une résolution assez faible. Cela signifie que nous ne pouvons pas nous attendre à des résultats parfaits au pixel près lorsque nous travaillons avec des images provenant de caméras modernes. Si nous voulons des segmentations plus précises, nous pouvons affiner un modèle de segmentation de pointe, comme indiqué dans notre précédent article de blog. Dans ce cas, nous pouvons toujours utiliser CLIPSeg pour générer quelques étiquettes approximatives, puis les affiner dans un outil d’étiquetage tel que Segments.ai. Avant de décrire comment faire cela, jetons d’abord un coup d’œil à la façon dont CLIPSeg fonctionne.

CLIP : le modèle magique derrière CLIPSeg

CLIP, qui signifie Contrastive Language-Image Pre-training, est un modèle développé par OpenAI en 2021. Vous pouvez donner à CLIP une image ou un morceau de texte, et CLIP produira une représentation abstraite de votre entrée. Cette représentation abstraite, également appelée incorporation, est en réalité juste un vecteur (une liste de nombres). Vous pouvez considérer ce vecteur comme un point dans un espace multidimensionnel. CLIP est entraîné de sorte que les représentations d’images et de textes similaires sont également similaires. Cela signifie que si nous donnons en entrée une image et une description textuelle correspondant à cette image, les représentations de l’image et du texte seront similaires (c’est-à-dire que les points multidimensionnels seront proches les uns des autres).

À première vue, cela peut ne pas sembler très utile, mais c’est en réalité très puissant. Par exemple, regardons rapidement comment CLIP peut être utilisé pour classer des images sans avoir jamais été formé sur cette tâche. Pour classer une image, nous donnons l’image et les différentes catégories parmi lesquelles nous voulons choisir à CLIP (par exemple, nous donnons une image et les mots “pomme”, “orange”,…). CLIP nous renvoie alors une incorporation de l’image et de chaque catégorie. Maintenant, il nous suffit de vérifier quelle incorporation de catégorie est la plus proche de l’incorporation de l’image, et voilà ! Cela semble magique, n’est-ce pas ?

Exemple de classification d’image à l’aide de CLIP (source).

De plus, CLIP n’est pas seulement utile pour la classification, mais il peut également être utilisé pour la recherche d’images (pouvez-vous voir comment cela est similaire à la classification ?), les modèles texte-vers-image (DALL-E 2 est alimenté par CLIP), la détection d’objets (OWL-ViT) et surtout pour nous : la segmentation d’image. Maintenant, vous comprenez pourquoi CLIP a vraiment été une percée en apprentissage automatique.

La raison pour laquelle CLIP fonctionne si bien est que le modèle a été formé sur un immense ensemble de données d’images avec des légendes textuelles. L’ensemble de données contenait 400 millions de paires image-texte provenant d’Internet. Ces images contiennent une grande variété d’objets et de concepts, et CLIP est excellent pour créer une représentation pour chacun d’entre eux.

CLIPSeg : segmentation d’image avec CLIP

CLIPSeg est un modèle qui utilise les représentations CLIP pour créer des masques de segmentation d’images. Il a été publié par Timo Lüddecke et Alexander Ecker. Ils ont réussi la segmentation d’images sans apprentissage en utilisant un décodeur basé sur le Transformer sur le modèle CLIP, qui reste figé. Le décodeur prend en entrée la représentation CLIP d’une image et la représentation CLIP de l’objet que vous souhaitez segmenter. À partir de ces deux entrées, le décodeur CLIPSeg crée un masque de segmentation binaire. Pour être plus précis, le décodeur n’utilise pas seulement la représentation CLIP finale de l’image que nous voulons segmenter, mais il utilise également les sorties de certaines des couches de CLIP.

Source

Le décodeur est entraîné sur l’ensemble de données PhraseCut, qui contient plus de 340 000 phrases avec des masques de segmentation d’images correspondants. Les auteurs ont également expérimenté différentes augmentations pour étendre la taille de l’ensemble de données. L’objectif ici est non seulement de pouvoir segmenter les catégories présentes dans l’ensemble de données, mais aussi de segmenter des catégories non vues. Les expériences montrent en effet que le décodeur peut généraliser à des catégories non vues.

Une caractéristique intéressante de CLIPSeg est que la requête (l’image que nous voulons segmenter) et l’invite (l’objet que nous voulons segmenter dans l’image) sont entrés sous forme de plongements CLIP. Le plongement CLIP pour l’invite peut provenir soit d’un morceau de texte (le nom de la catégorie), soit d’une autre image. Cela signifie que vous pouvez segmenter des oranges dans une photo en donnant à CLIPSeg une image d’exemple d’une orange.

Cette technique, appelée “visual prompting”, est vraiment utile lorsque l’objet que vous souhaitez segmenter est difficile à décrire. Par exemple, si vous voulez segmenter un logo sur une image d’un t-shirt, il n’est pas facile de décrire la forme du logo, mais CLIPSeg vous permet simplement d’utiliser l’image du logo comme invite.

L’article sur CLIPSeg contient quelques conseils pour améliorer l’efficacité du “visual prompting”. Ils constatent que le recadrage de l’image de requête (afin qu’elle ne contienne que l’objet que vous souhaitez segmenter) aide beaucoup. Le flou et l’assombrissement de l’arrière-plan de l’image de requête aident également un peu. Dans la section suivante, nous montrerons comment vous pouvez essayer le “visual prompting” vous-même en utilisant 🤗 transformers.

Utiliser CLIPSeg avec Hugging Face Transformers

Avec Hugging Face Transformers, vous pouvez facilement télécharger et exécuter un modèle CLIPSeg pré-entraîné sur vos images. Commençons par installer transformers.

!pip install -q transformers

Pour télécharger le modèle, il suffit de l’instancier.

from transformers import CLIPSegProcessor, CLIPSegForImageSegmentation

processor = CLIPSegProcessor.from_pretrained("CIDAS/clipseg-rd64-refined")
model = CLIPSegForImageSegmentation.from_pretrained("CIDAS/clipseg-rd64-refined")

Maintenant, nous pouvons charger une image pour tester la segmentation. Nous choisirons une photo d’un délicieux petit-déjeuner prise par Calum Lewis.

from PIL import Image
import requests

url = "https://unsplash.com/photos/8Nc_oQsc2qQ/download?ixid=MnwxMjA3fDB8MXxhbGx8fHx8fHx8fHwxNjcxMjAwNzI0&force=true&w=640"
image = Image.open(requests.get(url, stream=True).raw)
image

Text prompting

Commençons par définir quelques catégories de texte que nous voulons segmenter.

prompts = ["couverts", "crêpes", "myrtilles", "jus d'orange"]

Maintenant que nous avons nos entrées, nous pouvons les traiter et les entrer dans le modèle.

import torch

inputs = processor(text=prompts, images=[image] * len(prompts), padding="max_length", return_tensors="pt")
# prédiction
with torch.no_grad():
  outputs = model(**inputs)
preds = outputs.logits.unsqueeze(1)

Enfin, visualisons la sortie.

import matplotlib.pyplot as plt

_, ax = plt.subplots(1, len(prompts) + 1, figsize=(3*(len(prompts) + 1), 4))
[a.axis('off') for a in ax.flatten()]
ax[0].imshow(image)
[ax[i+1].imshow(torch.sigmoid(preds[i][0])) for i in range(len(prompts))];
[ax[i+1].text(0, -15, prompt) for i, prompt in enumerate(prompts)];

Incitation visuelle

Comme mentionné précédemment, nous pouvons également utiliser des images comme incitations d’entrée (c’est-à-dire à la place des noms de catégorie). Cela peut être particulièrement utile si la chose que vous voulez segmenter n’est pas facile à décrire. Pour cet exemple, nous utiliserons une photo d’une tasse de café prise par Daniel Hooper.

url = "https://unsplash.com/photos/Ki7sAc8gOGE/download?ixid=MnwxMjA3fDB8MXxzZWFyY2h8MTJ8fGNvZmZlJTIwdG8lMjBnb3xlbnwwfHx8fDE2NzExOTgzNDQ&force=true&w=640"
prompt = Image.open(requests.get(url, stream=True).raw)
prompt

Nous pouvons maintenant traiter l’image d’entrée et l’image d’incitation et les entrer dans le modèle.

encoded_image = processor(images=[image], return_tensors="pt")
encoded_prompt = processor(images=[prompt], return_tensors="pt")
# prédire
with torch.no_grad():
  outputs = model(**encoded_image, conditional_pixel_values=encoded_prompt.pixel_values)
preds = outputs.logits.unsqueeze(1)
preds = torch.transpose(preds, 0, 1)

Ensuite, nous pouvons visualiser les résultats comme précédemment.

_, ax = plt.subplots(1, 2, figsize=(6, 4))
[a.axis('off') for a in ax.flatten()]
ax[0].imshow(image)
ax[1].imshow(torch.sigmoid(preds[0]))

Essayons une dernière fois en utilisant les astuces d’incitation visuelle décrites dans le document, c’est-à-dire recadrer l’image et assombrir l’arrière-plan.

url = "https://i.imgur.com/mRSORqz.jpg"
alternative_prompt = Image.open(requests.get(url, stream=True).raw)
alternative_prompt

encoded_alternative_prompt = processor(images=[alternative_prompt], return_tensors="pt")
# prédire
with torch.no_grad():
  outputs = model(**encoded_image, conditional_pixel_values=encoded_alternative_prompt.pixel_values)
preds = outputs.logits.unsqueeze(1)
preds = torch.transpose(preds, 0, 1)

_, ax = plt.subplots(1, 2, figsize=(6, 4))
[a.axis('off') for a in ax.flatten()]
ax[0].imshow(image)
ax[1].imshow(torch.sigmoid(preds[0]))

Dans ce cas, le résultat est pratiquement le même. Cela est probablement dû au fait que la tasse de café était déjà bien séparée du fond dans l’image d’origine.

Utilisation de CLIPSeg pour pré-étiqueter des images sur Segments.ai

Comme vous pouvez le voir, les résultats de CLIPSeg sont un peu flous et de très basse résolution. Si nous voulons obtenir de meilleurs résultats, vous pouvez affiner un modèle de segmentation de pointe, comme expliqué dans notre précédent article de blog. Pour affiner le modèle, nous aurons besoin de données étiquetées. Dans cette section, nous vous montrerons comment vous pouvez utiliser CLIPSeg pour créer des masques de segmentation approximatifs, puis les affiner sur Segments.ai, une plateforme d’étiquetage avec des outils d’étiquetage intelligents pour la segmentation d’images.

Tout d’abord, créez un compte sur https://segments.ai/join et installez le SDK Python de Segments. Ensuite, vous pouvez initialiser le client Python Segments.ai en utilisant une clé API. Cette clé peut être trouvée sur la page du compte.

!pip install -q segments-ai

from segments import SegmentsClient
from getpass import getpass

api_key = getpass('Entrez votre clé API : ')
segments_client = SegmentsClient(api_key)

Ensuite, chargeons une image à partir d’un ensemble de données à l’aide du client Segments. Nous utiliserons l’ensemble de données de conduite autonome a2d2. Vous pouvez également créer votre propre ensemble de données en suivant ces instructions.

samples = segments_client.get_samples("admin-tobias/clipseg")

# Utilisez la dernière image comme exemple
sample = samples[1]
image = Image.open(requests.get(sample.attributes.image.url, stream=True).raw)
image

Nous devons également obtenir les noms de catégorie à partir des attributs de l’ensemble de données.

dataset = segments_client.get_dataset("admin-tobias/clipseg")
category_names = [category.name for category in dataset.task_attributes.categories]

Maintenant, nous pouvons utiliser CLIPSeg sur l’image comme précédemment. Cette fois, nous augmenterons également les sorties afin qu’elles correspondent à la taille de l’image d’entrée.

from torch import nn

inputs = processor(text=category_names, images=[image] * len(category_names), padding="max_length", return_tensors="pt")

# prédire
with torch.no_grad():
  outputs = model(**inputs)

# redimensionner les sorties
preds = nn.functional.interpolate(
    outputs.logits.unsqueeze(1),
    size=(image.size[1], image.size[0]),
    mode="bilinear"
)

Et nous pouvons visualiser à nouveau les résultats.

len_cats = len(category_names)
_, ax = plt.subplots(1, len_cats + 1, figsize=(3*(len_cats + 1), 4))
[a.axis('off') for a in ax.flatten()]
ax[0].imshow(image)
[ax[i+1].imshow(torch.sigmoid(preds[i][0])) for i in range(len_cats)];
[ax[i+1].text(0, -15, category_name) for i, category_name in enumerate(category_names)];

Maintenant, nous devons combiner les prédictions pour obtenir une seule image segmentée. Nous ferons simplement cela en prenant la catégorie avec la plus grande valeur sigmoïde pour chaque patch. Nous nous assurerons également que toutes les valeurs en dessous d’un certain seuil ne sont pas prises en compte.

seuil = 0.1

flat_preds = torch.sigmoid(preds.squeeze()).reshape((preds.shape[0], -1))

# Initialiser un masque "non étiqueté" fictif avec le seuil
flat_preds_with_treshold = torch.full((preds.shape[0] + 1, flat_preds.shape[-1]), seuil)
flat_preds_with_treshold[1:preds.shape[0]+1,:] = flat_preds

# Obtenir l'indice du masque supérieur pour chaque pixel
inds = torch.topk(flat_preds_with_treshold, 1, dim=0).indices.reshape((preds.shape[-2], preds.shape[-1]))

Voyons rapidement le résultat.

plt.imshow(inds)

Enfin, nous pouvons télécharger la prédiction sur Segments.ai. Pour ce faire, nous convertirons d’abord le bitmap en un fichier png, puis nous téléchargerons ce fichier sur Segments, et enfin nous ajouterons l’étiquette à l’échantillon.

from segments.utils import bitmap2file
import numpy as np

inds_np = inds.numpy().astype(np.uint32)
unique_inds = np.unique(inds_np).tolist()
f = bitmap2file(inds_np, is_segmentation_bitmap=True)

asset = segments_client.upload_asset(f, "clipseg_prediction.png")

attributes = {
      'format_version': '0.1',
      'annotations': [{"id": i, "category_id": i} for i in unique_inds if i != 0],
      'segmentation_bitmap': { 'url': asset.url },
  }

segments_client.add_label(sample.uuid, 'ground-truth', attributes)

Si vous examinez la prédiction téléchargée sur Segments.ai, vous verrez qu’elle n’est pas parfaite. Cependant, vous pouvez corriger manuellement les plus grandes erreurs, puis utiliser l’ensemble de données corrigé pour entraîner un meilleur modèle que CLIPSeg.

Conclusion

CLIPSeg est un modèle de segmentation sans apprentissage qui fonctionne avec des instructions à la fois textuelles et d’images. Le modèle ajoute un décodeur à CLIP et peut segmenter presque n’importe quoi. Cependant, les masques de segmentation en sortie sont encore de très faible résolution pour le moment, donc vous voudrez probablement affiner un autre modèle de segmentation si la précision est importante.

Notez qu’il y a d’autres recherches en cours sur la segmentation sans apprentissage, donc vous pouvez vous attendre à ce que d’autres modèles soient ajoutés dans un proche avenir. Un exemple est GroupViT, qui est déjà disponible dans 🤗 Transformers. Pour rester à jour avec les dernières nouvelles en matière de recherche en segmentation, vous pouvez nous suivre sur Twitter : @TobiasCornille , @NielsRogge , et @huggingface .

Si vous êtes intéressé par l’apprentissage de la façon d’affiner un modèle de segmentation de pointe, consultez notre précédent article de blog : https://huggingface.co/blog/fine-tune-segformer .

We will continue to update IPGirl; if you have any questions or suggestions, please contact us!

Share:

Was this article helpful?

93 out of 132 found this helpful

Discover more

AI

Grok L'IA Chatbot de xAI d'Elon Musk

Plongez dans Grok d'Elon Musk par xAI, un chatbot IA avec une récupération d'informations en temps réel, de l'humour ...

AI

Restez en avance sur la courbe de confiance en IA la trousse à outils responsable en IA en open-source est dévoilée.

Dans le paysage technologique en évolution rapide d’aujourd’hui, l’intelligence artificielle (IA) e...

AI

Elon Musk met en garde contre la montée de la superintelligence en Chine

L’entrepreneur renommé Elon Musk a récemment fait les gros titres avec sa déclaration audacieuse lors d’u...

AI

Le xAI d'Elon Musk affronte le ChatGPT d'OpenAI

Elon Musk, le milliardaire visionnaire derrière des entreprises telles que les voitures électriques, l’explorat...

AI

Elon Musk's xAI entraîné sur le flux de Twitter

Elon Musk, le visionnaire derrière des entreprises telles que Tesla et SpaceX, a de nouveau fixé son attention sur le...

AI

Juliette Powell et Art Kleiner, auteurs de la série d'interviews Le dilemme de l'IA

Le dilemme de l'IA est écrit par Juliette Powell et Art Kleiner. Juliette Powell est auteure, créatrice de télévision...