Heim  >  Artikel  >  Backend-Entwicklung  >  Verwendung von YOLO mit CLIP zur Verbesserung des Abrufs

Verwendung von YOLO mit CLIP zur Verbesserung des Abrufs

WBOY
WBOYOriginal
2024-08-05 21:58:521177Durchsuche

In diesem Artikel werden wir sehen, wie wir Objekterkennungsmodelle wie YOLO zusammen mit multimodalen Einbettungsmodellen wie CLIP verwenden können, um den Bildabruf zu verbessern.

Hier ist die Idee: Das Abrufen von CLIP-Bildern funktioniert wie folgt: Wir betten die Bilder, die wir haben, mithilfe eines CLIP-Modells ein und speichern sie irgendwo, beispielsweise in einer Vektordatenbank. Dann können wir während der Inferenz ein Abfragebild oder eine Eingabeaufforderung verwenden, dieses einbetten und aus den gespeicherten Einbettungen die nächstgelegenen Bilder finden, die abgerufen werden können. Das Problem besteht darin, dass die eingebetteten Bilder zu viele Objekte enthalten oder sich einige Objekte im Hintergrund befinden und wir trotzdem möchten, dass unser System sie abruft. Dies liegt daran, dass CLIP das Bild als Ganzes einbettet. Stellen Sie sich das so vor, als wäre ein Worteinbettungsmodell ein Satzeinbettungsmodell. Wir möchten in der Lage sein, nach Wörtern zu suchen, die Objekten in einem Bild entsprechen. Die Lösung besteht also darin, das Bild mithilfe eines Objekterkennungsmodells in verschiedene Objekte zu zerlegen. Betten Sie dann diese zerlegten Bilder ein, verknüpfen Sie sie jedoch mit ihrem übergeordneten Bild. Dies ermöglicht es uns, die Pflanzen abzurufen und den Elternteil zu ermitteln, von dem die Pflanze stammt. Mal sehen, wie es funktioniert.

Installieren Sie die Abhängigkeiten und importieren Sie sie

!pip install -q ultralytics torch matplotlib numpy pillow zipfile36 transformers

from ultralytics import YOLO
import matplotlib.pyplot as plt
from PIL import pillow
import os
from Zipfile import Zipfile, BadZipFile
import torch
from transformers import CLIPProcessor, CLIPModel, CLIPVisionModelWithProjection, CLIPTextModelWithProjection

Laden Sie den COCO-Datensatz herunter und entpacken Sie ihn

!wget http://images.cocodataset.org/zips/val2017.zip -O coco_val2017.zip

def extract_zip_file(extract_path):
    try:
        with ZipFile(extract_path+".zip") as zfile:
            zfile.extractall(extract_path)
        # remove zipfile
        zfileTOremove=f"{extract_path}"+".zip"
        if os.path.isfile(zfileTOremove):
            os.remove(zfileTOremove)
        else:
            print("Error: %s file not found" % zfileTOremove)
    except BadZipFile as e:
        print("Error:", e)

extract_val_path = "./coco_val2017"
extract_zip_file(extract_val_path)

Wir können dann einige der Bilder aufnehmen und eine Liste mit Beispielen erstellen.

source = ['coco_val2017/val2017/000000000139.jpg', '/content/coco_val2017/val2017/000000000632.jpg', '/content/coco_val2017/val2017/000000000776.jpg', '/content/coco_val2017/val2017/000000001503.jpg', '/content/coco_val2017/val2017/000000001353.jpg', '/content/coco_val2017/val2017/000000003661.jpg']

Initiieren Sie das YOLO-Modell und das CLIP-Modell

In diesem Beispiel verwenden wir das neueste Ultralytics Yolo10x-Modell zusammen mit OpenAI clip-vit-base-patch32.

device = "cuda"

 # YOLO Model
model = YOLO('yolov10x.pt')

# Clip model
model_id = "openai/clip-vit-base-patch32"
image_model = CLIPVisionModelWithProjection.from_pretrained(model_id, device_map = device)
text_model = CLIPTextModelWithProjection.from_pretrained(model_id, device_map = device)
processor = CLIPProcessor.from_pretrained(model_id)

Ausführen des Erkennungsmodells

results = model(source=source, device = "cuda")

Lassen Sie uns die Ergebnisse mit diesem Code-Snippet zeigen

# Visualize the results
fig, ax = plt.subplots(2, 3, figsize=(15, 10))

for i, r in enumerate(results):
    # Plot results image
    im_bgr = r.plot()  # BGR-order numpy array
    im_rgb = Image.fromarray(im_bgr[..., ::-1])  # RGB-order PIL image

    ax[i%2, i//2].imshow(im_rgb)
    ax[i%2, i//2].set_title(f"Image {i+1}")

Using YOLO with CLIP to improve Retrieval

Wir können also sehen, dass das YOLO-Modell bei der Erkennung der Objekte in den Bildern recht gut funktioniert. Bei der Kennzeichnung des Monitors als TV werden einige Fehler gemacht. Aber das ist in Ordnung. Die tatsächlichen Klassen, die YOLO zuweist, sind nicht so wichtig, da wir CLIP verwenden, um die Schlussfolgerung zu ziehen.

Definieren einiger Hilfsklassen

class CroppedImage:

  def __init__(self, parent, box, cls):

    self.parent = parent
    self.box = box
    self.cls = cls

  def display(self, ax = None):
    im_rgb = Image.open(self.parent)
    cropped_image = im_rgb.crop(self.box)

    if ax is not None:
      ax.imshow(cropped_image)
      ax.set_title(self.cls)
    else:
      plt.figure(figsize=(10, 10))
      plt.imshow(cropped_image)
      plt.title(self.cls)
      plt.show()

  def get_cropped_image(self):
    im_rgb = Image.open(self.parent)
    cropped_image = im_rgb.crop(self.box)
    return cropped_image

  def __str__(self):
    return f"CroppedImage(parent={self.parent}, boxes={self.box}, cls={self.cls})"

  def __repr__(self):
    return self.__str__()

class YOLOImage:
  def __init__(self, image_path, cropped_images):
    self.image_path = str(image_path)
    self.cropped_images = cropped_images

  def get_image(self):
    return Image.open(self.image_path)

  def get_caption(self):
    cls  =[]
    for cropped_image in self.cropped_images:
      cls.append(cropped_image.cls)

    unique_cls = set(cls)
    count_cls = {cls: cls.count(cls) for cls in unique_cls}

    count_string = " ".join(f"{count} {cls}," for cls, count in count_cls.items())
    return "this image contains " + count_string

  def __str__(self):
    return self.__repr__()

  def __repr__(self):
    cls  =[]
    for cropped_image in self.cropped_images:
      cls.append(cropped_image.cls)

    return f"YOLOImage(image={self.image_path}, cropped_images={cls})"

class ImageEmbedding:
  def __init__(self, image_path, embedding, cropped_image = None):
    self.image_path = image_path
    self.cropped_image = cropped_image
    self.embedding = embedding

CropImage-Klasse

Die CropImage-Klasse stellt einen Teil eines Bildes dar, das aus einem größeren übergeordneten Bild ausgeschnitten wurde. Es wird mit dem Pfad zum übergeordneten Bild, dem Begrenzungsrahmen, der den Zuschneidebereich definiert, und einer Klassenbezeichnung (z. B. „Katze“ oder „Hund“) initialisiert. Diese Klasse enthält Methoden zum Anzeigen des zugeschnittenen Bildes und zum Abrufen als Bildobjekt. Die Anzeigemethode ermöglicht die Visualisierung des zugeschnittenen Teils entweder auf einer bereitgestellten Achse oder durch Erstellen einer neuen Figur, wodurch sie für verschiedene Anwendungsfälle vielseitig einsetzbar ist. Darüber hinaus sind die Methoden __str__ und __repr__ für eine einfache und informative Zeichenfolgendarstellung des Objekts implementiert.

YOLOImage-Klasse

Die YOLOImage-Klasse ist für die Verarbeitung von Bildern konzipiert, die mit dem YOLO-Objekterkennungsmodell verarbeitet wurden. Es verwendet den Pfad zum Originalbild und eine Liste von CropImage-Instanzen, die die erkannten Objekte im Bild darstellen. Die Klasse bietet Methoden zum Öffnen und Anzeigen des vollständigen Bildes und zum Generieren einer Beschriftung, die die im Bild erkannten Objekte zusammenfasst. Die caption-Methode aggregiert und zählt die eindeutigen Klassenbezeichnungen der zugeschnittenen Bilder und liefert so eine prägnante Beschreibung des Bildinhalts. Diese Klasse ist besonders nützlich für die Verwaltung und Interpretation von Ergebnissen von Objekterkennungsaufgaben.

ImageEmbedding-Klasse

Die ImageEmbedding-Klasse verfügt über ein Bild und die zugehörige Einbettung, bei der es sich um eine numerische Darstellung der Bildmerkmale handelt. Diese Klasse kann mit dem Pfad zum Bild, dem Einbettungsvektor und optional einer CropImage-Instanz initialisiert werden, wenn die Einbettung einem bestimmten zugeschnittenen Teil des Bildes entspricht. Die ImageEmbedding-Klasse ist für Aufgaben im Zusammenhang mit Bildähnlichkeit, Klassifizierung und Abruf von wesentlicher Bedeutung, da sie eine strukturierte Möglichkeit bietet, die Bilddaten zusammen mit den berechneten Funktionen zu speichern und darauf zuzugreifen. Diese Integration ermöglicht eine effiziente Bildverarbeitung und maschinelle Lernabläufe.

Schneiden Sie jedes Bild zu und erstellen Sie eine Liste von YOLOImage-Objekten

yolo_images: list[YOLOImage]= []

names= model.names

for i, r in enumerate(results):
  crops:list[CroppedImage] = []
  boxes = r.boxes
  classes = r.boxes.cls
  for j, box in enumerate(r.boxes):
    box = tuple(box.xyxy.flatten().cpu().numpy())
    cropped_image = CroppedImage(parent = r.path, box = box, cls = names[classes[j].int().item()])
    crops.append(cropped_image)
  yolo_images.append(YOLOImage(image_path=r.path, cropped_images=crops))

Bilder mit CLIP einbetten

image_embeddings = []

for image in yolo_images:
  input = processor.image_processor(images= image.get_image(), return_tensors = 'pt')
  input.to(device)
  embeddings = image_model(pixel_values = input.pixel_values).image_embeds
  embeddings = embeddings/embeddings.norm(p=2, dim = -1, keepdim = True) # Normalize the embeddings
  image_embedding = ImageEmbedding(image_path = image.image_path, embedding = embeddings)
  image_embeddings.append(image_embedding)

  for cropped_image in image.cropped_images:
    input = processor.image_processor(images= cropped_image.get_cropped_image(), return_tensors = 'pt')
    input.to(device)
    embeddings = image_model(pixel_values = input.pixel_values).image_embeds
    embeddings = embeddings/embeddings.norm(p=2, dim = -1, keepdim = True) # Normalize the embeddings

    image_embedding = ImageEmbedding(image_path = image.image_path, embedding = embeddings, cropped_image = cropped_image)
    image_embeddings.append(image_embedding)

   **image_embeddings_tensor = torch.stack([image_embedding.embedding for image_embedding in image_embeddings]).squeeze()**

Wir können diese Bildeinbettungen jetzt übernehmen und in einer Vektordatenbank speichern, wenn wir möchten. Aber in diesem Beispiel verwenden wir einfach die Technik des inneren Skalarprodukts, um die Ähnlichkeit zu überprüfen und die Bilder abzurufen.

Abruf

query = "image of a flowerpot"

text_embedding = processor.tokenizer(query, return_tensors="pt").to(device)
text_embedding = text_model(**text_embedding).text_embeds

similarities = (torch.matmul(text_embedding, image_embeddings_tensor.T)).flatten().detach().cpu().numpy()

# get the top 5 similar images
k = 5
top_k_indices = similarities.argsort()[-k:]

# Display the top 5 results
fig, ax = plt.subplots(2, 5, figsize=(20, 5))
for i, index in enumerate(top_k_indices):
  if image_embeddings[index].cropped_image is not None:
    image_embeddings[index].cropped_image.display(ax = ax[0][i])
  else:
  ax[0][i].imshow(Image.open(image_embeddings[index].image_path))
  ax[1][i].imshow(Image.open(image_embeddings[index].image_path))
  ax[0][i].axis('off')
  ax[1][i].axis('off')
  ax[1][i].set_title("Original Image")
plt.show()

Using YOLO with CLIP to improve Retrieval

Using YOLO with CLIP to improve Retrieval
Using YOLO with CLIP to improve Retrieval
Using YOLO with CLIP to improve Retrieval

Sie sehen, dass wir auch kleine Pflanzen, die im Hintergrund versteckt sind, zurückholen können. Manchmal wird auch das Originalbild als Ergebnis gezogen, weil wir das auch einbetten.

Dies kann eine sehr wirkungsvolle Technik sein. Sie können auch die Modelle zur Erkennung und Einbettung Ihrer eigenen Bilder verfeinern und die Leistung noch weiter verbessern.

Ein Nachteil ist, dass wir das CLIP-Modell für alle erkannten Objekte ausführen müssen. Eine Möglichkeit, dies zu mildern, besteht darin, die Anzahl der von YOLO produzierten Kartons zu begrenzen.

Sie können den Code auf Colab unter diesem Link ansehen.

Using YOLO with CLIP to improve Retrieval


Möchten Sie eine Verbindung herstellen?

?Meine Website

?Mein Twitter

?Mein LinkedIn

Das obige ist der detaillierte Inhalt vonVerwendung von YOLO mit CLIP zur Verbesserung des Abrufs. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn