오늘의 인기 글
최근 글
최근 댓글
Today
Total
05-04 00:00
관리 메뉴

우노

[DL] Object Detection (Sliding Windows, YOLO) 본문

AI/Deep Learning

[DL] Object Detection (Sliding Windows, YOLO)

운호(Noah) 2021. 2. 10. 14:54
  • Object Detection에는 여러가지 Algorithm이 존재합니다.

    • Sliding Windows Detection
    • YOLO Detection
  • 하나하나 다뤄보겠습니다.

Sliding Windows Detection

  • 자동차 감지 알고리즘을 만들고 싶다고 가정해봅시다.

  • 그렇다면, Sliding Windows Detection은 다음과 같은 순서로 진행됩니다.

  • 1) 우선 X와 y로 Training Set를 만듭니다.

    • 이 때, X는 자동차만 표현하도록 딱 맞게 자른 이미지입니다.
  • 2) Training Set이 다 만들어졌다면, Training Set의 X를 Input으로 주는 ConvNet을 학습시킵니다.

    • ConvNet은 y를 출력하며, y는 자동차인지 아닌지를 0 또는 1로 나타냅니다.
  • 3) ConvNet 학습이 끝났다면, Test 이미지를 통해 성능을 Test 합니다.

    • Test 이미지를 입력 받은 뒤, Training 시 사용한 Window 크기 만큼 이미지를 잘라, 학습한 ConvNet의 입력으로 넣습니다.
    • ConvNet은 해당 Window에 Car가 있는지 없는지 판단하며, 결과를 0 또는 1로 나타냅니다.
    • 이는, Window가 이미지의 끝에 도착할 때까지 Sliding하며 반복됩니다.
    • 이를 완료하면, Test 이미지 내부의 잘라진 Window 각각은, 0 또는 1로 분류될 것입니다.
    • Window 중 1이 있다면 해당 Test 이미지에는 Car가 있는 것입니다.
    • 이를 Sliding Window 라고 부릅니다.
  • 하지만, Sliding Windows Detection 에는 커다란 단점이 하나 있습니다.

  • 바로 계산 비용입니다.

  • Sliding Windows Detection은 이미지에 있는 많은 사각 영역들을 잘라내고, ConvNet을 통해 각각을 독립적으로 실행시키기 때문에 계산 비용이 많이 듭니다.

  • 만약, 여러분이 아주 큰 스트라이드나 아주 큰 Window를 사용해 Sliding 한다면, ConvNet에 보내야할 Window의 숫자는 줄어들게 돼 계산 비용은 줄어들게 되지만,

  • 수행력에 안 좋은 영향을 줄 수도 있습니다.

  • 이러한, 계산 비용 문제는 다행이도 좋은 해결책을 가지고 있습니다.

  • 따라서 해결책 중 하나인, Convolutional Implementation of Sliding Windows에 대해서 알아보겠습니다.

Convolutional Implementation of Sliding Windows

  • 위에서 다룬 Sliding Windows Detection은, 이미지의 Window 크기마다 ConvNet을 실행하며,

  • Window가 이미지 끝에 도달할 때 까지 반복해야하므로, 매우 느리다는 단점을 가지고 있었습니다.

  • 하지만 Convolutional Implementation of Sliding Windows는 각각의 Window에 ConvNet을 실행할 필요 없이, 전체 Window에 한 번의 ConvNet만 실행 할 수 있습니다.

  • 예제를 통해 알아보겠습니다.

  • 아래 그림은, Sliding Windows Detection에서 사용되는 기존의 ConvNet 구조입니다.

    • 입력(Window)을 받아 4가지 객체 중 하나로 분류하는 예제이며
    • 기존의 ConvNet 구조에는 Fully Connected Layer가 존재합니다.
  • 아래 그림은, Convolutional Implementation of Sliding Windows에서 사용되는 ConvNet의 구조입니다.

    • 기존 ConvNet 구조에서 Fully Connected Layer를 Convolution Layer로 변환한 구조입니다.
    • Fully Connected Layer를 Convolution Layer로 변환함으로써, 해당 ConvNet을 전체 이미지에 적용할 수 있게 됩니다.
  • 변환한 ConvNet이 왜 효율적인지 자세히 알아보겠습니다. (아래 그림은 2차원만 표현한 그림입니다.)

    • 위 그림의 상단 예시는 14x14x3 이미지를 변환한 ConvNet을 사용해 Convolution한 결과입니다.
      • 14 x 14 x 3 이미지를 ConvNet을 통해 Convolution하니 1 x 1 x 4 의 결과가 나옵니다.
    • 하단 예시는, 16x16x3 이미지를 변환한 ConvNet을 사용해 Convolution한 결과입니다.
      • 16 x 16 x 3 이미지를 ConvNet을 통해 Convolution하니 2 x 2 x 4 의 결과가 나옵니다.
      • 이는, 전체 이미지에 대해 4개의 Label을 얻은 것과 동일합니다.
    • 만약, 기존의 ConvNet 방식이었다면 위와 같이 4개의 Label을 얻기 위해선
    • 16x16x3 이미지를 4가지 Window로 나눈 뒤, 각 Window 영역에서 ConvNet을 독립적으로 실행해 4개의 Label을 얻었을 것입니다.
    • 하지만, 위처럼 변환된 ConvNet을 이미지 전체에 사용한다면, 한 번의 Covolution을 통해 4개의 라벨값이 나오게 됩니다.
    • 이러한 방법은 공통 이미지 영역에 있는 많은 계산을 공유하기 때문에 빠릅니다.
  • 따라서, 아래 그림과 같이 28 x 28 x 3 이미지가 들어왔을 때, 한번의 Convolution으로 64(8x8)개 영역의 label 값을 얻을 수 있게 됩니다.

    • 하지만, 이러한 방법에도 각 Bounding Box가 객체를 정확하게 표현하지 못한다는 단점이 존재합니다.

YOLO Detection

  • 지금까지 Sliding Windows Detection 및 Convolutional Implementation of Sliding Windows에 대해서 알아보았습니다.

  • 하지만, Sliding Window로 이미지 영역을 한 칸씩 밀면서 객체를 감지하다보면, Bounding Box와 객체가 완벽하게 일치하지 않을 수 있다는 단점이 있었습니다.

  • 또한, Bounding box는 보통 정사각형이 아닌 직사각형입니다.

  • 따라서, Bounding Box 예측을 보다 정확히 하기 위해 YOLO 알고리즘이 사용됩니다.

    • YOLO는 You Only Look Once의 약자입니다.
  • YOLO의 기본 아이디어는, 아래 그림과 같이 이미지 분류 및 객체 위치 측정을 Sliding Window가 아닌 Grid로 나누어 적용하는 것입니다.

  • 또한, YOLO는 Training Set을 위한 Target Label y도 Sliding Window Detection 방법과 다르게 정의됩니다.

  • 예시를 통해 Target Label y에 대해서 알아보겠습니다.

  • 위 그림과 같이, Input X에 대한 Target Label y는 각 그리드 셀에 대해 Class Label(c1, c2, c3) 과 Bounding Box(bx, by, bh, bw) 로 구성됩니다.

  • 각 그리드 셀을 구체적으로 보면, 위 예제를 기준으로 [Pc, bx, by, bh, bw, c1, c2, c3]가 됩니다.

    • Pc (Probability of Class) : 이미지 내에 "객체가 있는가?"를 의미합니다.

      • Pc = 1이면 Object가 존재한다는 뜻이며
      • Pc = 0이면 Object가 없는 background라는 뜻입니다.
    • bx, by, bh, bw : 이미지 내 객체의 Bounding Box 좌표를 의미합니다.

      • bx : bounding box의 중심점 x좌표
      • by : bounding box의 중심점 y좌표
      • bh : bounding box의 높이
      • bw : bounding box의 너비
    • c1, c2, c3 : 어떤 객체로 분류되는가를 의미합니다.

      • Class1(Pedestrian), Class2(Car), Class3(Motorcycle)
  • 따라서, YOLO Detection은 다음과 같은 순서로 진행됩니다.

  • 1) 우선 X와 y로 Training Set를 만듭니다.

    • 객체를 탐지한 그리드 셀은, y = [1, bx, by, bh, bw, 0, 1, 0] 으로 구성할 수 있습니다.
      • 객체를 탐지한 그리드 셀의 벡터는
      • Pc = 1 이 되고, 객체에 해당하는 Class만 1이 됩니다.
      • 그 다음으로는, 객체의 Bounding Box 좌표(bx, by, bh, bw)가 할당됩니다.
    • 객체를 탐지한 그리드 셀은, y = [0, ?, ?, ?, ?, ?, ?, ?] 으로 구성할 수 있습니다.
      • 그리드 셀 내에 객체가 없기 때문에 Pc = 0 이 되고 나머지 원소는 어떤 값이 와도 의미가 없습니다.
    • 각각의 그리드 셀은 객체 Bounding box의 중심점을 가지고 있을 때만, Pc 가 1이 됩니다.
    • 따라서, 객체는 전체 그리드 셀 중 하나의 그리드 셀에만 할당되게 됩니다.
  • 2) Training Set이 다 만들어졌다면, Training Set의 X를 Input으로 주는 ConvNet을 학습시킵니다.

    • YOLO의 ConvNet은 Convolutional Implementation을 사용하기 때문에,
    • 각 그리드 셀마다 ConvNet을 학습하지 않고, 전체 그리드에 대해 한 번의 학습을 진행합니다.
    • 이러한 연산은 각 그리드 간 많은 연산이 공유되므로 효율적인 알고리즘이 됩니다.
  • 3) ConvNet 학습이 끝났다면, Test 이미지를 통해 성능을 Test 합니다.

    • 위 그림에서는, 3 x 3 grid로 Test 하고 있지만, 보통 19 x 19 grid 같은 미세한 그리드를 사용해, 동일한 그리드 셀 안에 여러 객체가 할당 될 가능성을 줄여줍니다.
    • 따라서, 위와 같은 이미지로 테스트 한다면, 각 그리드 셀에 대한 Label이 총 9개 나올 것이며, 각 Label은 8차원 벡터값을 가지고 있을 것입니다.
      • 각 라벨 벡터는
      • 객체를 탐지한 그리드 셀은 y = [1, bx, by, bh, bw, 0, 1, 0] 가 될 것이며
      • 객체를 탐지하지 못한 그리드 셀은 y = [0, ?, ?, ?, ?, ?, ?, ?] 가 될 것 입니다.
    • 각각의 그리드 셀은 객체 Bounding box의 중심점을 가지고 있을 때만, Pc 가 1이 됩니다.
    • 따라서, 객체는 전체 그리드 셀 중 하나의 그리드 셀에만 할당되게 됩니다.
    • 또한, 각 그리드 마다 해당 그리드 셀의 좌측 상단 좌표를 (0,0) 우측 하단 좌표를 (1,1)로 사용하기 때문에, bx, by는 0과 1사이의 값을 가지며
    • 객체의 Bounding Box는 해당 그리드 셀을 넘어갈 수 있기 때문에, bh, bw는 1보다 클 수 있습니다.

Intersection Over Union

  • 객체 탐지 알고리즘이 잘 작동하는지 확인하기 위해선 IOU 방법을 사용합니다.

  • 위 그림에서, 빨간색이 실제 객체의 Bounding Box이며, 보라색이 예측한 객체의 Bounding Box라면

  • IOU는 아래 그림과 같이, [ 두 Bounding Box의 교집합 / 두 Bounding Box의 합집합 ] 으로 계산할 수 있습니다.

  • IOU가 높을수록 성능이 좋은 것이며, 낮을수록 성능이 안 좋은 것입니다.

Non-max Suppression

  • 지금까지 배운 Object Detection의 문제는, 알고리즘이 동일한 객체에 대해 다수의 탐지체를 찾을 수 있다는 것입니다.

    • Training 시에는 객체의 중심점에 있는 그리드 셀만 Pc = 1로 설정해 객체를 인식한 것으로 다뤘지만
    • Test 시에는 각 그리드 셀 마다 객체의 중심점을 가지고 있다고 인식할 수 있습니다.
  • 따라서, Non-max Suppression은 다수의 객체로 인식한 결과에 대해, 동일한 객체를 인식한 것으로 정리하는 방법입니다.

  • 19 x 19 입력에 대해, 그리드를 사용해 객체를 탐지하는 예시를 들어보겠습니다.

    • 그림에서 각각의 객체는 중간 지점이 하나뿐이므로, 정상적이라면 객체마다 그리드 셀 하나가 할당되는 것이 맞습니다.
    • 하지만, 실제로는 361개의 그리드 셀 모두 각각 이미지를 분류하고 있기 때문에,
    • 각각의 그리드가 "여기에 객체가 있다"라고 인식할 확률이 큽니다.
    • 따라서, Non-max Suppression을 통해 다수의 객체로 인식된 결과에 대해 동일한 객체를 인식한 것으로 정리하는 과정이 필요합니다.
  • Non-max Suppression이 어떻게 진행되는지 알아보겠습니다.

    • 우선, 19 x 19 그리드 셀을 사용해 객체 탐지가 끝나면, 361개의 그리드 셀은 각각 아래와 같은 Label vector를 가지고 있을 것입니다.
      • [Pc, bx, by, bh, bw]
      • 이 때, Pc는 해당 그리드 셀이 객체를 가지고 있을 확률을 의미하며, bx, by, bh, bw는 객체로 예측한 바운딩박스 좌표를 의미합니다.
    • 따라서, 위 그림의 왼쪽 객체를 탐지한 그리드 셀들은 0.8, 0.7의 Pc 값을 가지고 있으며
    • 오른쪽 객체를 탐지한 그리드 셀들은 0.6, 0.9, 0.7의 Pc 값을 가지고 있게 됩니다.
    • 이후, Non-max Suppression은 다음과 같은 순서로 진행됩니다.
      • 우선, 전체 그리드 셀에 대해, Pc 값이 특정 임계값보다 작은 예측은 제거합니다.
      • 남은 그리드 셀에 대해, Pc 값이 가장 큰 그리드 셀을 고릅니다.
        • 위 예제에서는, 오른쪽 객체의 0.9 그리드 셀이 골라질 것입니다.
      • Pc 값이 가장 큰 그리드 셀과 전체 그리드 셀의 IOU를 구해, IOU 값이 높은 그리드 셀들은 동일한 객체를 탐지하고 있는걸로 간주하고 제거합니다.
        • 위 예제에서는, 오른쪽 객체의 0.6 그리드 셀과 0.7 그리드 셀이 제거될 것입니다.
      • 남은 그리드 셀에 대해, Pc 값이 가장 큰 그리드 셀을 고릅니다.
        • 위 예제에서는, 왼쪽 객체의 0.7 그리드 셀이 골라질 것입니다.
      • Pc 값이 가장 큰 그리드 셀과 전체 그리드 셀의 IOU를 구해, IOU 값이 높은 그리드 셀들은 동일한 객체를 탐지하고 있는걸로 간주하고 제거합니다.
        • 위 예제에서는, 왼쪽 객체의 0.6 그리드 셀이 제거될 것입니다.
    • 이와 같은 과정을 반복하면, 결국 동일한 객체에 대해 하나의 그리드 셀만 탐지한 것처럼 정리될 것입니다.
  • 위와 같은 알고리즘이 non-max suppression 이며

  • 위 예제에서는, 단 하나의 객체만 탐지하는 알고리즘을 설명했습니다.

  • 하지만 만약, 보행자, 오토바이 등 여러 객체를 추가로 탐지한다면

  • Label Vector에는 c1, c2, c3와 같은 추가적인 구성 요소가 생깁니다.

  • 이 땐, 각 class 당 non-max suppression을 독립적으로 수행하면 됩니다.

Anchor Boxes

  • 지금까지 다룬 객체 탐지 문제 중 하나는, 각 그리드 셀이 하나의 객체만 감지 할 수 있다는 것입니다.

  • 하지만 객체 탐지 시, 각 그리드 셀 안에는 여러 객체가 포함되어 있을 수도 있습니다.

  • 예제를 통해 살펴보겠습니다.

  • 이 예제에서는 3 x 3 그리드를 계속 사용하겠습니다.

  • 위 그림을 보시면, 보행자의 중심점과 차량의 중심점이 거의 같은 위치에 있으며, 둘 다 동일한 그리드 셀에 속해 있는 것을 볼 수 있습니다.

  • 만약, 해당 그리드 셀이 기존의 Label Vector [Pc, bx, by, bh, bw, c1, c2, c3] 를 사용한다면, 우리는 두 가지 객체를 탐지할 수 없습니다.

    • [Pc, bx, by, bh, bw, c1, c2, c3] Vector를 사용한다면, 1개의 Bounding Box 좌표만 할당할 수 있으므로 1개의 객체만 탐지할 수 있습니다.
  • 따라서, Anchor Boxes라는 개념이 나타났습니다.

  • Anchor Boxes는 아래 그림과 같이, 탐지하려는 객체의 모양을 미리 정의해놓고 객체가 탐지되었을 때 어떤 Anchor box와 유사한지 비교해 Vector 값을 할당하는 방식입니다.

    • Anchor Boxes는 5개 또는 그 이상 사용할 수 있지만
    • 설명을 쉽게 하기 위해 2개의 Anchor Box만 사용하겠습니다.
  • 예제를 통해 Anchor Boxes 과정을 살펴보겠습니다.

    • 위 그림과 같이 2가지 Anchor Boxes를 사용한다면, 각 그리드 셀은 2가지 객체에 대한 Target Label y 값을 가질 수 있으며 2개의 Vector를 이어붙인 형태가 됩니다.

    • 우선, Test 과정에서 각 그리드 셀은 객체를 탐지하며, 탐지한 객체의 Bounding Box가 Anchor box 1과 유사한지 Anchor box2와 유사한지 IOU를 통해 계산합니다.

    • IOU 계산 후, 높은 Anchor box Vector 자리에 값을 할당합니다.

    • 따라서, 아래 그림과 같이 각 그리드 셀이 무엇을 인식하느냐에 따라 Targe Label y 값이 할당됩니다.

      • 사람과 차를 인식했을 경우에는 [1, bx, by, bh, bw, 1, 0, 0, 1, bx, by, bh, bw, 0, 1, 0] 이며
      • 차만 인식했을 경우에는 [0, ?, ?, ?, ?, ?, ?, ?, 1, bx, by, bh, bw, 0, 1, 0] 입니다.
Comments