
인공지능 관련하여 프로젝트 개발에 있어 객체 탐지를 활용해야 하는 부분이 있었다. 특히, 영상 속에서 객체 탐지를 구현해야 했기에 실시간으로 객체 탐지를 잘 할 수 있는 것이 필요했다.
조사 결과 Yolo가 해당 기능에 적합했다고 판단하여 Yolo를 공부하게 되었다. 해당 프로젝트에서는 Yolo 중 v4를 기반으로 하여 공부하였다. 그 중 Darknet을 base로 한 Yolo 구현에 관하여 공부를 하였다.
해당 포스팅에서는 공부했던 내용에 대하여 기술하고, 느겼던 점 등을 게시하고자 한다.
(1) Darknet 구현은 주피터, 아나콘다 등 여러 tool을 이용하여 할 수 있지만, 필자는 Google Colab을 통해 구현하였다.
(2) Colab 버전으로 구현하게 될 시 많은 이미지를 train할 수 없는 문제가 발생한다. 만약, 많은 이미지를 학습 시킬 예정이라면, Colab Pro 버전을 구매하도록 하자.
(3) Colab에 ipynb 파일을 먼저 생성하여야 한다. ipynb 파일은 Colab에서 /content/drive/MyDrive 안에 생성한다. ipynb 파일의 파일명은 임의로 지정하여 저장하면 된다.
from google.colab import drive
drive.mount('/content/drive')
import os
path = "/content"
os.chdir(path)
from google.colab import drive
drive.mount('/content/drive', force_remount=True)
/content/drive/MyDrive 안에 yolov4 폴더를 생성
%cd /content/drive/MyDrive/yolov4/
!git clone https://github.com/AlexeyAB/darknet.git /content/drive/MyDrive/yolov4/
%cd /content/drive/MyDrive/yolov4/
!sed -i 's/OPENCV=0/OPENCV=1/' Makefile
!sed -i 's/GPU=0/GPU=1/' Makefile
!sed -i 's/CUDNN_HALF=0/CUDNN_HALF=1/' Makefile
!sed -i 's/CUDNN=0/CUDNN=1/' Makefile
!sed -i 's/LIBSO=0/LIBSO=1/' Makefile
!/usr/local/cuda/bin/nvcc --version
!make
(1) 다운로드
https://drive.google.com/open?id=1JKF-bdIklxOOVy-2Cr5qdvjgGpmGfcbp
(2) 저장 경로
ex) /content/drive/MyDrive/yolov4/build/darknet/x64/yolov4.conv.137
(1) Clone 받은 darket 파일에서 cfg 폴더 경로 내에 있는 yolov4-custom.cfg 라는 이름의 cfg 파일을 통째로 복사하여 yolov4-obj.cfg 라는 이름으로 같은 경로 내에 복사본을 생성한다.
(2) yolov4-obj.cfg 라는 이름의 빈 파일을 먼저 생성하고 yolov4-custom.cfg 파일의 내용을 복사해도 된다.
파일 구조는 아래와 같다.
darknet
ㄴ cfg
ㄴ yolov4-custom.cfg
ㄴ yolov4-obj.cfg
ㄴ ...
ㄴ ...
ex) 만약 클래스의 개수가 2개라면 max_batches=4000
ex) 만약 클래스 개수가 2개라면 steps=3200,3600
ex) 416x416 크기의 이미지를 입력하려면 width=416, height=416 (32의 배수로 설정하는 것을 권장)
ex) 만약 클래스의 개수가 2개라면 classes=2
ex) 만약 클래스의 개수가 2개라면 filters=21
전체 이미지 파일과 라벨링 파일
[/content/drive/MyDrive/yolov4/build/darknet/x64/data/obj] 경로에 삽입
만약, obj 폴더가 없다면 ~/x64/data에 obj 폴더를 생성하고 진행하면 된다.
이미지 파일과 라벨링 파일의 이름은 둘이 일치하기만 하다면 어떻게 설정하든지 상관없다.
또한 train 이미지와 valid 이미지 모두 darknet/build/darknet/x64/data/obj/ 경로 내에 넣어주면 된다.
# define helper functions
def imShow(path):
import cv2
import matplotlib.pyplot as plt
%matplotlib inline
image = cv2.imread(path)
height, width = image.shape[:2]
resized_image = cv2.resize(image,(3*width, 3*height), interpolation = cv2.INTER_CUBIC)
fig = plt.gcf()
fig.set_size_inches(18, 10)
plt.axis("off")
plt.imshow(cv2.cvtColor(resized_image, cv2.COLOR_BGR2RGB))
plt.show()
# use this to upload files
def upload():
from google.colab import files
uploaded = files.upload()
for name, data in uploaded.items():
with open(name, 'wb') as f:
f.write(data)
print ('saved file', name)
# use this to download a file
def download(path):
from google.colab import files
files.download(path)
def makefile():
import random as rd
import os
files = os.listdir('data/farm')
rd.shuffle(files)
files = ['/data/farm/'+i for i in files]
len(files)
#f = open("data/train.txt", 'w',encoding='UTF-8')
f1 = open("data/validation.txt", 'w',encoding='UTF-8')
count = 0
for file in files:
if file.split('.')[-1] =='txt':
pass
else:
if count > len(files)*0.4:
f1.write(file+'\n')
count +=1
#f.close()
f1.close()
이미지의 경로가 지정되어 있는 train.txt 파일과 test.txt 파일을 생성하고 저장하는 단계이다.
각각의 파일은 학습과 검증에 사용될 이미지의 상대 혹은 절대 경로를 저장하고 있다.
여러 방법이 있겠지만 아래의 방법을 따라하면 쉽게 진행할 수 있다.
먼저, glob 라이브러리를 활용하여 경로를 이전에 저장한 이미지들의 경로를 리스트 형태로 생성한다.
아래의 코드에서 이미지 경로 설정에 주의한다.
from glob import glob
img_list = glob('/content/drive/MyDrive/yolov4/build/darknet/x64/data/obj/*.jpg')
len(img_list)
sklearn 라이브러리의 train_test_split 함수를 사용하여 학습과 검증에 사용할 이미지를 분할한다.
#가져온 사진을 토대로 train, test set 나누기
from sklearn.model_selection import train_test_split
train_img_list, test_img_list = train_test_split(img_list, test_size=0.1, random_state=42) # random_state는 임의로 선택
print(len(train_img_list), len(test_img_list))
이제 학습 이미지 리스트와 검증 이미지 리스트를 각각 train.txt와 test.txt 파일에 저장한다.
각각의 txt 파일의 경로는 darknet/build/darknet/x64/data/ 경로 아래에 둔다.
경로 설정에 주의한다.
ex) 즉, train.txt와 test.txt의 파일의 내용은 예를 들어 아래와 같이 구성된다.
/content/drive/MyDrive/yolov4/build/darknet/x64/data/obj/img1.jpg
/content/drive/MyDrive/yolov4/build/darknet/x64/data/obj/img2.jpg
/content/drive/MyDrive/yolov4/build/darknet/x64/data/obj/img3.jpg
...
#나눠진 set들을 train.txt, test.txt에 경로, 이름 저장
with open('/content/drive/MyDrive/yolov4/build/darknet/x64/data/train.txt', 'w') as f:
f.write('\n'.join(train_img_list) + '\n')
with open('/content/drive/MyDrive/yolov4/build/darknet/x64/data/test.txt', 'w') as f:
f.write('\n'.join(test_img_list) + '\n')
!pwd
이제 학습을 하기 위한 데이터들의 관한 정보를 담고 있는 obj.names, obj.data 파일 2개를 만드는 단계이다.
/content/drive/MyDrive/yolov4/build/darknet/x64/data/ 경로 아래에 obj.names 라는 파일을 생성한다.
obj.names 파일에는 모든 클래스의 이름이 들어간다.
ex) 만약 클래스의 개수가 2개이고 각각, dog 와 cat이라면, obj.names 파일의 내용은 아래와 같이 구성된다.
dog
cat
/content/drive/MyDrive/yolov4/build/darknet/x64/data/ 경로 아래에 obj.data 라는 파일을 생성한다.
obj.data 파일의 내용은
1) 클래스의 개수,
2) train.txt 파일 경로,
3) test.txt 파일 경로,
4) obj.names 파일 경로,
5) 학습된 weight 파일을 백업할(저장할) 경로
총 5가지 line으로 구성된다.
ex) 즉, obj.data 파일의 내용은 아래와 같이 구성된다.
classes = 2
train = data/train.txt
valid = data/test.txt
names = data/obj.names
backup = backup
위 파일의 경로 설정에 매우 주의하도록 한다.
학습 시 train.txt , test.txt 나 obj.names 파일을 찾지 못하는 오류가 발생한다면
상대 경로 말고 절대 경로로 지정해도 된다.
절대 경로로 지정시 obj.data의 내용은 아래와 같이 된다.
classes = 2
train = /content/drive/MyDrive/yolov4/build/darknet/x64/data/train.txt
valid = /content/drive/MyDrive/yolov4/build/darknet/x64/data/test.txt
names = /content/drive/MyDrive/yolov4/build/darknet/x64/data/obj.names
backup = /content/drive/MyDrive/yolov4/build/darknet/x64/backup
!pwd
!chmod +x ./darknet
훈련 실행 코드의 형식은 아래와 같다.
!./darknet detector train {obj.data 경로} {yolov4-obj.cfg 경로} {yolov4.conv.137 경로} -dont_show
사용 예
!./darknet detector train /content/drive/MyDrive/yolov4/build/darknet/x64/data/obj.data /content/drive/MyDrive/yolov4/build/darknet/x64/cfg/yolov4-custom.cfg /content/drive/MyDrive/yolov4/build/darknet/x64/yolov4.conv.137 -dont_show
아래 코드 통해 이어서 진행
!./darknet detector train /content/drive/MyDrive/yolov4/build/darknet/x64/data/obj.data /content/drive/MyDrive/yolov4/build/darknet/x64/cfg/yolov4-custom.cfg /content/drive/MyDrive/yolov4/build/darknet/x64/backup/yolov4-custom_last.weights -dont_show
couldn't open file: train.txt 참고 링크 : https://github.com/pjreddie/darknet/issues/484
obj.data 파일에서 기존 형태는
classes = 2
train = data/train.txt
valid = data/test.txt
names = data/obj.names
backup = backup/
일 것이다.
이 상태에서 룬련 코드를 실행했을 때, couldn't open file: train.txt와 같은 에러가 뜬다면 상대 경로가 아닌 절대 경로를 대입해주어야 한다.
기왕 하는 것 train.txt 관련만 수정하지 말고 모두 수정해주면 좋을 것이다.
그리고 backup = backup/에서 /는 없애는 것이 좋다. 수정한 코드는 다음과 같다.
classes = 2
train = /content/drive/MyDrive/yolov4/build/darknet/x64/data/train.txt
valid = /content/drive/MyDrive/yolov4/build/darknet/x64/data/test.txt
names = /content/drive/MyDrive/yolov4/build/darknet/x64/data/obj.names
backup = /content/drive/MyDrive/yolov4/build/darknet/x64/backup
!pwd
!chmod +x ./darknet
(1) 실험 실행 코드 : !./darknet detector test {obj.data 경로} {yolov4-obj.cfg 경로} {학습된 weight 파일 경로} {테스트 이미지 파일 경로}
(2) 코드 실행 결과로 predictions.jpg 파일이 생성된다.
실험 실행 코드를 실행하기에 없어 테스트 이미지를 넣기 위한 폴더를 생성해야 함
(3) 해당 폴더는 /content/drive/MyDrive/yolov4/build/darknet/x64/data에 생성할 것
(4) 여기서는 farm 폴더로 생성했고 절대 경로는 /content/drive/MyDrive/yolov4/build/darknet/x64/data/farm 이다.
(5) 또 test하고자 하는 이미지를 farm 폴더 안에 넣어준다.
!./darknet detector test /content/drive/MyDrive/yolov4/build/darknet/x64/data/obj.data /content/drive/MyDrive/yolov4/build/darknet/x64/cfg/yolov4-custom.cfg /content/drive/MyDrive/yolov4/build/darknet/x64/backup/yolov4-custom_last.weights /content/drive/MyDrive/yolov4/build/darknet/x64/data/farm/bird_02.jpg
imShow('predictions.jpg')

imShow('chart_yolov4-custom.png')

(1) 작년(21년도)에도 AI를 활용한 프로젝트를 진행했으나, 그 당시의 프로젝트는 AI를 활용했다는 느낌이 크게 들지 않았다. 하지만 이번 프로젝트에서는 Yolo를 활용하고자 AI에 대한 공부를 많이 할 수 있었다.
(2) Yolo에서 코드를 실행시키고자 할 때 경로 관련 부분이 나올 때는 상대 경로보다는 절대 경로로 코드를 넣고 실행하는 것이 에러를 좀 덜 발생하게 하는 요인이라는 것을 인지했다.
-> 코드 관련 참고 사이트
-> 경로 관련 참고 사이트
-> 학습 관련 참고 사이트
-> Irish Github
-> 포스팅 관련 깃허브 링크