Transformers 文档
零样本目标检测
并获得增强的文档体验
开始使用
零样本目标检测
传统上,用于 目标检测 的模型需要标记图像数据集进行训练,并且仅限于检测来自训练数据集的类别。
零样本目标检测由 OWL-ViT 模型支持,该模型使用不同的方法。OWL-ViT 是一个开放词汇目标检测器。这意味着它可以根据自由文本查询检测图像中的对象,而无需在标记数据集上微调模型。
OWL-ViT 利用多模态表示来执行开放词汇检测。它将 CLIP 与轻量级对象分类和定位头结合在一起。开放词汇检测是通过嵌入 CLIP 文本编码器的自由文本查询,并将它们用作对象分类和定位头的输入来实现的,这些头将图像与其相应的文本描述相关联,而 ViT 将图像补丁作为输入进行处理。OWL-ViT 的作者首先从头开始训练 CLIP,然后使用二分匹配损失在标准目标检测数据集上端到端地微调 OWL-ViT。
通过这种方法,模型可以基于文本描述检测对象,而无需事先在标记数据集上进行训练。
在本指南中,您将学习如何使用 OWL-ViT
- 基于文本提示检测对象
- 用于批量目标检测
- 用于图像引导的目标检测
在开始之前,请确保您已安装所有必要的库
pip install -q transformers
零样本目标检测 pipeline
尝试使用 OWL-ViT 进行推理的最简单方法是在 pipeline() 中使用它。从 Hugging Face Hub 上的检查点 实例化零样本目标检测的 pipeline()
>>> from transformers import pipeline
>>> checkpoint = "google/owlv2-base-patch16-ensemble"
>>> detector = pipeline(model=checkpoint, task="zero-shot-object-detection")
接下来,选择您要检测对象的图像。在这里,我们将使用宇航员艾琳·柯林斯的图像,该图像是 NASA Great Images 数据集的一部分。
>>> import skimage
>>> import numpy as np
>>> from PIL import Image
>>> image = skimage.data.astronaut()
>>> image = Image.fromarray(np.uint8(image)).convert("RGB")
>>> image

将图像和要查找的候选对象标签传递给 pipeline。在这里,我们直接传递图像;其他合适的选项包括图像的本地路径或图像 URL。我们还传递了要查询图像中所有项目的文本描述。
>>> predictions = detector(
... image,
... candidate_labels=["human face", "rocket", "nasa badge", "star-spangled banner"],
... )
>>> predictions
[{'score': 0.3571370542049408,
'label': 'human face',
'box': {'xmin': 180, 'ymin': 71, 'xmax': 271, 'ymax': 178}},
{'score': 0.28099656105041504,
'label': 'nasa badge',
'box': {'xmin': 129, 'ymin': 348, 'xmax': 206, 'ymax': 427}},
{'score': 0.2110239565372467,
'label': 'rocket',
'box': {'xmin': 350, 'ymin': -1, 'xmax': 468, 'ymax': 288}},
{'score': 0.13790413737297058,
'label': 'star-spangled banner',
'box': {'xmin': 1, 'ymin': 1, 'xmax': 105, 'ymax': 509}},
{'score': 0.11950037628412247,
'label': 'nasa badge',
'box': {'xmin': 277, 'ymin': 338, 'xmax': 327, 'ymax': 380}},
{'score': 0.10649408400058746,
'label': 'rocket',
'box': {'xmin': 358, 'ymin': 64, 'xmax': 424, 'ymax': 280}}]
让我们可视化预测结果
>>> from PIL import ImageDraw
>>> draw = ImageDraw.Draw(image)
>>> for prediction in predictions:
... box = prediction["box"]
... label = prediction["label"]
... score = prediction["score"]
... xmin, ymin, xmax, ymax = box.values()
... draw.rectangle((xmin, ymin, xmax, ymax), outline="red", width=1)
... draw.text((xmin, ymin), f"{label}: {round(score,2)}", fill="white")
>>> image

手动进行文本提示的零样本目标检测
既然您已经了解了如何使用零样本目标检测 pipeline,让我们手动复制相同的结果。
首先从 Hugging Face Hub 上的检查点 加载模型和关联的处理器。在这里,我们将使用与之前相同的检查点
>>> from transformers import AutoProcessor, AutoModelForZeroShotObjectDetection
>>> model = AutoModelForZeroShotObjectDetection.from_pretrained(checkpoint)
>>> processor = AutoProcessor.from_pretrained(checkpoint)
让我们换一张不同的图像来改变一下。
>>> import requests
>>> url = "https://unsplash.com/photos/oj0zeY2Ltk4/download?ixid=MnwxMjA3fDB8MXxzZWFyY2h8MTR8fHBpY25pY3xlbnwwfHx8fDE2Nzc0OTE1NDk&force=true&w=640"
>>> im = Image.open(requests.get(url, stream=True).raw)
>>> im

使用处理器为模型准备输入。处理器结合了一个图像处理器(通过调整大小和标准化来为模型准备图像)和一个 CLIPTokenizer(负责处理文本输入)。
>>> text_queries = ["hat", "book", "sunglasses", "camera"]
>>> inputs = processor(text=text_queries, images=im, return_tensors="pt")
通过模型传递输入,进行后处理,并可视化结果。由于图像处理器在将图像馈送到模型之前调整了图像大小,因此您需要使用 post_process_object_detection() 方法来确保预测的边界框具有相对于原始图像的正确坐标
>>> import torch
>>> with torch.no_grad():
... outputs = model(**inputs)
... target_sizes = torch.tensor([im.size[::-1]])
... results = processor.post_process_object_detection(outputs, threshold=0.1, target_sizes=target_sizes)[0]
>>> draw = ImageDraw.Draw(im)
>>> scores = results["scores"].tolist()
>>> labels = results["labels"].tolist()
>>> boxes = results["boxes"].tolist()
>>> for box, score, label in zip(boxes, scores, labels):
... xmin, ymin, xmax, ymax = box
... draw.rectangle((xmin, ymin, xmax, ymax), outline="red", width=1)
... draw.text((xmin, ymin), f"{text_queries[label]}: {round(score,2)}", fill="white")
>>> im

批量处理
您可以传递多组图像和文本查询,以搜索多个图像中不同的(或相同的)对象。让我们同时使用宇航员图像和海滩图像。对于批量处理,您应该将文本查询作为嵌套列表传递给处理器,并将图像作为 PIL 图像、PyTorch 张量或 NumPy 数组的列表传递。
>>> images = [image, im]
>>> text_queries = [
... ["human face", "rocket", "nasa badge", "star-spangled banner"],
... ["hat", "book", "sunglasses", "camera"],
... ]
>>> inputs = processor(text=text_queries, images=images, return_tensors="pt")
以前,对于后处理,您将单个图像的大小作为张量传递,但您也可以传递元组,或者,在多个图像的情况下,传递元组列表。让我们为这两个示例创建预测,并可视化第二个示例 (image_idx = 1
)。
>>> with torch.no_grad():
... outputs = model(**inputs)
... target_sizes = [x.size[::-1] for x in images]
... results = processor.post_process_object_detection(outputs, threshold=0.1, target_sizes=target_sizes)
>>> image_idx = 1
>>> draw = ImageDraw.Draw(images[image_idx])
>>> scores = results[image_idx]["scores"].tolist()
>>> labels = results[image_idx]["labels"].tolist()
>>> boxes = results[image_idx]["boxes"].tolist()
>>> for box, score, label in zip(boxes, scores, labels):
... xmin, ymin, xmax, ymax = box
... draw.rectangle((xmin, ymin, xmax, ymax), outline="red", width=1)
... draw.text((xmin, ymin), f"{text_queries[image_idx][label]}: {round(score,2)}", fill="white")
>>> images[image_idx]

图像引导的目标检测
除了使用文本查询进行零样本目标检测外,OWL-ViT 还提供图像引导的目标检测。这意味着您可以使用图像查询在目标图像中查找相似的对象。与文本查询不同,只允许使用单个示例图像。
让我们以一张沙发上两只猫的图像作为目标图像,以一张单只猫的图像作为查询图像
>>> url = "http://images.cocodataset.org/val2017/000000039769.jpg"
>>> image_target = Image.open(requests.get(url, stream=True).raw)
>>> query_url = "http://images.cocodataset.org/val2017/000000524280.jpg"
>>> query_image = Image.open(requests.get(query_url, stream=True).raw)
让我们快速看一下这些图像
>>> import matplotlib.pyplot as plt
>>> fig, ax = plt.subplots(1, 2)
>>> ax[0].imshow(image_target)
>>> ax[1].imshow(query_image)

在预处理步骤中,现在需要使用 query_images
而不是文本查询
>>> inputs = processor(images=image_target, query_images=query_image, return_tensors="pt")
对于预测,不要将输入传递给模型,而是将它们传递给 image_guided_detection()。像以前一样绘制预测结果,除了现在没有标签。
>>> with torch.no_grad():
... outputs = model.image_guided_detection(**inputs)
... target_sizes = torch.tensor([image_target.size[::-1]])
... results = processor.post_process_image_guided_detection(outputs=outputs, target_sizes=target_sizes)[0]
>>> draw = ImageDraw.Draw(image_target)
>>> scores = results["scores"].tolist()
>>> boxes = results["boxes"].tolist()
>>> for box, score in zip(boxes, scores):
... xmin, ymin, xmax, ymax = box
... draw.rectangle((xmin, ymin, xmax, ymax), outline="white", width=4)
>>> image_target
