ConvNeXt와 Swin Transformer의 등장 배경
2020년대 초반 컴퓨터 비전 분야는 Vision Transformer(ViT)의 등장으로 큰 변화를 맞이했습니다. 하지만 Transformer 구조가 항상 CNN보다 우수한 것일까요? 이러한 질문에 답하기 위해 ConvNeXt는 순수 CNN 아키텍처를 현대화했고, Swin Transformer는 계층적 구조를 도입한 효율적인 Transformer를 제안했습니다.
핵심 포인트: ConvNeXt는 “CNN도 제대로 설계하면 Transformer만큼 강력하다”를 증명했고, Swin Transformer는 “Transformer도 효율적으로 설계할 수 있다”를 보여줬습니다.
아키텍처 핵심 비교
| 특성 | ConvNeXt | Swin Transformer |
|---|---|---|
| 기본 구조 | Modernized CNN | Hierarchical Transformer |
| 연산 방식 | Depthwise Convolution | Shifted Window Attention |
| 계층 구조 | 4 stages (ResNet 스타일) | 4 stages (피라미드 구조) |
| 토큰 크기 | 고정 (feature map) | 단계별 병합 (4→8→16→32) |
| Inductive Bias | 강함 (locality, translation equivariance) | 약함 (데이터 의존적) |
| 연산 복잡도 | (M: window size) |
ConvNeXt의 핵심 설계 원칙
ConvNeXt는 ResNet-50을 출발점으로 삼아 Swin Transformer의 설계 철학을 단계적으로 적용했습니다:
- Patchify Stem: 겹치지 않는 convolution으로 초기 패치 임베딩
- Inverted Bottleneck: MobileNetV2처럼 채널 확장 비율 4:1
- Large Kernel Size: depthwise convolution 사용
- LayerNorm + GELU: BatchNorm 대신 LayerNorm, ReLU 대신 GELU
import torch.nn as nn
class ConvNeXtBlock(nn.Module):
def __init__(self, dim, expansion=4, kernel_size=7):
super().__init__()
self.dwconv = nn.Conv2d(dim, dim, kernel_size, padding=kernel_size//2, groups=dim)
self.norm = nn.LayerNorm(dim)
self.pwconv1 = nn.Linear(dim, expansion * dim)
self.act = nn.GELU()
self.pwconv2 = nn.Linear(expansion * dim, dim)
def forward(self, x):
input = x
x = self.dwconv(x)
x = x.permute(0, 2, 3, 1) # (N, C, H, W) -> (N, H, W, C)
x = self.norm(x)
x = self.pwconv1(x)
x = self.act(x)
x = self.pwconv2(x)
x = x.permute(0, 3, 1, 2) # (N, H, W, C) -> (N, C, H, W)
return input + x
Swin Transformer의 Shifted Window Mechanism
Swin Transformer의 핵심은 Window-based Multi-head Self-Attention (W-MSA)과 Shifted Window MSA (SW-MSA)입니다.
- W-MSA: 입력을 윈도우로 나누고 각 윈도우 내에서만 attention 계산
- SW-MSA: 윈도우를 만큼 이동시켜 윈도우 간 정보 교환
연산 복잡도:
– 전역 attention:
– 윈도우 attention:
여기서 는 feature map의 높이와 너비, 는 채널 수, 은 윈도우 크기입니다.
import torch
import torch.nn as nn
class WindowAttention(nn.Module):
def __init__(self, dim, window_size, num_heads):
super().__init__()
self.dim = dim
self.window_size = window_size
self.num_heads = num_heads
head_dim = dim // num_heads
self.scale = head_dim ** -0.5
self.qkv = nn.Linear(dim, dim * 3)
self.proj = nn.Linear(dim, dim)
def forward(self, x):
B, N, C = x.shape
qkv = self.qkv(x).reshape(B, N, 3, self.num_heads, C // self.num_heads)
qkv = qkv.permute(2, 0, 3, 1, 4)
q, k, v = qkv[0], qkv[1], qkv[2]
attn = (q @ k.transpose(-2, -1)) * self.scale
attn = attn.softmax(dim=-1)
x = (attn @ v).transpose(1, 2).reshape(B, N, C)
x = self.proj(x)
return x
실전 성능 비교
ImageNet-1K 분류 성능
| 모델 | 파라미터 | FLOPs | Top-1 Acc | Throughput |
|---|---|---|---|---|
| ConvNeXt-T | 29M | 4.5G | 82.1% | 550 img/s |
| Swin-T | 29M | 4.5G | 81.3% | 485 img/s |
| ConvNeXt-S | 50M | 8.7G | 83.1% | 340 img/s |
| Swin-S | 50M | 8.7G | 83.0% | 295 img/s |
| ConvNeXt-B | 89M | 15.4G | 83.8% | 210 img/s |
| Swin-B | 88M | 15.4G | 83.5% | 180 img/s |
Throughput 측정 환경: V100 GPU, batch size 64, mixed precision
Object Detection (COCO)
Mask R-CNN 프레임워크 기준:
| Backbone | APbox | APmask | 학습 시간 (epoch당) |
|---|---|---|---|
| ConvNeXt-T | 46.2 | 41.7 | 3.5시간 |
| Swin-T | 46.0 | 41.6 | 4.1시간 |
| ConvNeXt-B | 49.1 | 43.7 | 6.2시간 |
| Swin-B | 48.5 | 43.4 | 7.3시간 |
Semantic Segmentation (ADE20K)
UperNet 프레임워크 기준:
| Backbone | mIoU | 파라미터 | 추론 속도 (FPS) |
|---|---|---|---|
| ConvNeXt-T | 46.7 | 60M | 28 |
| Swin-T | 44.5 | 60M | 22 |
| ConvNeXt-B | 49.1 | 122M | 15 |
| Swin-B | 48.1 | 121M | 12 |
최적 선택 전략
ConvNeXt를 선택해야 할 때
- 추론 속도가 중요한 엣지 디바이스: ConvNeXt는 GPU뿐만 아니라 CPU, 모바일 환경에서도 최적화가 잘 되어 있습니다.
- 전이 학습 데이터가 제한적: Strong inductive bias 덕분에 적은 데이터로도 안정적인 성능을 보입니다.
- 기존 CNN 파이프라인 활용: ResNet 기반 코드베이스를 큰 수정 없이 업그레이드할 수 있습니다.
- Dense prediction 작업: Segmentation, depth estimation 등에서 feature map의 공간 구조를 유지하는 것이 유리합니다.
실무 예시:
import timm
# ConvNeXt로 전이 학습 (제한된 데이터셋)
model = timm.create_model('convnext_tiny', pretrained=True, num_classes=10)
# 마지막 레이어만 학습
for param in model.parameters():
param.requires_grad = False
model.head.fc.requires_grad = True
Swin Transformer를 선택해야 할 때
- 충분한 학습 데이터와 컴퓨팅 자원: Transformer는 대규모 데이터셋에서 더 높은 상한선을 보입니다.
- 멀티모달 학습: Text-image 모델(CLIP, ALIGN 등)과의 통합이 용이합니다.
- Long-range dependency가 중요: 전역적 맥락 파악이 필요한 고해상도 의료 영상, 위성 영상 분석에 유리합니다.
- 최신 연구 트렌드 활용: Transformer 기반 최신 기법(MAE, DINO 등)을 쉽게 적용할 수 있습니다.
실무 예시:
import timm
# Swin Transformer로 고해상도 의료 영상 분류
model = timm.create_model(
'swin_base_patch4_window12_384', # 384x384 입력
pretrained=True,
num_classes=5,
img_size=384
)
하이브리드 접근법
최근 연구에서는 두 아키텍처의 장점을 결합한 방법들이 제안되고 있습니다:
- 초기 단계는 CNN, 후기 단계는 Transformer: 저수준 특징은 convolution으로 추출하고, 고수준 의미는 attention으로 통합
- Task-specific 선택: Backbone은 ConvNeXt, neck은 Transformer attention 사용
class HybridModel(nn.Module):
def __init__(self):
super().__init__()
# 초기 feature extraction: ConvNeXt
self.stem = ConvNeXtBlock(dim=96)
self.stage1 = ConvNeXtBlock(dim=192)
# 고수준 reasoning: Swin attention
self.stage2 = SwinTransformerBlock(dim=384)
self.head = nn.Linear(768, num_classes)
def forward(self, x):
x = self.stem(x)
x = self.stage1(x)
x = self.stage2(x)
return self.head(x)
실전 체크리스트
프로젝트 시작 전 다음 질문들로 결정을 내리세요:
- [ ] 학습 데이터셋 크기는? (< 10만장 → ConvNeXt, > 100만장 → Swin)
- [ ] 추론 환경은? (엣지/모바일 → ConvNeXt, 클라우드 → 자유)
- [ ] Latency 요구사항은? (< 10ms → ConvNeXt, > 50ms → 자유)
- [ ] 기존 코드베이스는? (CNN 기반 → ConvNeXt, 최신 Transformer → Swin)
- [ ] 작업 유형은? (Dense prediction → ConvNeXt, Classification/Detection → 자유)
- [ ] 메모리 제약은? (< 8GB GPU → 소형 모델 + ConvNeXt)
마무리
ConvNeXt와 Swin Transformer는 서로 경쟁하기보다는 상황에 따라 선택할 수 있는 강력한 도구입니다. ConvNeXt는 순수 CNN으로도 Transformer 수준의 성능을 달성할 수 있음을 증명했고, Swin Transformer는 효율적인 Transformer 설계의 가능성을 열었습니다.
실전 권장사항:
– 프로토타이핑 단계에서는 둘 다 시도해보고 실제 데이터셋에서 성능을 비교하세요.
– ConvNeXt는 빠른 실험 사이클과 안정적인 베이스라인에 유리합니다.
– Swin Transformer는 충분한 자원이 있을 때 더 높은 성능 상한선을 제공합니다.
– 최신 timm 라이브러리를 사용하면 두 모델 모두 간단히 불러올 수 있으니 적극 활용하세요!
궁극적으로 “어떤 모델이 더 좋은가?”보다 “내 문제에 더 적합한 모델은 무엇인가?”가 올바른 질문입니다.
이 글이 도움이 되셨나요?
Buy me a coffee
답글 남기기