CLIP (260830)

WonTerry·2026년 8월 30일

Deep Learning

목록 보기
28/40
from PIL import Image  # 이미지 파일을 열고 처리하기 위한 라이브러리입니다.
import torch  # 텐서 연산을 위한 PyTorch 라이브러리입니다.
from transformers import CLIPProcessor, CLIPModel  # CLIP 모델과 프로세서를 불러오는 라이브러리입니다.

# pip install transformers torch pillow 를 통해 필요한 라이브러리를 설치해야 합니다.

# CLIP 모델을 로드합니다.
# "openai/clip-vit-base-patch32"는 OpenAI에서 제공하는 CLIP 모델의 이름입니다.
# 이 모델은 이미지와 텍스트를 함께 처리할 수 있도록 학습되었습니다.
model = CLIPModel.from_pretrained(
    "openai/clip-vit-base-patch32"
)

# CLIP 프로세서를 로드합니다.
# CLIP 프로세서는 모델을 사용하여 이미지와 텍스트를 처리하는 방법을 정의합니다.
processor = CLIPProcessor.from_pretrained(
    "openai/clip-vit-base-patch32"
)

# 이미지를 불러옵니다.
# "dog.jpg"는 이미지 파일의 이름입니다.  이 파일을 코드와 같은 디렉토리에 위치시켜야 합니다.
image = Image.open("dog.jpg")

# 텍스트 목록을 정의합니다.
# 이 목록은 모델이 이미지와 비교할 텍스트 설명입니다.
texts = [
    "a photo of a bear",
    "a photo of a cat",
    "a photo of a dog",
    "a photo of a puppy"
]

# 텍스트와 이미지를 CLIP 모델에 입력하기 위한 형태로 변환합니다.
# processor() 함수는 이미지와 텍스트를 모델이 이해할 수 있는 텐서로 변환합니다.
# return_tensors="pt"는 PyTorch 텐서를 반환하도록 지정합니다.
# padding=True는 짧은 텍스트가 있을 경우 자동으로 패딩을 추가하여 모든 텍스트의 길이를 동일하게 만듭니다.
inputs = processor(
    text=texts,
    images=image,
    return_tensors="pt",
    padding=True
)

# 모델을 사용하여 이미지와 텍스트에 대한 예측을 수행합니다.
# outputs = model(**inputs) 는 inputs 딕셔너리의 키를 사용하여 모델의 메서드를 호출합니다.
# 이 코드는 이미지와 텍스트에 대한 CLIP 모델의 출력을 얻습니다.
outputs = model(**inputs)

# 출력에서 이미지에 대한 로짓(logits)을 추출합니다.
# logits는 모델이 각 텍스트가 이미지와 얼마나 관련 있는지 나타내는 숫자 값입니다.
logits = outputs.logits_per_image

# 로짓을 확률로 변환합니다.
# softmax() 함수는 로짓을 확률 분포로 변환합니다.  각 확률은 해당 텍스트가 이미지와 얼마나 관련 있는지 나타냅니다.
probs = logits.softmax(dim=1)

# 각 텍스트와 그에 해당하는 확률을 출력합니다.
# zip(texts, probs[0]) 는 texts 목록과 probs[0] (이미지 관련성 점수)를 함께 반복합니다.
# text는 텍스트 설명이고, probability는 해당 텍스트의 확률입니다.
# probability.item() 은 텐서에서 단일 숫자를 추출합니다.
for text, probability in zip(texts, probs[0]):
    print(text, probability.item())

a photo of a bear 0.0034679945092648268
a photo of a cat 0.0006398500991053879
a photo of a dog 0.20799367129802704
a photo of a puppy 0.7878984212875366


코드에 대한 설명:

이 코드는 CLIP (Contrastive Language-Image Pre-training) 모델을 사용하여 이미지와 텍스트 간의 유사성을 측정하는 방법을 보여줍니다. CLIP은 이미지와 텍스트를 동시에 학습하여 이 둘 사이의 관계를 이해하도록 설계되었습니다.

  1. 라이브러리 가져오기: 필요한 라이브러리를 가져옵니다.

    • PIL (Pillow): 이미지 파일을 열고 처리하기 위한 라이브러리입니다.
    • torch: 텐서 연산을 위한 PyTorch 라이브러리입니다. CLIP 모델은 PyTorch로 구현되어 있습니다.
    • transformers: Hugging Face에서 제공하는 라이브러리로, CLIP 모델과 프로세서를 쉽게 사용할 수 있도록 해줍니다.
  2. 모델 및 프로세서 로드:

    • CLIPModel.from_pretrained(): 사전 훈련된 CLIP 모델을 다운로드하고 로드합니다. "openai/clip-vit-base-patch32"는 OpenAI에서 제공하는 CLIP 모델의 이름입니다.
    • CLIPProcessor.from_pretrained(): 모델과 함께 사용되는 프로세서를 다운로드하고 로드합니다. 프로세서는 이미지와 텍스트를 모델이 이해할 수 있는 형식으로 변환하는 데 사용됩니다.
  3. 이미지 및 텍스트 준비:

    • Image.open("dog.jpg"): "dog.jpg"라는 이름의 이미지를 열고 로드합니다. (이미지가 코드와 같은 디렉토리에 있어야 합니다.)
    • texts: 이미지에 대한 설명으로 사용할 텍스트 목록을 정의합니다.
  4. 입력 데이터 변환:

    • processor(): 이미지와 텍스트를 CLIP 모델이 처리할 수 있는 형식으로 변환합니다. 이 함수는 이미지를 텐서로 변환하고, 텍스트를 토큰화하여 텐서로 변환합니다.
  5. 모델 실행 및 예측:

    • model(**inputs): CLIP 모델에 입력 데이터를 전달하고 예측을 수행합니다. **inputsinputs 딕셔너리의 키와 값을 모델의 메서드 호출에 전달하는 방법입니다.
  6. 결과 해석:

    • outputs.logits_per_image: 모델의 출력에서 이미지에 대한 로짓(logits)을 추출합니다. 로짓은 각 텍스트가 이미지와 얼마나 관련 있는지 나타내는 숫자 값입니다.
    • probs = logits.softmax(dim=1): 로짓을 확률 분포로 변환합니다. softmax 함수는 로짓을 0과 1 사이의 값으로 변환하여 각 텍스트의 확률을 나타냅니다.
    • for text, probability in zip(texts, probs[0]):: 각 텍스트와 그에 해당하는 확률을 반복하고 출력합니다.

핵심 개념:

  • CLIP (Contrastive Language-Image Pre-training): 이미지와 텍스트를 동시에 학습하여 이 둘 사이의 관계를 이해하는 모델입니다.
  • 로짓 (Logits): 모델이 각 텍스트가 이미지와 얼마나 관련 있는지 나타내는 숫자 값입니다.
  • 확률 (Probabilities): 로짓을 사용하여 계산된 각 텍스트의 확률입니다. 높은 확률은 해당 텍스트가 이미지와 더 관련 있음을 의미합니다.
  • 프로세서 (Processor): 모델을 사용하여 이미지와 텍스트를 처리하는 방법을 정의하는 클래스입니다.

이 코드는 CLIP 모델을 사용하는 기본적인 예제이며, 다양한 방식으로 활용될 수 있습니다. 예를 들어, 이미지를 설명하는 가장 적합한 텍스트를 찾거나, 주어진 텍스트에 대한 이미지를 생성할 수 있습니다.


CLIP은 이미지와 텍스트를 같은 의미 공간(embedding space)에 넣어 서로 비교할 수 있도록 학습한 멀티모달 모델입니다.

특히 앞서 이야기했던 ResNet → 전이학습 → Zero-shot → MVTec AD/WinCLIP의 흐름으로 이해하면 CLIP의 개념이 훨씬 명확합니다.

Image

Image

Image

Image

Image

1. CLIP을 한 문장으로 이해하면

"이미지와 그 이미지를 설명하는 문장을 서로 가까운 위치에 놓도록 학습한 모델"

입니다.

예를 들어 다음과 같은 이미지가 있다고 해보겠습니다.

이미지

🐕 강아지가 공원에서 뛰고 있음

CLIP은 이미지와 텍스트를 각각 Encoder에 넣습니다.

                 ┌─────────────────┐
Image ──────────▶│ Image Encoder   │───▶ Image Embedding
                 └─────────────────┘
                                             │
                                             │ Similarity
                                             ▼
                 ┌─────────────────┐
Text ───────────▶│ Text Encoder    │───▶ Text Embedding
                 └─────────────────┘

예를 들어:

Image Embedding
[0.12, -0.35, 0.82, ..., 0.41]

Text Embedding
[0.10, -0.31, 0.79, ..., 0.38]

두 벡터의 cosine similarity가 높다면

"이 이미지와 이 문장은 의미적으로 비슷하다."

라고 판단할 수 있습니다.


2. 기존 CNN과 무엇이 다른가?

여기가 가장 중요합니다.

예전에 사용했던 ResNet18 + CIFAR-10을 생각해보겠습니다.

ResNet은 일반적으로 다음과 같이 학습합니다.

Image
  ↓
ResNet
  ↓
Feature
  ↓
Linear Layer
  ↓
10개의 class
  ↓
dog
cat
car
...

즉, 정해진 클래스 분류기입니다.

학습할 때

Image → dog
Image → cat
Image → airplane

같은 정답 label이 필요합니다.


CLIP은 구조가 다릅니다.

CLIP은

Image ──▶ Image Encoder ──▶ Image Vector
                                  ↕
                            Similarity
                                  ↕
Text ───▶ Text Encoder ────▶ Text Vector

입니다.

따라서 "dog"라는 class를 직접 분류하도록 학습하는 것이 아닙니다.

대신

[강아지 이미지] ↔ "a photo of a dog"

[자동차 이미지] ↔ "a photo of a car"

[고양이 이미지] ↔ "a photo of a cat"

처럼 이미지와 자연어의 관계를 학습합니다.


3. CLIP의 핵심은 Contrastive Learning

CLIP의 CL은 Contrastive Language–Image Pre-training의 약자입니다.

핵심은 Contrastive Learning(대조 학습)입니다.

예를 들어 학습 데이터에 다음과 같은 이미지-텍스트 쌍이 있다고 해봅시다.

Image 1 → "a dog playing in a park"
Image 2 → "a cat sitting on a chair"
Image 3 → "a car on the road"

CLIP은 올바른 pair의 similarity를 높이고,

Image 1 ↔ "a dog playing in a park"   ↑
Image 2 ↔ "a cat sitting on a chair"  ↑
Image 3 ↔ "a car on the road"         ↑

틀린 pair의 similarity는 낮추도록 학습합니다.

Image 1 ↔ "a cat sitting on a chair" ↓
Image 1 ↔ "a car on the road"        ↓

이를 반복하면서 이미지와 텍스트의 공통 의미 공간을 만들어갑니다.


4. 실제 학습에서는 어떻게 하나?

한 batch에 이미지와 텍스트가 4개 있다고 해보겠습니다.

             Text
          T1   T2   T3   T4

Image I1  0.9  0.2  0.1  0.3
Image I2  0.1  0.8  0.2  0.1
Image I3  0.2  0.1  0.9  0.2
Image I4  0.3  0.1  0.2  0.8

대각선이 정답입니다.

I1 ↔ T1
I2 ↔ T2
I3 ↔ T3
I4 ↔ T4

따라서 학습 목표는 대략

diagonal similarity ↑
off-diagonal similarity ↓

가 됩니다.

이것이 CLIP의 핵심적인 학습 방식입니다.


5. 그러면 Zero-shot이 왜 가능한가?

이 부분이 CLIP의 가장 재미있는 부분입니다.

일반적인 이미지 분류 모델은 학습할 때

dog
cat
car
airplane
...

이라는 class를 알고 있어야 합니다.

그런데 CLIP은 텍스트와 이미지의 관계를 학습했기 때문에, 새로운 class가 등장해도 텍스트로 설명할 수 있습니다.

예를 들어 CLIP을 학습할 때

dog
cat
car

만 직접적인 분류 대상으로 사용하지 않았다고 생각해봅시다.

그런데 테스트할 때

"a photo of a dog"
"a photo of a cat"
"a photo of an airplane"

을 만들어서 이미지와 비교합니다.

                 similarity

Image
  │
  ├── "a photo of a dog"       0.82
  │
  ├── "a photo of a cat"       0.31
  │
  └── "a photo of an airplane" 0.12

그러면

dog

라고 판단할 수 있습니다.

새로운 classifier를 학습시키지 않았는데도 분류가 가능합니다.

그래서 Zero-shot classification이라고 합니다.


6. "Zero-shot = 사전학습이 필요 없다"는 뜻은 아니다

이 부분은 이전 질문과 연결됩니다.

아닙니다.

Zero-shot은

새로운 작업이나 새로운 클래스를 대상으로 별도의 supervised training을 하지 않는다

는 의미입니다.

CLIP 자체는 엄청난 규모의 이미지-텍스트 데이터로 사전학습(pre-training) 되어 있습니다.

개념적으로 보면

대규모 Image-Text Dataset
          ↓
      CLIP Pretraining
          ↓
   Image Encoder
   Text Encoder
          ↓
   공통 Embedding Space
          ↓
      ┌───────┬────────┬────────┐
      ↓       ↓        ↓        ↓
   분류     검색     유사도    Anomaly

입니다.


7. 그렇다면 CLIP의 Text는 왜 중요한가?

ResNet에서는

Image → Feature → Class

였지만,

CLIP에서는

Image → Image Embedding
                    ↕
              Text Embedding
                    ↕
             Semantic Meaning

입니다.

따라서 텍스트가 단순한 label이 아니라 일종의 의미를 표현하는 query가 됩니다.

예를 들어

"a photo of a normal object"
"a photo of a defective object"

라고 할 수도 있고,

더 구체적으로

"a normal metal surface"
"a scratched metal surface"
"a cracked metal surface"
"a dented metal surface"

처럼 표현할 수도 있습니다.

이것이 WinCLIP 같은 anomaly detection 방법에서 CLIP이 활용될 수 있는 이유와 연결됩니다.


8. MVTec AD와 연결하면

앞서 질문하셨던 부분이 바로 여기입니다.

MVTec AD에

bottle
cable
capsule
hazelnut
metal_nut
...

같은 객체가 있고,

예를 들어 metal_nut에 대해

normal
anomaly

만 있다고 생각하면,

"그러면 CLIP 학습용 Text가 normal과 anomaly밖에 없는 것 아닌가?"

라는 의문이 생깁니다.

하지만 CLIP 자체는 MVTec AD의 normal/anomaly label을 학습하기 위해 만들어진 모델이 아닙니다.

CLIP은 이미 일반적인 이미지-텍스트 관계를 학습한 사전학습 모델입니다.

WinCLIP과 같은 방법에서는 이 pretrained CLIP의 표현력을 이용해서

정상적인 이미지
        ↕
정상적인 상태를 설명하는 텍스트

비정상 이미지
        ↕
비정상 상태를 설명하는 텍스트

간의 관계를 이용하는 것입니다.


9. CLIP에서 "문장"은 단순한 Label보다 강력하다

이것이 ResNet과 CLIP을 비교할 때 상당히 중요한 차이입니다.

ResNet의 label:

dog

CLIP의 text:

"a photo of a dog"

뿐만 아니라

"a dog running in a park"
"a close-up photo of a dog"
"a damaged metal surface"

처럼 상황과 속성을 표현할 수 있습니다.

즉,

Label
   ↓
하나의 category

Text Prompt
   ↓
의미를 가진 표현

이라는 차이가 있습니다.


10. CLIP의 전체 구조

조금 더 기술적으로 보면 다음과 같습니다.

                CLIP
                 │
       ┌─────────┴─────────┐
       │                   │
       ▼                   ▼
 Image Encoder        Text Encoder
 (ViT/ResNet)         (Transformer)
       │                   │
       ▼                   ▼
 Image Feature        Text Feature
       │                   │
       └────────┬──────────┘
                ▼
       Projection / Embedding
                │
                ▼
       Normalized Embeddings
                │
                ▼
        Cosine Similarity

중요한 것은 두 Encoder가 서로 다른 입력을 받지만 최종적으로 같은 공간에서 비교 가능하도록 학습되어 있다는 것입니다.


11. CLIP을 수학적으로 보면

이미지 Encoder를

f(I)f(I)

텍스트 Encoder를

g(T)g(T)

라고 하면,

이미지와 텍스트의 similarity는 보통 cosine similarity를 이용해

sim(I,T)=f(I)g(T)f(I)g(T)sim(I,T) = \frac{f(I)\cdot g(T)} {\|f(I)\|\|g(T)\|}

처럼 계산할 수 있습니다.

즉,

Image
 ↓
f(I)
 ↓
Vector

Text
 ↓
g(T)
 ↓
Vector

       cosine similarity
             ↓
          얼마나
        의미적으로 가까운가?

입니다.


12. 그래서 CLIP은 "이미지를 이해한다"고 말할 수 있는가?

어느 정도는 그렇지만, 정확하게 표현하면

이미지와 자연어 표현 사이의 의미적 관계를 학습했다

라고 하는 것이 좋습니다.

CLIP이 이미지 내부의 모든 것을 인간처럼 이해한다는 의미는 아닙니다.

하지만

이미지 → 특징 추출
텍스트 → 의미 추출
       ↓
두 의미를 비교

할 수 있다는 것이 기존 CNN과 매우 큰 차이입니다.


13. 지금까지 배운 모델들을 한 줄로 비교하면

모델핵심
ResNet이미지를 특징으로 변환하고 class를 분류
AutoEncoder입력을 압축하고 복원
PatchCore정상 feature와의 거리를 이용해 anomaly 탐지
CLIP이미지와 텍스트를 같은 의미 공간에 정렬
WinCLIPCLIP의 image/text 표현을 이용한 zero-shot anomaly detection

특히 PatchCore와 CLIP의 차이가 중요합니다.

PatchCore

Image
 ↓
CNN Feature
 ↓
Patch Feature
 ↓
Normal Feature Memory
 ↓
거리 계산
 ↓
Anomaly Score

반면 CLIP은

Image
 ↓
Image Encoder
 ↓
Image Embedding
       ↕
Text Embedding
 ↓
Similarity

입니다.


14. 가장 중요한 개념 하나

CLIP을 이해할 때 저는 다음 그림을 머릿속에 가지고 있는 것을 추천합니다.

              같은 의미 공간

      "a dog" ●
              │
              │
       🐕     ●  Image embedding
              │
              
                         ● "a car"
                         
                    🚗   ●

즉,

CLIP은 이미지와 텍스트를 하나의 공통 언어로 번역해 놓는 모델

이라고 생각하면 상당히 이해하기 쉽습니다.

그리고 이 관점에서 보면 다음 단계로 자연스럽게 연결됩니다.

ResNet → Feature Space

CLIP → Image/Text Joint Feature Space

PatchCore → Feature Space에서 정상 데이터와 거리 측정

WinCLIP → CLIP의 Joint Feature Space에서 정상/이상 의미와 이미지의 관계 측정

이렇게 보면 지금까지 질문하셨던 ResNet, Zero-shot, MVTec AD, PatchCore, WinCLIP이 사실 하나의 큰 흐름으로 연결됩니다.

profile
Hello, I'm Terry! 👋 Enjoy every moment of your life! 🌱 My current interests are Signal processing, Machine learning, Python, Database, LLM & RAG, MCP & ADK, Multi-Agents, Physical AI, ROS2...

0개의 댓글