ViT
Vision Transformer
이미지를 패치로 나눠 Transformer에 입력하는 비전 모델. CNN의 대안으로 대규모 데이터셋에서 뛰어난 성능.
Vision Transformer
이미지를 패치로 나눠 Transformer에 입력하는 비전 모델. CNN의 대안으로 대규모 데이터셋에서 뛰어난 성능.
Vision Transformer(ViT)는 2020년 Google Research가 발표한 이미지 분류 모델로, 자연어 처리에서 성공한 Transformer 아키텍처를 컴퓨터 비전에 최초로 성공적으로 적용했습니다. "An Image is Worth 16x16 Words" 논문에서 이미지를 16x16 픽셀 패치로 분할하여 마치 단어처럼 처리하는 혁신적인 접근법을 제시했습니다.
ViT 이전의 컴퓨터 비전은 CNN(Convolutional Neural Network)이 지배했습니다. CNN은 지역적 특징을 추출하는 데 효과적이지만, 이미지 전체의 전역적 관계를 파악하는 데는 한계가 있었습니다. ViT는 Self-Attention 메커니즘을 통해 이미지의 모든 패치 간 관계를 동시에 학습하여 이 문제를 해결했습니다.
ViT의 작동 원리는 다음과 같습니다. 입력 이미지를 고정 크기 패치(보통 16x16)로 분할하고, 각 패치를 선형 임베딩으로 변환합니다. 위치 정보를 추가한 후 Transformer 인코더에 입력하면, Multi-Head Self-Attention을 통해 패치 간 관계를 학습합니다. CLS 토큰의 출력을 사용하여 최종 분류를 수행합니다.
실무에서 ViT는 ImageNet 같은 대규모 데이터셋에서 CNN을 능가하는 성능을 보여줍니다. 특히 사전 학습(Pre-training) 후 파인튜닝 패러다임에서 강점을 발휘하며, CLIP, DALL-E, Stable Diffusion 등 멀티모달 모델의 비전 인코더로 널리 사용됩니다. Hugging Face Transformers를 통해 쉽게 사용할 수 있습니다.
import torch
from transformers import ViTImageProcessor, ViTForImageClassification
from PIL import Image
import requests
# 1. 모델과 프로세서 로드
model_name = "google/vit-base-patch16-224"
processor = ViTImageProcessor.from_pretrained(model_name)
model = ViTForImageClassification.from_pretrained(model_name)
# 2. 이미지 로드 (URL 또는 로컬 파일)
url = "http://images.cocodataset.org/val2017/000000039769.jpg"
image = Image.open(requests.get(url, stream=True).raw)
# 3. 이미지 전처리 및 추론
inputs = processor(images=image, return_tensors="pt")
with torch.no_grad():
outputs = model(**inputs)
logits = outputs.logits
# 4. 예측 결과 출력
predicted_class_idx = logits.argmax(-1).item()
predicted_label = model.config.id2label[predicted_class_idx]
confidence = torch.softmax(logits, dim=-1)[0, predicted_class_idx].item()
print(f"예측 클래스: {predicted_label}")
print(f"신뢰도: {confidence:.2%}")
# 5. Top-5 예측 출력
top5_probs, top5_indices = torch.topk(torch.softmax(logits, dim=-1), 5)
print("\nTop-5 예측:")
for prob, idx in zip(top5_probs[0], top5_indices[0]):
label = model.config.id2label[idx.item()]
print(f" {label}: {prob.item():.2%}")
# 6. 특징 추출 (임베딩)
from transformers import ViTModel
feature_model = ViTModel.from_pretrained(model_name)
with torch.no_grad():
features = feature_model(**inputs)
cls_embedding = features.last_hidden_state[:, 0, :] # CLS 토큰
print(f"\nCLS 임베딩 차원: {cls_embedding.shape}") # [1, 768]
# 7. 커스텀 데이터셋 파인튜닝 예시
from transformers import Trainer, TrainingArguments
from datasets import load_dataset
# 데이터셋 로드 (예: CIFAR-10)
# dataset = load_dataset("cifar10")
#
# training_args = TrainingArguments(
# output_dir="./vit-finetuned",
# num_train_epochs=3,
# per_device_train_batch_size=16,
# learning_rate=2e-5,
# evaluation_strategy="epoch"
# )
#
# trainer = Trainer(
# model=model,
# args=training_args,
# train_dataset=dataset["train"],
# eval_dataset=dataset["test"]
# )
ViT 모델 변형 비교 (ImageNet-1K Top-1 Accuracy)
| 모델 | 파라미터 | ImageNet Acc. | 패치 크기 | 입력 해상도 |
|---|---|---|---|---|
| ViT-Tiny | 5.7M | 72.2% | 16x16 | 224x224 |
| ViT-Small | 22M | 79.9% | 16x16 | 224x224 |
| ViT-Base | 86M | 84.5% | 16x16 | 384x384 |
| ViT-Large | 307M | 87.8% | 16x16 | 384x384 |
| ViT-Huge | 632M | 88.5% | 14x14 | 518x518 |
CNN vs ViT 비교
"이미지 분류 모델로 ViT를 검토하고 있는데요, 우리 데이터셋이 10만 장 정도라 CNN 기반 EfficientNet이 더 나을 수 있어요. ViT는 대규모 사전학습 모델을 파인튜닝하는 방식으로 쓰면 좋을 것 같습니다."
"ViT가 CNN과 다른 점이 뭔가요?" - "CNN은 컨볼루션으로 지역 특징을 계층적으로 추출하지만, ViT는 Self-Attention으로 모든 패치 간 전역 관계를 한 번에 학습합니다. 그래서 대규모 데이터에서 강점이 있고, 작은 데이터에서는 inductive bias가 부족해 일반화가 어려울 수 있어요."
"CLIP이나 Stable Diffusion의 이미지 인코더가 ViT 기반이에요. 특히 CLIP ViT-L/14는 이미지-텍스트 정렬이 뛰어나서 zero-shot 이미지 분류나 검색에서 범용적으로 쓰이죠."
ViT를 처음부터 학습하려면 최소 수백만 장의 이미지가 필요합니다. 1만 장 정도의 데이터로 scratch 학습하면 과적합이 심합니다. 반드시 사전학습된 모델을 파인튜닝하세요.
ViT는 고정 패치 수로 학습됩니다. vit-base-patch16-224는 224x224 이미지를 14x14 패치로 나눕니다. 다른 해상도 이미지를 입력하면 위치 임베딩이 맞지 않아 성능이 저하됩니다. processor가 자동 리사이즈하지만, 원본 해상도가 크게 다르면 정보 손실이 발생합니다.
분류에는 ViTForImageClassification, 특징 추출에는 ViTModel을 사용하세요. 객체 탐지/세그멘테이션에는 Swin Transformer나 DETRs가 더 적합합니다. CLIP ViT는 멀티모달 태스크에 사용하세요.