[출처: https://ko.wikipedia.org/wiki/객체 탐지]
Object detection이란 이미지 내에서 물체의 위치와 그 종류를 찾아내는 것입니다. 이번 시간에는 딥러닝을 기반으로 하는 object detection에 대해 알아보도록 하겠습니다.
Object detection은 이미지 기반의 문제를 풀기 위해 다양한 곳에서 필수적으로 사용되는 중요한 기법입니다. 대표적으로 자율 주행을 위해서 차량이나 사람을 찾아내거나 얼굴 인식을 위해 사람 얼굴을 찾아내는 경우 등을 생각할 수 있습니다.
먼저, 터미널을 열어 개인 실습환경을 맞추고 경로를 변경, 실습에 필요한 디렉토리를 만들어 줍니다!!
$ mkdir -p ~/aiffel/object_detection/images
[출처:https://medium.com/@prashant.brahmbhatt32/the-yolo-object-detection-c195994b53aa]
주어진 이미지 안의 물체가 무엇인지를 알아내는 것입니다. 한 가지 물체를 찾기 때문에 가장 큰 물체를 알아내려고 합니다. 가장 단순한 딥러닝 형태이죠.
주어진 이미지 안의 물체가 어느 위치에 있는지를 찾아내는 것입니다. 주로 Bounding Box라는 사각형의 형태로 그 위치를 나타냅니다. 물체의 위치가 담긴 사각형을 (mix_x
, min_y
, max_x
, max_y
)로 나타내거나 (mix_x
, min_y
, width
, height
)로 나타냅니다.
주어진 이미지 안의 물체가 무엇인지, 어디에 있는지를 모두 알아내는 것입니다. 하나의 물체만 대상으로 할 수도 있지만, 보통 여러 물체를 찾아냅니다. 다만 위 이미지처럼 강아지가 두 마리인 경우 강아지1, 강아지2처럼 두 강아지를 구분하기도 하고 구분하지 않기도 합니다.
주어진 이미지 안의 물체 영역을 알아내는 것입니다. 사각형으로 나타내는 Localization이나 Detection과는 다르게, 물체의 실제 영역을 표현해야 하기 때문에 사각형으로 나타낼 수 없습니다. 공처럼 둥근 물체는 둥글게 파악하고, 강아지나 고양이도 각각 그 모습 그대로 파악합니다. 이렇게 표현된 영역을 Object Mask라고 합니다. 원본 이미지와 같은 크기의 데이터에 모든 값을 0으로 초기화 한 후, 물체가 있는 좌표의 데이터만 1,2, ... 등으로 mask를 씌우기 때문에 그렇게 부릅니다. Semantic Segmentation은 강아지가 두 마리인 경우 두 강아지를 별도로 구분하지 않습니다.
Semantic Segmentation과 동일한 역할을 하되 강아지가 두 마리 이상인 경우 이를 별도로 구분하는 차이점이 있습니다. 즉, 서로 다르게 mask된다는 뜻입니다.
[출처: http://research.sualab.com/introduction/2017/11/29/image-recognition-overview-2.html]
바운딩 박스는 이미지 내에서 물체의 위치를 사각형으로 감싼 형태의 도형으로 정의하고 이를 꼭짓점의 좌표로 표현하는 방식입니다.
이 때 2개의 점을 표현하는 방식은 두 가지가 있습니다. 첫 번째로 전체 이미지의 좌측 상단을 원점으로 정의하고 바운딩 박스의 좌상단 좌표와 우하단 좌표 두 가지의 좌표로 표현하는 방식이 있습니다. 두 번째는 이미지 내의 절대적인 좌표로 정의하지 않고 바운딩 박스의 폭과 높이로 정의하는 방식입니다. 이 경우 좌측 상단의 점에 대한 상대적인 위치로 물체의 위치를 정의할 수 있습니다.
이번에는 직접 이미지에 박스를 그려보는 시간을 갖도록 하겠습니다.
person.jpg 이미지를 images 폴더로 가져와, 원본 이미지 위에 인물을 감싸는 사각형을 그려봅시다.
위 이미지를 작업 환경으로 가져옵시다.
AIFFEL 주피터 노트북으로 할 시에는 해당 경로는 다음과 같이 설정한 후 이미지를 불러오면 됩니다.
$ ln -s ~/data/person.jpg ~/aiffel/object_detection/images/
from PIL import Image, ImageDraw
import os
img_path=os.getenv('HOME')+'/aiffel/object_detection/images/person.jpg'
img = Image.open(img_path)
draw = ImageDraw.Draw(img)
draw.rectangle((200, 30, 600, 420), outline=(0,255,0), width=2)
img
[출처: http://research.sualab.com/introduction/2017/11/29/image-recognition-overview-2.html]
위에서 정의한 바운딩 박스가 있을 때 우리가 만든 Localization 모델이 인식한 결과를 평가하려면 어떤 지표를 사용해야 할까요? 각 좌표값의 차이를 L1이나 L2로 정의할 수도 있지만 이는 박스가 크면 그 값이 커지고 작아지면 그 값이 작아져 크기에 따라 달라지는 문제가 생깁니다.
이렇게 면적의 절대적인 값에 영향을 받지 않도록 두 개의 박스의 차이를 상대적으로 평가하기 위한 방법 중 하나가 IoU(Intersection over Union)입니다. 영문 그대로, 교차하는 영역을 합친 영역으로 나눈 값입니다.
위의 그림에서 좀 더 직관적으로 볼 수 있습니다. 빨간색 영역 는 예측(perdiction)과 정답 (ground truth)의 교집합인 영역이고 회색 영역이 합집합인 영역일 때, IoU는 빨간 영역을 회색 영역으로 나눠준 값입니다.
참고로 정답과 예측값의 영역이 일치하는 경우는 IoU는 1이 될 수밖에 없습니다. 합집합인 영역과 교집합인 영역이 동일해지기 때문이죠.
물체의 영역을 숫자로 표현할 수 있게 되었습니다. 이제 localization을 위한 모델을 배워보봅시다.
classification 모델을 만들 땐 convolution layer로 구성된 백본 네트워크(backbone network)를 통해 이미지의 특성을 추출하고 그 다음에 클래스 간 분류를 위한 fully connected layer를 추가했습니다. Classification 문제를 풀 땐 표현해야 할 클래스에 따라 최종 결과 노드의 개수가 정해졌습니다.
이제 우리는 localization을 위해 박스의 위치를 표현할 output 노드 4개를 convolution layer로 구성된 백본 네트워크 다음에 추가해야 합니다.
y =
이를 위한 라벨은 위와 같습니다. 는 물체가 있을 확률이고 물체가 있을 때 , , 은 각각 클래스 1,2,3에 속할 확률을 나타냅니다. 가 0인 경우 배경인 경우가 될 것입니다. 필요에 따라서는 , , 과 를 분리하여 다른 활성화 함수를 적용하고 손실을 계산할 수도 있습니다.
그리고 여기에 우리가 원하는 바운딩 박스를 정의하기 위한 4개의 노드가 추가됩니다. 여기서는 바운딩 박스 좌측 상단의 점의 위치와 바운딩 박스의 폭, 높이로 박스를 표현했습니다. 따라서 , 는 좌측 상단의 점을 표현하는 x축과 y축의 좌표이고 , 는 바운딩 박스의 높이와 폭이 됩니다.
단, , , , 는 모두 입력 이미지의 너비 w, 높이 h로 각각 Normalize된 상대적인 값으로 표시된다는 것을 기억해야 합니다. 0과 1사이의 값을 띄겠죠!!
Classification모델 대신 위처럼 output을 추가해서 localization 모델을 구성한다고 했을 때, 전체적인 모델을 keras로 간단히 만들어봅시다.
import tensorflow as tf
from tensorflow import keras
output_num = 1+4+3 # object_prob 1, bbox coord 4, class_prob 3
input_tensor = keras.layers.Input(shape=(224, 224, 3), name='image')
base_model = keras.applications.resnet.ResNet50(
input_tensor=input_tensor,
include_top=False,
weights='imagenet',
pooling=None,
)
x = base_model.output
preds = keras.layers.Conv2D(output_num, 1, 1)(x)
localize_model=keras.Model(inputs=base_model.input, outputs=preds)
localize_model.summary()
이제 Localization을 확장해서 object deteection을 해보도록 하겠습니다. Localization을 위한 모델은 입력값으로 들어온 이미지에서 특정 물체가 있는지 확인하고, 물체가 있다면 그 위치를 찾아내도록 했습니다. 하지만 이제는 Multi object detection을 통해 앞서 설명한 바와 같이 이미지에 있는 여러 물체를 한꺼번에 찾아야 합니다. 이때는 어떻게 물체를 찾아낼 수 있을까요?
우리가 위에서 계산한 Localization은 일정한 크기의 입력 이미지에 어떤 물체가 있는지를 확인하고 그 위치를 찾아내는 방법이었습니다. 그러면 큰 이미지에서 여러 물체를 찾으려면 어떻게 해야 할까요?
[출처: https://www.researchgate.net/figure/Object-detection-by-sliding-window-approach_fig1_266215670]
우선 전체 이미지를 적당한 크기의 영역으로 나눈 후에, 각각의 영역에 대해 이전 스텝에서 만든 Localization network를 반복 적용해 보는 방식을 생각해 볼 수 있습니다. 이러한 방식을 슬라이딩 윈도우라고 합니다. Localization network의 입력으로 만들기 위해서 원본 이미지에서 잘라내는 크기를 윈도우 크기로 하여, 동일한 윈도우 사이즈의 영역을 이동시키면서(sliding) 수행하는 방식입니다. 마치 컨볼루션(Convolution)의 커널이 슬라이딩하는 것처럼 이해하시면 됩니다.
그러나 이 방식은 매우 많은 갯수의 window 영역에 대한 이미지의 localization을 돌아가면서 하나씩 다 진행해햐 하므로 처리해야 할 window 갯수만큼이나 시간이 더 걸린다는 단점이 존재합니다. 즉 처리속도 면에서 문제가 심각해진다는 뜻입니다.
[출처: https://medium.com/datadriveninvestor/evolution-of-object-recognition-algorithms-i-5803c7be0691]
Sliding window의 단점인 연산량과 속도를 개선하기 위한 방법 중 하나로 convolution을 사용하는 것입니다. Sliding window에서 언급했던 것과 같이, 이 아이디어는 convolution과 닮은 데가 있습니다. 위 그림에서 14x14 크기의 입력에 대해 convolution을 수행했을 때 최종적으로 얻어지는 1x1 사이즈의 출력을 sliding window 영역의 localization 결과라고 해석한다면, 거꾸로 14x14 크기의 receptive field가 바로 sliding window 영역이 되는 효과가 있습니다. 그러나 sliding window로 localization을 수행하는 방식처럼 순차적으로 연산이 실행되는 게 아니라 병렬적으로 동시에 진행되므로 convolution은 속도 면에서 훨씬 효율적입니다.
결과적으로 Sliding window를 한 번에 Convolution으로 연산을 할 수 있습니다. 이전 스텝에서 localization을 위한 output이 flat vector 형태로 생성되었다면, convolution의 결과로 얻어지는 1x1 형태의 output도 동일하게 localization 결과로 대체될 수 있을 것입니다.
위의 그림에서는 입력 이미지가 들어왔을 때 특성을 추출하기 위한 첫 번째 스테이지를 거친 후 classifier로 넘어갑니다. 이때 14x14, 16x16 크기의 입력 두 가지를 볼 수 있는데 14x14에서는 1칸에 대한 결과를 볼 수 있지만 16x16에서는 윈도우가 4개가 되어 4칸에 대한 결과를 볼 수 있습니다.
우리가 만드는 것이 차량을 찾는 Localization 모델이라면, 차량의 존재 여부에 대한 확률과 바운딩 박스를 정의하기 위한 4개의 값으로 크기가 5인 1x1 벡터가 output의 1x1 한 칸에 들어가게 됩니다.
Fully Convolutional Networks for Semantic Segmentation
해당 내용을 정리한 영상입니다.
[출처: https://unsplash.com/photos/I4pHtQX23k0/]
이제 확인했던 Detection 모델로 위의 그림을 인식한다고 가정해 봅시다. 그런데 한 가지 문제가 생겼습니다. 차 사이에 사람이 있습니다. 우리는 한 칸에 한 가지 물체만 감지하기 때문에 만약 모두 차를 잡게 된다면 사람을 놓칠 수밖에 없습니다.
앵커 박스(Anchor Box) 는 서로 다른 형태의 물체와 겹친 경우에 대응할 수 있다는 장점이 있습니다. 일반적으로 차는 좌우로 넓고 사람은 위아래로 길쭉합니다.따라서 사람의 형태와 유사한 형태, 차와 유사한 형태의 가상의 박스 두 개를 정의합니다.
기존에 위에서 본 모델의 구조에서 두 개의 클래스로 확장해 봅시다. 차와 사람 클래스에 대해서 물체를 감지하기 위해서는 한 개의 그리드 셀에 대한 결괏값 벡터가 물체가 있을 확률, 2개의 클래스, 그리고 바운딩 박스 4개로 총 7개의 차원을 가지게 될 것입니다. 따라서 입력값이 16x16일 때, 이 그림을 2x2로 총 4칸의 그리드로 나눴다고 한다면, 결괏값의 형태는 7개의 채널을 가져 2x2x7이 됩니다.
이 때 7개의 차원을 한 번 더 늘려주어 한 개의 물체 수를 늘려줍니다. 앵커 박스가 두 개가 된다면 결괏값의 형태는 2x2x14가 됩니다.
위 영상을 통해 자세한 내용을 학습했다면, 그림으로 다시 한 번 확인해 봅시다.
[출처: http://datahacker.rs/deep-learning-anchor-boxes/]
위에서 설명한 앵커 박스는 위와 같습니다. Anchor box #1
은 사람을 위해 설정한 크기이고 Anchor box #2
는 차를 위해 설정한 크기입니다. y의 라벨을 보면 앵커 박스가 2개가 됨에 따라서 output dimension이 두 배가 된 것을 볼 수 있습니다. 그리고 각각은 정해진 Anchor box에 매칭된 물체를 책임지게 됩니다.
그림 가장 우측에는 차만 있는 경우 사람을 담당하는 Anchor box #1의 가 0이 되고 차를 담당하는 Anchor box #2는 가 1이 되도록 클래스와 바운딩 박스를 할당하는 것을 볼 수 있습니다. 한 그리드 셀에서 앵커 박스에 대한 물체 할당은 위에서 배운 IoU로 할 수 있습니다. 인식 범위 내에 물체가 있고 두 개의 앵커 박스가 있는 경우 IoU가 더 높은 앵커 박스에 물체를 할당하게 됩니다.
(여기서 잠깐)
바운딩 박스와 앵커 박스라는 두 가지 개념이 혼동이 되시지 않나요?
*바운딩 박스 : 모델이 추론한 물체의 위치가 표현된 박스입니다. 혹은 물체 위치의 실제값으로 데이터셋에 준비된 라벨일 수도 있습니다. 물체마다 한 개가 존재하겠죠?
*앵커 박스 : 모델이 추론해야 할 위치의 후보들입니다. 이미지의 모든 영역을 뒤덮을만큼 다양한 앵커 박스를 만들어서 그중에 물체가 있을 확률이 가장 높은 앵커 박스를 물체의 바운딩 박스라고 예측하게 되죠. 앵커 박스를 사용하려면 학습 데이터의 라벨도 앵커 박스 형태로 바꿔 주어야 합니다.
[출처: https://www.quora.com/How-does-non-maximum-suppression-work-in-object-detection]
우리가 2x2 또는 더 큰 Grid cell에서 물체가 있는지에 대한 결과를 받게 된다면 매우 많은 물첼르 받게 됩니다. Anchor box를 사용하지 않더라도 2x2 격자에 모두 걸친 물체가 있는 경우 하나의 물체에 대해 4개의 Bounding box를 얻게 되죠. 이렇게 겹친 여러 개의 박스를 하나로 줄여줄 수 있는 방법 중 하나가 NMS(non-max suppression)입니다.
NMS는 겹친 박스들이 있을 경우 가장 확률이 높은 박스를 기준으로 기준이 되는 IoU 이상인 것들을 없앱니다. 이 때 IoU를 기준으로 없애는 이유는 어느 정도 겹치더라도 다르물체가 있는 경우가 있을 수 있기 때문입니다. Non-max suppression은 같은 class인 물체를 대상으로 적용하게 됩니다.
NMS의 IoU 기준이 0.3인 것과 0.5인 것 중어떤 것이 박스가 많이 남게 될까요?
- IoU기준이 일정 이상인 경우를 NMS 연산을 통해서 가장 높은 score인 하나를 남기게 됩니다. 그렇다면 문턱이 낮은 것이 더 많은 박스를 없애게 된다. 따라서 NMS의 IoU 기준이 0.3인 경우가 더 많은 박스가 사라지고 0.5인 경우가 많은 박스가 남게 됩니다.
5-5. Detection (2) 앵커 박스, NMS
3) 앵커 박스(Anchor box)
content img
[출처: https://unsplash.com/photos/I4pHtQX23k0/]
이제 확인했던 Detection 모델로 위의 그림을 인식한다고 가정해 봅시다. 한 가지 문제가 생겼습니다. 차 사이에 사람이 있습니다. 우리는 한 칸에 한 가지 물체를 감지하기 때문에 만약 모두 차를 잡게 된다면 사람을 놓칠 수밖에 없습니다.
앵커 박스(anchor box) 는 서로 다른 형태의 물체와 겹친 경우에 대응할 수 있습니다. 일반적으로 차는 좌우로 넓고 사람은 위아래로 길쭉합니다. 따라서 사람의 형태와 유사한 형태와 차와 유사한 형태의 가상의 박스 두 개를 정의합니다.
기존에 위에서 본 모델의 구조에서 두 개의 클래스로 확장해 봅시다. 차와 사람 클래스에 대해서 물체를 감지하기 위해서는 한 개의 그리드 셀에 대한 결괏값 벡터가 물체가 있을 확률, 2개의 클래스, 그리고 바운딩 박스 4개로 총 7개의 차원을 가지게 될 것입니다. 따라서 입력값이 16x16 일 때, 이 그림을 2x2로 총 4칸의 그리드로 나누었다고 하면, 결괏값의 형태는 7개의 채널을 가져 2x2x7이 됩니다.
이때 7개의 차원을 한 벌 더 늘려주어 한 개의 물체의 수를 늘려줍니다. 앵커 박스가 두 개가 된다면 결괏값의 형태는 2x2x14가 됩니다.
위 영상을 통해 자세한 내용을 학습했다면, 그림으로 다시 한 번 확인해 봅시다.
content img
[출처: http://datahacker.rs/deep-learning-anchor-boxes/]
위에서 설명한 앵커 박스는 위와 같습니다. Anchor box #1은 사람을 위해 설정한 크기이고 Anchor box #2는 차를 위해 설정한 크기입니다. y의 라벨을 보면 앵커 박스가 2개가 됨에 따라서 output dimension이 두 배가 된 것을 볼 수 있습니다. 그리고 각각은 정해진 Anchor box에 매칭된 물체를 책임지게 됩니다.
그림 가장 우측에는 차만 있는 경우 사람을 담당하는 Anchor box #1의 p_cp
c
가 0이 되고 차를 담당하는 Anchor box #2는 p_cp
c
는 1이 되도록 클래스와 바운딩 박스를 할당하는 것을 볼 수 있습니다. 한 그리드 셀에서 앵커 박스에 대한 물체 할당은 위에서 배운 IoU로 할 수 있습니다. 인식 범위 내에 물체가 있고 두 개의 앵커 박스가 있는 경우 IoU가 더 높은 앵커 박스에 물체를 할당하게 됩니다.
(여기서 잠깐)
바운딩 박스와 앵커 박스라는 두 가지 개념이 혼동이 되시지 않나요?
바운딩 박스 : 모델이 추론한 물체의 위치가 표현된 박스입니다. 혹은 물체 위치의 실제값으로 데이터셋에 준비된 라벨일 수도 있습니다. 물체마다 한 개가 존재하겠죠?
앵커 박스 : 모델이 추론해야 할 위치의 후보들입니다. 이미지의 모든 영역을 뒤덮을만큼 다양한 앵커 박스를 만들어서 그중에 물체가 있을 확률이 가장 높은 앵커 박스를 물체의 바운딩 박스라고 예측하게 되죠. 앵커 박스를 사용하려면 학습 데이터의 라벨도 앵커 박스 형태로 바꿔 주어야 합니다.
Q6. 차와 사람을 Detection하기 위한 모델의 output이 4x4 grid이고 각 cell에 Anchor box를 9개씩 정의한 경우 output의 dimension은 어떻게 될까요?
36차원
예시답안
예시답안
Output dimension은 [Batch size, 4, 4, 9x(1+4+2)]이 됩니다.
4) NMS(Non-Max Suppression)
content img
[출처: https://www.quora.com/How-does-non-maximum-suppression-work-in-object-detection]
우리가 2x2 또는 더 큰 Grid cell에서 물체가 있는지에 대한 결과를 받게 되면 매우 많은 물체를 받게 됩니다. Anchor box를 사용하지 않더라도 2x2격자에 모두 걸친 물체가 있는 경우 하나의 물체에 대해 4개의 Bounding box를 얻게 되죠. 이렇게 겹친 여러 개의 박스를 하나로 줄여줄 수 있는 방법 중 하나가 NMS(non-max suppression) 입니다.
NMS는 겹친 박스들이 있을 경우 가장 확률이 높은 박스를 기준으로 기준이 되는 IoU 이상인 것들을 없앱니다. 이때 IoU를 기준으로 없애는 이유는 어느 정도 겹치더라도 다른 물체가 있는 경우가 있을 수 있기 때문입니다. 이때 Non-max suppression은 같은 class인 물체를 대상으로 적용하게 됩니다.
Q7. NMS(Non-max suppression)는 IoU를 기준으로 박스를 없애게 됩니다 NMS의 IoU기준이 0.3인것과 0.5인 것중 어떤 것이 박스가 많이 남게 될까요?
0.5
예시답안
예시답안
IoU기준이 일정 이상인 경우를 NMS연산을 통해서 가장 높은 score인 하나를 남기게 됩니다. 그렇다면 문턱이 낮은 것이 많은 박스를 없애게 되겠죠. 따라서 NMS의 IoU기준이 0.3인 경우가 더 많은 박스가 사라지고 0.5인 경우가 많은 박스가 남게 됩니다.
Convolutional implementation of Sliding Windows
Anchor box
Non-max suppression(NMS)
지금까지 위의 세 가지 개념과 CNN을 활용한 물체 검출(Object detection) 방법을 배워보았습니다.
Convolution으로 슬라이딩 윈도우를 대신함으로써 여러 영역에서 Object localization을 병렬로 수행할 수 있게 되어 속도 측면의 개선이 있었습니다. Anchor box는 겹친 물체가 있을 때, IoU를 기준으로 서로 다른 Anchor에 할당하도록 하여 생긴 영역이 다른 물체가 겹쳤을 때도 물체를 검출할 수 있도록 할 수 있게 되었습니다. 마지막으로 Non-max suppression은 딥러닝 모델에서 나온 Object detection 결과들 중 겹친 결과들을 하나로 줄이면서 더 나은 결과를 얻을 수 있게 했습니다.
이제는 위 3가지를 토대로 접근한 다양한 검출 모델을 확인해 보도록 하겠습니다.
앞에서 봐왔던 바운딩 박스 regression과 앵커 박스, 그리고 NMS를 이용하면 어느 정도 동작하는 Detection 모델을 만들 수 있습니다. 그렇다면 이보다 더 나아간 방법들은 어떤 것들이 있을까요?
Detection task는 많은 산업에 활용되고 관련 연구도 활발하게 진행되고 있습니다.
딥러닝 기반의 Object Detection 모델은 크게 Single stage detector와 Two stage detector로 구분할 수 있습니다. 아래에서 그 예시를 볼 수 있습니다.
Many stage라고 적혀있는 방법에서는 물체가 있을 법한 위치의 후보(proposals)들을 뽑아내는 단계, 이후 실제로 물체가 있는지를 Classification과 정확한 바운딩 박스를 구하는 Regression를 수행하는 단계가 분리되어 있습니다. 대표적으로는 Faster-RCNN을 예로 들 수 있습니다.
One stage Detector는 객체의 검출과 분류, 그리고 바운딩 박스 regression을 한 번에 하는 방법입니다.
[출처: https://medium.com/@jitender_phogat/1-2-introducing-retinanet-and-focal-loss-for-dense-object-detection-7ef9c4901b61]
간단하게 single-stage와 two-stage로 구분해서 봤지만 딥러닝을 활용한 Object Detection 논문을 정리해 보면 아래와 같이 엄청나게 많습니다. 저희는 이 중에서 대표적인 Two-stage detector인 Fast R-CNN => Faster R-CNN의 변천사와 One-stage detector인 YOLO 및 SSD 를 살펴보도록 하겠습니다.
Object Detection in 20 Years: A Survey
[출처: https://arxiv.org/pdf/1311.2524.pdf]
위에서 보이는 Detection 모델들 중 먼저 R-CNN이라는 이름들이 눈에 띕니다. 이 논문들이 대표적인 two-stage 방법들입니다. R-CNN은 물체가 있을 법한 후보 영역을 뽑아내는 "Region proposal" 알고리즘 과 후보 영역을 분류하는 CNN을 사용합니다. 이때 Proposal을 만들어내는 데에는 Selective search라는 비 신경망 알고리즘이 사용됩니다. 이후에 후보 영역의 Classification과 바운딩 박스의 regression을 위해 신경망을 사용합니다.
위에서 본 R-CNN의 경우 region proposal을 selective search로 수행한 뒤 약 2,000개에 달하는 후보 이미지 각각에 대해서 컨볼루션 연산을 수행하게 됩니다. 이 경우 한 이미지에서 특성을 반복해서 추출하기 때문에 비효율적이고 느리다는 단점이 있습니다.
Fast R-CNN에서는 후보 영역의 classification과 바운딩 박스 regression을 위한 특성을 한 번에 추출 하여 사용합니다. R-CNN과의 차이는 후보 영역을 CNN을 거친 특성 맵(Feature Map) 에 투영해, 특성 맵을 잘라낸다는 사실입니다. 이렇게 되면 이미지를 잘라 개별로 CNN을 연산하던 R-CNN과는 달리 한 번의 CNN을 거쳐 그 결과물을 재활용할 수 있으므로 연산수를 줄일 수 있습니다.
이때 잘라낸 특성 맵의 영역은 여러 가지 모양과 크기를 가집니다. 이 영역은 입력의 크기가 정해져 있는 fully connected layer를 통과해야 하기 때문에 같은 크기로 변형되어야 하는데, 이를 위해서 RoI(Region of Interest) Pooling 이라는 방법을 적용합니다.
[출처: https://arxiv.org/pdf/1506.01497.pdf]
이미지 모델을 해석하기 위해 많이 사용하는 CAM(Classification Activation Map)에서는 물체를 분류하는 태스크만으로도 활성화 정도를 통해 물체를 어느 정도 찾을 수 있습니다. 이처럼 먼저 이미지에 CNN을 적용해 특성을 뽑아내면, 특성 맵만을 보고 물체가 있는지 알아낼 수 있습니다. 이때 특성 맵을 보고 후보 영역들을 얻어내는 네트워크가 RPN입니다. 후보 영역을 얻어낸 다음은 Fast R-CNN과 동일합니다.
YOLO는 이미지를 그리드로 나누고, 슬라이딩 윈도 기법을 컨볼루션 연산으로 대체해 Fully Convolutional Network 연산을 통해 그리드 셀 별로 바운딩 박스를 얻어낸 뒤 바운딩 박스들에 대해 NMS를 한 방식입니다. 논문을 보면 이미지를 7x7 짜리 그리드로 구분하고 각 그리드 셀마다 박스를 두 개 regression 하고 클래스를 구분하게 합니다. 이 방식의 경우 그리드 셀마다 클래스를 구분하는 방식이기 때문에 두 가지 클래스가 한 셀에 나타나는 경우 정확하게 동작하지는 않습니다. 하지만 매우 빠른 인식 속도를 자랑하는 방법입니다. Andrew Ng 교수님이 정리해 주는 설명을 확인해 보세요.
CNN에서 뽑은 특성 맵의 한 칸은 생각보다 큰 영역의 정보를 담게 됩니다. 여러 컨볼루션 레이어와 pooling을 거치기 때문에 한 특성 맵의 한 칸은 최초 입력 이미지의 넓은 영역을 볼 수 있게 되는데요.
YOLO의 경우 이 특성이 담고 있는 정보가 동일한 크기의 넓은 영역을 커버하기 때문에 작은 물체를 잡기에 적합하지 않습니다. 이러한 단점을 해결하고 다양한 크기의 특성 맵을 활용하고자 한 것이 SSD입니다. SSD는 위의 모델 아키텍쳐에서 볼 수 있듯이 다양한 크기의 특성 맵으로부터 classification과 바운딩 박스 regression을 수행합니다. 이를 통해서 다양한 크기의 물체에 대응할 수 있는 detection 네트워크를 만들 수 있습니다. 아래 참고 자료를 통해 자세한 내용을 확인해 보세요.
지금까지 딥러닝 기반의 Object detection을 알아봤습니다. Anchor를 쓰지 않는 FCOS(Fully Convolutional One-Stage Object Detection) 같은 방법도 있찌만 많은 방법들이 Anchor를 기반으로 구현되고 있습니다.
YOLO와 Faster-RCNN에서 Anchor를 기반으로 Loss를 계산하는 방식에는 두 가지 IoU를 threshold로 사용합니다. 하나는 Background IoU threshold, 나머지 하나는Foreground IoU threshold입니다. 이런 방식은 Faster-RCNN에서 먼저 확인할 수 있는데, 객체와의 IoU가 0.7 이상일 경우 Foreground로 할당하고 0.3 이하일 경우 배경(Background)으로 할당합니다. 0.3과 0.7의 중간 정도인 Anchor들은 불분명한 영역에 속하기 때문에 학습에 활용되지 않습니다.
위의 차량을 Detection 하기 위한 Detection model을 상상해보면 Feature map의 Grid 한 칸마다 다양한 크기 및 Apsect ratio를 가진 Anchor를 만들고 이와 차량의 크기를 비교해서 학습을 해야 합니다.
위의 예시를 보면 Anchor의 크기가 차량의 박스 크기에 비해 매우 작은 것을 알 수 있죠. 이 경우 차량 영역에 들어간 Anchor box이라도 교차(intersection)하는 면적이 작기 때문에 IoU가 작아 매칭이 되지 않는 것을 알 수 있습니다. 이러한 이유 때문에 우리가 탐지하고자 하는 물체에 따라서 Anchor box의 크기나 aspect ratio를 조정해 주어야 합니다.
만약 세로로 긴 물체를 주로 탐지해야 하면 세로로 긴 Anchor box를 많이 만들고 Matching되는 box를 늘려야 학습이 잘 될 수 있습니다.
차량을 Detection 하기 위해서 Anchor의 크기를 키우고 Aspect ratio를 조정하여 가로로 길게 만들 수 있습니다. 아래 예시에서는 Anchor의 크기를 키우고 Aspect ratio를 조정했습니다.
그리고 Anchor box와 녹색의 차량 bounding box 간의 IoU를 계산해서 물체와의 IoU가 0.3 이하인 경우는 배경으로 그리고 0.7 이상인 경우는 차량으로 할당되고 두 가지 모두에 해당하지 않는 경우에는 Loss가 학습에 반영되지 않도록 합니다.
위의 이미지에서는 노란색의 경우 배경으로 할당되고 회색은 학습에 미반영되며 녹색은 물체로 학습이 됩니다. 이전에 학습했던 것처럼 노란색의 경우에는 배경이므로 물체의 bounding box를 추정하기 위한 Regression은 loss에 반영되지 않습니다. 따라서 파란색 anchor box만이 regression을 학습할 수 있는 sample이 됩니다.
다양한 물체에 Anchor Box가 걸쳐있는 경우 가장 높은 IoU를 가진 물체의 Bounding box를 기준으로 계산이 됩니다.
Anchor box는 물체를 예측하기 위한 기준이 되는 Box입니다. 그럼 Anchor box에서 Bounding box는 어떤 식으로 계산이 될까요?
여러 가지 접근 방법이 있지만 YOLOv3를 기준으로 설명해드리겠습니다. YOLOv3의 전신인 YOLOv2부터 Bounding box Regression 방식을 사용하게 되는데요, 각 Anchor box에 대응되는 network는 , , , 의 4가지 output으로 bounding box를 regression 해서 정확한 box를 표현하게 됩니다.
Bounding box를 예측하기 위해 예측해야 할 것은 bounding box의 중심점(, ), 그리고 width()와 height()입니다. 그러나 이 값을 직접 예측하는 것이 아니라 위 그림에 있는 수식과 같이 anchor box의 정보 , , , 와 연관지어 찾는 방법을 사용합니다.
기존의 Anchor box 위 좌측 상단이 , 이고 width, height가 , 입니다. 이를 얼마나 x축 또는 y축 방향으로 옮길지 그리고 크기를 얼마나 조절해야 하는지를 예측하여 물체의 bounding box를 추론하게 됩니다.
Object Detection을 다루는 모델은 매우 다양하고, 버전업을 거듭하면서 성능이 지속적으로 개선되어 왔습니다. 하지만 이를 다루기 위한 기본적인 개념은 오늘 대략 언급하였습니다. 의외로 기본적인 개념은 몇 가지 되지 않는다는 것을 알 수 있었는데요, 핵심적인 모델들을 직접 구현해 보면서 오늘 다룬 개념들이 어떻게 조금씩 발전해 왔는지를 직접 체험해 보시기를 권합니다.