Introduction
One-Stage Detector
이미지가 들어오면 Conv & FC Layers를 거져서 output을 만들게 되고 이를 통해서 Classification과 Box Regression을 진행한다.
Two-Stage Detector
원본 이미지 -> Region Proposal -> 객체가 있을 것 같은 영역을 찾아낸다.
원본 이밎 -> Classification를 통해서 Feature map을 뽑아낸 후 -> Proposed Regions를 Feature map에 투영시켜서 Classification과 Box Regression을 진행
YOLO
Main Contribution
- object detection 을 regression problem으로 관점 전환
- Unified Architecture: 하나의 신경망으로 classification & localization 예측
- DPM, R-CNN 모델보다 속도 개선
- 여러 도메인에서 object detection 가능
Unified Detection
one-stage detection으로 통합
- input image를 S x S 그리드로 나눈다.
- Box Regression + Class Probability을 구함
하나의 그리드 셀에서 예측할 BBox를 2개, 클래스의 종류를 20이라고 할 때
Box Regression 진행 과정
하나의 그리드 셀을 기준으로 예측한 첫 번째 BBox는 진한 파란색 박스이고, 여기서 나온 output으로는 BBox의 정 중앙 좌표일 x, y 그리고 input의 w, h를 셀만큼 나누어서 정규화한 w, h(0~1) 그리고 물체가 BBox 내에 있는지 없는지 나타내는 Pc이다.
Classification
각 클래스에 대해서 해당 객체가 어떤 클래스에 해당할지에 대한 확률을 나타낸다.
Network Design
주로 사용한 모델의 구조는 GoogleNet. Conv Layer를 많이 쌓으면 연산량이 증가해서 중간에 Reduction Layer를 추가한 것을 확인할 수 있다.
Training Stage
어떻게 학습을 하는지에 대해서 다룸.
실제 객체가 있는 박스를 Groundtruth라고 하는데, 여기서 박스의 중앙에 점을 포함하고 있는 셀이 responsible한 셀이 되는 것이다.
학습을 할 때에는 한 가지 BBox를 사용을 하고, 여기서 BBox가 결정되는 기준이 IoU이다. Groundtruth와 겹치는 부분이 가장 많은 박스로 선택.
-> IoU가 가장 큰 값을 가진 박스는 노란색 박스이고, 여기서 스칼라값을 1로 표시하여 Loss Function에 반영이 되게 하였고, 다른 스칼라값은 0으로 두어 Loss Function에 반영이 되지 않게 하였다.
첫 번째는 모든 셀에 대해서 B개(예측하고자 했던 BBox 개수)의 BBox 좌표와 GT(GroundTruth) Box좌표의 오차를 구하는 공식
두 번째를 모든 셀에 대해서 B개의 확률값과 GT값의 오차를 구하는 공식
모든 셀의 confidence score와 정답 값의 오차를 구하는 공식
첫 번째 스칼라값: 몇 번째의 셀이 가장 예측력이 좋은 BBox를 표현
두 번째 스칼라값: 물체가 나타났는지(1) 아닌지(0)를 표현
세 번째 람다값: 어떤 BBox의 손실을 더 반영을 할 것인지를 표현
즉, 그리드 셀에 객체가 존재하는 경우의 오차와 예측 박스로 선정된 경우에만 오차를 학습한다.
Inference Stage(예측 단계)
첫 번째 BBox의 클래스 확률값과 학습 과정에서 구했던 Class Probability를 곱해서 각 바운딩 박스마다 구하게 된다.
이 과정대로 진행을 하게 된다면 BBox의 개수가 많아지게 되어, NMS(Non-Maximum Suppression) 알고리즘이 적용된다.
이 알고리즘을 통해 클래스 별로 비교를 해서 가장 예측력이 좋은 BBox만 남길 수 있다. 코드를 보면 특정 값을 넘지 않으면 0으로 처리
-> 예측값이 높은 BBox를 기준으로 내림차순 정렬
나머지 BBox는 BBox#12와의 IoU가 높아서 NMS에 의해서 제거된다.
만약 탐지해야되는 객체가 여러 개일 경우, 예측값이 높은 BBox끼리 IoU를 비교를 할 텐데, 이 때의 IoU는 낮은 값 또는 0의 값을 가지게 되므로 NMS에 의해서 제거되지 않는다.
서로 다른 Object가 있을 때
성능
속도: Fast YOLO >> YOLO >> DPM, R-CNN
성능: Faster R-CNN >> Fast R-CNN >> YOLO >> DPM
Limitaion
- 작은 물체에 대해서 탐지 성능이 낮음 -> BBox가 작게 되어서 IoU의 값 차이가 작아지게 되기 때문에
- 일반화된 지식이랑 다르게 객체 비율이 달라지면 detection 성능이 낮아짐.
YOLO9000: Better, Faster, Stronger
Main Contribution
- YOLOv2제안: YOLOv1의 단점을 개선하여 연산을 빠르게 정확도는 높임
- YOLO9000제안: Detection dataset의 적은 Class 개수로 인한 예측 가능한 class 개수의 증가. -> 존재하지 않은 클래스에 대한 예측도 가능해짐
- 새로운 classification network인 Darknet-19를 통해서 성능 향상
Better(Model: YOLOv2)
- batch normalization
이전 layer의 파라미터 변화로 인해 현재 layer의 입력 분포가 바뀌는 현상을 방지하기 위해서 사용. -> mini batch 사용하여 학습 시, 빠른 수렴 가능 + 정규화 효과를 통해서 overfitting 발생 X - high resolution classifier
YOLOv1에서는 classification에서는 저해상도를 사용해서 pretrain을 시킨다. 그 이후 task에서는 고해상도 사진을 넣고 Fine tuning 하는 과정을 거쳤는데, 이렇게 된다면 네트워크가 피팅되는데 시간이 걸린다.
Sol. 똑같이 저해상도 이미지로 pretrain을 한 다음 마지막 10 에포크 정도를 고해상도 이미지로 Fine-tunning 하게 한다. - Convolutional with anchor boxes
YOLOv2와 v1과의 차이
그리드 별로 anchor box 5개를 예측하되 anchor box의 원점은 grid cell 내에 존재하도록 예측해야된다.
output의 경우는 v1과 마찬가지고 x, y, w, h, Pc(클래스 예측 확률값)으로 나온다. - dimension clusters
생성한 anchor box를 기준으로 클러스터링을 수행하게 된다. -
K-means clustering에서 IoU를 사용하는 이유는 Euclidean distance를 사용하는 것 보다는 IoU를 사용하는 것이 더 정확한 결과값을 가져오기 때문이다. - anchor box를 어떻게 정의하는지를 말하고 있다.
- direct location prediction
-
시그모이드 함수를 사용함으로써 grid cell 내에 중심에 위치하도록(grid cell을 벗어나지 않도록) 하였다. - fine-grained features
26 _ 26_ 256 featuure map을 4등분하여 이를 stacking 하듯이 연결을 해서 이 feature map과 low reso feature map과 사이즈가 같아졌으므로 concatenate를 한다. - 이 과정을 통해서 Passthrough layer를 추가하여 High reso feature map을 Low reso feature map과 합치는 층이다.
- Multi-scale training
- FC층을 때고, one by one conv를 통해서 예측을 한다. 이렇게 되면 input 사이즈가 변해도 상관이 없게 된다.
Faster(Model: YOLOv2)
Global Average Pooling -> 채널별로 average pooling을 사용해서 1차원 벡터로 만들기 위함이다. 이를 통해서 Fc Layer를 사용할 때보다 params 개수가 크게 감소하였다.
Stronger(Model: YOLO9000)
- Hierarchical Classification
ImageNet의 클래스 구조가 트리 기반이 아님
-> Hierarchical Classification 학습을 통해서 WordTree를 생성한다. (강아지 > 푸들, 골든 리트리버 ,,) 이렇게 트리 기반 클래스 구조가 만들어 졌을 때, 상위 요소도 ground truth label로 propagate를 시킨다.
- Dataset Conbination ith WordTree
ImageNet + COCO 데이터셋 + ImageNet Detection을 합쳐서 9000개의 class label을 생성했다.
- Joint Classification and detection
- detection dataset과 classification dataset의 개수 차이가 크므로 oversampling으로 개수를 맞춥니다.
- detection dataset(훈련 데이터셋): propagate the loss(classification + bbox regression)
- classification dataset: propagate only classification loss
- COCO에 있는 데이터로 detection 학습 -> 9000개 객체에 대한 구분이 가능하다.
간단한 YOLO 구현
데이터셋 준비
자동차 인식 데이터셋 을 준비한다.
import pandas as pd
import numpy as np
import cv2
import matplotlib.pyplot as plt
box = pd.read_csv(
'./data/train_solution_bounding_boxes (1).csv')
box.head()
>>>
image xmin ymin xmax ymax
0 vid_4_1000.jpg 281.259045 187.035071 327.727931 223.225547
1 vid_4_10000.jpg 15.163531 187.035071 120.329957 236.430180
2 vid_4_10040.jpg 239.192475 176.764801 361.968162 236.430180
3 vid_4_10020.jpg 496.483358 172.363256 630.020260 231.539575
4 vid_4_10060.jpg 16.630970 186.546010 132.558611 238.386422
- testing_images folder: 테스트 데이터셋의 이미지
- training_images folder: 훈련 데이터셋의 이미지
- train_solution_bounding_boxes (1).csv: training_images의 객체가 있는 BBox의 위치(image(이미지 이름), xmin, ymin, xmax, ymax)
불러온 데이터셋 확인
sample = cv2.imread(
'./data/training_images/vid_4_1000.jpg')
sample = cv2.cvtColor(sample, cv2.COLOR_BGR2RGB)
point = box.iloc[0]
pt1 = (int(point['xmin']), int(point['ymax']))
pt2 = (int(point['xmax']), int(point['ymin']))
cv2.rectangle(sample, pt1, pt2, color=(255, 0, 0), thickness=2)
plt.imshow(sample)
cvtColor의 역할: 이미지 파일을 OpenCV 함수인 imread()를 통해서 열 때, BGR로 되어있는 색깔 순서를 RGB로 바꾸어 주는 역할을 한다.
YOLO 구현
# Yolo 로드
# 훈련된 가중치와 네트워크 구성을 저장하고 있는 파일을 불러옴.
net = cv2.dnn.readNet("./yolov3.weights",
"./yolov3.cfg")
# 클래스 카테고리를 가져옴.
classes = []
with open("./darknet/data/coco.names", "r") as f:
classes = [line.strip() for line in f.readlines()]
# 레이어 이름 가져오기
layer_names = net.getLayerNames()
# 만들어진 층에서 (13x13, 26x26, 52x52) Layer에 직접 접근해서 feature map 정보를 직접 가져와야 한다.
output_layers = [layer_names[i - 1] for i in net.getUnconnectedOutLayers()]
# 이미지 가져오기
img = cv2.imread(
'./data/training_images/vid_4_10000.jpg')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
height, width, channels = img.shape
Feature Map 정보를 사용해서 3개의 scale output layer에서 object detection 정보를 수집(결과를 받아온다.)
# 이미지를 blob으로 변환한다.
blob = cv2.dnn.blobFromImage(
img, 1/256, (416, 416), (0, 0, 0), swapRB=True, crop=False)
net.setInput(blob)
# outs는 출력으로 탐지된 개체에 대한 모든 정보와 위치를 제공한다.
outs = net.forward(output_layers)
Blob은 이미지에서 특징을 잡아내고 크기를 조정하는데 사용된다.
- 320 x 320: 작고 정확도는 떨어지지만 속도가 빠름
- 609 x 609: 정확도는 더 높지만 속도는 느림
- 416 x 416: 중간
cv2.dnn.blobFromImage(image, scalefactor=None, size=None, mean=None, swapRB=None, crop=None, ddepth=None) -> retval
- image: 입력 영상 / 이미지
- scalefactor: 입력 영상 픽셀 값에 곱할 값. 기본값은 1.
입력 이미지의 픽셀값을 0255로 했는지, 01로 정규화해서 이용했는지에 맞게 scalefacter를 곱했을 때 0~1이 나오도록 값을 결정해준다. - size: 출력 영상의 크기. 기본값은 (0, 0).
- mean: 입력 영상 각 채널에서 뺄 평균 값. 기본값은 (0, 0, 0, 0).
- swapRB: R과 B 채널을 서로 바꿀 것인지를 결정하는 플래그. 기본값은 False.
- crop: 크롭(crop) 수행 여부. 기본값은 False.
- ddepth: 출력 블롭의 깊이. CV_32F 또는 CV_8U. 기본값은 CV_32F.
정보를 화면에 표시
# 정보를 화면에 표시
class_ids = []
confidences = [] # 0에서 1까지의 탐지에 대한 신뢰도
boxes = [] # 감지된 개체를 둘러싼 사각형의 좌표
for out in outs:
for detection in out:
scores = detection[5:]
class_id = np.argmax(scores)
confidence = scores[class_id]
# 일단 신뢰도 0.5가 넘는 boxes 좌표만 가져오기
if confidence > 0.5:
# Object detected
center_x = int(detection[0] * width)
center_y = int(detection[1] * height)
w = int(detection[2] * width)
h = int(detection[3] * height)
# 좌표
x = int(center_x - w / 2)
y = int(center_y - h / 2)
boxes.append([x, y, w, h])
confidences.append(float(confidence))
class_ids.append(class_id)
# 동일한 개체에 대한 여러 박스 좌표들 중 제일 신뢰도가 높은 좌표를 제외하고 나머지는 제거하기 위한 코드(NMS)
indexes = cv2.dnn.NMSBoxes(boxes, confidences, 0.5, 0.4)
font = cv2.FONT_HERSHEY_PLAIN
colors = np.random.uniform(0, 255, size=(len(boxes), 3))
# 박스, label, confidence를 image 위에 그리는 코드
for i in indexes.flatten():
x, y, w, h = boxes[i]
print(x, y, w, h)
label = str(classes[class_ids[i]])
confidence = str(round(confidences[i], 2))
color = colors[i]
cv2.rectangle(img, (x, y), ((x+w), (y+h)), color, 2)
cv2.putText(img, label + " " + confidence,
(x, y+20), font, 2, (0, 255, 0), 2)
plt.imshow(img)
Total
def predict_yolo(img_path):
# 이미지 가져오기
img = cv2.imread(img_path)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
height, width, channels = img.shape
blob = cv2.dnn.blobFromImage(img, 1/256, (416, 416), (0, 0, 0), swapRB=True, crop=False)
net.setInput(blob)
outs = net.forward(output_layers)
class_ids = []
confidences = []
boxes = []
for out in outs:
for detection in out:
scores = detection[5:]
class_id = np.argmax(scores)
confidence = scores[class_id]
if confidence > 0.5:
# Object detected
center_x = int(detection[0] * width)
center_y = int(detection[1] * height)
w = int(detection[2] * width)
h = int(detection[3] * height)
# 좌표
x = int(center_x - w / 2)
y = int(center_y - h / 2)
boxes.append([x, y, w, h])
confidences.append(float(confidence))
class_ids.append(class_id)
indexes = cv2.dnn.NMSBoxes(boxes, confidences, 0.5, 0.4)
font = cv2.FONT_HERSHEY_PLAIN
colors = np.random.uniform(0, 255, size=(len(boxes), 3))
if len(indexes) > 0:
for i in indexes.flatten():
x, y, w, h = boxes[i]
print(x, y, w, h)
label = str(classes[class_ids[i]])
confidence = str(round(confidences[i], 2))
color = colors[i]
cv2.rectangle(img, (x, y), ((x+w), (y+h)), color, 2)
cv2.putText(img, label + " " + confidence, (x, y+20), font, 2, (0, 255, 0), 2)
plt.imshow(img)
else:
print('탐지된 물체가 없습니다.')
테스트
import glob
import random
paths = glob.glob('./data/testing_images/*.jpg')
img_path = random.choice(paths)
predict_yolo(img_path)
>>>
39 101 20 27
354 186 13 10
315 189 28 22
352 183 13 9
336 177 9 5
324 180 14 7
328 178 10 5
'Group Study (2022-2023) > Machine Learning' 카테고리의 다른 글
[Machine Learning] 6주차 스터디 - PART 2: Basic Deep Learning (2) / PART 3: Convolutional Neural Network (1) (0) | 2022.11.21 |
---|---|
[Machine Learning] 5주차 스터디 - PART 2: Basic Deep Learning (0) | 2022.11.18 |
[Machine Learning] 5주차 스터디 - Object Detection: -stage-detector (0) | 2022.11.13 |
[Machine Learning]4주차 스터디 - ResNet 논문 요약 및 코드실습 (0) | 2022.11.04 |
[Machine Learning] 3주차 스터디 - CNN의 이해(3) (0) | 2022.11.01 |