【Detection】FCOS - Fully Convolutional One-Stage Object Detection
- 논문 : FCOS: Fully Convolutional One-Stage Object Detection
- 분류 : Object Detection
- 저자 : Zhi Tian Chunhua Shen∗ Hao Chen Tong He
- 읽는 배경 : 교수님 수업의 Programming Assignment 대비하기
- 목차
- Paper Review
- Code Review
- Github link : https://github.com/tianzhi0549/FCOS
FCOS
1. Conclusion, Abstract, Introduction
- anchor boxes와 관련된 hyper-parameter와 학습 중 Matching 및 IOU 계산에 대한 연산들을 모두 제거했다. Hyper-parametor를 제거함으로써 heuristics한 many trick들을 모두 없앴다. 그리고 Anchor와의 관계 연산을 하지 않으므로 Faster Training이 가능하다.
- Sementic Segmentation 처럼. per-pixel prediction fashion 을 수행한다.
- 우리의 FCOS를 two-stage Detector에서 RPN으로 사용해도 좋은 결과를 가져다 준다. RPN 또한 Anchor-based 인 것을 기억하자.
- NMS 를 사용한 후처리 과정은 필요하다. FCOS with ResNeXt-64x4d-101에서 SOTA 성능 44.7% AP를 획득했다. 우리 모델은 simple and fast 하다!
- 원래 Class confidence만 예측하는 head만 있으면, low-quality predicted bounding boxes 들이 너무 많이 생긴다. 그래서 우리는 해당 1x1 pixel 점이 객체의 center와 얼마나 떨어져있냐를 수치로 가지고 있는 center-ness 값이 추출되도록 head를 추가했다.
2. Our Approach
- Anchor라는 개념없이, 각 Pyramid Feature Level의 한 1x1 픽셀 공간이 가지면 괜찮을 Class와, 가장 적절히 일치하는 Instance에 대한 the box offset (t, b, r, l) 을 검출한다.
- 헷갈리면, 이전 포스트 FSAF Architecture에서 Anchor based 부분까지 완전히 제거해 버렸다고 생각하면 좋다.
3.1 Fully Convolutional One-Stage Object Detector
- 우선 전체 architecture와 필기 꼭 참고하기. 그리고 아래의 수식들 하나하나 읽기.
3.2. Multi-level Prediction with FPN for FCOS
- FPN을 사용해서 Recall을 증가시키고, Overlapped bounding box의 ambiguity (다중 객체가 겹치는 해당 Feature map pixel에서 어떤 BB를 예측할 것인가?) 를 해결했다.
- FPN으로 적용되는 stride값은 P3, P4, P5, P6 and P7 에 대해서, 각각 8, 16, 32, 64 and 128 이다. 이 값은 위의 S 로 동작한다.
- Anchor-based detector에서 각각의 P_l 은 자신만의 Anchor size를 가짐으로써, 각 Level에서 검출하는 Instance의 크기가 서로 다른다. 여기서도 이런 개념을 추가했다. the range of bounding box regression 를 할당했다. 그 과정은 이와 같다.
- (1) 우선 모든 Feature level에 t* ( l* , t* , r* , b* ) 를 연산해놓는다. (Image에 대응하는 (l, t, r, b)를 S로 나눠주면 된다.)
- (2) 만약 max( l* , t* , r* , b* ) > m_i or max( l* , t* , r* , b* )< m_(i−1) 즉 일정 범위를 벗어나면 negative sample이라고 파악하고, bounding box regression 학습에 사용하지 않는다.
- (3) 여기서 m2, m3, m4, m5, m6 and m7 는 각각 0, 64, 128, 256, 512 and ∞ 으로 설정해 사용했다.
- 이 과정을 통해서, Inference을 하는 동안에는 각각의 Pyramid Feature level들은 자신이 예측해야하는 적절한 크기의 Instance를 우선적으로 검출한다.
- (필기참조) 하나의 Feature level Picel이 1개 이상의 GT BB를 할당하고 있다면, 단순하게 더 작은 area를 가진 GT BB를 Ground True로 설정해 예측하도록 한다.
- 그리고 단순하게 Shared Heads Between Feature Levels 를 사용한다. 즉 위의 보라색 head는 모두 파라메터를 공유한다. parameter-efficient (파라메터가 효율적으로 적은) 모델을 만들고 성능도 높혀준다. 하지만 이런 작업이 각 Level이 찾으려고 하는 Instance의 크기가 다른 것을 고려할 때 그리 합리적인 방법은 아닐 수 있습니다.
- (필기참조) 그래서 우리는 그냥 exp(x)를 사용하는 것 대신에, exp(s_i * x) 를 사용했다. (s_i 는 trainable scalar) 알아서 각 Level에 필요한 s_i 값을 주어줄 것이라고 예측했다.
3.3. Center-ness for FCOS
- (위 그림 참조) 그냥 Class Score만을 사용해서 NMS를 적용하니, a lot of low-quality predicted bounding boxes 가 추출되는 것을 확인할 수 있었다. 그래서 Center-ness를 예측하는 branch를 새롭게 만들었다.
- 그 branch에서는 normalized distance를 의미하는“center-ness”를 예측한다.
- When testing, 위의 Architecture 그림 처럼, center-ness와 classification score를 곱해서 최종 Confidence로 사용한다. 그리고 NMS를 적용한다.
- the center-ness를 사용하는 것 대신에, central portion (FSAF에서 Efficient Region (GT instance BB의 0.2 공간))을 사용하는 방법도 있다. 하지만 이것 조차 extra hyper-parameter를 사용하는 방법이라는 것에 명심해야한다.
- FCOS_PLUS 에서는 위의 2가지 방법을 융합해서 성능을 높혔다고 한다.
4. Experiments
- Training Details
- ResNet-50
- the same hyper-parameters with RetinaNet
- SGD, Weight decay and momentum are set as 0.0001 and 0.9
- initial learning rate being 0.01, batch of 16 images, 10 at iteration 60K and 80K.
- the input images are resized being 800.
- Inference Details
- the same post-processing hyperparameters of RetinaNe
- 4.1. Ablation Study
- (FPN) Multi-level Prediction 을 사용함으로써, ‘Best Possible Recalls 획득’ 그리고 ‘Ambiguous Samples 제거’ 를 할 수 있다.
- Best Possible Recalls 은 다음과 같이 정의할 수 있다. 위의 파란 필기도 참조. the ratio of the number of ground-truth boxes, a detector can recall at the most, divided by all ground-truth boxes.
- Ambiguous Samples
- 특히 위의 사진과 같이, 객체가 overlapping 될때 Ambiguous sampling (보통 FPN에서는 ‘다중’ 예측을 통한 후 NMS를 한다. 이때 ‘특정 한번’의 예측을 할 때, 보통 ‘특정 위치’에서 1개의 객체인식만 하면 되는데, 객체가 겹치는 경우에는, 이 ‘특정 위치’에서 어떤 객체를 우선적으로 예측해야하는지 애매모호한 경우가 발생한다. 이를 Ambiguous sampling 이라고 말하는 것 같다. )이 발생한다.
- 논문에는 정확한 정의와 계산 수식을 제시하고 있지 않다. 그저, 논문에서 말하는 몇가지 내용에 대해서 아래에 정리한다. 아래의 내용 말고 추가적인 내용은 없다. 왜 있는지? 무슨 소리를 하고 싶은건지 이해가 힘들다.
- Table2를 보면, FPN을 사용함으로써 Ambiguous sampling이 줄어든 것을 확인할 수 있다. 이 이유는 다음과 같다. 객체가 overlapping 하게 되는 보통의 경우에는 두 객체의 크기가 상대적으로 다르다. 따라서 FPN의 다른 Level에서 객체가 각각 검출되면 되기 때문에, Ambiguous sampling 의 발생 빈도를 상당히 줄일 수 있다.
- Moreover, 저자가 말하기로 같은 Class의 객체가 겹치면, 상대적으로 overlapping으로 인한 Ambiguous sampling은 적다고 한다.(어차피 비슷한 Feature map이 겹치므로) 반대로 겹치는 객체의 Class가 다르면, overlapping으로 인한 Ambiguous sampling이 크게 발생한다. (다른 Featere map이 서로 엃겨 섞이게 되므로. classifier는 당항할 것이다.)
- (FPN) Multi-level Prediction 을 사용함으로써, ‘Best Possible Recalls 획득’ 그리고 ‘Ambiguous Samples 제거’ 를 할 수 있다.
- 4.2. With or Without Center-ness / FCOS vs. Anchor-based Detectors / Comparison with State-of-the-art Detectors
FCOS code
Github link : [https://github.com/tianzhi0549/FCOS]
- 공부순서
- Readmd.md 읽기
- 패키지 전체 흐름 파악하기
- 핵심 코드 살펴보기
- demo/fcos_demo.py
- python tools/test_net.py
- train : python -m torch.distributed.launch
위의 5번까지 살짝 1시간 정도 본 결과 느낀점
- 아래의 기반 코드를 완전히 뜯어 부셔버리고, fcos코드를 보면 좋을 듯 하다. 하지만 시간이 없다면, 핵심 코드만 봐도 좋겠다. 우선 지금은 공부할 때가 아니다. 공부할 때 라는 생각이 들 때, 바로 공부해보자. 아래의 내용들을 참고하면 좋은 공부의 시작이 될 수 있다.
- 기반 코드 : https://github.com/facebookresearch/maskrcnn-benchmark
- 논문 내용 이해에 도움을 주는 핵심 코드 : https://github.com/tianzhi0549/FCOS/blob/master/fcos_core/modeling/rpn/inference.py
- 내가 만약 신경망을 처음부터 구성한다면, 심플하게 만들기 위해 도움 받을 수 있을 코드 : https://github.com/yhenon/pytorch-retinanet/tree/master/retinanet
- Test를 하던 Training을 하던 이것을 시작으로 Model을 만들었다.
그리고 전체적으로 살펴 본 결과, 코드 제작자가 직접 손수 손본 곳은 여기가 전부 인듯 하다. (처음에는 못 찾았는데, 검색으로 centerness를 검색함으로써 찾을 수 있었다.)
특히 /modeling/rpn/fcos/fcos.py에서 아래의 코드를 유심히 보자.
class FCOSModule(torch.nn.Module): """ Module for FCOS computation. Takes feature maps from the backbone and FCOS outputs and losses. Only Test on FPN now. """ def __init__(self, cfg, in_channels): # /modeling/rpn/fcos/fcos.py 에 정의되어 있다. head = FCOSHead(cfg, in_channels) # /modeling/rpn/fcos/inference.py 에 정의되어 있다. 이 객체는 딱 Test할 때만 사용하나 보다. box_selector_test = make_fcos_postprocessor(cfg)