Project/[약올림] Final Project

[Milestone Week 2] 알약 등록 기능을 위한 알약 이미지 인식 준비~배포

HJChung 2021. 1. 22. 09:03

2주차 때는 모든 팀원이 본격적으로 알람을 등록하는 주 기능을 구현하는데 집중했다. 

알람 등록시에는 <약 올리기> 버튼을 통해 위 사진과 같은 순서로 약 등록이 진행되며, 여기에 약 이미지 인식 및 분류를 위한 딥러닝 모델이 탑재된다. 

 

앞으로 보완해야 할 점이 참 많지만, 전체 프로세스를 모두 경험해보고 실제 모바일 앱 서비스에 탑재했다는 것 자체만으로 전반적인 개념과 더 필요한 것들은 무엇인지 정리할 수 있었던 귀중한 시간이었다. 

데이터가 젤 중요!!!!!!!!!!!!!!!!

 

이 기능을 구현하기 위해 어떤 과정을 진행했는지에 대해 적어보고자 한다. 

1. Data Download & Sampling

먼저 데이터 다운로드 및 샘플링 과정이다. 

우선 알약 데이터가 필요하다. 

이러한 데이터를 얻을 수 있을 것 같은 여러 공공데이터, Open API 에는 

등이 있다.

 

약올림의 약 정보를 보여주는 화면에서는 약 이름, 보관방법, 효능.. 등이 나와야 하지만 모델을 학습할 때는 약의 이미지와 약 이름만 있으면 되기 때문에 이미지url과 약의 이름이 함께 묶여있는 의약품안전나라에서 제공하는 공공데이터개방_낱알식별목록 csv 파일을 이용하였다. 

이 파일의 구성은 아래와 같다. 

즉 <큰제품이미지> url 로 들어가면 바로 로컬로 알약의 이미지가 바로 다운로드가 된다. 그래서 F 행(큰제품이미지)을 url로 넣고 B 행(품목명)을 파일명으로 해서 이미지 다운로드를 자동화하여서 데이터를 준비해보았다.

음.. 여기서 뭔가 잘못 되었는데..?라고 느끼시는 분들이 계실지도 모르겠다.

실제 이 데이터를 사용한다는 것에 약간.. 꺼림칙한 것은 사실이다. 실제 사용자들이 찍었을 만한 사진데이터를 학습시킨 것이 아니라 정말 깔끔하고 최상의 상태로 찍힌 사진만을 학습데이터로 이용했다는 점에서 가장 큰 한계점이 있다.
하지만, 약 한달반이라는 시간 동안 앱을 만들어야 하는 상황이라 직접 알약 이미지를 모을 수 없어서 일단은 해당 데이터에 여러 증강기법등의 효과를 주는 것으로 대신하고, 모바일에 이미지 인식기능을 넣는 과정 자체에 의의를 두고 구현하고자 하였다.

 

앞의 CSV 파일로 약 2만3천여개 정도의 알약 이미지를 다 다운받았고 알약 데이터들을 살펴보았다.
그리고 어떻게 접근을 해야 할지 여러 관련 연구사례를 살펴보던 중, 심화학습 기반 의약품 영상 자동식별 애플리케이션 개발 연구에서 "같은 모형의 알약끼리 모았을 때는 CNN모델이 알약의 형태는 고려하지 않고 색과 알약 내부의 패턴에 집중할 수 있기때문에 성능이 좋다는 해석이 가능하다.” 라는 내용이 흥미로웠다.

즉, 알약 데이터는 모양이 비슷하고 알약에 새겨진 글자만 다른 경우가 많기 때문에 모양에 가중치를 두어 학습시키기보다 내부 글자에 집중해서 학습시키기는 것이 좀 더 성능이 향상될 것이라고 판단되어서 나도 알약의 모양을 기준으로 데이터프레임을 나누었다. 

 

이렇게 데이터를 보면서 느낀 것은 글자는 알약의 앞,뒷면에 다르게 새겨지는 경우가 있으므로 사용자에게 ‘약의 앞 뒷 면을 나란히 찍어주세요’라는 안내사항이 있어야 할 것 같다는 것이었다. 

아니면 2개씩 쌍으로 되어 있는 이미지를 다 개별이미지로 나누고, 파란색 배경과 격자무늬를 없애고, edge 필터를 씌우는 등 온전히 약 이미지 특징인 모양, 색, 글자 에 대해서만 모델이 학습을 진행 할 수 있도록 모든 전처리를 해주어야 겠다고 생각했다. 

 

우선, 처음부터 모델의 성능에 집중하기보다 모델 배포까지  전체적인 흐름을 해 봐야겠다는 생각으로 일단 계속 진행했다. 

 

2. Data Labelling & Augmentation

데이터 준비를 모두 마친 후 우선 장방형의 100종류 알약을 학습시키는 것을 목표로 하였다. 

먼저 알약의 객체를 인식하고, 인식된 알약에 대해서만 분류가 가능하도록 만드는 것이 정확도 측면이나 서비스 의도와도 부합한다고 생각하였다. 처음에는 일단 어떻게 알약 객체를 배경으로부터 뽑아낼 수 있을까 생각했고, Grabcut을 이용해서 원하는 물체(알약)만 남겨두고 배경을 모두 없애보았었는데, 그 결과는 아래 처럼 어떤 것은 잘 되는데, 어떤 것은 깔끔하게 되지 않았다. 여러 코드에서 한번 나온 결과를 다시 수동으로 제거 할 부분과 살릴 부분을 표시해주어 깔끔하게 처리해주도록 하는데 백 몇장의 사진을 그렇게 하는 건 너무 비효율적이라는 생각이 들었다. 

 

그래서 각 알약마다 Labelimg라는 툴을 사용하여 편리하게 모두 라벨링해주었다.

그 후 라벨링한 Annotation을 포함하여 데이터 증강을 해주어야 하므로 Imgaug라는 라이브러리로 쉽게 노이즈 추가, 흔들림, 이미지 회전 등의 효과를 넣어서 데이터 수를 증가시켰다.

3. Image Classification

앞의 과정으로 데이터 준비는 일단락되었고, 이제 본격적으로 알약 이미지 분류 모델을 학습시키는 단계가 되었다.
모델에 데이터를 input하기 전, 이미지의 크기를 맞춰주고 어떻게 학습을 최적화시킬지에 대한 hyper parameter 조절등의 과정이있지만 이는 약간의 노가다와 운이 필요하다고 생각한다.(물론 결과 해석과 insight가 병행되어야 한다!) 그러나 여기선 어떤 모델을 왜 사용하였는가에 중점을 두어 정리하고자 한다. 

 

사용한 모델은 pretrained MobileNet이다. 위의 그래프를 보면 x축은 연산량, y축은 정확도, 그리고 원의 크기는 model의 용량과 같은 weight에 대한 것을 나타낸다. 그래프에서도 볼 수 있듯이 정확도가 크면 그만큼 모델의 크기도 어느정도 큰 것을 알 수 있다.

 

그런데 내가 해당 모델을 적용할 곳은 다름아닌 mobile환경이다. 그래서 성능도 물론 중요하지만 모바일에서 서비스를 제공하기 위해서는 속도와 하드웨어의 용량적인 측면도 고려해야 한다. 이전의 많은 사람들도 같은 고민을 하였고, 이러한 고민의 결과로 나온 모델 중 하나가 mobileNet이다. 

MobileNet은 Depth즉, channel을 분리해서 convolution연산을 진행하는 Depthwise separable convolution를 사용한다. 즉 각 채널별 spatial정보만을 이용하여 convolution을 수행하고, 그에 대해서 point wise convolution으로 channel간의 convolution을 한다. 이를 통해 위의 수식에서도 알 수 있듯이 연산량을 줄이고 효율화 및 경량화가 가능하다. 


 

학습 후 test한 결과 중 하나이다.  확실히 글자를 보고 인식하도록 하는게 중요할 것이라 생각했다. 

그리고 이 과정을 통해서 알게 된 insight가 있다. 

알약을 한쪽 면만 찍는 것의 위험성

1. 사용자가 글자가 없는 뒷면만을 찍을 경우 비슷한 알약이 매우 많다. (그래도 알약 하나만 찍는것이 UX상 좋다고 본다면, '글자가 있는 면을 찍어주세요' 라는 안내문구가 필요할 것이다. )

ex)

2. 양 면에 모두 글자가 있는 알약이 많은데, '글자가 잇는 면을 찍어주세요'라고 했을 때, 같은 글자가 적혀있는 알약이 많다.

ex) 

+ 여전히 존재하는 한계

이렇게 정형화된 사진 데이터가 아닌 직접 찍은 알약 사진 데이터가 없다. 

 

그래서 앞으로 아래의  것들을 시도해봐야겠다고 생각하며 처음부터 모델의 성능에 집중하기보다 모델 배포까지 전체적인 흐름을 해 봐야겠다는 생각으로 일단 계속 진행했다. 

Darkflow를 활용하여 YOLO 모델로 이미지 디텍션 구현

[DeepLearning] 스마트폰으로 촬영된 알약 이미지 인식 알고리즘 개발을 위한 Reference 정리중 <reference 4. 스마트폰으로 촬영된 알약 영상의 글자 및 형상 인식 방법>의 방법처럼

1) 알약 주변부 획득으로 그림자 제거,

2) 알약 영역 추출과 색, 흔들림 등 여러 효과로 data augmentation더 하기,

3) 글자부 획득(글자 인식을 학습; 할 수 있을진 모르겠다 ㅠ)

 

4. Model Deployment

이제 모델 학습까지 마쳤다! 이제 모바일 환경에 적용해야 할 단계이다. 이 과정에서 어떻게 해야하나 찾던 중 <핸즈온 머신러닝 2판> 을 읽고 답을 찾게 되었다. 모델을 배포하는 방법에는 여러가지가 있지만 현 단계에서는 먼저 모델을 저장 한 후 load 하여서 해당 모델에 predict 메소드를 통해 결과를 도출하도록 하였다. 

 

이후 현재(2021/01/28)는 Heroku와 Docker를 이용해서 배포환경에서 모델을 TFserving으로 배포하였습니다. 
이에 대한 내용은 블로그가 정리되는 대로 여기에 링크 남기도록 하겠습니다.
 

 

가장 먼저 학습시키고 .h5 형식으로 저장한 모델 .tflite형식으로 변환해주었다. TFLite 즉 TensorflowLite는 Android, iOS, 리눅스 등 다양한 모바일 환경과 임베디드 시스템에서 머신러닝 모델을 사용할 수 있게 하는 프레임워크이다.

※ 자세한 설명은 유튜브에서 <TensorFlow Lite: ML for mobile and IoT devices (TF Dev Summit '20)>으로 검색하면 TensorflowLite팀에서 소개한 영상을 통해 찾아볼 수 있다. 

TensorFlow Lite는 다음의 두 가지 주요 컴포넌트로 구성되어 있다. 

1. TF Lite interpreter는 최적화된 모델을 다양한 하드웨어에서 돌아갈 수 있도록 해주는 것이고, 

2. TF Lite converter는 텐서플로우 모델을 인터프리터가 사용할 수 있는 효율적인 형태로 바꿔주고, 모델 용량을 줄이고 성능은 유지할 수 있도록 최적화 기능을 제공한다.

그 후 필수 패키지를 import하고 

최적화된 모델을 하드웨어에서 돌아갈 수 있도록 하는 TF Lite Interpreter을 사용하여 학습된 모델을 불러온다. 이 때 모델을 사용할 때마다 로드하지 않고 서버가 시작할 때 모델을 로드할 수 있도록 하여 비효율과 메모리 소모를 줄이도록 하였다.

이제 /image 엔. 드포인트로 알약 이름 예측을 위한 POST요청을 처리하는 함수를 정의해주었다. 

서버가 요청을 받고  해당 엔드포인트로 file format으로 온 데이터를 모델에 input하기 전 학습단계에서 진행해주었던 것과 같이 사전 처리, 스케일링등을 해주는 prepare_image함수를 거치고, 

그 후 그 데이터를 모델을 통해 전달하게 되고 예측 결과를 JSON 형태으로 클라이언트에게 응답을 반환하는 것으로 마무리 된다. 

 

5.  앞으로 계속 고민하고 보완해 나가야하는 문제

1)  Darkflow를 활용한 YOLO 모델로 알약 이미지 객체인식

첫번째로 Labelimg와 imgaug로 라벨링을 마친 데이터를 가지고, Darkflow를 활용하여 YOLO 모델로 알약 이미지 객체인식 구현을 하였지만 여러 한계점으로 인해서 약올림 서비스에 도입되지는 못했다.
지금 화면에 나오는 것과 같이, 매우 fancy한 사진에 대해서는 알약 객체를 잘 인식하고 박스 쳐주는 것을 볼 수 있지만, 실제 촬영한 이미지에서는 객체검출을 잘 하지 못하는 것을 알 수 있다.

이 역시 맨 처음에 '꺼림칙하다'고 말한  데이터의 다양성 부족으로 인한 한계점이며, 현란한 모델 구현보다도 처음도 데이터, 끝도 데이터가 가장 중요하구나 라는 것을 깨달았았다. 

데이터가 젤 중요햐!!!!!!!!!!!!!!!!

2) 알약 인식 및 예측 모델 성능 개선 필요

두번째로 알약 인식 및 예측을 하는 모델의 성능 개선이 필요하다. 

첫번째 케이스에서 알 수 있듯이 모양과 색이 매우 비슷한 경우가 있다. 그렇기 때문에 알약에 새겨진 글자를 인식할 수 있도록 처리해주는 과정이 필요하다. 

두번째 케이스에서는 첫번째 경우와 반대로 새겨진 글자가 500으로 같지만 알약의 색이 다른 경우이다. 알약의 색은 찍는 환경, 조도,카메라 종류 등에 따라 달라질 수 있기 때문에 다양한 환경에서 찍힌 약들의 평균 색을 구하는 과정이 필요할 듯 하다. 

마지막으로 fancy한 데이터가 아닌 사용자가 실제 촬영할 때의 알약 이미지같은 raw 데이터가 없어서 모델의 정확도를 판단하기가 적절하지 않다. 그래서 이러한 사용자 데이터가 많이 필요하며 모이게 되면 이를 학습단계에 활용해야 한다.

 

3) 모델 배포 방법 개선 ✅

마지막으로 모델 배포 방법을 개선해야 한다. 

 

만약 서비스의 유저가 많은 경우 많은 초당 쿼리수를 받거나 한다면 규모를 확장해야 한다. TF서빙은 높은 부하를 처리할 수 있고 여러 모델을 서비스하며 모델 저장소에서 자동으로 쵯신버전 모델을 배포하는 등의 작업을 수행할 수 있다고 한다. 

그리고 TF 서빙 컨테이너를 서버에 배포하고 관리할 수 있도록 구글 클라우드 AI플랫폼을 사용하는 것도 안정적인 서비스를 위해 필요해 보인다. 

 

+ 이후에 TFServing을 이용한 배포에 대해서 궁금증을 끊을 수가 없어 공부하고 실습해보았다. 

이에 대한 내용은 [Docker] Docker 개념 잡기 및 Quick Start와 [DeepLearning, Docker] Tensorflow Model Serving에 정리해 두었다. 

+ 이후 현재(2021/01/28)는 Heroku와 Docker를 이용해서 배포환경에서 모델을 TFserving으로 배포하였습니다. 
이에 대한 내용은 블로그가 정리되는 대로 여기에 링크 남기도록 하겠습니다. 
 

 

 

앞으로 보완해야 할 점이 참 많지만, 전체 프로세스를 모두 경험해보고 실제 모바일 앱 서비스에 탑재했다는 것 자체만으로 전반적인 개념과 더 필요한 것들은 무엇인지 정리할 수 있었던 귀중한 시간이었다. 

 

reference

Darkflow를 활용하여 YOLO 모델로 이미지 디텍션 구현

imgaug를 이용하여 바운딩박스 정보를 포함한 이미지 증폭시키기

github.com/aleju/imgaug

Deploying Machine Learning Models on Google Cloud Platform (GCP)