[17일 차] YOLOv5 - Mask Wearing detection

Kimsoohyun·2022년 4월 14일
0
post-thumbnail

※ Notification
본 포스팅은 작성자가 이해한 내용을 바탕으로 작성된 글이기 때문에 틀린 부분이 있을 수 있습니다.
잘못된 부분이 있다면 댓글로 알려주시면 수정하도록 하겠습니다 :)

Intro

오늘은 YOLO의 각 버전별 특징을 확인하고, YOLOv5 모델을 코드를 통해 사용해보는 시간을 가졌다.

YOLOv3 ~ v5

YOLOv3는 YOLO를 만든 Joseph Redmon에 의해 2018년 4월 발표되었다. 백본 아키텍처 Darknet(C, CUDA로 작성된 오픈소스 신경망 프레임워크) 기반으로 만들어졌다.
Joseph Redmon은 YOLOv3를 마지막으로 더이상 YOLO 모델을 개발하지 않겠다고 했다.
들리는 소문에 의하면 YOLO 모델이 전쟁에서 군사적인 목적으로 사용된다는 것을 듣고 개발을 중단했다고 한다.

때문에 YOLOv4는 YOLOv3의 개발자가 아닌 Alexey Bochkovskiy가 2020년 4월에 발표하였다.
v3에 비해 AP, FPS가 각각 10%, 12% 향상되었다.

YOLOv5는 YOLOv3를 PyTorch로 구현한 Glenn Jocher가 2020년 6월에 발표했다.
v4에 비해 낮은 용량과 빠른 속도를 가지고 있으나 Darknet이 아닌 PyTorch 구현이므로 이전 버전과 다르다고 할 수도 있다. 때문에 처음 출시될 때 논문과 함꼐 출시되지 않았고, 이름을 YOLOv5라고 하는 것에 대해 논란이 있었다고 한다.

YOLOv4 vs YOLOv5

YOLOv4는 v5에 비해 느리게 동작하지만 FPS성능을 최적화 할 수 있고, YOLOv5는 v4에 비해 더 쉽게 환경을 구성하고, 구현할 수 있다는 특징이 있다.
때문에 연구나 분석 용도로는 YOLOv4를 사용하는 것이 더 좋을 것 같고, 실무적으로 빠르게 구현하고 배포하기에는 YOLOv5가 적합할 것이라고 생각된다.

YOLOv5

그렇다면 비교적 접근이 쉬운 v5 모델을 사용해보자.

먼저 YOLOv5의 Github를 clone 한 뒤 필요한 모듈들을 설치해준다.
아래는 Colab 환경에서의 코드 예시이다.

%cd /content
!git clone https://github.com/ultralytics/yolov5.git
!pip install -r /content/yolov5/requirements.txt

사용할 모델을 명시적으로 다운로드 해준다.
모델을 다운로드하지 않아도 YOLO 실행 시 자동으로 최신의 모델을 다운로드 해주는 것 같긴 하지만, 어떤 모델을 사용하는지 명확히 하기 위해 다운로드 해준다.

!wget -P /content/yolov5/ https://github.com/ultralytics/yolov5/releases/download/v6.0/yolov5s.pt

데이터셋의 위치를 알려주는 config file인 yaml 파일 확인 및 설정을 진행한다.

%cat /content/yolov5/data/coco128.yaml

coco128 dataset의 경우 80개의 class를 가지고 있으며 person, bicycle, car 등의 class를 가지고 있다.
지금은 수정할 필요가 없기 때문에 확인만 하고 넘어가도록 한다.

class에 해당하는 이미지들을 수집하여 임의의 test_set을 만든 뒤 Colab에 업로드 하고 detect를 실행해보자.
'YOLOv5_Native_TestData'이라는 이름으로 zip file을 만들어 /content 디렉토리에 업로드 한 뒤 해당 파일의 path를 list에 담고 확인해준다.

import zipfile
import glob

with zipfile.ZipFile('/content/YOLOv5_Native_TestData.zip', 'r') as target_file:
    target_file.extractall('/content/yolov5/YOLOv5_Native_TestData/')

test_image_list = glob.glob('/content/yolov5/YOLOv5_Native_TestData/*.jpg')

print(len(test_image_list))

test_image_list.sort()

for i in range(len(test_image_list)):

    print('i = ', i, test_image_list[i])

그 후 YOLOv5의 detect.py 파일을 실행시켜 Detection을 진행한다.
몇 가지 옵션이 존재하는데 우선 사용한 옵션만 보자면 weights 옵션을 통해 사용하고자 하는 모델을 명시해준다. 앞에서 다운로드한 모델의 경로를 입력해주면 된다.
또한, source 옵션을 통해 detection을 진행하고자 하는 파일들의 위치를 명시해준다.

!python3 /content/yolov5/detect.py --weights /content/yolov5/yolov5s.pt --source /content/yolov5/YOLOv5_Native_TestData/

더 자세한 옵션은 다음과 같다.

python detect.py --source 0  # webcam
                          img.jpg  # image
                          vid.mp4  # video
                          path/  # directory
                          path/*.jpg  # glob
                          'https://youtu.be/Zgi9g1ksQHc'  # YouTube
                          'rtsp://example.com/media.mp4'  # RTSP, RTMP, HTTP stream

detect.py 파일을 실행하여 정상적으로 완료되었다면 다음과 같이 exp라는 디렉토리 안에 해당 detection의 결과들이 저장되어 있을 것이다.
만약 여러번 detection을 수행했다고 한다면 exp2, exp3와 같이 횟수에 따라서 디렉토리가 생성됐을 것이다.

이 파일들을 zip file로 묶어 다운로드 하도록하자.
zip file로 묶어주는 이유는 14일 차 리뷰에서 이야기 했던 'I/O process in Colab'을 참고하면 된다.

from google.colab import files
import zipfile
import glob
import os

deteced_image_list = glob.glob('/content/yolov5/runs/detect/exp/*.jpg')

detected_image_nums = len(deteced_image_list)

if not os.path.exists('/content/detected_result/'):
    os.mkdir('/content/detected_result/')
    print('detected_result dir is created !!!')

with zipfile.ZipFile('/content/detected_result/detected_images.zip','w') as detected_images:
    for idx in range(detected_image_nums):
        detected_images.write(deteced_image_list[idx])

files.download('/content/detected_result/detected_images.zip')

다운로드가 완료되었다면 Local 환경에서 해당 데이터들을 확인해보자.
이미지의 해상도가 낮은 경우 다음과 같이 표시되기 때문에 이미지를 수집할 때 비교적 해상도가 높은 이미지를 수집하는 것을 권장한다.

roboflow

이제 YOLO 모델 내부에 있는 데이터가 아닌 우리가 원하는 데이터를 통해 detection을 진행해보자. roboflow에서는 object detection에 유용하게 사용할 수 있는 dataset을 제공한다.

Mask Wearing Dataset을 사용하여 detection을 진행해보자.
raw와 black-padding이 있는데 black-padding의 경우 padding을 주어 사이즈를 일관되게 만든 데이터 같았다. 필요에 맞게 사용하면 될 것 같다.
다운로드를 진행하면 다음과 같은 창이 나오는데, YOLO v5 PyTorch를 선택한 뒤 show download code를 체크하여 Continue 해주자.
이 경우 회원가입이 필요한데, 회원가입을 진행하고 계속하면된다. 내 경우에는 회원가입을 진행하고 Continue 버튼을 눌렀는데 반응이 없었는데, 창을 끈 뒤 다시 시도하거나 처음 페이지로 돌아가서 다시 진행하면 되는 것 같았다.
정상적으로 진행했다면 다음과 같은 화면을 볼 수 있는데, 해당 코드를 복사하여 Colab 환경에서 파일을 다운로드 할 수 있다.
코드를 보면 알겠지만 zip file을 다운 후 압축 해제, zip file 삭제 과정을 걸쳐서 하나의 디렉토리만 남는다.

%mkdir /content/Mask_Data

%cd /content/Mask_Data

!curl -L "https://public.roboflow.com/blabla" > roboflow.zip; unzip roboflow.zip; rm roboflow.zip

Colab 코드로 넘어가서, 먼저 /content 아래에 데이터를 저장할 디렉토리를 하나 만들어주고 해당 디렉토리로 이동한다. 그 후 아까 복사했던 코드를 입력해주면 된다.

%cat /content/Mask_Data/data.yaml

그 후 yaml 파일을 확인하고 환경에 맞게 수정해준다.

train: ../train/images
val: ../valid/images

nc: 2
names: ['mask', 'no-mask']

다운로드 한 yaml 파일은 다음과 같이 되어있는데 다음과 같이 환경에 맞게 수정해준다.
yaml 파일에는 상대경로로 되어있지만 명확성을 위해 절대경로로 명시해주는 것이 좋다.

import yaml

with open('/content/Mask_Data/data.yaml','r') as f:
    data = yaml.safe_load(f)

print(data)

data['train'] = '/content/Mask_Data/train/images/' # train 경로
data['val'] = '/content/Mask_Data/valid/images/' # validation 경로

data['nc'] = 2 # calss 개수
data['names'] = ['mask','no-mask'] # class 이름

with open('/content/Mask_Data/data.yaml','w') as f:
    yaml.dump(data, f)

print(data)

yaml 파일 수정이 완료되었다면, train을 위한 Hyperparameter를 설정해주고 train을 시작해보자.

# Hyperparameter setting

img_size = 416 # YOLO 기본 사이즈
batch_size = 32
epochs = 100

data_path = '/content/Mask_Data/data.yaml'
yaml_path = '/content/yolov5/models/yolov5s.yaml'
weights_path = '/content/yolov5/yolov5s.pt'

# train

!python3 /content/yolov5/train.py --img {img_size} --batch {batch_size} --epochs {epochs} --data {data_path} \
--cfg {yaml_path} --weights {weights_path}
%load_ext tensorboard
%tensorboard --logdir /content/yolov5/runs/train/exp/

설정한 epochs과 하드웨어 스펙에 따라서 시간이 소요되며, train이 완료된 후에 tensorboard를 통해 log를 확인할 수 있다.
이렇게 학습이 완료된 모델을 통해 detection을 진행하면 된다.
학습 모델은 yolov5/runs/train/exp/weights 안에 저장된다.
아까와 마찬가지로 학습 횟수에 따라 exp2, exp3와 같이 생성될 수도 있다.

!python3 /content/yolov5/detect.py \
--weights /content/yolov5/runs/train/exp/weights/best.pt \
--img 416 --conf 0.5 --source /content/Mask_Data/test/images/

--conf는 Bounding box를 결정할 때 얼마의 확률로 결정하는지 나타내는 값이다.
파일을 다운로드하여 결과를 보면 다음과 같이 인식되는 것을 확인할 수 있다.

General code

위에서는 파일의 경로 등을 모두 절대 경로로 작성해주었다.
그렇다면 다른 시스템에서 작업을 진행할 때 모든 경로들을 일일이 수정해주어야 한다.
이러한 번거로움을 줄이기 위해 General한 code를 작성해야 한다.
이를테면 다음과 같다.

%cd /content
!git clone https://github.com/ultralytics/yolov5.git
!pip install -r /content/yolov5/requirements.txt

해당 코드는 Colab 환경이 아니라면 Root 아래에 content라는 디렉토리가 존재하지 않는 경우가 많다. 때문에 General한 code를 작성하기 위해서는 최소한의 코드 변경으로 프로그램이 동작하게 만들어야 한다. 다음과 같이 변경하면 위 코드보다 좀 더 General한 code가 될 것이다.

ROOT_DIR = '/content'
%cd {ROOT_DIR} 
!git clone https://github.com/ultralytics/yolov5.git

YOLOv5_ROOT_DIR = os.path.join(ROOT_DIR, 'yolov5')
!pip install -r {os.path.join(YOLOv5_ROOT_DIR,'requirements.txt')}

다음과 같이 코드를 작성하면 시스템이 변경되어도 ROOT_DIR 변수 하나만 바꿔주게되면 정상적으로 동작한다.
이처럼 모든 절대 경로를 바꿔준다면 시스템이 변경되더라도 모든 경로들을 일일이 바꿔줄 필요가 없다.

또한, 시스템에 따라서 변해야하는 변수는 대문자로 쓰는 것이 conventional rule이다.

Outro

이전부터 이런 코드들을 어떻게 실행시키는지 어렵게만 느껴졌었는데, YOLO를 통해 어떻게 동작하는지 겪어보니 다른 github의 코드들도 쉽게 사용할 수 있을 것 같은 느낌이 든다.

기존의 잘 만들어진 모델을 사용하여 진행하다보니, 결과도 잘 나와서 실습을 진행하는 재미가 있는 것 같다.

초창기 블로그 포스팅을 진행할 때는 시간이 많이 걸려서 부담스럽다고 했었는데, 블로그 포스팅을 위해서 수업에서 배웠던 내용을 혼자서 진행해보고 정리하는 과정을 복습한다고 생각하니 좀 더 잘 정리하게 되는 것 같다.

profile
어제보다 나은

0개의 댓글