개요
목적
Docker Container로 백엔드 내에서 nnUNet을 활용하는 연구 프로젝트 서비스를 완전히 분할하고, Image를 활용하는 부분은 하나로, 나머지 기능은
각각 배포환경을 다르게 구성하여, microservice처럼 각 기능을 연결한 프로젝트 제작하기
요구조건
- nnUNet의 .nii.gz 데이터를 ndarray + props(nnUNet을 코드 상에서 실행하기 위한 또 다른 입력값)으로 추출해주는 SitkIO 함수를 활용해 I/O 횟수를 최소화(각 모델들을 한번의 I/O로 모두 실행가능하게)
- 메모리 소모량을 감소시키기 위해 각 알고리즘 실행 과정 속, 필요로 하는 최소값의 해상도로 알고리즘 수행
- 향후 다른 연구의 결합에 대한 유지/보수성 증가를 위해 CT Image를 직접적으로 활용하지 않는 다른 기능들은 따로 수행될 수 있도록 구성
구체화
Service | Index | Detail |
---|---|---|
nnUNet | 1 | 혈관, 요관, 구 버전 신장/종양, 구 버전 요관을 모델 별로 함수를 나누어 ndarray -> ndarray 구조로 각각 실행될 수 있도록 모듈화 |
nnUNet | 2 | 조건에 따라 모델을 선택해, 해당 함수가 실행될 수 있도록 구조화 및 입출력 구조 요구조건 달성 |
(optional) nnUNet | 3 | 빠르게 샘플을 만드는 기능을 추가, 만약 이를 추가할 거라면, 해당 서비스와 nnUNet 서비스가 병렬적으로 실행되고, obj 파일을 연속해서 업로드가 수행되야함 |
Smoothing | 1 | .nii.gz mask -> obj 파일로 만드는 업데이트된 기능(FE에 기능을 활용하기 위해선 해당 로직에 업데이트가 필요) |
post-processing | 1 | 인공지능 inference 결과와, mask 결과를 활용하여 Fat mask를 추가해주는 기능 |
(optional) post-processing | 2 | nnUNet의 기능을 후처리 작업을 통해 보정해주는 역할 |
API Gateway | 1 | nnUNet 관련 기능, Smoothing 관련 기능, post-processing 관련 기능을 각각 container로 나누어 이를 연결해주는 역할 |
발견된 문제
1. 서비스에 분할에 관하여
마이크로 서비스로 얻고 싶었던 이점은 아래와 같았다.
1. 각 연구자들의 새로운 연구결과를 결합할 때 도커로 배포만 가능하면, monolithic에 결합하는 수고 없이, 통신으로 이를 해결
2. 각 연구자들의 연구 결과를 분리함으로써 다양한 라이브러리 사용되는 배포환경의 충돌 방지
그러나 현재의 백엔드 시스템은 연구자들이 주로 사용하는 nnUNet이라는 AI 아키텍쳐를 활용할 때 용량이 큰 의료이미지의 I/O 병목을 줄이기 위하여 , 해당 파일을 한번 불러오고, 저장 없이 전처리, AI inference, 후처리를 수행한 후 최종 결과만을 저장하여, 이를 활용한다. 이를 구현하기 위해선 각 서비스별로 I/O를 수행하지 않고, 모든 연구결과를 활용하기 위해서는 해당 서비스가 monolithic하게 존재해야한다.
이는 현재 마이크로 서비스를 만드려는 목적과 상충하는 결과이다.
그렇기에 앞으로 마이크로 서비스를 제작할 때는, 데이터 크기가 큰 의료이미지의 특성에 따라 발생하는 아래와 같은 문제를 고려해야한다.
1. 의료 '이미지'는 용량이 매우 크기에 I/O 병목이 존재하며, gRPC로 이미지 자체를 넘기는 것은 비효율적이다.
2. 여러 서비스가 각각 이미지를 병렬적으로 로드하고 처리한다면, 이에 따른 메모리 소모량을 고려해야한다.
3. 각 연구는 다양한 라이브러리를 사용하기에 이를 하나의 배포환경에 합쳐버리면, 유지/보수 및 안정성이 상당히 떨어진다.
이러한 문제를 해결하기 위한 아이디어는, 몇몇 서비스들은 의료이미지를 필수로 활용하진 않는 것이다. mask 데이터는 의료 이미지 데이터에 비해 훨씬 용량이 작으며,
이에 대한 I/O를 수행하는 것은 이미지에 비해 훨씬 작업 소모량이 적다.
그렇기에 이미지를 다루는 연구 결과물들은 성능 최적화를 위해 monolithic하게 수행할 수도 있겠지만, mask에 대한 처리를 수행하는 로직들에 대해서는
서비스를 나누는 것을 고려할 수 있다.
속도의 향상과 유지/보수성의 tradeoff를 고려하여 문제를 해결할 방법이 필요하다.