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.
!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
!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']
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)
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}")
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.
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
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.
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.
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.
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))
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.
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()
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.
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!