Python/PyTorch 공부

[Object Detection] YOLO(v3)를 PyTorch로 바닥부터 구현하기 - Part 1

AI 꿈나무 2021. 1. 10. 19:30
반응형

 YOLO를 알아보고, pytorch로 바닥부터 구현해보는 블로그가 있어 번역 해보기로 했습니다! 많은 공부가 될 것 같습니다ㅎㅎ

 

 블로그는 아래 링크에서 확인하실 수 있습니다.

 

 

Tutorial on implementing YOLO v3 from scratch in PyTorch

Tutorial on building YOLO v3 detector from scratch detailing how to create the network architecture from a configuration file, load the weights and designing input/output pipelines.

blog.paperspace.com

 

 객체 탐지는 딥러닝의 발전에 의해 큰 이점을 얻은 분야입니다. 최근 몇년 동안 사람들은 YOLO, SSD, Mask RCNN, RetinaNet를 포함하여 객체 탐지에 대한 많은 알고리즘을 발전시켜왔습니다.

 

 저자는 몇달 동안 연구실에서 객체 탐지를 향상시키기 위해 일해왔습니다. 이 경험에서 가장 중요하다고 느낀 점 중 하나는 객체 탐지를 배우는 가장 좋은 방법이 스스로 바닥부터 알고리즘을 구현해보는 것입니다. 이 튜토리얼에서 이것을 해볼 것 입니다.

 

 빠른 객체 탐지 알고리즘 중 하나인 YOLO v3을 파이토치로 구현해 볼 것입니다. 이번 튜토리얼에 대한 코드는 Python 3.5와 PyTorch 0.4에서 작동되도록 설계됬습니다. 전체 코드는 여기에서 확인할 수 있습니다.

 

 이 튜토리얼은 5 파트로 나뉘어져 있습니다.

 

1. Part 1 : (현재) YOLO가 어떻게 작동하는지 이해하기

2. Part 2 : 신경망 구조의 계층 생성하기

3. Part 3 : 신경망의 순전파 구현하기

4. Part 4 : 비-최대 억제(Non-maximum suppression)와 객체 점수 임계값

5. Part 5 : 입력값과 출력값 

 

사전 지식

  • CNN이 어떻게 작동하는지 이해하고 있어야 합니다. 또한 Upsampling, Residual Blocks, skip connetcion에 대한 지식을 갖고 있어야 합니다.
  • 객체 탐지, 바운딩 박스 regression, IoU, 비-최대 억제가 무엇인지 알고 있어야 합니다.
  • 기본적인 PyTorch 사용법. 간단한 신경망을 생성할 수 있어야 합니다.

 

 저자는 위 사전 지식에 미치지 못하는 경우를 위해 맨 아래에 link를 제공합니다.

 

YOLO는 무엇인가요?

 YOLO는 You Only Look Once를 나타냅니다. 객체를 탐지하기 위해 깊은 CNN에 의해 학습되어지는 특징들을 사용하는 객체 검출기 입니다. 코드로 손을 더럽히기 전에, YOLO가 어떻게 작동하는지 이해해야 합니다.

 

Fully Convolutional Neural Network(FCN)

 YOLO는 오직 convolutional layers만을 사용하여, fully convolutional network(FCN)을 만듭니다. upsampling layers와 skip connection을 지닌 75개의 convolutional layers을 지니고 있습니다. pooling이 사용되지 않고, feature maps를 down sample하기 위해 stride=2인 convolution layer가 사용됩니다. 이를 통해 pooling으로 인한 low-level features의 손실을 방지할 수 있습니다.

 

 FCN이기 때문에, YOLO는 입력 이미지의 크기에 영향을 받지 않습니다. 하지만, 실제로는 일정한 입력 사이즈를 고정합니다. 이는 알고리즘을 구현할 때, head에서 보이는 여러 문제들 때문입니다.

 

 이 문제들 중 가장 큰 것은 이미지를 배치(배치로된 이미지는 GPU로 병렬처리할 수 있습니다.)로 처리하고 싶을 때, 모든 이미지가 고정된 높이와 넓이를 가져야합니다. 이것은 큰 배치로 다수의 이미지들을 연결시켜야 합니다.(많은 PyTorch tensors를 하나로 연결시키는 것)

 

 신경망은 신경망의 stride라고 불리는 인자에 의해 이미지가 다운 샘플링 됩니다. 예를 들어, 신경망의 stride가 32이면, 416 x 416 크기의 입력 이미지는 13 x 13 크기의 출력값을 생성합니다. 일반적으로 신경망에서 어떤 layer의 stride는 layer의 출력값이 입력 이미지보다 작게 해주는 인자와 동일합니다.

 

출력값 이해하기

 일반적으로, (모든 객체 탐지기의 경우에) convolutional layer에서 학습된 features는 detection prediction(바운딩 박스 coordinates, class label, 등)을 하는 classifier/regressor로 전달됩니다.

 

 YOLO에서 1x1 convolution을 사용하는 convolutional layer를 사용함으로써 예측이 진행됩니다.

 

 현재, 알아둬야 할 첫 번째는 output이 feature map 입니다. 1x1 convolution을 사용하기 때문에, prediction map의 크기는 정확히 이전 feature map의 크기입니다. YOLO v3(또는 하위 버전)에서, 이 predeiction map을 이해하는 방법은 각 cell이 바운딩 박스의 고정된 숫자를 예측하는 것입니다.

 

feature map에서 unit을 설명하기 위한 기술적으로 정확한 용어는 neuron이긴 하지만, 이 포스팅에서 더욱 직관적으로 이해하기 위해 이것을 cell이라고 부릅니다.

최종적으로 feature map에 Bx(5+C) 항목들을 갖게 됩니다. B는 각 cell에서 예측한 바운딩 박스의 개수를 나타냅니다. 논문에 따르면 이러한 B 바운딩 박스들 각각은 특정 객체를 탐지하는 데에 전문화되어있습니다. 각 바운딩 박스들은 5+C 속성을 갖고 있으며, 이것은 각 바운딩 박스에 대한 center 좌표, 차원, objectness 점수를 갖고 있고 각 바운딩 박스에 대한 C class confidences를 갖고 있습니다. YOLO v3은 모든 cell이 3개의 바운딩 박스들을 예측합니다.

 

 feature map의 각 cell은 객체의 중심이 해당 cell의 receptive field에 맞아 떨어지면, 바운딩 박스 중 하나를 통해 객체를 예측합니다.(receptive field는 cell이 볼 수 있는 입력 이미지의 영역입니다.)

 

 YOLO가 어떻게 학습되는지 알아보았고, 단지 하나의 바운딩 박스는 특정 객체를 탐지하는 역할을 합니다. 첫 번째로, 어떤 cell이 이 바운딩 박스를 갖고 있는지 알아내야 합니다.

 

 이것을 하기 위해 입력 이미지를 최종 feature mpa과 동일한 차원의 grid로 분할합니다.

 

 아래 예제를 확인해보겠습니다.

 

 예제에서 입력 이미지는 416 x 416이고 신경망의 stride는 32 입니다. 앞서 설명한 것 처럼, feature map의 차원은 13 x 13이 될 것입니다. 그리고나서 입력 이미지를 13 x 13 cell로 분할합니다.

 

 

 그리고나서, 객체의 ground truth box의 center를 포함하고 있는 cell이 객체를 예측하기 위해 선택됩니다. 위 그림에서 ground truth box(노랑색)을 포함한 cell은 빨강색 입니다.

 

 이제 빨강 cell은 grid에서 7번째 행의 7번째 cell입니다. 개를 탐지하는 것으로서 feature map의 7번째 행, 7번째 cell로 할당합니다. 

 

 이제 cell은 3개의 바운딩 박스를 예측할 수 있습니다. 하나는 개의 ground truth label로 할당되었습니다. 이것을 이해하기 위해 anchor의 개념을 살펴봐야 합니다.

 

여기서 말하는 cell은 prediction feature map에서의 cell인 것을 기억해야 합니다.  prediction feature map의 cell이 예측을 담당하게 하도록 입력 이미지를 grid로 분할했습니다. 

 

Anchor Boxes

 바운딩 박스의 높이와 넓이를 예측하는게 합리적일 수 있지만 실제로 이것은 training 동안 불안정한 gradient를 발생시킵니다. 대신에 최근 객체 탐지기의 대부분은 log-space transform 또는 미리 정의된 기본 값 바운딩 박스 anchors를 간단히 offset한 것을 예측합니다.

 

 그리고나서 이러한 변환들은 prediction을 얻기 위해 anchor boxes에 적용시킵니다. YOLO v3은 각 cell에서 3개 바운딩 박스를 예측하기 위한 3개의 anchor를 갖고 있습니다.

 

예측 하기

 아래 수식은 신경망의 출력값이 바운딩 박스 predictions를 얻기 위해 어떻게 변화되는지 설명합니다.

 

 

 bx, by, bw, bh는 prediction의 x,y 중심 좌표, 넓이, 높이입니다. tx, ty, tw, th는 신경망의 output입니다. cx, cy는 grid의 좌측 상단의 좌표 입니다. pw, ph는 박스에 대한 anchor 차원입니다. 

 

중앙 좌표

 sigmoid function을 통하여 중앙 좌표 prediction을 실행했습니다. 이것은 출력값이 0에서 1이 되도록 합니다. 왜 이것이 사용되었을 까요?

 

 보통, YOLO는 바운딩 박스의 완벽한 중심 좌표를 예측하지 않습니다. 이것은 다음의 offset을 예측합니다.

  • 객체를 예측하는 grid cell의 좌측 상단 코너와 관련있습니다.
  • feature map으로부터 cell의 차원이 1로 정규화 되었습니다.

 

 예를 들어, 개 이미지의 경우를 생각해보겠습니다. 만약 중심이 (0.4, 0.7)로 예측되었으면, 이것은 13x13 feature map에서 중심이 (6.4, 6.7)에 놓여져 있다는 것을 의미합니다.(빨강 cell의 좌측 상단 좌표가 (6,6)이기 때문입니다.)

 

 만약 예측된 x,y co-ordinates가 1보다 큰 (1.2, 0.7)이면 어떤 일이 발생할 까요? 이것은 중심이 (7.2, 6.7)에 놓여 있다는 것을 의미합니다. 빨강 cell의 오른 쪽에 있는 cell에 중심이 놓여 있습니다. 이 cell은 7번째 행에서 8번째 cell이라고 부를 수 있습니다. 이것은 YOLO 이론에 어긋납니다. 빨강 cell이 개를 예측하는 역할을 한다고 상정했는데, 개의 중심이 빨강 cell에 놓여있지 않고 이것의 옆에 있는 cell에 놓여 있기 때문입니다.

 

 그러므로 이 문제를 완화하기 위해 출력값은 출력 값을 0에서 1 사이로 만들어주는 sigmoid function에 전달됩니다. 그리고 이것은 효과적으로 예측하는 grid에 중심이 위치하도록 합니다.

 

바운딩 박스의 차원

 바운딩 박스의 차원은 출력에 log-space 변환을 적용하여 예측될 수 있습니다.

 

 

 어떻게 검출기의 출력이 최종 prediction 이 되도록 변환될까요?

 

  결과로 생긴 예측 bw, bh는 이미지의 높이와 넓이로 normalize 됩니다.(trining label은 이 방법으로 선택됩니다.) 따라서 만약 개를 포함하는 박스에 대한 prediction bx, by가 (0.3, 0.8) 이면 13x13 피쳐맵에서 실제 높이와 넓이는 (13 x 0.3, 13 x 0.8)입니다.

 

Objectness Score

 객체 점수는 바운딩 박스에 객체가 포함되어 있을 확률을 나타냅니다. 이것은 빨간색 및 인접 grid의 경우 거의 1이고, 예를 들어 모서리의 grid의 경우 거의 0이어야 합니다.

 

 objectness score은 확률로써 설명되기 때문에 sigmoid로 전달됩니다.

 

Class Confidences

 Class confidence는 검출된 객체가 특정 class(개, 고양이, 바나나, 차 등등)를 지니고 있을 확률을 나타냅니다. v3 이전에 YOLO는 class score에 softmax가 사용되었습니다.

 

 하지만 그 설계 선택은 v3에서 사라졌고 저자는 대신에 sigmoid를 사용하기로 선택했습니다. 이유는 Softmaxing class scores는 classes가 상호 배타적으로 가정하기 때문입니다. 간단히 말하면, 만약 객체가 하나의 class를 갖고 있으면 이것은 다른 class를 지니지 않는 것을 보장합니다. 여기서 사용할 COCO database에 대해서는 괜찮습니다.

 

 하지만 이 가정은 Women과 Person 같은 class를 지니고 있을 때, 어긋납니다. 이러한 이유로 저자는 Softmax activation 사용을 피했습니다.

 

서로 다른 scale에서 예측

 YOLO v3은 3개의 다른 scale에서 예측을 합니다. detection layer는 각각 stride = 32, 16, 8을 지닌 서로 다른 크기의 feature map에서 검출하기 위해 사용됩니다. 이것은 416 x 416 입력이 있을 때, 13 x 13, 26 x 26, 52 x 52 규모로 탐지를 하는 것을 의미합니다.

 

 신경망은 첫 번째 detection layer까지 입력값을 downsample 합니다. 여기서, detection은 stride=32를 지닌 layer의 feature map을 사용하여 진행됩니다. 추후에 layers이 2배로 upsample되고 동일한 feature map 크기를 지닌 이전 layer의 feature amp과 함께 연결됩니다. 또 다른 detection은 stride=16인 layer에서 만들어 집니다. 동일한 upsampling 절차가 반복되고 마지막 detection은 stride=8인 layer에서 만들어 집니다.

 

 각각의 scale에서 각 cell은 3개의 anchors를 사용하여 3개의 바운딩 박스를 예측하고, 사용된 총 anchor 수를 9로 만듭니다.(anchore는 서로 다른 scale을 지니고 있습니다.)

 

 

 저자는 이를 통해 YOLO v3이 작은 물체와 YOLO의 이전 버전에서 빈번한 error를 보다 잘 감지하는 데 도움이 된다고 말합니다. Upsampling은 신경망이 작은 물체를 탐지하는 데 중요한 세밀한 features를 학습하는데 도움을 줄 수 있습니다. 

 

Output Processing

 416 x 416 크기의 이미지에 대해 YOLO는 ((52x52) + (26x26) + 13x13)) x 3 = 10647 개의 바운딩 박스를 예측합니다. 하지만 우리의 이미지의 경우에 단지 하나의 객체(개)만 있습니다. 어떻게 탐지를 10647에서 1로 감소시킬 수 있을 까요?

 

 

Thresholding by Object Confidence

 첫 번째로, objectness score에 근거하여 박스들을 걸러냅니다. 일반적으로 임계값 아래의 점수를 지니고 있는 박스들은 무시됩니다.

 

비-최대 억제(Non-maximum Suppression)

 NMS는 동일한 이미지에서 다수의 검출 문제를 해결합니다. 예를 들어, 빨강 grid cell의 3개 바운딩 박스 모두는 박스를 검출하거나 인접 cell은 동일한 물체를 검출할수도 있습니다.

 

 

 아래 링크에서 NMS에 대해 알아볼 수 있습니다.

 

 

[Object Detection] 비-최대 억제(NMS, Non-maximum Suppression)를 이해하고 파이토치로 구현하기

 안녕하세요! 이번 포스팅에서는 비-최대 억제(NMS,Non-maximum Suppression)을 알아보도록 하겠습니다.  비최대 억제를 이해하기 위해서는 IoU(intersection over unio)에 대한 개념을 알아야합니다.  IoU에..

deep-learning-study.tistory.com

 

이번 튜토리얼에서 구현

 YOLO는 오직 신경망을 학습하는 데 사용된 dataset에 존재하는 classes를 지니고 있는 객체들만 탐지할 수 있습니다. 또 공식적으로 제공되는 YOLO의 weight file을 사용할 것입니다. 이 weight들은 COCO dataset로 신경망을 학습하여 얻어졌습니다. 그러므로 80개 객체 범주를 탐지할 수 있습니다.

 

 이제까지 첫 번째 part였습니다. 이 포스팅은 YOLO를 구현할 수 있도록 충분히 YOLO에 대해 알아보았습니다. 하지만 YOLO가 어떻게 작동하고, 어떻게 학습되었고, 다른 detector와 비교하여 어떤 성능을 내는지 깊게 파보고 싶다면 논문을 읽어보세요.

 

 첫 번째 part가 끝났습니다. 다음 part에서 detector를 구성하는 데 필요한 다양한 layer를 구현하겠습니다.

반응형