Colab에서 모델 학습을 시키기엔 무리가 있다고 판단했다. YOLOv5는 학습을 시작하기 전에 Train, Val, Test Dataset을 스캐닝 하는 시간이 있는데, 문제는 Google Drive에 마운트를 한 코랩 환경에서는 이 이미지를 하나하나 스캔하는게 매우매우매우 오래걸렸다. 평소 컴퓨터에서 스캐닝이 몇분만에 끝나는 반면에 코랩에서는 3만장 로드하는데 20시간이나 걸렸다(...) 그래서 컴퓨팅 인스턴스를 대여하기로 맘 먹었다.
처음엔 AWS나 Google Cloud에서 제공하는 머신러닝 인스턴스를 사용해 볼 까 했는데, JSON으로 라벨링을 또 따로해서 뽑아야 하고 결과물이 ONNX로 나왔기에 걸렀다. 어차피 변환하면 돼서 상관은 없는데 처음 해보는 거라 프로젝트를 혹여나 망칠 수 있을 것 같아 내가 알고있는 걸로 학습시키는게 낫다고 판단했다.
우선 Google Cloud에서 NVIDIA K80 Tesla 그래픽카드 하나를 Allocate 받아서 학습을 시켰고 CUDA, Torch를 세팅하는 과정은 스킵.... 이 과정에서 CUDA 버전을 제대로 설치했는데도 불구하고 Yolo학습시 APM FAIL, CUDA UNABLE 오류가 계속 떠서 미치는 줄 알았다. 이러면서 일주일 소요...결론은 CUDA 버전을 다운그레이드 하여 10.2에서 진행하니 잘 되었다. 아무래도 K80이 나름 나온지 좀 된 그래픽카드라서 그런 것 같다..
그렇게 30만장 학습 시키니까 1 Epoch에 드는 시간이 무려...
Epoch GPU_mem box_loss obj_loss cls_loss Instances Size
0/99 8.59G 0.06637 0.06815 0.05295 400 640: 19%|█▊ | 2464/13194
[3:08:22<14:50:22, 4.98s/it]
15시간 가까이 걸렸다. 50 Epoch만 학습시켜도 한달이 걸리는 상황.. 애초에 10GB짜리 그래픽 메모리 가진거 한장으로 30만장 학습이 무리기도 했고 해서 이미지를 1/10으로 줄이고 모델도 small -> nano로 교체했다. 결과는 하루정도 학습시켜서 끝냈고 mAP_0.5:0.95 = 0.3~~ 정도 나온다. 그런데 문제가 하나 있었다.
전체 이미지에서 등장하는 Instance 의 비율을 그래프로 나타낸건데, 보면 알다시피 어떤 Instance는 너무 적고 어떤건 너무 많다. 예를들어서 제일 많은건 Car(자동차) 이고 실제로도 데이터셋 어느 사진을 열어보더라도 차량 한대씩은 있었던 것 같다. 재밌는건 이 분포로 우리가 평소에 거리에서 무엇을 자주 볼 수 있고 못 보는지에 대한 얘기를 들을 수 있었는데, PARKING_METER(주차 정산기) 같은 경우에 우리나라에서 해외에 비해 그 수가 적기에 많이 없었다. 또 DOG, CAT 또한 많이 없었는데 재밌는건 비교했을때 그 수가 DOG >>>> CAT 이었다. 아무래도 고양이는 산책을 나오지 않고, 거리에서 볼 수 있는 고양이는 소수의 길냥이기에 나온 결과 인 듯. 그리고 내 생각보다 BOLLARD(진입로 차단 봉)이 굉장히 많았는데, 시각장애인 분들의 어려움을 담은 논문에서 볼라드 같은 경우 점자 안내판이 없는 경우가 매우 매우 많기에 도보 보행에 어려움을 많이 준다고 했었다. 이렇게 보니 얼마나 불편하고 보행에 위협이 되는지 그 숫자를 보고서 비로소. 그 어려움을 조금이나마 이해 할 수 있게 되었다.
아무튼,, 이러한 그래프로 보는 스토리는 뒤로하고 이 인스턴스의 불균형이 가져오는 문제점은 바로 학습의 불균형이 생긴다는 점 이었다. 만약 내가 데이터셋의 크기를 줄인다고 랜덤하게 데이터를 뽑아서 쓰면 표본이 모집단의 분포를 따라간다고 가정했을때 똑같은 인스턴스 갯수의 불균형이 생긴다. 차량 같은 경우엔 항상 너무 많아서 그렇다 치더라도, 그 개수가 적은 인스턴스(CAT, SCOOTER, PARKING_METER 등)는 데이터셋에 넣고 많은건 굳이 넣지 않거나 빼는 그러한 작업이 필요했다.
다음과 같은 방법을 사용했다.
Number of Class = 27(PARKING_METER, CAT 삭제)
최소 개수를 갖는 인스턴스 : Scooter = 1983개
각 인스턴스당 최소 1700개를 수집하여 새로운 폴더로 이미지를 옮긴다고 가정하면
1700 * 27 = 45900개(전체 이미지의 최소 인스턴스 갯수)
45900 *. 7 = 32130 (전체 데이터의 70%를 Train set으로)
Scooter 의 Instance 1700개 채워지면 다음 우선순위인 Wheel Chair 채우는 방식.
그리고 각 Instance의 개수 채움이 끝나면 옮겨진 이미지 전체를 한번 검사하는 과정 거침. 이미지는 옮기면서 라벨까지 같이 생성하고 배열에 사용된 이미지 파일 이름을 담는 식으로 중복 이동을 막음(최대 45900 개의 이미지이며 이것보단 훨씬 적을거로 예상)
실제로 사용된 이미지는 20k 정도였다.
코드는 Git에 올려두었다.
GitHub - zetstream33/AIhub_Dataset_DataSegmentation
Contribute to zetstream33/AIhub_Dataset_DataSegmentation development by creating an account on GitHub.
github.com
결과는 정확도 2배정도 상승! (small 모델 먼저 학습 시켰는데 정확도 올라가는 것 확인하고 medium 모델로 바꾸었다)
'프로젝트 : CV를 활용한 시각장애인용 어플리케이션' 카테고리의 다른 글
Part 2 : YoloV5 Custom Dataset 을 Train 하기 위해 XML->Yolo Format으로 변경 및 테스트 (0) | 2023.03.24 |
---|---|
Part 1 : 캡스톤디자인(1) 과목 프로젝트 기획 & Colab을 활용하여 Dataset을 Google drive에 옮기기 (2) | 2023.03.12 |