본문 바로가기

Deep Learning/Yolo

[3] YOLO 데이터 학습

필자는 컴퓨터 운영체제로서  'Linux Ubuntu 18.04.1 LTS'를 사용하고 그래픽 카드는 'GeForce GTX 970'을 사용한다. 이 글은 온전히 필자의 컴퓨터를 기준으로 작성했다.


이전 글에선 YOLO가 Detecting하는 방법들을 살펴보고, 직접 실행해 보았다.

지금까지는 주어진 가중치 파일(.weights)를 사용했다면, 이제부터는 직접 가중치 파일을 만들고 Test 해 보자. 먼저 임의의 데이터를 수집하고, class의 수와 종류를 선언하고, 학습을 시킨 후 마지막으로 잘 학습되었는지 확인해 볼 것이다.

1. 학습 계획 세우기

학습에 앞서 어떻게 학습을 할 것인지 간단한 계획을 세워보자..

① 어떤 객체를 학습시킬 것인지 생각한다.

② 데이터는 어떻게 구할 것인지 생각한다.

③ 데이터는 3가지 종류를 준비한다; Learning Data, Add data, Test data


필자는 다음과 같이 진행했다.

① 동그라미, 세모, 네모를 찾는 네트워크를 만들겠다.

② Python Imaging Library(PIL)을 이용해 직접 jpg파일을 제작한다.

③ Learning Data 준비하고, 학습시킨다. 그리고 Test data를 이용해 결과를 테스트한다.

③-1 만약 학습 결과가 만족스럽다면 끝.

③-2 만약 학습 결과가 만족스럽지 않다면, Learning data에 Add data를 추가하여 학습 데이터 수를 늘린 후 학습을 다시 진행한다. 그리고 Test Data를 이용해 다시 결과를 확인하고 비교한다.


2. Yolo_mark 다운로드

학습을 위해 'Yolo_mark'를 사용해보자.
~/opencv/opencv-3.2.0/build/darknet 경로에서 다음 명령어를 통해 다운로드 한다.

$ git clone https://github.com/AlexeyAB/Yolo_mark
$ cd Yolo_mark
$ cmake .
$ make


3. 학습 방법 둘러보기

지금부터는 학습을 위해 수정이 필요한 공간들을 잠깐 둘러보도록 하겠다.

~/opencv/opencv-3.2.0/build/darknet/Yolo_mark 경로에서 다음 명령어를 입력하면 창이 하나 뜬다.

$ bash ./linux_mark.sh


Boxing을 통해 학습 데이터를 만드는 창이다. esc를 누르면 종료된다.


~/opencv/opencv-3.2.0/build/darknet/Yolo_mark/x64/Release/data 경로에서 다음 명령어를 입력해보자. 


$ vi obj.data


data에 대한 정보들을 담아둔 파일이다. 이 곳에서 Class의 수, Training data 경로, Class 이름과 관련된 경로를 수정할 수 있다. 

이전에도 얘기했지만, vi 명령어에 대한 공부를 하자. 해야 이후에 진행이 가능하다. 모르면 찾아서 공부하자.

 

~/opencv/opencv-3.2.0/build/darknet/Yolo_mark/x64/Release/data 경로에서 다음 명령어를 입력해보자.


$ vi obj.names


학습할 class들의 이름을 저장하는 파일이다.


~/opencv/opencv-3.2.0/build/darknet/Yolo_mark/x64/Release/data/img 경로를 들어가보자.


학습할 데이터 jpg파일로 저장되어 있고. 데이터의 정보가 txt파일로 저장되어 있다.


~/opencv/opencv-3.2.0/build/darknet/Yolo_mark/x64/Release 경로에서 다음 명령어를 입력해보자.


$ vi yolo-obj.cfg


데이터들을 어떤 식으로 학습 시킬 것인지에 대한 정보이다. 

4. 학습을 위한 파일 수정

이제 앞서 계획한 대로 동그라미, 세모, 네모를 Detect하는 네트워크를 만들어 보자. 순서는 다음과 같이 진행하도록 한다.

4.1 Class 수 변경

~/opencv/opencv-3.2.0/build/darknet/Yolo_mark/x64/Release/data 경로에서 다음 명령어를 입력한다.


$ vi obj.data


동그라미, 세모, 네모에 총 3가지를 학습 시킬 것이므로, classes = 3으로 수정했다.

4.2 Class name 설정

~/opencv/opencv-3.2.0/build/darknet/Yolo_mark/x64/Release/data 경로에서 다음 명령어를 입력한다.


$ vi obj.names


동그라미, 세모, 네모에 총 3가지를 학습 시킬 것이므로, 각각의 이름을 'Circle', 'Quadrangle', 'Triangle'로 했다.

4.3 데이터 추가하기

준비된 이미지 파일들을 ~/opencv/opencv-3.2.0/build/darknet/Yolo_mark/x64/Release/data/img 경로로 옮긴다. 이때, 지원하는 이미지 파일 확장자는 *.jpg 뿐이니 참고하자.


필자는 Learning data 10000개를 준비했다.

4.3 데이터 Boxing

~/opencv/opencv-3.2.0/build/darknet/Yolo_mark 경로 에서 다음 명령어를 입력한다.

$ bash ./linux_mark.sh


Boxing을 통해 학습 데이터를 만드는 창이 뜬다. 이전과 다르게 우리가 추가한 데이터에 대한 이미지들이 뜬다. 

마우스를 이용해 Boxing을 하고, 숫자 키패드 0, 1, 2를 이용해 Boxing한 구간이 어떤 객체인지 naming한다. class number의 순서는 4.2에서 저장한 이름들 순서와 같다. 마음에 안들 경우 'c'를 눌러 지울 수 있다. 만약 하나의 데이터에 대한 Boxing이 끝났으면, space bar를 눌러 다음 데이터로 넘어갈 수 있다.


모든 데이터에 대한 Boxing이 끝나면 esc를 눌러 종료한다. ~/opencv/opencv-3.2.0/build/darknet/Yolo_mark/x64/Release/data/img에 들어가보면 이미지 파일에 대응하는 텍스트 파일이 생성된 모습을 볼 수 있다. 

텍스트 파일들은 Boxing한 것에 대한 정보들을 담고 있다. 왼쪽부터 순서대로 'Class_number' 'X' 'Y' 'Width' 'Height'에 대한 정보이다. X, Y좌표는 Boxing한 사각형의 중심 좌표를 나타내며, Width와 Height는 각각 사각형의 가로 길이와 세로 길이를 나타낸다.


4.4 cfg 파일 수정

~/opencv/opencv-3.2.0/build/darknet/Yolo_mark/x64/Release 경로에서 다음 명령어를 입력한다.


$ vi yolo-obj.cfg


창 가장 밑부분 까지 드래그 하면 [Convolutional] 부분과 [region] 부분을 볼 수 있다. 여기서 2가지 부분에 대한 수정이 필요하다.

먼저 [region]부분에 'classes'를 학습하는 class의 개수로 수정한다. 다음 [convolution] 부분에 'filters'는 다음 계산 결과를 입력한다.

filters = (classes + 5) * 5


필자의 경우를 예로 들어보자. classes = 3이 될 것이고, filters = (3 + 5) * 5 = 40이 되겠다.

4.5 convolutional layer 파일 다운로드

~/opencv/opencv-3.2.0/build/darknet 경로에서 다음 명령어를 통해 다운로드 하자.

$ wget https://pjreddie.com/media/files/darknet53.conv.74

4.6 파일 이동, 복사

거의 다 끝났다. 마지막으로 몇가지 파일들을 이동시켜야 한다.


~/opencv/opencv-3.2.0/build/darknet/Yolo_mark/x64/Release/data 경로의 'obj.data', 'obj.names', 'train.txt' 3가지 파일들을 ~/opencv/opencv-3.2.0/build/darknet/data 디렉토리로 이동시킨다. 

~/opencv/opencv-3.2.0/build/darknet/Yolo_mark/x64/Release 경로의 'yolo-obj.cfg' 파일을  ~/opencv/opencv-3.2.0/build/darknet 디렉토리로 이동시킨다.

~/opencv/opencv-3.2.0/build/darknet/Yolo_mark 경로의 'x64' 디렉토리를 ~/opencv/opencv-3.2.0/build/darknet 경로로 복사한다.


터미널을 이용한 명령어는 다음과 같다. 


$ cd ~

$ mv ~/opencv/opencv-3.2.0/build/darknet/Yolo_mark/x64/Release/data/obj.data ~/opencv/opencv-3.2.0/build/darknet/data

$ mv ~/opencv/opencv-3.2.0/build/darknet/Yolo_mark/x64/Release/data/obj.names ~/opencv/opencv-3.2.0/build/darknet/data

$ mv ~/opencv/opencv-3.2.0/build/darknet/Yolo_mark/x64/Release/data/train.txt ~/opencv/opencv-3.2.0/build/darknet/data

$ mv ~/opencv/opencv-3.2.0/build/darknet/Yolo_mark/x64/Release/yolo-obj.cfg ~/opencv/opencv-3.2.0/build/darknet

$ cp -r ~/opencv/opencv-3.2.0/build/darknet/Yolo_mark/x64 ~/opencv/opencv-3.2.0/build/darknet/data

5. 학습 진행

~/opencv/opencv-3.2.0/build/darknet 경로에서 명령어를 통해 학습을 시작하자.

$ ./darknet detector train data/obj.data yolo-obj.cfg darknet53.conv.74


실행시키면 다음과 같은 창이 뜨면서 학습을 진행한다.


몇번 학습을 진행했는지 확인이 가능하며, default값으로는 45000번 학습을 진행하게 되어있다. 필자의 경우 그림에서 볼 수 있다시피 한번 학습하는데 약 3초가 걸리므로 45000번 진행하는데 37.5시간 즉 1.6일이 필요하다. 현재 학습을 진행하는 동안 블로그 글을 작성하는 중이다.


터미널 중간 중간 다음과 같은 문장을 찾을 수 있다.

24674: 0.659918, 0.605959 avg, 0.001000 rate, 2.962139 seconds, 1579136 images

24674는 연산 횟수이고, 0.605959 avg는 평균 손실율을 의미한다. 그러므로 0.XXXXX avg에 해당하는 수치가 줄어들지 않는다면, 학습을 중단해야 한다.


학습을 중단하면, ~/opencv/opencv-3.2.0/build/darknet/backup 경로에 가중치 파일들이 생성된다. 가중치 파일들을 test해보고 가장 만족스러운 것을 선택하면 된다.

6. 학습 결과 확인

~/opencv/opencv-3.2.0/build/darknet/data에 준비된 Test data를 옮겨주고 ~/opencv/opencv-3.2.0/build/darknet 경로에서 다음 명령어를 통해 학습 결과를 확인할 수 있다.


$ ./darknet detector test data/obj.data yolo-obj.cfg backup/*.weights data/*.jpg


여러 가중치 파일들을 확인해보고 가장 결과가 좋은 것을 선택하면 된다.


학습이 끝나면 결과를 추가하겠다.




* Learning Data, Add data, Test data는 따로 존재하는 절대적인 데이터가 아니라 필자가 데이터를 구분할 때 편의를 위해 만든 이름들이다. 



References

Yolo_mark Open source : https://github.com/AlexeyAB/Yolo_mark


'Deep Learning > Yolo' 카테고리의 다른 글

[2] YOLO 사용법  (4) 2019.01.23
[1] YOLO를 알아보자  (0) 2019.01.22