Yolov5를 이용한 Object detection

심우석·2022년 7월 25일
1

computer vision

목록 보기
2/2
post-thumbnail

오늘은 yolov5 모델을 이용하여 image detection을 해보겠습니다.

저는

python==3.9,2

torch==1.2.0+cu102

버젼을 사용했습니다.

제가 사용한 데이터는 roboflow에서 제공하는 Pothole dataset입니다.

위 사진과 같이 도로에 움푹파인 구멍들이 labeling된 데이터셋입니다.

pothole dataset은 아래의 링크에서 다운받을 수 있습니다.

https://public.roboflow.com/object-detection/pothole

다음은 yolov5 github입니다.

아래의 주소를 gitclone 하셔도 좋고 들어가셔서 직접 다운받으셔도 무관합니다

https://github.com/ultralytics/yolov5

%cd /put/your/direction/to/download/models
!git clone https://github.com/ultralytics/yolov5

다운받은 Yolov5모델은 이렇게 구성되어 있네요.

Yolo의 원리 및 세부사항을 알고싶으신 분들은 아래의 링크 참조하시면 될것 같습니다.

저도 많은도움이 되었네요.

https://colab.research.google.com/drive/1KKp9-Fhr-PmN_Cndebb0wSy-JgcZuPST?usp=sharing

자 그럼 본격적으로 들어가 보도록 하겠습니다.

#%%get iamgedata
from glob import glob

train_img_list=glob('/home/nvidia/dogcat/yolov5/pothole_dataset/train/images/*.jpg')
test_img_list=glob('/home/nvidia/dogcat/yolov5/pothole_dataset/test/images/*.jpg')
valid_img_list=glob('/home/nvidia/dogcat/yolov5/pothole_dataset/valid/images/*.jpg')
print(len(train_img_list),len(test_img_list),len(valid_img_list))

glob을 사용하여 다운받은 pothole dataset에서 이미지 데이터를 가져옵니다.

경로는 개인이 다운받은 경로로 수정하시면 됩니다.

길이를 보니 465 67 133으로 잘 가져와졌군요.

#%%set imagedata
import yaml
with open('/home/nvidia/dogcat/yolov5/pothole_dataset/train.txt','w') as f:
  f.write('\n'.join(train_img_list)+'\n')
with open('/home/nvidia/dogcat/yolov5/pothole_dataset/test.txt','w') as f:
  f.write('\n'.join(test_img_list)+'\n')
with open('/home/nvidia/dogcat/yolov5/pothole_dataset/valid.txt','w') as f:
  f.write('\n'.join(valid_img_list)+'\n')

다음은 가져온 파일을 yaml파일로 만들어줍니다.

#%%writetemplate function
from IPython.core.magic import register_line_cell_magic

@register_line_cell_magic
def writetemplate(line,cell):
  with open(line,'w') as f:
    f.write(cell.format(**globals()))

다음은 여러가지 template들은 text처럼 사용할수 있도록 하는 함수를 만들어 줍니다.

%cat /home/nvidia/dogcat/yolov5/pothole_dataset/data.yaml

cat을 이용해서 data,yaml을 확인해봅니다.

train: ../train/images

val: ../valid/images

nc: 1

names: ['pothole']

이렇게 나오네요. 이것을 우리가 가진 데이터와 적합하게 바꿔줍니다.

#%%set data.yaml
%%writetemplate /home/nvidia/dogcat/yolov5/pothole_dataset/data.yaml

train: /home/nvidia/dogcat/yolov5/pothole_dataset/train/images
test: /home/nvidia/dogcat/yolov5/pothole_dataset/test/images
val: /home/nvidia/dogcat/yolov5/pothole_dataset/valid/images

nc: 1
names: ['pothole']

이렇게 말이죠.

개인적으로 저는 경로를 사용할 때 절대경로를 사용하는 것을 선호합니다.

하지만 상대경로를 사용하여도 무관합니다.

%cat /home/nvidia/dogcat/yolov5/pothole_dataset/data.yaml

다시 한번 확인해보면 잘 바뀌어져 있네요.

#%%get numclasses in data
with open("/home/nvidia/dogcat/yolov5/pothole_dataset/data.yaml",'r') as stream:
  num_classes=str(yaml.safe_load(stream)['nc'])

다음은 data의 확인을 위해 data.yaml을 가져와서 클래스의 갯수를 변수에 저장시켜줍니다.

알고 있지만 습관적으로 이런 작업을 해주면 실수가 줄어들겠죠?

%cat /home/nvidia/dogcat/yolov5/models/yolov5s.yaml

저는 yolov5s모델을 이용해서 학습할 것이기 때문에 모델확인을 위해 cat을 사용해줍니다

위와 같이 모델의 구조를 확인할 수 있습니다.

%%writetemplate /home/nvidia/dogcat/yolov5/models/custom_yolov5s.yaml

# Parameters
nc: (num_classes)  # number of classes
depth_multiple: 0.33  # model depth multiple
width_multiple: 0.50  # layer channel multiple
anchors:
  - [10,13, 16,30, 33,23]  # P3/8
  - [30,61, 62,45, 59,119]  # P4/16
  - [116,90, 156,198, 373,326]  # P5/32

# YOLOv5 v6.0 backbone
backbone:
  # [from, number, module, args]
  [[-1, 1, Conv, [64, 6, 2, 2]],  # 0-P1/2
   [-1, 1, Conv, [128, 3, 2]],  # 1-P2/4
   [-1, 3, C3, [128]],
   [-1, 1, Conv, [256, 3, 2]],  # 3-P3/8
   [-1, 6, C3, [256]],
   [-1, 1, Conv, [512, 3, 2]],  # 5-P4/16
   [-1, 9, C3, [512]],
   [-1, 1, Conv, [1024, 3, 2]],  # 7-P5/32
   [-1, 3, C3, [1024]],
   [-1, 1, SPPF, [1024, 5]],  # 9
  ]

# YOLOv5 v6.0 head
head:
  [[-1, 1, Conv, [512, 1, 1]],
   [-1, 1, nn.Upsample, [None, 2, 'nearest']],
   [[-1, 6], 1, Concat, [1]],  # cat backbone P4
   [-1, 3, C3, [512, False]],  # 13

   [-1, 1, Conv, [256, 1, 1]],
   [-1, 1, nn.Upsample, [None, 2, 'nearest']],
   [[-1, 4], 1, Concat, [1]],  # cat backbone P3
   [-1, 3, C3, [256, False]],  # 17 (P3/8-small)

   [-1, 1, Conv, [256, 3, 2]],
   [[-1, 14], 1, Concat, [1]],  # cat head P4
   [-1, 3, C3, [512, False]],  # 20 (P4/16-medium)

   [-1, 1, Conv, [512, 3, 2]],
   [[-1, 10], 1, Concat, [1]],  # cat head P5
   [-1, 3, C3, [1024, False]],  # 23 (P5/32-large)

   [[17, 20, 23], 1, Detect, [nc, anchors]],  # Detect(P3, P4, P5)
  ]

복사후 미리 정의해둔 writetemplate를 이용하여 저희가 사용할 모델을 nc를 수정후 저장하여 줍니다.

원본을 수정하기보단 새로 정의하여 주는것이 안전합니다.

%cat /home/nvidia/dogcat/yolov5/models/custom_yolov5s.yaml

수정한 custom model을 확인하여보면 역시나 잘 정의되었네요.

#%%train
!python /home/nvidia/dogcat/yolov5/train.py --img 640 --batch 32 --epochs 100 --data /home/nvidia/dogcat/yolov5/pothole_dataset/data.yaml --cfg /home/nvidia/dogcat/yolov5/models/custom_yolov5s.yaml --weights '' --name pothole_results --cache

yolov5의 train.py를 사용하여 학습시켜줍니다.

파라미터들은 위의 값이 절대적인 수치가 아님을 알려드립니다.

각자의 필요에 따라 파라미터를 수정 후 사용하시길바랍니다.

#%%load tensorboard
%load_ext tensorboard
%tensorboard --logdir runs

혹시 google colaboraty에서 파일을 실행하시는분은 위의 코드로 학습결과를 더 간편히 볼 수 있습니다

#%%check result folder list
!ls /home/nvidia/dogcat/yolov5/runs/train/pothole_results4/

학습 후 결과들이 저장된 파일에는 이런형식으로 저장되어있네요.

#%%result
from IPython.display import Image,clear_output,display
display(Image(filename='/home/nvidia/dogcat/yolov5/runs/train/pothole_results4/results.png',width=1000))

그 중 result.png파일을 보면 학습과정을 한눈에 볼수 있습니다.

validation의 loss를 보니 epoch을 더 높이면 더 좋은 결과를 얻을 수 있을것 같습니다

#%%first trainbatch
display(Image(filename='/home/nvidia/dogcat/yolov5/runs/train/pothole_results4/train_batch0.jpg',width=1000))

첫번째 train batch의 데이터들을 살펴봐줍니다.

#%%labeled first validation batch
display(Image(filename='/home/nvidia/dogcat/yolov5/runs/train/pothole_results4/val_batch0_labels.jpg',width=1000))

위의 코드로 라벨링된 validation데이터도 체크해줍니다.

#%%check wights folder list
%ls /home/nvidia/dogcat/yolov5/runs/train/pothole_results4/weights

가중치 파일을 보면 가장 수치가 좋았던 모델과 마지막으로 학습니 끝난 모델 두개가 저장되어 있네요.

일반적인 상황에서는 best.pt를 사용하면 좋겠죠?

best.pt last.pt

#%%run detect.py
!python /home/nvidia/dogcat/yolov5/detect.py --weights /home/nvidia/dogcat/yolov5/runs/train/pothole_results4/weights/best.pt --img 640 --conf 0.4 --source /home/nvidia/dogcat/yolov5/pothole_dataset/test/images

detect.py 에 best.pt를 적용해서 test image들을 object detection해봅니다. 제 기준으로는 꽤 빠른 속도로 진행되네요.

size가 작은 모델을 사용한것이 효과 있는것 같습니다.

import glob
import random
from IPython.display import Image,display

image_name=random.choice(glob.glob('/home/nvidia/dogcat/yolov5/runs/detect/exp2/*.jpg'))
display(Image(filename=image_name))

random하게 detection이 끝난 image들을 가져와서 잘 되었는지 확인해줍니다.

잘 detection 되었네요.

이상입니다. 긴 글 봐주셔서 감사합니다~.

0개의 댓글