YOLO v1 논문보기

ROI crop 여부에 따른 탐색 방법 구분

ROI: 객체 여부를 확인하는 영역

  • O - 2-stage: R-CNN

  • X - 1-stage: YOLO

Convolutional 연산에 대한 고찰

  • input의 중심 픽셀 위치 = output의 픽셀 위치


  • input의 최다 참여 픽셀 위치 = output의 중심 픽셀 위치
    • 상하좌우 대각선 인접한 칸의 숫자 (자신의 칸 포함)만큼 사용된다.
    • 4 6 4
      6 9 6
      4 6 4

  • 2, 2 픽셀에는 원본의 2, 2 픽셀과 그 주위 픽셀들이 반영
    • ConV연산은 픽셀의 위치 정보가 유지된다.
      (원본의 위치 정보가 유지되면서 피처맵이 계산된다.)



  • Pooling 피처맵과 convolution 피처맵 비교 
    • 1,1 픽셀에 상응하는 이전 피처맵은 좌측 상단 4px이다.


  • 결론:
    • Conv연산 만으로도 각각 예측한 값이 구분되어(위치정보) 있다.
    • ROI가 필수는 아니다.

  • 연습
    • 224 x 224 이미지가 input 될 때, 아래 조건에 해당하는 모델을 기준으로 최종 피처맵이 몇이 될까요?

    • 조건1: conv(3x3, pad) x 2 + pool(2x2) 을 한 블록으로 구성
      (stride 설정: conv=1, pool=2)
      • 1블록: 112 x 112 (절반으로 축소)

    • 조건2: 총 5블록으로 구성
      • 2^5 = 32
      • 224/32 = 7
      • 7 x 7

    • 조건3: conv에서 필터 개수는 16개부터 시작하여, 블록마다 2배씩 증가
      • 16, 32, 64, 128, 256
      • 7 x 7 x 256

    • 224 x 224 x ch 이 7 x 7 x ch 이 된 것은 원본을 49픽셀(7x7)로 나누어 각 그리드 영역별로 객체 추론을 한다.

YOLO v1 논문 읽기

  • 448 x 448 x 3 >> Convolution... pool... >> 7 x 7 x 30

  • 1 x 1 x 30 에는 64 x 64 x 3 이 압축되어 있다.

  • 30개의 채널은 30개의 추론 값을 말한다.

  • 이때 1개의 추론 값은 해당 영역의 추론 값(객체 레이블과 위치정보)이 있다.

YOLO v1 단계

  1. Resize image
    이미지 사이즈 전처리

  2. Run convolutional network
    448 x 448 x 3   >>   7 x 7 x 30

  3. Non-max suppression (NMS)
    추론할 필요가 없는 (7x7=49)x2 값은 탈락시킨다.

30개 채널 값 구성

  • 30 = [xywh + confidence] x 2 + cls_prob(20)

  • b-box의 정확한 위치 값을 위해 2개 그려서 confidence기준으로 하나만 살린다.
    [ xywh + confidence ]

  • 참고로 객체의 b-box는 (7x7) 그리드를 벗어날 수 있음. 

Confidence score

  • 물체를 잡았을 확률

  • 논문:
    • score = 0 또는 IOU
    • 물체를 잡았다고 해도 같은 취급을 할 수 없다.
    • B-BOX로 IOU값을 나온 뒤에야 score를 산출할 수 있다.

  • 편의:
    • score = 0 또는 1
    • 물체만 잡으면 다같이 1로 보자

추론 알고리즘

  1. class별로 98(=49*2)개의 Confidence_score가 계산. 그 중 대부분은 0에 가까운 값.

  2. Threshold(Confidence 임계값)를 넘지 못하는 작은 score는 모두 제거 - 1차 제거

  3. 살아남은 Confidence_score 중에도 서로 같은 object를 추론한 값들이 대부분일 것이다.

  4. maximum과 일정(IOU Threshold)이상 겹치는 non-max score(NMS)는 모두 제거 - 2차 제거


생각해보기

  • Threshold의 기준을 높게 잡으면, 제거가 많아진다.
    • 인식 갯수가 적어진다.

  • 겹치는 건 버린다고 할 때, 겹침 정도(IOU Threshold)의 기준을 높게 잡으면, 제거가 줄어든다.
    • 인식 갯수가 많아진다.
    • Precision이 떨어진다. recall은 상승한다.

  • Threshold, IOU Threshold는 데이터셋을 기준으로 레퍼런스 값을 사용한다. 순서는 크게 중요치 않으나 Threshold부터 정하고 IOU Threshold를 정한다.

loss function

SSE (or MSE): regression loss 방식

  1. Bbox x, y 오차
    x, y, w, h에 가중치 x5를 추가한다.

  2. Bbox w, h 오차
    루트: 큰 물체에 대한 예측 오차를 해소하기 위해서

  3. Bbox confidence(=C) 오차 (ob)
    obj_sum 대비 noobj_sum 의 갯수가 더 많으므로 가중치 x0.5를 추가한다.

  4. Bbox confidence(=C) 오차 (no-ob)

  5. Grid class prob 오차


YOLO의 정답 모양

  • 객체 1개의 정답은 한 픽셀만 갖고 있는다.
    • 객체의 중심 x, y를 갖고 있는 픽셀

  • 정답 픽셀은 box가 1개만 있다. (0~24)까지만 사용한다.
  • 가로 x 세로 x (num_classes+ 2*xywhc)
    • num_classes[0:20]
    • confidence[20]
    • xywhc[21:25]

  • 나머지 픽셀은 (num_classes+ 2*xywhc)이 모두 0이다.
    • (0~24)의 값이 모두 0이다. 

YOLO의 정답 비교코드

  • 같은 픽셀에 위치한 예측 bbox2개와 정답 bbox를 쌍으로 가져가서 iou를 계산한다.
    • (예측1[21:25], 정답[21:25]) , (예측2[26:30], 정답[21:25])
    • iou_b1 = compute_iou(predictions[..., 21:25], target[..., 21:25]) 
      # (batch_size, S, S, 1)
    • iou_b2 = compute_iou(predictions[..., 26:30], target[..., 21:25]) 
      # (batch_size, S, S, 1)


  • IOU 계산은 xmin, ymin, xmax, ymax로 치환하여,
    IOU = inter / union 으로 값을 구한다.
    • intersection
      x1 = torch.max(box1_x1, box2_x1) # 두 박스의 xmin 중 큰 값
      y1 = torch.max(box1_y1, box2_y1) # 두 박스의 ymin 중 큰 값
      x2 = torch.min(box1_x2, box2_x2) # 두 박스의 xmax 중 작은 값
      y2 = torch.min(box1_y2, box2_y2) # 두 박스의 ymax 중 작은 값
      intersection = (torch.clamp(x2 - x1, min=0) * torch.clamp(y2 - y1, min=0))
      # 아예 겹치는 부분이 없으면, 위 수식의 결과 '-' 값이 나옴. min으로 하면 0
       

  • 객체상으로 (num_classes+ 2*xywhc) 30칸이 있던 자리에 각 박스의 IOU만 남긴다.
    • ious = torch.cat(
                   [iou_b1.unsqueeze(-1), iou_b2.unsqueeze(-1)], dim=-1
               )  # (batch_size, S, S, 2)


  • 각 IOU 중 큰 값의 박스 위치(bestbox)를 알아낸다. 예측1[21:25] 구간인지, 예측2[26:30]구간인지
    • iou_maxes, bestbox = torch.max(ious, dim=-1) 


  • 정답 confidence를 구한다.
    • exists_box = target[..., 20].unsqueeze(-1)


  • bextbox 위치에 박스 예측값을 엇갈려 곱해, bestbox값을 살린다. 그 bestbox에 정답 confidence를 곱해서, 정답을 갖고 있는 픽셀에 해당하는 예측값만 남긴다.
    • box_predictions = exists_box * ( bestbox * predictions[..., 26:30]
                                                + (1 - bestbox) * predictions[..., 21:25]

댓글 쓰기

다음 이전