본문 바로가기

프로젝트

[회고] 실시간 바이탈 이상탐지 서비스 개발 회고 : "아쉬움이 큰 만큼 더 성장할 수 있기를"

1. 프로젝트 소개 

해당 프로젝트는 회사에서 자체 AI 서비스 론칭을 위해 진행했던 프로젝트로 인공지능 모델을 만들고 이를 서비스화할 때 어떻게 적용해야 하는지 경험할 수 있었던 프로젝트였습니다. 이 프로젝트에 대해 기술적으로 자세히 다루고 싶지만, 현재 진행 중인 서비스라서 기술적인 내용보다는 업무 수행 과정에서 새롭게 알게 된 점과 느낀 점을 중심으로 회고를 진행하려 합니다.

프로젝트에 대해 간단한 소개를 하자면 다음과 같습니다. 

  • 프로젝트명: 실시간 바이탈 이상탐지 서비스 개발
  • 도메인: 헬스케어
  • 프로젝트 목표 : 스마트 밴드에서 실시간으로 수집되는 바이탈의 이상을 탐지하고 알림 진행
  • 담당 업무: 실시간 바이탈 데이터 기반 이상 탐지 모델 개발 및 운영 적용

바이탈 이상탐지 프로세스

 

2. 바이탈 이상탐지 모델 개발

적합한 이상탐지 모델 개발의 필요성

이상탐지가 하나의 분석 주제로 분류될 정도로 이상탐지는 공정, 게임, 금융, 의료 등 다양한 산업 분야에서 필요로 하는 기술입니다. 그만큼 이상탐지에 쓰이는 기법은 초기 통계적 기법에서 딥러닝 모델까지 다양하게 존재하며 서비스 및 데이터의 특징이나 필요한 모델 성능을 고려하여 선택해야 합니다. 복잡하고 고도화된 모델이 항상 좋은 것만은 아니기 때문입니다. 여전히 공정에서는 공정 단계에서 빠른 이상 탐지를 위해 간단한 통계 모형을 쓰고 있기도 합니다. 딥러닝과 같은 고도화된 모델은 상당한 자원을 소모하며, 모델 개발과 운영 시 성능 저하에 대한 지속적인 모니터링이 필요합니다. 따라서 실제 운영에서 딥러닝을 적용하는 것이 유용한지에 대한 사전 검토가 반드시 필요합니다.

LSTM-AutoEncoder 모델 사용 이유

프로젝트에서는 이상탐지를 위해 시계열 데이터 특성을 고려한 LSTM 모델과 이상탐지에서 주로 사용되는 AutoEncoder 모델을 결합하여 사용하였습니다. LSTM 모델을 사용한 이유는 시간에 따라 계속 변화하는 사람의 상태를 보존하여 단기 및 장기 시계열 데이터의 패턴을 잘 학습하는 모델이기 때문입니다. AutoEncoder는 입력 데이터의 주요 특징을 저차원으로 압축한 다음 다시 복원하며 복원 시 입력 데이터의 재구성 오류(reconstruction error)로 이상 징후를 판단합니다. 정상적인 바이탈 데이터 패턴을 학습하였기에 이상 패턴이 들어오게 되면 복원 오류가 커져 이상이라고 판단할 수 있습니다. LSTM은 시계열 데이터를 잘 처리하고 AutoEncoder는 정상 패턴을 학습하여 복원하는 특징이 있어, 이 두 모델을 결합하면 시간에 따른 일반적인 변화와 이상 상태를 효과적으로 구분할 수 있습니다. 

LSTM + AutoEncoder 모델 구조

 

개별 모델 생성의 필요성

실시간 이상탐지 모델을 만들면서 가장 어려웠던 점은 사람마다 모델을 다르게 만들어야 한다는 것이었습니다. 바이탈 데이터의 특징은 사람마다 데이터의 특성이 너무나도 다르게 나타나기 때문입니다. 항상 체온이 낮게 측정되는 사람, 열이 많은 사람, 혈압이 높은 사람, 평균 심장 박동이 빠른 사람 등  주변에서도 사람마다 바이탈의 특성이 다르다는 걸 쉽게 관찰할 수 있습니다. 이를 하나의 모델로 만들게 되면 사람마다 다른 데이터의 특성이 무시가 되고 일반적인 사람의 특성만 고려가 되어 이상을 탐지하게 될 것입니다. 그렇기 때문에 해당 서비스가 추구하는 이상탐지는 개인 맞춤형 정밀한 이상탐지였으며, 의료진의 인터뷰를 통해서도 통합 모델의 위험성을 인지하고 있었기 때문에 환자 별 모델을 생성도록 하였습니다. 

아주 단순하게 예를 든다면, 일반적으로 체온이 37도가 넘으면 위험하다고 알려져 있지만 평균 체온이 각기 다른 세 사람이 있을 때 Person 2는 항상 열이 많아 37도가 오히려 정상이라고 봐야 합니다. (실제로는 37도가 넘으면 위험하게 볼 수도 있을 것 같습니다. 개별 모델 적용 필요성의 예시로만 봐주세요!)

세 사람의 한 달동안 체온 변화 예시

개별 모델 생성의 한계

개별 모델을 만드는 것에 있어서 환자 별 상태를 저장하게 하도록 구조를 짜는 것과 환자 별 결측을 처리하는 방법도 신경을 많이 썼던 부분이지만, 가장 크게 이슈가 되었던 부분은 자원 문제였습니다. 개별모델을 사용한다는 것은 서비스 이용하는 n 명의 사람이 있다면 n 개의 모델이 만들어지게 된다는 뜻입니다. 이렇게 모델이 만들어지게 되면 모델 학습 및 예측에 필요한 자원도 선형적으로 늘어나게 됩니다. 실제로 서비스 배포 후 테스트를 진행하며 메모리 이슈가 있었고, 이를 처리하기 위해 모델 저장 방식을 변경하고, 서비스를 이용하지 않는 사람들을 메모리에서 주기적으로 제거하는 방식으로 처리를 했습니다. 하지만 서비스 이용자가 급격하게 늘어날 경우 대비할 수 있는 방법은 아니기 때문에 추후, 서비스 이용자를 대상으로 몇 개의 공통 모델을 만들어 관리하거나 모델 경량화 기법 등을 추가로 적용해 보면 좋을 것 같습니다.

 

3. 실시간 모델 운영 적용 

지금껏 분석 프로젝트에서는 타 회사, 타 기관의 과거 데이터를 한 번에 입수하여 모델을 개발하고, 운영에 적용할 때는 모델 학습은 주 단위, 월 단위로 학습을 진행하고, 모델 예측 결과 또한 일 단위 배치로 결과를 냈습니다. 그렇기에 이번 프로젝트를 통해 배웠던 점은 실시간으로 데이터가 들어왔을 때는 데이터를 어떻게 처리해야 하며, 결과를 실시간으로 송신은 어떻게 해야 하는지, 모델 학습을 운영에 있어서는 어떻게 자동화 시킬 수 있을지였습니다.

데이터 수집 및 결과 전송 : Kafka

출처 : Kafka 구현 후 링크드인 내부 시스템 구조 ( https://www.confluent.io/blog/event-streaming-platform-1/   참고)

카프카는 대용량의 실시간 데이터를 빠르게 전송하고 처리할 수 있는 분산 스트리밍 플랫폼입니다. 카프카는 메시지를 토픽(topic)이라는 단위로 관리하며, 다양한 데이터 소스로부터 데이터를 받아 적절한 순서대로 전달할 수 있습니다. 이로 인해 실시간 데이터 처리와 데이터 전송의 안정성을 보장할 수 있습니다.

이번 프로젝트에서는 실시간으로 들어오는 바이탈 데이터의 수집과 전송을 위해 카프카를 사용했으며, 장애 시 과거의 데이터도 다시 가져올 수 있도록 카프카 스트림즈를 도입하였습니다. 카프카 스트림즈(Kafka Streams)는 카프카 내의 데이터를 실시간으로 처리하는 애플리케이션 개발을 지원하는 라이브러리로, 메시지 전송뿐만 아니라 데이터 변환, 집계, 윈도우 기능 등을 활용하여 복잡한 데이터 처리 로직을 구현할 수 있는 특징이 있습니다. 프로젝트에서 카프카 스트림즈를 사용했던 이유는, LSTM 모델을 적용하기 위해서는 과거의 데이터가 필요한데 장애가 발생했을 때에도 특정 시점의 과거 데이터를 다시 조회하여 가져올 수 있도록 하기 위해서였습니다. 

또한, 사람의 상태를 순차적으로 저장하여 이상을 감지하는 모델을 만드는 것이기 때문에 바이탈 신호가 섞이게 되면 제대로 된 예측이 이루어질 수 없습니다. 바이탈 데이터의 순서가 보장될 수 있도록 병원별로 파티션을 나누고 환자 ID를 키값으로 두어 특정 병원 데이터를 독립적으로 처리할 수 있도록 하였습니다. 이런 구조를 통해 환자 별 순서가 어긋나는 문제를 방지하고, 데이터 전송의 지연을 줄여 데이터의 안정성과 연속성을 확보한 시스템을 구축하였습니다. 

모델 학습 : MLflow

출처 : https://mlflow.org/docs/2.7.0/what-is-mlflow.html

MLflow는 머신러닝 실험을 관리하고 추적하는 오픈 소스 플랫폼으로, 모델 개발과 배포의 전체 워크플로우를 체계적으로 관리하는 데 유용합니다. MLflow는 네 가지 주요 구성 요소로 이루어져 있습니다. 

  1. MLflow Tracking: 실험 결과를 체계적으로 추적할 수 있으며, 모델의 하이퍼파라미터, 성능 지표, 데이터 버전 등을 저장하여 비교할 수 있습니다.
  2. MLflow Projects: 프로젝트 구성 정보를 담아, 다양한 환경에서 동일한 코드로 실험을 재현할 수 있도록 지원합니다.
  3. MLflow Models: 다양한 모델 형식을 저장하고 배포할 수 있는 일관된 형식을 제공하여, 특정 모델이 쉽게 로드되고 사용될 수 있도록 합니다.
  4. MLflow Registry: 모델 버전을 관리하고, 운영 배포 시 새로운 모델이 실험 중인 모델보다 나은 성능을 보장할 수 있는 워크플로우를 제공합니다.

이번 프로젝트에서는 MLflow를 사용하여 모델 실험 결과를 저장하고 성능을 비교하는 작업을 수행했습니다. 모델의 정확도와 같은 성능 지표를 MLflow Tracking에 기록하고, 이전 모델과 비교하여 정확도가 개선된 경우에만 운영에 배포하는 조건을 설정했습니다. mlflow를 통해 매 실험마다 어떤 실험이 더 좋았는지 비교하기가 용이해졌고, 실험을 보다 쉽게 관리할 수 있었습니다. 또한, 성능이 향상된 모델만 배포하도록 설정하여, 모델의 품질을 보장하고 배포를 자동화할 수 있었습니다. 처음 MLflow를 사용해 봤는데 해당 플랫폼을 통해 모델 개발과 운영 배포가 보다 효율적으로 이루어질 수 있었습니다.

모델 배포 : Git, Jenkins, ArgoCD, Docker, Kubernates

 

Git, Jenkins, Argo CD, Docker, 그리고 Kubernetes를 사용하여 모델 배포 파이프라인을 구축하며 운영 서비스를 개발하였습니다. 운영 서비스 개발을 처음 진행하다보니 모든 도구가 낯설었지만 하나씩 프로젝트에 적용해 가며 자동화 도구들의 편리함에 금방 적응해 갔습니다. 처음 배울 때의 두려움만 극복하면 이후가 매우 편해진다는 것을 알게 되었고, 새로운 기술들에 대해 계속 관심을 가져야겠다는 생각이 들었습니다. 

(1) Git

출처 : https://blog.timo-reymann.de/best-practices-for-github-pull-requests/

Git은 코드 버전 관리를 위한 필수 도구로, 여러 명의 팀원이 동시에 작업하더라도 변경 사항을 추적하고, 필요시 되돌리는 기능을 제공합니다. 협업 과정에서 Pull Request (PR)를 통해 코드 검토를 수행하면서 코드의 일관성을 유지하고 품질을 높일 수 있었습니다. PR하는 과정에서 처음에는 꼬임이 발생하여 여러 번 브랜치도 삭제하고, 강제로 병합도 해보면서 시련을 겪었지만 그런 경험이 바탕이 되어 이제는 제법 익숙하게 git을 다룰 수 있게 되었습니다.  

(2) Jenkins

출처 : https://en.wikipedia.org/wiki/Jenkins_%28software%29

Jenkins는 CI/CD(Continuous Integration/Continuous Deployment)를 위한 오픈 소스 자동화 서버입니다. 코드를 수정하거나 모델을 업데이트할 때마다 Jenkins는 빌드, 테스트, 배포를 자동으로 수행해, 작업 시간을 단축하고 실수를 줄일 수 있게 해 줍니다. Jenkins를 통해 git 배포를 위한 branch에 변경 사항이 업데이트가 되면 자동으로 도커 이미지를 만들어 자동으로 배포할 수 있도록 파이프라인을 구축하였습니다. 

(3) Argo CD

출처 : https://argoproj.github.io/cd/

Argo CD는 Kubernetes 환경에서 GitOps 방식을 통해 지속적인 배포를 자동화하는 도구입니다. Git에 새 코드를 푸시하면 Argo CD가 이를 감지하고 변경 사항을 Kubernetes 클러스터에 반영합니다. 처음으로 Kubernetes와 Argo CD를 결합해 사용하면서, Git에서 직접 코드를 관리하고 배포를 수행하는 방식의 편리함을 경험했습니다. 이를 통해 코드와 인프라 변경사항이 자동으로 동기화되어 안정적인 운영이 가능해졌습니다.

(4) Docker

Docker는 애플리케이션을 컨테이너로 패키징하여 배포와 실행을 간소화하는 플랫폼입니다. Docker를 통해 모델 추론 서비스를 컨테이너 이미지로 만들고, Kubernetes 환경에 손쉽게 배포할 수 있었습니다. 분석 프로젝트를 수행하다보면 패키지 버전이 달라지는 등 환경이 달라지게 되면 코드가 동작되지 않는 경우도 발생하는데 도커를 통해 안정적으로 코드가 동작되는 환경을 배포 전에 테스트를 할 수 있어 안정적인 운영과 확장이 가능했습니다.

(5) Kubernetes

Kubernetes는 컨테이너화된 애플리케이션의 자동 배포, 스케일링 및 관리 기능을 제공하는 오픈 소스 플랫폼입니다. 모델 서비스가 다양한 상황에서도 안정적으로 실행될 수 있도록, Kubernetes 클러스터를 통해 리소스를 최적화하고 롤링 업데이트를 진행할 수 있었습니다. 프로젝트에서 쿠버네티스를 사용한 이유는 이상탐지 추론 팟, 웹 서비스 팟, 수집 서버 팟 등으로 각 서비스를 팟으로 관리함으로써 서로 영향을 미치지 않고 독립적으로 작동하고, 특정 서비스에서 리소스가 크게 증가할 경우 쉽게 확장이 가능하도록 하기 위함이었습니다. 쿠버네티스 환경을 직접 구축하고 관리하진 않았지만, 해당 환경에서 개발한 덕분에 쿠버네티스의 장점과 특징을 경험할 수 있었습니다. 

 

 

4. 효과적인 협업을 위한 의사소통의 필요성과 업무 분배의 중요성

  그동안의 분석 프로젝트에서는 분석 과제를 담당하는 실무자들과 데이터 사이언티스트들끼리만 소통했기 때문에 업무를 진행함에 있어서 의사소통에 불편함을 느낀 적이 크게 없었습니다. 하지만 이번 프로젝트에서 서비스 개발을 위해 아키텍쳐를 설계해 주는 분들과 인프라를 설계하고 개발해 주는 백엔드 개발자 분들, 모델 결과를 받아 처리하는 프론트엔드 개발자 분들 등 서비스를 개발하기 위해 노력하고 있는 많은 동료 분들과 함께 협업하면서 소통이 얼마나 중요하고 어려운 문제인지 알게 되었습니다.

  초반에 이슈가 생겼을 때 이슈를 빠르게 전달해서 해결해야 한다는 생각에 직접적으로 이슈를 전달하고 진행 과정을 체크해 나갔었습니다. 이후 처리해야 할 이슈가 한 사람에게 집중되며 업무 과부화와 지연이 발생한 적이 있었습니다. 협업을 진행할 때는 일의 진행 상황에 대한 지속적인 체크와 이슈 관리가 필수적이라고 생각됩니다. 그러나 기술적으로 모든 내용을 알고 업무를 분배할 기술 리더가 부재한 상황에서 사전 업무 분배와 우선순위 선정이 원활하지 않았습니다. 그러다 보니 처리해야 할 이슈가 몰린 개발자는 이슈 처리에 대한 부담을 가진 채 계속 업무가 과중되었고, 업무 과중에 대한 소통이 원활하게 되지 않아 번아웃과 업무 지연이 발생하게 되었습니다. 이후 이슈 관리의 중요성을 모두 인지하여 이슈가 발생했을 때 이슈를 기록하고 이슈의 긴급도와 난이도를 고려해 처리해야 할 담당자와 우선순위를 할당할 수 있도록 프로젝트 관리 툴을 적용해 업무 과부하 문제는 해소가 되었습니다. 

5. 총평  

이번 프로젝트는 지금까지 데이터 사이언티스트로 근무하면서 가장 많이 배우고, 가장 많이 고생하고, 가장 아쉬움이 많이 남는 프로젝트였습니다. 서비스 개발 회사가 아니기 때문에 좀 더 자문을 구하고 배울 수 있는 분들이 많지 않아 아쉬웠고, 그 안에서 고군분투하면서 다양한 기술을 배우고 성장하였지만 부족함도 많이 느꼈습니다. 프로젝트에서 나와 반년이 지난 지금 다시 되돌아보니 아쉬운 점들이 더욱 보이는 것 같습니다. 마지막으로 프로젝트를 통해 배웠던 점, 프로젝트에서 추가적으로 개선할 수 있는 방법들을 적어보며 마무리해보겠습니다.

[ 배운 점 ]

  • 운영에 필요한 도구들 : git, jenkins, docker, argoCD, kubernates, mlflow, grafana
  • 실시간 데이터 처리 방법 : kafka, kafka streams
  • 의사소통의 필요성과 업무 분배의 중요성  

[ 프로젝트 개선 사항 ] 

  • 장애 발생 대응 : 카프카 스트림을 사용하지 않고 컨슈머의 오프셋 조절
  • 데이터 수집 이슈 : TimeGAN 등 합성 데이터 생성하여 데이터 증강
  • 개별 모델 메모리 이슈 :  모델 경량화, 전이 학습 등 다양한 방법 적용

아쉬움이 크다는 것은 그만큼 더 개선할 여지가 있다는 뜻으로 알고, 내가 적용해보고 싶었던 것들에 대해서 다음 기회에 적용해 볼 수 있도록 앞으로 공부해보도록 하겠습니다. :)