제로샷 이미지 분류

제로샷 이미지 분류 (Zero-shot image classification)

제로샷 이미지 분류는 특정 카테고리의 라벨링된 예시 데이터로 명시적으로 학습되지 않은 모델을 사용해 이미지를 여러 카테고리로 분류하는 작업이에요.

출처: 문서

본문

전통적으로 이미지 분류는 특정 라벨링된 이미지 집합으로 모델을 학습시키고, 그 모델이 특정 이미지 특징을 라벨에 "매핑"하는 법을 배우는 방식이에요. 이런 모델을 새로운 라벨 집합이 등장하는 분류 작업에 사용해야 할 때는 모델을 "재보정(recalibrate)"하기 위한 파인튜닝이 필요해요.

반면 제로샷 또는 개방 어휘(open vocabulary) 이미지 분류 모델은 대개 이미지와 관련 설명의 큰 데이터셋으로 학습된 다중 모달(multimodal) 모델이에요. 이런 모델은 제로샷 이미지 분류를 포함한 많은 다운스트림 작업에 사용할 수 있는 정렬된 비전-언어 표현(vision-language representation)을 학습해요.

이것은 추가적인 학습 데이터 없이도 모델이 새롭고 보지 못한 카테고리로 일반화할 수 있게 하고, 사용자가 목표 개체의 자유 형식 텍스트 설명으로 이미지를 질의할 수 있게 해주는 더 유연한 이미지 분류 접근 방식이에요.

이 가이드에서는 다음을 배워요:

  • 제로샷 이미지 분류 파이프라인 만들기
  • 손으로 직접 제로샷 이미지 분류 추론 실행하기

시작하기 전에 필요한 라이브러리를 모두 설치했는지 확인해요:

pip install -q "transformers[torch]" pillow

제로샷 이미지 분류 파이프라인

제로샷 이미지 분류를 지원하는 모델로 추론을 시도하는 가장 간단한 방법은 해당 pipeline()을 사용하는 거예요. Hugging Face Hub의 체크포인트에서 파이프라인을 인스턴스화해요:

>>> from transformers import pipeline

>>> checkpoint = "openai/clip-vit-large-patch14"
>>> detector = pipeline(model=checkpoint, task="zero-shot-image-classification")

다음으로 분류하고 싶은 이미지를 선택해요.

>>> from PIL import Image
>>> import requests

>>> url = "https://unsplash.com/photos/g8oS8-82DxI/download?ixid=MnwxMjA3fDB8MXx0b3BpY3x8SnBnNktpZGwtSGt8fHx8fDJ8fDE2NzgxMDYwODc&force=true&w=640"
>>> image = Image.open(requests.get(url, stream=True).raw)

>>> image

이미지와 후보 개체 라벨을 파이프라인에 전달해요. 여기서는 이미지를 직접 전달해요. 다른 적절한 옵션으로는 이미지의 로컬 경로나 이미지 URL이 있어요. 후보 라벨은 이 예시처럼 단순한 단어일 수도 있고, 더 설명적인 표현일 수도 있어요.

>>> predictions = detector(image, candidate_labels=["fox", "bear", "seagull", "owl"])
>>> predictions
[{'score': 0.9996670484542847, 'label': 'owl'},
 {'score': 0.000199399160919711, 'label': 'seagull'},
 {'score': 7.392891711788252e-05, 'label': 'fox'},
 {'score': 5.96074532950297e-05, 'label': 'bear'}]

손으로 직접 하는 제로샷 이미지 분류

이제 제로샷 이미지 분류 파이프라인을 사용하는 법을 봤으니, 제로샷 이미지 분류를 수동으로 실행하는 방법을 살펴볼게요.

먼저 Hugging Face Hub의 체크포인트에서 모델과 관련 프로세서를 로드해요. 여기서는 이전과 같은 체크포인트를 사용할 거예요:

>>> from transformers import AutoProcessor, AutoModelForZeroShotImageClassification

>>> model = AutoModelForZeroShotImageClassification.from_pretrained(checkpoint)
>>> processor = AutoProcessor.from_pretrained(checkpoint)

분위기를 바꾸기 위해 다른 이미지를 사용해 보도록 해요.

>>> from PIL import Image
>>> import requests

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

>>> image

프로세서를 사용해 모델용 입력을 준비해요. 프로세서는 이미지를 리사이즈하고 정규화해서 모델에 준비하는 이미지 프로세서와, 텍스트 입력을 처리하는 토크나이저를 결합해요.

>>> candidate_labels = ["tree", "car", "bike", "cat"]
# follows the pipeline prompt template to get same results
>>> candidate_labels = [f'This is a photo of {label}.' for label in candidate_labels]
>>> inputs = processor(images=image, text=candidate_labels, return_tensors="pt", padding=True)

입력을 모델에 통과시키고 결과를 후처리해요:

>>> import torch

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

>>> logits = outputs.logits_per_image[0]
>>> probs = logits.softmax(dim=-1).numpy()
>>> scores = probs.tolist()

>>> result = [
...     {"score": score, "label": candidate_label}
...     for score, candidate_label in sorted(zip(probs, candidate_labels), key=lambda x: -x[0])
... ]

>>> result
[{'score': 0.998572, 'label': 'car'},
 {'score': 0.0010570387, 'label': 'bike'},
 {'score': 0.0003393686, 'label': 'tree'},
 {'score': 3.1572064e-05, 'label': 'cat'}]