우선 Neck을 이해하기 전에 2-stage-detector의 pipline에 대해 살펴보자. 아래의 그림처럼 입력 이미지가 backbone을 거쳐나온 마지막 feature map만 RPN을 거쳐 Roi영역을 출력하는 것을 볼 수 있다.
이것이 2-stage-detector인 Faster-RCNN의 기본 파이프라인이다. 다음은 Neck을 사용한 2-stage-detector의 pipeline을 보자.
결론부터 말하자면 Neck은 detection model이 다양한 크기의 객체를 감지할 수 있도록 한다.
backbone network의 마지막 feature map은 receptive field가 얉은 층보다 크. 때문에 큰 객체를 감지하는 데 효과가 좋지만. 작은 객체를 감지하는 데 있어 어려움이 있다.
이러한 문제를 해결하기 위해 Neck을 사용하여 high level의 feature를 low level로 전달하여 이를 Roi에 사용하여 다양한 크기의 객체를 감지할 수 있도록 한다.
다음은 이러한 Neck을 사용하여 다양한 크기의 객체를 적은 컴퓨팅 자원으로 인지하는 FPN에 대해 알아보자.
그림을 보면 입력 이미지를 convolutional network에 입력해 4개의 feature map을 추출한다(bottom up). 이후 추출한 feature map들을 top-down 방식으로 low level에 1x1 conv를 진행하여 채널을 늘리고 high level feature에 Upsampling을 진행해 서로 차원을 맞추고 더하여 아래층에 전달 이렇게 top down방식을 통해 구한 feature들에 각각 서로 다른 3X3,1X1 연산을 순서대로 작용해 확률과, 바운딩 박스의 좌표를 예측
FPN의 과정은 간략하게 설명하면 아래와 같이 세 단계로 구성된다.
#1. bulid laterals: 같은 사이즈의 채널로 변경
laterals = [
lateral_conv(input[i]) for i, lateral_conv in enumarate(self.lateral_convs)
]
#2. bulid top-down: 같은 사이즈의 feature를 top-down형식으로 아래 층에 전달
for i in range(3,0,-1):
prev_shape = laterals[i-1].shape[2:]
laterals[i-1] += F.interpolate(laterals[i], size = prev_shape)
#3. bulid output: 최종 3x3 conv를 통과 하여 RPN으로 들어갈 feature 완성
outs = [
self.fpn_convs[i](laterals[i]) for i in range(4)
]
backbone으로 사용할 모델의 깊이가 깊을 수록 top-down할 때 high level의 feature가 low level에 온전히 전달이 안될 수가 있다.
이를 해결하기위해 FPN을 기반으로 변형된 네트워크가 많이 고안되었다.