본문 바로가기

머신러닝/[논문으로 짚어보는 딥러닝의 맥]

이미지의 각 픽셀을 분류하는 Semantic Segmentation

학습목표

Semantic Segmentation은 각 이미지 내의 픽셀별로 픽셀이 어디에 속하는지 분류를 해결하는 문제로, 본 강의에서는 이 Semantic Segmentation의 개념을 알아보도록 하겠습니다. 이 분야는 실생활에서 의료, 교통 분야에 많이 활용되고 있습니다. 특히 자율 주행 자동차 기술에 많이 접목되어 있기 때문에 흥미를 느끼며 강의를 들으셔도 좋을 것 같습니다.

핵심 키워드

  • Semantic Segmentation
  • CNN
  • Fully Convolutional Network (FCN)
  • Full-Resolution Residual Nets

학습하기

 이번에는 Semantic segmentation을 보겠습니다 .이는 이미지가 주어졌을 때, 각 픽셀별로 어디에 속하는지 분류를 푸는 문제입니다. 보통 이미지를 분류하는 MLP의 목적은, 이미지를 나타내는 원핫 벡터를 찾는 개념입니다. 클래스의 개수가 10개라면, 10이라는 길이를 갖는 벡터를 찾는게 목표인거죠. 그런데 Semantic segmentation의 경우, 앞의 개념을 각 픽셀마다 적용한다는 느낌입니다. 이미지가 100x100이라면 10000번의 분류를 시행하는 셈이죠. 어디에 사용되느냐. 자율 주행에 정말 많이 활용됩니다. 내 앞에 있는 영역이 사람인지, 도로인지, 벽인지 이런 것들을 분류하는 겁니다. 작년에 테슬라가 사고가 났었는데, 그 원인이 앞에 트럭이 하나 있었는데, 이 트럭이 흰색이라서 하늘이라고 판단한겁니다. 테슬라 내부 판단 모델이. 

 해서 저희는 총 4개의 논문을 볼 예정입니다. 첫번째로 DL을 이용한 Segmentation의 시초인 "Fully Convolutional Networks for Semantic Segmentation" 입니다. 이 논문에서는 이름에서 알 수 있듯이 Fully Convolutional Network를 소개합니다. 앞선 CNN에서 앞에는 Conv layer를 사용하고 마지막에는 Fully connected layer를 사용했던 것에 비해, 이 모델은 Fully connected layer가 없습니다. 모두 Conv layer죠. 모든 Network가 Conv layer를 가지면 몇 가지 특징이 있는데, Input size에 제약이 없다는 겁니다. 기존 CNN은 24x24와 같이 Input size를 제한했습니다. 왜냐면 결국 마지막에 Fully connected로 진입하기 위해서는 Flatten과정이 필요하고, 이후는 모두 고정된 사이즈로 행렬 연산이 진행되기 때문에, Fully connected로 들어갈 당시의 쉐잎이 다 같아야하는거죠. 그런데 모든 Layer가 Conv라면 조금 다릅니다. 큰 Input을 넣으면 그에 맞는 큰 Input이 나와요. 우리가 일반적으로, CNN을 만든다고 하면 Convolutional subsampling을 반복하다고 Fully connect로 들어간다고 했었죠. 이미지가 들어오면, Conv feature map을 만들고, Flatten시키고, FC를 통과하고. 그런데 이걸 Fully conv net으로 만들 수 있습니다. Fully conn로 들어가기전 Feature map이 10x10x100(w x h x ch)이라고 해봅시다. 여기에는 10000개의 숫자가 들어가 있는데, 그럼 이걸 Flatten시켜도 10000개의 수를 가져요. 이제 이걸 4096차원으로 줄이고 싶다고 해봅시다. 어떻게 할까요. Fully conn같은 경우 그냥 10000x4096 행렬을 곱해주면 됬었어요. 이걸 Conv를 통해 진행해봅시다. 10x10x100짜리 Feature map에 10x10x100짜리 Filter(=Kernel)을 4096번(Ch) 곱해주면 되겠죠. 마찬가지로 4096Dim에서 22Dim으로 줄이려면 1x1x4096 Filter를 22개 사용하면 되겠죠. 지금까지 뭘 했냐면 Fully conn를 Fully conv로 구현한겁니다. 여기서 알 수 있는 것은 Fully conn을 전혀 사용하지 않고 어떤 Dim이 들어왔을 때 One hot vector화 시킬 수 있다는 겁니다. 이게 Semantic segmentation의 시작입니다. 그림을 보시면 Fully conn 에서는 데이터가 Flatten되어 세로로 4096Dim을 가지던 것이 세로 22Dim 데이터로 바뀌고, 이에 필요한 연산은 4096x22입니다. 같은 역활을 하는 Fully conv에서는 채널을 확장시켜 가로로 4096Dim을 가지던 것이 1x1 Conv를 이용해 가로 22Dim 데이터가 되고, 이에 필요한 연산은 1x1x4096x22입니다. Fully conn과 같죠. 이런걸 Convolutionalization이라고 하고, Heatmap을 만들 수 있게 합니다. 그런데 이런 Fully conv도 결국 앞단에서 Subsampling과정을 거치니까 24x24이미지를 Input으로 넣어도 Output의 이미지는 그보다 작아집니다. 우리가 원하는건 24x24 Output을 그대로 내어주면서 각각의 픽셀마다 어떤 분류값이 존재하길 원해요 때문에 이후 과정이 필요합니다.

 우리가 원하는 Output은 500x500인데 지금까지의 결과는 10x10입니다. 그럼 이걸 키워야겠죠. Deconvolution을 통해서! 이건 Conv의 역연산이라고 생각해도 좋습니다. 아 그리고 Stride를 2라고 생각하겠습니다. 이 경우 Conv를 통과하면 Feature map의 크기는 절반이 되겠죠. 평면에서 생각해봅시다 어떤 이미지의 3x3 부분에 3x3 Filter를 적용하여 Conv시키면 1개 값이 나오겠죠. 그럼 Deconv는 어떻게 하느냐. 1x1의 값을 스칼라 취급해서 3x3 Filter에 곱하는 겁니다. 그러면 1개 픽셀이 3x3으로 확장되겠죠. 이게 끝입니다. Deconv는 Conv의 반대 연산. 물론 나의 필요에 따라 Size는 잘 정해줘야겠죠. 물론 과정을 곱씹어보면, 많은 Conv를 거친, 그러니까 Spatial한 정보가 이미 많이 줄어든 상황에서 무작정 Deconv시키면 거기에는 Spatial한 정보가 당연히 많이 손실된 상태입니다. 때문에 여러단계의 Feature map을 복합적으로 Deconv시켜서 사용하는 방법이 필요합니다. 20가지 클래스로 분류하는 Semantic segmentation에 대해, 100x100x3 이미지가 들어가면 100x100x20 아웃풋이 나오는 이 문제인데, 이런 문제를 End to End 문제라고 합니다. 이런건 사실 Input과 Output을 연결하는 어떤 함수를 찾는 문제일 뿐이에요. Detection 같은 문제는 함수를 찾는 중간 과정이 굉장히 어렵습니다만, Sematic segmentation은 구현이 그렇게 어렵지는 않습니다. 이게 FCN-8s에 대한 이야기입니다.

 다음은 "Semantic Image Segmentation with Deep Convolutional Nets and Fully Connected CRFs" 입니다. 기존(FCN-8s)는 2가지 단점이 있어요. 1. Signal downsampling 이건 Subsampling을 하면 정보가 줄어들죠. 애초에 정보가 줄어들어있기 대문에 뭔가를 복원해도 잘 안된다는 말이고, 그럼 Pooling이 없는 Net를 만들어보자 한 겁니다. 이미지 전체를 분류하는 데에는 좋은 아이디어지만 Segmentation처럼 모든 픽셀에 대한 정보를 다루어야할 때에는 그다지 효과적이지 않다는 거죠 이런 Subsampling이. 2. Spatial insensitvity 이거도 비슷한 이야긴데, Spatial한 정보를 잃었기 때문에, 윤곽선을 잘 못 땁니다. 그래서 이걸 잘 해결하기 위해 Conditional random field라는 후처리 알고리즘을 적용합니다. 다만 이건 DL과는 관련없습니다. Atrous conv란게 뭐냐면 입력 이미지에 비해서 Dense한 Feature map을 만들고자하는겁니다. 무슨말이냐면, 우리가 Conv를 하게 되는데, 입력 이미지의 사이즈에 비해 일반적으로 Output 이미지는 줄어들게되죠. 3x3 이미지에 3x3 필터를 씌우는데, Stride가 1이라면, 3x3 Feature map이 나오죠. 우린 여기서 그 사이사이에 0을 집어넣을 거에요. 그러면 3x3이 아닌 5x5 Feature map이 나오겠죠. 이게 Atrous conv입니다. 이렇게 사이즈를 키워도, 뒤에 붙어 있는 Pooling 등의 과정을 거치면 다시 이미지는 본래보다 작아지겠죠. 이걸 저지하려는게 Cond rand field입니다. 이건, 간략히 말하면, 그림으로 잘 설명될 수 있습니다. 해당 픽셀이 어떤 클래스에 속할지에 대한 정보가 담긴 Unary term과 주변 픽셀이 어떤 클래스일지에 대한 정보가 담긴 Pairwise term 이 두가지를 잘 조합해서 결론을 내리는거죠. DL과는 별 상관없이 기존의 방법론 중 하나입니다. Input - Atrous conv - Coarse Score map - Bilinear Interpolation - CRF - Output 이런 파이프라인을 따라가는거죠. 

 다음은 "Learning Deconvolution Network for Semantic Segmentation" 입니다. Deconv넷인데 이거보다는 Unpooling net에 가깝습니다. 기존 문제는 1. 일반적으로 같은 Recptive field를 갖게 됩니다. 어떤 이미지를 Segmentation 한다고 했을때 우리는 크기를 대충 가늠할 수 있어야합니다. 그러니까 버스의 전면부 사진이 있는데, 버스의 앞유리에 자전거가 비쳐져있다고 합시다. 버스 전체의 이미지를 보면 이건 버스라는걸 알아요. 그런데 전면부 유리만 크롭해서 판단하라고하면, 이게 버스 유리가 아니라 자전거라고 판단한다는 거죠. 작은 물체를 판단할 때는 작은 필드가 필요한거죠. 그래서 큰이미지 안에서 작은 이미지를 정확히 분류하는 문제는 잘 안됬습니다. 그래서 이 논문에서는 아예 극단적으로, 1x1까지 Receptive field를 줄여버리자는 겁니다. 정확히는 Unpooling을 통해서 기존의 1x1 Pixel이 전체 이미지의 어디에 있었는가에 대한 정보를 잘 복원시키게 됩니다. 그래서 그림을 보면, Unpooling은 Pooling의 반대과정인데, 그렇게 쉬운 과정은 아닙니다. 예를 들면 2x2 Feature map에 Pooling을 적용하면 1개 값이 나오고, 이걸 Unpooling을 한다는 건 1개 값을 2x2로 확장하는 건데, 이걸 어떤 위치에 놓아야할지를 모릅니다. (그러니까 1개를 2x2로 만드는데 1개값을 2x2로 복제하는 개념이 아니라 나머지는 0으로, 원래 위치에는 어떤 값을 채워야합니다) 그래서 Switch variable을 만들어서 Pooling할 때 선택된 위치를 저장했다가 이후 Unpooling과정에서 사용합니다. 그렇게 만들어진 Net은 Symmetric한 구조를 갖게됩니다. 결국 이미지가 들어오면, Conv로 줄이고, Uncov로 0을 끼워넣고, Pooling으로 줄이고, Unpooling으로 0을 끼워넣고 반복입니다. Maxpool기준으로 Pooling된 값의 위치는 결국 중요한 정보가 있는 위치입니다. Conv가 Feature extractor니까 이런 흐름은 자연스럽습니다. 그래서 이 논문에서는 1. Batch Norm 2. Two stage traing 이건 물체 중간에 있는게 판단하기 더 쉬우니까, 중간에 있는거 먼저 학습하고, 나머지 학습하고 이런 식입니다. 3. Ensemble model. 이건 논란이 있는데, 일반적으로 앙상블은 Net자체가 여러 개 있습니다. 그런데 여기서는 이미지를 분할하고 각각의 이미지를 Model을 학습시키고, Majoritiy voting을 통해 결과를 내는 방식입니다.

 마지막은 "DeepLab: Semantic Image Segmentation with Deep Convolutional Nets, Atrous Convolution, and Fully Connected CRFs"입니다. 사실 굉장히 비슷한 이야기입니다. CRF, Atrous conv 등을 사용했으니까요. 여기서는 Astrous spatial pyramid pooling, ASPP가 조금 다릅니다. 문제 제기가 있습니다. 1. Reduced feature resolution. 정보가 소실된다. 이건 Astrous conv로 처리합니다. 2. Existence of objects at multiple scales. 이게 중요합니다. 앞의 논문과 동일한 문제인데요, 애초에 이미지랑 물체 사이즈가 다른데 하나의 Receptive field로 문제를 풀면 잘 안된다는 거죠. 그래서 ASPP를 제안합니다. 3. Reduced localization accuracy. 윤곽선을 잘 못잡는건데 이건 CRF로 잡습니다. 우린 ASPP를 잘 이해해보면 되겠죠. Atrous는 A + trous인데 trous는 holes라는 말입니다. Conv filter 사이에 0을 집어 넣어서 더 Dense한 Matrix를 끌어내는거죠. ASPP는 다양한 Receptive field를 끌어내기 위함입니다. 전체 이미지에서 물체를 판단할때, 엄청나게 많은 부분을 볼필요는 없어요. 사실 일부분만 봐도 어느정도 알 수 있습니다. 그리고 물체별로 다른 Receptive field가 필요한건데, 이걸만들기 위해 같은 픽셀에 대해 3x3 Conv를 적용하되 집어넣는 0의 개수만 달리해서 만들어 보자 이거죠. 파라미터의 개수는 9개로 고정하되 다양한 Recep field를 만들어내는. Inception module 과 굉장히 비슷한데 조금더 극단적으로 만든 겁니다. 성능이 훨씬 잘나오죠.

다른 논문들은 간략히만 보겠습니다. 사실 데이터를 줄였다가 다시 복원하는 흐름에서, 당연 원래 데이터가 잘 복원될 수가 없어요. 게다가 CRF는 시간이 꽤나 걸리는 방법론이라서, 실시간 서비스에는 적합하지가 않아요. 그래서 Full-Resolution Residual Network라 해서, 기본 이미지를 계속 끌고가고, 다른 줄기를 만들어 거기에서 Polling stream을 처리하는, 그래서 Residual을 학습하는 이런 플로우를 그려나갑니다. 이렇게하면 가드레일 같이 얇고 잡기 힘든 것도 잘 잡을 수 있게 됩니다. 

 U-Net 구조는 BatchNorm 처럼 쓰면 왠만하면 좋은 구조입니다. 앞단의 Layer에서 나온 Feature map을 뒷단에서 나온 Feature map에 그냥 병합하는 겁니다. 앞의 정보를 잃지 않기 위해서. GAN등 에서도 굉장에 많이 활용되는데요. 조금 더 선명한 이미지를 얻을 수 있죠. 가장 큰 단점은, 병합하는 과정에서 Channel이 늘어나고, Param 수가 늘어난다는 점입니다.

 Deep contextual networks는 U-Net을 조금 간략화시켰습니다. Param수가 조금 더 적죠. FusionNet은 의료영상에서 굉장히 많이 활용되는데요. U-Net처럼 앞단의 정보를 사용하는데 병합이 아니라 단순히 더합니다. 그리고 ResNet Connection이 있습니다. GPU를 엄청 먹는다는 단점이 있습니다. Pyramid Scene Parsing Net. 이건 굉장히 예쁩니다. 일단 Pretrained model을 사용해요. 이미지가 들어오면 일단 Pretraind model로 Feature map을 얻고, 그 다음 서로다른 Size의 Polling을 적용하고, Upsampling하고, CNN에서 뽑은 정보와 각기 다른 Upsampling 정보와 병합합니다. 앞의 구조들은 Pretrained CNN을 사용한 것이 없습니다. 그래서 이 Network는 굉장히 효율적이죠. Param의 수도 적구요. 이상입니다.