Transformers documentation

Zero-shot 객체 감지

You are viewing main version, which requires installation from source. If you'd like regular pip install, checkout the latest stable version (v5.22.2).
Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Zero-shot 객체 감지

전통적으로 객체 감지에 사용되는 모델은 학습을 위해 라벨이 붙은 이미지 데이터셋이 필요하며, 학습 데이터에 포함된 클래스 집합 내에서만 감지가 가능합니다.

Zero-shot object detection은 사전 학습이나 클래스에 대한 사전 지식 없이 이미지에서 객체와 해당 클래스를 감지하는 컴퓨터 비전 작업입니다. Zero-shot object detection 모델은 이미지와 후보 클래스 목록을 입력으로 받아, 객체가 감지된 위치의 bounding box와 라벨을 출력합니다.

Hugging Face에는 이러한 오픈 보카불리 제로샷 객체 감지기가 많이 있습니다.

이 가이드에서는 이러한 모델을 사용하는 방법을 배웁니다:

  • 텍스트 프롬프트를 기반으로 객체를 감지
  • 배치 객체 감지
  • 이미지 기반 객체 감지를 위한

시작하기 전에 필요한 라이브러리가 모두 설치되어 있는지 확인하세요:

pip install -q transformers

Zero-shot 객체 감지 파이프라인

모델로 추론을 가장 간단하게 시도하는 방법은 pipeline()을 사용하는 것입니다. Hugging Face Hub의 체크포인트에서 제로샷 객체 감지를 위한 파이프라인을 생성합니다:

>>> from transformers import pipeline

>>> # Use any checkpoint from the hf.co/models?pipeline_tag=zero-shot-object-detection
>>> checkpoint = "iSEE-Laboratory/llmdet_large"
>>> detector = pipeline(model=checkpoint, task="zero-shot-object-detection")

다음으로, 객체를 감지할 이미지를 선택합니다. 여기서는 NASA Great Images 데이터셋에 포함된 Eileen Collins 우주비행사의 이미지를 사용합니다.

>>> from transformers.image_utils import load_image

>>> url = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/zero-sh-obj-detection_1.png"
>>> image = load_image(url)
>>> image
Astronaut Eileen Collins

이미지와 탐색할 후보 객체 라벨을 pipeline에 전달합니다. 여기서는 이미지를 직접 전달하지만, 이미지 로컬 경로나 이미지 URL도 적절한 옵션입니다. 또한, 이미지에서 쿼리하려는 모든 항목에 대한 텍스트 설명도 함께 전달합니다.

>>> predictions = detector(
...     image,
...     candidate_labels=["human face", "rocket", "nasa badge", "star-spangled banner"],
...     threshold=0.45,
... )
>>> predictions
[{'score': 0.8409242033958435,
  'label': 'human face',
  'box': {'xmin': 179, 'ymin': 74, 'xmax': 272, 'ymax': 179}},
 {'score': 0.7380027770996094,
  'label': 'rocket',
  'box': {'xmin': 353, 'ymin': 0, 'xmax': 466, 'ymax': 284}},
 {'score': 0.5850900411605835,
  'label': 'star-spangled banner',
  'box': {'xmin': 0, 'ymin': 0, 'xmax': 96, 'ymax': 511}},
 {'score': 0.5697067975997925,
  'label': 'human face',
  'box': {'xmin': 18, 'ymin': 15, 'xmax': 366, 'ymax': 511}},
 {'score': 0.47813931107521057,
  'label': 'star-spangled banner',
  'box': {'xmin': 353, 'ymin': 0, 'xmax': 459, 'ymax': 274}},
 {'score': 0.46597740054130554,
  'label': 'nasa badge',
  'box': {'xmin': 353, 'ymin': 0, 'xmax': 462, 'ymax': 279}},
 {'score': 0.4585932493209839,
  'label': 'nasa badge',
  'box': {'xmin': 132, 'ymin': 348, 'xmax': 208, 'ymax': 423}}]

예측 결과를 시각화해 보겠습니다:

>>> 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
Visualized predictions on NASA image

수동으로 텍스트 프롬프트 기반 제로샷 객체 감지

zero-shot object detection 파이프라인 사용법을 확인했으니, 이제 동일한 결과를 수동으로 재현해 보겠습니다.

Hugging Face Hub의 체크포인트에서 모델과 관련 프로세서를 로드하는 것으로 시작합니다. 여기서는 이전과 동일한 체크포인트를 사용합니다:

>>> from transformers import AutoProcessor, AutoModelForZeroShotObjectDetection

>>> model = AutoModelForZeroShotObjectDetection.from_pretrained(checkpoint, device_map="auto")
>>> processor = AutoProcessor.from_pretrained(checkpoint)

다른 이미지로 변경하기 변화를 주기 위해 다른 이미지를 사용해 보겠습니다.

>>> url = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/zero-sh-obj-detection_3.png"
>>> image = load_image(url)
>>> image
Beach photo

processor를 사용하여 모델의 입력을 준비합니다.

>>> text_labels = ["hat", "book", "sunglasses", "camera"]
>>> inputs = processor(text=text_labels, images=image, return_tensors="pt").to(model.device)

입력을 모델에 통과시키고, 후처리한 후 결과를 시각화합니다. 이미지 프로세서가 모델에 전달하기 전에 이미지를 리사이즈했으므로, 예측된 바운딩 박스가 원본 이미지에 대해 올바른 좌표를 갖도록 post_process_object_detection 메서드를 사용해야 합니다:

>>> import torch

>>> with torch.inference_mode():
...     outputs = model(**inputs)

>>> results = processor.post_process_grounded_object_detection(
...    outputs, threshold=0.50, target_sizes=[(image.height, image.width)], text_labels=text_labels,
... )[0]

>>> draw = ImageDraw.Draw(image)

>>> scores = results["scores"]
>>> text_labels = results["text_labels"]
>>> boxes = results["boxes"]

>>> for box, score, text_label in zip(boxes, scores, text_labels):
...     xmin, ymin, xmax, ymax = box
...     draw.rectangle((xmin, ymin, xmax, ymax), outline="red", width=1)
...     draw.text((xmin, ymin), f"{text_label}: {round(score.item(),2)}", fill="white")

>>> image
Beach photo with detected objects

배치 처리

여러 이미지에 대해 서로 다른(또는 동일한) 객체를 검색하기 위해 여러 세트의 이미지와 텍스트 쿼리를 전달할 수 있습니다. 천체 비행사 이미지와 해변 이미지를 함께 사용해 보겠습니다. 배치 처리를 수행하려면, 프로세서에 텍스트 쿼리를 중첩 리스트로 전달하고, 이미지는 PIL 이미지 리스트, PyTorch 텐서, 또는 NumPy 배열 리스트로 전달해야 합니다.

>>> url1 = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/zero-sh-obj-detection_1.png"
>>> url2 = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/zero-sh-obj-detection_3.png"
>>> images = [load_image(url1), load_image(url2)]
>>> text_queries = [
...     ["human face", "rocket", "nasa badge", "star-spangled banner"],
...     ["hat", "book", "sunglasses", "camera", "can"],
... ]
>>> inputs = processor(text=text_queries, images=images, return_tensors="pt", padding=True)

이전에는 후처리 시 단일 이미지의 크기를 텐서로 전달했지만, 튜플을 전달할 수도 있고, 여러 이미지의 경우 튜플 목록을 전달할 수도 있습니다. 두 예시에 대한 예측을 생성하고 두 번째 예시(image_idx = 1)를 시각화해 보겠습니다.

>>> with torch.no_grad():
>>>     outputs = model(**inputs)

>>> target_sizes = [(image.height, image.width) for image in images]
>>> results = processor.post_process_grounded_object_detection(
...     outputs, threshold=0.3, target_sizes=target_sizes, text_labels=text_labels,
... )

결과를 시각화해 보겠습니다:

>>> image_idx = 1
>>> draw = ImageDraw.Draw(images[image_idx])

>>> scores = results[image_idx]["scores"].tolist()
>>> text_labels = results[image_idx]["text_labels"]
>>> boxes = results[image_idx]["boxes"].tolist()

>>> for box, score, text_label in zip(boxes, scores, text_labels):
>>>     xmin, ymin, xmax, ymax = box
>>>     draw.rectangle((xmin, ymin, xmax, ymax), outline="red", width=1)
>>>     draw.text((xmin, ymin), f"{text_label}: {round(score,2)}", fill="white")

>>> images[image_idx]
Beach photo with detected objects

이미지 기반 객체 감지

텍스트 쿼리를 이용한 zero-shot 객체 감지 외에도 OWL-ViT와 OWLv2와 같은 모델은 이미지 기반 객체 감지를 제공합니다. 이는 이미지 쿼리를 사용하여 대상 이미지에서 유사한 객체를 찾을 수 있음을 의미합니다.

>>> from transformers import AutoProcessor, AutoModelForZeroShotObjectDetection

>>> checkpoint = "google/owlv2-base-patch16-ensemble"
>>> model = AutoModelForZeroShotObjectDetection.from_pretrained(checkpoint, device_map="auto")
>>> processor = AutoProcessor.from_pretrained(checkpoint)

텍스트 쿼리와 달리, 단일 예시 이미지만 허용됩니다.

소파에 두 마리의 고양이가 있는 이미지를 대상 이미지로, 고양이 한 마리가 있는 이미지를 쿼리로 설정해 보겠습니다:

>>> 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)
>>> fig.show()
Cats

전처리 단계에서는 텍스트 쿼리 대신 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
Cats with bounding boxes
Update on GitHub