관리 메뉴

TEAM EDA

Detection and Segmentation 본문

EDA Study/Object Detection

Detection and Segmentation

김현우 2020. 9. 13. 01:00

해당 강의는 CS231의 Detection and Segmentation 강의를 보고 정리한 내용입니다.

 

 

보통의 이미지 분류의 문제는 이미지가 들어오면, 해당 이미지가 속하는 카테고리에 대한 출력을 제공합니다. 위의 예시는 고양이 사진을 보고, 1000개의 카테고리에서 각각의 클래스에 속할 확률을 제공합니다 

 

이번에는 이를 좀 더 심화한 Object Detection에 대해서 보겠습니다. 

Sementic Segmentation 문제에서는 입력은 이미지이고, 출력으로 이미지의 모든 픽셀에 카테고리를 정합니다. 가령 이 예제의 경우는 입력이 고양이고 출력은 모든 픽셀에 대해 픽셀이 "고양이, 잔디, 하늘, 나무"로 분류합니다. 하지만, 기존의 Classification과 다른 점은 이미지 전체에 카테고리 하나가 아니라 모든 픽셀에 카테고리가 매겨지는 점입니다. 

Sementic Segmentation은 개별 객체를 구분하지 않습니다. 가령 오른쪽 이미지를 보면 암소가 두마리 보입니다. Sementic Segmentation의 경우에는 픽셀의 카테고리만 구분해 줍니다. 그렇기 때문에 암소 두마리를 구별할 수 없습니다. "암소"라고 레이블링된 픽셀 덩어리만 얻을 수 있습니다. 이는 Sementic Segmentation의 단점입니다. 나중에 배울Instatnce Segmentation이 이를 해결할 수 있습니다.

 

Sementic Segmentation 문제에 접근해볼 수 있는 방법 중 하나는 분류을 통한 접근입니다. Sementic Segmentation을 위해서 Sliding window를 적용해볼 수 있습니다. 입력 이미지를 아주 작은 단위로 쪼갭니다. 

위의 예시에서는 암소 머리 주변에서 영역 세 개를 추출했습니다. 이 작은 영역만을 가지고 분류 문제를 푼다고만 생각해보겠습니다. 해당 영역이 어떤 카테고리에 속하는 지를 정하는 것입니다. 하지만, 이 방법은 비용이 너무 크기에 좋은 방법이 아닙니다. 모든 픽셀에 대해서 작은 영역으로 쪼개고, 이 모든 영역을 포워드, 백워드 하는 것은 비용이 너무 큽니다. 그리고 서로 다른 영역이라도 인접해 있으면 어느정도는 겹치있기 때문에 특징들을 공유할 수도 있을 것입니다. 이렇게 영역을 분할하는 경우에도 영역들끼리 공유할만한 특징들이 아주 많은 것입니다. 위의 방법은 비효율적인 방법이지만, Segmentation을 할 때 가장 먼저 생각할 수 있는 방법입니다. 

 

Fully Convolutional Network는 이전보다 개선된 방법입니다. 이미지 영역을 나누고 독립적으로 분류하는 방법이 아닙니다. Fc-layer가 없고 Convolution Layer으로 구성된 네트워크 형태를 가집니다. 

3 x 3 zero padding을 수행하는 Conv Layer들을 쌓아올리면 이미지의 공간정보를 손실하지 않을 것입니다. 이 네트워크의 출력 Tensor는 C x H x W 입니다. C는 카테고리의 수입니다. 이 출력 Tensor는 입력 이미지의 모든 픽셀 값에 대해 분류 점수를 매긴 값입니다. 이는 Conv Layer만 쌓아올린 네트워크를 이용해서 계산할 수 있습니다. 이 네트워크를 학습시키려면 우선 모든 픽셀의 Classification loss를 계산하고 평균 값을 취합니다. 그리고 기존처럼 Back propagation을 진행하면 됩니다. 

 

여기서 궁금한 점은 어떻게 Training Dataset을 만드냐는 점입니다. 이는 굉장히 비용이 큰 작업입니다. 입력 이미지에 모든 픽셀에 대해서 레이블링을 해야 합니다. 위의 이미지에서는 Cow의 픽셀에 모두 Cow를 Cow라고 레이블링 해야하는 것입니다. 또 다른 궁금한 점은 Loss function을 어떻게 설계하는 것입니다. 이 문제에서는 모든 픽셀을 분류하는 것입니다. 다라서 출력의 모든 픽셀에 Cross Entropy를 적용합니다. 보통은 하이퍼파라미터만 잘 유지해주면 위의 작업은 잘 작동합니다. 하지만, 입력 이미지의 Spatial Size를 계속 유지해줘야 하기에 비용이 아주 큽니다. 그래서, 아래와 같이 특징맵을 Downsampling/Upsampling 해주는 구조를 많이 사용합니다. 

Spatial resolution 전체를 가지고 Convolution을 수행하기 보다는 Original Resolution 에서는 Conv layer는 소량만 사용합니다. 그리고 Max pooling, Stride, Convolution 등으로 특징맵을 Downsample 합니다. 기존의 이미지 분류에서는 FC-Layer가 있지만, 여기에서는 Spatial Resolution을 다시 키운다는 차이가 있습니다. 결국 다시 입력 이미지의 해상도와 같아집니다. 이 방법을 이용하면 계산 효율이 좋아집니다. 이 방법을 통해 네트워크가 lower resolution을 처리하도록하여 네트워크를 더 깊게 만들 수 있습니다. 

 

Convolution에서 이미지의 Spatial Size를 줄이기 위한 Stried Conv 라던가 다양한 Pooling 들은 다뤄본 적이 있었습니다. 하지만, Upsampling의 경우는 처음일 것입니다. 네트워크의 특징맵의 사이즈를 키울 수 있는 전략이 무엇일까요? Upsampling의 전략 중 하나는 unpooling입니다. 

또 다른 전략은 Max Unpooling입니다. 이는 각 unpooling과 pooling을 연관짓는 방법입니다. downsampling시에는 Max pooling에서 사용한 요소를 잘 기억했다가 해당 요소에 값을 채워넣는 것입니다. 그 외에는 0의 값을 채워줍니다. 

하지만, 이 방법이 왜 좋은지에 대한 의문이 생깁니다. 실제로 Input과 Output은 매우 달라보이기 때문입니다. Semantic Segmentation에서는 모든 픽셀들의 클래스를 모두 잘 분류해야 합니다. 예측한 Segmentation 결과에서객체들간의디테일한경계가 명확할수록 좋습니다. 하지만, Maxpooling을 하게되면, 특징맵의 비균진성이 발생합니다. (2x2 pooling을 할 때, 어디에서 왔는 지 모름. 공간정보를 잃어버림) Maxpooling 후의 특징 맵만 봐서는 이 값들이 Receptive field 중 어디에서 왔는 지 모릅니다. Unpool시에 기존 Maxpool에서 뽑아온 자리로 값을 넣어주면 공간 정보를 조금은 더ㅏ 디테일하게 다룰 수 있습니다. Max pooling 에서 잃어버린 공간정보를 조금 더 보존할 수 있게됩니다. 

 

세번째 전략은 Transpose Convolution 입니다.  

필터와 입력의 내적값이 아닌, 필터 * 입력(가중치)를 통해서 값을 계산합니다. 그리고 겹치는 부분은 합을 통해서 계산해줍니다. Spatial Size를 키워주기 위해서 학습된 Convolution을 사용하는 방법입니다. 페이퍼에 따라서는 deconvolution이라는 용어를 사용하기는 하지만, 신호 처리 관점에서는 좋은 용어는 아닙니다. 

 

구체적으로 위의 과정을 보면, 아래와 같습니다. 여기서는 단순하게 3x1의 Filter를 이요해서 계산한 예입니다. 

위의 겹치는 부분을 더해주는 것은 문제가 될 수 있습니다. Receptive field의 크기에 따라서 magnitudes이 달라지기 때문입니다. 실제로 최근들어 제기되고 있는 문제기도 합니다. 3x3 stride 2 transpose convolution을 사용하면 checkerboard artifacts(겹쳐지는 부분들)가 발생하고는 합니다. 최근 논문에서는 4x4 stride 2혹은 2x2 stride 2를 사용해서 문제를 완화시키기도 합니다. 

 

이번에 배울 Task는 Classfication + Localization입니다. 기존의 이미지 분류는 레이블을 매기는 문제였습니다. 하지만, 때로는 어떤 카테고리에 속하는 지 뿐만 아니라 어디에 있는지를 알고 싶을 수 있습니다. cat에 분류하는 것 뿐만아니라 cat의 위치에 네모박스를 구하는 것입니다. 이는 object detection과는 다릅니다. localization 문제에서는 이미지내에서 내가 관심있는 객체가 오직 하나라고 생각합니다. 

 

이 문제를 풀 때도 기존의 image classification에서 사용하던 기법들을 고스란히 녹일 수 있습니다. 아키텍쳐의 기본 구조는 아래와 같습니다. 

특이한 점은 Fully Connected Layer가 하나 더 있어서 Box의 위치를 결정하는 좌표를 제공하는 점입니다. 이 네트워크를 학습시킬 때는 loss가 두개가 존재합니다. 그리고 이 문제를 fully supervised setting을 가정합니다. 따라서 학습 이미지에는 카테고리 레이블과 해당 객체의 bounding box GT를 동시에 가지고 있어야 합니다. 자, 이제 여기에는 두가지의 로스가 있습니다. 먼저, Class scores를 예측하기 위한 Softmax loss가 있습니다. 그리고 Ground Truth Bbox와 예측한 Bbox 사이의 차이를 측정하는 Loss가 있습니다. L2 loss, l1, smooth l1 등을 이용해서 regression loss를 정의할 수 있습니다. 

 

Q. 왜 분류와 Bbox를 동시에 하는게 좋으며, 가령 오분류에 대해서는 Bbox가 있으면 어떻게 되는지? 

A. 일반적으로는 문제가 되지 않음. 실제로 많은 사람들이 두 Loss를 동시에 학습시킵니다. 하지만, 오분류의 문제에서는 문제가 될 수 있습니다. 많이 쓰는 해결책 중 하나는 Bbox를 하나만 예측하지 않고 카테고리마다 하나 씩 예측하는 방법을 사용합니다. 그리고 Ground Truth 카테고리에 속한 예측된 Bbox에만 Loss와 연결시킵니다. 

 

Q. 두 개의 Loss의 단위가 다른데, 합쳐도 무방한 지? 

A. 보통 이러한 문제를 Multi-task Loss라고 하는데, Loss에 대한 가중치의 합에 대한 Gradient를 계산해야 합니다. 그렇기에, 이때 가중치를 직접 조절해주어야 하는데, 이에 의해서 Loss 자체의 속성이 바뀌므로 다른 성능 지표를 도입해서 실제 모델의 성능지표를 봐야합니다. 

 

Q. 왜 굳이 같이 학습을 하는가? 앞 쪽의 네트워크는 고정시키고 마지막 Fc-layer만 학습시키는 방법은 어떤지입니다. 

A. Transfer Learning 관점에서 보면 fine Tune을 시도하면 성능이 좋아집니다. 실제로 많이 쓰는 트릭 중 하나는 우선 네트워크를 Freeze하고 두 FC-layer을 학습시키는 방법입니다. 그리고 Fc-layer가 수렴하면 전체 시스템을 Fine Tune하는 방식입니다. 

 

이러한, Bounding 아이디어는 Homan Pose Estimation과 같은 다양한 분야에서도 적용이 가능합니다. 

 

다음은 Object Detection 문제입니다. 해당 분야는 정말로 이야기할게 많은 주제입니다. Object Detection 문제에서도 고정된 카테고리인 경우가 있습니다. task는 입력 이미지가 주어지면 이미지에 나타나는 객체들의 Bbox와 해당하는 카테고리를 예측합니다. 기존의 Localization과는 조금 다른게, 예측해야 하는 Bbox의 수가 입력 이미지에 따라 달라지기 때문입니다. 각 이미지에 객체가 몇 개나 있을지 의문이기 때문입니다. 

 

Object Detection 문제를 풀때 에전부터 많은 사람들이 도입했던 방법은 Sliding Window입니다. 

CNN은 이 작은 영역에 대해서 분류를 수행할 것입니다. CNN은 여기에 개, 고양이도 없다고 표현할 것입니다. 하지만, 여기에 배경이라는 카테고리를 추가해서 아무것도 없다면 배경이라는 값을 추출할 것입니다. 

하지만, 어떻게 영역을 추출할 지에 대한 문제가 있습니다. 이미지에 Objects가 몇 개가 존재할 지, 어디에 존재할 지, 크기가 어떻게 되는 지도 알 수 없습니다. 그래서 Sliding windows를 사용하려면 너무나 많은 경우의 수가 존재합니다. 작은 영역 하나마다 거대한 cnn을 통과시키려면 엄청난 계산량을 필요로 합니다.

대신에, Region Proposals Network라는 전통적인 방법을 사용합니다. 이 Network는 Objects가 있을만한 Bbox를 제공해줍니다. 이미지 내에서 객체가 있을법한 후보 Region Proposas를 뭉텅진(blobby)곳을 제공합니다. 이 지역들은 객체가 있을지도 모르는 후보 영역들이고 비교적 빠르게 작동합니다. 이런 방법중에서는 Selective Search라는 방법이 있는데, Cpu로 2초간 돌리면 2000개 정도의 후보를 제공합니다. 비교적 Recall은 높지만 많은 노이즈가 낀다는 문제가 있습니다. 

 

지금까지 말씀드린 아이디어가 모두 몇해 전 나온 R-CNN이라는 논문에 등장합니다.이미지가 주어지면  Region roposal을 얻기 위해 Region Proposal Network를 수행합니다. Region Proposal은 Region of Interest (ROI) 라고도 합니다. Selective Search를 통해 2000개의 ROI를 얻어냅니다. 하지만 여기에서는 각 ROI의 사이즈가 각양각색이라는 점이 문제가 될 수 있습니다. 추출된 ROI로 CNN Classification을 수행하려면 FC-Layer 등으로 인해서 보통 같은 입력사이즈로 맞춰줘야만 합니다. 따라서 Region proposals을 추출하면 CNN의 입력으로 사용하기 위해서는 동일한 고정된 크기로 변형시켜야 합니다. 다시말해 Region proposals을 추출하면 고정된 사이즈로 크기를 바꿉니다.그리고 각각의 Region Proposals을 CNN에 통과시킵니다. 그리고 RCNN의 경우에는 ROI들의 최종 Classification에 SVM을 사용했습니다. (SVM 옆에 Bbox reg 값도 추가되어야 함) 

 

 

위의 계산이 느린 문제는 Fast R-CNN에서 대부분 해결되었습니다.

Fast R CNN에서는 각 ROI 마다 각각 CNN을 수행하지 않습니다. 전체 이미지에 CNN을 수행합니다. 그 결과 전체 이미지에 대한 고해상도 Feature Map을 얻을 수 있습니다. 하지만, 여전히 Selective Search같은 Region Proposal 방법을 사용합니다. 하지만, 이미지에서 ROI를 뜯어내지는 않습니다. 이제부터는 CNN Feature Map에 ROI를 Projection 시키고 전체 이미지가 아닌 Feature map에서 가져오는 형태입니다. 이제는 CNN의 feature를 여러 ROIs가 서로 공유할 수 있습니다. 그 다음 fc-layer가 있습니다. fc-layer는 고정된 크기의 입력을 받습니다. 따라서 cnn feature map에서 뜯어온 roi는 fc-layer의 입력에 맞게 크기를 조정해줘야합니다. 학습이 가능하도록 미분가능한 방법을 사용해야합니다. 이 방법이 바로 roi pooling layer입니다. Feature Map에서 가져온 ROI의 크기를 조정하고나면 FC-layer의 입력으로 넣어서 Classification Score와 Linear Regression Offset을 계산할 수 있습니다. 이후에 두개의 Loss를 합해서 Multi-task loss를 계산하면 됩니다. 

하지만, Fast R-CNN도 Region Proposal을 계산할 때, 병목현상이 발생하는 문제가 있습니다. Faster R-CNN은 네트워크가 Region proposal을 직접만들면서 위의 문제를 해결했습니다. 별도의 Region proposal Network가 있어서 해당영역에 대한 계산을 합니다. 이때, 4개의 Loss가 존재하기에 이들에 대한 균형을 맞추는게 까다로운 문제가 됩니다. 

 

이 둘의 기본적인 아이디어는 각 Task를 따로 게산하지 말고 하나의 regression 문제로 풀어보자는 문제입니다. 거대한 CNN을 통과하면 모든 것을 담은 예측값이 한번에 나옵니다. 입력 이미지가 있으면 이미지를 큼지막하게 나눕니다. 가령 7x7 grid로 나눌 수 있을 것입니다. 각 Grid Cell 내부에는 Base BBox가 존재합니다. 이 경우에는 Base BBox가 세 가지 있습니다. 길쭉한놈 넓죽한놈 정사각형 이죠 실제로는 세 개 이상 사용합니다. 이제는 이 객 grid cell에 대해서 BBoxes가 있고 이를 기반으로 예측을 수행할 것입니다. 우선 하나는 BBox의 offset을 예측할 수 있을 것입니다. 실제 위치가 되려면 base BBox를 얼만큼 옮겨야 하는지를 뜻합니다. 그리고 각 BBox에 대해서 Classification scores를 계산해야 합니다. 이 BBox 안에 이 카테고리에 속한 객체가 존재할 가능성을 의미합니다. 네트워크에 입력 이미지가 들어오면 7 x 7 Grid마다 (5B + C) 개의 tensor를 가집니다. 여기에서 B는 base BBox의 offset (4개)과 confidence score(1개)로 구성됩니다. 그리고 C는 C개의 카테고리에 대한 Classification score 입니다. 정리하면, 네트워크이 입력은 이미지이고 출력은 3-dim tensor 입니다. 그리고 이를 거대한 CNN으로 한번에 학습시킵니다. 지금까지 알아본 방법들(YOLO/SDD)은 "Single Shot Mthods" 입니다.후보 base BBoxes와 GT Objects를 매칭시키는 방법입니다. 하지만 가만보면 Faster R-CNN에서 쓰는RPN이 이와 유사해 보입니다. 결국은 둘 다 Regression + Classification 문제를 푸는 것입니다. R-CNN 계열, Single-Shot 계열 이라고 나눠도 분명 겹치는 아이디어들이 있습니다. Faster R-CNN은 RPN으로 먼저 Regression 문제를 풀고 ROI단위로 Classification을 하는 방식입니다. 반면 single shot methods는 단 한번에 forward pass만으로 끝내버립니다. object detection 문제에는 아주 다양한 요소들이 있습니다.가령 다양한 base networks들을 적용해 볼 수도 있습니다. VGG, ResNet 등 말이죠. 그리고 다양한 아키텍쳐를 선택할 수 있습니다. 여러 대분류(metastrategies)가 있었습니다. 가령 Faster R-CNN과 같은 Region을 기반으로한 방법들도 있었고 Sigle Shot Detection 기반의 방법들도 있었습니다. 말씀드리지 않았지만 R-FCN 도 있습니다. 앞서 말씀드린 두 집단의 중간 위치에 있습니다. 

그리고 아주 다양한 Hyperparameters가 있습니다. 이미지 크기를 몇 으로 할지, Region Proposals을 몇 개로 할 지 아주 다양합니다. 올해(2017) CVPR에 실린 아주 좋은 논문이 있습니다. 앞서 말씀드린 다양한 알고리즘들의 성능을 측정하기 위해 다양한 변수들을 이용해서 통제실험을 진행한 논문입니다. 관심있으신 분들은 이 논문을 보시기 바랍니다.

 

위와 같이 다양한 문제를 섞어서 문제를 풀 수도 있습니다. (Object Detection + Captioning) 

 

마지막으로 배울 task는 instance segmentation입니다. 입력 이미지가 주어지면 객체 별로 객체의 위치를 알아내야 합니다. 이때 Object 별로 Bbox를 예측하는 것이 아닌 객체 별 Segmentation Mask를 예측해야 합니다. 이미지에서 각 객체에 해당하는 픽셀을 에측해야 하는 문제입니다. Semantic Segmentation과 Object Detection을 결합한 문제입니다. 이러한 문제를 푸는 아주 다양한 방법이 있지만, 그 중 하나는 Mask R-CNN입니다. 

Faster R-CNN에서 했던 것처럼 특징 맵에서 RPN의 ROI 만큼을 뜯어내는 과정은 비슷합니다. 하지만, 분류나 Box regression 하는게 아니라 bbox마다 Segmentation mask를 에측하도록 합니다. rpn으로 뽑은 roi 영역 내에서 각각 semantic segmentation을 수행합니다. feature map으로부터 roi pooling(align)을 수행하면 두 갈래로 나뉩니다. 상단에 보이는 첫 번쩌 갈래는 faster r-cnn과 유사합니다. 첫 번째 갈래에서는 각 region proposal이 어떤 카테고리에 속하는지 계산합니다. 그리고 region proposal의 좌표를 보정해주는 bbox regression이 있습니다. 그리고 하단의 두번째 갈래는 semantic segmentation을 위한 미니 네트워크같이 생겼습니다. 각 픽셀마다 객체인지 아닌지를 분류합니다.