계획(로드맵)

Traffic Light(hereinafter referred to as TL)의 종류가 엄청 다양하기 때문에, Bus-only TL을 Detection을 하는데는 한 단계 기술을 거치는 것으로는 충분하지 않다. TL을 검출해내고, Traffic Sign의 글자도 인식해야 한다.

  1. TL Detection

    • class 0 : General TL
      • 2단계로 넘어간다.
    • class 1 : Bus-shaped TL
      • Detection 끝.
    • class 2 : TL with Sign
    • Real-time processing에 적합한 YOLO를 사용할 것으로 예상된다.
  2. Traffic Sign Detection

    • 신호등과 가까운 표지판을 찾아내야한다. 대개 해당 신호등의 위쪽에 있다.
    • 그 표지판에 적힌 글자에 버스 전용, 중앙 차선이 포함되어 있는지 확인해내야한다.
    • 저해상도 이미지의 깨진 글자를 인식해낼수 있어야 한다.
    • 깨진 글자를 해결할 수 있는 기술이 필요하다
      • up-scaling
    • Tesseract OCR, SVM
    • 참고 링크

예상되는 한계점 : Real-Time Image Processing이기 때문에 Input Image의 화질이 좋지 않다.
horizontal TL에 대해서만 고려하고, 검출하는 모델을 만들었기 때문에 vertical TL에 대한 성능은 확신할 수 없다.

'Project > Bus Traffic Light Detection' 카테고리의 다른 글

Presentation(1)  (0) 2019.05.20
19/04/15 진행 상황  (0) 2019.04.16
19/04/10 진행 상황  (0) 2019.04.10
19/04/01 진행 상황  (0) 2019.04.01
Project proposal  (0) 2019.03.28

YOLO Build on Windows

  • CUDA, cuDNN, OpenCV, VS 2017을 사용합니다.
  • AlexyAB의 darknet을 이용했습니다.

빌드하기 전 준비사항

  • VS 2017은 설치되어있다는 가정하에 진행하겠습니다.

    • Visual Studio Installer에서 데스크톱용 VC++ 2015.3 v14.00(v140) 도구집합 먼저 설치 하시고 진행하셔야 합니다(CUDA 설치 전에 해야하기 때문).
      Image
  • 위 github에서 repository를 Downlaoad 받습니다. 이 경로를 darknet이라고 부르겠습니다.

  • CUDA와 cuDNN을 설치하셔야 하는데, 버전을 기억해두셔야 합니다.

    • CUDA : https://developer.nvidia.com/cuda-downloads
      • Visual Studio Integration 체크 해서 설치해야합니다.
        Image
      • 자신의 CUDA 버전에 맞는 cuDNN을 다운받고 압축을 푼 후 CUDA가 설치된 경로에 붙여넣기 하면 됩니다. CUDA와 똑같은 경로를 cudnn이라는 이름으로 환경변수 등록까지 마쳐야합니다.
  • 다음으로 OpenCV를 다운받습니다.

    • OpenCV Download 링크에서 들어가서 다운받습니다.
    • 저는 2.4.13.6 버전을 다운받았습니다.
  • OpenCV를 설치한 경로는 환경변수에 아래와 같이 등록해줘야합니다.

    • 제 opencv 경로는 C:\opencv\opencv2.4.13.6\으로 시작합니다.

빌드

  • darknet\build\darknet\darknet.sln을 실행합니다.
  • 먼저 상단의 메뉴에서 Release, x64로 바꿔줍니다.
    Image
  • 프로젝트 속성 - C/C++ - 일반 - 추가 포함 디렉터리에서 opencv 경로를 자신의 경로에 맞게 수정합니다.

Image

  • 프로젝트 속성 - 링커 - 일반 - 추가 라이브러리 디렉터리에서 opencv 경로를 수정합니다.

Image

  • 빌드 종속성을 자신의 CUDA 버전에 맞게 수정합니다.

Image

Image

  • 빌드(F7)를 누르면 끝입니다!

Darkflow 설치 및 사용법 on Windows

  • 이 github 페이지를 참조했습니다.

  • Anaconda, tensorflow-gpu, opencv3, numpy가 설치되어 있는 환경에서 진행했습니다.

  • Python 3.5가 권장된다고 합니다. 저는 3.6.5에서 진행했습니다.

  • 선택사항으로 가상 환경(virtualenv, conda, pipenv)에서 진행해도 된다고 하는데, 저는 아직 가상 환경에 대한 체감이 없어서 그냥 base env에서 진행했습니다.

사전 준비

  • pip3 install --upgrade tensorflow
  • pip3 install cython
  • pip3 install opencv-python

repo Download

  • Darkflow github Page에서 repo를 다운로드 받고 그 디렉토리에서 다음을 실행합니다.
    • python setup.py build_ext --inplace
    • python flow --h
    • Microsoft Visual C++ 14.0 is required error가 생기는 경우 이 곳을 참조해서 해보세요. 저는 해당되지 않아서 자세히는 잘 모르겠습니다.

시작 방법

  • 3가지 방법이 있다.
    • python setup.py build_ext --inplace
      • 이 방법을 쓰면 ./flow로 명령을 실행해야한다고 한다.
    • pip install -e .
    • pip install .
  • 나는 세번째가 제일 짧아서 세번째걸로 했다. 별 문제 없이 됐다.

학습 방법(Training on your own dataset)

  • cfg 디렉토리에서 cfg 파일을 복사해서 원하는 대로 이름을 변경한다.(Original cfg를 건드리지 않는것이 좋다.)

  • 복사한 cfg 파일의 [region] 부분 밑에 class 수를 원하는대로 변경한다. 나는 일단 신호등 하나만 할거라서 1로 했다.

    [region]
    anchors =  0.57273, 0.677385, 1.87446, 2.06253, 3.33843, 5.47434, 7.88282, 3.52778, 9.77052, 9.16828
    bias_match=1
    classes=1
    coords=4
    num=5
    softmax=1
    jitter=.3
    rescore=1
  • 바로 위의 [convolutional] 부분을 수정해야한다. filters 값을 num * (class + 5)로 한다. 나는 num이 5고 class는 1이어서 5 * (1 + 5) = 30으로 바꿨다.

    [convolutional]
    size=1
    stride=1
    pad=1
    filters=30
    activation=linear
  • labels.txt에 class명을 적는다.

    traffic light
  • Train Command 예시

    • bash
      • python flow --model cfg/my.cfg --train --load yolo.weights --dataset data/train_traffic_light --annotation data/annotations --gpu 1.0
    • cmd
      • python flow --model cfg\my.cfg --train --load yolo.weights --dataset data\train_traffic_light --annotation data\annotations --gpu 1.0
  • Argument

    • --train : 학습 시킬때
    • --load : weights 파일 Load, -1을 주면 ckpt/checkpoint에서 가장 최근걸 불러온다.
    • --trainer adam : Adam optimizer로 완전히 새로운 weights 파일로 시작.
    • --model : cfg 파일 경로
    • --annotation : xml 파일 경로
    • --dataset : 학습 image 파일 경로
    • --demo : video test시 video 파일 경로 입력
    • --imgdir : image test시 image 파일 경로 입력
  • defaults.py

    • 수정할 수 있는 부분이 많다. 추후 업데이트.

YOLO Annotation (txt) to VOC Annotation (xml)

YOLO 학습때 사용한 annotation 파일은 txt 형식이고, 간결하다.

darkflow로 학습하려니 annotation 형식이 달라서 학습이 되지 않았다.

xml 형식이 필요하대서 찾아보니까 txt에 비해 많이 복잡했다.

하나하나 다시 박스 처리를 해주는건 미친짓이기에 txt 파일을 xml로 변환했다.

나와 같은 어려움을 겪는 사람이 있을게 분명하기에 코드를 공유해봅니다..

convert.py

from lxml import etree
from PIL import Image
import csv
import os

# fw is txt file that composed train image file path

IMG_PATH = "D:/__Project__/darkflow-master/data/train_traffic_light"
fw = os.listdir(IMG_PATH)
# path of save xml file
save_path = 'D:/__Project__/darkflow-master/data/annotations/'

# txt_folder is txt file root that using darknet rectbox
txt_folder = 'D:/__Project__/darkflow-master/data/train_traffic_light_TXT'

# edit ypur label set
labels = ['traffic light']


def csvread(fn):
    with open(fn, 'r') as csvfile:
        list_arr = []
        reader = csv.reader(csvfile, delimiter=' ')

        for row in reader:
            list_arr.append(row)
    return list_arr


def convert_label(txt_file):
    if((txt_file[0]) == str(0)):
        label = 'traffic light'

    return label

# core code = convert the yolo txt file to the x_min,x_max...


def extract_coor(txt_file, img_width, img_height):
    x_rect_mid = float(txt_file[1])
    y_rect_mid = float(txt_file[2])
    width_rect = float(txt_file[3])
    height_rect = float(txt_file[4])

    x_min_rect = ((2 * x_rect_mid * img_width) - (width_rect * img_width)) / 2
    x_max_rect = ((2 * x_rect_mid * img_width) + (width_rect * img_width)) / 2
    y_min_rect = ((2 * y_rect_mid * img_height) -
                  (height_rect * img_height)) / 2
    y_max_rect = ((2 * y_rect_mid * img_height) +
                  (height_rect * img_height)) / 2

    return x_min_rect, x_max_rect, y_min_rect, y_max_rect


for line in fw:
    root = etree.Element("annotation")

    # try debug to check your path
    img_style = IMG_PATH.split('/')[-1]
    img_name = line
    image_info = IMG_PATH + "/" + line
    img_txt_root = txt_folder + "/" + line[:-4]
    txt = ".txt"

    txt_path = img_txt_root + txt
    txt_file = csvread(txt_path)
    ######################################

    # read the image  information
    img_size = Image.open(image_info).size

    img_width = img_size[0]
    img_height = img_size[1]
    img_depth = Image.open(image_info).layers
    ######################################

    folder = etree.Element("folder")
    folder.text = "%s" % (img_style)

    filename = etree.Element("filename")
    filename.text = "%s" % (img_name)

    path = etree.Element("path")
    path.text = "%s" % (IMG_PATH)

    source = etree.Element("source")
    ##################source - element##################
    source_database = etree.SubElement(source, "database")
    source_database.text = "Unknown"
    ####################################################

    size = etree.Element("size")
    ####################size - element##################
    image_width = etree.SubElement(size, "width")
    image_width.text = "%d" % (img_width)

    image_height = etree.SubElement(size, "height")
    image_height.text = "%d" % (img_height)

    image_depth = etree.SubElement(size, "depth")
    image_depth.text = "%d" % (img_depth)
    ####################################################

    segmented = etree.Element("segmented")
    segmented.text = "0"

    root.append(folder)
    root.append(filename)
    root.append(path)
    root.append(source)
    root.append(size)
    root.append(segmented)

    for ii in range(len(txt_file)):

        label = convert_label(txt_file[ii][0])
        x_min_rect, x_max_rect, y_min_rect, y_max_rect = extract_coor(
            txt_file[ii], img_width, img_height)

        object = etree.Element("object")
        ####################object - element##################
        name = etree.SubElement(object, "name")
        name.text = "%s" % (label)

        pose = etree.SubElement(object, "pose")
        pose.text = "Unspecified"

        truncated = etree.SubElement(object, "truncated")
        truncated.text = "0"

        difficult = etree.SubElement(object, "difficult")
        difficult.text = "0"

        bndbox = etree.SubElement(object, "bndbox")
        #####sub_sub########
        xmin = etree.SubElement(bndbox, "xmin")
        xmin.text = "%d" % (x_min_rect)
        ymin = etree.SubElement(bndbox, "ymin")
        ymin.text = "%d" % (y_min_rect)
        xmax = etree.SubElement(bndbox, "xmax")
        xmax.text = "%d" % (x_max_rect)
        ymax = etree.SubElement(bndbox, "ymax")
        ymax.text = "%d" % (y_max_rect)
        #####sub_sub########

        root.append(object)
        ####################################################

    file_output = etree.tostring(root, pretty_print=True, encoding='UTF-8')
    # print(file_output.decode('utf-8'))
    ff = open('%s%s.xml' % (save_path, img_name[:-4]), 'w', encoding="utf-8")
    ff.write(file_output.decode('utf-8'))

AlexyAB의 YOLO github page 내용을 정리했습니다. 자세한 사항은 들어가셔서 보실 수 있습니다.

YOLO Training on Windows.

명령어 사용법

  • -ext_output : output coordinate of objects

  • -save_labels < data/test.txt : test.txt에 적힌 경로의 이미지에 label 적힌 txt 저장.(Marking 좌표 저장)

    • ex) darknet.exe detector test .data .cfg .weights -dont_show -ext_output -save_labels < data/train.txt
  • 이미지 예시

    • darknet.exe detector test datafile.data cfgfile.cfg weightsfile.weights -i 0(-thresh 0.25) (output.jpg -ext_output)
  • 동영상 예시

    • darknet.exe detector demo datafile.data cfgfile.cfg weightsfile.weights test.mp4 -i 0 (-out_filename output.avi)
  • net-videocam

    • darknet.exe detector demo datafile.data cfgfile.cfg weightsfile.weights http://192.168.0.80:8080/video?dummy=param.mjpg -i 0
  • WebCamera

    • darknet.exe detector demo datafile.data cfgfile.cfg weightsfile.weights -c 0
  • darknet.exe detector demo datafile.data cfgfile.cfg weightsfile.weights -dont_show -ext_output < data/train.txt > result.txt

  • webcam에 관한 내용

  1. Download for Android phone mjpeg-stream soft: IP Webcam / Smart WebCam

  2. Connect your Android phone to computer by WiFi (through a WiFi-router) or USB

  3. Start Smart WebCam on your phone

  4. Replace the address below, on shown in the phone application (Smart WebCam) and launch:

  • 194 MB COCO-model: darknet.exe detector demo data/coco.data yolo.cfg yolo.weights http://192.168.0.80:8080/video?dummy=param.mjpg -i 0
  • 194 MB VOC-model: darknet.exe detector demo data/voc.data yolo-voc.cfg yolo-voc.weights http://192.168.0.80:8080/video?dummy=param.mjpg -i 0

학습하는 법

  1. yolov3.cfg를 복사해서 yolo-obj.cfg 이름으로 바꾼 뒤 다음 내용으로 수정한다.

    • batch=64
    • subdivision=8
    • Line 610, 696, 783에서 class=N(N은 내 클래스 수)
    • Line 603, 689, 776에서 filters=(N+5)x3
  2. obj.names 파일을 만든 후 build\darkent\x64\data\에 저장한다.

    • 내용은 내 클래스 이름들을 각 줄에 적는다.
  3. obj.data 파일을 build\darknet\x64\data\에 다음과 같은 내용을 입력후 저장한다.

    classes = 1 train = data/train.txt valid = data/test.txt names = data/obj.names backup = backup/

  4. 학습시킬 이미지 파일들을 build\darknet\x64\data\obj\에 저장한다.

  5. 이미지 파일들은 Yolo_mark를 통해 bounding box marking을 해줘야한다.

  6. train.txt 파일을 build\darknet\x64\data\에 넣는다. 내용은 이미지 파일의 상대경로를 적어주어야한다.

    data/obj/img1.jpg data/obj/img2.jpg data/obj/img3.jpg ...

  7. 미리 학습된 weights를 다운로드 받는다.

  8. 학습을 시작한다.

    darknet.exe detector train mydata.data mycfg.cfg darknet53.conv.74

  9. 학습이 끝나면 build\darknet\x64\backup\에서 yolo-obj_final.weights를 얻을 수 있다. 또 backup\에 100번째 반복마다 저장이 된다.

  10. 주의사항

    • cfg 파일에 width와 height는 32로 나누어 떨어지는 수가 들어가야 한다.
    • 학습 후 사용 방법 darknet.exe detector test data/obj.data yolo-obj.cfg yolo-obj_8000.weights
    • Out of memory 오류가 발생할 경우 cfg 파일에서 subdivision16, 3264로 고친다.

학습을 멈추는 시점

보통 class 마다 2000번의 반복정도가 적당하다. 구체적인 학습 중단 시점은 아래와 같다.

  1. 학습 도중, 0.XXXXXXX avg가 감소하지 않는다면 중단해야한다.

    여러번을 반복해도 avg loss가 감소하지 않으면 중단해야한다.

  2. 학습을 중단시키고, darknet\build\darknet\x64\backup 폴더에서 .weights 파일을 얻을 수 있는데, 그 중 가장 좋은 것을 골라야한다.

    예를 들어 9000번의 반복을 했을때, 가장 좋은 것(Overfitting이 덜한 것)은 7000, 8000번째에 있을 수 있다. (Early Stopping Point로부터 얻어낸다.)

Image

2.1. Early Stopping Point로부터 weights를 얻어내려면 obj.data에서 validation dataset을 명시해줘야한다. valid 경로를 지정해준다. validation 이미지가 따로 없다면, train과 같은 파일을 사용한다.

2.2 아래 명령어로 어떤 weights가 더 좋은 성능을 보이는지 알 수 있다.

darknet.exe detector map data/obj.data yolo-obj.cfg backup\\yolo-obj\_7000.weights

darknet.exe detector map data/obj.data yolo-obj.cfg backup\\yolo-obj\_8000.weights

darknet.exe detector map data/obj.data yolo-obj.cfg backup\\yolo-obj\_9000.weights

  • -map flag를 통해 train 시킬수도 있다.

darknet.exe detector train data/obj.data yolo-obj.cfg darknet53.conv.74 -map

학습 효과 올리기

  • 학습 전
    • cfg 파일 맨 아래 random=1로 수정. (다른 해상도에 대해 정확도를 높여준다.)
    • 작은 객체 탐지를 위해서 cfg 파일 Line 717 stride=4, Line 720 layers=-1,11로 수정.
    • 좌우 구별 감지를 원하면 Line 17에서 flip=0 입력.
    • 빠른 학습을 위해서 Line 548 stopbackward=1 입력.
    • anchors 크기 재계산해서 더 정확하게 계산하기 : darknet.exe detector calc_anchors data/obj.data -num_of_clusters 9 -width 416 -height 416
  • 학습 후
    • cfg 파일에서 heightwidth608 혹은 832로 수정.
    • Out of Memory 오류가 생기면 subdivision16, 32, 64로 수정.

이 페이지를 번역했습니다

Single Shot Detectors

Faster R-CNN은 전용 Region Proposal 네트워크에 이어 Classifier가 있다.

Region-based Detector는 정확하지만 Cost가 있다.

Faster R-CNN은 PASCAL VOC 2007 테스트 세트를 7 FPS로 처리한다.

R-FCN과 같이 연구자들은 각 ROI의 작업량을 줄여 프로세스를 간소화하고 있다.

feature_maps = process(image)
ROIs = region_proposal(feature_maps)
for ROI in ROIs
    patch = roi_align(feature_maps, ROI)
    results = detector2(patch)    
    # Reduce the amount of work here!

대안으로 우리는 별도의 Region Proposal 단계가 필요한가? Boundary boxes 및 Classes를 Feature Map에서 한번에 직접 추출할 수 있습니까?

feature_maps = process(image)
results = detector3(feature_maps) 
# No more separate step for ROIs

슬라이딩 윈도우 감지기를 다시 살펴보겠습니다.

Feature Map 위로 윈도우를 밀어 물체를 감지할 수 있다.

서로 다른 개체 유형에 대해 서로 다른 윈도우 모양을 사용한다.

이전 슬라이딩 윈도우의 치명적인 오점은 창을 최종 Boundary box로 사용한다는 것이다.

그 부분에서 대부분의 물체를 cover하기 위해 너무 많은 모양이 필요하다.

좀 더 효과적인 해결책은 윈도우를 초기 추측으로 정하는 것이다.

그러면 현재 슬라이딩 윈도우로부터 class와 boundary box를 동시에 예측하는 탐지기를 갖는다.

Image

  • 슬라이딩 윈도우에 상대적인 예측을 한다.

이 개념은 R-CNN의 anchor와 매우 유사하다.

단, Single Shot Detector는 Boundary box와 class를 동시에 예측한다.

간단히 요약해보자. 예를 들어 8x8 Feature Map이 있으며 각 위치에서 K 예측을 한다. 즉 8x8xK 예측을 한다.

Image

각각의 위치마다 K개의 anchors(anchor: 고정된 초기의 추측 boundary box)가 있다. 우리는 anchors를 신중히 결정하고 모든 장소에 같은 anchor 모양들을 사용한다.

Image

  • location마다 4개의 예측을 하기 위해 4개의 anchor를 사용한다.

여기에 각각 하나의 특정한 anchor와 관련된 4개의 예측(파란색)과 4개의 anchor(초록색)가 있다.

Image

  • anchor에 관련된 4개의 예측.

Faster R-CNN에서 우리는 5개의 매개변수를 예측하기 위해 하나의 Convolution filter를 사용한다.(anchor와 관련된 예측된 box에 대한 4개의 매개변수와 objectness confidence에 대한 1개의 매개변수)

따라서 3x3xDx5 Conv fitler는 8x8xD에서 8x8x5까지 Feature map을 변환한다.

Single Shot Detector에서 Conv filter는 분류에 대한 C 클래스의 확률도 예측한다.(클래스당 1개)

따라서 Feature map을 3x3xDx25 Conv filter를 적용하여 C=20일때 8x8xD에서 8x8x25으로 변환한다.

Image

  • 각 위치에서 k개의 예측에 각각 25개의 매개변수가 있다.

Single Shot Detector는 보통 실시간 처리 속도로 정확성을 교환한다.

또한 너무 가깝거나 너무 작은 물체를 감지하는데 문제가 있는 경향이 있다.

아래 그림의 경우 왼쪽 하단에 9개의 산타가 있지만 SSD는 5개만 감지합니다.

Image

SSD

SSD는 VGG19 네트워크를 Feature 추출기로 사용하는 Single Shot Detector이다.(Faster R-CNN의 CNN과 동일)

그런 다음 나중에 사용자 정의 Conv Layer(청색)를 나중에 추가하고 Conv filter(녹색)을 사용하여 예측한다.

Image

  • 분류와 위치 모두에 대한 Single Shot 예측

그러나 Conv Layer는 공간 차원과 해상도를 줄인다.

따라서 위의 모델은 대형 객체만 탐지할 수 있다.

이를 해결하기 위해 우리는 Multiple Feature map에서 독립적인 개체 탐지를 한다.

Image

  • 탐지를 위해 multi-scale Feature map을 사용한다.

다음은 Feature map의 크기를 보여주는 다이어그램이다.

Image

SSD는 개체를 감지하기 위해 Conv 네트워크에 이미 있는 레이어를 사용한다.

다이어그램을 scale에 가깝게 다시 그리면 공간 해상도가 크게 떨어졌고, 저해상도에서 감지하기에는 너무 어려운 작은 물체를 찾는 기회를 놓치고 있다는 것을 알아야 한다.

이런 문제가 있으면 입력 이미지의 해상도를 높여야 한다.

Image

YOLO

YOLO는 DarkNet을 사용하여 Feature 감지를 수행한 다음 Conv Layer를 만든다.

Image

그러나 Multi-scale feature map을 사용하여 독립적으로 탐지하지는 않는다.

대신 부분적으로 평평하게 만들고(flatten) 다른 저해상도 map과 연결한다.

예를 들어 YOLO는 28x28x512 Layer를 14x14x2048로 reshape한다.

그런 다음 14x14x1024 Feature map과 연결된다.

그 후에 YOLO는 새로운 14x14x3072 Layer에 Conv filter를 적용하여 예측한다.

YOLO(v2)는 첫번째 release의 경우 mAP를 63.4에서 78.6까지 구현을 향상시켜줬다.

YOLO9000은 9000개의 다른 범주의 개체를 탐지할 수 있다.

Image

다음은 YOLO 논문에서 보고한 다양한 detector에 대한 mAP와 FPS 비교이다.

YOLOv2는 다른 입력 이미지 해상도를 가질 수 있다.

해상도가 낮은 입력 이미지는 더 높은 FPS를 갖지만 mAP는 더 낮다.

Image

YOLOv3

YOLOv3는 Feature 추출을 위해 더 복잡한 백본으로 변경된다.

Darknet-53은 주로 ResNet의 잔여 네트워크와 같이 건너뛰는 연결을 사용하는 3x31x1 필터로 구성된다.

Darknet-53은 ResNet-152보다 BFLOP(Billion Floating Point OPerations)이 적지만 2배 빠른 속도로 같은 분류 정확도를 갖는다.

Image

YOLOv3는 작은 피사체를 더 잘 감지하기 위해 Feature Pyramid를 추가했다.

서로 다른 감지기에 대한 정확도와 속도간의 tradeoff가 있다.

Image

FPN(Feature Pyramid Networks)

특히 작은 Object에서 다른 scale일때 object를 탐지하는 것이 어렵다.

FPN은 정확성과 속도를 향상시키기 위해 피라미드 개념으로 설계된 Feature 추출기이다.

Faster R-CNN과 같은 감지기의 Feature 추출기를 대체하고 고품질 Feature map pyramid를 생성한다.

Data Flow

Image

FPN은 Bottom-up과 Top-down 경로로 구성된다. Bottom-up은 Feature 추출을 위한 일반적인 Conv Network이다. 올라갈수록 공간 해상도는 떨어진다. 더 높은 수준의 구조가 감지되면 각 계층의 semantic value가 증가한다.

Image

SSD는 여러 Feature map에서 탐지한다.

그러나 Object detection에 대해서는 bottom layers는 선택되지 않는다.

그것들은 해상도가 높지만 속도가 느려지기 때문에 의미적 가치가 높지 않다.

따라서 SSD는 상위 계층만 감지하기 때문에 작은 개체에 대해서는 성능이 훨씬 떨어진다.

Image

FPN은 Semantic rich layer로부터 더 높은 해상도를 생성하는 Top-down 방식을 제공한다.

Image

재구성된 레이어는 큰 의미가 있지만 Object의 위치는 모든 다운샘플링 및 업샘플링 후에 정확하지 않다.

재구성된 레이어와 해당 feature map 사이에 측면 연결을 추가하여 detector가 위치를 더 잘 예측할수 있게 도와준다.

Image

다음은 bottom-up 및 top-down 경로에 대한 세부 다이어그램이다. P2, P3, P4, P5는 물체 감지를 위한 feature map의 피라미드이다.

Image

FPN with RPN

FPN은 자체적으로 Object Detector가 아니다.

+ Recent posts