728x90
반응형

 

neck => fpn을 위해서 만듬

- backbone에서 size는 줄어는데 depth는 늘어나니까 갈수록 추상화된 정보들이 남음

neck에서 다양한 크기의 feature map을 다시 활용, 풍부하게 뽑아보자

 

feature pyramid network

feature pyramid network

mapping으로 정보를 전달해줌 => single shot detection

작은 object들을 보다 잘 detect하기 위해 다양한 feature map을 활용

상위 feature map의 추상화된 정보와 하위 feature map의 정보를 효과적으로 적용

반응형
728x90
반응형

Video Object Detection 수행

원본 영상 보기

!wget -O ./data/Jonh_Wick_small.mp4 https://github.com/chulminkw/DLCV/blob/master/data/video/John_Wick_small.mp4?raw=true

VideoCapture와 VideoWriter 설정하기

  • VideoCapture를 이용하여 Video를 frame별로 capture 할 수 있도록 설정
  • VideoCapture의 속성을 이용하여 Video Frame의 크기 및 FPS 설정.
  • VideoWriter를 위한 인코딩 코덱 설정 및 영상 write를 위한 설정
video_input_path = '/content/data/Jonh_Wick_small.mp4'

cap = cv2.VideoCapture(video_input_path)
frame_cnt = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
print('총 Frame 갯수:', frame_cnt)

# 총 Frame 갯수: 58
video_input_path = '/content/data/Jonh_Wick_small.mp4'
video_output_path = './data/John_Wick_small_cv01.mp4'

cap = cv2.VideoCapture(video_input_path)

codec = cv2.VideoWriter_fourcc(*'XVID')

vid_size = (round(cap.get(cv2.CAP_PROP_FRAME_WIDTH)),round(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))) 
vid_fps = cap.get(cv2.CAP_PROP_FPS )
    
vid_writer = cv2.VideoWriter(video_output_path, codec, vid_fps, vid_size) 

frame_cnt = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
print('총 Frame 갯수:', frame_cnt)

# 총 Frame 갯수: 58

총 Frame 별로 iteration 하면서 Object Detection 수행. 개별 frame별로 단일 이미지 Object Detection과 유사

# bounding box의 테두리와 caption 글자색 지정
green_color=(0, 255, 0)
red_color=(0, 0, 255)

while True:

    hasFrame, img_frame = cap.read()
    if not hasFrame:
        print('더 이상 처리할 frame이 없습니다.')
        break

    rows = img_frame.shape[0]
    cols = img_frame.shape[1]
    # 원본 이미지 배열 BGR을 RGB로 변환하여 배열 입력
    cv_net.setInput(cv2.dnn.blobFromImage(img_frame,  swapRB=True, crop=False))
    
    start= time.time()
    # Object Detection 수행하여 결과를 cv_out으로 반환 
    cv_out = cv_net.forward()
    frame_index = 0
    # detected 된 object들을 iteration 하면서 정보 추출
    for detection in cv_out[0,0,:,:]:
        score = float(detection[2])
        class_id = int(detection[1])
        # detected된 object들의 score가 0.5 이상만 추출
        if score > 0.5:
            # detected된 object들은 scale된 기준으로 예측되었으므로 다시 원본 이미지 비율로 계산
            left = detection[3] * cols
            top = detection[4] * rows
            right = detection[5] * cols
            bottom = detection[6] * rows
            # labels_to_names_0딕셔너리로 class_id값을 클래스명으로 변경.
            caption = "{}: {:.4f}".format(labels_to_names_0[class_id], score)
            #print(class_id, caption)
            #cv2.rectangle()은 인자로 들어온 draw_img에 사각형을 그림. 위치 인자는 반드시 정수형.
            cv2.rectangle(img_frame, (int(left), int(top)), (int(right), int(bottom)), color=green_color, thickness=2)
            cv2.putText(img_frame, caption, (int(left), int(top - 5)), cv2.FONT_HERSHEY_SIMPLEX, 0.5, red_color, 1)
    print('Detection 수행 시간:', round(time.time()-start, 2),'초')
    vid_writer.write(img_frame)
# end of while loop

vid_writer.release()
cap.release()

# Detection 수행 시간: 8.54 초
# Detection 수행 시간: 8.34 초
...
# Detection 수행 시간: 8.38 초
# 더 이상 처리할 frame이 없습니다.

video detection 전용 함수 생성.

def do_detected_video(cv_net, input_path, output_path, score_threshold, is_print):
    
    cap = cv2.VideoCapture(input_path)

    codec = cv2.VideoWriter_fourcc(*'XVID')

    vid_size = (round(cap.get(cv2.CAP_PROP_FRAME_WIDTH)),round(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
    vid_fps = cap.get(cv2.CAP_PROP_FPS)

    vid_writer = cv2.VideoWriter(output_path, codec, vid_fps, vid_size) 

    frame_cnt = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
    print('총 Frame 갯수:', frame_cnt)

    green_color=(0, 255, 0)
    red_color=(0, 0, 255)
    while True:
        hasFrame, img_frame = cap.read()
        if not hasFrame:
            print('더 이상 처리할 frame이 없습니다.')
            break
        
        img_frame = get_detected_img(cv_net, img_frame, score_threshold=score_threshold, use_copied_array=False, is_print=is_print)
        
        vid_writer.write(img_frame)
    # end of while loop

    vid_writer.release()
    cap.release()
do_detected_video(cv_net, '/content/data/Jonh_Wick_small.mp4', './data/John_Wick_small_02.mp4', 0.2, False)

# 총 Frame 갯수: 58
# person: 0.9495
# person: 0.2871
# bicycle: 0.3498
# car: 0.9882
# car: 0.9622
# ...
# car: 0.4122
# horse: 0.8085
# tie: 0.3411
# 더 이상 처리할 frame이 없습니다.

 

반응형
728x90
반응형

OpenCV DNN 패키지를 이용하여 Faster R-CNN 기반의 Object Detection 수행

  • Tensorflow 에서 Pretrained 된 모델 파일을 OpenCV에서 로드하여 이미지와 영상에 대한 Object Detection 수행.

입력 이미지로 사용될 이미지 다운로드/보기

!mkdir /content/data
!wget -O ./data/beatles01.jpg https://raw.githubusercontent.com/chulminkw/DLCV/master/data/image/beatles01.jpg
import cv2
import matplotlib.pyplot as plt
%matplotlib inline

img = cv2.imread('./data/beatles01.jpg')
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

print('image shape:', img.shape)
plt.figure(figsize=(12, 12))
plt.imshow(img_rgb)

Tensorflow에서 Pretrained 된 Inference모델(Frozen graph)와 환경파일을 다운로드 받은 후 이를 이용해 OpenCV에서 Inference 모델 생성

!mkdir ./pretrained
!wget -O ./pretrained/faster_rcnn_resnet50_coco_2018_01_28.tar.gz http://download.tensorflow.org/models/object_detection/faster_rcnn_resnet50_coco_2018_01_28.tar.gz
!wget -O ./pretrained/config_graph.pbtxt https://raw.githubusercontent.com/opencv/opencv_extra/master/testdata/dnn/faster_rcnn_resnet50_coco_2018_01_28.pbtxt
!tar -xvf ./pretrained/faster*.tar.gz -C ./pretrained
!pwd
!ls -lia ./pretrained/faster_rcnn_resnet50_coco_2018_01_28

dnn에서 readNetFromTensorflow()로 tensorflow inference 모델을 로딩

cv_net = cv2.dnn.readNetFromTensorflow('./pretrained/faster_rcnn_resnet50_coco_2018_01_28/frozen_inference_graph.pb', 
                                     './pretrained/config_graph.pbtxt')

coco 데이터 세트의 클래스id별 클래스name mapping.

# OpenCV Yolo용 
labels_to_names_seq = {0:'person',1:'bicycle',2:'car',3:'motorbike',4:'aeroplane',5:'bus',6:'train',7:'truck',8:'boat',9:'traffic light',10:'fire hydrant',
                        11:'stop sign',12:'parking meter',13:'bench',14:'bird',15:'cat',16:'dog',17:'horse',18:'sheep',19:'cow',20:'elephant',
                        21:'bear',22:'zebra',23:'giraffe',24:'backpack',25:'umbrella',26:'handbag',27:'tie',28:'suitcase',29:'frisbee',30:'skis',
                        31:'snowboard',32:'sports ball',33:'kite',34:'baseball bat',35:'baseball glove',36:'skateboard',37:'surfboard',38:'tennis racket',39:'bottle',40:'wine glass',
                        41:'cup',42:'fork',43:'knife',44:'spoon',45:'bowl',46:'banana',47:'apple',48:'sandwich',49:'orange',50:'broccoli',
                        51:'carrot',52:'hot dog',53:'pizza',54:'donut',55:'cake',56:'chair',57:'sofa',58:'pottedplant',59:'bed',60:'diningtable',
                        61:'toilet',62:'tvmonitor',63:'laptop',64:'mouse',65:'remote',66:'keyboard',67:'cell phone',68:'microwave',69:'oven',70:'toaster',
                        71:'sink',72:'refrigerator',73:'book',74:'clock',75:'vase',76:'scissors',77:'teddy bear',78:'hair drier',79:'toothbrush' }
# OpenCV Tensorflow Faster-RCNN용
labels_to_names_0 = {0:'person',1:'bicycle',2:'car',3:'motorcycle',4:'airplane',5:'bus',6:'train',7:'truck',8:'boat',9:'traffic light',
                    10:'fire hydrant',11:'street sign',12:'stop sign',13:'parking meter',14:'bench',15:'bird',16:'cat',17:'dog',18:'horse',19:'sheep',
                    20:'cow',21:'elephant',22:'bear',23:'zebra',24:'giraffe',25:'hat',26:'backpack',27:'umbrella',28:'shoe',29:'eye glasses',
                    30:'handbag',31:'tie',32:'suitcase',33:'frisbee',34:'skis',35:'snowboard',36:'sports ball',37:'kite',38:'baseball bat',39:'baseball glove',
                    40:'skateboard',41:'surfboard',42:'tennis racket',43:'bottle',44:'plate',45:'wine glass',46:'cup',47:'fork',48:'knife',49:'spoon',
                    50:'bowl',51:'banana',52:'apple',53:'sandwich',54:'orange',55:'broccoli',56:'carrot',57:'hot dog',58:'pizza',59:'donut',
                    60:'cake',61:'chair',62:'couch',63:'potted plant',64:'bed',65:'mirror',66:'dining table',67:'window',68:'desk',69:'toilet',
                    70:'door',71:'tv',72:'laptop',73:'mouse',74:'remote',75:'keyboard',76:'cell phone',77:'microwave',78:'oven',79:'toaster',
                    80:'sink',81:'refrigerator',82:'blender',83:'book',84:'clock',85:'vase',86:'scissors',87:'teddy bear',88:'hair drier',89:'toothbrush',
                    90:'hair brush'}
labels_to_names = {1:'person',2:'bicycle',3:'car',4:'motorcycle',5:'airplane',6:'bus',7:'train',8:'truck',9:'boat',10:'traffic light',
                    11:'fire hydrant',12:'street sign',13:'stop sign',14:'parking meter',15:'bench',16:'bird',17:'cat',18:'dog',19:'horse',20:'sheep',
                    21:'cow',22:'elephant',23:'bear',24:'zebra',25:'giraffe',26:'hat',27:'backpack',28:'umbrella',29:'shoe',30:'eye glasses',
                    31:'handbag',32:'tie',33:'suitcase',34:'frisbee',35:'skis',36:'snowboard',37:'sports ball',38:'kite',39:'baseball bat',40:'baseball glove',
                    41:'skateboard',42:'surfboard',43:'tennis racket',44:'bottle',45:'plate',46:'wine glass',47:'cup',48:'fork',49:'knife',50:'spoon',
                    51:'bowl',52:'banana',53:'apple',54:'sandwich',55:'orange',56:'broccoli',57:'carrot',58:'hot dog',59:'pizza',60:'donut',
                    61:'cake',62:'chair',63:'couch',64:'potted plant',65:'bed',66:'mirror',67:'dining table',68:'window',69:'desk',70:'toilet',
                    71:'door',72:'tv',73:'laptop',74:'mouse',75:'remote',76:'keyboard',77:'cell phone',78:'microwave',79:'oven',80:'toaster',
                    81:'sink',82:'refrigerator',83:'blender',84:'book',85:'clock',86:'vase',87:'scissors',88:'teddy bear',89:'hair drier',90:'toothbrush',
                    91:'hair brush'}

이미지를 preprocessing 수행하여 Network에 입력하고 Object Detection 수행 후 결과를 이미지에 시각화

img.shape
# (633, 806, 3)
# 원본 이미지가 Faster RCNN기반 네트웍으로 입력 시 resize됨. 
# scaling된 이미지 기반으로 bounding box 위치가 예측 되므로 이를 다시 원복하기 위해 원본 이미지 shape정보 필요
rows = img.shape[0]
cols = img.shape[1]
# cv2의 rectangle()은 인자로 들어온 이미지 배열에 직접 사각형을 업데이트 하므로 그림 표현을 위한 별도의 이미지 배열 생성. 
draw_img = img.copy()

# 원본 이미지 배열 BGR을 RGB로 변환하여 배열 입력. Tensorflow Faster RCNN은 마지막 classification layer가 Dense가 아니여서 size를 고정할 필요는 없음.  
cv_net.setInput(cv2.dnn.blobFromImage(img, swapRB=True, crop=False))

# Object Detection 수행하여 결과를 cvOut으로 반환 
cv_out = cv_net.forward()
print(cv_out.shape)

# bounding box의 테두리와 caption 글자색 지정
green_color=(0, 255, 0)
red_color=(0, 0, 255)

# detected 된 object들을 iteration 하면서 정보 추출
for detection in cv_out[0,0,:,:]:
    score = float(detection[2])
    class_id = int(detection[1])
    # detected된 object들의 score가 0.5 이상만 추출
    if score > 0.5:
        # detected된 object들은 scale된 기준으로 예측되었으므로 다시 원본 이미지 비율로 계산
        left = detection[3] * cols
        top = detection[4] * rows
        right = detection[5] * cols
        bottom = detection[6] * rows
        # labels_to_names_seq 딕셔너리로 class_id값을 클래스명으로 변경.
        caption = "{}: {:.4f}".format(labels_to_names_0[class_id], score)
        print(caption)
        #cv2.rectangle()은 인자로 들어온 draw_img에 사각형을 그림. 위치 인자는 반드시 정수형.
        cv2.rectangle(draw_img, (int(left), int(top)), (int(right), int(bottom)), color=green_color, thickness=2)
        cv2.putText(draw_img, caption, (int(left), int(top - 5)), cv2.FONT_HERSHEY_SIMPLEX, 0.4, red_color, 1)

img_rgb = cv2.cvtColor(draw_img, cv2.COLOR_BGR2RGB)

plt.figure(figsize=(12, 12))
plt.imshow(img_rgb)

# (1, 1, 100, 7)
# person: 0.9998
# person: 0.9996
# person: 0.9993
# person: 0.9970
# person: 0.8995
# car: 0.8922
# car: 0.7602
# car: 0.7415
# car: 0.6930
# car: 0.6918
# car: 0.6896
# car: 0.6717
# car: 0.6521
# car: 0.5730
# car: 0.5679
# car: 0.5261
# car: 0.5012
# <matplotlib.image.AxesImage at 0x7f943493e810>

cv_out
# [0, class_id, class_confidence, 좌표 4개]
# array([[[[0.00000000e+00, 0.00000000e+00, 9.99780715e-01,
          2.80248284e-01, 4.11070347e-01, 4.66062069e-01,
          8.59829903e-01],
          ...
          [0.00000000e+00, 8.60000000e+01, 1.52409787e-03,
          6.01132810e-01, 7.01487005e-01, 7.45222032e-01,
          8.93119752e-01]]]], dtype=float32)

단일 이미지의 object detection을 함수로 생성

import time

def get_detected_img(cv_net, img_array, score_threshold, use_copied_array=True, is_print=True):
    
    rows = img_array.shape[0]
    cols = img_array.shape[1]
    
    draw_img = None
    if use_copied_array:
        draw_img = img_array.copy()
    else:
        draw_img = img_array
    
    cv_net.setInput(cv2.dnn.blobFromImage(img_array, swapRB=True, crop=False))
    
    start = time.time()
    cv_out = cv_net.forward()
    
    green_color=(0, 255, 0)
    red_color=(0, 0, 255)

    # detected 된 object들을 iteration 하면서 정보 추출
    for detection in cv_out[0,0,:,:]:
        score = float(detection[2])
        class_id = int(detection[1])
        # detected된 object들의 score가 함수 인자로 들어온 score_threshold 이상만 추출
        if score > score_threshold:
            # detected된 object들은 scale된 기준으로 예측되었으므로 다시 원본 이미지 비율로 계산
            left = detection[3] * cols
            top = detection[4] * rows
            right = detection[5] * cols
            bottom = detection[6] * rows
            # labels_to_names 딕셔너리로 class_id값을 클래스명으로 변경. opencv에서는 class_id + 1로 매핑해야함.
            caption = "{}: {:.4f}".format(labels_to_names_0[class_id], score)
            print(caption)
            #cv2.rectangle()은 인자로 들어온 draw_img에 사각형을 그림. 위치 인자는 반드시 정수형.
            cv2.rectangle(draw_img, (int(left), int(top)), (int(right), int(bottom)), color=green_color, thickness=2)
            cv2.putText(draw_img, caption, (int(left), int(top - 5)), cv2.FONT_HERSHEY_SIMPLEX, 0.4, red_color, 1)
    if is_print:
        print('Detection 수행시간:',round(time.time() - start, 2),"초")

    return draw_img
# image 로드 
img = cv2.imread('./data/beatles01.jpg')
print('image shape:', img.shape)

# tensorflow inference 모델 로딩
cv_net = cv2.dnn.readNetFromTensorflow('./pretrained/faster_rcnn_resnet50_coco_2018_01_28/frozen_inference_graph.pb', 
                                     './pretrained/config_graph.pbtxt')
# Object Detetion 수행 후 시각화 
draw_img = get_detected_img(cv_net, img, score_threshold=0.5, use_copied_array=True, is_print=True)

img_rgb = cv2.cvtColor(draw_img, cv2.COLOR_BGR2RGB)

plt.figure(figsize=(12, 12))
plt.imshow(img_rgb)

# image shape: (633, 806, 3)
# person: 0.9998
# person: 0.9996
# person: 0.9993
# person: 0.9970
# person: 0.8995
# car: 0.8922
# car: 0.7602
# car: 0.7415
# car: 0.6930
# car: 0.6918
# car: 0.6896
# car: 0.6717
# car: 0.6521
# car: 0.5730
# car: 0.5679
# car: 0.5261
# car: 0.5012
# Detection 수행시간: 8.62 초
# <matplotlib.image.AxesImage at 0x7f94346af150>

 

 

# 다른 image 테스트
!wget -O ./data/baseball01.jpg https://raw.githubusercontent.com/chulminkw/DLCV/master/data/image/baseball01.jpg
img = cv2.imread('./data/baseball01.jpg')
print('image shape:', img.shape)

# tensorflow inference 모델 로딩
cv_net = cv2.dnn.readNetFromTensorflow('./pretrained/faster_rcnn_resnet50_coco_2018_01_28/frozen_inference_graph.pb', 
                                     './pretrained/config_graph.pbtxt')
# Object Detetion 수행 후 시각화 
draw_img = get_detected_img(cv_net, img, score_threshold=0.5, use_copied_array=True, is_print=True)

img_rgb = cv2.cvtColor(draw_img, cv2.COLOR_BGR2RGB)

plt.figure(figsize=(12, 12))
plt.imshow(img_rgb)

# image shape: (476, 735, 3)
# person: 0.9998
# person: 0.9997
# person: 0.9977
# sports ball: 0.8867
# baseball bat: 0.8420
# baseball glove: 0.9815
# Detection 수행시간: 7.56 초
# <matplotlib.image.AxesImage at 0x7f9434623f50>

 

반응형
728x90
반응형

# OpenCV DNN 장단점

1) 장점

- 딥러닝 개발 프레임워크 없이 쉽게 Inference 구현 가능

- OpenCV에서 지원하는 다양한 Computer Vision 처리 API와 Deep Learning을 쉽게 결합

 

2) 단점

- GPU 지원기능이 약함

- DDN 모듈은 과거에 NVIDIA GPU 지원이 안됨, 2019년 10월에 google에서 NVIDIA GPU 지원 발표함. 아직 환경 구성, 설치가 어려움, 점차 개선 예상됨

- OpenCV는 모델을 학습할수있는 방법을 제공하지 않으며 오직 inference만 가능

- CPU기반에서 Inference 속도가 개선되었으나, NVIDIA GPU가 지원되지 않아 타 Deep learning framework 대비 interence 속도가 크게 저하됨

 

# 타 deep learning frame과의 연동

- opencv는 자체적으로 딥러닝 가중치 모델을 생성하지 않고 타 framework에서 생성된 모델을 변환하여 로딩함

- dnn패키지는 파일로 생성된 타 프레임워크 모델을 로딩할 수 있도록 readNetFromxxx(가중치 모델, 환경 파일)API 제공

- 가중치 모델파일은 타 프레임워크 모델 파일, 환경 파일은 타 프레임워크 모델 파일의 환경(Config)파일을 DNN패키지에서 다시 변환한 환경 파일

Framework 타 framework 모델 로딩 특징
tensorflow cvNet = Cv2.dnn.readNetFromTensorflow(모델, 환경파일) 많은 모델 제공
darknet cvNet = Cv2.dnn.readNetFromDarknet(모델, 환경파일) yolo만 로딩가능
torch cvNet = Cv2.dnn.readNetFromTorch(모델, 환경파일)  
caffe cvNet = Cv2.dnn.readNetFromCaffe(모델, 환경파일)  

* weights model은 tensorflow API로 PreTrained된 모델(Frozen Graph)를 다운로드

* config는 pretrained된 모델(Frozen Graph)를 구동을 위한 Config 다운로드

 

opencv지원 tensorflow모델

1) inference 수행시간 위주

- MobileNet-SSD v1

 

2) inference 정확도 위주

- inception-SSD v2

- Faster RCNN inception v2

- Faster RCNN ResNet-50

 

# opencv DNN을 이용한 inference 수행 절차

# 가중치 모델 파일과 환경설정 파일을 로드하여 inference network model 생성
cvNet = cv2.dnn.readNetFromTensorflow('frozen_inference_graph.ph', 'graph.pbtxt')

img = cv2.imread('img.jpg')
rows, cols, channels = img.shape

# 입력 이미지를 preprocessing 하여 network 입력
cvNet.setInput(cv2.dnn.blobFromImage(img, size = (300, 300), swapRB=True, crop=False))

# interence network에서 detect된 정보 output 추출
networkOutput = cvNet.forward()

# 추출된 output에서 detect 정보를 기반으로 원본 image위에 object detection 시각화
for detection in networkOutput[0,0]:
	# object detected 결과, bounding box 좌표, 예측 레이블들을 원본 image위에 시각화 로직

 

# opencv blobFromImage()

Image를 preprocessing 수행하여 network에 입력할수있게 제공

- 이미지 사이즈 고정

- 이미지 값 스케일링

- BGR을 RGB로 변경, 이미지를 CROP할수있는 옵션 제공

OpenCV의 BGR은 well-known이니깐

# BGR을 해결하는 법

1) cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

 

2) cvNet.setInput(cv2.dnn.blobFromImage(img, size=(300, 300), swapRB=True, crop=False))

swapRB=True로 변환하여 네트워크에 입력

 

# video stream capture를 이용한 video object detection

opencv의 videocapture() api를 이용하여 video stream을 frame by frame 별로 capture한 image에 object detection을 수행하는 방식

input_video = cv2.VideoCapture(input_file_path)
while(True) :
	frame 별로 Object Detection 수행

 

 

 

 

 

반응형
728x90
반응형

# Ground Truth BB 겹치는 IOU값에 따라 Anchor Box를 분류함.

- IOU가 가장 높은 Anchor는 Positive

- IOU가 0.7 이상이면 Positive

- IOU가 0.3 이하면 Negative / Negative는 Not Object임을 학습시키기 위해

- IOU가 0.3 ~ 0.7이면 아예 학습에 포함시키지 않고 filtering out 함

 

# Anchor Box를 Reference로 한 Bounding Box Regression

- 예측 BB와 Positive Anchor Box와의 좌표 차이는 Ground Truth와 Positive Anchor Box와의 좌표 차이와 최대한 동일하게 될수있도록 regression 학습

- Ground Truth Box와 Positive Anchor Box의 중심좌표 간 거리(좌표 차이)와 Positive Anchor box와 Predicted Anchor box와의 중심좌표 거리(고정값)가 비슷하면 유사한 것이다.

 

 

# Anchor box에 따른 RPN output

 

2배는 classification, 4배는 4*9 36 reg

 

# RPN Loss 함수

Pi Anchor i가 오브젝트일 예측확률
Pi* Anchor i의 Ground Truth Object여부
Ti Anchor i와 예측 좌표 차이(x,y,w,h)
Ti* Anchor i와 Ground Truth 좌표 차이(x,y,w,h)
Ncls 미니 배치에 따른 정규화 값(256)
Nbox 박스 개수 정규화 값(최대2400)
L 밸런싱 값 : 10

 

# Faster RCNN Training : Alternating Training

먼저 RPN부터 학습하고 Faster RCNN을 학습시키고 도출된 Loss로 fine tuning

 

 

 

=> selective search를 제거해서 최초로 Deep learning으로만 구성된 알고리즘임

반응형
728x90
반응형

Image data

이미지 데이터를 다룰 때는 주의 해야 것들이 있다

1. 이미지 데이터의 크기가 재각각이다

2. 이미지 데이터를 머신러닝 데이터로 사용하기 위해서는 array data로 바꿔야한다

3. 이미지 데이터를 파일로 갖고 있을 경우 tensorflow에서는 tf.io.read_file('') 불러온다

4. 불러온 이미지 파일 type 따라서 decoder를 달리해야 한다

5. png 파일은 투명도를 지원한다. 따라서 같은 크기더라도 채널 정보가 4차원이 된다

이미지가 크기가 다를때 세 가지 해결 방식

1. resize

- resize를 통해 크기를 통일시킨다

- , resize를 하게 되면 데이터의 의미가 유지되지 않는다(이미지 왜곡이 발생한다)

2. crop

- 내가 생각한 이미지가 생각보다 사용한다

- 데이터를 일일이 crop 해야하는 단점이 있다

3. padding

- 내가 생각한 이미지가 생각보다 작을 사용한다

# sppnet, r-cnn에서 resize관련 이슈를 해결한 방식을 배울 것이다

이미지 데이터의 크기가 크면 클수록 좋을까?

# 가정: cpu, gpu의 성능은 최고라고 가정한다 => 데이터가 많으면 많을 수록 좋다

데이터가 많다는 것은 2차원 데이터에서 row가 늘어나는 것이다

row가 많으면 처리할 연산량이 많아지기 때문에 처리속도가 떨어진다

하지만 하드웨어 성능관점에서 벗어나면 데이터의 row가 많으면 많을 수록 좋다

 

그렇다면 column(feature/dimension)은 크면 클 수록 좋을까? => column은 i.i.d 가정을 갖고 있다

예를 들어 꽃을 설명 할 때 꽃 잎 정보만 주어 졌을 때 정확하게 학습할까 아니면 꽃 잎 정보, 꽃 줄기 정보, 꽃의 씨앗 정보가 주어졌을 때 더 정확하게 학습할까?

당연 더 많은 종류의 정보가 주어졌을 때 학습을 잘 할 수 있다 => 더 많은 nuance를 갖기 때문에 feature가 많은 것은 유리할 수 있다

하지만, 차원이 증가하면 증가할 수록 차원의 저주가 발생한다

즉, 차원이 증가함에 따라 필요한 데이터는 기하 급수적으로 늘어난다

 

데이터에 따라, 모델에 따라, feature 갯수에 따라 데이터가 작으면 overfitting이 발생할 수 있다

예를 들어 사람을 인식하는 모델이 있다고 가정했을 때 눈, 코, 입 정보만 주어진 데이터로 학습을 할 경우

사람의 눈, 코, 입이 포함되어 있는 데이터의 경우는 정확하게 인식할 수 있지만

눈, 코, 입과 더불어 사람의 몸 전체가 주어진 데이터에 대해서는 사람이라고 인식을 하지 못하게 될 수도 있다.

뿐만 아니라 사람을 인식하는 모델을 학습할 때 사람 몸 전체에 대한 정보가 주어진 데이터를 학습하는데

데이터에 대한 feature갯수 보다 데이터의 갯수가 적을 경우 학습된 사람 데이터에 대해서만

정확하게 인식하고 조금이라도 다르게 생긴 사람 데이터 정보가 들어 왔을 때 정확히 인식하지 못할 가능성이 발생 할 수 있다

Feature selection

유의미한 feature만 추려서 사용한다

1. Filter (Statistics)

- 통계 값을 활용하여 클래스와 가장 밀접한 feature를 택한다

- 상관성 분석을 통해 구분한다

2. Wrapper

- Algorithm + feature를 활용하여 최적의 feature를 택한다

3. Embeded

- Algorithm으로 자체만으로 feature의 중요도를 알려준다

- Feature 기반의 분류를 있는 것에만 사용할 있다

 

Feature selection은 한계가 있다

이미지 데이터는 i.i.d가 아니기 때문에 feature간의 독립성이 약해서 feature selection을 사용할 없다

 

import pathlib
dataset_url = "https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz"
data_dir = tf.keras.utils.get_file(origin=dataset_url, 
                                   fname='flower_photos', 
                                   untar=True)

data_dir = pathlib.Path(data_dir)

image_count = len(list(data_dir.glob('*/*.jpg')))
print(image_count)

Filter

import seaborn as sns
from sklearn.feature_selection import SelectKBest, chi2 # 카이제곱 검정: 관찰된 빈도가 기대되는 빈도와 의미있게 다른지의 여부를 검정하기 위해 사용되는 검정방법이다
iris = sns.load_dataset('iris')
skb = SelectKBest(chi2, k=3) # 클래스와 연관성이 가장 큰 3가지 feature를 고른다 
skb.fit_transform(iris.iloc[:,:-1], iris.species)
skb.fit_transform(iris.iloc[:,:-1], iris.species)[:5]
array([[5.1, 1.4, 0.2],
       [4.9, 1.4, 0.2],
       [4.7, 1.3, 0.2],
       [4.6, 1.5, 0.2],
       [5. , 1.4, 0.2]])
iris.iloc[:5] # sepal_length, petal_length, petal_width 3가지 feature가 선택되었다 

sepal_length	sepal_width	petal_length	petal_width	species
0	5.1	3.5	1.4	0.2	setosa
1	4.9	3.0	1.4	0.2	setosa
2	4.7	3.2	1.3	0.2	setosa
3	4.6	3.1	1.5	0.2	setosa
4	5.0	3.6	1.4	0.2	setosa
vars(skb)
{'k': 3,
 'pvalues_': array([4.47651499e-03, 1.56395980e-01, 5.53397228e-26, 2.75824965e-15]),
 'score_func': <function sklearn.feature_selection._univariate_selection.chi2>,
 'scores_': array([ 10.81782088,   3.7107283 , 116.31261309,  67.0483602 ])}
skb.get_params()
#
{'k': 3,
 'score_func': <function sklearn.feature_selection._univariate_selection.chi2>}
iris.corr() # petal_length, petal_width 두 가지 feature가 서로 연관되어 있기 때문에 둘 중 하나를 택한다 
	sepal_length	sepal_width	petal_length	petal_width
sepal_length	1.000000	-0.117570	0.871754	0.817941
sepal_width	-0.117570	1.000000	-0.428440	-0.366126
petal_length	0.871754	-0.428440	1.000000	0.962865
petal_width	0.817941	-0.366126	0.962865	1.000000

Wrapper

알고리즘과 데이터의 feature에 따른 경우의 수를 고려하여 계산하는 방식

from sklearn.feature_selection import RFE # Recursive feature extraction 
from sklearn.linear_model import LogisticRegression

rfe = RFE(LogisticRegression(), n_features_to_select=2) # 4개 중에 2개 선택 (iris feature가 4개 이기 때문에)
rfe.fit_transform(iris.iloc[:,:-1], iris.species) # fit_transform
vars(rfe)
#
{'estimator': LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,
                    intercept_scaling=1, l1_ratio=None, max_iter=100,
                    multi_class='auto', n_jobs=None, penalty='l2',
                    random_state=None, solver='lbfgs', tol=0.0001, verbose=0,
                    warm_start=False),
 'estimator_': LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,
                    intercept_scaling=1, l1_ratio=None, max_iter=100,
                    multi_class='auto', n_jobs=None, penalty='l2',
                    random_state=None, solver='lbfgs', tol=0.0001, verbose=0,
                    warm_start=False),
 'n_features_': 2,
 'n_features_to_select': 2,
 'ranking_': array([3, 2, 1, 1]),
 'step': 1,
 'support_': array([False, False,  True,  True]),
 'verbose': 0}
iris.columns[:-1][rfe.support_] 

# Index(['petal_length', 'petal_width'], dtype='object')

Embeded

from sklearn.tree import DecisionTreeClassifier # 분기를 시켜 feature의 중요도를 나타낸다 
from sklearn.ensemble import RandomForestClassifier

dt = DecisionTreeClassifier()
dt.fit(iris.iloc[:,:-1], iris.species)

dt.feature_importances_ # feature의 중요도를 알려준다 
# array([0.01333333, 0.        , 0.56405596, 0.42261071])
iris.iloc[:,:-1].columns
# Index(['sepal_length', 'sepal_width', 'petal_length', 'petal_width'], dtype='object')
rf = RandomForestClassifier()
rf.fit(iris.iloc[:,:-1], iris.species)

rf.feature_importances_
# array([0.10738656, 0.02592046, 0.41244991, 0.45424308])

Dimension Reduction

차원 축소

nuance 손실도 발생하고 원본 데이터를 손상시킨다는 단점이 있다

 

from sklearn.decomposition import PCA
pca = PCA(2) # 2차원으로 줄인다 
pca.fit_transform(iris.iloc[:,:-1], iris.species) # 4차원 -> 2차원 / 공간이 왜곡 되었다 
# array([[-2.68412563,  0.31939725],
       [-2.71414169, -0.17700123],
       [-2.88899057, -0.14494943],
       [-2.74534286, -0.31829898],

Feature selection vs Dimension reduction

Feature selection은 데이터 값을 그대로 유지하면서 feature를 축소 했지만,

Dimension reduction은 데이터 값을 변형하면서 차원을 축소 한다 => 공간을 왜곡시킨다

!pip install mglearn
import mglearn
mglearn.plot_pca.plot_pca_illustration() # 차원이 축소 되어도 의미를 잃지 않았다 / 고차원의 특성이 저차원에서도 유지가 되었다 / manifold

Manifold

고차원의 데이터를 공간상에 표현하면 각 데이터들은 점의 형태로 찍혀지는데,

이러한 점들을 잘 아우르는 subspace를 manifold라고 한다

 

Path

import cv2
import os # 운영체제별로 결과가 상이할 수 있다 
from pathlib import Path # 운영체제 별로 상이하지 않게 범용적으로 사용 가능 

os.listdir('flower_photos/daisy')[:10]
['7410356270_9dff4d0e2e_n.jpg',
 '7568630428_8cf0fc16ff_n.jpg',
 '10770585085_4742b9dac3_n.jpg',
 '4286053334_a75541f20b_m.jpg',
 '8759177308_951790e00d_m.jpg',
 '4131565290_0585c4dd5a_n.jpg',
 '8710109684_e2c5ef6aeb_n.jpg',
 '3504430338_77d6a7fab4_n.jpg',
 '2612704455_efce1c2144_m.jpg',
 '8021540573_c56cf9070d_n.jpg']
path = 'flower_photos/daisy'
images = [cv2.imread(os.path.join(path,i)) for i in os.listdir(path)] # os.listdir : 특정 디렉토리를 리스트로 만들어 준다 

!pwd
# /content/drive/My Drive/Colab Notebooks/고급시각반 정리/flower_photos
path = Path('flower_photos/daisy') # path 객체로 불러온다 
images = [cv2.imread(str(i)) for i in path.iterdir()]

len(images)
# 633

Pattern

path 객체는 pattern을 사용할 수 있다

import glob # 패턴을 활용할 수 있는 패키지 
image = [cv2.imread(i) for i in glob.glob('flower_photos/daisy/*.jpg')] # glob 모듈의 glob 함수는 사용자가 제시한 조건에 맞는 파일명을 리스트 형식으로 반환한다.
len(image)
# 633
import imageio
imageio.volread(path) # s mode를 알아야 한다?

path = 'flower_photos/daisy'
imageio.mimread(path, format='jpg') # multiple image를 불러들일 수 있다. 단, jpeg는 multi-image 불러들일 수 없다 
# RuntimeError: Format JPEG-PIL cannot read in mode 'I'
from skimage.io import imread_collection
imc = imread_collection('flower_photos/daisy/*.jpg')  # 패턴을 정확히 이해해야 한다 

imc.files[:10]
['flower_photos/daisy/5547758_eea9edfd54_n.jpg',
 'flower_photos/daisy/5673551_01d1ea993e_n.jpg',
 'flower_photos/daisy/5673728_71b8cb57eb.jpg',
 'flower_photos/daisy/5794835_d15905c7c8_n.jpg',
 'flower_photos/daisy/5794839_200acd910c_n.jpg',
 'flower_photos/daisy/11642632_1e7627a2cc.jpg',
 'flower_photos/daisy/15207766_fc2f1d692c_n.jpg',
 'flower_photos/daisy/21652746_cc379e0eea_m.jpg',
 'flower_photos/daisy/25360380_1a881a5648.jpg',
 'flower_photos/daisy/43474673_7bb4465a86.jpg']
w = os.walk('flower_photos/daisy')
for _, _, files in os.walk('flower_photos/daisy'):
  for i in range(10):
    print(files[i])
    
7410356270_9dff4d0e2e_n.jpg
7568630428_8cf0fc16ff_n.jpg
10770585085_4742b9dac3_n.jpg
4286053334_a75541f20b_m.jpg
8759177308_951790e00d_m.jpg
4131565290_0585c4dd5a_n.jpg
8710109684_e2c5ef6aeb_n.jpg
3504430338_77d6a7fab4_n.jpg
2612704455_efce1c2144_m.jpg
8021540573_c56cf9070d_n.jpg
import tensorflow as tf 
img = tf.keras.preprocessing.image_dataset_from_directory('flower_photos/')
# Found 3670 files belonging to 5 classes.

type(img)
# tensorflow.python.data.ops.dataset_ops.BatchDataset

for i in img:
  print(i[0].numpy()) # float형태로 한꺼번에 불러온다 단, 범용적으로 사용하지 못하는 단점이 있다

전처리의 중요성

전처리는 정답이 없다

import tensorflow as tf 
import matplotlib.pyplot as plt

(X_train, y_train), (X_test, y_test) = tf.keras.datasets.mnist.load_data()
# (X_train, y_train), (X_test, y_test) = tf.keras.datasets.cifar10.load_data()

정 중앙에 있는 숫자 + 비틀림이 없는 숫자 + 크기가 일정

- 이러한 가정이 있기 때문에 성능이 좋았다, 가정을 한 데이터에 대해서는 대표성을 잘 지닌다

- 그러다 다양한 상황의 일반적인 데이터에는 성능이 좋지 못할 수도 있다

ex) A라는 사람의 필체를 학습한 a모델이 있다고 했을 때 A라는 사람의 글씨는 정확히 인식할 수 있지만 다른 사람의 필체는 정확하게 인식하지 못할 가능성이 높다

plt.imshow(X_train[0]) # 정 중앙에 있는 숫자 + 비틀림이 없는 숫자 + 크기가 일정 (전처리를 통해서 새로운 데이터 분포를 만든 것) => 이러한 가정이 있기 때문에 성능이 좋았다, 가정을 한 데이터에 대해서는 대표성을 잘 지닌다

plt.imshow(X_train[0]) # 3차원 데이터 이기 때문에 전통적인 머신러닝에 사용할 수 없다

plt.imshow(X_train[0], cmap='gray')

X_train[0].shape
# (32, 32, 3)

X_train[0].flatten() # 1차원으로 변경, copy방식 => 원본하고 같이 바뀌고 싶지 않을 때
# array([ 59,  62,  63, ..., 123,  92,  72], dtype=uint8)

X_train[0].ravel()   # 1차원으로 변경, view방식 => 원본하고 같이 바뀌고 싶을 때 
# array([ 59,  62,  63, ..., 123,  92,  72], dtype=uint8)

color 이미지 일 때 (32, 32, 3) 이미지는 머신러닝 관점에서 차원은 3072(32X32X3)이다

따라서 차원의 저주 문제가 발생한다

 

gray로 바꿈으로써 차원을 축소할 수도 있다 => color를 gray로 바꿀 때 단순히 평균해서 바꾸기도 한다 => np.mean(X_train[0], axis=2)

from skimage.color import rgb2gray
X_train[0].size, rgb2gray(X_train[0]).size # nuance
(3072, 1024)
Raw data Featured Data
원본데이터 전처리된 데이터
의미 손실이 없는 대신 패턴을 찾기 어렵다 일부 의미가 손실되지만 패턴을 찾기 좋다
차원의 저주가 발생할 수 있다 차원의 축소가 된다
연산량이 많이 요구된다 연산량이 많이 줄어든다
저장 공간이 많이 요구된다 저장 공간이 많이 줄어든다

이미지 변화 적용(Filter)

Filter도 전처리 방법중 하나 이다 어떻게, 어떤 Filter를 적용하는 것이 맞는지 정확히 알 수 없다

Image augmentation

원본 이미지의 의미를 유지시키면서 변형 하고 새로운 데이터 셋으로 사용 한다

 

from sklearn.datasets import load_digits
data = load_digits()
data.images.shape
# (1797, 8, 8)

plt.imshow(data.images[2], cmap='gray')

data.data # 하나의 데이터는 1차원으로 변경되었다 
array([[ 0.,  0.,  5., ...,  0.,  0.,  0.],
       [ 0.,  0.,  0., ..., 10.,  0.,  0.],
       [ 0.,  0.,  0., ..., 16.,  9.,  0.],
       ...,
       [ 0.,  0.,  1., ...,  6.,  0.,  0.],
       [ 0.,  0.,  2., ..., 12.,  0.,  0.],
       [ 0.,  0., 10., ..., 12.,  1.,  0.]])

Model

이미지 데이터는 공통적으로 Non Linear다

Non Linear라는 것은 데이터 셋을 비선형적으로 구분해야 한다

머신러닝은 meta 프로그래밍이 가능하다

=> 메타 프로그래밍은 자기 자신 혹은 다른 컴퓨터 프로그램을 데이터로 취급하며 프로그램을 작성·수정하는 것을 말한다

특징들이 일반적이기 때문에 (abstract)

import cv2
import numpy as np
from sklearn.tree import DecisionTreeClassifier

dt = DecisionTreeClassifier() # 1단계 (Hyperparameter)

dt.fit(data.data, data.target)
# DecisionTreeClassifier(ccp_alpha=0.0, class_weight=None, criterion='gini',
#                       max_depth=None, max_features=None, max_leaf_nodes=None,
#                       min_impurity_decrease=0.0, min_impurity_split=None,
#                       min_samples_leaf=1, min_samples_split=2,
#                       min_weight_fraction_leaf=0.0, presort='deprecated',
#                       random_state=None, splitter='best')
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.neural_network import MLPClassifier, MLPRegressor
from sklearn.svm import SVC, SVR
from sklearn.neighbors import KNeighborsClassifier

t = cross_val_score(dt, data.data, data.target, cv = 10) 
t 
# array([0.79444444, 0.86666667, 0.85      , 0.8       , 0.78333333,
#       0.87222222, 0.90555556, 0.81005587, 0.81564246, 0.82681564])
t.mean() # 전처리가 잘 되어 있기 때문에 성능이 좋다 
# 0.8324736188702669
data.data = data.data.astype('float32')
knn1 = cv2.ml.KNearest_create()
knn1.train(data.data, cv2.ml.ROW_SAMPLE ,data.target) # 데이터가 연속이라는 가정을 두고 학습을 해야 하기 때문에 데이터 타입이 float이어야 한다 
# True
knn2 = KNeighborsClassifier()
knn2.fit(data.data, data.target)

# KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski',
#                     metric_params=None, n_jobs=None, n_neighbors=5, p=2,
#                     weights='uniform')
knn1.findNearest(data.data[3][np.newaxis], 3) # 2차원 데이터를 받는다 
#(3.0,
# array([[3.]], dtype=float32),
# array([[3., 3., 3.]], dtype=float32),
# array([[  0., 197., 232.]], dtype=float32))
knn2.predict(data.data[3][np.newaxis])
# array([3])

%timeit knn1.findNearest(data.data, 5) 
# 10 loops, best of 5: 148 ms per loop

%timeit knn2.predict(data.data) 
# 1 loop, best of 5: 417 ms per loop

 

 

 

 

 

 

반응형

'Computer_Science > Computer Vision Guide' 카테고리의 다른 글

3-9. openCV의 DNN으로 Object Detection 구현 개요  (0) 2021.09.27
3-8. RPN, Positive Anchor Box  (0) 2021.09.26
3-7. anchor box를 이용한 RPN  (0) 2021.09.24
3-6. Faster RCNN  (0) 2021.09.24
3-5. fast RCNN  (0) 2021.09.24
728x90
반응형

def rpn(base_layers, num_anchors) :
	x = Concolution2D(512, (3, 3), padding='same', activation='relu', kernel_initializer='normal', name='rpn_conv1')(base_layers)
    
    x_class = Concolution2D(num_anchors, (1, 1), activation='sigmoid', kernel_initializer='uniform', name='rpn_out_class')(x)
    x_regr = Concolution2D(num_anchors*4, (1, 1), activation='linear', kernel_initializer='zero', name='rpn_out_regress')(x)
    
    return [x_class, x_regr, base_layers]

 

w50 x h40 x d512 => 3x3 conv, 512 channel =>

1) 이진분류 : 1x1 conv 9(anchor 개수) output channel => sigmoid Binary ( FG / BG ) 

                      => w50 x h40 9anchor box => grid x box = 18000개

2) 영역추천 : 1x1 conv 4x9 output channel => bounding box regression (x1, y1, w, h)

                        (x1, y1, w, h) 9anchor box => 36

 

# RPN Bounding Box Regression

- RPN Bounding Box Regression은 Anchor Box를 Reference로 이용하여 Ground truth와 예측 Bbox의 중심좌표 x, y 그리고 w, h 의 차이가 Anchor box와 Ground Truth 간의 중심 좌표 x,y,w,h 차이와 최대한 동일하게 예측 될 수 있어야 함.

Anchor Box와 Predicted box, Ground Truth의 차이

1) PB, GTB 중심점 간의 거리

2) AB, GTB 중심점 간의 거리

두 차이가 동일하면 같게 예측 한 것이라는 가정

 

 

 

 

 

 

 

 

 

반응형
728x90
반응형

faster RCNN = RPN(Region Proposal Network) + Fast RCNN

- conv layer를 통과한 feature map은 두 경로로 흘러감

1) RPN 

2) feature map

 

Region Proposal Network 구현 이슈

- 피처는 pixel값, target은 Ground Truth bounding box인데 어떻게 selective search 수준의 region proposal을 할수있을까?

=> Anchor Box : object 유무 여부의 후보 box

anchor box는 후보군 값인데 GT box를 넣어주면 deep learning으로 가능

동일 grid point 기준, 구성은 9개, 서로 다른 크기 3개, 서로다른 ratio 3개 로 구성 => object 형태가 다르기 때문

다양하게 해야 겹치는 object, 다른 비율의 object를 찾을수있음

 

진행하다보면 각 grid point와 point별 anchor box가 또 겹침

다 겹치면 image boundary 형성

 

 

 

 

 

 

 

 

 

 

 

 

 

 

반응형
728x90
반응형

fast RCNN은 기존 RCNN에 spp layer사용해서 CNN LAYER 학습 횟수를 효과적으로 줄인 것과 마찬가지 원리이다.

spp layer이 아닌 ROI pooling Layer로 적용방법은 일부 다르다

- fast RCNN은 Roi pooling을 이용한다.

- 또한 SVM이라는 별도의 classification이 아닌 바로 softmax를 사용해서 deep learning network 으로 끌어들인다.

- multi task loss function으로 classification과 regression를 함께 최적화한다.

 

- faster RCNN은 selective search를 deep learning영역을 끌어들인 RPN을 사용한다.

 

# ROI pooling

- feature map 상의 임의의 ROI를 고정크기의 Pooling 영역으로 매핑

- 매핑 시 일반적으로 max pooling 적용 => 크기를 맞춰줌

- feature map의 depth와 roi pooling의 depth( channel )는 동일함, size만 고정

(spp는 depth없이 그냥 1차원 fixed length로 만들어버림)

 

- 후에 softmax 사용, ( vs svm

 

# 전과정을 deep learning으로 진행시킨 것의 의의

- softmax를 사용하는 등의 편리

- classification, regression을 multi task loss로 통합 최적화 가능

- 전과정을 back propagation을 통해 가중치 최적화 가능

 

multi-task loss
성능 비교

 

 

 

 

반응형
728x90
반응형

SPPNet : Spatial Pyramid pooling

RCNN의 문제점, 

Spatial Pyramid Matching

 

sppnet은 fast rcnn에서 개념을 차용해감

 

# RCNN의 주요 문제점

1) 너무 느린 Detection 시간

=> region을 너무 많이 proposal 하고 cnn입력됨. // region 영역 이미지가 crop과 warp까지 적용함

 

# RCNN 개선 방안

1) 원본이미지를 Selective search 하고, 다시 원본이미지를 feature extractor에 넣고 feature map을 생성함

=> 1개의 이미지만 extracted 하는 것이라 훨씬 간편함 vs 2000여개 region를 extracting

=> crop, warp의 이미지 훼손도 방지

 

=> 당시엔 feature map 이 3차원이라 dense layer, softmax,FC로 만들수가 없어서 1차원으로 만들게 됨

1D flattened fc input이 static해서 일정한 scale로 feature 고정이 안되면 안받아줌 -> 어쩔 수 없이 svm을 쓰게 되었다.

2) SPPNet

feature map 내의 중구난방 scale의 region을 별도로 mapping 할 수 있는 spp layer을 만듬

SPM을 적용해서 균일한 scale로 적용시킴

 

# spp(Spatial pyramid pooling)

CNN image classification에서 서로 다른 이미지의 크기를 고정된 크기로 변환하는 기법으로 소개

=> input image size를 고정하지 말자는 개념

대신 conv layer와 fc layer를 유연하게 연결시킬수있는 layer를 두면 classification layer를 적용하는데 문제없다.

기존 : image -> corp/warp -> conv layers -> fc layers -> output

spp : image -> conv layers -> spatial pyramid pooling -> fc layers -> output

# spatial pyramid pooling 

Bag of visual words => spatial pyramid matching

- 하나의 object를 조각조각 쪼개서(bag of visual words) histogram으로 확인하면 특징적인 부분이 드러난다.

- 원본의 정보를 새로운 mapping 정보로 변환함, 기준은 histogram

=> 비정형의 원본을 기준에 의한 정형적인 histogram화 시킨 것

 

단점은 언어면 문맥이 없고, visual object면 형상, 배치적 맥락이 없음, 그저 빈도수만 고려

=> spatial 위치 개념을 분면 상으로 넣어줌

 

# spatial pyramid matching 

image를 분면으로 쪼개면 좌표당 hitogram을 정보표현을 할 수 있다

이것으로 classification을 할 수 있다.

 

level 0는 전형 고려하지 않은 상태 => level2는 16분면으로 쪼개서 spatial 당 정보 생성 후 그 안에서 분류

 

- 분면 분할을 했기 때문에 histogram이 균일해진다.

- pooling => 원본 feature에서 일부분을 뽑아냄 => classify한 부분을 뽑아냄

나누는 분면에 따라서 feature vector가 달라짐

- 아니, 근데 원본 pooling을 했는데 또 spp를 해도 되는건가? 데이터 손실이 발생하지 않을까?

=> img size가 warp이 되면서 손실이 생각보다 적고, 성능이 높아졌다.

왜냐하면 feature map 분면분할 하면서 분면개수로 fixed length representation로 layer를 만들고 scale size가 어떻든 상관이 없어진다.

 

이상태에서 dense layer를 하면 된다.

 

# RCNN 과 SPP NET 비교

                    1개 image가 2000여번 CNN 통과                            1개 image가 1번만 CNN 통과

 

 

반응형

+ Recent posts