안녕하세요 pulluper 입니다 😊
오늘은 object detection에서 많이 쓰이는 anchor box 에 대하여 알아보겠습니다.
Anchor 란 "닻"을 의미합니다. 배를 움직이지 않게 하고 배가 어느 위치에 있는지 확인하는 기준이 될 수 있습니다.
그러한 의미에서 anchor box는 object 가 있음직한 기준의 역할을 합니다.
Anchor box란 무엇일까요?
Anchor box는 미리 정해진 object가 있음직한 box 를 의미합니다.
이 box는 object detection에서 여러가지 역할을 합니다.
Anchor box는 겹쳐있는 object를 모두 검출하기 위해 고안되었습니다.
그림을 보시면, 자동차와 사람이 겹쳐 있습니다. 이때, 두 물체를 모두 검출하기 위해서 다양한 종횡비(aspect ratio)와 크기(scale)로 이루어진 anchor box를 이용해서 모두 구하려합니다. deep neural network를 통한 object detection은 출력이 convolution의 ouput인 2차원 그리드인 경우가 많은데, 각 그리드에서 여러가지 object를 검출 할 수 있도록 도와주는 미리 정해진 box입니다. 아래 그림과 같이 한 이미지에 대하여 적으면 몇백개 많으면 몇만개가 넘는 anchor들이 존재하고 적용되게 됩니다.
그리고 Anchor box는 object detection의 성능에 많은 영향을 끼칩니다. 다음은 여러 알고리즘들에서 사용한 anchor들을 비교한 표 입니다.
Algorithm | Number of Anchors | Image resolution |
YOLOv2 | 845 | 300 x 300 |
SSD | 8732 | 416 x 416 |
YOLOv3 | 10647 | 416 x 416 |
Faster RCNN | 20646 | 600 x 1000 |
RetinaNet | 67995 | 600 x 600 |
Anchor box를 어떻게 만들까요?
anchor box 는 기본적으로 center coordinate로 만듭니다.
이에 대한 정보는 다음 포스팅을 참조하시면 좋을 것 같습니다. https://csm-kr.tistory.com/13?category=1130013
Anchor box를 만들기 위해서는 각 anchor box의 종횡비(aspect_ratio)와 크기(scale) 이 필요합니다. aspect_ratio는 w / h 이고, scale은 실제 pixel 값이나 area값 혹은 input 이미지의 비율 등으로 주어집니다. 각 output feature(grid) 에 대한 anchor들을 center coordinates로 바꾸어서 보통 [num_anchors, 4]의 shape 으로 저장합니다.
Faster RCNN을 예로 들어보면, area = [$128^2$, $256^2$, $512^2$] 이고, aspect ratio = [0.5, 1.0 , 2.0] 입니다.
만들고 싶은 anchor의 좌표를 cx, cy, w, h로 잡고 Input image의 크기로 normalization 을 해 줄 것입니다.
input image 의 크기를 편의를 위해 640 x 640으로 잡고, network 의 output feature를 40 x 40이라 하겠습니다.
각 output feature를 돌면서, 0~1의 상대적 위치를 잡을 수 있으므로,
anchor의 cx = i + 0.5 / 40 로,
anchor의 cy = j + 0.5 / 40 로 잡을 수 있습니다.
anchor의 w = $\sqrt{area \times aspect ratio}$ / width of input image = $\sqrt{(w \times h) \times \frac{w}{h}}$ / width of input image,
anchor의 h = $\sqrt{area \times \frac{1}{aspect ratio}}$ / height of input image = $\sqrt{(w \times h) \times \frac{h}{w}}$ / height of input image 으로 계산 가능합니다.
즉 area 가 $128^2$이고, aspect ratio가 0.5이면, w = $\sqrt{128^2 \times 0.5} = 90.51 $, h = $\sqrt{128^2 \times 2} = 181.02$ 이고 이를 각각 640 으로 나눠주면 normalization 이 되어 약 (w, h) = (0.1414.., 0.2828..) 를 얻게 됩니다.
위의 예에 대한 code는 다음과 같습니다.
import numpy as np
def create_anchors(image_size=(640, 640), num_pooling=4):
print('make retina anchors')
# get height and width of features
image_height, image_width = size = image_size # h, w
feature_height, feature_width = image_height, image_width
for i in range(num_pooling):
feature_height = feature_height // 2
feature_width = feature_width // 2
# the shape of network output is (40, 40)
areas = [128**2, 256**2, 512**2]
aspect_ratios = np.array([0.5, 1.0, 2.0])
center_anchors = []
# 4. make anchors
for j in range(feature_height): # f_h
for i in range(feature_width): # f_w
c_x = (i + 0.5) / feature_width # (0-1 scaling)
c_y = (j + 0.5) / feature_height # (0-1 scaling)
for aspect_ratio in aspect_ratios:
for area in areas:
w = np.sqrt(area * aspect_ratio) / image_width
h = np.sqrt(area / aspect_ratio) / image_height
anchor = [c_x,
c_y,
w,
h]
center_anchors.append(anchor)
center_anchors = np.array(center_anchors).astype(np.float32)
return center_anchors
Anchor box는 deep learning을 이용한 object detection 문제를 간접적인 방법으로 바꿉니다.
이것이 무슨 말일까요? 먼제 어떤 deep neural network를 $f_{\theta}$ 라고 합시다. 그리고 supervised learning에서 dataset $(x, y)$ 를 이용해서 object detection 문제를 푼다고 할 때, 목표는 두가지 입니다. 물체의 위치(box 의 좌표점),물체의 class를 알아내는 것 입니다. anchor를 사용한 object detection 네트워크 $f_{\theta}$의 output는 이미지로부터 직접적으로 box의 좌표점과 class를 생성해내지 않습니다. 알고리즘 마다 약간씩 다르지만 네트워크의 output은 anchor box와 predicted box의 관계를 예측하고 이를 통해서 다시 anchor 로부터 드디어 box의 좌표를 만들어냅니다. 이를 자세히 알아보겠습니다.
이번에도 Anchor를 사용한 대표적인 알고리즘인 Faster RCNN 으로 예를 들어서 보겠습니다.
1) target 만들기
supervised learning에서 학습을 위해 정답이 필요합니다. anchor를 이용할 때는 정답을 만들기 위해서 anchor box가 들어갑니다. 위에서 관계를 예측한다고 하였습니다. 이 관계란 구체적으로 보면 GT(ground truth)와 Anchor box의 각 좌표에 대한 수식을 통해 나온 값이며 이것을 target이라 지칭하며, 다음과 같이 표현합니다.
그리고 target을 기준으로 smooth l1 loss, IoU loss로 학습을 진행합니다.
이에 대한 코드는 다음과 같습니다.
def make_target(gtcxcy, ancxcy):
"""
for loss, gtcxcy(gt cxcy) to tgcxcy(target cxcy)
"""
tgcxcy = (gtcxcy[:, :2] - ancxcy[:, :2]) / ancxcy[:, 2:]
tgwh = torch.log(cxcy[:, 2:] / ancxcy[:, 2:])
return torch.cat([tgcxcy, tgwh], dim=1)
2) 예측된 target 으로부터 box로 만들기
학습의 정답이 target이기 때문에 prediction(예측)시 네트워크는 이미지를 입력을 받고 $f_{\theta}(x) = \hat{t} = \{\hat{t_x}, \hat{t_y}, \hat{t_w}, \hat{t_h}\}$를 출력합니다. 이때, Anchor box와 예측된 Target을 알기 때문에 위의 수식의 역연산을 통해서 prediction box의 좌표를 얻을 수 있게 됩니다. 이는 다음과 같습니다. $P$는 prediction box를 뜻합니다.
이러한 일련의 과정을 통해야만 최종 prediction bouding box의 좌표를 얻을 수 있기에 object detection 을 간접적인 방법으로 바꾸는 것 입니다. 네트워크가 직접 bounding box의 좌표를 만드는게 아니라, anchor를 통해야만 bounding box의 좌표를 얻을 수 있도록 설계된 것 입니다. 이를 코드로 나타내면 다음과 같습니다.
def make_prediction(tgcxcy, ancxcy):
"""
for test and demo, tgcxcy to predicted box
"""
pred_cxcy = tgcxcy[:, :2] * ancxcy[:, 2:] + ancxcy[:, :2]
pred_wh = torch.exp(tgcxcy[:, 2:]) * ancxcy[:, 2:]
return torch.cat([pred_cxcy, pred_wh], dim=1)
마지막으로 Prediction 시 어떤 Anchor Box 를 사용하는지도 중요합니다. 이는 알고리즘마다 약간씩 다른데, grid나 각 anchor에 대하여 그것들이 물체가 있음직한 score를 이용하여 anchor를 실제 prediction에 사용합니다. 이후 NMS 등과 같은 post processing으로 마지막 예측박스의 갯수를 정합니다.
이번 포스팅은 Anchor box에 대하여 정리해 봤습니다.
각 알고리즘마다 조금씩의 차이는 있지만 이런 프로세스로 흘러간다는 점을 염두해 두시고 학습하시면 좋겠네요.
질문과 의견 및 토론은 항상 환영합니다. 😎😎😎😎😎
감사합니다.
'Object Detection > Etc' 카테고리의 다른 글
[Object Detection] bounding box coordinates 설명과 pytorch 구현 (4) | 2021.05.09 |
---|
댓글