📒 작품 소개 ☆
YOLOv5 모델을 활용하여 처음 만들어보는 인공지능 프로젝트
최근 야생 동물이 고속도로에 뛰어들어 차량과 사고가 발생하는 것을 한문철 블랙박스 사고 영상에서 본 적 있다.
사고가 발생하면 운전자와 자동차, 야생 동물의 죽음 등 많은 피해가 발생한다.
사고를 막기 위한 인공지능 모델을 만들어보면 어떨까? 생각해 보았다.
야생 동물마다 들을 수 있는 주파수가 다 다르다고 하는데, 야생 동물이 자주 출현하는 곳에 카메라를 설치해서 해당 야생 동물이 나타나면, 동물이 들을 수 있는 큰 주파수 소리로 쫓아내어 도로에 뛰어드는 것을 방지해 볼 순 없을까? 하는 생각으로 모델을 만들어보았다.
https://github.com/hwanggiju/Detect_WildAnimals
GitHub - hwanggiju/Detect_WildAnimals
Contribute to hwanggiju/Detect_WildAnimals development by creating an account on GitHub.
github.com
목차
1. 개발 환경
2. 목표
3. 나의 역할
4. 활동 내용
5. 활동 결과
6. 마무리
#2 YOLO 모델을 활용하여 야생 동물 LoadKill 방지 모델 생성하기
작품 기간 : 2022.09.19 ~ 2022.09.22
1. 개발 환경
- 활용한 모델 : YOLOv5s
- 개발 언어 : Python
- 개발 도구 : Google Colab, Jupyter Notebook, labelImg
2. 목표
- 로드킬이 자주 발생하는 동물 Top 6마리를 조사하여 실시간으로 동물들을 탐지할 수 있는 모델을 생성한다.
3. 나의 역할
- 야생 동물 이미지 데이터를 크롤링하고, 관련 영상을 찾아서 프레임을 추출한 후 이미지 데이터를 수집
- labelImg 프로그램을 사용하여 라벨링
- YOLOv5s 모델 생성 및 학습
4. 활동 내용
>> 야생 동물 이미지 데이터 크롤링 (Google)
- 구글에서 동물 이름을 검색하여 나오는 관련 이미지를 모두 크롤링하여 저장한다.
- 먼저 웹에서 크롤링하기 위한 라이브러리를 소환해준다.
from selenium import webdriver
from bs4 import BeautifulSoup as bs
import urllib.request
import os
import time
- 다음으로 원하는 이미지 검색어를 입력해주고, 크롬을 열어 검색어 url 주소로 접속해준다.
- 여기서, 크롬을 실행시켜주는 드라이버를 먼저 다운 받아주어야 한다.
- https://chromedriver.chromium.org/downloads
ChromeDriver - WebDriver for Chrome - Downloads
Current Releases If you are using Chrome version 110, please download ChromeDriver 110.0.5481.30 If you are using Chrome version 109, please download ChromeDriver 109.0.5414.74 If you are using Chrome version 108, please download ChromeDriver 108.0.5359.71
chromedriver.chromium.org
- 크롤링할 때, 웬만하면 time.sleep를 꼭 넣어서 IP 차단되는 일이 없게하자...ㅠ
keyword = input("검색어 입력 : ")
url = 'https://www.google.com/search?q=' + keyword
url = url + '&rlz=1C1IBEF_koKR976KR976&sxsrf=AJOqlzXxEtnx5_mVCkZaSMt-zTOLqj311A:1674480860307&source=lnms&tbm=isch&sa=X&ved=2ahUKEwj6lPKm5938AhXdQPUHHU-4CvkQ_AUoAXoECAEQAw&biw=1920&bih=936&dpr=1'
driver = webdriver.Chrome('크롬 드라이버 실행파일 경로 지정')
driver.get(url)
time.sleep(2)
- 크롬에서 이미지 창이 뜨면 모든 이미지를 로드시키기 위해 화면을 맨 아래로 스크롤하여 내려준 후, BeautifulSoup 도구로 html 파싱하여 웹에서 F12를 눌러서 이미지가 해당되는 범위를 추출해준다.
for i in range(10) :
# 아래로 스크롤하는 명령어 지정
driver.execute_script('window.scrollTo(0, document.body.scrollHeight);')
time.sleep(3)
html_source = driver.page_source
soup = bs(html_source, 'html.parser') # html 파싱
img_list = set(soup.find('div', class_='photo_group').find_all('img'))
- 이미지를 저장하기 위한 폴더를 하나 생성하고, 추출한 이미지를 반복을 통해 차곡차곡 이미지 파일로 저장시켜준다.
fdir = '폴더를 저장할 경로'
fName = os.listdir(fdir)
fName_dir = '생성할 폴더명'
print(fdir + fName_dir + '로 폴더 생성') # 폴더 생성 완료 확인 출력!
cnt = 0
for img_url in img_list :
tmp_name = '이미지를 저장할 절대 경로 지정' + '.jpg' # 확장자 붙여주기
try :
urllib.request.urlretrieve(img_url['src'], tmp_name)
cnt += 1
except :
pass
cnt += 1
driver.close()
>> 영상 프레임 이미지 추출
- OpenCV 라이브러리를 활용해서 영상을 프레임 당 이미지로 추출하여 수집하는 방법이다.
- 코드는 다음과 같다.
import cv2
import os
cap = cv2.VideoCapture('/content/sample1.mp4')
cnt = 0
while (cap.isOpened()) :
ret, image = cap.read()
if ret == False :
break
if (int(cap.get(1)) % 10 == 0) :
print('Save frame number : ' + str(int(cap.get(1))))
cv2.imwrite('/content/dirve/MyDrive/저장 폴더 이름/이미지 파일 이름_%d.jpg'%cnt, image)
print('Save frame %d' % cnt)
cnt += 1
cap.release()
- 위 두가지 방법으로 이미지를 수집하였고, 라벨링을 진행하였다.
>> 라벨링
- YOLO 모델을 활용하기 위한 라벨링 작업으로 labelImg 프로그램을 사용하였다.
- 클래스는 총 6가지로 분류하였다.
- 로드킬이 자주 발생하는 야생 동물를 조사해보았다.
- 고라니, 너구리, 맷돼지, 맷토끼, 고양이(삵), 오소리 총 6가지 동물 클래스로 분류하였다.
- 아래와 같이 수집한 이미지 데이터를 labelImg 프로그램을 사용하여 바운딩 박스를 그려주고 해당 클래스와 박스 좌표값을 텍스트 파일로 저장할 수 있었다.
- 모든 라벨링 작업을 마치고 모든 야생 동물에 대해 총 약 2400장의 학습 이미지 데이터를 수집할 수 있었다.
>> YOLOv5s 모델 생성 및 학습
- 먼저 YOLOv5s 모델을 불러온다.
- https://github.com/ultralytics/yolov5
GitHub - ultralytics/yolov5: YOLOv5 🚀 in PyTorch > ONNX > CoreML > TFLite
YOLOv5 🚀 in PyTorch > ONNX > CoreML > TFLite. Contribute to ultralytics/yolov5 development by creating an account on GitHub.
github.com
- 구글 코랩에서 드라이브와 마운트 해준 후, 위의 깃허브 링크를 통해 다운받아준다.
# 구글 드라이브 연결
from google.colab import drive
drive.mount('/content/drive')
# /content 경로 이동
%cd /content/프로젝트 경로
# 깃에서 욜로 5 가져오기
!git clone https://github.com/ultralytics/yolov5
- 학습을 위해 YOLO의 data.yaml 파일을 수정하여 프로젝트에 맞게 클래스 이름을 변경시켜준다.
- 또한, 훈련 데이터 셋과 검증 데이터 셋은 동일한 이미지 데이터로 지정해주었다.
- 아쉬웠던 점 : 훈련 데이터 셋과 검증 데이터 셋을 나누어 지정해주는 게 좀 더 좋은 학습 내용이 되었을 거 같다는 생각이 든다...
- 아래와 코드와 같이 data.yaml 파일을 수정해준다.
from IPython.core.magic import register_line_cell_magic
# .yaml 파일 수정하기 위한 설정
@register_line_cell_magic
def writetemplate(line, cell) :
with open(line, 'w') as f:
f.write(cell.format(**globals()))
# data.yaml 파일 수정
%%writetemplate /content/yolov5/wildAnimal_dir/data.yaml
train: /content/yolov5/wildAnimal_dir/images
val: /content/yolov5/wildAnimal_dir/images
nc: 6
names: ['elk', 'wild boar', 'rabbit', 'badger', 'Raccoons', 'cat']
- 또한, YOLOv5s 모델을 사용할 것이기 때문에 yolov5s.yaml 파일도 수정해주는데, 원본 파일은 그대로 나두고 원본 파일을 복사해서 수정하여 custom_yolov5s.yaml 파일을 새로 만들어서 저장하였다.
- 아래 코드에서 nc 파라미터를 클래스 개수만큼 수정해주고, 나머진 그대로 저장하였다.
%%writetemplate /content/yolov5/models/custom_yolov5s.yaml
# YOLOv5 🚀 by Ultralytics, GPL-3.0 license
# Parameters
nc: 6 # 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)
]
- 학습을 위한 yolov5s 기본 설정을 마치고 학습을 돌린다.
- 학습은 폴더 안에 있는 train.py를 실행시켜 원하는 이미지 크기와, 배치 사이즈, 에포크 횟수 등의 파라미터를 입력한 후 실행시켜주면 된다.
- 여기서는 수정한 .yaml 파일들을 넣어주었고 yolov5s 기본 학습 가중치를 적용시켜 학습 결과를 wildanimal_result 이름으로 저장하였다.
!python train.py --img 640 --batch 32 --epochs 90 --data ./wildAnimal_dir/data.yaml --cfg ./models/custom_yolov5s.yaml --weight yolov5s.pt --name wildanimal_result --cache
- 학습된 결과는 다음과 같다.
- mAP0.95 결과는 약 94% 정도로 상당히 높게 나온 것을 확인해 볼 수 있었다.
5. 활동 결과
- 학습한 결과를 텐서보드를 활용하여 그래프로 확인해보았다.
- 실시간으로 테스트를 진행하기 어려워 영상으로 대체하여 테스트를 진행하였다.
- 한계점 : 너구리와 오소리의 경우, 외관적으로 비슷한 부분이 있어 테스트를 해보았을 때 잘 찾아내지 못하는 문제점을 확인해 볼 수 있었다. 이 점을 볼 때, yolo 모델의 경우 간단하고 추론 속도가 빨라 실시간 이미지 객체 인식에 좋은 성능을 보이는 것 같지만, 비슷한 객체의 경우 구체적인 특징을 잘 찾아내지 못하는 한계점도 확인해 볼 수 있었다.
6. 마무리
지금까지 만든 인공지능 모델을 실제로 적용시켜본다면,
야생 동물 출몰지역에 카메라를 배치하여 탐지한 야생 동물별로 들을 수 있는 최대 주파수를 출력하도록 설정해서 생태 도로 방향으로 유도시키거나 도로 방향으로 넘어오지 못하게 예방할 수 있지 않을까 더 생각해봤다. 🤔