딥러닝 프로젝트 회고

Y·2023년 6월 28일
0

프로젝트

목록 보기
5/5

딥러닝 프로젝트

이번 학기에 수강한 컴퓨터 비전 과목 과제로 프로젝트를 진행했다. 주제는 비전과 관련된 자유 주제였는데, 우리 팀은 Skeleton Detection을 주제로 선정하였다. 교수님께서 논문을 하나 선정해서 구현해보는 방향을 추천하셔서 우리가 선정한 논문은 DeepPose: Human Pose Estimation via Deep Neural Networks 였다. skeleton detection 분야에서 딥러닝을 활용한 거의 첫 논문이고, 중요한 논문이라고 해서 해당 논문으로 선정을 했는데 문제는 공개된 공식 코드가 없었다...

그래서 우리는 일단 깃허브에 공개돼있는 오픈소스들을 찾았는데, 가장 star 수가 많은 repository를 기준으로 일단 학습을 돌려보려고 했다. 그런데... 해당 repository는 마지막으로 업데이트된 것이 6년 전이었다. (아마 이후로 방치된듯함...) chainer를 이용해서 구현한 코드인데, 지금 chainer 최신 버전은 7.8.x고 저 repository에서 사용하는 chainer버전은 1.13.0이었다. (심지어 한 번 업데이트된게 저 버전이었음...) 지금 버전에선 당연히... 안 돌아갔다. 하지만 이 repository만 star수가 확연히 많기도 하고(애초에 deeppose를 구현한 코드가 거의 없었음) 현재 버전으로 어떻게 수정을 하면 좀... 되지않을까? 라는 안일한 생각으로 이 코드를 한 번 수정해보자고 의견을 모았다.

일단은 chainer자체를 사용해본적이 아예 없었어서... chainer 공식문서 읽으면서 동시에 코드들을 읽고 대략적으로 흐름을 이해한 후에, 단순히 IDE상으로 확인할 수 있는, deprecated된 부분들은 모두 수정해줬다. 그러고나서 실행했는데 당연히 또 실행이 안 됐다... ㅎㅎ... 나는 노트북을 쓰고 있었는데, 메모리 에러가 계속 떠서 처음에는 코드에 뭔가 문제가 있나 찾아보다가 아무리봐도 뭐가 문제인지 모르겠고... 데스크톱으로 실행해보고 있는 다른 팀원분들은 메모리 에러는 안 뜨신다고 해서 일단 그럼 코랩으로 실행을 해보려고 했다. 근데 코랩에서는 데이터셋이 너무 용량이 커서(12GB였음ㅎ) 안 돌아갔다... 심지어 코랩은 에러 문구 띄워주지도 않음 그래서 학교 실습실 데스크톱으로 실행하니까 메모리 에러는 안 떴는데, 다른 에러가 뜨기 시작했다.

코드는 chainer를 정석적인 방식으로 사용하는데, Trainer를 활용해서 훈련을 한다. (사실 처음엔 chainer에 대해서 아는게 아예 없어서 공식문서 파면서 삽질을 많이 했는데 나중에 우연히 chainer 공식 github 들어가니까 example 코드들이 꽤 다양하게 있길래 처음부터 이걸 봤으면 쉬웠을텐데... 후회했다....) Trainer를 사용하기 위해서는 Updater가, Updater를 사용하기 위해서는 Iterator가 필요한데 기존 코드에서는 iterators.MultiProcessIterator와 training.ParallelUpdater를 사용하고 있었다. 정확한 이유는 로그가 자세하지 않아서 파악을 못 했는데 일단 에러 로그상으로 발생하는 에러는 저 객체들을 실행하는 부분과 관련이 있었고, 고민을 하다가 example 코드들을 보니 MultiProcessIterator에 MultiProcesUpdater를 쓰고 있기에, updater를 먼저 MultiProcessUpdater로 변경을 해봤다. 그랬더니 프로세스끼리 충돌해서 실행하다가 코드가 자꾸 멈췄다. 그래서 updater는 원래의 ParallelUpdater로 되돌리고, Iterator을 MultiThreadIterator으로 수정했다. 그러니까 정상적으로 작동을 했다!! 기존의 코드가 오류가 난 이유는 여전히 잘 모르겠지만, 멀티프로세싱 환경을 구동하는 과정에서 뭔가 문제가 있었던 게 아닐까 싶다.

그래서 드디어 학습을 시킬 수 있었는데... 문제는 CPU/GPU 환경이었다. CPU에서는 이제 학습이 돌아가는데 당연히 속도가 ... 끔찍하게 느렸다. GPU를 써야만했다. 그런데 GPU 환경 설정이 또 버전 맞추는 것들 때문에 너무 힘들었다. 이 부분은 팀원분께서 고생해주셨다. GPU에 따라서 Nvidia-Driver, CUDA, cuDNN, CuPy, Chainer의 버전이 서로 다 맞물려서 맞아야만 정상적으로 gpu를 사용해서 코드를 돌릴 수 있었는데, CuPy가 정말... 애를 먹였다. 필요한 CuPy 특정 버전이 있었는데, Anaconda 환경에서 버전 목록에 해당 CuPy 버전이 아예 뜨지도 않는거다. 분명히 공식문서에 해당 CuPy버전이 해당 Anaconda 버전에서 존재하는데, 아예 리스트가 안 떠서 도대체 뭐가 문제인지 계속 고민을 했는데 허무하다고 해야할지... 윈도우에서는 해당 CuPy버전이 지원이 안되고 linux/ubuntu에서 지원이 되는 거였다. 그래서 ubuntu로 환경을 바꿔서 처음부터 세팅 다시하니 필요한 CuPy버전 설치가 됐고, GPU로도 학습을 돌릴 수 있게 됐다!! 그런데... GPU가 확실히 CPU보단 빠른 것 같긴한데 생각보다 엄청 빠르지도 않는거다. 그래도 CPU보단 빠르니까... 하고 냅뒀는데 다른 부분(test 부분) 코드를 수정하다가 혹시나? 하고 MultiThreadIterator의 스레드 수를 조정해주니 속도가 훨씬 빨라졌다! default값이 스레드 1개였고, 싱글 스레드나 다름없는 상태로 돌아가고 있는 거여서 GPU였는데도 느린거였다.

  • CPU 사용시 10 epoch 5시간
  • GPU(스레드 1개) 사용시 90 epoch 34시간
  • GPU(스레드 24개) 사용시 90 epoch 9시간

으로, 스레드를 사용하니 시간이 눈에 띄게 빨라졌다. (그래서 파라미터 조정해서 여러개 돌려볼 수도 있었음!) 사실 전공과목에서 GPU에는 스레드 개수를 적게하면 오히려 비효율적이고, 스레드 개수를 매우 크게 하는 게 더 효율적이라고 배웠어서 스레드 수를 많이 크게도 늘려봤는데 그렇게하니까 스레드끼리 충돌이 나버렸다. 24개 정도일때가 충돌 안나고 정상적으로 돌아가는 최대치여서 스레드 24개로 설정해줬다.

그래서 학습까지는 했는데, 이 학습은 train set에 있는 이미지로 학습을 하고 test set에 있는 이미지를 특정 epoch 주기마다 validation 형식으로 테스트해주어서, 기본 train코드에서도 train과 test가 다 이루어지고 있었다. 그런데 일단 우리는 skeleton detection을 하고 있었고, 어떤 사진에 대해서 skeleton detection을 하는 output 이미지를 갖고 싶었다. 기존 코드에도 이러한 evaluation 코드 파일이 있기는 했는데 거의 미완성 상태? 였는지 아예 돌아가지가 않았다. 문제가 있었던 부분은 3가지 정도로 나눌 수 있었다.

1)모델 파일 불러오기
npz파일을 직렬화를 통해서 불러오는데, model 객체 파일의 key값과 model 소스 파일의 속성 값이 달라서(model 소스파일의 속성값은 conv1인데 객체 파일의 key값은 predictor/conv1이런 식이었다.)직렬화 과정에서 오류가 발생했다. 그래서, path base를 설정해주고 모델의 각 레이어별로 직렬화를 따로 해주는 방식으로 하니 해결할 수 있었다.

2)오픈소스 contribution에서 발생한 문제
먼저 해당 코드에서 transform이라는 클래스의 객체를 선언하여 사용하는 부분이 있었는데, 그러한 클래스에 대한 코드는 없었다. 그래서 커밋 내역 추적을 해봤는데, transform.py라는 파일이 있었는데 이 파일이 삭제가 된 거였다! 아마도 해당 파일을 삭제하기 전에 evaluation 코드가 작성되었고, 해당 파일이 삭제된 이후에 evaluation 코드가 수정되지 않은 것으로 보였다. 오픈소스 contribution 과정에서 파일들이 개별적으로 업데이트되며 발생한 오류로 보여서 이 부분은 삭제되기 직전의 가장 최신 버전 파일으로 되살려줬다. 그런데 여기서 끝이 아니었다... 불러온 model 객체에 대해서 predict를 생성하는 부분이 있었는데, model 소스 코드도 변경이 돼서 더 이상 model에 존재하지 않는 속성을 호출하고 있는 거였다. 그래서 이 부분도 커밋 내역 추적을 해봤는데, 그 당시에는 현재 두 개로 나누어져 있는 파일(model과 loss로 나누어짐)이 하나의 파일(model)로 작성되어 있었다. 이것 역시 오픈소스 contribution과정에서 발생한 오류 같았다. 하지만 model을 수정하면 train 코드도 수정을 해야할 것 같아서... 그냥 evaluate 과정을 현재 model 코드에 맞게 수정을 해줬다.

3)NaN값
학습을 하면서 뭐가 문제인지는 잘 모르겠지만.. 특정 레이어에서 epoch가 커지면 NaN값이 저장되는 에러가 발생했다. 모델 객체는 epoch별로 저장을 해뒀는데, 최초로 NaN값이 뜨기 이전의 직전 epoch 객체에서 해당 레이어를 확인해보니 0으로 값이 뜨고 있어서... 모델 객체를 불러올 때 만약 NaN값이 존재하면 0으로 대체해주는 방식으로 코드를 추가해줬다.

이외에도 자잘한 형식 문제나, deprecated된 부분의 문제 등을 해결해줘서 evaluate 코드도 정상적으로 작동시킬 수 있었다! 추가로, 기존 코드는 예측한 관절 위치에 대해서 openCV를 활용해서 작은 점을 찍는 방식이었는데, Skeleton Detection이다보니 선을 이어서 그려주는 편이 낫겠다고 생각해서 팀원분께서 코드를 수정해서 선을 잇는 방식으로 변경해주셨다. 그리고, 논문에서는 PCP와 PDJ라는 성능 평가 방식을 제시하는데 해당 코드에는 이러한 성능 평가 지표를 계산하는 코드는 없었다. (loss값만 제공을 했음..) 그래서 또 다른 팀원분께서 해당 값을 계산하는 코드도 작성해주셨다.

이러한 과정을 통해서 학습을 성공적으로(?) 돌리고, 결과값을 생성하고, 성능도 평가할 수 있었다. 정말 힘들었는데(아예 실행조차도 되지 않은 기간이 너무 길었어서 심적으로 압박이 심했다.) 성공적으로 마무리돼서 너무 기뻤다...

이번 프로젝트를 하면서 오픈소스를 우리의 상황에 맞게, 어떻게 적절한 방식으로 활용할 수 있는지, 그리고 타인이 작성한 코드를 어떤식으로 분석하고 이해해야 하는지에 대해서 배울 수 있었던 것 같다. 그래서 딥러닝이라는 분야를 떠나서... 넓고 넓은 오픈소스 생태계에 발 담그고 개발을 하고 있는 입장으로서 정말 뜻깊은 프로젝트였다! 그리고 이 저장소도 오픈소스이기는 한데, 7년전 이후로 업데이트 되지 않고 방치된 상태라 PR을 날리지는 않았어서... 다음번에는 기회가 된다면 오픈소스 컨트리뷰션에 참가도 한 번 해보고 싶다고 생각하게 됐다.

profile
개발자, 학생

0개의 댓글