시맨틱 세그멘테이션(Semantic Segmentation)은 이미지의 모든 픽셀에 클래스 레이블을 할당하는 작업이다. 단순 분류(이미지 전체) 또는 객체 탐지(바운딩 박스)보다 세밀하며, 픽셀 단위로 "이 영역이 무엇인지"를 판단한다. 자율주행, 의료 영상, 위성 이미지 분석 등에 활용된다.
세그멘테이션 유형 비교
| 유형 | 설명 | 같은 클래스 여러 객체 | 예시 모델 |
|---|
| 시맨틱 | 픽셀 → 클래스 레이블 | 구분하지 않음 | FCN, DeepLab, SegFormer |
| 인스턴스 | 픽셀 → 개체 단위 레이블 | 각각 구분 | Mask R-CNN, YOLACT |
| 파노픽 | 시맨틱 + 인스턴스 결합 | 구분 + 배경 처리 | Panoptic FPN, Mask2Former |
예시 이미지에 개 두 마리가 있을 때:
시맨틱: [개][개][배경][배경] ← 두 개를 같은 "개" 클래스로 처리
인스턴스: [개_1][개_2][배경] ← 두 개를 각각 다른 객체로 구분
파노픽: [개_1][개_2][잔디][하늘] ← 인스턴스 + 배경 클래스 동시 처리
핵심 개념 용어
| 용어 | 설명 |
|---|
| Classification | 이미지 전체에서 객체 클래스 판별 |
| Localization | 관심 영역의 위치 특정 |
| Object Detection | 클래스 + 위치 (바운딩 박스) |
| Semantic Segmentation | 픽셀 단위 클래스 분류 (위치 + 분류 통합) |
| Instance Segmentation | 객체 탐지 기반, 개체별 픽셀 마스크 생성 |
| Things | 셀 수 있는 객체 (사람, 차, 개) — 인스턴스 구분 가능 |
| Stuff | 셀 수 없는 배경 (하늘, 잔디, 도로) — 시맨틱 처리 |
시맨틱 분할이 중요한 이유
AI·머신러닝의 발전으로 이미지 분할은 컴퓨터가 시각 정보를 인간의 뇌와 유사하게 해석하는 핵심 기술이 됐다.
이미지 분석 작업은 다음 세 가지 질문으로 구분된다.
| 질문 | 작업 | 예시 |
|---|
| 무엇이 있는가 (What) | 이미지 분류 | "이 이미지에 개가 있다" |
| 어디에 있는가 (Where) | 객체 탐지 | "개가 이 바운딩 박스 안에 있다" |
| 정확히 어디까지인가 (Exactly where) | 시맨틱 분할 | "이 픽셀들이 개다" |
시맨틱 분할은 세 질문을 동시에 해결한다. 객체 탐지가 대략적인 위치(바운딩 박스)를 제공하는 데 비해, 시맨틱 분할은 픽셀 단위의 정확한 경계를 출력해 더 정밀한 장면 이해가 가능하다. 자율주행·의료 영상·위성 분석처럼 경계의 정확도가 의사결정에 직결되는 영역에서 필수적이다.
시맨틱 vs 인스턴스: 시맨틱 분할은 동일 클래스의 여러 객체가 겹쳐 있으면 하나의 세그먼트로 합쳐 처리한다. 인스턴스 분할은 가려진 경우에도 개별 인스턴스를 구별한다. 판옵틱 분할은 공통 백본(주로 FPN) 위에 시맨틱 헤드와 인스턴스 헤드를 연결해 두 작업을 동시에 수행하며, 초기 방식(두 작업 따로 수행 후 후처리 결합)보다 계산 효율이 높다.
동작 워크플로우
1. 데이터 수집 및 픽셀 단위 주석(Annotation)
↓
2. CNN/Transformer 기반 인코더-디코더 모델 선택
↓
3. 학습: 각 픽셀의 클래스 확률 예측 → 손실 계산
↓
4. 추론: 새 이미지 입력 → 픽셀별 클래스 확률 맵 출력
↓
5. Argmax → 최종 세그멘테이션 맵 (H × W, 각 값 = 클래스 인덱스)
인코더-디코더 구조
현대 세그멘테이션 모델의 공통 구조.
입력 이미지 (H×W×3)
↓
[인코더] — 다운샘플링, 특성 추출 (ResNet, Swin 등)
↓ skip connections (U-Net 방식)
[디코더] — 업샘플링, 공간 해상도 복원
↓
출력 맵 (H×W×C) → argmax → 세그멘테이션 맵
핵심 아키텍처
FCN (Fully Convolutional Network, 2015)
최초로 CNN을 완전 합성곱 레이어로만 구성. 완전 연결층(FC)을 제거해 임의 크기 입력 처리 가능.
FCN의 핵심 연산 두 가지:
- •다운샘플링: 컨볼루션 레이어가 쌓일수록 공간 해상도가 줄어든다. 고수준 특성은 추출되지만 픽셀 단위 위치 정보가 손실된다.
- •최대 풀링(Max Pooling): 특성 맵의 영역에서 가장 큰 값만 선택해 다음 레이어로 전달한다. 불변성을 높이지만 해상도를 추가로 낮춘다.
이를 보완하기 위해 전치 합성곱(ConvTranspose2d) 으로 업샘플링해 원래 해상도의 세그멘테이션 맵을 복원한다.
python
import torch.nn as nn
import torchvision
class FCN(nn.Module):
def __init__(self, num_classes=21):
super().__init__()
backbone = torchvision.models.vgg16(pretrained=True).features
self.encoder = backbone
# FC → 1×1 Conv 변환 (임의 해상도 지원)
self.classifier = nn.Sequential(
nn.Conv2d(512, 4096, 1), nn.ReLU(), nn.Dropout(),
nn.Conv2d(4096, 4096, 1), nn.ReLU(), nn.Dropout(),
nn.Conv2d(4096, num_classes, 1),
)
self.upsample = nn.ConvTranspose2d(num_classes, num_classes, 32, stride=32)
def forward(self, x):
x = self.encoder(x)
x = self.classifier(x)
return self.upsample(x)
U-Net (2015) — 인코더-디코더 + Skip Connection
의료 영상 분할을 위해 개발. 스킵 커넥션이 인코더의 공간 정보를 디코더로 직접 전달해 경계 복원 우수.
python
import torch
import torch.nn as nn
class DoubleConv(nn.Module):
def __init__(self, in_ch, out_ch):
super().__init__()
self.net = nn.Sequential(
nn.Conv2d(in_ch, out_ch, 3, padding=1), nn.BatchNorm2d(out_ch), nn.ReLU(inplace=True),
nn.Conv2d(out_ch, out_ch, 3, padding=1), nn.BatchNorm2d(out_ch), nn.ReLU(inplace=True),
)
def forward(self, x): return self.net(x)
class UNet(nn.Module):
def __init__(self, in_channels=3, num_classes=21):
super().__init__()
f = [64, 128, 256, 512]
self.enc = nn.ModuleList([DoubleConv(in_channels if i==0 else f[i-1], f[i]) for i in range(4)])
self.pool = nn.MaxPool2d(2)
self.bottleneck = DoubleConv(f[-1], f[-1]*2)
self.up = nn.ModuleList([nn.ConvTranspose2d(f[-1]*2 if i==0 else f[3-i+1], f[3-i], 2, 2) for i in range(4)])
self.dec = nn.ModuleList([DoubleConv(f[3-i]*2, f[3-i]) for i in range(4)])
self.out_conv = nn.Conv2d(f[0], num_classes, 1)
def forward(self, x):
skips = []
for enc in self.enc:
x = enc(x); skips.append(x); x = self.pool(x)
x = self.bottleneck(x)
for i, (up, dec) in enumerate(zip(self.up, self.dec)):
x = up(x)
x = torch.cat([skips[3-i], x], dim=1)
x = dec(x)
return self.out_conv(x)
model = UNet()
print(model(torch.randn(2, 3, 256, 256)).shape) # (2, 21, 256, 256)
DeepLab v3+ (2018) — 팽창 합성곱 + ASPP
Atrous(팽창) 합성곱으로 해상도 손실 없이 넓은 수용 영역(receptive field) 확보.
DeepLab v1·v2는 ASPP 출력을 완전 연결 조건부 랜덤 필드(Dense CRF) 에 통과시켜 픽셀 간 관계를 모델링하고 경계를 정밀하게 다듬었다. DeepLab v3+에서는 디코더 구조가 이를 대체해 CRF 없이도 우수한 경계 복원이 가능해졌다.
python
class AtrousConv(nn.Module):
"""팽창 합성곱: 필터 사이에 dilation 간격을 두어 넓은 영역 수용"""
def __init__(self, in_ch, out_ch, dilation):
super().__init__()
self.conv = nn.Conv2d(in_ch, out_ch, 3, padding=dilation, dilation=dilation)
self.bn = nn.BatchNorm2d(out_ch)
def forward(self, x):
return nn.functional.relu(self.bn(self.conv(x)))
class ASPP(nn.Module):
"""Atrous Spatial Pyramid Pooling: 다중 스케일 문맥 정보 통합"""
def __init__(self, in_ch, out_ch=256):
super().__init__()
self.branches = nn.ModuleList([
nn.Sequential(nn.Conv2d(in_ch, out_ch, 1), nn.BatchNorm2d(out_ch), nn.ReLU()),
AtrousConv(in_ch, out_ch, dilation=6),
AtrousConv(in_ch, out_ch, dilation=12),
AtrousConv(in_ch, out_ch, dilation=18),
])
self.global_pool = nn.Sequential(
nn.AdaptiveAvgPool2d(1),
nn.Conv2d(in_ch, out_ch, 1), nn.BatchNorm2d(out_ch), nn.ReLU()
)
self.proj = nn.Conv2d(out_ch * 5, out_ch, 1)
def forward(self, x):
H, W = x.shape[2:]
feats = [b(x) for b in self.branches]
gp = nn.functional.interpolate(self.global_pool(x), (H, W), mode='bilinear', align_corners=False)
feats.append(gp)
return self.proj(torch.cat(feats, dim=1))
PSPNet (2017) — 피라미드 풀링
다양한 공간 스케일에서 문맥 정보를 추출하는 피라미드 풀링 모듈.
입력 특성 맵
↓ 4가지 풀링 (1×1, 2×2, 3×3, 6×6 grid)
[Global][반전역][중간][지역] 풀링
↓ 업샘플링 후 concatenation
다중 스케일 문맥 통합 → 최종 예측
손실 함수
python
import torch
import torch.nn.functional as F
# 1. Cross-Entropy Loss (표준)
criterion = torch.nn.CrossEntropyLoss(ignore_index=255)
loss = criterion(pred, target)
# 2. Dice Loss (클래스 불균형 완화)
def dice_loss(pred, target, smooth=1e-6):
pred = pred.softmax(dim=1)
target = F.one_hot(target, num_classes=pred.shape[1]).permute(0,3,1,2).float()
intersection = (pred * target).sum(dim=(2,3))
dice = (2*intersection + smooth) / (pred.sum(dim=(2,3)) + target.sum(dim=(2,3)) + smooth)
return 1 - dice.mean()
# 3. Focal Loss (어려운 픽셀에 집중)
def focal_loss(pred, target, gamma=2.0):
ce = F.cross_entropy(pred, target, reduction='none')
pt = torch.exp(-ce)
return ((1 - pt) ** gamma * ce).mean()
# 실제로는 Cross-Entropy + Dice 혼합 사용이 많음
total_loss = criterion(pred, target) + dice_loss(pred, target)
평가 지표
IoU (Intersection over Union) & mIoU
IoU = TP / (TP + FP + FN)
= 교집합 / 합집합
mIoU = 모든 클래스의 IoU 평균 (벤치마크 표준 지표)
python
def mean_iou(pred, target, num_classes):
"""mIoU = 클래스별 IoU의 평균"""
ious = []
pred = pred.flatten()
target = target.flatten()
for cls in range(num_classes):
pred_cls = (pred == cls)
target_cls = (target == cls)
intersection = (pred_cls & target_cls).sum().float()
union = (pred_cls | target_cls).sum().float()
if union == 0:
continue
ious.append((intersection / union).item())
return sum(ious) / len(ious) if ious else 0.0
# Pixel Accuracy (픽셀 정확도)
def pixel_accuracy(pred, target):
correct = (pred == target).sum().float()
return correct / target.numel()
AP (Average Precision)
인스턴스 분할·객체 탐지의 표준 지표. 정밀도(Precision)-재현율(Recall) 곡선의 아래 면적으로 계산한다.
정밀도 = TP / (TP + FP) ← 예측이 얼마나 정확한가
재현율 = TP / (TP + FN) ← 실제 객체를 얼마나 놓치지 않는가
AP = 정밀도-재현율 곡선 아래 면적
AP50 = IoU ≥ 0.50 조건에서의 AP
AP75 = IoU ≥ 0.75 조건에서의 AP (더 엄격한 기준)
mAP = 모든 클래스의 AP 평균
IoU의 한계: 예측 마스크가 실제 마스크를 완전히 포함할 만큼 크면 IoU = 1이 되는 경우가 있다. 또한 겹치는 부분이 없는 예측은 얼마나 틀렸는지와 무관하게 IoU = 0이 된다. 이런 한계를 보완하기 위해 AP를 함께 사용한다.
벤치마크 데이터셋
| 데이터셋 | 클래스 수 | 이미지 수 | 주요 용도 |
|---|
| PASCAL VOC | 21 | 11,530 | 일반 세그멘테이션 표준 |
| Cityscapes | 19 | 25,000 | 자율주행 도시 장면 |
| ADE20K | 150 | 25,210 | 실내외 장면 |
| COCO Stuff | 172 | 164,000 | 시맨틱 + 인스턴스 |
| CamVid | 32 | 701 | 도로 영상 |
주요 모델 비교
| 모델 | 백본 | mIoU (VOC) | 특징 |
|---|
| FCN | VGG-16 | 67.2 | 최초 완전 합성곱 |
| U-Net | Custom | — | 의료 영상, Skip Connection |
| PSPNet | ResNet-101 | 85.4 | 피라미드 풀링 |
| DeepLabv3+ | ResNet-101 | 89.0 | ASPP + Atrous Conv |
| SegFormer | MiT | 84.0 | 경량 Transformer |
| Mask2Former | Swin-L | 91.0 | 범용 세그멘테이션 |
산업별 활용 사례
| 분야 | 활용 | 요구사항 |
|---|
| 자율주행 | 도로·차선·보행자·장애물 구분 | 실시간, 높은 정확도 |
| 의료 영상 | 종양·장기·조직 경계 분할 | 경계 정밀도 |
| 위성/항공 | 토지 이용·수체·도시 지도화 | 대규모 이미지 처리 |
| 증강현실·소셜미디어 | 배경 교체·인물 사진 모드, Instagram·TikTok 필터·효과 실시간 적용 | 실시간 처리 |
| 농업 | 해충 침입 감지, 살충제 살포 자동화, 건강한 작물과 병든 구역 정밀 구분 | 멀티스펙트럼 대응 |
한계 및 도전 과제
| 한계 | 설명 |
|---|
| 주석 비용 | 픽셀 단위 레이블링은 매우 시간·비용 소모적 |
| 클래스 불균형 | 배경 픽셀이 전경보다 압도적으로 많음 |
| 작은 객체 | 해상도 손실로 소형 객체 분할 어려움 |
| 인스턴스 미구분 | 같은 클래스 여러 객체를 구별 불가 |
| 계산량 | 픽셀 단위 예측으로 높은 GPU 메모리 필요 |
관련 개념
- •YOLO — 같은 컴퓨터 비전, 객체 탐지(바운딩 박스)
- •CNN — 세그멘테이션 모델의 핵심 구성 요소
- •Transformer — SegFormer, Mask2Former의 기반 아키텍처
- •컴퓨터 비전 — 세그멘테이션의 상위 분야
- •딥러닝 — 현대 세그멘테이션 모델 학습 기반
- •전이 학습 — ImageNet 사전학습 백본 활용
참고문헌
- 1.IBM. (2024). 시맨틱 분할이란 무엇인가요? IBM Think
- 2.IBM. (2024). 인스턴스 분할이란 무엇인가요? IBM Think
- 3.Long, J., Shelhamer, E., & Darrell, T. (2015). Fully Convolutional Networks for Semantic Segmentation. CVPR 2015
- 4.Ronneberger, O., Fischer, P., & Brox, T. (2015). U-Net: Convolutional Networks for Biomedical Image Segmentation. MICCAI 2015
- 5.Chen, L.-C., Zhu, Y., Papandreou, G., Schroff, F., & Adam, H. (2018). Encoder-Decoder with Atrous Separable Convolution for Semantic Image Segmentation (DeepLab v3+). ECCV 2018
- 6.Zhao, H., Shi, J., Qi, X., Wang, X., & Jia, J. (2017). Pyramid Scene Parsing Network (PSPNet). CVPR 2017
- 7.Lakshmanan, V., Gorner, M., & Gillard, R. (2021). Practical Machine Learning for Computer Vision. O'Reilly Media.