CLIP은 2021년에 언어-이미지 쌍을 사전학습하는 방법을 제시한 연구입니다. (이미지, 이미지에 대한 텍스트)를 쌍으로 대조적학습(Contrastive learning)을 사전학습하여, 자연어처리에서와의 접근방식과 유사하게 비전문제에서도 사전학습결과후, 각 테스크에서 좋은 성능을 낼 수 있음을 보여줍니다.

 

Preliminary


  • Zero shot learning(제로샷 러닝): 모델이 훈련 데이터에서 직접 학습하지 않은 클래스 또는 레이블을 인식하고 분류할 수 있게 하는 학습방법

 

 

Introduction


언어모델에서의 MLM(Masked language model)같은 특정 테스트와 무관한 학습을 하는 것으로 자연어쪽에서는 성공적인 연구성과를 보여주었습니다. 흔히, 일반화된 아키텍처(General model)에서 다운스트림으로 제로샷(Zero shot)으로 전이학습하기가 용이해져서, 아키텍처에 예측할 해더(분류기레이어)등을 추가할필요가 없어져왔습니다. 그 결과로 GPT-3같이 여러 목적에도 다양하게 사용할 수 있는 모델이 데이터가 부족해도 사용할 수 있게 되었습니다. 이런 학습방법은 웹에서 수집한 데이터로 사전학습을 하니, 라벨링을 직접하지 않습니다. 그럼에도, 크라우드소싱으로 라벨링한 것보다 좋은 성능을 보였고, 사전학습을 하는 것이 표준적인 관행이 되었습니다. 하지만, 비전문제에서도 이런 접근방법이 가능한지에 대해서는 아직 연구된바 없었습니다. 특히, 비전문제에서는 보통 클라우드 라벨링으로 모은 ImageNet으로 사전학습데이터를 사용하는데, 웹에서 사용한 데이터로 이런 사전학습을 할 수 없을까?가 이 연구의 motivation입니다.

 

여태까지는, 이미지를 표현할 때, 언어를 이용한 표현을 해볼 수 있겠는지와 관련된 연구는 별로 없었습니다. 실제로, 이전의 연구성과들에서는성능이 거의 안나왔었습니다 (11.5% 정확도, 이 때, SOTA가 88.4%). 이후, 인스타그램 이미지에서 ImageNet 관련 이미지 해시테그를 예측 하는 사전학습을 이용하자, SOTA보다 더 좋은 결과들을 보였습니다 (역시, 데이터가 많아야..). 이후에도 비슷한 접근방식으로 JFT-300M dataset을 만들어 사전학습하여 성능향상을 보였던 논문도 있었습니다. 하지만, 이런 방식도 결국 클레스를 N개로 정하다보니, "zero-shot"의 학습성능을 제한한다는 것에 한계를 제안합니다(결국 softmax하여 분류기를 추가하기에 일반화 목적성능의 달성이 어려움). 생각해보면, 자연어는 이미지보다 더 많은 클레스의 표현이 가능하기에, 이런 지도학습에도 더 도움을 줄 수 있을 것 같습니다. 

 

CLIP 방법론: 이미지 표현 < 자연어표현이 더 풍부, 자연어기반 지도학습으로 zero-shot구현


CLIP의 핵심아이디어는 이미지의 인식방법이 자연어로부터 배울 수 있다는 것입니다. 이를 위해 아래의 단계대로 실험을 진행했습니다.

  1. 대규모 데이터셋 구축(creating a sufficient large dataset)
  2. CLIP(Pre-training method) 구성(selecting an efficient pretraining method)
  3. 모델 크기 선택(Choosing and scaling a model)
  4. 학습(Training)

 

 

1. 대규모 데이터셋구축

새로운 아이디어는 아니고, 이전에는 N-gram이나 크라우드소싱데이터를 이용했다면, CLIP에서는 대규모데이터를 학습하려 노력했습니다. 자연어로 지도가 됨을 보여주기 위해서, 대규모데이터가 필요했습니다. 

특히 1) 직접 클레스에 라벨링이 아니라 이미지에 대한 설명을 학습해볼 수도 있는 것이구요(이미지의 특징의 학습이 자연어로 지도됨). 2) 라벨링이 되어있지 않아도, 온라인상에서 일반적인 더 큰 이미지를 구축하려고 노력했습니다. ImageNet이나 MS-COCO 데이터셋 10만장밖에안되고, YFCC100M 데이터도 100million이지만 데이터 퀄리티가 좋지 않아(title, 설명등이 미포함), 전처리하고나면 ImageNet정도 사이즈밖에안되서 적다고합니다. 실제로 OpenAI에서는 4억장의 이미지-텍스트 쌍을 인터넷에서 구했다고 합니다. 이미지를 얻기위해서 5만개의 쿼리를 사용했고, 클레스 벨런스때문에, 쿼리당 20,000개의 이미지-텍스트 쌍을 넘지않도록했다고합니다. 이 데이터셋을 WebImageText(WIT)라 명명했습니다.

 

 

2. CLIP(Pre-training method) 

CLIP은 효율적인 사전학습을 찾으려고 노력한 결과물입니다. 연구 초기에 사전학습방식을 결정할때, 아래와 같은 3가지의 방법을 적용해보았습니다. 3가지 목적으로 각각 이미지는 ViT(Vision Transformer)로 인코딩하고, 텍스트는 Transformer로 인코딩한다음에 이미지의 캡션을 예측하도록 Joint traning을 진행했습니다. 각 3가지는 Transformer Language model은 언어 생성, Bag of words은 순서가 없는, Bag of words contrasative (CLIP)은 BOW에 대조적학습까지 적용한 방법입니다. 같은 파라미터라면, 성능은 CLIP이 훨씬 효율이 높아 CLIP으로 사전학습을 하는 것을 목표로 했습니다.

 

CLIP은 N개의 배치로 튜플인 (이미지, 텍스트)의 페어를 입력을 받습니다. 만일 N개가 배치로 들어온다면, N x N의 메트릭스를 만들 수 있고, N개의 이미지와 N개의 텍스트 각각 하나씩만 실제 연관된 이미지-텍스트여서 N개의 Positive로 정의하고, $N^{2}-N$의 negative 페어를 만들어냅니다. 이를 대조적학습으로 학습하는 방법입니다 (아래의 Figure 3). 

Figure 3. Numpy-like한 슈도코드

3. 모델 크기 선택(Choosing and scaling a model)

이미지 인코딩을 위한 아키텍처를 고를때는 처음에는 ResNet-50을 고르고 일부 변형했다고 합니다. 이는 이미 일반적으로 성공적인 성능을 보여왔기에 첫 선택이었다고 합니다. 그리고, 두 번째로는 ViT을 이용했다고합니다. 텍스트 인코딩은 Transformer을 이용했고, 65M Parameter + 12 Layer + 8 attention head + BPE 인코딩으로 얻어진 voca size은 49,152사이즈입니다.

4. 학습(Training)

학습은 ResNet 시리즈 5개(ResNet-50, 101 Efficientnet 아류 3개)랑 Vision transformer (B/32, B/16, L/14)을 학습했습니다. 그외엔 하이퍼파라미터는 Grid search/랜덤서치로 1에폭에 했구요.

 

결과


본문을 참고하시면 좋을 것 같습니다. 아래와 같은 내용이 담겨있습니다.

  1. Zero-shot Transfer 하는 경우 이미지분류에서도 압도적인 성능을 낼 수 있음
  2. 프롬프트엔지니어링하면, 기존대비 5%p이상의 성능을 낼 수 있음
  3. CLIP이 잘되는 /잘안되는 데이터셋마다 차이를 보이긴 함
  4. Linear probe(인코더+분류기 레이어 부착후 재학습)한 경우도 매우 좋음

 

사용예시


CLIP official github에 제시된 것처럼 clone 후에, jupyter notebook에서 모델을 다운로드 받아보겠습니다.

import torch
import clip
from PIL import Image

device = "cuda" if torch.cuda.is_available() else "cpu"
model, preprocess = clip.load("ViT-B/32", device=device)

 

CLIP.png은 아래와 같은 다이어그램입니다

위와 같은 다이어그램을 preprocessing (resize->CenterCrop -> RGB -> 텐서변환->정규화)를 거쳐 전처리하고 CLIP에 포워딩해서 백터를 얻어보겠습니다. 또한, CLIP에 넣을 3개의 배치로 텍스트를 넣어보겠습니다. 텍스트는 토큰화되어서 (3, 77)의 77개의 시퀀싱을 갖는 백터며, 각 순서에 맞춰 인덱싱으로 원소가 구성되어있습니다.

image = preprocess(Image.open("CLIP.png")).unsqueeze(0).to(device)
text = clip.tokenize(["a diagram", "a dog", "a cat"]).to(device) # torch.Size([3, 77])


------
print(model.visual) # Vision transformer은 768차원 반환하지만 추가로, 512차원으로 embedding해주는 레이어가 부착되어있습니다.
VisionTransformer(
  (conv1): Conv2d(3, 768, kernel_size=(32, 32), stride=(32, 32), bias=False)
  (ln_pre): LayerNorm((768,), eps=1e-05, elementwise_affine=True)
  (transformer): Transformer(
  ...
  (ln_post): LayerNorm((768,), eps=1e-05, elementwise_affine=True)
 )
 
-----
print(model.transformer) # transformer은 512차원의 벡터를 반환합니다.
Transformer(
  (resblocks): Sequential(
  ...
  (ln_2): LayerNorm((512,), eps=1e-05, elementwise_affine=True)
    )
  )
)

 

CLIP논문에 맞춰, 이미지 표현(image_features), 텍스트 피쳐(text_features)을 구하고, 정규화 후 코사인유사도를 계산해보겠습니다. 유사도 계산후, 유사도(logit)으로 3차원의 벡터가 얻어졌고, "CLIP.png"와 "a diagram", "a dog", "a cat"의 각각의 쌍(pairwise)의 유사도가 [25.5528, 20.0899, 19.7495]로 얻어졌습니다. softmax로 구하면, 0.9928로 0번째 텍스트와 가장 유사도가 높음을 알 수 있습니다. CLIP은 이와 같이 이미지를 가장 잘 설명할 수 있는 text와의 유사도를 구하는 방식입니다.

# normalized features
image_features = image_features / image_features.norm(dim=1, keepdim=True)
text_features = text_features / text_features.norm(dim=1, keepdim=True)

# cosine similarity as logits
logit_scale = model.logit_scale.exp()
logits_per_image = logit_scale * image_features @ text_features.t()  # (1, 512) @ (512, 3)
logits_per_text = logits_per_image.t()

print(logits_per_image.shape, logits_per_text.shape)
print(logits_per_image)
print(logits_per_image.softmax(dim=-1))
# torch.Size([1, 3]) torch.Size([3, 1])
# tensor([[25.5528, 20.0899, 19.7495]], grad_fn=<MmBackward0>)
# tensor([[0.9928, 0.0042, 0.0030]], grad_fn=<SoftmaxBackward0>)

 

그외 사례에서도 아래와같이 적용해보면, 약학정보원에서 얻은 약(타이레놀)과 가장 설명이 유사한 텍스트를 잘 찾아줌을 확인할 수 있습니다.

반응형

+ Recent posts