[ML Project] Bone-Age-Assessment(1)

김현우
None
Published in
9 min readDec 21, 2020

휴먼스케이프 Software engineer Covy입니다.

이번 포스트에서는 헬스케어와 딥러닝을 어떻게 하면 접목시켜 재미있는 프로젝트를 진행할 수 있을까를 고민하다가 마침 kaggle에서 bone-age-dataset을 발견하여 이 dataset을 가지고 사이드 프로젝트를 진행하면 어떨까해서 시작하게 되었습니다.

이전 [ML Practice] 포스트들에서는 Pytorch framework를 이용해서
1. Custom Dataset을 구현하고,
2. 학습을 위한 Layer와 Model을 정의하고,
3. Train을 하며,
4. Local directory에 Image Saving을 하는
방법들에 대해서 설명했었습니다.

이번 포스트에서는 Pytorch framework를 이용해 Bone-Age-Assessment이라는 주제 아래에서 앞선 [ML Practice]들에서 설명드렸던 내용 구현 + 추가적으로
1. csv file 읽는 방법
2. Model Save/Load를 하는 방법,
3. Model Test를 하는 방법,
4. Jupyter Notebook을 활용한 단일/다중 Test 및 결과 가시화를 하는 방법
에 대해서 설명드리겠습니다.

모델 구현에 참고한 논문은 아래와 같습니다.
“Pediatric Bone Age Assessment Using Deep Convolutional Neural Networks”

Bone Age Assessment

Reading CSV file

딥러닝 학습을 진행하다보면 csv file 을 마주하는 경우가 많습니다. Classification을 비롯한 여러 supervised learning들에서 csv file은 ground truth data를 제공하는 파일 형식 중 하나이며, 이를 읽어들여서 학습 데이터에서 사용해야 할 일 또한 많습니다.
첫 번째 주제인 Reading CSV file에서는 csv file을 읽을 수 있는 library인 pandas를 소개해드리려고 합니다.

위 코드는 제가 구현한 프로젝트의 CustomDataset입니다. 저는 dataLoader를 통해 image 뿐만이 아니라, image와 매칭되는 label 또한 산출하고 싶었기 때문에 dataset에서 csv file을 읽고, image에 해당되는 label을 image와 함께 넘겨주도록 설정했습니다.

위 코드의 8번째 줄,

label_data = pd.read_csv(label_data_dir)

에서 label_data를 불러오고,
28번째 줄,

dataRow = self.label_data.loc[self.label_data['id'] == idValue]

에서 .loc method를 이용해서 데이터의 id 항목이 앞서 구한 idValue랑 같은 데이터의 row를 가져옵니다.
이후 29번째와 30번째 줄에서

boneage = int(dataRow['boneage'])
gender = int(dataRow['male'])

을 통해 label 정보를 가져옵니다.
이것으로 간단하게 pandas를 이용해 csv file을 읽어들이고, 특정 조건을 만족하는 row를 선택하는 방법에 대해서 알아보았습니다.

Model Save/Load

모델을 학습하더라도 학습이 진행되는 런타임에서만 결과를 확인할 수 있다면… 매번 다시 학습을 시켜서 결과를 확인해야 할 것입니다.
그런데, 아시다시피 딥러닝의 학습시간은 길게는 몇 주~몇 달이 걸리기도 하고, 짧더라도 몇 시간은 걸리는 경우가 많습니다.
이를 위해서 존재하는 기능이 Model Save/Load 입니다.
학습이 진행되는 런타임에 학습된 model과 optimizer의 상태를 저장해두고 나중에 불러서 쓸 수 있게 하는 형태입니다.

위 코드는 제가 구현한 프로젝트에서의 save/load function입니다.

save에서는 저장할 model인 classificationModel, 저장할 optimizer인 optim, 그리고 학습이 진행된 마지막 epoch 수, 저장할 directory 위치를 받아서 torch.save를 이용해 저장합니다.
이 때 사용되는 state._dict()는 model, optimizer의 학습 가능한 매개변수를 dictionary 형태로 나타낸 것입니다.

load에서는 저장된 model을 가져올 directory 위치, state를 load하여 적용할 classificationModel, optimizer를 받아서 torch.load를 통해서 dictionary 형태로 저장된 model을 얻어낸 후에 이를 key로 접근하여 load_state_dict를 통해서 parameter를 적용합니다.
제가 구현한 코드에서는 가져올 directory에서 가장 큰 epoch인 model을 가져오기 위한 로직이 일부 포함되어 있습니다.

이것으로 간단하게 Model Save/Load 방법에 대해서 알아보았습니다. 저는 이 기능을 통해서 “12시간동안밖에 지속되지 않는 Google Colaboratory”에서 학습을 이어나갈 수 있었습니다….

Testing Model

모델을 학습시키는 것만큼 중요한 것이 모델을 평가하는 것입니다. 앞선 [ML Practice]들에서는 모델 학습 중간에 이미지를 저장하거나, loss data를 뽑아서 가시화하는 방법들로 “학습이 잘 되고 있는가"를 확인했지만, 실제로는 test dataset을 이용한 testing이 필요합니다.
세 번째 주제인 Testing Model에서는 두 번째 주제에서 설명드렸던 Model Save/Load 중 Model Loading을 이용해서 진행할 예정입니다.

결론부터 말씀드리자면, train할 때 주로 사용하던 코드와 크게 다르지 않습니다. 다른 부분이라면,
1. model을 eval mode로 실행한다는 점,
2. optimizer를 갱신하지 않는다는 점,
3. epoch을 반복할 필요가 없다는 점
이 되겠습니다.

두 번째 주제에서 설명드린 것처럼 처음에 classificationModel, optim, startEpoch등을 loading합니다. 다만, testing할 때는 optimizer를 갱신하거나, epoch을 이어받아서 학습을 추가로 진행할 것이 아니기 때문에 classificationModel의 정보만이 유효하게 작용합니다.

이후 진행하는 것은 test dataset을 한 바퀴(1 epoch) 돌면서 load한 classificationModel의 forward path를 통과시켜 나온 결과를 산출하는 과정입니다. 저 같은 경우는 train할 때와 마찬가지로 print() 구문으로 결과를 출력함은 물론 plotting을 위해 label과 predict data를 반환까지 진행했습니다.

Visualizing Result with Jupyter Notebook

결과를 가시적으로 보여줄 수 있는 수단으로 Jupyter Notebook + matplotlib 의 조합을 사용할 수 있습니다. 장점은 testing data를 손쉽게 바꿔가면서 test result를 빠르게 확인할 수 있다는 점입니다.
저는 VScode의 jupyer notebook extension을 활용해 구현을 진행했습니다.

import

가장 먼저 진행한 과정은 필요한 것들을 import하는 과정입니다. 자세한 설명은 생략하도록 하겠습니다.

이후 ageX, ageY에 test를 진행한 데이터를 받아와 저장하는 과정을 진행했습니다. 이 ageX와 ageY의 경우 plotting을 위해 사용될 예정입니다. 중간 과정으로 찍히는 label과 예측값도 확인해볼 수 있습니다.

위는 plotting data입니다.
x 좌표는 실제 실제 label의 boneage이고, 푸른 점의 y좌표는 실제 label의 boneage, 주황색 점의 y좌표는 예측 boneage입니다.
데이터들의 분포를 통해 한 눈에 예측한 값들이 실제 값과 유사하게 align되어 있음을 확인할 수 있습니다.

추가로, 위의 결과는 전체 데이터를 넣고 결과를 뽑아낸 것이라면, 하나의 데이터를 넣고 그 결과를 얻어보고 싶은 경우에는 아래와 같이 구현할 수 있습니다.

제일 먼저, 이미지를 불러오는 과정입니다.

다음으로, 이미지 전처리 과정입니다. 여기서는 학습 시간 감축을 위한 이미지 resizing이 주목적입니다.

마지막으로, label 데이터를 가져오고 모델을 불러온 뒤, 결과를 출력하는 과정입니다. 마지막 세션에서 보이는 것과 같이 실제 골 연령, 예측 골 연령을 출력해서 나타낼 수 있습니다.

Conclusion

이것으로 Bone-Age-Assessment 프로젝트의 첫 번째 진행상황인 모델 구현, 학습, 평가, 가시화를 간단하게 진행해 보았습니다.
이전에 [ML Practice]에서 많이 다루었던 모델 구현과 학습 관련 부분은 이번 포스트에서는 생략했습니다. 관심 있으신 분은 한 번 논문의 내용을 보고, 직접 작성해보시는 것도 좋을 것 같습니다.

--

--