본문 바로가기

갈아먹는 Object Detection [5] Yolo: You Only Look Once

지난 글

갈아먹는 Object Detection [1] R-CNN

갈아먹는 Object Detection [2] Spatial Pyramid Pooling Network

갈아먹는 Object Detection [3] Fast R-CNN

갈아먹는 Object Detection [4] Faster R-CNN

들어가며

오늘 리뷰할 논문은 real time object detection의 혁명을 몰고 온 yolo입니다. 우선 결과부터 보시죠.

Yolo는 2015년에 나온 논문으로 Faster R-CNN에 비하여 부려 6배 가량 빠른 속도를 보입니다. 정확도는 비록 조금 낮다 하더라고 정말 비약적인 발전이라 할 수 있네요!

 

영향력: Joseph Redmon라는 사람이 1 저자이며 R-CNN의 Ross가 3 저자로 참여했습니다. 인용 횟수는 8천회에 달합니다. 1 저자가 궁금하여 좀 찾아봤는데 생각보다 훨씬 더 독특한 사람이었습니다.  개인 홈페이지가 어디서 봤다 했더니 C 언어로 짜여진 뉴럴넷 프레임 워크 Darknet의 창시자이자 운영자인 놀랍게도... 대학원생이었습니다. 이렇게 생긴 대학원생 홈페이지는 처음보네요.

주요 기여: 1 Step Object Detection 기법을 제시하였으며, fps가 무려 45로 속도 측면에서 획기적인 발전을 이루었습니다.

https://pjreddie.com/

 

Survival Strategies for the Robot Rebellion

Welcome to my website! I am a graduate student advised by Ali Farhadi. I work on computer vision. I maintain the Darknet Neural Network Framework, a primer on tactics in Coq, occasionally work on research, and try to stay off twitter. Outside of computer s

pjreddie.com

 

https://www.youtube.com/watch?v=XS2UWYuh5u0

오늘 진행할 리뷰는 Deepsystems라는 러시아 형님들의 리뷰 자료[2]를 많이 참고하였습니다. yolo가 동작 하는 방식에서 대해서 진짜 뼈 째로 갈아먹은 자료라 구체적인 동작 방식이 궁금하신 분들은 페이퍼를 한 번 보시고, 해당 자료를 보시면 좋습니다.

 

 

Unified Detection

Yolo가 기존의 Object Dection과 가장 크게 구분되는 부분은 기존에 1) region proposal 2) classification 이렇게 두 단계로 나누어서 진행하던 방식에서 region proposal 단계를 제거하고 한번에 Object Detection을 수행하는 구조를 갖는다는 점입니다. 이것이 어떻게 가능할까요? 아래 그림은 yolo의 1 Step 구조를 간단히 보여줍니다.

Yolo Unified Detection

먼저 입력 이미지를 S X S 그리드 영역으로 나눕니다. (실제 입력 이미지를 나누는 것이 아닙니다! 이 부분의 세부 내용은 아래에 더 자세히 다룹니다.) 이제 각 그리드 영역에서 먼저 물체가 있을 만한 영역에 해당하는 B개의 Bounding Box를 예측합니다. 이는 (x, y, w, h)로 나타내어 지는데 (x, y)는 bounding box의 중심점 좌표이며 w, h는 넓이와 높이입니다. 다음으로 해당 박스의 신뢰도를 나타내는 Confidence를 계산합니다. 이는 해당 그리드에 물체가 있을 확률 Pr(Object)와 예측한 박스와 Ground Truth 박스와의 겹치는 영역을 비율을 나타내는 IoU를 곱해서 계산합니다.

Confidence

그 다음으로 각각의 그리드마다 C개의 클래스에 대하여 해당 클래스일 확률을 계산하며 수식은 아래와 같습니다. 이 때, 특이한 점은 기존의 Object Detection에서는 항상 클래스 수 + 1 (배경)을 집어넣어 클래시피케이션을 하는데, yolo는 그렇지 않습니다.

이렇게 yolo는 입력 이미지를 그리드로 나누고, 각 그리드 별로 바운딩 박스와 클래시피케이션을 동시에 수행합니다. 여기까지만 들어서는 어떻게 구현될지 잘 감이 오질 않습니다. 구체적인 네트워크 디자인을 보면서 더 알아보겠습니다.

Network Design

Yolo Network

논문에서 가져온 네트워크 그림입니다. 저자는 GoogleNet의 아키텍쳐에서 영감을 받았으며, Inception 블럭 대신 단순한 컨볼루션으로 네트웤을 구성했다고 합니다. 224x224 크기의 이미지 넷 클래시피케이션으로 pretrain 시켰습니다. 이후엔 입력 이미지로 448x448 크기 이미지를 입력으로 받습니다. 그리고 앞쪽 20개의 컨볼루션 레이어는 고정한 채, 뒷 단의 4개 레이어만 object detection 테스크에 맞게 학습시킵니다. 아래는 [2]에서 가져온 더 직관적인 그림입니다.

Yolo Network

이제 네트워크의 출력인 7x7x30 피쳐맵에 대해서 알아보겠습니다. 여기 안에는 우리가 앞서서 말했던 그리드 별 바운딩 박스와 신뢰도 지수, 그리고 각 클래스 별 예측값들이 담겨져 있습니다.

먼저 7x7은 그리드를 의미하며, 각각의 인덱스는 총 30차원의 백터 값을 가집니다. 위 그림을 보시면 7x7 그리드 가운데 하나의 인덱스에 붉은 색 박스가 쳐져있는 것을 볼 수 있습니다. 앞서 우리는 하나의 인덱스에서 B개의 Bounding Box를 추측한다고 했으며, 논문에서는 이를 2로 설정하였습니다. 30차원 벡터 가운데 앞의 10 개의 수는 바로 이 두 개의 박스를 의미합니다. 하나의 박스는 중심점 x와 y, 너비와 높이 w,h 그리고 신뢰도 지수 C 이렇게 (x, y, w, h, C) 다섯개 차원의 벡터로 나타낼 수 있으며, 두 개 박스는 10차원 벡터에 해당합니다.

 

그 다음 오는 20차원 벡터는 해당 인덱스가 특정 클래스일 확률 값들이며, 여기서는 클래스가 20인 데이터 셋을 사용하였기 때문에 20 차원 벡터로 표현됩니다. 잠깐 기억을 더듬으면 우리는 박스의 신뢰도를 Pr(obj) * IoU로 구했고, 각 클래스별 확률 값을 구할 때는 Pr(classi | object) 로 구했습니다. 따라서 이 둘을 곱해주면 Pr(classi) * IoU 가 되고, 이는 곧 해당 박스가 특정 클래스일 확률 값이 됩니다. 이제 이 작업을 인덱스 i의 모든 B개 바운딩 박스에 적용하고, 이를 다시 SxS 인덱스에 적용하면 다음과 같은 결과를 얻습니다.

이제 이렇게 구한 벡터들을 모두 모은 뒤 일렬로 나란히 세우면, 가장 위 차원부터 각 클래스별로 전체 바운딩 박스에서의 확률 값을 구할 수 있습니다. 물론 여기에는 동일한 물체에 중복되어 지정된 박스들도 있을 것입니다. 이를 방지하고자 NMS라는 작업을 거치게 되는데, 구체적인 작동방식은 [2]의 슬라이드 39 - 70을 참고하시면 됩니다. 이제 NMS를 거쳐서 살아남은 최종 결과를 이미지 위에 그려주는 작업만 남았습니다.

NMS를 거치게 되면 벡터들의 대부분의 값들은 0이 됩니다. 하나의 바운딩 박스는 하나의 클래스에 속하므로, 벡터에서 최대 값을 계산하여 해당하는 클래스를 이미지 위에 박스와 함께 그려주면 됩니다.

Loss Function

지금까지 조금 복잡하지만 아주아주 신기한 (대체 어떻게 이런 생각을 해냈을까 그저 놀라운...) yolo의 네트워크 구조를 알아보았습니다. 그렇다면 이 네트워크를 어떻게 학습시킬 수 있을까요? 저자들은 아주 세심하게 디자인 된 로스 펑션을 제시합니다.

Yolo Loss Function

수식이 좀 긴데 전혀 쫄 필요가 없습니다. 이를 이해하기 위해선 먼저 1obj ij라고 생긴 기호를 이해해야 합니다. 이는 object 가 등장하는 i 인덱스의 j번째 바운딩 박스가 최종 프레딕션을 낸 것을 의미합니다. 앞서 우리는 NMS를 거쳐서 살아남은 일부 바운딩 박스만 최종 프레딕션에 포함시켰습니다. 따라서 Loss Function을 구할 때도 이 박스들을 찾아서 로스를 구하는 것입니다. 어렵지 않죠?

Yolo Loss Front Half

로스 펑션의 앞단입니다. 크게 어려울 것 없이 최종 프레딕션에 포함된 바운딩 박스를 찾아내어 x, y 좌표, w, h 값, C 값이 예측 값과 ground truth 값의 차를 구해 모두 더해줍니다. 이 때, x, y, C 값은 그냥 단순 차를 구했고 w, h는 비율 값이기 때문에 루트를 씌워 차이를 구해준 점이 다릅니다만 큰 차이는 없습니다. 앞에 붙은 람다는 물체가 있을 때의 오차와 없을 때의 오차 간의 비율을 맞춰주기 위한 것인데, 논문에서는 모두 5로 설정했습니다.

 

찾아낸 물체들이 얼마나 정확한지 못지 않게 중요한 것이 못 찾아낸 물체들에 대한 페널티를 매기는 것입니다.  1 noobj ij 라는 것은 물체가 없다고 판단된 i 인덱스의 j번째 바운딩 박스가 사실은 가장 ground truth와 IoU가 가장 높은 인덱스를 말합니다. 즉, 물체로 찾아냈어야 하는데 못찾아낸 인덱스입니다. 이에 대해선 찾아냈어야 하므로 C의 값의 차를 구해 로스에 더 해줍니다.

 

마지막으로 모든 물체가 있다고 판단된 인덱스 i들에 대해서 모든 클래스들에 대해서 예측 값과 실제 값의 차를 구해 더해줍니다.

 

지금까지 다소 길었지만 한 줄 한 줄 로스 펑션을 이해해 보았습니다. 수식은 복잡하지만 개념 자체는 직관적으로 와닿습니다. 괜히 수식 보고 잔뜩 쫄 필요가 전혀 없습니다!

 

마치며

지금까지 제 숙원 사업이었던 yolo 페이퍼 리뷰를 해보았습니다. 

 

Yolo는 기존 Object Detection 알고리즘보다 속도 측면에서 비약적인 발전을 이루었지만 동시에 한계점도 있습니다. 그리드 단위로 나누어 예측을 하기 때문에 새 떼와 같이 작은 물체가 여러개 모여있는 object들을 잘 잡아내지 못합니다. 이러한 문제점들은 분명 이후의 논문들에서 해결을 해보았겠죠?

 

뒤에 이어지는 논문들도 기대가 되면서 이만 마치도록 하겠습니다.

감사합니다.

 

[1] Redmond et al, You Only Look Once: Unified, Real-Time Object Detection, 2015, CVPR

[2] Deepsystems, yolo review, https://docs.google.com/presentation/d/1aeRvtKG21KHdD5lg6Hgyhx5rPq_ZOsGjG5rJ1HP7BbA/pub?start=false&loop=false&delayms=3000&slide=id.p