Semantic Segmentation Task를 학습하는데는 2가지 데이터가 필요합니다: (Input) X Data : 학습할 Image dataset (Input) Y Data : 학습할 Image에 대응되는 Color Map Image file
특히, Y Data 의 경우에 “JPG” 포맷이 아닌 “PNG” 포맷을 사용하게 됩니다.
JPG 포맷은 손실 압축을 사용하기 때문에, 용량이 작다는 장점이 있지만 _사용자의 눈에 잡히지 않는 특정 부분의 Color 값이 변경된다는 특징_이 있습니다.
이번 글에서는 Semantic Segmentation의 Label Image를 생성하는 방법과 일반적인 Image Data 와의 차이점을 살펴보도록 하겠습니다.
시작하기에 앞서, Semantic Segmentation Task가 정확히 어떤 Task인지 알아야 합니다. Semantic Segmentation Task의 경우, 전체 이미지에 대해 각각의 픽셀이 어느 Label(=Category)에 속하는지 분류하는 문제입니다.
정교한 분류를 해내야 하기 때문에 Atrous Convolution과 같은 **Receptive Field(수용 영역, 필터가 한 번에 볼 수 있는 영역)**가 넓은 합성 곱 연산을 주로 사용합니다.
DeepLab V3+ 코드 중에서, 가장 중요한 Loss Function 구현 부분을 보도록 하겠습니다. (Github Repository : https://github.com/jfzhang95/pytorch-deeplab-xception)
import torch
import torch.nn as nn
class SegmentationLosses(object):
def __init__(self, weight=None, batch_average=True, ignore_index=255, cuda=False):
self.ignore_index = ignore_index
self.weight = weight
self.batch_average = batch_average
self.cuda = cuda
def build_loss(self, mode='ce'):
"""Choices: ['ce' or 'focal']"""
if mode == 'ce':
return self.CrossEntropyLoss
elif mode == 'focal':
return self.FocalLoss
else:
raise NotImplementedError
def CrossEntropyLoss(self, logit, target):
n, c, h, w = logit.size()
criterion = nn.CrossEntropyLoss(weight=self.weight, ignore_index=self.ignore_index,
reduction='mean')
if self.cuda:
criterion = criterion.cuda()
loss = criterion(logit, target.long())
if self.batch_average:
loss /= n
return loss
def FocalLoss(self, logit, target, gamma=2, alpha=0.5):
n, c, h, w = logit.size()
criterion = nn.CrossEntropyLoss(weight=self.weight, ignore_index=self.ignore_index,
reduction='mean')
if self.cuda:
criterion = criterion.cuda()
logpt = -criterion(logit, target.long())
pt = torch.exp(logpt)
if alpha is not None:
logpt *= alpha
loss = -((1 - pt) ** gamma) * logpt
if self.batch_average:
loss /= n
return loss
위의 DeepLab V3+ Repository에 구현되어 있는 Loss Function 입니다.
여기서 우리는 핵심적인 코어 함수가 nn.CrossEntropyLoss 임을 알 수 있습니다. Cross-Entropy Loss Function(이하 CE Loss)은 Semantic Segmentation Task(이하 분할 문제)이전에 분류 문제(Classification)에서 자주 쓰이는 손실 함수입니다.
그럼 왜 분류 문제와 분할 문제는 둘다 CE Loss를 쓰는 것일까요?
분류 문제(Classification) 에서는 이미지 1장 전체에 대한 Label을 분류합니다.
(ex. 이 사진은 고양이 사진입니다!)분할 문제(Semantic Segmentation) 에서는 이미지 1장 내의 1개 픽셀에 대한 Label을 분류합니다. (ex. 이 픽셀은 고양이에 해당하는 픽셀입니다!)
위에서 서술 하였듯이, 두 문제 모두 분류를 하긴 하지만 Classification 문제의 경우는 이미지 전체를 분류하고, Semantic Segmentation 문제의 경우는 1개 픽셀에 대해서만 분류합니다.
*(분류 문제 신경망에서, Batch Size가 1이라고 가정한다면 단순히 True-Label 1개와 Predicted-Label 1개를 비교하는 것처럼, True-Label’s 1–pixel과 Predicted-Label’s 1-pixel을 비교하는 것입니다.
이는 이미지의 width * height 수만큼 반복됩니다.)*
1개 픽셀이라고 한다면? 일반적인 Color Image는 3채널의 RGB 값이 들어오지만, CE Loss를 사용하는 분할 문제 특성 상 1개 채널의 값이 들어오는데 이 값이 바로 Label Value가 되는 것입니다.